mcp: Allow registration of custom JSON-RPC methods (#956)

## Description

This PR introduces support for custom (non-standard) JSON-RPC methods in
the MCP Go SDK.
This feature enables servers to handle arbitrary JSON-RPC methods and
clients to invoke them, all while maintaining full type safety and
integrating seamlessly with the SDK's existing middleware and session
management.

- Server-Side Registration: Added AddReceivingCustomMethod to allow
servers to register handlers for custom methods. Incoming requests are
automatically unmarshaled into user-defined parameter structs.
- Client-Side Calling: Added AddSendingCustomMethod which returns a
strongly-typed caller function that clients can use to invoke custom
methods and receive strongly-typed results.
- Helper Structs: Provided ParamsBase and ResultBase for users to embed
in their custom structs. This allows them to easily satisfy the SDK's
internal Params and Result interfaces.

Fixes #954
This commit is contained in:
Guglielmo Colombo 2026-06-25 23:13:17 +02:00 • committed by GitHub
commit 65ece59643
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -486,6 +486,7 @@ func connectStreamable(ctx context.Context, server *Server, transport *Streamabl
if err != nil {
return nil, err
}
transport.connection.server = server
transport.connection.toolLookup = server.getServerTool
return s, nil
}
@ -846,6 +847,7 @@ type streamableServerConn struct {
logger *slog.Logger
server *Server
toolLookup func(name string) (*serverTool, bool)
incoming chan jsonrpc.Message // messages from the client to the server
@ -1415,7 +1417,15 @@ func (c *streamableServerConn) servePOST(w http.ResponseWriter, req *http.Reques
// Preemptively check that this is a valid request, so that we can fail
// the HTTP request. If we didn't do this, a request with a bad method or
// missing ID could be silently swallowed.
if _, err := checkRequest(jreq, serverMethodInfos); err != nil {
// Use the server's receiving method infos (which include any custom
// methods registered via AddReceivingCustomMethod) when available;
// fall back to the standard methods otherwise, e.g. in tests that
// exercise streamableServerConn directly without a server.
methodInfos := serverMethodInfos
if c.server != nil {
methodInfos = c.server.receivingMethodInfos()
}
if _, err := checkRequest(jreq, methodInfos); err != nil {
if protocolVersion >= protocolVersion20260728 && errors.Is(err, jsonrpc2.ErrNotHandled) && jreq.IsCall() {
writeJSONRPCError(w, http.StatusNotFound, jreq.ID, &jsonrpc.Error{
Code: jsonrpc.CodeMethodNotFound,