# Architecture - mcp-server (MCP Server) ## Overview Architecture documentation for the Memento MCP (Model Context Protocol) server, an Express-based microservice that provides AI assistant and automation integration for the Memento note-taking application. **Architecture Pattern:** Microservice API **Framework:** Express.js 4.22.1 **Protocol:** MCP SDK 1.0.4 **Language:** JavaScript (ES modules) **Database:** Shared SQLite via Prisma --- ## Technology Stack ### Core | Technology | Version | Purpose | |------------|---------|---------| | Node.js | 20+ | Runtime | | Express.js | 4.22.1 | Web framework | | MCP SDK | 1.0.4 | Model Context Protocol | | Prisma | 5.22.0 | ORM | ### Transport - **Primary:** Stdio (standard input/output) - **Alternative:** Server-Sent Events (SSE) via `index-sse.js` ### Database - **ORM:** Prisma 5.22.0 - **Database:** SQLite (shared with keep-notes) - **File:** `../keep-notes/prisma/dev.db` --- ## Architecture Pattern: Microservice ### System Architecture ``` ┌─────────────────┐ │ MCP Client │ │ (AI Assistant) │ │ N8N Workflow │ └────────┬────────┘ │ MCP Protocol ↓ ┌─────────────────┐ │ mcp-server │ │ │ │ MCP Tools: │ │ - create_note │ │ - get_notes │ │ - search_notes │ │ - update_note │ │ - delete_note │ │ - toggle_pin │ │ - toggle_archive│ │ - get_labels │ └────────┬────────┘ │ ↓ ┌─────────────────┐ │ Prisma ORM │ │ │ │ Shared SQLite │ └─────────────────┘ ``` ### Communication Flow 1. **MCP Client** (AI assistant, N8N) connects via stdio 2. **Request:** Tool invocation with parameters 3. **Processing:** Server executes business logic 4. **Database:** Prisma queries/updates 5. **Response:** JSON result returned via stdio --- ## Server Structure ### File Organization ``` mcp-server/ ├── index.js # Main MCP server (stdio transport) ├── index-sse.js # SSE variant (HTTP + SSE) ├── package.json # Dependencies ├── README.md # Server documentation ├── README-SSE.md # SSE documentation ├── N8N-CONFIG.md # N8N setup guide └── prisma/ # Prisma client (shared) ├── schema.prisma # Schema reference └── [generated client] ``` ### Entry Points **Primary: index.js** ```javascript #!/usr/bin/env node import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; // ... tool definitions const transport = new StdioServerTransport(); await server.connect(transport); ``` **Alternative: index-sse.js** ```javascript // HTTP server with Server-Sent Events // For web-based MCP clients ``` --- ## MCP Tool Architecture ### Tool Registration Pattern ```javascript server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ { name: 'create_note', description: 'Create a new note in Memento', inputSchema: { type: 'object', properties: { /* ... */ }, required: ['content'] } }, // ... 7 more tools ] } }); ``` ### Tool Execution Pattern ```javascript server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { switch (name) { case 'create_note': { const note = await prisma.note.create({ /* ... */ }); return { content: [{ type: 'text', text: JSON.stringify(parseNote(note)) }] }; } // ... handle other tools } } catch (error) { throw new McpError(ErrorCode.InternalError, error.message); } }); ``` --- ## Available MCP Tools ### Note Management (6 tools) | Tool | Purpose | Required Params | |------|---------|----------------| | **create_note** | Create note | content | | **get_notes** | List all notes | (optional) includeArchived, search | | **get_note** | Get single note | id | | **update_note** | Update note | id, (optional) fields to update | | **delete_note** | Delete note | id | | **search_notes** | Search notes | query | ### Note Operations (2 tools) | Tool | Purpose | Required Params | |------|---------|----------------| | **toggle_pin** | Toggle pin status | id | | **toggle_archive** | Toggle archive status | id | ### Data Query (1 tool) | Tool | Purpose | Required Params | |------|---------|----------------| | **get_labels** | Get all unique labels | (none) | **Total Tools:** 9 tools --- ## Database Integration ### Connection Details ```javascript const prisma = new PrismaClient({ datasources: { db: { url: `file:${join(__dirname, '../keep-notes/prisma/dev.db')}` } } }); ``` **Path Resolution:** - From `mcp-server/index.js` - To: `../keep-notes/prisma/dev.db` - Absolute: `D:/dev_new_pc/Keep/keep-notes/prisma/dev.db` ### Database Access Pattern **Read Operations:** ```javascript const notes = await prisma.note.findMany({ where: { /* conditions */ }, orderBy: [/* sorting */] }); ``` **Write Operations:** ```javascript const note = await prisma.note.create({ data: { /* note data */ } }); ``` **Update Operations:** ```javascript const note = await prisma.note.update({ where: { id: args.id }, data: { /* updates */ } }); ``` **Delete Operations:** ```javascript await prisma.note.delete({ where: { id: args.id } }); ``` --- ## Data Processing ### JSON Field Parsing **Helper Function:** ```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, }; } ``` **Purpose:** Convert JSON strings from DB to JavaScript objects **Fields Parsed:** - `checkItems`: Array of checklist items - `labels`: Array of label names - `images`: Array of image URLs/data --- ## Error Handling ### MCP Error Pattern ```javascript import { McpError, ErrorCode } from '@modelcontextprotocol/sdk/types.js'; // Not found throw new McpError(ErrorCode.InvalidRequest, 'Note not found'); // Server error throw new McpError(ErrorCode.InternalError, `Tool execution failed: ${error.message}`); // Unknown tool throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`); ``` ### Error Types | Error Code | Usage | |------------|-------| | `InvalidRequest` | Invalid parameters, resource not found | | `MethodNotFound` | Unknown tool requested | | `InternalError` | Server-side failures (DB, parsing, etc.) | --- ## Tool Schemas ### create_note **Input Schema:** ```json { "type": "object", "properties": { "title": { "type": "string" }, "content": { "type": "string" }, "color": { "type": "string", "enum": ["default","red",...] }, "type": { "type": "string", "enum": ["text","checklist"] }, "checkItems": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "text": { "type": "string" }, "checked": { "type": "boolean" } }, "required": ["id","text","checked"] } }, "labels": { "type": "array", "items": { "type": "string" } }, "images": { "type": "array", "items": { "type": "string" } }, "isPinned": { "type": "boolean" }, "isArchived": { "type": "boolean" } }, "required": ["content"] } ``` ### update_note **Input Schema:** ```json { "type": "object", "properties": { "id": { "type": "string" }, "title": { "type": "string" }, "content": { "type": "string" }, "color": { "type": "string" }, "checkItems": { "type": "array", "items": {/*...*/} }, "labels": { "type": "array", "items": { "type": "string" } }, "isPinned": { "type": "boolean" }, "isArchived": { "type": "boolean" }, "images": { "type": "array", "items": { "type": "string" } } }, "required": ["id"] } ``` **Behavior:** Only updates fields provided (partial update) --- ## Transport Layer ### Stdio Transport (Primary) **Implementation:** ```javascript import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; const transport = new StdioServerTransport(); await server.connect(transport); ``` **Use Cases:** - AI assistants (ChatGPT, Claude, etc.) - N8N MCP integration - Command-line tools - Desktop applications **Communication:** - **Input:** STDIN (JSON-RPC messages) - **Output:** STDOUT (JSON-RPC responses) - **Logging:** STDERR (diagnostic messages) ### SSE Transport (Alternative) **File:** `index-sse.js` **Implementation:** HTTP server with Server-Sent Events **Use Cases:** - Web-based clients - Browser integrations - Real-time notifications - Long-running operations --- ## Concurrency Model ### Single-Threaded Event Loop - Node.js event loop - No parallel execution - Sequential request handling ### Database Concurrency - SQLite handles concurrent reads - Single writer limitation - Prisma manages connection ### Scalability **Current:** Single instance **Limitations:** - No load balancing - No automatic failover - Single point of failure **Future Enhancements:** - Multiple instances with connection pooling - PostgreSQL for better concurrency - Redis for session management - Message queue for async operations --- ## Security Architecture ### Current: No Authentication **Rationale:** - Trusted environment (localhost) - AI assistants need full access - Simplified integration ### Security Considerations **Risks:** - No access control - No rate limiting - No audit logging - Direct database access **Recommendations for Production:** 1. Add API key authentication 2. Implement rate limiting 3. Add request logging 4. Restrict to localhost or VPN 5. Use reverse proxy (nginx) for SSL ### Future Security - JWT tokens for authentication - Role-based access control - IP whitelisting - Request signing - Audit logging --- ## Performance Characteristics ### Latency - **Direct DB access:** ~1-5ms per query - **JSON parsing:** ~0.1-0.5ms - **Total tool execution:** ~5-20ms ### Throughput - **Single-threaded:** Limited by CPU - **SQLite:** ~1000-5000 ops/sec - **Bottleneck:** Database I/O ### Optimization Opportunities 1. **Connection pooling:** Reuse Prisma client 2. **Query optimization:** Add indexes 3. **Caching:** Redis for frequent queries 4. **Batching:** Batch multiple operations --- ## Monitoring & Observability ### Current: Basic Logging ```javascript console.error('Memento MCP server running on stdio'); ``` **Logged to:** STDERR (won't interfere with stdio transport) ### Future Monitoring Needs 1. **Request Logging:** Log all tool invocations 2. **Error Tracking:** Sentry, Rollbar 3. **Performance Monitoring:** Query latency 4. **Metrics:** Tool usage statistics 5. **Health Checks:** `/health` endpoint --- ## Deployment Architecture ### Development ```bash cd mcp-server npm install npm start # Connects via stdio ``` ### Production Options **Option 1: Standalone Process** ```bash node /path/to/mcp-server/index.js ``` **Option 2: Docker Container** ```dockerfile FROM node:20-alpine COPY mcp-server/ /app WORKDIR /app RUN npm install CMD ["node", "index.js"] ``` **Option 3: Docker Compose** ```yaml services: mcp-server: build: ./mcp-server volumes: - ./keep-notes/prisma:/app/db ``` **Option 4: Process Manager** - PM2 - Systemd service - Supervisord --- ## Integration Patterns ### N8N Workflow Integration **Setup:** See `N8N-CONFIG.md` **Usage:** 1. Add MCP node in N8N 2. Configure connection to mcp-server 3. Select tools (create_note, search_notes, etc.) 4. Build workflow **Example Workflow:** - Trigger: Webhook - Tool: create_note - Parameters: From webhook data - Output: Created note ### AI Assistant Integration **Supported Assistants:** - ChatGPT (via MCP plugin) - Claude (via MCP plugin) - Custom AI agents **Usage Pattern:** 1. User asks assistant: "Create a note about..." 2. Assistant calls MCP tools 3. Tools execute on Memento DB 4. Results returned to assistant 5. Assistant responds to user --- ## Versioning & Compatibility ### Current Version **Server:** 1.0.0 **MCP Protocol:** 1.0.4 ### Backward Compatibility - Tool schemas evolve - New tools added (non-breaking) - Existing tools maintained ### Versioning Strategy - Semantic versioning (MAJOR.MINOR.PATCH) - MAJOR: Breaking changes - MINOR: New features, backward compatible - PATCH: Bug fixes --- ## Testing Strategy ### Current: Manual Testing - N8N workflow testing - Direct stdio invocation - SSE variant testing ### Recommended Tests 1. **Unit Tests:** Tool execution logic 2. **Integration Tests:** Prisma operations 3. **E2E Tests:** Full MCP protocol flow 4. **Load Tests:** Concurrent tool execution ### Test Tools - Jest for unit tests - Supertest for HTTP endpoints - Playwright for E2E - Artillery for load testing --- ## Configuration Management ### Environment Variables **Current:** Hardcoded (dev.db path) **Recommended:** ```bash DATABASE_URL="file:../keep-notes/prisma/dev.db" LOG_LEVEL="info" PORT="3000" # For SSE variant ``` ### Configuration File **Future:** `config.json` ```json { "database": { "url": "file:../keep-notes/prisma/dev.db" }, "logging": { "level": "info" }, "server": { "name": "memento-mcp-server", "version": "1.0.0" } } ``` --- ## Maintenance & Operations ### Startup ```bash node index.js # Output to stderr: "Memento MCP server running on stdio" ``` ### Shutdown - Send SIGTERM (Ctrl+C) - Graceful shutdown - Close database connections ### Health Checks **Future:** `/health` endpoint ```javascript app.get('/health', (req, res) => { res.json({ status: 'ok', uptime: process.uptime() }) }) ``` --- ## Troubleshooting ### Common Issues **1. Database Connection Failed** - **Symptom:** "Unable to connect to database" - **Cause:** Incorrect path or missing DB file - **Fix:** Verify `../keep-notes/prisma/dev.db` exists **2. Permission Denied** - **Symptom:** "EACCES: permission denied" - **Cause:** File permissions on SQLite DB - **Fix:** chmod 644 dev.db **3. Stdio Not Working** - **Symptom:** No response from server - **Cause:** Client not connected to stdin/stdout - **Fix:** Ensure proper stdio redirection --- ## Future Enhancements ### Short Term 1. Add authentication 2. Implement rate limiting 3. Add request logging 4. Health check endpoint 5. Configuration file support ### Long Term 1. WebSocket support for real-time 2. GraphQL integration 3. Batch operations 4. Transaction support 5. Multi-database support --- ## Summary The mcp-server is a lightweight, focused microservice that: - **Exposes 9 MCP tools** for note management - **Connects directly to SQLite** via Prisma - **Uses stdio transport** for AI/automation integration - **Provides N8N workflow** integration - **Shares database** with keep-notes web app - **Offers SSE variant** for web clients This architecture provides a clean separation of concerns while maintaining data consistency through the shared database layer.