Module: Omakase::MCP

Defined in:
lib/omakase/mcp.rb

Overview

An MCP server's tools, as methods on the agent — so generated code calls a remote tool the same way it calls anything else the agent exposes.

Class Method Summary collapse

Class Method Details

.attach(agent_class, client) ⇒ Object



9
10
11
12
13
14
15
16
17
18
19
20
# File 'lib/omakase/mcp.rb', line 9

def attach(agent_class, client)
  client.tools.each do |tool|
    name = method_name(tool)
    # A remote tool list must not quietly shadow a capability the agent already has.
    raise Error, "#{agent_class} already has ##{name}" if Capabilities.names(agent_class).include?(name)

    agent_class.describe(description(tool))
    # nil is how a model leaves an argument out; MCP servers reject it.
    agent_class.define_method(name) { |**arguments| MCP.result(tool.execute(**arguments.compact)) }
  end
  client
end

.description(tool) ⇒ Object

The signature is **arguments, so what those arguments are goes here.



33
34
35
36
37
38
39
40
41
# File 'lib/omakase/mcp.rb', line 33

def description(tool)
  schema = tool.params_schema || {}
  required = schema["required"] || []
  arguments = (schema["properties"] || {}).map do |name, property|
    "#{name}: #{property["type"]}#{" (required)" if required.include?(name)}"
  end
  text = tool.description.to_s.gsub(/\s+/, " ").strip
  [text, ("Arguments — #{arguments.join(", ")}" if arguments.any?)].compact.join(" ")
end

.method_name(tool) ⇒ Object

Tool names may hold characters a Ruby method name cannot.



23
# File 'lib/omakase/mcp.rb', line 23

def method_name(tool) = tool.name.tr("-", "_").to_sym

.result(value) ⇒ Object

ponytail: text only — an image or audio result is dropped.

Raises:



26
27
28
29
30
# File 'lib/omakase/mcp.rb', line 26

def result(value)
  raise Error, value[:error] if value.is_a?(Hash) && value[:error]

  value.to_s
end