mcp: remove references to ClientRequest[T] for concrete T (#343)

See related PR about ServerRequest[T].
This commit is contained in:
Jonathan Amsterdam 2025-08-21 15:24:58 -04:00 • committed by GitHub
commit bf79d784b9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 60 additions and 47 deletions

View file

@ -55,14 +55,14 @@ func NewClient(impl *Implementation, opts *ClientOptions) *Client {
type ClientOptions struct { type ClientOptions struct {
// Handler for sampling. // Handler for sampling.
// Called when a server calls CreateMessage. // Called when a server calls CreateMessage.
CreateMessageHandler func(context.Context, *ClientRequest[*CreateMessageParams]) (*CreateMessageResult, error) CreateMessageHandler func(context.Context, *CreateMessageRequest) (*CreateMessageResult, error)
// Handlers for notifications from the server. // Handlers for notifications from the server.
ToolListChangedHandler func(context.Context, *ClientRequest[*ToolListChangedParams]) ToolListChangedHandler func(context.Context, *ToolListChangedRequest)
PromptListChangedHandler func(context.Context, *ClientRequest[*PromptListChangedParams]) PromptListChangedHandler func(context.Context, *PromptListChangedRequest)
ResourceListChangedHandler func(context.Context, *ClientRequest[*ResourceListChangedParams]) ResourceListChangedHandler func(context.Context, *ResourceListChangedRequest)
ResourceUpdatedHandler func(context.Context, *ClientRequest[*ResourceUpdatedNotificationParams]) ResourceUpdatedHandler func(context.Context, *ResourceUpdatedNotificationRequest)
LoggingMessageHandler func(context.Context, *ClientRequest[*LoggingMessageParams]) LoggingMessageHandler func(context.Context, *LoggingMessageRequest)
ProgressNotificationHandler func(context.Context, *ClientRequest[*ProgressNotificationParams]) ProgressNotificationHandler func(context.Context, *ProgressNotificationClientRequest)
// If non-zero, defines an interval for regular "ping" requests. // If non-zero, defines an interval for regular "ping" requests.
// If the peer fails to respond to pings originating from the keepalive check, // If the peer fails to respond to pings originating from the keepalive check,
// the session is automatically closed. // the session is automatically closed.
@ -132,7 +132,7 @@ func (c *Client) Connect(ctx context.Context, t Transport, _ *ClientSessionOptio
ClientInfo: c.impl, ClientInfo: c.impl,
Capabilities: c.capabilities(), Capabilities: c.capabilities(),
} }
req := &ClientRequest[*InitializeParams]{Session: cs, Params: params} req := &InitializeRequest{Session: cs, Params: params}
res, err := handleSend[*InitializeResult](ctx, methodInitialize, req) res, err := handleSend[*InitializeResult](ctx, methodInitialize, req)
if err != nil { if err != nil {
_ = cs.Close() _ = cs.Close()
@ -145,7 +145,7 @@ func (c *Client) Connect(ctx context.Context, t Transport, _ *ClientSessionOptio
if hc, ok := cs.mcpConn.(clientConnection); ok { if hc, ok := cs.mcpConn.(clientConnection); ok {
hc.sessionUpdated(cs.state) hc.sessionUpdated(cs.state)
} }
req2 := &ClientRequest[*InitializedParams]{Session: cs, Params: &InitializedParams{}} req2 := &InitializedClientRequest{Session: cs, Params: &InitializedParams{}}
if err := handleNotify(ctx, notificationInitialized, req2); err != nil { if err := handleNotify(ctx, notificationInitialized, req2); err != nil {
_ = cs.Close() _ = cs.Close()
return nil, err return nil, err
@ -248,7 +248,7 @@ func changeAndNotify[P Params](c *Client, notification string, params P, change
notifySessions(sessions, notification, params) notifySessions(sessions, notification, params)
} }
func (c *Client) listRoots(_ context.Context, req *ClientRequest[*ListRootsParams]) (*ListRootsResult, error) { func (c *Client) listRoots(_ context.Context, req *ListRootsRequest) (*ListRootsResult, error) {
c.mu.Lock() c.mu.Lock()
defer c.mu.Unlock() defer c.mu.Unlock()
roots := slices.Collect(c.roots.all()) roots := slices.Collect(c.roots.all())
@ -260,7 +260,7 @@ func (c *Client) listRoots(_ context.Context, req *ClientRequest[*ListRootsParam
}, nil }, nil
} }
func (c *Client) createMessage(ctx context.Context, req *ClientRequest[*CreateMessageParams]) (*CreateMessageResult, error) { func (c *Client) createMessage(ctx context.Context, req *CreateMessageRequest) (*CreateMessageResult, error) {
if c.opts.CreateMessageHandler == nil { if c.opts.CreateMessageHandler == nil {
// TODO: wrap or annotate this error? Pick a standard code? // TODO: wrap or annotate this error? Pick a standard code?
return nil, jsonrpc2.NewError(CodeUnsupportedMethod, "client does not support CreateMessage") return nil, jsonrpc2.NewError(CodeUnsupportedMethod, "client does not support CreateMessage")
@ -436,35 +436,35 @@ func (cs *ClientSession) Unsubscribe(ctx context.Context, params *UnsubscribePar
return err return err
} }
func (c *Client) callToolChangedHandler(ctx context.Context, req *ClientRequest[*ToolListChangedParams]) (Result, error) { func (c *Client) callToolChangedHandler(ctx context.Context, req *ToolListChangedRequest) (Result, error) {
if h := c.opts.ToolListChangedHandler; h != nil { if h := c.opts.ToolListChangedHandler; h != nil {
h(ctx, req) h(ctx, req)
} }
return nil, nil return nil, nil
} }
func (c *Client) callPromptChangedHandler(ctx context.Context, req *ClientRequest[*PromptListChangedParams]) (Result, error) { func (c *Client) callPromptChangedHandler(ctx context.Context, req *PromptListChangedRequest) (Result, error) {
if h := c.opts.PromptListChangedHandler; h != nil { if h := c.opts.PromptListChangedHandler; h != nil {
h(ctx, req) h(ctx, req)
} }
return nil, nil return nil, nil
} }
func (c *Client) callResourceChangedHandler(ctx context.Context, req *ClientRequest[*ResourceListChangedParams]) (Result, error) { func (c *Client) callResourceChangedHandler(ctx context.Context, req *ResourceListChangedRequest) (Result, error) {
if h := c.opts.ResourceListChangedHandler; h != nil { if h := c.opts.ResourceListChangedHandler; h != nil {
h(ctx, req) h(ctx, req)
} }
return nil, nil return nil, nil
} }
func (c *Client) callResourceUpdatedHandler(ctx context.Context, req *ClientRequest[*ResourceUpdatedNotificationParams]) (Result, error) { func (c *Client) callResourceUpdatedHandler(ctx context.Context, req *ResourceUpdatedNotificationRequest) (Result, error) {
if h := c.opts.ResourceUpdatedHandler; h != nil { if h := c.opts.ResourceUpdatedHandler; h != nil {
h(ctx, req) h(ctx, req)
} }
return nil, nil return nil, nil
} }
func (c *Client) callLoggingHandler(ctx context.Context, req *ClientRequest[*LoggingMessageParams]) (Result, error) { func (c *Client) callLoggingHandler(ctx context.Context, req *LoggingMessageRequest) (Result, error) {
if h := c.opts.LoggingMessageHandler; h != nil { if h := c.opts.LoggingMessageHandler; h != nil {
h(ctx, req) h(ctx, req)
} }

View file

@ -211,7 +211,7 @@ func TestClientCapabilities(t *testing.T) {
name: "With sampling", name: "With sampling",
configureClient: func(s *Client) {}, configureClient: func(s *Client) {},
clientOpts: ClientOptions{ clientOpts: ClientOptions{
CreateMessageHandler: func(context.Context, *ClientRequest[*CreateMessageParams]) (*CreateMessageResult, error) { CreateMessageHandler: func(context.Context, *CreateMessageRequest) (*CreateMessageResult, error) {
return nil, nil return nil, nil
}, },
}, },

View file

@ -74,13 +74,13 @@ func TestEndToEnd(t *testing.T) {
} }
sopts := &ServerOptions{ sopts := &ServerOptions{
InitializedHandler: func(context.Context, *InitializedRequest) { InitializedHandler: func(context.Context, *InitializedServerRequest) {
notificationChans["initialized"] <- 0 notificationChans["initialized"] <- 0
}, },
RootsListChangedHandler: func(context.Context, *RootsListChangedRequest) { RootsListChangedHandler: func(context.Context, *RootsListChangedRequest) {
notificationChans["roots"] <- 0 notificationChans["roots"] <- 0
}, },
ProgressNotificationHandler: func(context.Context, *ProgressNotificationRequest) { ProgressNotificationHandler: func(context.Context, *ProgressNotificationServerRequest) {
notificationChans["progress_server"] <- 0 notificationChans["progress_server"] <- 0
}, },
SubscribeHandler: func(context.Context, *SubscribeRequest) error { SubscribeHandler: func(context.Context, *SubscribeRequest) error {
@ -129,25 +129,25 @@ func TestEndToEnd(t *testing.T) {
loggingMessages := make(chan *LoggingMessageParams, 100) // big enough for all logging loggingMessages := make(chan *LoggingMessageParams, 100) // big enough for all logging
opts := &ClientOptions{ opts := &ClientOptions{
CreateMessageHandler: func(context.Context, *ClientRequest[*CreateMessageParams]) (*CreateMessageResult, error) { CreateMessageHandler: func(context.Context, *CreateMessageRequest) (*CreateMessageResult, error) {
return &CreateMessageResult{Model: "aModel", Content: &TextContent{}}, nil return &CreateMessageResult{Model: "aModel", Content: &TextContent{}}, nil
}, },
ToolListChangedHandler: func(context.Context, *ClientRequest[*ToolListChangedParams]) { ToolListChangedHandler: func(context.Context, *ToolListChangedRequest) {
notificationChans["tools"] <- 0 notificationChans["tools"] <- 0
}, },
PromptListChangedHandler: func(context.Context, *ClientRequest[*PromptListChangedParams]) { PromptListChangedHandler: func(context.Context, *PromptListChangedRequest) {
notificationChans["prompts"] <- 0 notificationChans["prompts"] <- 0
}, },
ResourceListChangedHandler: func(context.Context, *ClientRequest[*ResourceListChangedParams]) { ResourceListChangedHandler: func(context.Context, *ResourceListChangedRequest) {
notificationChans["resources"] <- 0 notificationChans["resources"] <- 0
}, },
LoggingMessageHandler: func(_ context.Context, req *ClientRequest[*LoggingMessageParams]) { LoggingMessageHandler: func(_ context.Context, req *LoggingMessageRequest) {
loggingMessages <- req.Params loggingMessages <- req.Params
}, },
ProgressNotificationHandler: func(context.Context, *ClientRequest[*ProgressNotificationParams]) { ProgressNotificationHandler: func(context.Context, *ProgressNotificationClientRequest) {
notificationChans["progress_client"] <- 0 notificationChans["progress_client"] <- 0
}, },
ResourceUpdatedHandler: func(context.Context, *ClientRequest[*ResourceUpdatedNotificationParams]) { ResourceUpdatedHandler: func(context.Context, *ResourceUpdatedNotificationRequest) {
notificationChans["resource_updated"] <- 0 notificationChans["resource_updated"] <- 0
}, },
} }
@ -992,10 +992,10 @@ func TestAddTool_DuplicateNoPanicAndNoDuplicate(t *testing.T) {
func TestSynchronousNotifications(t *testing.T) { func TestSynchronousNotifications(t *testing.T) {
var toolsChanged atomic.Bool var toolsChanged atomic.Bool
clientOpts := &ClientOptions{ clientOpts := &ClientOptions{
ToolListChangedHandler: func(ctx context.Context, req *ClientRequest[*ToolListChangedParams]) { ToolListChangedHandler: func(ctx context.Context, req *ToolListChangedRequest) {
toolsChanged.Store(true) toolsChanged.Store(true)
}, },
CreateMessageHandler: func(ctx context.Context, req *ClientRequest[*CreateMessageParams]) (*CreateMessageResult, error) { CreateMessageHandler: func(ctx context.Context, req *CreateMessageRequest) (*CreateMessageResult, error) {
if !toolsChanged.Load() { if !toolsChanged.Load() {
return nil, fmt.Errorf("didn't get a tools changed notification") return nil, fmt.Errorf("didn't get a tools changed notification")
} }
@ -1057,7 +1057,7 @@ func TestNoDistributedDeadlock(t *testing.T) {
// possible, and in any case making tool calls asynchronous by default // possible, and in any case making tool calls asynchronous by default
// delegates synchronization to the user. // delegates synchronization to the user.
clientOpts := &ClientOptions{ clientOpts := &ClientOptions{
CreateMessageHandler: func(ctx context.Context, req *ClientRequest[*CreateMessageParams]) (*CreateMessageResult, error) { CreateMessageHandler: func(ctx context.Context, req *CreateMessageRequest) (*CreateMessageResult, error) {
req.Session.CallTool(ctx, &CallToolParams{Name: "tool2"}) req.Session.CallTool(ctx, &CallToolParams{Name: "tool2"})
return &CreateMessageResult{Content: &TextContent{}}, nil return &CreateMessageResult{Content: &TextContent{}}, nil
}, },

View file

@ -8,17 +8,30 @@ package mcp
// TODO: expand the aliases // TODO: expand the aliases
type ( type (
CallToolRequest = ServerRequest[*CallToolParams] CallToolRequest = ServerRequest[*CallToolParams]
CompleteRequest = ServerRequest[*CompleteParams] CompleteRequest = ServerRequest[*CompleteParams]
GetPromptRequest = ServerRequest[*GetPromptParams] GetPromptRequest = ServerRequest[*GetPromptParams]
InitializedRequest = ServerRequest[*InitializedParams] InitializedServerRequest = ServerRequest[*InitializedParams]
ListPromptsRequest = ServerRequest[*ListPromptsParams] ListPromptsRequest = ServerRequest[*ListPromptsParams]
ListResourcesRequest = ServerRequest[*ListResourcesParams] ListResourcesRequest = ServerRequest[*ListResourcesParams]
ListResourceTemplatesRequest = ServerRequest[*ListResourceTemplatesParams] ListResourceTemplatesRequest = ServerRequest[*ListResourceTemplatesParams]
ListToolsRequest = ServerRequest[*ListToolsParams] ListToolsRequest = ServerRequest[*ListToolsParams]
ProgressNotificationRequest = ServerRequest[*ProgressNotificationParams] ProgressNotificationServerRequest = ServerRequest[*ProgressNotificationParams]
ReadResourceRequest = ServerRequest[*ReadResourceParams] ReadResourceRequest = ServerRequest[*ReadResourceParams]
RootsListChangedRequest = ServerRequest[*RootsListChangedParams] RootsListChangedRequest = ServerRequest[*RootsListChangedParams]
SubscribeRequest = ServerRequest[*SubscribeParams] SubscribeRequest = ServerRequest[*SubscribeParams]
UnsubscribeRequest = ServerRequest[*UnsubscribeParams] UnsubscribeRequest = ServerRequest[*UnsubscribeParams]
)
type (
CreateMessageRequest = ClientRequest[*CreateMessageParams]
InitializedClientRequest = ClientRequest[*InitializedParams]
InitializeRequest = ClientRequest[*InitializeParams]
ListRootsRequest = ClientRequest[*ListRootsParams]
LoggingMessageRequest = ClientRequest[*LoggingMessageParams]
ProgressNotificationClientRequest = ClientRequest[*ProgressNotificationParams]
PromptListChangedRequest = ClientRequest[*PromptListChangedParams]
ResourceListChangedRequest = ClientRequest[*ResourceListChangedParams]
ResourceUpdatedNotificationRequest = ClientRequest[*ResourceUpdatedNotificationParams]
ToolListChangedRequest = ClientRequest[*ToolListChangedParams]
) )

View file

@ -54,14 +54,14 @@ type ServerOptions struct {
// Optional instructions for connected clients. // Optional instructions for connected clients.
Instructions string Instructions string
// If non-nil, called when "notifications/initialized" is received. // If non-nil, called when "notifications/initialized" is received.
InitializedHandler func(context.Context, *InitializedRequest) InitializedHandler func(context.Context, *InitializedServerRequest)
// PageSize is the maximum number of items to return in a single page for // PageSize is the maximum number of items to return in a single page for
// list methods (e.g. ListTools). // list methods (e.g. ListTools).
PageSize int PageSize int
// If non-nil, called when "notifications/roots/list_changed" is received. // If non-nil, called when "notifications/roots/list_changed" is received.
RootsListChangedHandler func(context.Context, *RootsListChangedRequest) RootsListChangedHandler func(context.Context, *RootsListChangedRequest)
// If non-nil, called when "notifications/progress" is received. // If non-nil, called when "notifications/progress" is received.
ProgressNotificationHandler func(context.Context, *ProgressNotificationRequest) ProgressNotificationHandler func(context.Context, *ProgressNotificationServerRequest)
// If non-nil, called when "completion/complete" is received. // If non-nil, called when "completion/complete" is received.
CompletionHandler func(context.Context, *CompleteRequest) (*CompleteResult, error) CompletionHandler func(context.Context, *CompleteRequest) (*CompleteResult, error)
// If non-zero, defines an interval for regular "ping" requests. // If non-zero, defines an interval for regular "ping" requests.

View file

@ -121,7 +121,7 @@ func TestStreamableTransports(t *testing.T) {
HTTPClient: httpClient, HTTPClient: httpClient,
} }
client := NewClient(testImpl, &ClientOptions{ client := NewClient(testImpl, &ClientOptions{
CreateMessageHandler: func(context.Context, *ClientRequest[*CreateMessageParams]) (*CreateMessageResult, error) { CreateMessageHandler: func(context.Context, *CreateMessageRequest) (*CreateMessageResult, error) {
return &CreateMessageResult{Model: "aModel", Content: &TextContent{}}, nil return &CreateMessageResult{Model: "aModel", Content: &TextContent{}}, nil
}, },
}) })
@ -255,7 +255,7 @@ func testClientReplay(t *testing.T, test clientReplayTest) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel() defer cancel()
client := NewClient(testImpl, &ClientOptions{ client := NewClient(testImpl, &ClientOptions{
ProgressNotificationHandler: func(ctx context.Context, req *ClientRequest[*ProgressNotificationParams]) { ProgressNotificationHandler: func(ctx context.Context, req *ProgressNotificationClientRequest) {
notifications <- req.Params.Message notifications <- req.Params.Message
}, },
}) })
@ -344,7 +344,7 @@ func TestServerInitiatedSSE(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel() defer cancel()
client := NewClient(testImpl, &ClientOptions{ client := NewClient(testImpl, &ClientOptions{
ToolListChangedHandler: func(context.Context, *ClientRequest[*ToolListChangedParams]) { ToolListChangedHandler: func(context.Context, *ToolListChangedRequest) {
notifications <- "toolListChanged" notifications <- "toolListChanged"
}, },
}) })