Skip to content

Add MCP Streamable HTTP client transport #47

Description

@Hunter-Thompson

Summary

Add MCP Streamable HTTP as a supported client transport alongside the existing stdio transport.

The SDK currently models ServerConfig as stdio-only and rejects every non-stdio type in pkg/agentsdk/mcp/manager.go. This prevents SDK hosts from connecting to remotely deployed MCP servers even though the upstream dependency (github.com/modelcontextprotocol/go-sdk) supports the current MCP protocol surface.

This also follows the transport split described by MCP: stdio for locally managed subprocesses and Streamable HTTP for remote servers.

Current behavior

  • pkg/agentsdk/mcp/config.go documents ServerConfig as stdio-only.
  • NewManagerFromConfig rejects non-empty transport types other than stdio.
  • Connection and reconnection both call connectStdioServer directly.
  • Existing tool/resource wrapping, AllowedTools, read-only-hint policy, descriptor sanitization, config snapshotting, and reconnect behavior are coupled to a stdio-created serverConn.

Proposed scope

Configuration

Extend ServerConfig with a Streamable HTTP configuration shape, for example:

{
  "mcpServers": {
    "remote": {
      "type": "streamable-http",
      "url": "https://mcp.example.com/mcp",
      "headers": {
        "Authorization": "${MCP_REMOTE_AUTHORIZATION}"
      },
      "allowedTools": ["search"]
    }
  }
}

The final credential mechanism does not have to use this exact interpolation syntax, but secrets should be resolved through an explicit host/environment mechanism rather than encouraging plaintext credentials in .mcp.json.

Refactor connection setup behind a transport-specific factory so stdio remains behaviorally unchanged and reconnect uses the selected transport rather than calling connectStdioServer unconditionally.

Protocol and lifecycle

Streamable HTTP connections should support the same SDK-facing behavior as stdio where the remote server advertises it:

  • MCP initialize/session negotiation;
  • tool discovery and invocation;
  • resource listing and reading;
  • pagination;
  • context cancellation and configured connect/request deadlines;
  • clean Manager.Close behavior;
  • bounded reconnect after transport/session failure;
  • server identity and qualified tool naming identical to stdio;
  • existing AllowedTools, TrustReadOnlyHint, descriptor sanitization, and config snapshot checks.

Use the upstream MCP Go SDK transport rather than implementing the wire protocol locally where possible.

Security requirements

Remote MCP creates a different trust boundary from a local subprocess. The implementation should therefore:

  • require HTTPS by default, with an explicit development opt-in for loopback HTTP;
  • validate the initial URL and every redirect against the SDK's private-network/SSRF policy, or expose an equivalent host-supplied destination policy;
  • avoid forwarding ambient process credentials;
  • resolve only explicitly configured authentication headers/environment variables;
  • redact authorization, cookie, and other credential-bearing headers from logs, traces, snapshots, and returned errors;
  • apply connect, request, response-size, and idle limits;
  • preserve the existing treatment of remote descriptors and tool outputs as untrusted content;
  • never silently fall back from a failed HTTP transport to stdio or an unrestricted client.

If complete OAuth discovery/refresh support would make this issue too large, static host-supplied headers or a narrow request-authorization callback are sufficient for the first version; OAuth can be tracked separately.

Acceptance criteria

  • .mcp.json accepts an explicitly documented Streamable HTTP server type and URL.
  • Existing stdio configuration and behavior remain backward compatible.
  • A transport factory is used by initial connection and reconnection paths.
  • Remote tools can be listed and called through mcp.BuildTools.
  • Remote resources can be listed and read when advertised.
  • AllowedTools, permission mapping, read-only-hint trust, descriptor sanitization, and untrusted-output handling work identically across transports.
  • Cancellation, timeouts, session loss/reconnect, and manager shutdown are covered by deterministic httptest tests.
  • Tests cover HTTPS policy, loopback development opt-in, private-address/redirect rejection, and credential redaction.
  • The MCP feature example and public documentation include one remote-server configuration example and explain the security boundary.

Out of scope

  • Hosting an MCP server from this SDK.
  • Supporting the deprecated standalone HTTP+SSE transport.
  • Building a general OAuth product or storing long-lived credentials in the SDK.
  • Durable cross-session event delivery or waking inactive agents; those are separate orchestration concerns.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions