Connect Kireo memory MCP to Cursor
Add the Kireo memory MCP server to Cursor by creating ~/.cursor/mcp.json with one mcpServers.kireo entry that runs npx -y -p @kireo/mcp-server kireo-mcp and passes your ki_sk_ API key. Cursor's Agent then gets eight memory tools. Point Claude Code at the same key and both editors read and write one store.
Before you paste anything
Three prerequisites, and none of them are Cursor settings. You need Node.js 20 or newer on PATH — the package declares "node": ">=20.0.0" in its engines field, so npx can fetch and run it. You need a Kireo API key shaped like ki_sk_… from the API Keys page. And you need to know which of the two config files you want — Cursor documents ~/.cursor/mcp.json in your home directory for tools available everywhere, and <workspace>/.cursor/mcp.json for project-specific ones.
There is no separate install step. The npx invocation in the config is the install: Cursor spawns it, npm resolves @kireo/mcp-server, and the process talks JSON-RPC over stdio.
Sources on this page are split deliberately. Numbers about the server process were measured on a real machine. Statements about Cursor's own behaviour are cited from Cursor's documentation, checked 2026-08-03 — we could not run Cursor on the machine used for the measurements, so nothing here claims a Cursor end-to-end test.
The mcp.json block
Create the file if it does not exist, paste this, save. Same shape either way — put it in ~/.cursor/mcp.json to have Kireo everywhere, or in .cursor/mcp.json at a repo root to scope it to that project.
The -p flag is not optional and not cosmetic. The npm package publishes two binaries — kireo-mcp (the MCP server) and kireo (a CLI) — and neither is named mcp-server, so npx cannot infer which one to run from the package name alone. Running npx -y @kireo/mcp-server exits 1 with npm error could not determine executable to run (measured 2026-08-03, npm 11.11.1). Older copies of this snippet that omit -p were still in circulation when this page was written — including in the package README shipped with 0.2.1. They do not work.
Keeping the key out of a file you might commit
A per-repo .cursor/mcp.json lives inside your repository, and an env block puts a live ki_sk_ key on a path somebody eventually commits. Cursor documents an envFile option for exactly this, and it is available to Kireo because Kireo is a STDIO server: “The envFile option is only available for STDIO servers. Remote servers (HTTP/SSE) do not support envFile” (cursor.com/docs/context/mcp, checked 2026-08-03).
The referenced file holds one line: KIREO_API_KEY=ki_sk_live_.... An absolute path is used above on purpose — Cursor's documentation does not specify how a relative envFile path is resolved, so pinning it removes the question.
Verify it works
Start with the half that does not involve Cursor at all. If the package cannot start in a terminal, it will not start under Cursor either, and the terminal shows you why.
Then open Cursor's Settings → MCP and look for the kireo entry with its eight tools. Cursor's docs do not state whether mcp.json is hot-reloaded after an edit, so we will not claim it either way — if the entry is not there, that screen is the first place to look.
The end-to-end check is to ask the Agent for a health probe. It calls a real tool and reports both halves of the connection at once:
initialize + tools/list handshake in 791–1,106 ms (median 812 ms), returning 8 tools every time — macOS 26.2 arm64, Node v25.8.2, npm 11.11.1, @kireo/mcp-server 0.2.1, measured 2026-08-03. A first run with a cold cache has to download the package first and will be slower; that case was not measured, so no number is given for it.What Cursor's Agent gets 8 tools
These are the eight tools the server registers, in registration order, with the argument limits that actually bite when an agent calls them unattended. Names and constraints are read from packages/mcp-server/src/tools/*.ts and confirmed against a live tools/list handshake with the published build (@kireo/mcp-server 0.2.1, 2026-08-03).
memory_saveWrites one typed record. Required field: content.content 1–8,000 chars · type is one of fact, decision, preference, event, goal, insight, relationship, other (default fact) · returns { id, created_at, schema_version, embedding_status }, not the full recordmemory_searchHybrid semantic + keyword retrieval. Required field: query.query 1–2,000 chars · limit defaults to 10, max 50 · namespace is optional — omitting it widens the query to every bucket on the accountmemory_recallReplays a namespace with no query — the “what were we doing” call.limit defaults to 20, max 50 · order is recency (default) or importance · namespace defaults to "default"memory_getFetches one record when the agent already holds the id.id must match ^mem_[A-Za-z0-9]+$ — the same pattern as update and deletememory_updatePATCH semantics: only the fields you pass are changed.sending id alone is rejected with “Provide at least one field besides id”memory_deleteRemoves a record. Always a soft delete.recoverable for 30 days, then purged automatically · the hard flag is accepted for compatibility and has no effectmemory_list_namespacesEnumerates the buckets on your account.no arguments · returns { name, created_at } per namespace — no per-namespace countsmemory_healthProbes local process and remote API in one call.no arguments · returns local { server_version, node_version, platform } and remote { status }
One rule applies to all eight: every input schema is strict (additionalProperties: false). An extra field an agent invents is rejected with InvalidParams — it is not silently ignored. The same strictness applies to values: namespace must match ^[a-z0-9_-]{1,32}$ (no uppercase, no dots, no slashes), tags must match ^[a-z0-9_-]+$, and metadata must serialise to 2,048 bytes or less.
Two behaviours are worth knowing before you tune anything. min_score on memory_search is not an API parameter — it is applied client-side inside the MCP server, afterlimit has already been enforced server-side, so a threshold returns fewer rows than limit rather than digging deeper for replacements. And memory_recall with order: "importance" pages through at most the 1,000 most recent rows and sorts those locally, always returning next_cursor: null — it is a recency-weighted importance ranking, not a ranking of your whole history.
Three things specific to Cursor
1. Write "type": "stdio" even though the docs' example omits it
Cursor's MCP documentation is internally inconsistent here: its STDIO field table marks type as required, while the example JSON further down the same page leaves it out (cursor.com/docs/context/mcp, checked 2026-08-03). The config at the top of this page includes it, because every real config we could inspect carries it — the entries already present in this machine's ~/.cursor/mcp.json have the field names type, command, args, and Claude Code writes "type": "stdio" into the .mcp.json it generates. Most copies of the Kireo snippet in circulation predate this and omit type. Adding it costs nothing and removes a variable.
2. envFile exists here and does not exist in Claude Code
This is the one place the two configs genuinely diverge rather than just looking different. Cursor gives STDIO servers an envFile option; Claude Code instead expands ${VAR} references inside .mcp.json. If you are keeping a per-repo config, use the envFile variant shown above rather than porting the Claude Code pattern across — ${VAR} has no meaning to Cursor, and an unexpanded literal fails the server's key check (^ki_sk_[A-Za-z0-9_-]+$) at startup.
Both key failures are loud in the right place and invisible in the wrong one. Missing key: [kireo-mcp] fatal: Error: Invalid Kireo configuration: KIREO_API_KEY (apiKey): Required. Wrong shape (an sk-… key pasted by habit, say): KIREO_API_KEY must look like ki_sk_xxx. Both were reproduced on 2026-08-03; both go to stderr and exit 1, which is why the host usually only shows you “failed to connect”.
3. A broken Kireo entry fails quietly, by design
Cursor “isolates server failures to prevent one server from affecting others” (cursor.com/docs/context/mcp, checked 2026-08-03). That is the right behaviour and it has a cost: when the kireo entry dies, your other MCP servers keep working and the failure reads as “the memory tools just aren't there”. A server you toggled off in settings — Cursor supports toggling servers on and off without removing them — produces the identical symptom.
~/.kireo/logs/ on macOS, Linux and Windows alike, but the files on disk are mcp-server.log.1, .log.2, .log.3 — there is no plain mcp-server.log, so the command everyone types first returns “no such file” (checked on this machine, 2026-08-03). Turning the level up with KIREO_LOG_LEVEL=debug is safe over stdio: logs go to those rotating files plus stderr and never to stdout, so they cannot corrupt the JSON-RPC stream.FAQ
Should the Kireo entry go in ~/.cursor/mcp.json or the project’s .cursor/mcp.json?
Cursor documents both: ~/.cursor/mcp.json in your home directory for tools available everywhere, and .cursor/mcp.json inside a project for project-specific tools (cursor.com/docs/context/mcp, checked 2026-08-03). The Kireo memory MCP server keeps no per-project state — the namespace argument is what separates projects — so the global file is usually enough. Use the per-repo file when a client project needs its own API key.
Will Cursor and Claude Code really see the same memories?
Yes, when both client entries carry the same ki_sk_ key. Every request the server makes sends Authorization: Bearer <key>, and stored rows carry a user_id, so two entries holding one key are one account. Save from Cursor into namespace "acme-api" and memory_recall with that namespace from Claude Code returns it. memory_search with namespace omitted searches every namespace on the account.
Cursor shows no Kireo tools and no error. What do I check?
Cursor isolates server failures so that one server cannot affect the others (cursor.com/docs/context/mcp, checked 2026-08-03), which is exactly why a broken entry reads as silence rather than an error. Check the kireo entry under Settings → MCP and confirm it is not toggled off, then read ~/.kireo/logs/. The files are rotated — mcp-server.log.1, .log.2, .log.3 — there is no plain mcp-server.log. A missing or malformed key kills the process at startup with a fatal line on stderr naming KIREO_API_KEY.
Where does memory text go, and is it sent to a third-party AI provider?
Kireo’s privacy page states: "Your memory content and its embeddings stay on our own infrastructure (Hetzner compute); account metadata lives in Neon Postgres; encrypted off-site backups go to Cloudflare R2. Your memory text is never sent to a third-party AI or embedding provider." The server sends Authorization, Accept-Language, X-Client and X-Request-Id on every request, plus X-Device-Id only while telemetry is on — set KIREO_TELEMETRY=0 to drop it. Local log files redact authorization headers, API keys, tokens and passwords.
Is sharing memory across editors unique to the Kireo memory MCP server?
No, and it would be dishonest to claim it. It is a property of MCP itself, which the specification describes as an open standard inspired by the Language Server Protocol — implement a server once, connect any compliant host (modelcontextprotocol.io/specification/latest, checked 2026-08-03). Other memory servers do it too: mem0’s OpenMemory MCP is local-first and keeps everything on your own machine across Cursor, Claude Desktop, Windsurf and Cline (mem0.ai/blog/introducing-openmemory-mcp, checked 2026-08-03), and Graphiti, the Apache-2.0 temporal knowledge-graph engine behind Zep, ships an MCP server of its own (github.com/getzep/graphiti, checked 2026-08-03). Kireo’s trade is the opposite one: a hosted store you do not operate, with a web UI for reading and deleting what was written.