diff --git a/README.md b/README.md index 6440384..f754705 100644 --- a/README.md +++ b/README.md @@ -953,6 +953,7 @@ This class supports: - Tool listing via the `tools/list` method (`MCP::Client#tools`) - Tool invocation via the `tools/call` method (`MCP::Client#call_tools`) - Resource listing via the `resources/list` method (`MCP::Client#resources`) +- Resource template listing via the `resources/templates/list` method (`MCP::Client#resource_templates`) - Resource reading via the `resources/read` method (`MCP::Client#read_resources`) - Prompt listing via the `prompts/list` method (`MCP::Client#prompts`) - Prompt retrieval via the `prompts/get` method (`MCP::Client#get_prompt`) diff --git a/lib/mcp/client.rb b/lib/mcp/client.rb index 7ecf39a..eeb93a9 100644 --- a/lib/mcp/client.rb +++ b/lib/mcp/client.rb @@ -58,6 +58,20 @@ def resources response.dig("result", "resources") || [] end + # Returns the list of resource templates available from the server. + # Each call will make a new request – the result is not cached. + # + # @return [Array] An array of available resource templates. + def resource_templates + response = transport.send_request(request: { + jsonrpc: JsonRpcHandler::Version::V2_0, + id: request_id, + method: "resources/templates/list", + }) + + response.dig("result", "resourceTemplates") || [] + end + # Returns the list of prompts available from the server. # Each call will make a new request – the result is not cached. # diff --git a/test/mcp/client_test.rb b/test/mcp/client_test.rb index 168ed94..71422ee 100644 --- a/test/mcp/client_test.rb +++ b/test/mcp/client_test.rb @@ -145,6 +145,43 @@ def test_read_resource_returns_empty_array_when_no_contents assert_empty(contents) end + def test_resource_templates_sends_request_to_transport_and_returns_resource_templates_array + transport = mock + mock_response = { + "result" => { + "resourceTemplates" => [ + { "name" => "template1", "uriTemplate" => "file:///path/{filename}", "description" => "First template" }, + { "name" => "template2", "uriTemplate" => "http://example.com/{id}", "description" => "Second template" }, + ], + }, + } + + transport.expects(:send_request).with do |args| + args.dig(:request, :method) == "resources/templates/list" && args.dig(:request, :jsonrpc) == "2.0" + end.returns(mock_response).once + + client = Client.new(transport: transport) + resource_templates = client.resource_templates + + assert_equal(2, resource_templates.size) + assert_equal("template1", resource_templates.first["name"]) + assert_equal("file:///path/{filename}", resource_templates.first["uriTemplate"]) + assert_equal("template2", resource_templates.last["name"]) + assert_equal("http://example.com/{id}", resource_templates.last["uriTemplate"]) + end + + def test_resource_templates_returns_empty_array_when_no_resource_templates + transport = mock + mock_response = { "result" => { "resourceTemplates" => [] } } + + transport.expects(:send_request).returns(mock_response).once + + client = Client.new(transport: transport) + resource_templates = client.resource_templates + + assert_empty(resource_templates) + end + def test_prompts_sends_request_to_transport_and_returns_prompts_array transport = mock mock_response = {