Skip to content

MCP — both directions

ostk speaks MCP in both directions. Inbound: an external client (Claude Code, Cursor, anything) drives ostk as an MCP server. Outbound: ostk-driven agents call external MCP services (linear, github, postgres, etc.) via a userspace proxy.

ostk mcp Run the stdio MCP bridge. Invoked by external MCP clients as a subprocess. Forwards to a running daemon, falls back to in-process serve.
ostk mcp diag Reconcile the kernel's MCP tool surface against CORE_SEED_LANGUAGE. Exits 1 on drift.
ostk driver list List configured outbound MCP servers from HUMANFILE's mcp: section.
ostk driver call <name> <tool> Invoke a tool on a configured outbound MCP server (ephemeral subprocess).
ostk driver serve <name> Run an outbound MCP subprocess persistently on a Unix domain socket.

The outbound verbs were renamed from ostk mcp {list,call,serve} to ostk driver {list,call,serve} when ostk mcp (no subcommand) was reclaimed for the inbound bridge. Legacy ostk mcp ... still routes to the new ostk driver ... via McpLegacy dispatch in src/main.rs.

Drive ostk from an external MCP client

Your agent tool (Claude Code, Cursor, your own client) launches ostk mcp as a subprocess and speaks the MCP JSON-RPC protocol over stdio. The bridge translates that into kernel calls. Your agent gets gen-tracked writes, hash-chained audit, and pin-cap enforcement without changing its UI.

Source: src/main.rs (Commands::Mcp { command: None } branch — runs run_mcp_bridge), src/serve/server.rs (run_mcp_bridge, bridge_stdio_to_daemon). The bridge resolved the "two isolated kernels" problem (→1309 Phase 2B) — the Claude Code MCP process and ostk daemon used to have separate ServerStates that couldn't see each other's work.

Configuration

Most MCP clients use the same mcpServers shape. Add this entry to your client's MCP config:

TERMINAL
{
  "mcpServers": {
    "ostk": {
      "command": "ostk",
      "args": ["mcp"]
    }
  }
}
Claude Code (project-scoped) .mcp.json
Claude Code (global) ~/.claude/settings.json
Cursor ~/.cursor/mcp.json
Other clients consult their MCP docs — schema is consistent

Verify the surface

Restart the client. Ask the agent to list its tools. You should see ostk-namespaced tools appear:

EXPECTED_TOOLS (subset)
mcp__ostk__bash — kernel-mediated shell with audit + compression
mcp__ostk__read — file read with gen_table tracking
mcp__ostk__fs_ops — file mutation with OCC conflict detection
mcp__ostk__search — unified code/files/needles/decisions search
mcp__ostk__lock, spawn, interact, session, tack, help — coordination primitives

The authoritative list is ostk mcp diag. Tool count varies by kernel version. Names are namespaced as mcp__<server>__<tool> by the MCP client — so mcp__ostk__bash is the bash verb routed through your ostk server entry.

First write — see the audit chain

Have the agent edit a small file. In your terminal:

TERMINAL
$ tail -f .ostk/journal.jsonl
{"event":"tool.fs_ops","path":"src/lib.rs","gen_before":4,"gen_after":5,"writer":"claude-code-1","ts":"2026-04-26T19:42:11Z","prev_hash":"...","sig":"..."}
{"event":"tool.bash","cmd":"cargo check","exit_code":0,"duration_ms":2841,...}

Each row is hash-chained against the previous (prev_hash) and Ed25519-signed in-process (sig). Two agents editing the same file get a CAS conflict instead of a silent overwrite. Capability boundaries from .ostk/pins/<name>/pin.caps apply uniformly.

Inbound troubleshooting

Agent reports "no MCP server named ostk" Config file path or JSON syntax. Validate with `cat .mcp.json | jq .`. Restart the agent tool — most clients only read MCP config at startup.
Tools listed but every call fails Run `ostk mcp diag` directly. If it errors, check `ostk init` ran in this project — the bridge resolves the project root by walking up from CWD looking for .ostk/.
Writes succeed but no audit row appears You're probably writing through the agent's native filesystem tools, not the ostk-namespaced ones. Restrict the agent to mcp__ostk__* tools (most MCP clients have an allowlist).
Two daemons fight for the socket `ostk daemon restart` (swaps a rebuilt binary cleanly) or `pkill -f "ostk daemon"` then re-invoke. The bridge auto-recovers from a clean socket.
Permission errors on write Pin caps deny by default. Check `.ostk/pins/default/pin.caps`. T3 (no GPG identity) gets read-only by design — see /docs/security/#gpg-rooted-trust-tiers.

