Chapter 25: mcp, how a client reaches the window in milliseconds

An MCP client such as Claude Code starts its servers when it starts, and gives each one 30 seconds to answer initialize. This repository's ../../.mcp.json names one server, jev, and its command is tools/mcp/launch.sh. Everything in this folder exists to make that command answer fast, every time.

It used to be nix develop -c buck2 run //apps/native:native -- mcp. On a cold cache that is a build of minutes; the client gave up after 30 seconds, and the connection failed at startup twice (2026-09-20 and 2026-09-21).

So now there are two steps, and only the fast one is on the client's clock:

sequenceDiagram
  participant You
  participant I as install.sh
  participant C as MCP client
  participant L as launch.sh
  participant P as run/bin/native mcp
  You->>I: after a build you want the proxy to be
  I->>I: build //apps/native, copy it to run/bin/native, root its store paths
  C->>L: start the "jev" server
  L->>P: exec (bash builtins only, no build, no devshell)
  P-->>C: initialize answered in milliseconds

If there is no copy yet, launch.sh answers initialize with a JSON-RPC error saying to run install.sh, which the client shows, and exits.

Aside: why a copy that may be old is fine. The proxy (chapter 8) is a pass-through. It asks the window for its tool list and forwards calls by name, so the tools a client sees are the running window's, whatever build the proxy came from, and it speaks to the window over MCP's own streamable HTTP, which does not change with our code. A proxy several commits older than the window is normal and correct. Re-run install.sh only when packages/mcp/src/proxy.rs itself changes, then reconnect the client (/mcp in Claude Code), since the running proxy keeps its own copy.

Try it.

tools/mcp/install.sh
tools/mcp/test.sh

The second times initialize and tools/list through launch.sh in a bare environment, with and without a binary.

For the people who maintain it

In this folder

PathWhat
install.shBuilds //apps/native:native and copies it to run/bin/native, with the devshell's library path in run/bin/native.env and every store path it links rooted under run/bin/roots/. Re-execs itself inside nix develop if it is not already.
launch.shWhat .mcp.json runs. Execs the copy; if there is none, answers initialize with a JSON-RPC error saying to run install.sh, and exits. Bash builtins only, so it runs in a bare environment.
test.shTimes initialize and tools/list through launch.sh in a bare environment, with and without a binary, against a scratch copy of the layout.

← Previous: Chapter 24, tools/ · Up: tools · Next: Chapter 26, watch/ →