Skip to content

Build a Memory-Enabled MCP Server

The Model Context Protocol (MCP) lets AI assistants like Claude Desktop, Cursor, and Windsurf use external tools. With Recall’s MCP server, you can give any MCP-compatible assistant persistent memory.

After this tutorial, your AI assistant will be able to:

  • Remember facts you tell it across sessions
  • Recall information when relevant to conversations
  • Update memories when information changes
  • Forget things when you ask it to

Option 1: Use the Pre-built Server (Easiest)

Section titled “Option 1: Use the Pre-built Server (Easiest)”

Recall provides a ready-to-use MCP server. Just install and configure.

Terminal window
npm install -g @youcraft/recall-mcp-server

Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):

{
"mcpServers": {
"recall": {
"command": "recall-mcp",
"args": ["--db", "~/memories.db"],
"env": {
"OPENAI_API_KEY": "sk-your-api-key"
}
}
}
}

Edit .cursor/mcp.json in your project or home directory:

{
"mcpServers": {
"recall": {
"command": "recall-mcp",
"args": ["--db", "~/memories.db"],
"env": {
"OPENAI_API_KEY": "sk-your-api-key"
}
}
}
}

Similar configuration in their respective settings files.

Restart Claude Desktop, Cursor, or your MCP client. You should see “recall” tools available.

Tell your assistant:

“Remember that my favorite programming language is TypeScript and I prefer functional programming.”

Later, ask:

“What do you know about my programming preferences?”

It will recall the information you stored!

The MCP server provides these tools:

ToolDescription
memory_storeStore a new memory
memory_queryFind relevant memories
memory_listList all memories
memory_updateUpdate an existing memory
memory_deleteDelete a memory
memory_clearDelete all memories

For more control, build your own server using the @youcraft/recall-mcp package.

Terminal window
mkdir my-memory-server
cd my-memory-server
npm init -y
npm install @youcraft/recall @youcraft/recall-mcp \
@youcraft/recall-adapter-sqlite @youcraft/recall-embeddings-openai \
@youcraft/recall-extractor-openai @modelcontextprotocol/sdk

Create server.ts:

import { Server } from '@modelcontextprotocol/sdk/server/index.js'
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
import { createMemory } from '@youcraft/recall'
import { createMcpTools, handleMcpToolCall } from '@youcraft/recall-mcp'
import { sqliteAdapter } from '@youcraft/recall-adapter-sqlite'
import { openaiEmbeddings } from '@youcraft/recall-embeddings-openai'
import { openaiExtractor } from '@youcraft/recall-extractor-openai'
// Create memory instance
const memory = createMemory({
db: sqliteAdapter({ filename: process.env.DB_PATH || 'memories.db' }),
embeddings: openaiEmbeddings({ apiKey: process.env.OPENAI_API_KEY! }),
extractor: openaiExtractor({ apiKey: process.env.OPENAI_API_KEY! }),
})
// Create MCP server
const server = new Server(
{ name: 'my-memory-server', version: '1.0.0' },
{ capabilities: { tools: {} } }
)
// Register tools
server.setRequestHandler('tools/list', async () => ({
tools: createMcpTools(),
}))
// Handle tool calls
server.setRequestHandler('tools/call', async request => {
const { name, arguments: args } = request.params
// Default userId - in production, get this from auth
const userId = args.userId || 'default'
return handleMcpToolCall(memory, name, { ...args, userId })
})
// Start server
const transport = new StdioServerTransport()
await server.connect(transport)

Extend with your own tools:

import { createMcpTools } from '@youcraft/recall-mcp'
// Get base tools
const baseTools = createMcpTools()
// Add custom tools
const allTools = [
...baseTools,
{
name: 'memory_summarize',
description: 'Get a summary of all memories for a user',
inputSchema: {
type: 'object',
properties: {
userId: { type: 'string', description: 'User ID' },
},
required: ['userId'],
},
},
]
server.setRequestHandler('tools/list', async () => ({
tools: allTools,
}))
server.setRequestHandler('tools/call', async request => {
const { name, arguments: args } = request.params
if (name === 'memory_summarize') {
const memories = await memory.list(args.userId)
return {
content: [
{
type: 'text',
text: `User has ${memories.length} memories:\n${memories
.map(m => `- ${m.content}`)
.join('\n')}`,
},
],
}
}
return handleMcpToolCall(memory, name, args)
})
Terminal window
npx tsc

Configure your MCP client to use your custom server:

{
"mcpServers": {
"my-memory": {
"command": "node",
"args": ["/path/to/my-memory-server/server.js"],
"env": {
"OPENAI_API_KEY": "sk-your-api-key",
"DB_PATH": "~/my-memories.db"
}
}
}
}

For applications with multiple users, pass the userId dynamically:

server.setRequestHandler('tools/call', async request => {
const { name, arguments: args } = request.params
// Get userId from the request context or arguments
const userId = args.userId || request.context?.userId || 'anonymous'
return handleMcpToolCall(memory, name, { ...args, userId })
})

For production deployments, use PostgreSQL instead of SQLite:

Terminal window
npm install @youcraft/recall-adapter-postgresql pg pgvector
import { postgresAdapter } from '@youcraft/recall-adapter-postgresql'
const memory = createMemory({
db: postgresAdapter({
connectionString: process.env.DATABASE_URL!,
usePgVector: true,
}),
embeddings: openaiEmbeddings({ apiKey: process.env.OPENAI_API_KEY! }),
extractor: openaiExtractor({ apiKey: process.env.OPENAI_API_KEY! }),
})

Run the server manually to see logs:

Terminal window
OPENAI_API_KEY=sk-xxx recall-mcp --db ./test.db

Use the MCP inspector:

Terminal window
npx @modelcontextprotocol/inspector recall-mcp --db ./test.db

Query your database directly:

Terminal window
sqlite3 memories.db "SELECT * FROM memories"
  1. API Keys: Never commit API keys. Use environment variables.
  2. User Isolation: Always scope memories by userId to prevent data leaks.
  3. Database Location: Store the database in a secure location.
  4. Input Validation: The MCP server validates inputs, but add additional checks for production.