How to check client capabilities and handle unsupported capability errors?
Is your feature request related to a problem? Please describe. I have two semi-related questions, caused by uncertainty of how to check client capabilities from an MCP server.
- How can I checking the client capabilities before using them?
- Can you expos the errors from internal/jsonrpc so I can check for them? (is this a possible solution?)
re 1: How to check Capabilities
I'd like to figure out if a MCP client supports a specific MCP server capability (e.g., ListRoots). I'm assuming client capabilities by reading the fields in the mcp.ClientCapabilities struct- Is this advisable?
Also, the Roots field is a value struct, so I can't check for nil on that like I can with the other capabilities fields Sampling or Elicitation: https://github.com/modelcontextprotocol/go-sdk/blob/d256a9c1094ee4044dc3fa6e55d3559df0047107/mcp/protocol.go#L183-L195
re 2: Error types from internal/jsonrpc
When using the elicitation/sampleing/logging capabilities, the examples just return an error to the client. The don't differentiate between the different types, or use any errors.Is(). So when a client doesn't support a capability (e.g., roots), the SDK returns a JSON-RPC error code -32601 (Method Not Found). However, ErrMethodNotFound is in the internal jsonrpc2 package and cannot be imported by my project, so I can't use errors.Is() to check if an error from ListRoots(), CreateMessage(), or Elicit() is due to an unsupported client capability.
Describe the solution you'd like
- Consistent capability structure: Make Roots a pointer type like the other capabilities:
type ClientCapabilities struct {
Roots *RootsCapabilities `json:"roots,omitempty"` // Changed from inline struct
Sampling *SamplingCapabilities `json:"sampling,omitempty"`
Elicitation *ElicitationCapabilities `json:"elicitation,omitempty"`
}
type RootsCapabilities struct {
ListChanged bool `json:"listChanged,omitempty"`
}
This would allow checking Capabilities.Roots != nil to determine if roots are supported at all.
- Export JSON-RPC errors: Export common JSON-RPC errors from the public jsonrpc package:
// jsonrpc/jsonrpc.go
var (
ErrMethodNotFound = internal.ErrMethodNotFound
ErrInvalidParams = internal.ErrInvalidParams
// etc.
)
This would enable library authors to use errors.Is(err, jsonrpc.ErrMethodNotFound) to detect specific error conditions.
Describe alternatives you've considered
Right now I need to do string matching on the error, or infer client capabilities from reading the ClientCapabilities.
Additional context Possibly related to #166 Thank you for reading, and designing such a useful library!
CC @jba
The way this is supposed to work is that you'd check for the presence of the Roots capability. The fact that the Roots client capability is not a distinguished type is almost certainly an oversight. It looks like it dates back to an earlier version of the SDK, and was somehow un-pointerized in https://go-review.git.corp.google.com/c/tools/+/672575.
Given that we have a backward compatibility promise at this point, it may be too late to fix this :(. I'm not sure if we can make an exception for what appears to clearly be a bug.
Well, this is unfortunate. I've drafted a workaround in #608, for discussion.
Regarding errors: yes I agree we should expose distinguished errors. I think this is largely covered by #452.