Skip to content

MCP reference

ctx mcp is the whole server. It speaks JSON-RPC 2.0 over stdio — one JSON object per line on stdin, one per line on stdout — and serves the .contexo/ tree of the directory it was started in. There is no port, no daemon, no separate login: your agent spawns ctx mcp as a child process, and everything the agent can do with Contexo goes through that pipe.

.mcp.json — Claude Code; Cursor's .cursor/mcp.json is byte-identical
{
"mcpServers": {
"contexo": { "command": "ctx", "args": ["mcp"] }
}
}

The server advertises protocol version 2024-11-05 and identifies itself as contexo. It implements five methods — initialize, tools/list, tools/call, resources/list, resources/read — and answers anything else with JSON-RPC error -32601.

Each agent reads MCP servers from a different file. ctx init writes the same server definition into the ones it can, merging into any existing config rather than overwriting it.

Agent Config Scope Wired by ctx init?
Claude Code ./.mcp.json project Always
Cursor ./.cursor/mcp.json project When Cursor is detected
Codex ~/.codex/config.toml global No — when detected, init prints the command to run

Cursor counts as detected when ~/.cursor/ exists or cursor is on PATH; wiring it only writes a harmless project-local file. Codex is detected by the codex binary on PATH only, and is never wired automatically because its config is global and shared across every project. Wire it deliberately with ctx mcp install --tool=codex, which shells out to codex mcp add rather than hand-editing the TOML.

ctx init --no-cursor and ctx init --no-mcp opt out. See ctx mcp for install, uninstall, status and guide.

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

Any other MCP client works too — it is a standard stdio server, so the only thing that differs per harness is where you paste the entry:

ctx mcp guide
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.

Contexo records which agent is asking. On initialize, the server reads params.clientInfo.name from the request and keeps it for the life of the process:

initialize request (excerpt)
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"clientInfo": { "name": "claude-code", "version": "1.2.3" }
}
}

That name is sent as the X-Contexo-Client header on pulls, and nowhere else. ctx pull from a terminal sends the same header with the fixed value ctx-cli, so server-side activity distinguishes “an agent pulled this” from “a human ran the CLI”. Pushes send no client header at all — the commit carries the author_name / author_email from your local credentials, so every write is attributed to the person who owns them, whichever agent produced it.

Ten tools, all listed by tools/list. Each page shows the exact input schema the agent sees over the wire.

Tool What it does
ctx_write_page Write a knowledge page into .contexo/ and regenerate the index
ctx_push Push local pages to the team server, filtered by tag or type
ctx_pull Pull new pages from the team server into .contexo/
ctx_status Server, repo, auth, page count, last pull sha, never-pushed pages
ctx_history Commit timeline for one page
ctx_diff Section-aware diff between two versions of a page
ctx_evolution Every commit touching a page, each paired with its diff, in one call
ctx_capture_session Hand the agent the local capture buffer plus a source-page template
ctx_migrate Catalog a project’s existing docs/wiki so the agent can import them
ctx_generate Catalog subsystems from the codebase (via Graphify) to seed a fresh KB

Several of these do not just return data — they return a directive the agent is expected to act on (<PUSH_PAUSED>, <MERGE_REQUIRED>, <MIGRATE_CATALOG>, <GENERATE_RESUME>, …). Those are documented in agent directives.

Five read-only ctx:// URIs. Full semantics, including the drift notice and the search parameters, are on resources.

URI MIME type Returns
ctx://index text/markdown The generated knowledge index — every page, grouped by type
ctx://tags text/markdown Tag → page mapping
ctx://wiki/{slug} text/markdown One concept, entity, or analysis page
ctx://raw/{session-id} text/markdown One raw session capture from raw/sessions/
ctx://search?q={query}&type={type}&tag={tag} application/json Matching pages as metadata, no bodies