# API Contracts - mcp-server (Memento MCP Server) ## Overview The mcp-server provides a Model Context Protocol (MCP) interface for integrating Memento with AI assistants and automation tools like N8N. It exposes tools (functions) that can be called via the MCP protocol. **Protocol:** Model Context Protocol (MCP) SDK v1.0.4 **Transport:** Stdio (standard input/output) **Type:** JavaScript ES modules **Database:** Shared Prisma SQLite database (connects to `keep-notes/prisma/dev.db`) --- ## MCP Tools The server exposes the following MCP tools that can be invoked by MCP clients: --- ### create_note Create a new note in Memento. **Parameters:** ```json { "title": "string (optional) - Note title", "content": "string (required) - Note content", "color": "string (optional, default: 'default') - Note color: default|red|orange|yellow|green|teal|blue|purple|pink|gray", "type": "string (optional, default: 'text') - Note type: 'text' or 'checklist'", "checkItems": "array (optional) - Checklist items (if type is 'checklist')", "labels": "array (optional) - Note labels/tags", "isPinned": "boolean (optional, default: false) - Pin the note", "isArchived": "boolean (optional, default: false) - Archive the note", "images": "array (optional) - Note images as base64 encoded strings" } ``` **Response (text content):** ```json { "id": "clxxxxxxx", "title": "string or null", "content": "string", "color": "string", "type": "text|checklist", "checkItems": [...] | null, "labels": [...] | null, "images": [...] | null, "isPinned": boolean, "isArchived": boolean, "createdAt": "ISO8601 datetime", "updatedAt": "ISO8601 datetime" } ``` **Error Response:** - Throws `McpError` with `ErrorCode.InternalError` on failure --- ### get_notes Get all notes from Memento with optional filtering. **Parameters:** ```json { "includeArchived": "boolean (optional, default: false) - Include archived notes", "search": "string (optional) - Search query to filter notes (case-insensitive)" } ``` **Response (text content):** ```json [ { "id": "clxxxxxxx", "title": "string or null", "content": "string", "color": "string", "isPinned": boolean, "isArchived": boolean, "type": "text|checklist", "checkItems": [...] | null, "labels": [...] | null, "images": [...] | null, "order": number, "createdAt": "ISO8601 datetime", "updatedAt": "ISO8601 datetime" } ] ``` **Ordering:** `isPinned DESC`, `order ASC`, `updatedAt DESC` **Error Response:** - Throws `McpError` with `ErrorCode.InternalError` on failure --- ### get_note Get a specific note by ID. **Parameters:** ```json { "id": "string (required) - Note ID" } ``` **Response (text content):** ```json { "id": "clxxxxxxx", "title": "string or null", "content": "string", "color": "string", "isPinned": boolean, "isArchived": boolean, "type": "text|checklist", "checkItems": [...] | null, "labels": [...] | null, "images": [...] | null, "reminder": "ISO8601 datetime" | null, "isReminderDone": boolean, "reminderRecurrence": "string" | null, "reminderLocation": "string" | null, "isMarkdown": boolean, "size": "small|medium|large", "embedding": "JSON string" | null, "userId": "string" | null, "order": number, "createdAt": "ISO8601 datetime", "updatedAt": "ISO8601 datetime" } ``` **Error Response:** - Throws `McpError` with `ErrorCode.InvalidRequest` if note not found - Throws `McpError` with `ErrorCode.InternalError` on other failures --- ### update_note Update an existing note. **Parameters:** ```json { "id": "string (required) - Note ID", "title": "string (optional) - Note title", "content": "string (optional) - Note content", "color": "string (optional) - Note color", "checkItems": "array (optional) - Checklist items", "labels": "array (optional) - Note labels", "isPinned": "boolean (optional) - Pin status", "isArchived": "boolean (optional) - Archive status", "images": "array (optional) - Note images as base64 encoded strings" } ``` **Response (text content):** ```json { "id": "clxxxxxxx", "title": "string or null", "content": "string", "color": "string", "type": "text|checklist", "checkItems": [...] | null, "labels": [...] | null, "images": [...] | null, "isPinned": boolean, "isArchived": boolean, "createdAt": "ISO8601 datetime", "updatedAt": "ISO8601 datetime" } ``` **Notes:** - Automatically updates `updatedAt` timestamp - Arrays (checkItems, labels, images) are JSON-encoded before storage **Error Response:** - Throws `McpError` with `ErrorCode.InternalError` on failure --- ### delete_note Delete a note by ID. **Parameters:** ```json { "id": "string (required) - Note ID" } ``` **Response (text content):** ```json { "success": true, "message": "Note deleted" } ``` **Error Response:** - Throws `McpError` with `ErrorCode.InternalError` on failure --- ### search_notes Search notes by query. **Parameters:** ```json { "query": "string (required) - Search query" } ``` **Response (text content):** ```json [ { "id": "clxxxxxxx", "title": "string or null", "content": "string", "color": "string", "isPinned": boolean, "isArchived": boolean, "type": "text|checklist", "checkItems": [...] | null, "labels": [...] | null, "images": [...] | null, "createdAt": "ISO8601 datetime", "updatedAt": "ISO8601 datetime" } ] ``` **Search Logic:** - Only searches non-archived notes (`isArchived: false`) - Case-insensitive search across `title` and `content` fields - Uses SQL `LIKE` operator (contains matching) **Ordering:** `isPinned DESC`, `updatedAt DESC` **Error Response:** - Throws `McpError` with `ErrorCode.InternalError` on failure --- ### get_labels Get all unique labels from all notes. **Parameters:** ```json {} ``` **Response (text content):** ```json [ "label1", "label2", "label3" ] ``` **Notes:** - Extracts labels from all notes in the database - Labels are stored as JSON arrays in the `labels` field - Returns unique, sorted list of all label strings - Does not create or use the Label table (reads directly from Note.labels) **Error Response:** - Throws `McpError` with `ErrorCode.InternalError` on failure --- ### toggle_pin Toggle pin status of a note. **Parameters:** ```json { "id": "string (required) - Note ID" } ``` **Response (text content):** ```json { "id": "clxxxxxxx", "title": "string or null", "content": "string", "color": "string", "isPinned": boolean, // Toggled value "isArchived": boolean, "type": "text|checklist", "checkItems": [...] | null, "labels": [...] | null, "images": [...] | null, "createdAt": "ISO8601 datetime", "updatedAt": "ISO8601 datetime" } ``` **Error Response:** - Throws `McpError` with `ErrorCode.InvalidRequest` if note not found - Throws `McpError` with `ErrorCode.InternalError` on other failures --- ### toggle_archive Toggle archive status of a note. **Parameters:** ```json { "id": "string (required) - Note ID" } ``` **Response (text content):** ```json { "id": "clxxxxxxx", "title": "string or null", "content": "string", "color": "string", "isPinned": boolean, "isArchived": boolean, // Toggled value "type": "text|checklist", "checkItems": [...] | null, "labels": [...] | null, "images": [...] | null, "createdAt": "ISO8601 datetime", "updatedAt": "ISO8601 datetime" } ``` **Error Response:** - Throws `McpError` with `ErrorCode.InvalidRequest` if note not found - Throws `McpError` with `ErrorCode.InternalError` on other failures --- ## Server Information **Name:** `memento-mcp-server` **Version:** `1.0.0` **Capabilities:** Tools only (no resources or prompts) ## Connection Details **Transport:** Stdio (Standard Input/Output) **Entry Point:** `index.js` **Alternative SSE Endpoint:** `index-sse.js` (Server-Sent Events variant) ## Database Connection ```javascript const prisma = new PrismaClient({ datasources: { db: { url: `file:${join(__dirname, '../keep-notes/prisma/dev.db')}` } } }); ``` **Important:** The MCP server connects directly to the keep-notes SQLite database file, sharing the same data as the web application. ## Error Handling All errors are returned as MCP errors with appropriate error codes: - `ErrorCode.InvalidRequest`: Invalid parameters or resource not found - `ErrorCode.MethodNotFound`: Unknown tool requested - `ErrorCode.InternalError`: Server-side errors (database, parsing, etc.) ## Usage Example With N8N or MCP-compatible client: ```javascript // List available tools server.tools() // Create a note server.callTool('create_note', { title: 'Meeting Notes', content: 'Discussed Q1 roadmap...', labels: ['work', 'planning'], color: 'blue' }) // Search notes server.callTool('search_notes', { query: 'roadmap' }) // Toggle pin server.callTool('toggle_pin', { id: 'clxxxxxxx' }) ``` --- ## Helper Functions ### parseNote(dbNote) Internal helper to parse JSON fields from database: ```javascript function parseNote(dbNote) { return { ...dbNote, checkItems: dbNote.checkItems ? JSON.parse(dbNote.checkItems) : null, labels: dbNote.labels ? JSON.parse(dbNote.labels) : null, images: dbNote.images ? JSON.parse(dbNote.images) : null, }; } ``` This function is called on all note objects returned to clients to ensure JSON arrays are properly parsed from their string representation in the database. --- ## Integration with N8N The MCP server is designed to work with N8N workflows: 1. Install N8N MCP integration 2. Configure connection to `memento-mcp-server` 3. Use tools in N8N nodes: - Create notes from external sources - Search and retrieve notes - Update notes based on triggers - Archive/delete old notes - Extract labels for categorization --- ## Notes - **No Authentication:** MCP server runs with direct database access (no auth layer) - **Shared Database:** Uses same SQLite file as keep-notes web app - **JSON Encoding:** Array fields (checkItems, labels, images) stored as JSON strings - **Idempotent Operations:** Toggle operations (pin, archive) are idempotent - **Case-Insensitive Search:** Search operations use `mode: 'insensitive'` - **Ordering:** Results sorted by relevance (pinned first, then by date)