Part of #408. Depends on the response-sink refactor.
Why
MCP stdio spawns one child per client by design, so the best stdio can do is one process per session. A machine-wide singleton needs a transport many clients can share.
What
Add an HTTP listener behind an env flag (MCP_HTTP_PORT), keeping stdio as the default so existing installs are untouched.
Must match the streamable-HTTP MCP profile Claude Code already speaks — it connects to HTTP MCP servers with {"type":"http","url":...}, SSE-framed replies and an mcp-session-id header. Evidence it works: the daintree entry in a real ~/.claude.json is exactly this shape.
Note http/https are already imported in the server, but only for outbound provider health checks (transport.request at :498 and :579) — there is no listener today.
Acceptance
Part of #408. Depends on the response-sink refactor.
Why
MCP stdio spawns one child per client by design, so the best stdio can do is one process per session. A machine-wide singleton needs a transport many clients can share.
What
Add an HTTP listener behind an env flag (
MCP_HTTP_PORT), keeping stdio as the default so existing installs are untouched.Must match the streamable-HTTP MCP profile Claude Code already speaks — it connects to HTTP MCP servers with
{"type":"http","url":...}, SSE-framed replies and anmcp-session-idheader. Evidence it works: thedaintreeentry in a real~/.claude.jsonis exactly this shape.Note
http/httpsare already imported in the server, but only for outbound provider health checks (transport.requestat :498 and :579) — there is no listener today.Acceptance
MCP_HTTP_PORT=Nstarts a listener; unset keeps pure stdioinitialize/tools/list/tools/callall answer over HTTPmcp-session-idis honoured{"type":"http","url":...}and call a provider