When POST requests in the streamableClientConn return a transient error, return this error to the caller rather than permanently breaking the connection. This is achieved by using the special sentinel ErrRejected error to the jsonrpc2 layer. In doing so, the change revealed a pre-existing bug: ErrRejected had the same code as ErrConnectionClosing, and jsonrpc2.WireError implements errors.Is, so the two sentinel values could be conflated. This is fixed by using a new internal code. There's more to do for #683: we should also retry transient errors in handleSSE. For #683
97 lines
3.6 KiB
Go
97 lines
3.6 KiB
Go
// Copyright 2018 The Go MCP SDK Authors. All rights reserved.
|
|
// Use of this source code is governed by an MIT-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package jsonrpc2
|
|
|
|
import (
|
|
"encoding/json"
|
|
)
|
|
|
|
// This file contains the go forms of the wire specification.
|
|
// see http://www.jsonrpc.org/specification for details
|
|
|
|
var (
|
|
// ErrParse is used when invalid JSON was received by the server.
|
|
ErrParse = NewError(-32700, "parse error")
|
|
// ErrInvalidRequest is used when the JSON sent is not a valid Request object.
|
|
ErrInvalidRequest = NewError(-32600, "invalid request")
|
|
// ErrMethodNotFound should be returned by the handler when the method does
|
|
// not exist / is not available.
|
|
ErrMethodNotFound = NewError(-32601, "method not found")
|
|
// ErrInvalidParams should be returned by the handler when method
|
|
// parameter(s) were invalid.
|
|
ErrInvalidParams = NewError(-32602, "invalid params")
|
|
// ErrInternal indicates a failure to process a call correctly
|
|
ErrInternal = NewError(-32603, "internal error")
|
|
|
|
// The following errors are not part of the json specification, but
|
|
// compliant extensions specific to this implementation.
|
|
|
|
// ErrServerOverloaded is returned when a message was refused due to a
|
|
// server being temporarily unable to accept any new messages.
|
|
ErrServerOverloaded = NewError(-32000, "overloaded")
|
|
// 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(-32004, "server is closing")
|
|
// ErrClientClosing is a dummy error returned for calls initiated while the client is closing.
|
|
ErrClientClosing = NewError(-32003, "client is closing")
|
|
|
|
// The following errors have special semantics for MCP transports
|
|
|
|
// ErrRejected may be wrapped to return errors from calls to Writer.Write
|
|
// that signal that the request was rejected by the transport layer as
|
|
// invalid.
|
|
//
|
|
// Such failures do not indicate that the connection is broken, but rather
|
|
// should be returned to the caller to indicate that the specific request is
|
|
// invalid in the current context.
|
|
ErrRejected = NewError(-32005, "rejected by transport")
|
|
)
|
|
|
|
const wireVersion = "2.0"
|
|
|
|
// wireCombined has all the fields of both Request and Response.
|
|
// We can decode this and then work out which it is.
|
|
type wireCombined struct {
|
|
VersionTag string `json:"jsonrpc"`
|
|
ID any `json:"id,omitempty"`
|
|
Method string `json:"method,omitempty"`
|
|
Params json.RawMessage `json:"params,omitempty"`
|
|
Result json.RawMessage `json:"result,omitempty"`
|
|
Error *WireError `json:"error,omitempty"`
|
|
}
|
|
|
|
// WireError represents a structured error in a Response.
|
|
type WireError struct {
|
|
// Code is an error code indicating the type of failure.
|
|
Code int64 `json:"code"`
|
|
// Message is a short description of the error.
|
|
Message string `json:"message"`
|
|
// Data is optional structured data containing additional information about the error.
|
|
Data json.RawMessage `json:"data,omitempty"`
|
|
}
|
|
|
|
// NewError returns an error that will encode on the wire correctly.
|
|
// The standard codes are made available from this package, this function should
|
|
// only be used to build errors for application specific codes as allowed by the
|
|
// specification.
|
|
func NewError(code int64, message string) error {
|
|
return &WireError{
|
|
Code: code,
|
|
Message: message,
|
|
}
|
|
}
|
|
|
|
func (err *WireError) Error() string {
|
|
return err.Message
|
|
}
|
|
|
|
func (err *WireError) Is(other error) bool {
|
|
w, ok := other.(*WireError)
|
|
if !ok {
|
|
return false
|
|
}
|
|
return err.Code == w.Code
|
|
}
|