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.
Tool arguments
Section titled “Tool arguments”fileaccepts 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,linesis optional (inputSchema.requiredis["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_symbollookup goes further — see Self-healing lookups.
Self-healing lookups
Section titled “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 namelines, capped at 20 with... and N more.
symbol not found: NodeDataasuggestions: NodeData
struct NodeDataenum NodeKindfn parse_node... and 6 moreSuggestions 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.
Security posture
Section titled “Security posture”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
execchildren run under a wall-clock timeout, so a hung command cannot wedge the stdio loop.
Configuration
Section titled “Configuration”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.
Protocol notes
Section titled “Protocol notes”- Newline-delimited JSON-RPC 2.0 over stdio.
initializeresponds withprotocolVersion: "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.