Default capabilities advertise listChanged, prompts, resources and logging on a tools-only stateless server
Maintainer antworten meist innerhalb von 1 Tag
Bewertung
- Schwierigkeit
- 3/5
- Geschätzter Aufwand
- 1-2 Tage
- Anfängerfreundlichkeit
- 56/100
- Issue-Typ
- Bug
- Klarheit
- Klar beschrieben
- Aktivitätsstatus
- Aktiv
- Tech-Stack
- ruby
- Bereich
- backend-api-design
Rechercherichtung
Start by reading MCP::Server#default_capabilities and #discover_capabilities, then trace how the initialize response obtains its capabilities and how stateless transport handles notifications and logging. Compare the initialize and server/discover results for the supplied reproduction. Done means both lifecycles advertise capabilities the server and transport can provide, with tests covering the tools-only stateless case.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Beschreibung
Describe the bug
When capabilities: is not passed, MCP::Server advertises Server#default_capabilities regardless of what the server has or what its transport can deliver:
{ tools: { listChanged: true }, prompts: { listChanged: true }, resources: { listChanged: true }, logging: {} }
On a server with one tool, no prompts, no resources, behind StreamableHTTPTransport.new(server, stateless: true, serve_subscriptions_listen: false), the initialize result still promises:
listChangedon tools, prompts and resources, although a stateless transport cannot sendnotifications/*/list_changed(the transports page says notifications are not supported in stateless mode);promptsandresources, which the server does not have;logging, although request-scoped log messages are skipped in stateless mode.
server/discover already strips listChanged/subscribe when the transport does not serve subscriptions/listen (Server#discover_capabilities, from #533), but initialize does not, so the same server describes itself differently on the two lifecycles. prompts, resources and logging are advertised on both.
To Reproduce
require "bundler/inline"
gemfile do
source "https://rubygems.org"
gem "mcp", "1.8.0"
gem "rack"
end
require "json"
class EchoTool < MCP::Tool
description "Echoes a message"
input_schema(properties: { message: { type: "string" } }, required: ["message"])
def self.call(message:, server_context:)
MCP::Tool::Response.new([{ type: "text", text: message }])
end
end
def post(body, headers = {})
env = Rack::MockRequest.env_for(
"http://localhost/mcp",
method: "POST",
input: JSON.generate(body),
"CONTENT_TYPE" => "application/json",
"HTTP_ACCEPT" => "application/json, text/event-stream",
)
headers.each { |k, v| env[k] = v }
Rack::Request.new(env)
end
server = MCP::Server.new(name: "echo", version: "1.0.0", tools: [EchoTool])
transport = MCP::Server::Transports::StreamableHTTPTransport.new(
server, stateless: true, serve_subscriptions_listen: false
)
_, _, body = transport.handle_request(post(
jsonrpc: "2.0", id: 1, method: "initialize",
params: { protocolVersion: "2025-11-25", capabilities: {}, clientInfo: { name: "c", version: "1" } },
))
puts "initialize: #{JSON.parse(body.first).dig("result", "capabilities").to_json}"
_, _, body = transport.handle_request(post(
{ jsonrpc: "2.0", id: 2, method: "server/discover",
params: { _meta: { "io.modelcontextprotocol/protocolVersion" => "2026-07-28",
"io.modelcontextprotocol/clientInfo" => { name: "c", version: "1" },
"io.modelcontextprotocol/clientCapabilities" => {} } } },
{ "HTTP_MCP_PROTOCOL_VERSION" => "2026-07-28", "HTTP_MCP_METHOD" => "server/discover" },
))
puts "server/discover: #{JSON.parse(body.first).dig("result", "capabilities").to_json}"
Output, the same on 1.8.0 and on main at 56af0c7:
initialize: {"tools":{"listChanged":true},"prompts":{"listChanged":true},"resources":{"listChanged":true},"logging":{}}
server/discover: {"tools":{},"prompts":{},"resources":{},"logging":{}}
Expected behavior
Capabilities that describe what this server can do. The spec (lifecycle, Capability Negotiation) says capabilities "establish which optional protocol features will be available during the session", and tools defines listChanged as "whether the server will emit notifications when the list of available tools changes" (prompts and resources say the same). For the repro, that is {"tools":{}} on both lifecycles.
A client that takes the default at its word waits for a list_changed that cannot arrive and asks for prompts and resources that do not exist. Passing capabilities: { tools: {} } works around it, but the default is what most servers ship with.
Two possible shapes, either would fix it:
- Derive the default from the server:
tools/prompts/resourcesonly when some are registered (or a list handler is set),loggingonly when it can be delivered. - At minimum, apply the same stripping
discover_capabilitiesdoes to theinitializeresult, and droplistChangedinstateless: true.
I'm happy to send a PR for whichever shape you prefer.
Additional context
mcp1.8.0 (latest release) andmain56af0c7- Ruby 3.4.10, rack 3.2.7, macOS
- Related: #531 / #533 (the
serve_subscriptions_listen: falseflag and the discover-side stripping), #602 (methods of undeclared capabilities).
- Vorherrschende Sprache
- Ruby
- Sterne
- 924
- Forks
- 136
- Ø Merge
- 1 T. 6 Std.
- Gemergte PRs (30 T.)
- 39
Entwicklungsumgebung
- Kein Dockerfile und keine Docker-Compose-Datei
- Keine Pull-Request-Vorlage
- Beitragsleitfaden lesen
Erste Schritte
- Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
- Forken Sie das Repository und arbeiten Sie in einem Branch.
- Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.
Mehr aus modelcontextprotocol/ruby-sdk
-
Empty members in the Accept header cause a 500Evtl. vergeben @koic hat das vor 3 Tagen übernommen. Offenbug
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 82/100
modelcontextprotocol/ruby-sdk#609 ·
Maintainer antworten meist innerhalb von 1 Tag
-
Error responses carry "id": null, which the MCP schema does not allowEvtl. vergeben @koic hat das vor 3 Tagen übernommen. Offenbug
Schwierigkeit 3/5 Ein halber Tag Anfängerfreundlichkeit 45/100
modelcontextprotocol/ruby-sdk#606 ·
Maintainer antworten meist innerhalb von 1 Tag
-
String request ids are limited to letters, digits, "_" and "-"Evtl. vergeben @koic hat das vor 3 Tagen übernommen. Offenbug
modelcontextprotocol/ruby-sdk#603 · 1 zugewiesene Person ·
Maintainer antworten meist innerhalb von 1 Tag
-
Methods of undeclared capabilities return -32603 instead of -32601Evtl. vergeben @koic hat das vor 3 Tagen übernommen. Offenbug
modelcontextprotocol/ruby-sdk#602 · 1 zugewiesene Person ·
Maintainer antworten meist innerhalb von 1 Tag
-
Requests with "id": null are run like notificationsEvtl. vergeben @koic hat das vor 3 Tagen übernommen. Offenbug
modelcontextprotocol/ruby-sdk#601 · 1 zugewiesene Person ·
Maintainer antworten meist innerhalb von 1 Tag
Alle Issues in modelcontextprotocol/ruby-sdk
Ähnliche Issues
-
Feature Feature Parity
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 82/100
valkey-io/valkey-glide-ruby#369 ·
Maintainer antworten meist innerhalb von 2 Tagen
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 85/100
Maintainer antworten meist innerhalb von 1 Tag
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 74/100
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 90/100
Maintainer antworten meist innerhalb von 3 Tagen
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 75/100
thewca/worldcubeassociation.org#16088 ·
Maintainer antworten meist innerhalb von 1 Tag