MCP: server advertising `resources` capability is treated as having none

Status Open
Maintainer reply None cached
Activity 0 comments · opened Sep 7, 2026

What happens

An MCP server that advertises the resources capability in its initialize response is treated by Claude Code as having no resource support:

  • ListMcpResourcesTool with that server name returns No resources found. MCP servers may still provide tools even if they have no resources.
  • ReadMcpResourceTool against a valid URI returns Server "<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, rmcp 3.1.4, Streamable HTTP at http://localhost:<port>/core/mcp
  • Also reproduced through mcp-remote 0.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.

View original on GitHub ↗