memkit
A fully local, persistent memory layer for AI agents that runs as an MCP stdio server and provides an AI SDK adapter for seamless integration with generateText/streamText agents.
README
memkit
A fully local, persistent memory layer for AI agents. Runs as an MCP server over stdio for Claude Desktop, OpenCode, and any MCP client — and also ships a native AI SDK adapter so you can drop it directly into any generateText / streamText agent without any MCP wiring.
Your AI remembers things. Across sessions. Across projects. Without sending anything to the cloud (unless you want it to).
What it does
Every time your AI learns something worth keeping, it calls add_memory. That memory gets embedded into a vector, stored in a local SQLite database, and automatically linked to similar memories in the same project through a lightweight graph.
When the AI needs to recall something, it calls search_memory. Semantic search finds the closest matches, and optionally walks the graph one hop out to surface related context the AI might not have thought to ask for.
Three tables. Six tools. One SQLite file on your disk.
How it works
Your AI agent
|
|--- AI SDK adapter (import "code-memory/adapter")
| |
| |-- memoryTools injected into generateText/streamText
| |-- memoryMiddleware auto recall + auto store via wrapLanguageModel
| |-- MemoryEmbeddingModel AI SDK-compatible EmbeddingModelV3
|
|--- MCP stdio server (bun run start)
| |
| | stdio (JSON-RPC)
|
|--- Embedding Backend (ollama / openai)
|
|--- SQLite
|-- session
|-- memory (content + embedding blob)
|-- memory_edge (similarity links)
When you add a memory:
- Text gets embedded via your chosen backend
- Inserted into SQLite with the embedding as a raw float32 blob
- Similarity scan runs against all memories in the same project
- Any pair above the threshold (default 0.82 cosine similarity) gets a graph edge
When you search:
- Query gets embedded
- Cosine similarity computed against all project memories
- Results ranked and filtered by minimum score
- If
expand_graphis on, neighbors of top results are pulled in
AI SDK Adapter
This is the recommended way to use code-memory when building agents with the Vercel AI SDK. No MCP client, no subprocess, no boilerplate — just import and go.
Install
bun add memkit ai
# or
npm install memkit ai
Set your embedding backend env vars (see Configuration below), then:
createMemory — one call setup
import { createMemory } from "memkit/adapter"
import { streamText, stepCountIs } from "ai"
import { openai } from "@ai-sdk/openai"
const memory = createMemory({
projectId: "my-app",
sessionId: "user-abc",
})
// Wrap your model — auto recall before generation, auto store after
const model = memory.wrapModel(openai("gpt-4o"))
const result = await streamText({
model,
tools: { ...memory.tools },
stopWhen: stepCountIs(10),
messages,
})
That's it. Every call to streamText or generateText will:
- Search for relevant past memories and inject them into the system prompt
- Store the assistant's response as a new memory after generation
memoryMiddleware — manual control
If you want to wire the middleware yourself via wrapLanguageModel:
import { wrapLanguageModel, streamText } from "ai"
import { memoryMiddleware } from "memkit/adapter"
import { anthropic } from "@ai-sdk/anthropic"
const model = wrapLanguageModel({
model: anthropic("claude-sonnet-4-5"),
middleware: memoryMiddleware({
projectId: "my-app",
sessionId: "user-abc",
searchOptions: {
limit: 5, // top memories to inject (default: 5)
minScore: 0.55, // similarity threshold (default: 0.55)
expandGraph: true // pull in graph neighbors (default: false)
},
autoRecall: true, // inject memories before generation (default: true)
autoStore: true, // store assistant replies after generation (default: true)
// optional: customize the memory block injected into the system prompt
systemPromptTemplate: (memories) =>
`<memory>\n${memories.map(m => m.content).join("\n")}\n</memory>`,
}),
})
const result = await streamText({ model, messages })
memoryTools — explicit tool use
Give the model direct control over memory. Useful when you want the model to decide what to remember rather than auto-storing everything.
import { generateText, stepCountIs } from "ai"
import { memoryTools } from "memkit/adapter"
import { openai } from "@ai-sdk/openai"
const result = await generateText({
model: openai("gpt-4o"),
tools: { ...memoryTools },
stopWhen: stepCountIs(10),
system: `You have persistent memory. Use add_memory to store important context.
Use search_memory before answering questions that might benefit from past context.`,
messages,
})
Available tools: add_memory, search_memory, delete_memory, list_sessions, get_graph, forget_session.
createMemoryAsync — with embedding model
If you also need the EmbeddingModel (for embed() / embedMany() calls), use the async factory:
import { createMemoryAsync } from "memkit/adapter"
import { embed } from "ai"
const memory = await createMemoryAsync({
projectId: "my-app",
sessionId: "user-abc",
})
// memory.embeddingModel is a fully typed EmbeddingModelV3
const { embedding } = await embed({
model: memory.embeddingModel,
value: "some text to embed",
})
Adapter API reference
| Export | Type | Description |
|---|---|---|
createMemory(config) |
sync | Returns { tools, middleware, wrapModel } |
createMemoryAsync(config) |
async | Same + embeddingModel resolved |
memoryTools |
object | All 6 tools as a named map, spread into tools |
memoryMiddleware(config) |
function | LanguageModelMiddleware for wrapLanguageModel |
getMemoryEmbeddingModel() |
async | Returns a MemoryEmbeddingModel (EmbeddingModelV3) |
MemoryEmbeddingModel |
class | AI SDK-compatible embedding model class |
CreateMemoryConfig:
{
projectId: string
sessionId: string
searchOptions?: {
limit?: number // default 5
minScore?: number // default 0.55
expandGraph?: boolean // default false
}
autoStore?: boolean // default true
autoRecall?: boolean // default true
systemPromptTemplate?: (memories: SearchResult[]) => string
}
MCP Server
The stdio MCP server works unchanged for non-AI-SDK consumers.
Getting started
You need bun and an embedding backend. The easiest local option is ollama:
curl -fsSL https://ollama.ai/install.sh | sh
ollama pull nomic-embed-text
git clone https://github.com/xmanish/memkit.git
cd memkit
bun install
bun run start
With Claude Desktop
Add to ~/Library/Application Support/Claude/claude_desktop_config.json on macOS:
{
"mcpServers": {
"memory": {
"command": "bun",
"args": ["run", "/path/to/memkit/src/server.ts"],
"env": {
"EMBEDDING_BACKEND": "ollama"
}
}
}
}
With OpenCode
Add to .opencode/config.json:
{
"mcp": {
"memory": {
"type": "stdio",
"command": "bun",
"args": ["run", "/path/to/code-memory/src/server.ts"],
"env": {
"EMBEDDING_BACKEND": "ollama"
}
}
}
}
Via AI SDK MCP client
import { streamText, experimental_createMCPClient } from "ai"
const mcp = await experimental_createMCPClient({
transport: {
type: "stdio",
command: "bun",
args: ["run", "/path/to/code-memory/src/server.ts"],
},
})
const tools = await mcp.tools()
const result = await streamText({
model: "anthropic/claude-sonnet-4-5",
tools,
messages,
system: `You have persistent memory. Use add_memory to store important context.
Use search_memory before answering questions that benefit from past context.`,
})
Configuration
All configuration is via environment variables:
# embedding backend: "ollama" (default) or "openai"
EMBEDDING_BACKEND=ollama
# ollama
OLLAMA_BASE_URL=http://localhost:11434
OLLAMA_EMBED_MODEL=nomic-embed-text
# openai (only needed if EMBEDDING_BACKEND=openai)
OPENAI_API_KEY=sk-...
OPENAI_EMBED_MODEL=text-embedding-3-small
# database location
DB_PATH=~/.memkit/memory.db
# graph linking
EDGE_THRESHOLD=0.82
EDGE_TOP_K=10
Tools reference
add_memory
Store something the AI should remember.
{
"content": "The user prefers dark mode and uses vim keybindings",
"session_id": "sess_abc123",
"project_id": "proj_myapp",
"metadata": { "source": "user_preference" }
}
Returns { "id": "mem_...", "linked_count": 3 }.
search_memory
Find relevant memories by meaning.
{
"query": "what editor settings does the user like",
"project_id": "proj_myapp",
"limit": 5,
"min_score": 0.6,
"expand_graph": true
}
get_graph
Traverse the memory graph from any node.
{ "memory_id": "mem_abc123", "depth": 2 }
Returns { "nodes": [...], "edges": [...] }.
delete_memory
{ "id": "mem_abc123" }
list_sessions
{ "project_id": "proj_myapp" }
forget_session
Delete all memories for a session.
{ "session_id": "sess_abc123" }
How the graph works
When you add a memory it doesn't just sit in a table. It gets compared against every other memory in the project and any pair with similarity above the threshold gets linked.
"user likes dark mode" ----0.91---- "prefers dark themes in all apps"
|
0.85
|
"UI should default to dark"
A search for "theme preferences" might directly hit "user likes dark mode", and graph expansion pulls in "UI should default to dark" even if that memory's embedding isn't a top match for the query.
Project structure
code-memory/
src/
server.ts MCP stdio server, tool routing
memory.ts core logic: add, search, graph traversal
db.ts SQLite setup, migrations, cosine similarity
types.ts zod schemas for all inputs and outputs
embeddings/
index.ts backend factory (ollama | openai)
ollama.ts ollama embedding client
openai.ts openai embedding client
adapter/ AI SDK integration layer
index.ts public exports
tools.ts AI SDK tool() definitions
middleware.ts LanguageModelMiddleware — auto recall + store
embedding-model.ts EmbeddingModelV3 adapter
create-memory.ts createMemory() / createMemoryAsync() factories
package.json
tsconfig.json
README.md
Roadmap
- Memory compaction (summarize old memories to save space)
- TTL / expiry on memories
- Better graph algorithms (PageRank-style importance scoring)
- npm package
License
MIT
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
Neon Database
MCP server for interacting with Neon Management API and databases
E2B
Using MCP to run code via e2b.
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.