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

@ -727,6 +727,22 @@ type Params interface {
isNil() bool
}
// ParamsBase can be embedded in custom parameter structs to satisfy the
// [Params] interface. It provides the required [Meta] field and the unexported
// isParams marker method.
//
// type SearchParams struct {
// mcp.ParamsBase
// Query string `json:"query"`
// }
type ParamsBase struct {
Meta `json:"_meta,omitempty"`
}
func (*ParamsBase) isParams() {}
func (p *ParamsBase) isNil() bool { return p == nil }
// RequestParams is a parameter (input) type for an MCP request.
type RequestParams interface {
Params
@ -751,6 +767,20 @@ type Result interface {
SetMeta(map[string]any)
}
// ResultBase can be embedded in custom result structs to satisfy the
// [Result] interface. It provides the required [Meta] field and the unexported
// isResult marker method.
//
// type SearchResult struct {
// mcp.ResultBase
// Hits []string `json:"hits"`
// }
type ResultBase struct {
Meta `json:"_meta,omitempty"`
}
func (*ResultBase) isResult() {}
// emptyResult is returned by methods that have no result, like ping.
// Those methods cannot return nil, because jsonrpc2 cannot handle nils.
type emptyResult struct{}