# Memento MCP Server Model Context Protocol (MCP) server for integrating Memento note-taking app with N8N, Claude Desktop, Cursor, and other MCP clients. **Version 3.2.0** - Enhanced with error handling, observability, rate limiting, and input validation. ## Features - ✅ **22 Tools** for notes, notebooks, labels, and reminders - 🔒 **API Key Authentication** with secure storage - 🚀 **Performance Optimized** with connection pooling and caching - 📊 **Observability** with Prometheus metrics export - 🛡️ **Input Validation** using Zod schemas - ⏱️ **Rate Limiting** per-user and global - 🚨 **Structured Error Handling** with detailed messages - 📝 **Audit Logging** for compliance ## Quick Start ```bash cd mcp-server npm install ``` ### stdio Mode (Claude Desktop, Cline) ```bash npm start # or node index.js ``` Claude Desktop configuration: ```json { "mcpServers": { "memento": { "command": "docker", "args": ["exec", "-i", "memento-mcp", "node", "index.js"] } } } ``` ### HTTP Streamable Mode (N8N, remote) ```bash npm run start:http # or node index-sse.js ``` ## Authentication When `MCP_REQUIRE_AUTH=true` (default in Docker), all requests require an `x-api-key` header. Generate API keys from the Memento web UI: **Settings > MCP**. ```bash # Example: health check with API key curl -H "x-api-key: mcp_sk_xxx" http://localhost:3001/health ``` ## Available Tools (22) ### Notes (13) | Tool | Description | |------|-------------| | `create_note` | Create a new note | | `get_notes` | List notes (filterable) | | `get_note` | Get a specific note by ID | | `update_note` | Update an existing note | | `delete_note` | Delete a note permanently | | `search_notes` | Search notes by keyword | | `move_note` | Move a note to a notebook | | `toggle_pin` | Pin/unpin a note | | `toggle_archive` | Archive/unarchive a note | | `append_to_note` | Append content to a note | | `find_and_update_note` | Find and update a note | | `batch_move_notes` | Move multiple notes at once | | `batch_delete_notes` | Delete multiple notes at once | ### Notebooks (6) | Tool | Description | |------|-------------| | `create_notebook` | Create a notebook | | `get_notebooks` | List all notebooks | | `get_notebook` | Get notebook details | | `update_notebook` | Update a notebook | | `delete_notebook` | Delete a notebook | | `reorder_notebooks` | Reorder notebooks | | `get_notebook_hierarchy` | Get tree structure of notebooks | ### Labels (4) | Tool | Description | |------|-------------| | `create_label` | Create a label | | `get_labels` | List labels | | `update_label` | Update a label | | `delete_label` | Delete a label | ### Reminders (1) | Tool | Description | |------|-------------| | `get_due_reminders` | Get due reminders | ### Utilities (2) | Tool | Description | |------|-------------| | `export_notes` | Export notes as JSON | | `import_notes` | Import notes from JSON | ## HTTP Endpoints | Endpoint | Method | Description | Auth Required | |----------|--------|-------------|---------------| | `/` | GET | Server info | No | | `/health` | GET | Health check | No | | `/metrics` | GET | Prometheus metrics | No* | | `/sessions` | GET | Active sessions | Yes | | `/mcp` | GET/POST | Main MCP endpoint | Yes | | `/sse` | GET/POST | Legacy redirect to `/mcp` | Yes | *Metrics can be disabled with `MCP_ENABLE_METRICS=false` ## Configuration | Variable | Default | Description | |----------|---------|-------------| | `PORT` | 3001 | Server port | | `DATABASE_URL` | required | PostgreSQL connection string | | `MCP_REQUIRE_AUTH` | false | Require x-api-key header | | `MCP_API_KEY` | - | Static fallback API key | | `MCP_LOG_LEVEL` | info | Log level (debug, info, warn, error, silent) | | `MCP_REQUEST_TIMEOUT` | 30000 | Request timeout in ms | | `MCP_RATE_LIMIT` | 100 | Requests per window per user | | `MCP_RATE_LIMIT_WINDOW` | 60000 | Rate limit window in ms | | `MCP_MAX_SESSIONS` | 500 | Maximum concurrent sessions | | `MCP_SESSION_TTL` | 3600000 | Session TTL in ms | | `MCP_ENABLE_METRICS` | true | Enable metrics endpoint | | `MCP_ENABLE_AUDIT_LOG` | true | Enable audit logging | | `MCP_MAX_REQUEST_SIZE` | 10485760 | Max request size in bytes (10MB) | | `APP_BASE_URL` | http://localhost:3000 | Memento app URL | | `USER_ID` | - | Optional user ID filter | | `DB_CONNECTION_LIMIT` | 10 | Prisma connection pool limit | | `DB_POOL_TIMEOUT` | 10 | Prisma pool timeout in seconds | ## Error Handling All errors follow a structured format: ```json { "_error": true, "code": -32602, "httpCode": 400, "message": "Invalid params", "description": "Invalid method parameter(s)", "detail": "Input validation failed", "field": "content", "category": "validation", "timestamp": "2026-05-24T12:00:00.000Z" } ``` ### Error Codes | Code | HTTP | Name | |------|------|------| | -32700 | 400 | Parse error | | -32600 | 400 | Invalid request | | -32601 | 404 | Tool not found | | -32602 | 400 | Invalid params | | -32603 | 500 | Internal error | | -32000 | 500 | Database error | | 401 | 401 | Authentication failed | | 403 | 403 | Forbidden | | 429 | 429 | Rate limit exceeded | | 408 | 408 | Request timeout | | 409 | 409 | Conflict | | 422 | 422 | Unprocessable entity | | 503 | 503 | Service unavailable | ## Metrics Prometheus-compatible metrics are available at `/metrics`: ``` # HELP mcp_requests_total Total number of requests mcp_requests_total 1234 # HELP mcp_latency_ms Request latency in milliseconds mcp_latency_ms{quantile="0.5"} 45 mcp_latency_ms{quantile="0.95"} 120 mcp_latency_ms{quantile="0.99"} 250 # HELP mcp_errors_total Total number of errors mcp_errors_total{category="validation"} 5 mcp_errors_total{category="database"} 2 # HELP mcp_auth_total Authentication attempts mcp_auth_total{result="success"} 500 mcp_auth_total{result="failure"} 10 # HELP mcp_sessions_active Active sessions mcp_sessions_active 15 ``` ## N8N Integration ### MCP Client Node Configuration 1. Add a **MCP Client** node in N8N 2. Select **Streamable HTTP** as transport 3. Endpoint: `http://memento-mcp:3001/mcp` (Docker) or `http://YOUR_IP:3001/mcp` 4. Add **Header Auth**: `x-api-key` = your MCP API key ### Example Workflow: Create a note from email ```json { "tool": "create_note", "arguments": { "title": "{{ $json.subject }}", "content": "{{ $json.body }}", "labels": ["email", "inbox"], "notebookId": "inbox-notebook-id" } } ``` ## Docker Deployment ```yaml services: memento-mcp: build: ./mcp-server environment: DATABASE_URL: ${DATABASE_URL} MCP_REQUIRE_AUTH: "true" MCP_LOG_LEVEL: "info" ports: - "3001:3001" healthcheck: test: ["CMD", "curl", "-f", "http://localhost:3001/health"] interval: 30s timeout: 10s retries: 3 ``` ## Testing ```bash # Run all tests npm test # Run performance tests npm run test:perf # Run connection tests npm run test:connection # Validate configuration npm run validate ``` ## Security Considerations 1. **Always use authentication in production** (`MCP_REQUIRE_AUTH=true`) 2. **Use HTTPS** when exposing the server over the internet 3. **Set appropriate rate limits** for your use case 4. **Monitor metrics** for unusual activity 5. **Keep dependencies updated** with `npm audit` 6. **Use environment variables** for sensitive configuration ## Troubleshooting ### Database connection failed ``` FATAL: Database connection failed ``` - Verify `DATABASE_URL` is correct and reachable - Check database credentials and permissions - Ensure database is running and accessible ### Rate limit exceeded ``` 429 Too Many Requests ``` - Wait for the rate limit window to expire (check `Retry-After` header) - Increase `MCP_RATE_LIMIT` if needed - Use multiple API keys for different applications ### Authentication failed ``` 401 Unauthorized ``` - Verify API key is correct and active - Check that `MCP_REQUIRE_AUTH=true` if using API keys - Ensure API key hasn't been revoked ## Development ```bash # Run with debug logging MCP_LOG_LEVEL=debug npm run dev # Check configuration npm run validate # Run tests npm test ``` ## License MIT