Skip to content

Commit 7b910bc

Browse files
committed
Fix default handler return values to comply with MCP spec
The no-op handlers for `completion/complete`, `resources/subscribe`, and `resources/unsubscribe` returned `nil`. When a client accesses the expected response structure (e.g., `result[:completion][:values]`), a `nil` result raises `NoMethodError`. The MCP spec requires specific response structures even for no-op handlers. Returning spec-compliant defaults ensures that clients receive valid responses without requiring servers to explicitly override each handler. `completion/complete` now returns `{ completion: { values: [], hasMore: false } }`. ref: https://modelcontextprotocol.io/specification/2025-11-25/server/utilities/completion `resources/subscribe` and `resources/unsubscribe` now return `{}` (empty result). ref: https://modelcontextprotocol.io/specification/2025-11-25/server/resources#subscriptions
1 parent 5b04089 commit 7b910bc

File tree

2 files changed

+84
-3
lines changed

2 files changed

+84
-3
lines changed

lib/mcp/server.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,9 @@ def initialize(
9999
Methods::LOGGING_SET_LEVEL => method(:configure_logging_level),
100100

101101
# No op handlers for currently unsupported methods
102-
Methods::RESOURCES_SUBSCRIBE => ->(_) {},
103-
Methods::RESOURCES_UNSUBSCRIBE => ->(_) {},
104-
Methods::COMPLETION_COMPLETE => ->(_) {},
102+
Methods::RESOURCES_SUBSCRIBE => ->(_) { {} },
103+
Methods::RESOURCES_UNSUBSCRIBE => ->(_) { {} },
104+
Methods::COMPLETION_COMPLETE => ->(_) { { completion: { values: [], hasMore: false } } },
105105
Methods::ELICITATION_CREATE => ->(_) {},
106106
}
107107
@transport = transport

test/mcp/server_test.rb

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1540,6 +1540,87 @@ class Example < Tool
15401540
assert_includes response[:result][:content][0][:text], "Invalid arguments"
15411541
end
15421542

1543+
test "#handle completion/complete returns default completion result" do
1544+
server = Server.new(
1545+
name: "test_server",
1546+
capabilities: { completions: {} },
1547+
)
1548+
1549+
server.handle({ jsonrpc: "2.0", method: "initialize", id: 1 })
1550+
server.handle({ jsonrpc: "2.0", method: "notifications/initialized" })
1551+
1552+
response = server.handle({
1553+
jsonrpc: "2.0",
1554+
id: 2,
1555+
method: "completion/complete",
1556+
params: {
1557+
ref: { type: "ref/prompt", name: "test" },
1558+
argument: { name: "arg", value: "val" },
1559+
},
1560+
})
1561+
1562+
assert_equal(
1563+
{
1564+
jsonrpc: "2.0",
1565+
id: 2,
1566+
result: { completion: { values: [], hasMore: false } },
1567+
},
1568+
response,
1569+
)
1570+
end
1571+
1572+
test "#handle resources/subscribe returns empty result" do
1573+
server = Server.new(
1574+
name: "test_server",
1575+
capabilities: { resources: { subscribe: true } },
1576+
)
1577+
1578+
server.handle({ jsonrpc: "2.0", method: "initialize", id: 1 })
1579+
server.handle({ jsonrpc: "2.0", method: "notifications/initialized" })
1580+
1581+
response = server.handle({
1582+
jsonrpc: "2.0",
1583+
id: 2,
1584+
method: "resources/subscribe",
1585+
params: { uri: "https://example.com/resource" },
1586+
})
1587+
1588+
assert_equal(
1589+
{
1590+
jsonrpc: "2.0",
1591+
id: 2,
1592+
result: {},
1593+
},
1594+
response,
1595+
)
1596+
end
1597+
1598+
test "#handle resources/unsubscribe returns empty result" do
1599+
server = Server.new(
1600+
name: "test_server",
1601+
capabilities: { resources: { subscribe: true } },
1602+
)
1603+
1604+
server.handle({ jsonrpc: "2.0", method: "initialize", id: 1 })
1605+
server.handle({ jsonrpc: "2.0", method: "notifications/initialized" })
1606+
1607+
response = server.handle({
1608+
jsonrpc: "2.0",
1609+
id: 2,
1610+
method: "resources/unsubscribe",
1611+
params: { uri: "https://example.com/resource" },
1612+
})
1613+
1614+
assert_equal(
1615+
{
1616+
jsonrpc: "2.0",
1617+
id: 2,
1618+
result: {},
1619+
},
1620+
response,
1621+
)
1622+
end
1623+
15431624
test "tools/call with no args" do
15441625
server = Server.new(tools: [@tool_with_no_args])
15451626

0 commit comments

Comments
 (0)