MCP Server
The local CortexDB MCP package for Claude, Cursor, Windsurf, VS Code Copilot and any MCP client that starts a local server; the CortexDB server itself also serves remote MCP over HTTP.
cortexdb-mcp is a small bridge process that exposes CortexDB to any Model Context Protocol client
that starts a local server: Claude Desktop, Claude Code, Cursor, Windsurf, VS Code Copilot. It speaks
MCP over stdio on the person's computer and calls your CortexDB server's REST API.
Remote MCP: the server serves /mcp itself
For an MCP client that connects to a server by URL instead, including connector apps such as ChatGPT
and Claude, CortexDB 0.14.0 serves MCP over HTTP at /mcp, with OAuth sign-in (CORTEX_MCP=on, off by
default). See Connecting AI Assistants.
Requires Python 3.10+. cortexdb-mcp doesn't install on Python 3.9 — pip refuses with
"Requires-Python >=3.10". macOS users on Apple's bundled Python 3.9 need a newer interpreter first:
brew install python@3.11 (then python3.11 -m pip install …), or use pipx / uv which manage
their own Python.
Installation
# pip (any Python 3.10+ venv)
pip install 'cortexdb-mcp>=0.9.0'
# pipx — recommended on macOS/Linux; auto-isolates the install
pipx install --python python3.11 'cortexdb-mcp>=0.9.0'
# uv — fastest; pulls its own Python if needed
uvx --python 3.11 cortexdb-mcp --helpThe PyPI package is cortexdb-mcp, not cortexdbai-mcp (which does not exist on PyPI). The
current release is listed in
Versioning and SDK compatibility; if you run an
older one, see Upgrading.
Verify it's on your PATH:
cortexdb-mcp --version # cortexdb-mcp 0.9.0
cortexdb-mcp --helpThe binary takes two options. --transport accepts only stdio: this package runs next to the
assistant (for an HTTP endpoint, use the server's own /mcp).
--tool-profile all|read|write|code (or CORTEXDB_TOOL_PROFILE) selects the tool surface; see
Tool profiles. 0.9.0 is the release for CortexDB 0.14.0; against an older server the
tools it adds answer 404.
Windows: use the full .exe path
On Windows, use the full path to cortexdb-mcp.exe (e.g.
%LOCALAPPDATA%\Programs\Python\Python313\Scripts\cortexdb-mcp.exe) in the MCP config — Windows MCP
clients don't resolve bare command names through PATH reliably.
Setup
Every MCP client uses a JSON config file. The structure is the same everywhere — only the file path differs. There are three ways to set it up.
Option A — CortexDB Cloud
Create an API token on your dashboard, which also shows your actor and default scope, and give the server all four:
{
"mcpServers": {
"cortexdb": {
"command": "cortexdb-mcp",
"env": {
"CORTEXDB_URL": "https://api.cortexdb.ai",
"CORTEXDB_API_KEY": "<your API token>",
"CORTEXDB_ACTOR": "user:acct_42",
"CORTEXDB_SCOPE": "org:acct_42/user:acct_42"
}
}
}
}The token lasts 90 days; replace it with a new one from the dashboard. Every tool call counts against
your plan. With no CORTEXDB_API_KEY the server tries an anonymous
POST /v1/auth/signup against CORTEXDB_URL instead; CortexDB Cloud has signup off (its accounts come
from cortexdb.ai), and a self-hosted server only allows it with its dev minter on, so set the key.
Option B — Bring your own token (your own IdP)
Set these env vars so the server skips signup and uses the credentials you supply:
CORTEXDB_API_KEY— The bearer credential: a person's or an agent's token minted viaPOST /v1/auth/tokens, or a token from your identity provider through the server's issuers file.CORTEXDB_ACTOR— Sent asX-Cortex-Actor. Optional since 0.9.0: left unset, it is the token'ssubwhen that names an actor (user:,agent:,service:,system:). SetCORTEXDB_ACTOR=-for an identity provider's token whose issuer maps the subject itself; the server takes it alone.CORTEXDB_SCOPE— The default scope path tools use when one isn't passed explicitly. Optional when signup supplied one; otherwise required (a tool call without a scope fails withno scope configured; it does not fall back to the actor).
Option C — Self-hosted server
Point CORTEXDB_URL at your server and supply the server's key as the bearer. CORTEXDB_SCOPE is
required here (a self-hosted server normally has no signup to derive one from); a tool call without a
scope fails with no scope configured.
{
"mcpServers": {
"cortexdb": {
"command": "cortexdb-mcp",
"env": {
"CORTEXDB_URL": "http://localhost:3141",
"CORTEXDB_API_KEY": "<the server's CORTEX_API_KEY value>",
"CORTEXDB_ACTOR": "user:alice",
"CORTEXDB_SCOPE": "user:alice"
}
}
}
}On a server started with CORTEX_INSECURE_NO_AUTH=1, omit CORTEXDB_API_KEY (no Authorization
header is sent; the server serves each request as the X-Cortex-Actor the MCP server sends from
CORTEXDB_ACTOR, or user:local without one) but keep CORTEXDB_SCOPE. See
Self-hosting defaults and the
authorization note on presets.
The operator key under the deny mode
On a cloud_shared_saas server the operator key's reads of memories need a break-glass header
(Operator Modes), and every tool that reads answers
BREAK_GLASS_REQUIRED without one. Prefer a person's own token. For genuine operator work, set
CORTEXDB_BREAK_GLASS_REASON (incident, legal, support, security, migration, restore or
other) and CORTEXDB_BREAK_GLASS_TICKET (your case reference); every request then carries the
header and is audited.
Local state
The server stores its credentials (and only its credentials) under:
- macOS / Linux:
$XDG_CONFIG_HOME/cortexdb-mcp/state.json(default~/.config/cortexdb-mcp/state.json) - Windows:
%APPDATA%\cortexdb-mcp\state.json
The file is mode 0600 on POSIX. Contents: { "token", "actor", "scope", "expires_at" } — the values
POST /v1/auth/signup returned (user_id is stored as actor; expires_at when the mint reported
one, used to sign up again on expiry). No memories are stored locally. It is only read
when CORTEXDB_API_KEY is unset; an explicit env key always wins. Delete the file to force a re-signup on the next call.
This path and key set differ from the CLI's state file
The MCP server reads <APPDATA|XDG>/cortexdb-mcp/state.json, while the CLI and connectors use
~/.cortexdb/state.json — and the CLI writes the actor under user_id, not actor. Reusing one
anonymous identity across both tools means copying the file to the other tool's path and renaming
user_id ↔ actor — see CLI configuration.
Per-client configuration
The JSON blocks below show a token in the env block (Options A and B). For a self-hosted
server use the Option C env block instead.
Claude Desktop
macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
Windows: %APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"cortexdb": {
"command": "cortexdb-mcp",
"env": {
"CORTEXDB_API_KEY": "v4.public.eyJpc3MiOi...",
"CORTEXDB_ACTOR": "user:u_019e2f...",
"CORTEXDB_SCOPE": "org:u_019e2f.../user:u_019e2f..."
}
}
}
}Claude Code (CLI)
claude mcp add cortexdb \
-e CORTEXDB_URL=https://api-v1.cortexdb.ai \
-e CORTEXDB_API_KEY=v4.public... \
-e CORTEXDB_ACTOR=user:u_019e... \
-e CORTEXDB_SCOPE=org:u_019e.../user:u_019e... \
-- cortexdb-mcpThe server's name comes first: -e takes several values, so a name written after the -e flags is
read as one more variable (and the command fails with missing required argument 'commandOrUrl').
Everything after -- is the server's own command line, so -- cortexdb-mcp --tool-profile write adds
the write tools. Add --scope user to make the server available in every project, or
--scope project to write it to a shareable .mcp.json in the repository root. Without --scope,
Claude Code stores the entry in ~/.claude.json (local scope, this project only); there is no
~/.claude/mcp.json. To edit by hand, put the same mcpServers block into .mcp.json (project) or
~/.claude.json (user/local).
For the server's own remote MCP endpoint, Claude Code takes the URL and a header instead:
claude mcp add --transport http cortexdb https://memory.acme.example/mcp --header "Authorization: Bearer <token>"
(Connecting AI Assistants).
Cursor
Edit ~/.cursor/mcp.json:
{
"mcpServers": {
"cortexdb": {
"command": "cortexdb-mcp",
"env": {
"CORTEXDB_URL": "https://api-v1.cortexdb.ai",
"CORTEXDB_API_KEY": "v4.public...",
"CORTEXDB_ACTOR": "user:u_019e...",
"CORTEXDB_SCOPE": "org:u_019e.../user:u_019e..."
}
}
}
}Windsurf
Edit ~/.codeium/windsurf/mcp_config.json (same mcpServers block as Cursor).
VS Code (GitHub Copilot)
Add to .vscode/mcp.json (project) or ~/.vscode/mcp.json (global). Note the key is servers, not
mcpServers:
{
"servers": {
"cortexdb": {
"command": "cortexdb-mcp",
"env": {
"CORTEXDB_URL": "https://api-v1.cortexdb.ai",
"CORTEXDB_API_KEY": "v4.public...",
"CORTEXDB_ACTOR": "user:u_019e...",
"CORTEXDB_SCOPE": "org:u_019e.../user:u_019e..."
}
}
}
}Tools exposed
The default profile, all, lists 33 tools; write lists 35, read 26 and code 4. The server
also registers 3 resources (cortexdb://health, cortexdb://episodes, cortexdb://insights) and 5
prompts. Since 0.9.0 a tool refuses an argument it does not take (it used to drop it), and every tool
carries MCP annotations (readOnlyHint, destructiveHint, idempotentHint), so a client can ask
before a destructive call.
Matched spans and code citations
memory_searchshows matched document spans. For a long (chunked) document the reply ends with--- N matched document span(s) ---: one line per chunk a retrieval channel matched, with the event id, the channel (bm25orvector) and the section path, for exampleevt_… [bm25] Handbook > VPN troubleshooting: …. Needs server capabilitymatched_fragments_v1; short memories, and servers without that capability, show nothing extra. When the server serves an excerpt of the document, the span line names the section but carries no span text.- Code tools describe citations as
repo:path@<snippet-hash>#Lstart-Lend(the hash covers the snippet, not a git commit) and label call-graph nodes by their qualified C++ name (buffered_file::close).
Every tool that takes a scope accepts it as
tenant_id (a legacy name — it is a v1 scope path) and falls back to CORTEXDB_SCOPE.
Memory
| MCP tool | v1 endpoint | Notes |
|---|---|---|
memory_store | POST /v1/experience | Wraps free-form text in a conversation envelope with a fresh idempotency_key (or the one you pass); source / episode_type become source: / type: labels; namespace appends /ns:<name> to the scope; provenance names the events it was made from; consistency returns a token to read the write back with. ttl_seconds is accepted but ignored (the reply says so). Returns captured immediately — it does not wait for indexing — and names where a redirected write landed (redirected_to). |
memory_status | GET /v1/experience/status | Did a store land? Check by event_id or idempotency_key (keys are kept 24 h) after a timeout. |
memory_search | POST /v1/recall | Sends view only when CORTEXDB_VIEW is set, so the server picks (holistic, or granular at a shared org-tree scope); diagnostics="none" so free-tier tokens succeed. Takes extra_scopes (up to 40), coverage, at_least and purpose. Shows the first max_results memories from the pack's context_block, falling back to derived facts. |
get_context | POST /v1/recall | Same call, rendered as memories + facts + beliefs for "what should I know before I respond". include_graph only adds a hint line. |
advanced_search | POST /v1/recall | time_range_start / time_range_end become a temporal window; source / episode_type filter on labels; limit / offset page the results. |
memory_list | GET /v1/events | Scope-aware list of raw events, newest first; pages by cursor (each page ends with More: cursor=<next>); episode_type filters on the type: label. |
memory_get | GET /v1/events/{id} | Single event by id; tenant_id is sent as ?scope=, the event's exact scope. |
Deleting
| MCP tool | v1 endpoint | Notes |
|---|---|---|
forget_preview | POST /v1/forget/preview | Dry run: per-layer estimated counts plus a fpvw_… preview id. Same selector rules as the delete tools. |
memory_forget | POST /v1/forget | query → selector.about_subject; no query → whole-scope confirm_all=true. Pass from_preview_id from forget_preview for the two-phase flow. Always cascade: derived_only: it deletes derived records (facts, beliefs, episodes, understanding) and keeps the memories; use memory_delete or forget_by_key to delete memories. |
memory_bulk_delete | POST /v1/forget (+ /v1/forget/preview when dry_run=true) | Subject-targeted delete by query; dry_run previews instead. |
memory_delete | POST /v1/forget | Selector preset for one memory_ids=[…]. |
Knowledge graph and beliefs
| MCP tool | v1 endpoint | Notes |
|---|---|---|
entity_list | GET /v1/facts | Distinct fact subjects in the scope (synthetic subjects filtered out). |
entity_get | GET /v1/facts?subject= | Facts filtered to one subject (predicate -> object lines). |
entity_edges | GET /v1/facts?subject= | Same query, rendered as subject --[predicate]--> object. |
entity_link | POST /v1/experience | Records a "X relates to Y" sentence for the LLM extractor to turn into a fact. |
belief_declare | POST /v1/beliefs | Writes a belief record directly (statement, confidence, optional supports event/fact ids, subject, predicate). A newer belief on the same subject+predicate closes the previous one. |
list_conflicts | GET /v1/conflicts | Detected contradictions for a scope (status=open default, or all). |
resolve_conflict | POST /v1/conflicts/{id}/resolve | pick (needs winner) / split (boundary, earlier, later) / new_information (record) / dismiss. Wrong or missing fields are rejected client-side with the expected list. |
claim_history | GET /v1/claims/history | Full bi-temporal change-log of one subject+predicate claim, with any conflicts on it. |
Access, rollups, notices and the directory (0.9.0)
| MCP tool | Profile | v1 endpoint | Notes |
|---|---|---|---|
access_check | all, read, write | POST /v1/access/check | Can a principal read, write or own a scope or a memory? ALLOWED or DENIED with the link that decided. Your own token by default, or another principal for an Owner of the scope |
access_explain | all, read, write | POST /v1/access/explain | Why, link by link |
rollups | all, read, write | GET /v1/rollups | A team's rollups: typed totals and synthesis items |
notices | all, read, write | GET /v1/access/notices?mine=true | Your own unacknowledged notices: who read what of yours, when and why |
acknowledge_notices | all, read, write | POST /v1/access/notices/ack | Acknowledges them; changes no memory |
directory_lookup | all, read, write | GET /v1/directory | People and named scopes by name or email prefix, with only the fields you may read |
publish | write | POST /v1/publish | A person copies a memory they are served into a wider scope they write |
forget_by_key | write | POST /v1/forget | Forgets memories by their idempotency keys or capture labels, reading nothing first, with a preview |
Status, usage and helpers
| MCP tool | v1 endpoint | Notes |
|---|---|---|
health_check | GET /v1/auth/whoami | Auth + reachability in one call: caller, tenant, preset, capabilities. |
get_usage | GET /v1/auth/whoami | Same call plus the X-RateLimit-Limit and X-Cortex-Token-Expires-* response headers. |
get_insights | GET /v1/events, /v1/facts, /v1/beliefs (up to 500 each) | Heuristic pass over the scope — contradictions, low-confidence beliefs, key entities, activity spikes, new sources. No recall and no LLM involved. |
cortexdb_check_call | none (offline) | Validates a planned HTTP call or SDK snippet before you make it — catches POST /v1/memories, client.remember(...), a scope missing its type: prefix, a selector combined with confirm_all — and returns the correction. |
Code memory
Four read-only tools for the code memory plane; the server must run with
CORTEX_CODE_PLANE=1 or every call returns 503 CODE_PLANE_DISABLED. Repository registration is an
operator action through the API/CLI, not an MCP tool.
| MCP tool | v1 endpoint | Notes |
|---|---|---|
code_explore | POST /v1/code/context (one repo) or POST /v1/code/workspace/context (several) | Token-budgeted evidence envelope of cited snippets (repo:path@hash#Lx-Ly). |
code_impact | GET /v1/code/impact | Reverse dependency closure of a symbol, depth 1–6. |
code_inventory | POST /v1/code/symbol/search or POST /v1/code/inventory | kind is required: a symbol-prefix search, or a bounded structural inventory (stats, files, …). |
code_graph | POST /v1/code/graph/query | Bounded graph traversal from roots, with node/edge budgets. |
Code tools need the code plane
The four code_* tools answer 503 CODE_PLANE_DISABLED on a server without CORTEX_CODE_PLANE=1.
Entity/Facts tools need enrichment on self-host
entity_list / entity_get / entity_edges / list_conflicts / claim_history read the Facts
layer, which is empty on a content-only self-hosted instance — those layers need enrichment
configured. memory_store / memory_search / memory_list / belief_declare work regardless. See
Self-hosting defaults.
Resources and prompts
The server also registers three MCP resources — cortexdb://health (GET /v1/auth/whoami),
cortexdb://episodes (the scope's last 50 raw events via GET /v1/events) and cortexdb://insights
(the same heuristic pass as get_insights) — and five prompts: investigate_incident(topic),
summarize_knowledge(topic), deployment_review(service), onboard_to_codebase(repo) and
weekly_digest(tenant_id?). The prompts are plain instruction templates; they make no API calls
themselves.
Tool profiles
| Profile | Tools |
|---|---|
all (default) | Every memory, access and code tool but the opt-in writes (33) |
write | all, plus publish and forget_by_key (35) |
read | Only the tools that write no memory (26; acknowledge_notices changes only your notices) |
code | code_explore, code_impact, code_inventory, code_graph (4) |
Select one with --tool-profile or CORTEXDB_TOOL_PROFILE. A tool outside the profile is removed
from the listing and cannot be called. Resources and prompts are registered under every profile.
Configuration Reference
| Environment variable | Default | Notes |
|---|---|---|
CORTEXDB_URL | https://api-v1.cortexdb.ai | v1 endpoint. With no CORTEXDB_API_KEY, anonymous signup is attempted against this URL (any host). |
CORTEXDB_API_KEY | (none) | Any bearer: a person's or an agent's token, an identity provider's token, or, self-hosted, the server's CORTEX_API_KEY value. Unset → the cached state file, then anonymous signup. |
CORTEXDB_ACTOR | the token's sub | Sent as X-Cortex-Actor; must match the token's sub. - sends none (an identity provider's token whose issuer maps the subject). |
CORTEXDB_SCOPE | (none) | Default scope for tools that don't take an explicit one; set automatically by signup. Required otherwise. |
CORTEXDB_VIEW | (unset: the server's default) | Recall reach for memory_search / get_context / advanced_search: holistic, descend, or granular. At a shared org-tree scope only granular and raw are allowed. |
CORTEXDB_TOOL_PROFILE | all | all, read, write or code, as --tool-profile. |
CORTEXDB_SUBJECT_TOKEN | (none) | With the operator key: a person's token, sent as X-Cortex-Subject-Token, so the server counts what that person would be refused (a dry run of moving off the key). |
CORTEXDB_BREAK_GLASS_REASON, CORTEXDB_BREAK_GLASS_TICKET, CORTEXDB_BREAK_GLASS_NOTE | (none) | With the operator key under the deny mode: every request carries X-Cortex-Break-Glass built from them. |
CORTEXDB_PURPOSE | (none) | The purpose reads declare unless a call names its own. |
CORTEXDB_TENANT_ID | (none) | Legacy tenant id (v0 callers only). |
CORTEXDB_TIMEOUT | 30.0 | HTTP request timeout (seconds). |
The wheel also carries a small FastAPI app (uvicorn cortexdb_mcp.api:app) that serves the insights
pass as GET /api/insights for a dashboard. It is not part of the MCP surface.
Architecture
Your Machine CortexDB
┌──────────┐ stdio ┌───────────┐ HTTPS ┌──────────┐
│ Cursor / │ ◄─────────► │ cortexdb- │ ◄─────────► │ v1 API │
│ Claude / │ MCP JSON │ mcp │ REST │ server │
│ VS Code │ │ (bridge) │ │ │
└──────────┘ └───────────┘ └──────────┘The bridge process holds the bearer token in memory, injects Authorization and X-Cortex-Actor
headers on every call, and translates MCP tool invocations into v1 HTTP requests. Nothing is stored
locally except the credentials.
Next steps
- Python SDK — programmatic access,
V1Client+AsyncV1Client. - TypeScript SDK — Node.js and browser apps,
V1Client.signup()one-liner. - Auth — how tokens, actors, and capabilities fit together.
- API Reference — endpoint-by-endpoint reference.