ctx mcp
ctx mcp is Contexo’s MCP server: with no subcommand it speaks JSON-RPC over
stdio and hands the calling agent this project’s knowledge base. Its
subcommands write that same server into each agent’s own config file.
When you’d reach for it
Section titled “When you’d reach for it”You rarely type the bare command — the agent spawns it. You reach for the
subcommands when an agent showed up after ctx init ran, when you want Codex
wired (the one agent Contexo never wires silently, because its MCP config is
global), or when the agent lists a contexo server with no tools and you need
to know whether the problem is the wiring or the directory it was launched in.
Two things trip people up. Agents read their MCP config at startup, so every
wiring change needs an agent restart before it means anything. And the entry
Contexo writes is literally {"command": "ctx", "args": ["mcp"]} — so ctx
has to be on the PATH the agent sees, which on macOS GUI apps is often not
the PATH your shell sees.
Synopsis
Section titled “Synopsis”ctx mcp # run the server over stdio (agents invoke this)ctx mcp install [--tool=…] # wire it into an agent's configctx mcp uninstall [--tool=…] # remove that wiringctx mcp status # what's wired for this projectctx mcp guide # config recipes for every other harnessctx mcp takes no flags.
Inherited from the root command:
| Flag | Type | Default | Description |
|---|---|---|---|
--root | string | project root directory (default: current directory) |
--root is more load-bearing here than on other commands. The bare server
resolves its project exactly once, at startup, from --root or the process’s
working directory — and never re-checks. Agents launch ctx mcp with the
project as the working directory, so you normally don’t need it; a harness that
spawns MCP servers from a fixed directory does.
How it works
Section titled “How it works”Bare ctx mcp opens the page store at <root>/.contexo, then reads
newline-delimited JSON-RPC 2.0 from stdin and writes exactly one JSON response
line to stdout per request (input lines up to 10 MB). It handles initialize,
tools/list, tools/call, resources/list and resources/read; every other
method returns -32601 method not found. It reports protocol version
2024-11-05 and serverInfo.name = "contexo", and it stores the
clientInfo.name you send in initialize, which is how a pull gets attributed
to the agent that made it.
All 10 tools and 5 resources are served from that
one process — there is no daemon and no port. Most of the work is local disk;
ctx_push, ctx_pull, ctx_history, ctx_diff and ctx_evolution call the
Contexo server, and reads of ctx://wiki/{slug} fire a best-effort drift check
against it (cached for 60s, silently skipped when offline).
The dormant server
Section titled “The dormant server”If <root>/.contexo does not exist, the server does not fail. It runs
dormant: initialize succeeds, tools/list and resources/list return
empty arrays, and everything else answers
-32601 method not available (no .contexo project in this directory).
That exists because of Codex. Codex’s MCP config is global, so a single
~/.codex/config.toml entry launches ctx mcp in every directory you open
Codex in. A server that exited non-zero in unrelated repos would surface as a
broken integration on every launch; a server with zero tools is honest and
quiet. The practical consequence: if an agent shows contexo connected but
with no tools, you are outside a Contexo project (or the agent’s working
directory isn’t the project root). Run ctx init, then restart the agent.
Common errors
Section titled “Common errors”| Message | Cause and fix |
|---|---|
mcp: open store: … (did you run 'ctx init'?) |
.contexo exists but can’t be opened as a directory — usually a stray .contexo file, or a permissions problem. A merely missing .contexo goes dormant instead of erroring. |
mcp install: not a Contexo project (run 'ctx init' first) |
ctx mcp install refuses to wire an agent to a project that doesn’t exist yet. uninstall, status and guide have no such check. |
unknown --tool "x" (want claude, cursor, codex, or all) |
Typo in --tool. Accepted values are exactly claude, cursor, codex, all (and empty, which means all). |
ctx mcp install
Section titled “ctx mcp install”Writes the contexo MCP server into an agent’s config.
ctx mcp install # claude + cursor, plus codex if it's on PATHctx mcp install --tool=claude # ./.mcp.jsonctx mcp install --tool=cursor # ./.cursor/mcp.jsonctx mcp install --tool=codex -y # ~/.codex/config.toml, no prompt| Flag | Type | Default | Description |
|---|---|---|---|
--tool | string | all | agent to wire: claude|cursor|codex|all |
--yes, -y | bool | false | skip confirmation prompts (e.g. Codex's global config) |
Each agent reads MCP servers from a different place, and only one of them is global:
| Agent | Config it reads | Scope | How Contexo writes it |
|---|---|---|---|
| Claude Code | ./.mcp.json |
project | merges the JSON itself |
| Cursor | ./.cursor/mcp.json |
project | merges the JSON itself |
| Codex | ~/.codex/config.toml |
global | shells out to codex mcp add contexo -- ctx mcp |
Contexo never parses Codex’s TOML — that file’s format is Codex’s business, so
wiring and unwiring both go through the codex CLI. That is also why Codex is
the only agent this command probes for: wiring it means running codex mcp add,
so the binary has to be on PATH. Claude and Cursor get no detection at all —
each is just a project-local JSON file, harmless to write for an agent you
don’t run.
--tool=all (the default) wires Claude and Cursor unconditionally and adds
Codex only when that binary is present — an absent Codex is skipped silently.
Ask for it explicitly and a missing binary is an error instead:
mcp install codex: Codex CLI not found (`codex` not on PATH).
The JSON merge is idempotent and preserves every other key in the file — but it
is not a “leave what’s there” merge: if the existing contexo entry differs in
any way from {"command": "ctx", "args": ["mcp"]}, it is replaced. Custom
tweaks (an absolute path to ctx, an env block) are silently reverted by the
next ctx mcp install or ctx init. An entry that already matches is left
untouched and reported as already wired.
Adds Contexo's MCP server so an agent's tools (ctx_push/pull/write_page,
history/diff, etc.) become available:
claude -> ./.mcp.json (project-local)
cursor -> ./.cursor/mcp.json (project-local)
codex -> ~/.codex/config.toml (GLOBAL — prompts unless --yes)
--tool=all wires the project-local agents (claude, cursor) and also codex
when it is installed.
Usage:
ctx mcp install [flags]
Flags:
-h, --help help for install
--tool string agent to wire: claude|cursor|codex|all (default "all")
-y, --yes skip confirmation prompts (e.g. Codex's global config)
Global Flags:
--root string project root directory (default: current directory)ctx mcp uninstall
Section titled “ctx mcp uninstall”Removes the contexo entry from an agent’s config.
ctx mcp uninstall # all threectx mcp uninstall --tool=cursor # just ./.cursor/mcp.json| Flag | Type | Default | Description |
|---|---|---|---|
--tool | string | all | agent to unwire: claude|cursor|codex|all |
Unlike install, this does not require a Contexo project — you can unwire a
directory whose .contexo/ is already gone. For Claude and Cursor it deletes
just the contexo key; if that leaves mcpServers empty and mcpServers was
the only top-level key, the file is deleted rather than left as an empty husk.
Any other key in the file (another MCP server, an unrelated setting) keeps the
file alive. For Codex it runs codex mcp remove contexo, but only after
checking codex mcp get contexo — a Codex that isn’t installed, or isn’t
wired, prints nothing to do. instead.
To undo the whole ctx init — MCP entries, capture hooks, the .gitignore
line and the knowledge directory — use ctx detach instead of
running these one at a time.
ctx mcp status
Section titled “ctx mcp status”One table showing, per agent, whether the MCP server and the capture hook are wired for this project.
ctx mcp statusctx mcp status takes no flags.
Agent integrations for this project:
AGENT MCP SERVER CAPTURE (STOP HOOK)
Claude Code wired (.mcp.json) installed
Cursor wired (.cursor/mcp.json) installed
Codex not installed not installed
Add another agent (Windsurf, OpenCode, Hermes, ...)? Run `ctx mcp guide`.Every cell is computed live from a different source, which is worth knowing when a row looks wrong:
- Claude Code / Cursor MCP — reads
./.mcp.jsonand./.cursor/mcp.jsonand checks for anmcpServers.contexokey. - Codex MCP —
not installedmeans thecodexbinary isn’t on PATH; otherwise it shells out tocodex mcp get contexoand reportswired (~/.codex, global)ornot wired (~/.codex, global). - Capture — reads three different files:
.claude/settings.json,.codex/hooks.json,.cursor/hooks.json. Seectx hooks.
ctx mcp status reports what is on disk now, not what the running agent
loaded. A row that says wired while the agent still shows no contexo server
means the agent hasn’t been restarted since the wiring changed.
ctx mcp guide
Section titled “ctx mcp guide”Prints config recipes for agents Contexo doesn’t wire directly.
ctx mcp guidectx mcp guide takes no flags.
Add Contexo to another agent or harness
---------------------------------------
Contexo's MCP server is a standard stdio server: command "ctx", args ["mcp"].
Add that to the agent's own MCP config — same server everywhere; only the
file and format differ:
AGENT CONFIG FORMAT / HOW
Claude Code ./.mcp.json JSON mcpServers — ctx mcp install --tool=claude
Cursor ./.cursor/mcp.json JSON mcpServers — ctx mcp install --tool=cursor
Codex ~/.codex/config.toml TOML [mcp_servers.contexo] — ctx mcp install --tool=codex
Windsurf ~/.codeium/windsurf/mcp_config.json JSON mcpServers
OpenCode ./opencode.json JSON mcp: { contexo: { type: "local", command: ["ctx","mcp"] } }
Hermes config.yaml YAML mcp_servers: { contexo: { command: ctx, args: [mcp] } }
OpenClaw (CLI-managed) run the `openclaw mcp` command
JSON mcpServers entry: "contexo": { "command": "ctx", "args": ["mcp"] }
Any other MCP client: add the same server; see its docs for the exact path.
Capture (the Stop hook): Claude Code, Codex, and Cursor are supported —
ctx hooks install --tool=claude|codex|cursor|all
Claude parses its transcript; Codex and Cursor pair their prompt + response
hooks inline. Other MCP-capable harnesses get the tools now; capture as they
expose a stop/turn-end hook.This is static text — it needs no project and makes no network call, so it
works anywhere. The same guide is printed at the end of ctx init;
ctx mcp status only points at it. Every row is the same server (command: "ctx",
args: ["mcp"]); only the file and the surrounding syntax change, which is why
“add Contexo to my agent” is a config question and never a build question.
See also
Section titled “See also”ctx init— creates.contexo/and does this wiring for youctx hooks— the other half of agent integration: per-turn capturectx detach— remove every wirectx initadded- MCP reference — the tools this server exposes
