Class: LLM::MCP

Inherits:
Object
  • Object
show all
Includes:
RPC
Defined in:
lib/llm/mcp.rb,
lib/llm/mcp/rpc.rb,
lib/llm/mcp/pipe.rb,
lib/llm/mcp/error.rb,
lib/llm/mcp/command.rb

Overview

The LLM::MCP class provides access to servers that implement the Model Context Protocol. MCP defines a standard way for clients and servers to exchange capabilities such as tools, prompts, resources, and other structured interactions.

In llm.rb, LLM::MCP currently supports stdio and HTTP transports and focuses on discovering tools that can be used through LLM::Context and LLM::Agent.

Like LLM::Context, an MCP client is stateful and is expected to remain isolated to a single thread.

Defined Under Namespace

Modules: RPC, Transport Classes: Command, Error, Pipe

Constant Summary collapse

TimeoutError =
Class.new(Error)
@@clients =
{}

Class Method Summary collapse

Instance Method Summary collapse

Methods included from RPC

#call

Constructor Details

#initialize(llm = nil, stdio: nil, http: nil, timeout: 30) ⇒ LLM::MCP

Returns A new MCP instance.

Parameters:

  • llm (LLM::Provider, nil) (defaults to: nil)

    The provider to use for MCP transports that need one

  • stdio (Hash, nil) (defaults to: nil)

    The configuration for the stdio transport

  • http (Hash, nil) (defaults to: nil)

    The configuration for the HTTP transport

  • timeout (Integer) (defaults to: 30)

    The maximum amount of time to wait when reading from an MCP process

Options Hash (stdio:):

  • :argv (Array<String>)

    The command to run for the MCP process

  • :env (Hash)

    The environment variables to set for the MCP process

  • :cwd (String, nil)

    The working directory for the MCP process

Options Hash (http:):

  • :url (String)

    The URL for the MCP HTTP endpoint

  • :headers (Hash)

    Extra headers for requests



71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/llm/mcp.rb', line 71

def initialize(llm = nil, stdio: nil, http: nil, timeout: 30)
  @llm = llm
  @timeout = timeout
  if stdio && http
    raise ArgumentError, "stdio and http are mutually exclusive"
  elsif stdio
    @command = Command.new(**stdio)
    @transport = Transport::Stdio.new(command:)
  elsif http
    @transport = Transport::HTTP.new(**http, timeout:)
  else
    raise ArgumentError, "stdio or http is required"
  end
end

Class Method Details

.clientsObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



29
# File 'lib/llm/mcp.rb', line 29

def self.clients = @@clients

.http(llm = nil, **http) ⇒ LLM::MCP

Builds an MCP client that uses the HTTP transport.

Parameters:

  • llm (LLM::Provider, nil) (defaults to: nil)

    An instance of LLM::Provider. Optional.

  • http (Hash)

    The HTTP transport configuration

Returns:



49
50
51
# File 'lib/llm/mcp.rb', line 49

def self.http(llm = nil, **http)
  new(llm, http:)
end

.stdio(llm = nil, **stdio) ⇒ LLM::MCP

Builds an MCP client that uses the stdio transport.

Parameters:

  • llm (LLM::Provider, nil) (defaults to: nil)

    An instance of LLM::Provider. Optional.

  • stdio (Hash)

    The stdio transport configuration

Returns:



38
39
40
# File 'lib/llm/mcp.rb', line 38

def self.stdio(llm = nil, **stdio)
  new(llm, stdio:)
end

Instance Method Details

#call_tool(name, arguments = {}) ⇒ Object

Calls a tool by name with the given arguments

Parameters:

  • name (String)

    The name of the tool to call

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

    The arguments to pass to the tool

Returns:

  • (Object)

    The result of the tool call



128
129
130
131
# File 'lib/llm/mcp.rb', line 128

def call_tool(name, arguments = {})
  res = call(transport, "tools/call", {name:, arguments:})
  adapt_tool_result(res)
end

#persist!LLM::MCP

Configures an HTTP MCP transport to use a persistent connection pool via the optional dependency [Net::HTTP::Persistent](github.com/drbrain/net-http-persistent)

Examples:

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

Returns:



110
111
112
113
# File 'lib/llm/mcp.rb', line 110

def persist!
  transport.persist!
  self
end

#startvoid

This method returns an undefined value.

Starts the MCP process.



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

def start
  transport.start
  call(transport, "initialize", {clientInfo: {name: "llm.rb", version: LLM::VERSION}})
  call(transport, "notifications/initialized")
end

#stopvoid

This method returns an undefined value.

Stops the MCP process.



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

def stop
  transport.stop
  nil
end

#toolsArray<Class<LLM::Tool>>

Returns the tools provided by the MCP process.

Returns:



118
119
120
121
# File 'lib/llm/mcp.rb', line 118

def tools
  res = call(transport, "tools/list")
  res["tools"].map { LLM::Tool.mcp(self, _1) }
end