Skip to content

Commit 57d4c45

Browse files
committed
Add Callbacks Feature
MCPServer is upgraded with the capacity to notify before and/or after requests run. Developers can choose Before / After events, and can submit callbacks that are notified during EVERY request lifecycle, or else specific request methods. The specific request method callbacks receive typed message and/or result objects. A special OnError callback is also provided. To accomplish this with a minimal margin for error, a bit of a refactoring was done: - The `MCPServer.HandleMessage` method was moved from server.go into its own file. - The individual request handlers' prototypes were changed. rather than returning `mcp.JSONRPCMessage`, they return a tuple of their specific result type and error. - A code generation schema was introduced, to facilitate adding functionality to each clause in the switch statement within `HandleMessage()`. - Now that HandleMessage() now receives a typed result object and possible error, it is able to pass those results to any configured callbacks. I considered several options including a strategy pattern to make HandleMessage() more DRY, but opted to stick with the minimal reorganization of the code, and to keep the algorithm as flat and obvious as possible. I think the codegen mitigates the repetitiveness of that section of code.
1 parent 771de1d commit 57d4c45

File tree

13 files changed

+1312
-241
lines changed

13 files changed

+1312
-241
lines changed

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,18 @@ Prompts can include:
509509

510510
For examples, see the `examples/` directory.
511511

512+
## Extras
513+
514+
### Request Callbacks
515+
516+
Hook into the request lifecycle by creating a `Callbacks` object with your
517+
selection among the possible callbacks. This enables telemetry across all
518+
functionality, and observability of various facts, for example the ability
519+
to count improperly-formatted requests, or to log the agent identity during
520+
initialization.
521+
522+
Add the `Callbacks` to the server at the time of creation using the
523+
`server.WithCallbacks` option.
512524

513525
## Contributing
514526

examples/everything/main.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,38 @@ const (
2929
)
3030

3131
func NewMCPServer() *server.MCPServer {
32+
33+
callbacks := &server.Callbacks{}
34+
35+
callbacks.AddBeforeAny(func(id any, method mcp.MCPMethod, message any) {
36+
fmt.Printf("beforeAny: %s, %v, %v\n", method, id, message)
37+
})
38+
callbacks.AddAfterAny(func(id any, method mcp.MCPMethod, message any, result any) {
39+
fmt.Printf("afterAny: %s, %v, %v, %v\n", method, id, message, result)
40+
})
41+
callbacks.AddOnError(func(id any, method mcp.MCPMethod, message any, err error) {
42+
fmt.Printf("onError: %s, %v, %v, %v\n", method, id, message, err)
43+
})
44+
callbacks.AddBeforeInitialize(func(id any, message *mcp.InitializeRequest) {
45+
fmt.Printf("beforeInitialize: %v, %v\n", id, message)
46+
})
47+
callbacks.AddAfterInitialize(func(id any, message *mcp.InitializeRequest, result *mcp.InitializeResult) {
48+
fmt.Printf("afterInitialize: %v, %v, %v\n", id, message, result)
49+
})
50+
callbacks.AddAfterCallTool(func(id any, message *mcp.CallToolRequest, result *mcp.CallToolResult) {
51+
fmt.Printf("afterCallTool: %v, %v, %v\n", id, message, result)
52+
})
53+
callbacks.AddBeforeCallTool(func(id any, message *mcp.CallToolRequest) {
54+
fmt.Printf("beforeCallTool: %v, %v\n", id, message)
55+
})
56+
3257
mcpServer := server.NewMCPServer(
3358
"example-servers/everything",
3459
"1.0.0",
3560
server.WithResourceCapabilities(true, true),
3661
server.WithPromptCapabilities(true),
3762
server.WithLogging(),
63+
server.WithCallbacks(callbacks),
3864
)
3965

4066
mcpServer.AddResource(mcp.NewResource("test://static/resource",

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ go 1.23
55
require (
66
github.com/google/uuid v1.6.0
77
github.com/stretchr/testify v1.9.0
8+
github.com/yosida95/uritemplate/v3 v3.0.2
89
)
910

1011
require (
1112
github.com/davecgh/go-spew v1.1.1 // indirect
1213
github.com/pmezard/go-difflib v1.0.0 // indirect
13-
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
1414
gopkg.in/yaml.v3 v3.0.1 // indirect
1515
)

mcp/types.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,20 @@ import (
88
"github.com/yosida95/uritemplate/v3"
99
)
1010

11+
type MCPMethod string
12+
13+
const (
14+
MethodInitialize MCPMethod = "initialize"
15+
MethodPing MCPMethod = "ping"
16+
MethodResourcesList MCPMethod = "resources/list"
17+
MethodResourcesTemplatesList MCPMethod = "resources/templates/list"
18+
MethodResourcesRead MCPMethod = "resources/read"
19+
MethodPromptsList MCPMethod = "prompts/list"
20+
MethodPromptsGet MCPMethod = "prompts/get"
21+
MethodToolsList MCPMethod = "tools/list"
22+
MethodToolsCall MCPMethod = "tools/call"
23+
)
24+
1125
type URITemplate struct {
1226
*uritemplate.Template
1327
}

0 commit comments

Comments
 (0)