Skip to content

Connect your agent

There is exactly one server to connect: ctx mcp, a plain MCP server over stdio. Every agent gets the same ten tools and five resources. The only thing that differs between agents is which file holds the server entry — and, for Codex, that the file is global rather than per-project.

what ctx writes into .mcp.json / .cursor/mcp.json
{
"mcpServers": {
"contexo": { "command": "ctx", "args": ["mcp"] }
}
}

The server resolves the project from its working directory, which is why a global registration still gives per-project knowledge: run the agent in ~/work/acme-api and it reads ~/work/acme-api/.contexo/.

Agent MCP config Scope Wired by
Claude Code ./.mcp.json project ctx init — always
Cursor ./.cursor/mcp.json project ctx init — when Cursor is detected
Codex ~/.codex/config.toml global never automatic — ctx mcp install --tool=codex
Anything else its own file varies you, once — see other clients

Detection is deliberately asymmetric. Cursor counts as installed if ~/.cursor exists or cursor is on your PATH, because wiring it only writes a harmless project-local file. Codex counts only if the codex binary is on your PATH — a bare ~/.codex directory is not enough, since other tools create that directory too, and a false positive there would mean touching a global config.

ctx init
  Wired Claude Code (.mcp.json) — restart your agent to load the contexo server
  Cursor detected — wired .cursor/mcp.json
  Created .gitignore with .contexo/
Installed Contexo capture Stop-hook in .claude/settings.json
Restart Claude Code (or open a new session) so the hook is picked up.
Installed Cursor capture hooks (.cursor/hooks.json: beforeSubmitPrompt + afterAgentResponse)
Initialized .contexo in ~/projects/acme-api

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 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.

In one run: the .contexo/ tree, Claude Code’s MCP entry, Cursor’s MCP entry (detected here), capture hooks for both, and the .gitignore line. Codex, when present, gets a one-line nudge rather than a config write.

Each piece has an opt-out:

FlagTypeDefaultDescription
--no-cursorboolfalseskip auto-wiring Cursor (.cursor/mcp.json) even when Cursor is detected
--no-gitignoreboolfalseskip adding .contexo/ to .gitignore
--no-hooksboolfalseskip registering the Claude Code Stop hook for per-turn capture
--no-mcpboolfalseskip wiring the MCP server into agent configs (.mcp.json, .cursor/mcp.json)

ctx init merges rather than replaces — it preserves every other key in .mcp.json and every other server under mcpServers, and re-running when the entry is already there prints “already has the contexo entry” and changes nothing.

Terminal window
ctx mcp install --tool=claude # ./.mcp.json
ctx mcp install --tool=cursor # ./.cursor/mcp.json
ctx mcp install --tool=codex # ~/.codex/config.toml — global
ctx mcp install # = --tool=all

--tool=all wires the project-local agents and adds Codex only when the CLI is actually installed. All of these require an initialized project: outside one, ctx mcp install errors with “not a Contexo project (run ‘ctx init’ first)”.

Codex owns its TOML, so Contexo never edits ~/.codex/config.toml directly — it shells out to codex mcp add contexo -- ctx mcp (and codex mcp remove / codex mcp get for uninstall and status). Because the result is global, the command asks “Wire Contexo into Codex’s GLOBAL config (~/.codex/config.toml)?” and does nothing unless you answer yes.

Pass --yes to skip the prompt in a script. After it lands, every Codex session on your machine launches ctx mcp — and each one operates on whatever project it was started in. Started somewhere with no .contexo/, ctx mcp serves a dormant server that advertises zero tools and zero resources rather than failing, so the global entry costs nothing in unrelated repos.

Add the same stdio server to whatever config your client uses:

Windsurf — ~/.codeium/windsurf/mcp_config.json
{ "mcpServers": { "contexo": { "command": "ctx", "args": ["mcp"] } } }
OpenCode — ./opencode.json
{ "mcp": { "contexo": { "type": "local", "command": ["ctx", "mcp"] } } }
Codex — ~/.codex/config.toml (written for you by codex mcp add)
[mcp_servers.contexo]
command = "ctx"
args = ["mcp"]

ctx mcp guide prints this list from the binary you actually have installed, including a few more harnesses — worth running instead of trusting a docs page that could age.

Wiring MCP gives the agent the tools. Capture hooks are what give ctx_push something to distil: they append each turn to a local buffer under .contexo/raw/sessions/_pending/. No LLM call, no upload.

Agent Hook file Events Command
Claude Code .claude/settings.json Stop ctx capture turn
Codex .codex/hooks.json UserPromptSubmit + Stop ctx capture turn --agent codex
Cursor .cursor/hooks.json beforeSubmitPrompt + afterAgentResponse ctx capture turn --agent cursor

All three files are project-local, so ctx init installs Claude’s hook always and the other two whenever those agents are detected. Claude’s hook reads the session transcript; Codex and Cursor need two hooks each because they pair the prompt they saw on the way in with the response text on the way out, which avoids parsing a transcript at all.

Manage them separately from MCP wiring:

Terminal window
ctx hooks install --tool=claude|codex|cursor|all
ctx hooks uninstall --tool=…
ctx hooks status
ctx hooks status
claude: installed (.claude/settings.json)
codex:  not installed (.codex/hooks.json)
cursor: installed (.cursor/hooks.json)

Contexo tags its Claude hook entry with an internal marker, so install is idempotent and uninstall removes only Contexo’s hook and leaves yours alone. The hook command exits 0 when the project isn’t a Contexo project, and setting CONTEXO_CAPTURE_DISABLE=1 turns capture off without unwiring anything.

ctx mcp status
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`.

That’s the local view. For the end-to-end check, restart your agent and ask it to call ctx_status — if it answers with your repo, page count and last-pull sha, the server is loaded and talking to the right project.

Terminal window
ctx mcp uninstall --tool=claude|cursor|codex|all
ctx hooks uninstall --tool=claude|codex|cursor|all

ctx mcp uninstall removes only the contexo entry. If that empties mcpServers and mcpServers was the file’s only key, the file is deleted instead of left behind as a husk; any other server or key you had is preserved. To undo everything ctx init did in one step — MCP entries, hooks, the .gitignore line — use ctx detach, which lists what it will do and waits for a yes. It deletes .contexo/ too unless you pass --keep-knowledge.