Class: LLM::MCP::Transport::HTTP

Inherits:
Object
  • Object
show all
Defined in:
lib/llm/mcp/transport/http.rb

Overview

The LLM::MCP::Transport::HTTP class provides an HTTP transport for LLM::MCP. It sends JSON-RPC messages with HTTP POST requests and buffers response messages for non-blocking reads.

Instance Method Summary collapse

Constructor Details

#initialize(url:, headers: {}, timeout: nil) ⇒ LLM::MCP::Transport::HTTP

Parameters:

  • url (String)

    The URL for the MCP HTTP endpoint

  • headers (Hash) (defaults to: {})

    Extra headers to send with requests

  • timeout (Integer, nil) (defaults to: nil)

    The timeout in seconds. Defaults to nil



20
21
22
23
24
25
26
27
28
# File 'lib/llm/mcp/transport/http.rb', line 20

def initialize(url:, headers: {}, timeout: nil)
  @uri = URI.parse(url)
  @use_ssl = @uri.scheme == "https"
  @headers = headers
  @timeout = timeout
  @queue = []
  @monitor = Monitor.new
  @running = false
end

Instance Method Details

#write(message) ⇒ void

This method returns an undefined value.

Writes a JSON-RPC message via HTTP POST.

Parameters:

  • message (Hash)

    The JSON-RPC message

Raises:

  • (LLM::MCP::Error)

    When the transport is not running or the HTTP request fails



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/llm/mcp/transport/http.rb', line 62

def write(message)
  raise LLM::MCP::Error, "MCP transport is not running" unless running?
  req = Net::HTTP::Post.new(uri.path, headers.merge("content-type" => "application/json"))
  req.body = LLM.json.dump(message)
  if persistent_client.nil?
    http = Net::HTTP.start(uri.host, uri.port, use_ssl:, open_timeout: timeout, read_timeout: timeout)
    args = [req]
  else
    http = persistent_client
    args = [uri, req]
  end
  http.request(*args) do |res|
    unless Net::HTTPSuccess === res
      raise LLM::MCP::Error, "MCP transport write failed with HTTP #{res.code}"
    end
    read(res)
  end
end

#startvoid

This method returns an undefined value.

Starts the HTTP transport.

Raises:



35
36
37
38
39
40
41
# File 'lib/llm/mcp/transport/http.rb', line 35

def start
  lock do
    raise LLM::MCP::Error, "MCP transport is already running" if running?
    @queue.clear
    @running = true
  end
end

#stopvoid

This method returns an undefined value.

Stops the HTTP transport and closes the connection. This method is idempotent.



47
48
49
50
51
52
53
# File 'lib/llm/mcp/transport/http.rb', line 47

def stop
  lock do
    return nil unless running?
    @running = false
    nil
  end
end

#read_nonblockHash

Reads the next queued message without blocking.

Returns:

  • (Hash)

Raises:

  • (LLM::MCP::Error)

    When the transport is not running

  • (IO::WaitReadable)

    When no complete message is available to read



88
89
90
91
92
93
94
# File 'lib/llm/mcp/transport/http.rb', line 88

def read_nonblock
  lock do
    raise LLM::MCP::Error, "MCP transport is not running" unless running?
    raise IO::WaitReadable if @queue.empty?
    @queue.shift
  end
end

#running?Boolean

Returns true when the MCP server connection is alive

Returns:

  • (Boolean)

    Returns true when the MCP server connection is alive



99
100
101
# File 'lib/llm/mcp/transport/http.rb', line 99

def running?
  @running
end

#persist!LLM::MCP::Transport::HTTP Also known as: persistent

Configures the transport to use a persistent HTTP connection pool via the optional dependency Net::HTTP::Persistent

Examples:

mcp = LLM.mcp(http: {url: "https://example.com/mcp"}).persistent
# do something with 'mcp'

Returns:



110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/llm/mcp/transport/http.rb', line 110

def persist!
  LLM.lock(:mcp) do
    require "net/http/persistent" unless defined?(Net::HTTP::Persistent)
    unless LLM::MCP.clients.key?(key)
      http = Net::HTTP::Persistent.new(name: self.class.name)
      http.read_timeout = timeout
      http.open_timeout = timeout
      LLM::MCP.clients[key] ||= http
    end
  end
  self
end