Extract server capabilities into dedicated Capabilities class

Refactor capabilities handling into MCP::Server::Capabilities to improve
code organization and separation of concerns. This provides a cleaner API
for configuring server capabilities including prompts, resources, tools,
completions, logging, and experimental features.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Kevin Fischer 2025-06-04 22:52:16 +09:00
commit 72663c0a3f
No known key found for this signature in database
GPG key ID: 8E4CB46A9AC8D1C1
3 changed files with 294 additions and 0 deletions

View file

@ -3,6 +3,7 @@
require "json_rpc_handler"
require_relative "instrumentation"
require_relative "methods"
require_relative "server/capabilities"
module MCP
class Server

View file

@ -0,0 +1,96 @@
# frozen_string_literal: true
module MCP
class Server
class Capabilities
def initialize(capabilities_hash = nil)
@completions = nil
@experimental = nil
@logging = nil
@prompts = nil
@resources = nil
@tools = nil
if capabilities_hash
support_completions if capabilities_hash.key?(:completions)
support_experimental(capabilities_hash[:experimental]) if capabilities_hash.key?(:experimental)
support_logging if capabilities_hash.key?(:logging)
if capabilities_hash.key?(:prompts)
support_prompts
prompts_config = capabilities_hash[:prompts] || {}
support_prompts_list_changed if prompts_config[:listChanged]
end
if capabilities_hash.key?(:resources)
support_resources
resources_config = capabilities_hash[:resources] || {}
support_resources_list_changed if resources_config[:listChanged]
support_resources_subscribe if resources_config[:subscribe]
end
if capabilities_hash.key?(:tools)
support_tools
tools_config = capabilities_hash[:tools] || {}
support_tools_list_changed if tools_config[:listChanged]
end
end
end
def support_completions
@completions ||= {}
end
def support_experimental(config = {})
@experimental = config || {}
end
def support_logging
@logging ||= {}
end
def support_prompts
@prompts ||= {}
end
def support_prompts_list_changed
support_prompts
@prompts[:listChanged] = true
end
def support_resources
@resources ||= {}
end
def support_resources_list_changed
support_resources
@resources[:listChanged] = true
end
def support_resources_subscribe
support_resources
@resources[:subscribe] = true
end
def support_tools
@tools ||= {}
end
def support_tools_list_changed
support_tools
@tools[:listChanged] = true
end
def to_h
{
completions: @completions,
experimental: @experimental,
logging: @logging,
prompts: @prompts,
resources: @resources,
tools: @tools,
}.compact
end
end
end
end

View file

@ -0,0 +1,197 @@
# 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