SatGate's MCP proxy aggregates upstream MCP servers and adds budget enforcement, cost attribution, and access control. Currently only stdio transport is implemented for upstreams. We need HTTP/SSE and Streamable HTTP transports so the proxy can connect to remote MCP servers over the network — this is required for any real enterprise deployment.
The Transport interface is in pkg/mcpserver/transport.go:
type Transport interface {
ReadMessage(ctx context.Context) (json.RawMessage, error)
WriteMessage(ctx context.Context, msg json.RawMessage) error
Close() error
}The UpstreamManager in pkg/mcpserver/upstream.go calls connect() which currently only supports stdio. The UpstreamConfig struct already has URL and Transport fields.
For MCP servers using the older SSE protocol (pre-2025-03-26 spec):
- Client→Server: HTTP POST to the upstream's message endpoint
- Server→Client: SSE stream (text/event-stream) for responses and notifications
- The SSE endpoint URL is obtained during initialization (server sends an
endpointevent) - Must handle SSE reconnection with exponential backoff
- Must handle
event: message(JSON-RPC response) andevent: endpoint(session URL) - Content-Type for POST:
application/json - Must pass session ID from SSE connection to POST requests
For MCP servers using the new Streamable HTTP protocol (2025-03-26 spec):
- Single endpoint: All communication via HTTP POST to one URL
- Request: POST with
Content-Type: application/json, body is JSON-RPC message - Response: Can be either:
Content-Type: application/json— single JSON-RPC responseContent-Type: text/event-stream— SSE stream of multiple responses (for long-running tools)
- Must include
Mcp-Session-Idheader after initialization (server provides it in init response) - GET request to same endpoint opens an SSE stream for server-initiated notifications
- DELETE request to same endpoint terminates the session
- Must handle both response types transparently
- Implement
connectHTTP(name string, cfg UpstreamConfig) (*UpstreamClient, error)for SSE - Implement
connectStreamable(name string, cfg UpstreamConfig) (*UpstreamClient, error)for Streamable HTTP - Update
connect()switch to route"sse"→connectHTTP,"http"or"streamable"→connectStreamable - Add reconnection logic in
readLoopfor HTTP transports (similar to stdio respawn)
transport: "sse"→ SSE transport (legacy)transport: "http"ortransport: "streamable"→ Streamable HTTP transport (preferred)urlfield is required for both- Optional
headersmap for auth headers (e.g.,Authorization: Bearer <token>) - Optional
tls_skip_verifyfor self-signed certs (development only)
Add to UpstreamConfig in config.go:
Headers map[string]string `yaml:"headers,omitempty"`
TLSSkipVerify bool `yaml:"tlsSkipVerify,omitempty"`- Unit tests for both transports using httptest.Server
- Test SSE reconnection behavior
- Test Streamable HTTP with both JSON and SSE response modes
- Test session management (Mcp-Session-Id lifecycle)
- Test timeout handling
- Test concurrent tool calls through HTTP transport
- Integration test: start mock MCP server over HTTP, connect, discover tools, call a tool
- No external dependencies beyond stdlib + zerolog (already in go.mod)
- Connection pooling via http.Client (reuse connections)
- Graceful shutdown: Close() must drain in-flight requests
- All errors must be wrapped with context (upstream name, URL, method)
- Debug logging for all HTTP requests/responses (zerolog)
- Must handle upstream returning 4xx/5xx gracefully (not crash)
- Race-free: safe for concurrent tool calls from multiple agents
- CREATE:
pkg/mcpserver/transport_sse.go - CREATE:
pkg/mcpserver/transport_sse_test.go - CREATE:
pkg/mcpserver/transport_streamable.go - CREATE:
pkg/mcpserver/transport_streamable_test.go - MODIFY:
pkg/mcpserver/upstream.go(add connectHTTP, connectStreamable) - MODIFY:
pkg/mcpserver/config.go(add Headers, TLSSkipVerify to UpstreamConfig) - MODIFY:
pkg/mcpserver/upstream.goconnect() switch
- Do not modify transport.go's Transport interface
- Do not change the stdio transport
- Do not add external dependencies
- Do not break existing tests (run
go test ./pkg/mcpserver/...)