mco: update JSON-RPC error codes to align with updated MCP specification (#1016)

This PR updates the error codes to align with the updated specifications
in
https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2907

ErrServerClosing and ErrClientClosing are reverted to their 1.6.0
version codes, as they do not overlap anymore with the newly introduced
error codes.
This commit is contained in:
Guglielmo Colombo 2026-06-22 10:27:31 +02:00 • committed by GitHub
commit 3486f6bcaf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 18 additions and 16 deletions

View file

@ -31,9 +31,9 @@ var (
// ErrUnknown should be used for all non coded errors.
ErrUnknown = NewError(-32001, "unknown error")
// ErrServerClosing is returned for calls that arrive while the server is closing.
ErrServerClosing = NewError(-32006, "server is closing")
ErrServerClosing = NewError(-32004, "server is closing")
// ErrClientClosing is a dummy error returned for calls initiated while the client is closing.
ErrClientClosing = NewError(-32007, "client is closing")
ErrClientClosing = NewError(-32003, "client is closing")
// The following errors have special semantics for MCP transports
@ -45,8 +45,6 @@ var (
// should be returned to the caller to indicate that the specific request is
// invalid in the current context.
ErrRejected = NewError(-32005, "rejected by transport")
// ErrUnsupportedProtocolVersion is returned when a server does not support the protocol version.
ErrUnsupportedProtocolVersion = NewError(-32004, "unsupported protocol version")
)
const wireVersion = "2.0"

View file

@ -306,7 +306,7 @@ func (c *Client) Connect(ctx context.Context, t Transport, opts *ClientSessionOp
// Try to negotiate a mutually supported version if the server
// reports an UnsupportedProtocolVersionError with a supported version.
var werr *jsonrpc.Error
if errors.As(err, &werr) && werr.Code == CodeUnsupportedProtocolVersion && werr.Data != nil {
if errors.As(err, &werr) && werr.Code == CodeUnsupportedProtocolVersion && len(werr.Data) > 0 {
var data UnsupportedProtocolVersionData
if err := json.Unmarshal(werr.Data, &data); err == nil {
if negotiatedVersion := negotiateMutuallySupportedVersion(data.Supported); negotiatedVersion != "" && negotiatedVersion >= protocolVersion20260728 {
@ -384,7 +384,10 @@ func (c *Client) discover(ctx context.Context, cs *ClientSession) (*InitializeRe
if negotiated == "" || negotiated < protocolVersion20260728 {
// If there is no overlap, fall back to initialize so version
// negotiation can happen via the legacy path.
return nil, jsonrpc2.ErrUnsupportedProtocolVersion
return nil, &jsonrpc2.WireError{
Code: CodeUnsupportedProtocolVersion,
Message: "unsupported protocol version",
}
}
return &InitializeResult{

View file

@ -355,15 +355,15 @@ func clientSessionMethod[P Params, R Result](f func(*ClientSession, context.Cont
// MCP-specific error codes.
const (
// CodeMissingRequiredClientCapabilities is the JSON-RPC error code defined by
// SEP-2575 for MissingRequiredClientCapabilitiesError.
CodeMissingRequiredClientCapabilities = -32003
// CodeUnsupportedProtocolVersion is the JSON-RPC error code defined by
// SEP-2575 for UnsupportedProtocolVersionError.
CodeUnsupportedProtocolVersion = -32004
// CodeHeaderMismatch indicates that HTTP headers do not match the corresponding values
// in the request body, or that required headers are missing or malformed.
CodeHeaderMismatch = -32001
CodeHeaderMismatch = -32020
// CodeMissingRequiredClientCapabilities is the JSON-RPC error code defined by
// SEP-2575 for MissingRequiredClientCapabilitiesError.
CodeMissingRequiredClientCapabilities = -32021
// CodeUnsupportedProtocolVersion is the JSON-RPC error code defined by
// SEP-2575 for UnsupportedProtocolVersionError.
CodeUnsupportedProtocolVersion = -32022
// CodeURLElicitationRequired indicates that the server requires URL elicitation
// before processing the request. The client should execute the elicitation handler
// with the elicitations provided in the error data.

View file

@ -955,7 +955,8 @@ func (s *stream) release() {
//
// Per SEP-2575:
// - MethodNotFound (-32601) MUST return HTTP 404.
// - InvalidParams (-32602) and UnsupportedProtocolVersion (-32004) MUST
// - InvalidParams (-32602), UnsupportedProtocolVersion (-32022) and
// CodeMissingRequiredClientCapabilities (-32021) MUST
// return HTTP 400.
func extractErrorStatus(ctx context.Context, msg jsonrpc.Message) int {
if protocolVersionFromContext(ctx) < protocolVersion20260728 {

View file

@ -2050,7 +2050,7 @@ func TestStreamableMcpHeaderValidation(t *testing.T) {
}
// TestStreamableMcpHeaderValidationErrorFormat verifies that header
// validation errors return a JSON-RPC error with code -32001 and
// validation errors return a JSON-RPC error with code -32020 and
// Content-Type application/json, per SEP-2243.
func TestStreamableMcpHeaderValidationErrorFormat(t *testing.T) {
orig := supportedProtocolVersions
@ -2125,7 +2125,7 @@ func TestStreamableMcpHeaderValidationErrorFormat(t *testing.T) {
t.Errorf("Content-Type = %q, want %q", baseMediaType(toolCallResp.Header.Get("Content-Type")), "application/json")
}
// Verify JSON-RPC error body contains error code -32001.
// Verify JSON-RPC error body contains error code -32020.
msg, err := jsonrpc2.DecodeMessage(toolCallRespBody)
if err != nil {
t.Fatalf("failed to decode message: %v", err)
@ -2138,8 +2138,8 @@ func TestStreamableMcpHeaderValidationErrorFormat(t *testing.T) {
if !errors.As(resp.Error, &wireErr) {
t.Fatalf("expected *jsonrpc2.WireError, got %T", resp.Error)
}
if wireErr.Code != -32001 {
t.Errorf("wireErr.Code = %d, want -32001", wireErr.Code)
if wireErr.Code != CodeHeaderMismatch {
t.Errorf("wireErr.Code = %d, want %d", wireErr.Code, CodeHeaderMismatch)
}
if !strings.Contains(wireErr.Message, "Mcp-Method header value") {
t.Errorf("wireErr.Message = %q, want it to contain %q", wireErr.Message, "Mcp-Method header value")