Skip to content

Change default proxy mode from deprecated SSE to streaming-http #2210

@JAORMX

Description

@JAORMX

Problem

ToolHive currently defaults to using the SSE (Server-Sent Events) transport for proxying MCP servers. However, the SSE transport is deprecated in favor of the newer streaming-http transport (also referred to as streamable-http in the codebase).

According to the MCP specification, the streaming-http transport is the recommended approach for HTTP-based MCP communication.

Current Behavior

The default proxy mode is set to SSE in two locations in the CLI/API:

  1. CLI (cmd/thv/app/run_flags.go:384):

    func validateAndSetupProxyMode(runFlags *RunFlags) error {
        if !types.IsValidProxyMode(runFlags.ProxyMode) {
            if runFlags.ProxyMode == "" {
                runFlags.ProxyMode = types.ProxyModeSSE.String() // default to SSE for backward compatibility
            } else {
                return fmt.Errorf("invalid value for --proxy-mode: %s", runFlags.ProxyMode)
            }
        }
        return nil
    }
  2. API (pkg/api/v1/workload_service.go:98):

    // Default proxy mode to SSE if not specified
    if !types.IsValidProxyMode(req.ProxyMode) {
        if req.ProxyMode == "" {
            req.ProxyMode = types.ProxyModeSSE.String()
        } else {
            return nil, fmt.Errorf("%w: %s", retriever.ErrInvalidRunConfig, fmt.Sprintf("Invalid proxy_mode: %s", req.ProxyMode))
        }
    }

Expected Behavior

The default proxy mode should be streamable-http instead of sse to align with:

  • Modern MCP specification recommendations
  • The deprecation of the SSE transport
  • Better performance and reliability characteristics of streaming-http

Proposed Solution

Change the default proxy mode from types.ProxyModeSSE to types.ProxyModeStreamableHTTP in both locations:

  1. Update cmd/thv/app/run_flags.go:384:

    func validateAndSetupProxyMode(runFlags *RunFlags) error {
        if !types.IsValidProxyMode(runFlags.ProxyMode) {
            if runFlags.ProxyMode == "" {
                runFlags.ProxyMode = types.ProxyModeStreamableHTTP.String() // default to streamable-http (SSE is deprecated)
            } else {
                return fmt.Errorf("invalid value for --proxy-mode: %s", runFlags.ProxyMode)
            }
        }
        return nil
    }
  2. Update pkg/api/v1/workload_service.go:98:

    // Default proxy mode to streamable-http if not specified (SSE is deprecated)
    if !types.IsValidProxyMode(req.ProxyMode) {
        if req.ProxyMode == "" {
            req.ProxyMode = types.ProxyModeStreamableHTTP.String()
        } else {
            return nil, fmt.Errorf("%w: %s", retriever.ErrInvalidRunConfig, fmt.Sprintf("Invalid proxy_mode: %s", req.ProxyMode))
        }
    }

Impact

  • Breaking change: Users relying on the default SSE behavior will need to explicitly specify:
    • CLI: --proxy-mode sse
    • API: "proxyMode": "sse"
  • Migration path: Users can explicitly set the proxy mode during the transition period
  • Benefits:
    • Better alignment with MCP specification
    • Improved performance and reliability
    • Future-proofing as SSE support may be removed

Additional Context

The codebase already has full support for streaming-http transport:

  • Transport type defined: types.TransportTypeStreamableHTTP
  • Proxy mode defined: types.ProxyModeStreamableHTTP
  • Implementation: pkg/transport/proxy/streamable/
  • Tests: Multiple e2e tests for streamable-http transport

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions