Skip to content

MCP Adapter

ctxctl mcp is an optional adapter that serves the same five commands as MCP tools over stdio. The CLI remains the canonical interface; nothing about it changes when the adapter runs.

Tool Wraps
ctxctl_outline outline <file>
ctxctl_symbol symbol <file> --name <s>
ctxctl_read read <file> [--lines N-M]
ctxctl_deps deps <file>
ctxctl_exec exec <cmd> [--keep <pat>]

Results come back as plain text with the same saved% metrics as the CLI, wrapped as { content: [{ type: "text", text }] }. Failures (missing file, unknown symbol, bad arguments) surface as isError: true results, never protocol errors. A ctxctl_exec call whose wrapped command exits non-zero also surfaces as an error result carrying the child’s exit code.

  • file accepts a workspace-relative path or an absolute path under the pinned workspace root (existing targets are symlink-resolved); absolute paths outside the root are rejected.
  • On ctxctl_read, lines is optional (inputSchema.required is ["file"]): omit it or pass an empty string for the whole file. Formats: "N", "N-M", "N-" (open-ended to end of file), comma lists such as "100-150,200-210". An invalid token is rejected naming the accepted formats: invalid range `1x2`: expected N, N-M, or N-.
  • A JSON number for a string-typed argument is coerced to its decimal string form (lines: 100 → "100"); other type mismatches fail naming key, expected type, and got type.
  • Errors teach the fix: unknown tools enumerate the registry, missing arguments append an expected-usage example from the tool’s schema, and unknown argument keys list the valid keys. A missed ctxctl_symbol lookup goes further — see Self-healing lookups.

Since v0.3.3 a missed ctxctl_symbol lookup teaches instead of failing flat. The first line stays verbatim (symbol not found: <name>); below it the error carries everything needed to retry correctly:

  • A suggestions: line with up to five ranked look-alike names from the file’s actual symbols — case-insensitive prefix matches first, then substring matches, then edit distance ≤ 2, ties broken alphabetically.
  • A mini-outline of the file’s top-level symbols as kind name lines, capped at 20 with ... and N more.
symbol not found: NodeDataa
suggestions: NodeData
struct NodeData
enum NodeKind
fn parse_node
... and 6 more

Suggestions and outline derive only from file content and the query, so the message stays byte-stable; when nothing resembles the query, the bare error passes through untouched.

Since v0.3.1 the adapter is workspace-pinned by design:

  • Tool calls resolve paths against the server’s pinned workspace root, not the ambient process CWD.
  • Tool arguments are validated before dispatch — malformed calls fail fast without reaching a handler.
  • Spawned exec children run under a wall-clock timeout, so a hung command cannot wedge the stdio loop.

Add ctxctl to any MCP client that launches stdio servers:

{
"mcpServers": {
"ctxctl": {
"command": "ctxctl",
"args": ["mcp"]
}
}
}

This shape works in opencode, Cursor, Claude Desktop, and other MCP-native clients.

  • Newline-delimited JSON-RPC 2.0 over stdio.
  • initialize responds with protocolVersion: "2025-03-26", tool capabilities, and server info (name: "ctxctl").
  • Notifications (messages without an id) produce no response.
  • Malformed JSON gets JSON-RPC error -32700; an id-carrying message without a method gets -32600 (invalid request); unknown methods get -32601.
  • Config resolution is identical to the CLI, including --config.
  • The server exits 0 on clean stdin EOF.