## 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
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
McpErrorwithErrorCode.InternalErroron 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
McpErrorwithErrorCode.InternalErroron 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
McpErrorwithErrorCode.InvalidRequestif note not found - Throws
McpErrorwithErrorCode.InternalErroron 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
updatedAttimestamp - Arrays (checkItems, labels, images) are JSON-encoded before storage
Error Response:
- Throws
McpErrorwithErrorCode.InternalErroron 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
McpErrorwithErrorCode.InternalErroron 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
titleandcontentfields - Uses SQL
LIKEoperator (contains matching)
Ordering: isPinned DESC, updatedAt DESC
Error Response:
- Throws
McpErrorwithErrorCode.InternalErroron 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
labelsfield - Returns unique, sorted list of all label strings
- Does not create or use the Label table (reads directly from Note.labels)
Error Response:
- Throws
McpErrorwithErrorCode.InternalErroron 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
McpErrorwithErrorCode.InvalidRequestif note not found - Throws
McpErrorwithErrorCode.InternalErroron 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
McpErrorwithErrorCode.InvalidRequestif note not found - Throws
McpErrorwithErrorCode.InternalErroron 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 foundErrorCode.MethodNotFound: Unknown tool requestedErrorCode.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:
- Install N8N MCP integration
- Configure connection to
memento-mcp-server - 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)