class LittleGhost::MCP::HTTPTransport
HTTPTransport sends MCP JSON-RPC messages over Streamable HTTP. It applies time and response-size limits and keeps the negotiated MCP session ID.
Security and trust
HTTPS is required by default. allow_insecure_http is only for an explicitly trusted local development endpoint. Scope caller-supplied credential headers to the target server. Response bodies and negotiated session IDs are validated before use.
One transport instance retains one negotiated MCP session ID and sends it with later requests. Scope the transport and its Client to one trusted server and one authenticated principal; never share that pair across tenants. LittleGhost does not send MCP session-termination DELETE requests, so configure server-side expiry or manage that lifecycle outside this transport when the server requires explicit cleanup.
Constants
- DEFAULT_MAX_RESPONSE_BYTES
-
Default upper bound for one
MCPresponse body (10 MiB).
Public Class Methods
# File lib/little_ghost/mcp/client.rb, line 38 def initialize(url:, headers: {}, timeout: 60, signer: nil, allow_insecure_http: false, max_response_bytes: DEFAULT_MAX_RESPONSE_BYTES) @uri = URI(url) unless %w[http https].include?(@uri.scheme) && @uri.host raise ConfigurationError, "MCP URL must be an HTTP(S) URL" end if @uri.scheme == "http" && !allow_insecure_http raise ConfigurationError, "MCP URL must use HTTPS unless allow_insecure_http is enabled" end @headers = headers.transform_keys(&:to_s).freeze @timeout = Float(timeout) raise ArgumentError, "timeout must be positive" unless @timeout.positive? @max_response_bytes = Integer(max_response_bytes) raise ArgumentError, "max_response_bytes must be positive" unless @max_response_bytes.positive? @signer = signer @session_id = nil end
Configures time and response-size limits. signer, when supplied, is called with each Net::HTTP request before it is sent.
Public Instance Methods
Source
# File lib/little_ghost/mcp/client.rb, line 61 def send(payload, context: nil) return perform_send(payload, timeout: @timeout) unless context response = nil stream = Support::InterruptibleStream.new( cancellation_token: context.cancellation_token, deadline: context.deadline ) do |emit| emit.call(perform_send(payload, timeout: context.remaining_time(@timeout))) end stream.each { |value| response = value } response end
Sends one JSON-RPC payload. A RunContext supplies cancellation and a deadline; without it the configured timeout applies.