jevstrudel.git / tools / mcp / README.md

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) that buck2 run //:dev runs, 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, then shared-tools.json, as the Worker lists them). It polls the Worker's tool list and sends tools/list_changed when 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.

FileWhat it is
strudel-mcp.mjsThe stdio server: reads the ports, wires the rest together.
proxy.mjsForwarding and the environment switch, apart from stdio.
oauth.mjsThe OAuth client: the SDK's auth() plus the loopback redirect, state and iss checks, and revocation.
browser.mjsOpening the authorize page in the user's browser.
proxy.test.mjsnode --test: the switch and forwarding, against fakes (in nix flake check).
package.jsonThe 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.