Skip to content

Commit abce3e1

Browse files
committed
Test README per server configuration example
This test revealed that the `define_` helper methods were failing to ensure the server supports the type of capability they were defining.
1 parent 90f7746 commit abce3e1

File tree

4 files changed

+73
-0
lines changed

4 files changed

+73
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ or by creating an explicit configuration and passing it into the server.
155155
This is useful for systems where an application hosts more than one MCP server but
156156
they might require different instrumentation callbacks.
157157

158+
<!-- SNIPPET ID: per_server_configuration -->
158159
```ruby
159160
configuration = MCP::Configuration.new
160161
configuration.exception_reporter = ->(exception, server_context) {

lib/mcp/server.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,13 @@ def handle_json(request)
8787
end
8888

8989
def define_tool(name: nil, description: nil, input_schema: nil, annotations: nil, &block)
90+
@capabilities.support_tools
9091
tool = Tool.define(name:, description:, input_schema:, annotations:, &block)
9192
@tools[tool.name_value] = tool
9293
end
9394

9495
def define_prompt(name: nil, description: nil, arguments: [], &block)
96+
@capabilities.support_prompts
9597
prompt = Prompt.define(name:, description:, arguments:, &block)
9698
@prompts[prompt.name_value] = prompt
9799
end
@@ -102,6 +104,7 @@ def resources_list_handler(&block)
102104
end
103105

104106
def resources_read_handler(&block)
107+
@capabilities.support_resources
105108
@handlers[Methods::RESOURCES_READ] = block
106109
end
107110

@@ -116,6 +119,7 @@ def tools_list_handler(&block)
116119
end
117120

118121
def tools_call_handler(&block)
122+
@capabilities.support_tools
119123
@handlers[Methods::TOOLS_CALL] = block
120124
end
121125

@@ -125,6 +129,7 @@ def prompts_list_handler(&block)
125129
end
126130

127131
def prompts_get_handler(&block)
132+
@capabilities.support_prompts
128133
@handlers[Methods::PROMPTS_GET] = block
129134
end
130135

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# frozen_string_literal: true
2+
3+
require "mcp"
4+
5+
# Minimally mock Bugsnag for the test
6+
module Bugsnag
7+
class Report
8+
attr_reader :metadata
9+
10+
def initialize
11+
@metadata = {}
12+
end
13+
14+
def add_metadata(key, value)
15+
@metadata[key] = value
16+
end
17+
end
18+
19+
class << self
20+
def notify(exception)
21+
report = Report.new
22+
yield report
23+
puts "Bugsnag notified of #{exception.inspect} with metadata #{report.metadata.inspect}"
24+
end
25+
end
26+
end
27+
28+
b = binding
29+
eval(File.read("code_snippet.rb"), b) # rubocop:disable Security/Eval -- We need to run the snippet in this context
30+
server = b.local_variable_get(:server)
31+
32+
server.define_tool(name: "error_tool") { raise "boom" }
33+
34+
puts server.handle_json({
35+
jsonrpc: "2.0",
36+
id: "1",
37+
method: "tools/call",
38+
params: { name: "error_tool", arguments: {} },
39+
}.to_json)

test/integration/readme_code_snippets_test.rb

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,34 @@ class ReadmeCodeSnippetsTest < ActiveSupport::TestCase
8989
STDOUT
9090
end
9191

92+
test "Per-Server Configuration example works exactly as documented in README" do
93+
stdout = run_code_snippet("per_server_configuration")
94+
95+
request = {
96+
jsonrpc: "2.0",
97+
id: "1",
98+
method: "tools/call",
99+
params: { name: "error_tool", arguments: {} },
100+
}.to_json
101+
102+
error = MCP::Server::RequestHandlerError.new("Internal error calling tool error_tool", request)
103+
metadata = { model_context_protocol: { request: } }
104+
105+
response = {
106+
jsonrpc: "2.0",
107+
id: "1",
108+
error: { code: -32603, message: "Internal error", data: "Internal error calling tool error_tool" },
109+
}.to_json
110+
111+
expected_output = <<~OUTPUT
112+
Bugsnag notified of #{error.inspect} with metadata #{metadata.inspect}
113+
Got instrumentation data {method: "tools/call", tool_name: "error_tool", error: :internal_error, duration: 1.23}
114+
#{response}
115+
OUTPUT
116+
117+
assert_equal(expected_output, stdout)
118+
end
119+
92120
private
93121

94122
def assert_json_lines(expected, actual, message = "Expected the given JSON lines")

0 commit comments

Comments
 (0)