DRIVING OSTK FROM CUSTOM TOOLS & SCRIPTS

You don't need Claude Code or Cursor to leverage the ostk kernel. You can drive it directly from custom scripts, CI pipelines, or proprietary editor extensions using two transport methods:

1. Subprocess Pipe Transport (Stdio)

Spawn ostk mcp as a persistent background process. Write JSON-RPC 2.0 messages to its stdin and read structured responses from its stdout.

Example payload sent to stdio:
{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "mcp__ostk__read",
    "arguments": {
      "path": "src/main.rs"
    }
  },
  "id": 1
}
          

2. UNIX Domain Socket Transport

For maximum performance and zero process-startup overhead, connect directly to the UNIX domain socket located at .ostk/ostk.sock. This bypasses the MCP abstraction layer entirely and invokes System ABI verbs directly.

Simple Node.js integration script:
const net = require('net');
const client = net.createConnection('.ostk/ostk.sock', () => {
  client.write(JSON.stringify({
    jsonrpc: '2.0',
    method: 'read',
    params: { path: 'README.md' },
    id: 1
  }) + '\n');
});

client.on('data', (data) => {
  console.log('Kernel Response:', JSON.parse(data.toString()));
  client.end();
});
          

Call external MCP services from ostk-driven agents

Your ostk-driven agent needs to talk to Linear, GitHub, Postgres, or any other MCP-speaking service. ostk's driver subcommand is a userspace proxy — agents invoke ostk driver call <name> <tool> and the proxy connects, sends one JSON-RPC request, prints the response, exits.

Deliberately at arm's length: the kernel never speaks MCP protocol bytes. Output flows through the same compression + audit pipeline as any shell output. Source: src/commands/mcp_proxy.rs (run_list, run_call, run_serve, run_persistent_call, run_ephemeral_call, run_jsonrpc_session).

Configuration

Outbound MCP servers are declared in .ostk/HUMANFILE under an mcp: section (not ostk.toml). Simple key-value: name → command line.

TERMINAL
# .ostk/HUMANFILE

mcp:
  linear: npx -y @anthropic/linear-mcp-server
  github: gh mcp-server
  postgres: npx -y @modelcontextprotocol/server-postgres

Source: src/commands/mcp_proxy.rs lines 7–11, 53, 134–147 (HUMANFILE parsing).

Execution modes

EPHEMERAL (default)

One subprocess per ostk driver call. Connect, JSON-RPC once, exit.

Higher latency per call, zero resident memory. Source: mcp_proxy.rs run_ephemeral_call.
PERSISTENT

ostk driver serve <name> runs a long-lived subprocess on a Unix domain socket; subsequent calls reuse it.

Lower latency, resident memory. Source: mcp_proxy.rs run_serve, run_persistent_call.

How it works

01
Operator declares servers in HUMANFILE mcp: section. No kernel registration, no boot-time discovery.
02
Agent calls shell("ostk driver call linear list-issues"). The shell command runs as userspace subprocess.
03
ostk driver connects to the server over stdio, sends one JSON-RPC request, reads the response, exits. Output flows through the normal compression + audit pipeline as any shell output does.
04
Compare to built-in tools (file:edit, shell, etc.) which DO route through the kernel directly. Outbound MCP is deliberately at arm's length.
ASPECT
INBOUND (ostk mcp)
OUTBOUND (ostk driver)
Direction
External client → ostk
Ostk-driven agent → external service
Transport
stdio (subprocess)
stdio (subprocess) or unix socket (persistent)
Tool scope
Kernel verbs (bash, fs_ops, read, search, ...)
Whatever the external server exposes
Audit path
Kernel-direct (every call → audit row)
Shell wrapper (call appears as bash row + nested response)
Pin cap enforcement
Yes (kernel-mediated)
No (the proxy does not impose ostk policy on the remote server)
Compression
Yes (uniform)
Yes (output passes through shell compressor)
Configuration
Client's MCP config (mcpServers)
.ostk/HUMANFILE mcp: section