Simplify capability handling again

This commit is contained in:
Kevin Fischer 2025-06-14 16:40:22 +09:00
commit d7c866efcf
No known key found for this signature in database
GPG key ID: 8E4CB46A9AC8D1C1
3 changed files with 13 additions and 277 deletions

View file

@ -3,7 +3,6 @@
require "json_rpc_handler"
require_relative "instrumentation"
require_relative "methods"
require_relative "server/capabilities"
module MCP
class Server
@ -23,8 +22,7 @@ module MCP
include Instrumentation
attr_writer :capabilities
attr_accessor :name, :version, :tools, :prompts, :resources, :server_context, :configuration, :transport
attr_accessor :name, :version, :tools, :prompts, :resources, :server_context, :configuration, :capabilities, :transport
def initialize(
name: "model_context_protocol",
@ -47,10 +45,7 @@ module MCP
@resource_index = index_resources_by_uri(resources)
@server_context = server_context
@configuration = MCP.configuration.merge(configuration)
@capabilities = Capabilities.new(capabilities)
@capabilities.support_tools if tools.any?
@capabilities.support_prompts if prompts.any?
@capabilities.support_resources if resources.any? || resource_templates.any?
@capabilities = capabilities || default_capabilities
@handlers = {
Methods::RESOURCES_LIST => method(:list_resources),
@ -72,10 +67,6 @@ module MCP
@transport = transport
end
def capabilities
@capabilities.to_h
end
def handle(request)
JsonRpcHandler.handle(request) do |method|
handle_request(request, method)
@ -123,7 +114,6 @@ module MCP
end
def resources_list_handler(&block)
@capabilities.support_resources
@handlers[Methods::RESOURCES_LIST] = block
end
@ -132,12 +122,10 @@ module MCP
end
def resources_templates_list_handler(&block)
@capabilities.support_resources
@handlers[Methods::RESOURCES_TEMPLATES_LIST] = block
end
def tools_list_handler(&block)
@capabilities.support_tools
@handlers[Methods::TOOLS_LIST] = block
end
@ -146,7 +134,6 @@ module MCP
end
def prompts_list_handler(&block)
@capabilities.support_prompts
@handlers[Methods::PROMPTS_LIST] = block
end
@ -194,6 +181,14 @@ module MCP
}
end
def default_capabilities
{
tools: { listChanged: true },
prompts: { listChanged: true },
resources: { listChanged: true },
}
end
def server_info
@server_info ||= {
name:,

View file

@ -1,197 +0,0 @@
# frozen_string_literal: true
require "test_helper"
module MCP
class Server
class CapabilitiesTest < ActiveSupport::TestCase
test "can be initialized with a capabilities hash" do
capabilities = MCP::Server::Capabilities.new(prompts: {})
assert_equal({ prompts: {} }, capabilities.to_h)
end
test "ignores unknown values in capabilities hash" do
capabilities = MCP::Server::Capabilities.new(prompts: {}, invalid: :value)
assert_equal({ prompts: {} }, capabilities.to_h)
end
test "support prompts" do
capabilities = MCP::Server::Capabilities.new
capabilities.support_prompts
assert_operator capabilities.to_h, :key?, :prompts
end
test "support resources" do
capabilities = MCP::Server::Capabilities.new
capabilities.support_resources
assert_operator capabilities.to_h, :key?, :resources
end
test "support tools" do
capabilities = MCP::Server::Capabilities.new
capabilities.support_tools
assert_operator capabilities.to_h, :key?, :tools
end
test "support completions" do
capabilities = MCP::Server::Capabilities.new
capabilities.support_completions
assert_operator capabilities.to_h, :key?, :completions
assert_empty(capabilities.to_h[:completions])
end
test "support logging" do
capabilities = MCP::Server::Capabilities.new
capabilities.support_logging
assert_operator capabilities.to_h, :key?, :logging
assert_empty(capabilities.to_h[:logging])
end
test "support experimental with custom config" do
capabilities = MCP::Server::Capabilities.new
capabilities.support_experimental({ myFeature: { enabled: true } })
assert_operator capabilities.to_h, :key?, :experimental
assert_equal({ myFeature: { enabled: true } }, capabilities.to_h[:experimental])
end
test "support prompts list changed" do
capabilities = MCP::Server::Capabilities.new
capabilities.support_prompts_list_changed
assert_equal({ prompts: { listChanged: true } }, capabilities.to_h)
end
test "support resources list changed" do
capabilities = MCP::Server::Capabilities.new
capabilities.support_resources_list_changed
assert_equal({ resources: { listChanged: true } }, capabilities.to_h)
end
test "support resources subscribe" do
capabilities = MCP::Server::Capabilities.new
capabilities.support_resources_subscribe
assert_equal({ resources: { subscribe: true } }, capabilities.to_h)
end
test "support resources with both list changed and subscribe" do
capabilities = MCP::Server::Capabilities.new
capabilities.support_resources_list_changed
capabilities.support_resources_subscribe
assert_equal({ resources: { listChanged: true, subscribe: true } }, capabilities.to_h)
end
test "support tools list changed" do
capabilities = MCP::Server::Capabilities.new
capabilities.support_tools_list_changed
assert_equal({ tools: { listChanged: true } }, capabilities.to_h)
end
test "initializes with prompts list changed from hash" do
capabilities = MCP::Server::Capabilities.new(prompts: { listChanged: true })
assert_equal({ prompts: { listChanged: true } }, capabilities.to_h)
end
test "initializes with resources list changed and subscribe from hash" do
capabilities = MCP::Server::Capabilities.new(resources: { listChanged: true, subscribe: true })
assert_equal({ resources: { listChanged: true, subscribe: true } }, capabilities.to_h)
end
test "initializes with tools list changed from hash" do
capabilities = MCP::Server::Capabilities.new(tools: { listChanged: true })
assert_equal({ tools: { listChanged: true } }, capabilities.to_h)
end
test "initializes with completions from hash" do
capabilities = MCP::Server::Capabilities.new(completions: {})
assert_equal({ completions: {} }, capabilities.to_h)
end
test "initializes with logging from hash" do
capabilities = MCP::Server::Capabilities.new(logging: {})
assert_equal({ logging: {} }, capabilities.to_h)
end
test "initializes with experimental config from hash" do
capabilities = MCP::Server::Capabilities.new(experimental: { feature1: { enabled: true }, feature2: "config" })
assert_equal({ experimental: { feature1: { enabled: true }, feature2: "config" } }, capabilities.to_h)
end
test "initializes with all capabilities from hash" do
capabilities = MCP::Server::Capabilities.new(
completions: {},
experimental: { customFeature: true },
logging: {},
prompts: { listChanged: true },
resources: { listChanged: true, subscribe: true },
tools: { listChanged: true },
)
expected = {
completions: {},
experimental: { customFeature: true },
logging: {},
prompts: { listChanged: true },
resources: { listChanged: true, subscribe: true },
tools: { listChanged: true },
}
assert_equal(expected, capabilities.to_h)
end
test "handles nil values in capabilities hash gracefully" do
capabilities = MCP::Server::Capabilities.new(
prompts: nil,
resources: nil,
tools: nil,
)
assert_equal({ prompts: {}, resources: {}, tools: {} }, capabilities.to_h)
end
test "to_h returns empty hash when no capabilities are set" do
capabilities = MCP::Server::Capabilities.new
assert_empty(capabilities.to_h)
end
test "calling support methods multiple times does not duplicate entries" do
capabilities = MCP::Server::Capabilities.new
capabilities.support_prompts
capabilities.support_prompts
capabilities.support_prompts_list_changed
assert_equal({ prompts: { listChanged: true } }, capabilities.to_h)
end
end
end
end

View file

@ -116,9 +116,9 @@ module MCP
"result": {
"protocolVersion": "2024-11-05",
"capabilities": {
"prompts": {},
"resources": {},
"tools": {},
"prompts": { listChanged: true },
"resources": { listChanged: true },
"tools": { listChanged: true },
},
"serverInfo": {
"name": @server_name,
@ -778,68 +778,6 @@ module MCP
assert_equal custom_version, response[:result][:protocolVersion]
end
test "has tool capability only if tools or a tools_list_handler is defined" do
server_with_tools = Server.new(name: "test_server", tools: [@tool])
assert_includes server_with_tools.capabilities, :tools
server_with_handler = Server.new(name: "test_server")
server_with_handler.tools_list_handler do
[{ name: "test_tool", description: "Test tool" }]
end
assert_includes server_with_handler.capabilities, :tools
server_without_tools = Server.new(name: "test_server")
refute_includes server_without_tools.capabilities, :tools
end
test "has prompt capability only if prompts or a prompts_list_handler is defined" do
server_with_prompts = Server.new(name: "test_server", prompts: [@prompt])
assert_includes server_with_prompts.capabilities, :prompts
server_with_handler = Server.new(name: "test_server")
server_with_handler.prompts_list_handler do
[{ name: "test_prompt", description: "Test prompt" }]
end
assert_includes server_with_handler.capabilities, :prompts
server_without_prompts = Server.new(name: "test_server")
refute_includes server_without_prompts.capabilities, :prompts
end
test "has resources capability only if resources, template or custom handler is defined" do
server_with_resources = Server.new(name: "test_server", resources: [@resource])
assert_includes server_with_resources.capabilities, :resources
server_with_resource_template = Server.new(name: "test_server", resource_templates: [@resource_template])
assert_includes server_with_resource_template.capabilities, :resources
server_with_resources_list_handler = Server.new(name: "test_server")
server_with_resources_list_handler.resources_list_handler do
[{ uri: "test_resource", name: "Test resource", description: "Test resource" }]
end
assert_includes server_with_resources_list_handler.capabilities, :resources
server_with_resources_templates_list_handler = Server.new(name: "test_server")
server_with_resources_templates_list_handler.resources_templates_list_handler do
[{ uri_template: "test_resource/{id}", name: "Test resource", description: "Test resource" }]
end
assert_includes server_with_resources_templates_list_handler.capabilities, :resources
server_without_resources = Server.new(name: "test_server")
refute_includes server_without_resources.capabilities, :resources
end
test "tools/call validates arguments against input schema when validate_tool_call_arguments is true" do
server = Server.new(
tools: [TestTool],