Module: MCPClient::ServerSSE::OriginPolicy

Included in:
JsonRpcTransport, ReconnectMonitor, SseParser
Defined in:
lib/mcp_client/server_sse/origin_policy.rb

Overview

Origin pinning for the legacy HTTP+SSE transport.

Everything this transport sends carries the caller's configured headers (Authorization, API keys, cookies), and callback responses carry roots/sampling/elicitation data, so no request may leave the origin the caller connected to — neither by a server-chosen endpoint URI nor by a redirect.

Instance Method Summary collapse

Instance Method Details

#origin_of(uri) ⇒ String

Returns scheme://host:port of the URI.

Parameters:

  • uri (URI::Generic)

Returns:

  • (String)

    scheme://host:port of the URI



26
27
28
# File 'lib/mcp_client/server_sse/origin_policy.rb', line 26

def origin_of(uri)
  "#{uri.scheme}://#{uri.host}:#{uri.port}"
end

#reject_cross_origin_redirect!(_old_env, new_env) ⇒ void

This method returns an undefined value.

Refuse to follow a redirect that leaves the SSE connection's origin.

Pinning the endpoint event's origin is not sufficient on its own: a same-origin endpoint can answer a POST with a 307/308 to another origin, and faraday-follow_redirects replays the request there. It strips only the literal Authorization header, so configured API-key and other custom headers — plus the JSON-RPC body — would still reach the foreign origin.

Raises ConnectionError rather than TransportError because the server has already received the original request; with_retry must not re-send it.

Parameters:

  • _old_env (Faraday::Env)

    the redirecting response environment

  • new_env (Faraday::Env)

    environment of the request about to be replayed

Raises:



46
47
48
49
50
51
52
53
54
# File 'lib/mcp_client/server_sse/origin_policy.rb', line 46

def reject_cross_origin_redirect!(_old_env, new_env)
  base = URI.parse(@base_url)
  target = new_env.url
  return if same_origin?(base, target)

  message = "Refusing cross-origin redirect from #{origin_of(base)} to #{origin_of(target)}"
  @logger.error(message)
  raise MCPClient::Errors::ConnectionError, message
end

#same_origin?(base, other) ⇒ Boolean

Returns whether both share scheme, host and port.

Parameters:

  • base (URI::Generic)

    the SSE connection URL

  • other (URI::Generic)

    the URL to compare

Returns:

  • (Boolean)

    whether both share scheme, host and port



18
19
20
21
22
# File 'lib/mcp_client/server_sse/origin_policy.rb', line 18

def same_origin?(base, other)
  base.scheme == other.scheme &&
    base.host&.downcase == other.host&.downcase &&
    base.port == other.port
end