Skip to content

executor: MCP stdio server in the rocco binary (#84) - #109

Merged
srinji-kaggss merged 1 commit into
mainfrom
executor/mcp-stdio
Nov 3, 2026
Merged

srinji-kaggss merged 1 commit into
mainfrom
executor/mcp-stdio

Conversation

@srinji-kaggss

@srinji-kaggss srinji-kaggss commented Nov 3, 2026 •

Copy link
Copy Markdown
Collaborator

What changed

  • rocco mcp serves MCP (spec 2025-06-18) over stdio from the shipped rocco binary: initialize/initialized lifecycle with version negotiation, ping, tools/list, tools/call, JSON-RPC errors -32700/-32600/-32601/-32602, newline-delimited framing. Blocking std loop on lgwks_std::json; no new crate, no rmcp, no new pub item.
  • Bounds: frames over 1 MiB are discarded as they stream in and answered with -32600, and the server keeps serving. Pending work is one frame. EOF exits 0.
  • Files: src/mcp/{mod,wire,tools}.rs, src/bin/rocco.rs (dispatches mcp), src/main.rs (stderr helper, behaviour unchanged), INVARIANTS.md (one line).

The one tool

larry_submit_task (goal, repo, files, acceptance). A malformed task returns a tool error invalid_arguments. A well-formed task is refused with the typed tool error executor_not_connected (isError true) until #85 and #83 land. It never returns success.

Proof

  • Gates: build, clippy -D warnings, fmt, diff check clean; cargo nextest run --workspace --locked: 513/513 passed, 282 MB peak RSS.
  • tools/list round trips, n=3000, debug binary: p50 52 us, p95 62 us, p99 89 us.
  • Server peak RSS 8.2 MB over a 5002-frame scripted session (/usr/bin/time -l, debug build).
  • Seeded sims (tests/sim_mcp_stdio.rs, tests/sim_mcp_protocol.rs) replay bit-identically across 24 seeds and run 100 concurrent sessions with kill -9; tests/mcp_stdio_journey.rs covers the lifecycle, malformed and oversized frames and exit codes.

Pareto comparison against rmcp 3.8.0 (newest)

Axis rocco mcp rmcp 3.8.0 (server, transport-io) Source
New crates in the build 0 62 MEASURED, docs/dependencies/cargo-sweep.md
Cold build of the MCP layer 0 s added 69.5 s MEASURED, cargo sweep
Peak build RSS unchanged 545 MB MEASURED, cargo sweep
Server peak RSS, 5002 frames 8.2 MB (debug) NOT RUN
tools/list p50/p95/p99, n=3000 52/62/89 us (debug) NOT RUN

On build cost and dependency count, rocco mcp dominates rmcp. The runtime rows for rmcp are NOT RUN: the estate guard (ESTATE-DUPLICATION) refuses a scratch server that uses tokio and serde_json, even outside this repository, and rmcp needs both. Until a matched runtime run exists, no latency superiority over rmcp is claimed.

Not ported from forge-mcp

  • jsonrpc.rs: client-side framing adapted from OpenAI Codex per forge's NOTICE, so it is rewritten from the MCP spec instead.
  • The 2026-07-28 stateless era in server.rs: this order targets the 2025-06-18 revision.

Backout

Revert the merge commit; rocco without arguments is unchanged.

Closes #84

🤖 Generated with Claude Code

Adds `rocco mcp`: a blocking std stdin/stdout MCP server written from the
MCP 2025-06-18 specification on lgwks_std::json. No new crate, no pub item,
no rmcp. forge-mcp's Codex-adapted client framing (jsonrpc.rs) is not ported
and its 2026-07-28 stateless era is not served.

- src/mcp/wire.rs: newline-delimited framing, 1 MiB frame bound enforced
  while streaming (oversized line discarded unbuffered, answered -32600,
  server keeps serving), JSON-RPC reply shapes.
- src/mcp/mod.rs: initialize/initialized lifecycle with version
  negotiation, ping, tools/list, tools/call, -32700/-32600/-32601/-32602,
  notifications and client responses never answered, one frame of pending
  work, EOF exits 0.
- src/mcp/tools.rs: one tool, larry_submit_task (goal, repo, files,
  acceptance), typed TaskError. A well-formed task is refused with the
  typed tool error executor_not_connected until the executor lands.
- src/bin/rocco.rs dispatches `mcp`; src/main.rs routes diagnostics
  through one stderr helper (behaviour unchanged).

Proof (debug build, local pipe): 513 of 513 nextest tests pass, including
tests/sim_mcp_stdio.rs and tests/sim_mcp_protocol.rs (seeded, 24 seeds
replayed bit-identically, 100 concurrent sessions with kill -9 of a tenth)
and tests/mcp_stdio_journey.rs. tools/list round trips n=3000 p50=52us
p95=62us p99=89us; peak RSS 8.2 MB over a 5002-frame scripted session.

Backout: revert this commit; rocco without arguments is unchanged.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

Design-Plan: 0e2e05cad5c39473 (blocking std stdin/stdout loop on lgwks_std::json, modules private to the rocco binary)
Cited: modelcontextprotocol/servers#4207
Cited: https://modelcontextprotocol.io/specification/draft/basic/transports/stdio
Cited: https://inferensys.com/glossary/tool-calling-and-api-execution/model-context-protocol-mcp/message-framing
Cited: https://github.com/JSLEEKR/mcpbench
Cited: https://www.claudemap.org/en/guides/mcp-debugging
@srinji-kaggss
srinji-kaggss merged commit ed716a8 into main Nov 3, 2026
6 checks passed
@srinji-kaggss
srinji-kaggss deleted the executor/mcp-stdio branch November 3, 2026 18:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Track 3: MCP stdio server, ported from forge-mcp

1 participant