Keep/docs/api-contracts-mcp-server.md
sepehr 640fcb26f7 fix: improve note interactions and markdown LaTeX support
## Bug Fixes

### Note Card Actions
- Fix broken size change functionality (missing state declaration)
- Implement React 19 useOptimistic for instant UI feedback
- Add startTransition for non-blocking updates
- Ensure smooth animations without page refresh
- All note actions now work: pin, archive, color, size, checklist

### Markdown LaTeX Rendering
- Add remark-math and rehype-katex plugins
- Support inline equations with dollar sign syntax
- Support block equations with double dollar sign syntax
- Import KaTeX CSS for proper styling
- Equations now render correctly instead of showing raw LaTeX

## Technical Details

- Replace undefined currentNote references with optimistic state
- Add optimistic updates before server actions for instant feedback
- Use router.refresh() in transitions for smart cache invalidation
- Install remark-math, rehype-katex, and katex packages

## Testing

- Build passes successfully with no TypeScript errors
- Dev server hot-reloads changes correctly
2026-01-09 22:13:49 +01:00

10 KiB

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:

{
  "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):

{
  "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:

{
  "includeArchived": "boolean (optional, default: false) - Include archived notes",
  "search": "string (optional) - Search query to filter notes (case-insensitive)"
}

Response (text content):

[
  {
    "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:

{
  "id": "string (required) - Note ID"
}

Response (text content):

{
  "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:

{
  "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):

{
  "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:

{
  "id": "string (required) - Note ID"
}

Response (text content):

{
  "success": true,
  "message": "Note deleted"
}

Error Response:

  • Throws McpError with ErrorCode.InternalError on failure

search_notes

Search notes by query.

Parameters:

{
  "query": "string (required) - Search query"
}

Response (text content):

[
  {
    "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:

{}

Response (text content):

[
  "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:

{
  "id": "string (required) - Note ID"
}

Response (text content):

{
  "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:

{
  "id": "string (required) - Note ID"
}

Response (text content):

{
  "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

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:

// 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:

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)