Summary
Add native support for remote MCP servers over Streamable HTTP (MCP 2025-03-26 / 2025-06-18) and the legacy HTTP+SSE transport, in addition to the existing stdio (local subprocess) transport.
Motivation
jcode currently only connects to MCP servers that run as local subprocesses speaking JSON-RPC over stdin/stdout. At config load time, any server entry with type: http / type: sse (Claude Code style) or a bare url is recognized and then skipped with a log line saying HTTP/SSE transports are not yet supported.
This is increasingly limiting:
- Hosted MCP gateways (e.g. Context7, Firecrawl, Zapier, GitHub Copilot's MCP endpoint, corporate proxy servers) are only reachable over Streamable HTTP. Users who use Claude Code with these servers cannot use them in jcode at all.
- Remote/centralized MCP servers over legacy SSE still exist in the wild; the protocol is deprecated but widely deployed, and Claude Code still accepts
type: sse configs.
- Users migrating from Claude Code already have
~/.claude.json / project .mcp.json files full of type: http + headers entries that jcode silently drops today.
Proposed design
- Config model: extend
McpServerConfig with a headers map (Claude Code compat: {"Authorization": "Bearer ..."} etc.) and add a TransportKind resolution (stdio / streamable-http / sse) driven by the type field, falling back to url presence.
- Transport layer: a new
transport.rs module with a shared ResponseRouter (correlates JSON-RPC responses to pending requests by id) and three transports:
StdioTransport — the existing subprocess path, moved out of client.rs unchanged in behavior.
StreamableHttpTransport — POST application/json; handles synchronous JSON responses, 202 Accepted + GET text/event-stream async responses, Mcp-Session-Id capture/echo, and forwards configured headers on every request.
SseTransport — legacy HTTP+SSE: GET opens the event stream, the endpoint event names the POST endpoint, responses come back over the stream.
- Loading: keep HTTP/SSE entries in config instead of dropping them; only entries with neither
command nor url are skipped.
- Schema cache: the tool-schema fingerprint must cover
url/headers/transport so cached schemas invalidate when a remote config changes.
- No API change upstream:
McpHandle / McpManager / SharedMcpPool / McpTool interfaces stay the same; only the transport plumbing changes.
Implementation status
A full implementation is already written and tested on a branch (feat/mcp-http-sse), including:
- 16 unit tests (SSE parser, response router, URL resolution)
- 4 end-to-end tests against an in-process TCP server (sync HTTP, async 202 + SSE, legacy SSE, header forwarding)
- Verified against the official reference MCP SDK (both Streamable HTTP and legacy SSE) and live production servers: Context7 (mcp.context7.com), Firecrawl, and a WebSearch/Fetch gateway, all with header auth working.
cargo fmt, clippy -D warnings (on the touched code), and cargo check --all-targets --all-features are clean; the existing 63 jcode-base + 14 app-core MCP tests pass.
The working branch is at Eivs:feat/mcp-http-sse; a PR can be opened from it once this issue is tracked.
Additional context
- Environment: macOS; the same behavior applies on Linux. HTTP/SSE support is transport-only, so the shared pool / session model is unaffected.
- Protocol versions targeted: Streamable HTTP per the 2025-03-26 and 2025-06-18 specs (async
202 + SSE, session id header), plus the legacy 2024-era SSE transport for backward compatibility.
- The existing stdio behavior is preserved exactly; this is purely additive.
Thanks for considering. Happy to rebase / adjust the PR based on maintainer preference (e.g. splitting the SSE transport out if you'd rather land Streamable HTTP first).
Summary
Add native support for remote MCP servers over Streamable HTTP (MCP 2025-03-26 / 2025-06-18) and the legacy HTTP+SSE transport, in addition to the existing stdio (local subprocess) transport.
Motivation
jcode currently only connects to MCP servers that run as local subprocesses speaking JSON-RPC over stdin/stdout. At config load time, any server entry with
type: http/type: sse(Claude Code style) or a bareurlis recognized and then skipped with a log line saying HTTP/SSE transports are not yet supported.This is increasingly limiting:
type: sseconfigs.~/.claude.json/ project.mcp.jsonfiles full oftype: http+headersentries that jcode silently drops today.Proposed design
McpServerConfigwith aheadersmap (Claude Code compat:{"Authorization": "Bearer ..."}etc.) and add aTransportKindresolution (stdio/streamable-http/sse) driven by thetypefield, falling back tourlpresence.transport.rsmodule with a sharedResponseRouter(correlates JSON-RPC responses to pending requests by id) and three transports:StdioTransport— the existing subprocess path, moved out ofclient.rsunchanged in behavior.StreamableHttpTransport— POSTapplication/json; handles synchronous JSON responses,202 Accepted+ GETtext/event-streamasync responses,Mcp-Session-Idcapture/echo, and forwards configured headers on every request.SseTransport— legacy HTTP+SSE: GET opens the event stream, theendpointevent names the POST endpoint, responses come back over the stream.commandnorurlare skipped.url/headers/transportso cached schemas invalidate when a remote config changes.McpHandle/McpManager/SharedMcpPool/McpToolinterfaces stay the same; only the transport plumbing changes.Implementation status
A full implementation is already written and tested on a branch (
feat/mcp-http-sse), including:cargo fmt, clippy-D warnings(on the touched code), andcargo check --all-targets --all-featuresare clean; the existing 63 jcode-base + 14 app-core MCP tests pass.The working branch is at
Eivs:feat/mcp-http-sse; a PR can be opened from it once this issue is tracked.Additional context
202+ SSE, session id header), plus the legacy 2024-era SSE transport for backward compatibility.Thanks for considering. Happy to rebase / adjust the PR based on maintainer preference (e.g. splitting the SSE transport out if you'd rather land Streamable HTTP first).