tools/mcp
strudel-mcp.mjs is the MCP server Claude Code starts from .mcp.json
(nix run .#mcp). It speaks MCP over stdio and forwards each message to
one of two jevstrudel environments:
- dev (the default): the jevstrudel Worker's MCP endpoint
(
worker/src/mcp.ts) thatbuck2 run //:devruns, playing into this machine's tabs with no sign-in. It keeps no connection, so the Worker can restart or reload under a running Claude Code session; while it is down, tool calls say how to start it, and the tool list is the Worker's own files (worker/src/tools.json, thenshared-tools.json, as the Worker lists them). It polls the Worker's tool list and sendstools/list_changedwhen it changes, so an edited tool reaches Claude Code without a restart. - prod: the public site's hosted MCP (
/jev/mcp,worker/README.md, The hosted MCP), as the user's own account.
The proxy adds one tool of its own to either list, use_environment:
{ "environment": "prod" } or "dev" switches, and with no argument it
says which is in use. A switch sends tools/list_changed, since the lists
differ (prod has list_songs, publish_song, comment, …; both have the
shared tools, list_sounds, ask_jev_sound, api_reference, the settings,
play_song, ask_jev_song, react and vote).
The first switch to prod signs in. The proxy is an OAuth client of the
site: the MCP SDK's auth() does discovery, dynamic registration, PKCE and
the token exchange; the proxy listens for the redirect on 127.0.0.1 and
a random port and opens the authorize page in the Windows browser
(rundll32.exe url.dll,FileProtocolHandler through WSL interop). The user
signs in with a passkey and allows the app; the call waits up to two
minutes for that, and if it takes longer, answers with the URL and switches
by itself when the sign-in completes. A token prod refuses later (expired,
or the app disconnected in the account panel) is refreshed silently, or
else the call answers with a new sign-in's URL. Rate limits and missing
scopes come back as tool errors saying so.
The tokens and the registration are in the proxy's memory only: a new Claude Code session signs in once, and the proxy revokes its grant when it exits.
| File | What it is |
|---|---|
strudel-mcp.mjs | The stdio server: reads the ports, wires the rest together. |
proxy.mjs | Forwarding and the environment switch, apart from stdio. |
oauth.mjs | The OAuth client: the SDK's auth() plus the loopback redirect, state and iss checks, and revocation. |
browser.mjs | Opening the authorize page in the user's browser. |
proxy.test.mjs | node --test: the switch and forwarding, against fakes (in nix flake check). |
package.json | The MCP SDK, pinned; package-lock.json is what nix fetches. |
tools/mcp-e2e/proxy.mjs runs the prod path end to end against a local
production Worker.