Class: Phronomy::Tools::Mcp

Inherits:
Agent::Context::Capability::Base show all
Defined in:
lib/phronomy/tools/mcp.rb

Overview

A Phronomy::Agent::Context::Capability::Base subclass that wraps a tool exposed by an external MCP (Model Context Protocol) server.

Uses the official MCP Ruby SDK v1.x for transport handling, which provides the MCP initialize handshake, HTTP/SSE parsing, and request cancellation.

Supports two transport schemes:

Each generated tool instance owns one MCP client. Calls, reconnects, and explicit close operations are serialized because the SDK's stdio transport does not support concurrent response readers.

Examples:

web_search = Phronomy::Tools::Mcp.from_server(
  "stdio://./mcp-server",
  tool_name: "search_web"
)
agent_class.tools(web_search)

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Agent::Context::Capability::Base

approval_facts, #call, #call_async, execution_mode, max_result_size, #name, on_error, on_schema_error, param, param_enums, param_schemas, #params_schema, redact_params, requires_approval, #requires_approval, #requires_approval?, tool_name

Constructor Details

#initializeMcp

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.

Returns a new instance of Mcp.



315
316
317
318
319
# File 'lib/phronomy/tools/mcp.rb', line 315

def initialize
  @mcp_call_mutex = Mutex.new
  @mcp_client = nil
  build_and_connect_client!
end

Class Method Details

.from_server(server_uri, tool_name:, headers: {}) ⇒ Mcp

Build a Mcp instance by querying a running MCP server for the tool definition identified by tool_name.

additionalProperties omitted from the remote schema is accepted, but Phronomy still exposes and accepts only parameters declared in properties.

Parameters:

  • server_uri (String)

    URI of the MCP server.

  • tool_name (String)

    the tool name as registered in the MCP server

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

    additional HTTP headers forwarded to discovery and execution

Returns:

  • (Mcp)

    configured tool instance



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/phronomy/tools/mcp.rb', line 65

def from_server(server_uri, tool_name:, headers: {})
  transport = nil
  begin
    transport = build_transport(server_uri, headers: headers)
    client = MCP::Client.new(transport: transport)
    client.connect
    tool_def = extract_tool_def(client, tool_name.to_s, server_uri)
  rescue ArgumentError, Phronomy::ToolError
    raise
  rescue => e
    raise Phronomy::ToolError, "MCP connection failed: #{e.message}"
  ensure
    close_transport_safely(transport)
  end

  build_tool_class(tool_name, server_uri, tool_def, headers: headers).new
end

Instance Method Details

#approval_metadataObject



295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
# File 'lib/phronomy/tools/mcp.rb', line 295

def 
  scheme, rest = self.class.instance_variable_get(:@mcp_server_uri).to_s.split("://", 2)
  server_origin = case scheme
  when "http", "https"
    uri = URI.parse("#{scheme}://#{rest}")
    default_port = (scheme == "https") ? 443 : 80
    suffix = (uri.port == default_port) ? "" : ":#{uri.port}"
    "#{scheme}://#{uri.host}#{suffix}"
  when "stdio"
    command = Shellwords.split(rest.to_s).first
    "stdio://#{command}"
  else
    scheme.to_s
  end
  {transport: scheme&.to_sym, server_origin: server_origin}
rescue URI::InvalidURIError
  {transport: :unknown, server_origin: "unknown"}
end

#closevoid

This method returns an undefined value.

Closes the currently connected client synchronously. A transport already detached after cancellation is owned by the Runtime cleanup pool and is drained during Runtime shutdown; this method does not wait for that older cleanup operation.

The instance can be used again after close; the next call reconnects.



340
341
342
# File 'lib/phronomy/tools/mcp.rb', line 340

def close
  @mcp_call_mutex.synchronize { invalidate_mcp_client! }
end

#execute(cancellation_token: nil, **args) ⇒ String, ...

Executes the remote MCP tool.

Parameters:

Returns:

  • (String, Array, Hash)


325
326
327
328
329
330
# File 'lib/phronomy/tools/mcp.rb', line 325

def execute(cancellation_token: nil, **args)
  @mcp_call_mutex.synchronize do
    ensure_mcp_client!
    perform_mcp_call(cancellation_token: cancellation_token, args: args)
  end
end

#tool_originObject

MCP Tools fail closed by default and identify their remote origin.



291
292
293
# File 'lib/phronomy/tools/mcp.rb', line 291

def tool_origin
  :mcp
end