MCP: server advertising `resources` capability is treated as having none
What happens
An MCP server that advertises the resources capability in its initialize response is treated by Claude Code as having no resource support:
ListMcpResourcesToolwith that server name returnsNo resources found. MCP servers may still provide tools even if they have no resources.ReadMcpResourceToolagainst a valid URI returnsServer "<name>" does not support resources
tools/* from the same server works fine. Another MCP server configured in the same session (a stdio one) does have its resources listed correctly, so resource support is working in general — just not for this server.
The server is advertising it
Server is Rust + rmcp 3.1.4, Streamable HTTP transport, stateless (legacy_session_mode: false, json_response: true). Verified directly on the wire with curl:
initialize:
{"jsonrpc":"2.0","id":1,"result":{
"protocolVersion":"2025-11-25",
"capabilities":{"resources":{},"tools":{}},
"serverInfo":{"name":"...","version":"..."}
}}
resources/list:
{"jsonrpc":"2.0","id":2,"result":{"resources":[
{"uri":"schema://.../relationships.md","name":"...","mimeType":"text/markdown","size":13995}
]}}
resources/read returns the document, and resources/templates/list returns {"resourceTemplates":[]}. All HTTP 200.
Identical capabilities are returned when the client negotiates 2024-11-05, 2025-06-18, 2025-11-25 or 2026-07-28, and the same results come through when the server is reached via the mcp-remote stdio bridge rather than directly.
The client received it
Claude Code's own MCP log for the session records a line from that same handshake:
{"debug":"Server instructions truncated from 2221 to 2048 chars", ...}
The server's instructions string is exactly 2221 characters, so the initialize response that the client parsed is the one shown above — the one carrying "resources":{}. No connection error is logged.
Possibly relevant
The one observable difference from the stdio server whose resources do get listed is the shape of the capability object:
| server | capabilities |
|---|---|
| works | {"resources":{"listChanged":false},"tools":{"listChanged":false}} |
| fails | {"resources":{},"tools":{}} |
Both are spec-legal — resources: {} means "supported, no optional sub-capabilities". The bundled MCP SDK's own assertCapability check (if (!this._capabilities.resources) throw ...) treats {} as present, since {} is truthy, so that check is not the one rejecting it. Something upstream of it appears to decide the server has no resources.
Environment
- Claude Code in the desktop app (Code tab), macOS 15 (Darwin 25.4.0)
- Server: self-hosted,
rmcp3.1.4, Streamable HTTP athttp://localhost:<port>/core/mcp - Also reproduced through
mcp-remote0.1.38 as a stdio bridge to the same server
Expected
A server advertising capabilities.resources (including as an empty object) has its resources listed by ListMcpResourcesTool and readable by ReadMcpResourceTool.