Skip to content

Commit 73070f1

Browse files
committed
Allow Client#call_tool to accept a tool name
## Motivation and Context `Client#call_tool` previously required an `MCP::Client::Tool` object to call a tool. This made the API harder to use compared to other MCP SDK implementations, which accept a tool name string directly: - Python SDK: `session.call_tool(name, arguments)` accepts a name string. https://github.com/modelcontextprotocol/python-sdk/blob/v1.26.0/src/mcp/client/session.py#L370 - TypeScript SDK: `client.callTool({ name, arguments })` accepts a name string. https://github.com/modelcontextprotocol/typescript-sdk/blob/ccb78f2/packages/client/src/client/client.ts#L834 ## How Has This Been Tested? Updated existing tests and added new tests. ## Breaking Change No. This change adds a `name:` parameter so callers can pass a tool name string directly without looking up a `Tool` object first. The existing `tool:` parameter continues to work for backward compatibility.
1 parent 1b8e45f commit 73070f1

File tree

2 files changed

+37
-3
lines changed

2 files changed

+37
-3
lines changed

lib/mcp/client.rb

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,21 +92,29 @@ def prompts
9292

9393
# Calls a tool via the transport layer and returns the full response from the server.
9494
#
95+
# @param name [String] The name of the tool to call.
9596
# @param tool [MCP::Client::Tool] The tool to be called.
9697
# @param arguments [Object, nil] The arguments to pass to the tool.
9798
# @param progress_token [String, Integer, nil] A token to request progress notifications from the server during tool execution.
9899
# @return [Hash] The full JSON-RPC response from the transport.
99100
#
100-
# @example
101+
# @example Call by name
102+
# response = client.call_tool(name: "my_tool", arguments: { foo: "bar" })
103+
# content = response.dig("result", "content")
104+
#
105+
# @example Call with a tool object
101106
# tool = client.tools.first
102107
# response = client.call_tool(tool: tool, arguments: { foo: "bar" })
103108
# structured_content = response.dig("result", "structuredContent")
104109
#
105110
# @note
106111
# The exact requirements for `arguments` are determined by the transport layer in use.
107112
# Consult the documentation for your transport (e.g., MCP::Client::HTTP) for details.
108-
def call_tool(tool:, arguments: nil, progress_token: nil)
109-
params = { name: tool.name, arguments: arguments }
113+
def call_tool(name: nil, tool: nil, arguments: nil, progress_token: nil)
114+
tool_name = name || tool&.name
115+
raise ArgumentError, "Either `name:` or `tool:` must be provided." unless tool_name
116+
117+
params = { name: tool_name, arguments: arguments }
110118
if progress_token
111119
params[:_meta] = { progressToken: progress_token }
112120
end

test/mcp/client_test.rb

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,32 @@ def test_call_tool_sends_request_to_transport_and_returns_content
6767
assert_equal([{ type: "text", text: "Hello, world!" }], content)
6868
end
6969

70+
def test_call_tool_by_name
71+
transport = mock
72+
arguments = { foo: "bar" }
73+
mock_response = {
74+
"result" => { "content" => [{ "type": "text", "text": "Hello, world!" }] },
75+
}
76+
77+
transport.expects(:send_request).with do |args|
78+
args.dig(:request, :params, :name) == "tool1" &&
79+
args.dig(:request, :params, :arguments) == arguments
80+
end.returns(mock_response).once
81+
82+
client = Client.new(transport: transport)
83+
result = client.call_tool(name: "tool1", arguments: arguments)
84+
content = result.dig("result", "content")
85+
86+
assert_equal([{ type: "text", text: "Hello, world!" }], content)
87+
end
88+
89+
def test_call_tool_raises_when_no_name_or_tool
90+
client = Client.new(transport: mock)
91+
92+
error = assert_raises(ArgumentError) { client.call_tool(arguments: { foo: "bar" }) }
93+
assert_equal("Either `name:` or `tool:` must be provided.", error.message)
94+
end
95+
7096
def test_resources_sends_request_to_transport_and_returns_resources_array
7197
transport = mock
7298
mock_response = {

0 commit comments

Comments
 (0)