Skip to content

Commit 393b7af

Browse files
committed
mcp: introduce Requests
Handlers and client/server methods take a single request argument combining the session and params. This slightly simplifies the signature for handlers, since there is no longer an often-ignored session argument. But more importantly, it opens the door to adding more information in requests, such as auth info and HTTP request headers. For #243.
1 parent 8186bf3 commit 393b7af

File tree

25 files changed

+341
-289
lines changed

25 files changed

+341
-289
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,9 +115,9 @@ type HiParams struct {
115115
Name string `json:"name" jsonschema:"the name of the person to greet"`
116116
}
117117

118-
func SayHi(ctx context.Context, cc *mcp.ServerSession, params *mcp.CallToolParamsFor[HiParams]) (*mcp.CallToolResultFor[any], error) {
118+
func SayHi(ctx context.Context, req *mcp.RequestFor[*mcp.ServerSession, *mcp.CallToolParamsFor[HiParams]]) (*mcp.CallToolResultFor[any], error) {
119119
return &mcp.CallToolResultFor[any]{
120-
Content: []mcp.Content{&mcp.TextContent{Text: "Hi " + params.Arguments.Name}},
120+
Content: []mcp.Content{&mcp.TextContent{Text: "Hi " + req.Params.Arguments.Name}},
121121
}, nil
122122
}
123123

design/design.md

Lines changed: 16 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -431,12 +431,9 @@ We provide a mechanism to add MCP-level middleware on the both the client and se
431431
432432
```go
433433
// A MethodHandler handles MCP messages.
434-
// The params argument is an XXXParams struct pointer, such as *GetPromptParams.
435-
// For methods, a MethodHandler must return either an XXResult struct pointer and a nil error, or
436-
// nil with a non-nil error.
437-
// For notifications, a MethodHandler must return nil, nil.
438-
type MethodHandler[S Session] func(
439-
ctx context.Context, _ *S, method string, params Params) (result Result, err error)
434+
// For methods, exactly one of the return values must be nil.
435+
// For notifications, both must be nil.
436+
type MethodHandler[S Session] func(ctx context.Context, method string, req *Request[S]) (result Result, err error)
440437

441438
// Middleware is a function from MethodHandlers to MethodHandlers.
442439
type Middleware[S Session] func(MethodHandler[S]) MethodHandler[S]
@@ -620,8 +617,9 @@ type Tool struct {
620617
Name string `json:"name"`
621618
}
622619

623-
type ToolHandlerFor[In, Out any] func(context.Context, *ServerSession, *CallToolParamsFor[In]) (*CallToolResultFor[Out], error)
624-
type ToolHandler = ToolHandlerFor[map[string]any, any]
620+
// A ToolHandlerFor handles a call to tools/call with typed arguments and results.
621+
type ToolHandlerFor[In, Out any] func(context.Context, *RequestFor[*ServerSession, *CallToolParamsFor[In]]) (*CallToolResultFor[Out], error)
622+
625623
```
626624
627625
Add tools to a server with the `AddTool` method or function. The function is generic and infers schemas from the handler
@@ -671,8 +669,8 @@ type AddParams struct {
671669
Y int `json:"y"`
672670
}
673671

674-
func addHandler(ctx context.Context, ss *mcp.ServerSession, params *mcp.CallToolParamsFor[AddParams]) (*mcp.CallToolResultFor[int], error) {
675-
return &mcp.CallToolResultFor[int]{StructuredContent: params.Arguments.X + params.Arguments.Y}, nil
672+
func addHandler(ctx context.Context, req *mcp.RequestFor[*mcp.ServerSession, *mcp.CallToolParamsFor[AddParams]]) (*mcp.CallToolResultFor[int], error) {
673+
return &mcp.CallToolResultFor[int]{StructuredContent: req.Params.Arguments.X + req.Params.Arguments.Y}, nil
676674
}
677675
```
678676
@@ -688,8 +686,6 @@ Client sessions can call the spec method `ListTools` or an iterator method `Tool
688686
689687
```go
690688
func (cs *ClientSession) CallTool(context.Context, *CallToolParams[json.RawMessage]) (*CallToolResult, error)
691-
692-
func CallTool[TArgs any](context.Context, *ClientSession, *CallToolParams[TArgs]) (*CallToolResult, error)
693689
```
694690
695691
**Differences from mcp-go**: We provide a full JSON Schema implementation for validating tool input schemas against incoming arguments. The `jsonschema.Schema` type provides exported features for all keywords in the JSON Schema draft2020-12 spec. Tool definers can use it to construct any schema they want. The `jsonschema.For[T]` function can infer a schema from a Go struct. These combined features eliminate the need for variadic arguments to construct tool schemas.
@@ -775,10 +771,10 @@ If a server author wants to support resource subscriptions, they must provide ha
775771
```go
776772
type ServerOptions struct {
777773
...
778-
// Function called when a client session subscribes to a resource.
779-
SubscribeHandler func(context.Context, ss *ServerSession, *SubscribeParams) error
780-
// Function called when a client session unsubscribes from a resource.
781-
UnsubscribeHandler func(context.Context, ss *ServerSession, *UnsubscribeParams) error
774+
// Function called when a client session subscribes to a resource.
775+
SubscribeHandler func(context.Context, *RequestFor[*ServerSession, *SubscribeParams]) error
776+
// Function called when a client session unsubscribes from a resource.
777+
UnsubscribeHandler func(context.Context, *RequestFor[*ServerSession, *UnsubscribeParams]) error
782778
}
783779
```
784780
@@ -797,10 +793,10 @@ When a list of tools, prompts or resources changes as the result of an AddXXX or
797793
```go
798794
type ClientOptions struct {
799795
...
800-
ToolListChangedHandler func(context.Context, *ClientSession, *ToolListChangedParams)
801-
PromptListChangedHandler func(context.Context, *ClientSession, *PromptListChangedParams)
796+
ToolListChangedHandler func(context.Context, *RequestFor[*ClientSession, *ToolListChangedParams])
797+
PromptListChangedHandler func(context.Context, *RequestFor[*ClientSession, *PromptListChangedParams])
802798
// For both resources and resource templates.
803-
ResourceListChangedHandler func(context.Context, *ClientSession, *ResourceListChangedParams)
799+
ResourceListChangedHandler func(context.Context, *RequestFor[*ClientSession, *ResourceListChangedParams])
804800
}
805801
```
806802
@@ -811,13 +807,10 @@ type ClientOptions struct {
811807
Clients call the spec method `Complete` to request completions. If a server installs a `CompletionHandler`, it will be called when the client sends a completion request.
812808
813809
```go
814-
// A CompletionHandler handles a call to completion/complete.
815-
type CompletionHandler func(context.Context, *ServerSession, *CompleteParams) (*CompleteResult, error)
816-
817810
type ServerOptions struct {
818811
...
819812
// If non-nil, called when a client sends a completion request.
820-
CompletionHandler CompletionHandler
813+
CompletionHandler func(context.Context, *RequestFor[*ServerSession, *CompleteParams]) (*CompleteResult, error)
821814
}
822815
```
823816

examples/server/completion/main.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,17 @@ import (
1616
// a CompletionHandler to an MCP Server's options.
1717
func main() {
1818
// Define your custom CompletionHandler logic.
19-
myCompletionHandler := func(_ context.Context, _ *mcp.ServerSession, params *mcp.CompleteParams) (*mcp.CompleteResult, error) {
19+
myCompletionHandler := func(_ context.Context, req *mcp.RequestFor[*mcp.ServerSession, *mcp.CompleteParams]) (*mcp.CompleteResult, error) {
2020
// In a real application, you'd implement actual completion logic here.
2121
// For this example, we return a fixed set of suggestions.
2222
var suggestions []string
23-
switch params.Ref.Type {
23+
switch req.Params.Ref.Type {
2424
case "ref/prompt":
2525
suggestions = []string{"suggestion1", "suggestion2", "suggestion3"}
2626
case "ref/resource":
2727
suggestions = []string{"suggestion4", "suggestion5", "suggestion6"}
2828
default:
29-
return nil, fmt.Errorf("unrecognized content type %s", params.Ref.Type)
29+
return nil, fmt.Errorf("unrecognized content type %s", req.Params.Ref.Type)
3030
}
3131

3232
return &mcp.CompleteResult{

examples/server/custom-transport/main.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,10 @@ type HiArgs struct {
8585
}
8686

8787
// SayHi is a tool handler that responds with a greeting.
88-
func SayHi(ctx context.Context, ss *mcp.ServerSession, params *mcp.CallToolParamsFor[HiArgs]) (*mcp.CallToolResultFor[struct{}], error) {
88+
func SayHi(ctx context.Context, req *mcp.RequestFor[*mcp.ServerSession, *mcp.CallToolParamsFor[HiArgs]]) (*mcp.CallToolResultFor[struct{}], error) {
8989
return &mcp.CallToolResultFor[struct{}]{
9090
Content: []mcp.Content{
91-
&mcp.TextContent{Text: "Hi " + params.Arguments.Name},
91+
&mcp.TextContent{Text: "Hi " + req.Params.Arguments.Name},
9292
},
9393
}, nil
9494
}

examples/server/hello/main.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ type HiArgs struct {
2222
Name string `json:"name" jsonschema:"the name to say hi to"`
2323
}
2424

25-
func SayHi(ctx context.Context, ss *mcp.ServerSession, params *mcp.CallToolParamsFor[HiArgs]) (*mcp.CallToolResultFor[struct{}], error) {
25+
func SayHi(ctx context.Context, req *mcp.RequestFor[*mcp.ServerSession, *mcp.CallToolParamsFor[HiArgs]]) (*mcp.CallToolResultFor[struct{}], error) {
2626
return &mcp.CallToolResultFor[struct{}]{
2727
Content: []mcp.Content{
28-
&mcp.TextContent{Text: "Hi " + params.Arguments.Name},
28+
&mcp.TextContent{Text: "Hi " + req.Params.Arguments.Name},
2929
},
3030
}, nil
3131
}
@@ -69,8 +69,8 @@ var embeddedResources = map[string]string{
6969
"info": "This is the hello example server.",
7070
}
7171

72-
func handleEmbeddedResource(_ context.Context, _ *mcp.ServerSession, params *mcp.ReadResourceParams) (*mcp.ReadResourceResult, error) {
73-
u, err := url.Parse(params.URI)
72+
func handleEmbeddedResource(_ context.Context, req *mcp.RequestFor[*mcp.ServerSession, *mcp.ReadResourceParams]) (*mcp.ReadResourceResult, error) {
73+
u, err := url.Parse(req.Params.URI)
7474
if err != nil {
7575
return nil, err
7676
}
@@ -84,7 +84,7 @@ func handleEmbeddedResource(_ context.Context, _ *mcp.ServerSession, params *mcp
8484
}
8585
return &mcp.ReadResourceResult{
8686
Contents: []*mcp.ResourceContents{
87-
{URI: params.URI, MIMEType: "text/plain", Text: text},
87+
{URI: req.Params.URI, MIMEType: "text/plain", Text: text},
8888
},
8989
}, nil
9090
}

examples/server/memory/kb.go

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ func (fs *fileStore) Read() ([]byte, error) {
8484

8585
// Write saves data to file with 0600 permissions.
8686
func (fs *fileStore) Write(data []byte) error {
87-
if err := os.WriteFile(fs.path, data, 0600); err != nil {
87+
if err := os.WriteFile(fs.path, data, 0o600); err != nil {
8888
return fmt.Errorf("failed to write file %s: %w", fs.path, err)
8989
}
9090
return nil
@@ -431,10 +431,10 @@ func (k knowledgeBase) openNodes(names []string) (KnowledgeGraph, error) {
431431
}, nil
432432
}
433433

434-
func (k knowledgeBase) CreateEntities(ctx context.Context, ss *mcp.ServerSession, params *mcp.CallToolParamsFor[CreateEntitiesArgs]) (*mcp.CallToolResultFor[CreateEntitiesResult], error) {
434+
func (k knowledgeBase) CreateEntities(ctx context.Context, req *mcp.RequestFor[*mcp.ServerSession, *mcp.CallToolParamsFor[CreateEntitiesArgs]]) (*mcp.CallToolResultFor[CreateEntitiesResult], error) {
435435
var res mcp.CallToolResultFor[CreateEntitiesResult]
436436

437-
entities, err := k.createEntities(params.Arguments.Entities)
437+
entities, err := k.createEntities(req.Params.Arguments.Entities)
438438
if err != nil {
439439
return nil, err
440440
}
@@ -450,10 +450,10 @@ func (k knowledgeBase) CreateEntities(ctx context.Context, ss *mcp.ServerSession
450450
return &res, nil
451451
}
452452

453-
func (k knowledgeBase) CreateRelations(ctx context.Context, ss *mcp.ServerSession, params *mcp.CallToolParamsFor[CreateRelationsArgs]) (*mcp.CallToolResultFor[CreateRelationsResult], error) {
453+
func (k knowledgeBase) CreateRelations(ctx context.Context, req *mcp.RequestFor[*mcp.ServerSession, *mcp.CallToolParamsFor[CreateRelationsArgs]]) (*mcp.CallToolResultFor[CreateRelationsResult], error) {
454454
var res mcp.CallToolResultFor[CreateRelationsResult]
455455

456-
relations, err := k.createRelations(params.Arguments.Relations)
456+
relations, err := k.createRelations(req.Params.Arguments.Relations)
457457
if err != nil {
458458
return nil, err
459459
}
@@ -469,10 +469,10 @@ func (k knowledgeBase) CreateRelations(ctx context.Context, ss *mcp.ServerSessio
469469
return &res, nil
470470
}
471471

472-
func (k knowledgeBase) AddObservations(ctx context.Context, ss *mcp.ServerSession, params *mcp.CallToolParamsFor[AddObservationsArgs]) (*mcp.CallToolResultFor[AddObservationsResult], error) {
472+
func (k knowledgeBase) AddObservations(ctx context.Context, req *mcp.RequestFor[*mcp.ServerSession, *mcp.CallToolParamsFor[AddObservationsArgs]]) (*mcp.CallToolResultFor[AddObservationsResult], error) {
473473
var res mcp.CallToolResultFor[AddObservationsResult]
474474

475-
observations, err := k.addObservations(params.Arguments.Observations)
475+
observations, err := k.addObservations(req.Params.Arguments.Observations)
476476
if err != nil {
477477
return nil, err
478478
}
@@ -488,10 +488,10 @@ func (k knowledgeBase) AddObservations(ctx context.Context, ss *mcp.ServerSessio
488488
return &res, nil
489489
}
490490

491-
func (k knowledgeBase) DeleteEntities(ctx context.Context, ss *mcp.ServerSession, params *mcp.CallToolParamsFor[DeleteEntitiesArgs]) (*mcp.CallToolResultFor[struct{}], error) {
491+
func (k knowledgeBase) DeleteEntities(ctx context.Context, req *mcp.RequestFor[*mcp.ServerSession, *mcp.CallToolParamsFor[DeleteEntitiesArgs]]) (*mcp.CallToolResultFor[struct{}], error) {
492492
var res mcp.CallToolResultFor[struct{}]
493493

494-
err := k.deleteEntities(params.Arguments.EntityNames)
494+
err := k.deleteEntities(req.Params.Arguments.EntityNames)
495495
if err != nil {
496496
return nil, err
497497
}
@@ -503,10 +503,10 @@ func (k knowledgeBase) DeleteEntities(ctx context.Context, ss *mcp.ServerSession
503503
return &res, nil
504504
}
505505

506-
func (k knowledgeBase) DeleteObservations(ctx context.Context, ss *mcp.ServerSession, params *mcp.CallToolParamsFor[DeleteObservationsArgs]) (*mcp.CallToolResultFor[struct{}], error) {
506+
func (k knowledgeBase) DeleteObservations(ctx context.Context, req *mcp.RequestFor[*mcp.ServerSession, *mcp.CallToolParamsFor[DeleteObservationsArgs]]) (*mcp.CallToolResultFor[struct{}], error) {
507507
var res mcp.CallToolResultFor[struct{}]
508508

509-
err := k.deleteObservations(params.Arguments.Deletions)
509+
err := k.deleteObservations(req.Params.Arguments.Deletions)
510510
if err != nil {
511511
return nil, err
512512
}
@@ -518,10 +518,10 @@ func (k knowledgeBase) DeleteObservations(ctx context.Context, ss *mcp.ServerSes
518518
return &res, nil
519519
}
520520

521-
func (k knowledgeBase) DeleteRelations(ctx context.Context, ss *mcp.ServerSession, params *mcp.CallToolParamsFor[DeleteRelationsArgs]) (*mcp.CallToolResultFor[struct{}], error) {
521+
func (k knowledgeBase) DeleteRelations(ctx context.Context, req *mcp.RequestFor[*mcp.ServerSession, *mcp.CallToolParamsFor[DeleteRelationsArgs]]) (*mcp.CallToolResultFor[struct{}], error) {
522522
var res mcp.CallToolResultFor[struct{}]
523523

524-
err := k.deleteRelations(params.Arguments.Relations)
524+
err := k.deleteRelations(req.Params.Arguments.Relations)
525525
if err != nil {
526526
return nil, err
527527
}
@@ -533,7 +533,7 @@ func (k knowledgeBase) DeleteRelations(ctx context.Context, ss *mcp.ServerSessio
533533
return &res, nil
534534
}
535535

536-
func (k knowledgeBase) ReadGraph(ctx context.Context, ss *mcp.ServerSession, params *mcp.CallToolParamsFor[struct{}]) (*mcp.CallToolResultFor[KnowledgeGraph], error) {
536+
func (k knowledgeBase) ReadGraph(ctx context.Context, req *mcp.RequestFor[*mcp.ServerSession, *mcp.CallToolParamsFor[struct{}]]) (*mcp.CallToolResultFor[KnowledgeGraph], error) {
537537
var res mcp.CallToolResultFor[KnowledgeGraph]
538538

539539
graph, err := k.loadGraph()
@@ -549,10 +549,10 @@ func (k knowledgeBase) ReadGraph(ctx context.Context, ss *mcp.ServerSession, par
549549
return &res, nil
550550
}
551551

552-
func (k knowledgeBase) SearchNodes(ctx context.Context, ss *mcp.ServerSession, params *mcp.CallToolParamsFor[SearchNodesArgs]) (*mcp.CallToolResultFor[KnowledgeGraph], error) {
552+
func (k knowledgeBase) SearchNodes(ctx context.Context, req *mcp.RequestFor[*mcp.ServerSession, *mcp.CallToolParamsFor[SearchNodesArgs]]) (*mcp.CallToolResultFor[KnowledgeGraph], error) {
553553
var res mcp.CallToolResultFor[KnowledgeGraph]
554554

555-
graph, err := k.searchNodes(params.Arguments.Query)
555+
graph, err := k.searchNodes(req.Params.Arguments.Query)
556556
if err != nil {
557557
return nil, err
558558
}
@@ -565,10 +565,10 @@ func (k knowledgeBase) SearchNodes(ctx context.Context, ss *mcp.ServerSession, p
565565
return &res, nil
566566
}
567567

568-
func (k knowledgeBase) OpenNodes(ctx context.Context, ss *mcp.ServerSession, params *mcp.CallToolParamsFor[OpenNodesArgs]) (*mcp.CallToolResultFor[KnowledgeGraph], error) {
568+
func (k knowledgeBase) OpenNodes(ctx context.Context, req *mcp.RequestFor[*mcp.ServerSession, *mcp.CallToolParamsFor[OpenNodesArgs]]) (*mcp.CallToolResultFor[KnowledgeGraph], error) {
569569
var res mcp.CallToolResultFor[KnowledgeGraph]
570570

571-
graph, err := k.openNodes(params.Arguments.Names)
571+
graph, err := k.openNodes(req.Params.Arguments.Names)
572572
if err != nil {
573573
return nil, err
574574
}

0 commit comments

Comments
 (0)