Skip to content

Commit 7e2dd54

Browse files
committed
add RequestContext to support logging, progress, cancellation notification
1 parent 617c676 commit 7e2dd54

26 files changed

+425
-199
lines changed

client/inprocess_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ func TestInProcessMCPClient(t *testing.T) {
2727
mcp.WithDestructiveHintAnnotation(false),
2828
mcp.WithIdempotentHintAnnotation(true),
2929
mcp.WithOpenWorldHintAnnotation(false),
30-
), func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
30+
), func(ctx context.Context, reqContext server.RequestContext, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
3131
return &mcp.CallToolResult{
3232
Content: []mcp.Content{
3333
mcp.TextContent{
@@ -48,7 +48,7 @@ func TestInProcessMCPClient(t *testing.T) {
4848
URI: "resource://testresource",
4949
Name: "My Resource",
5050
},
51-
func(ctx context.Context, request mcp.ReadResourceRequest) ([]mcp.ResourceContents, error) {
51+
func(ctx context.Context, reqContext server.RequestContext, request mcp.ReadResourceRequest) ([]mcp.ResourceContents, error) {
5252
return []mcp.ResourceContents{
5353
mcp.TextResourceContents{
5454
URI: "resource://testresource",
@@ -70,7 +70,7 @@ func TestInProcessMCPClient(t *testing.T) {
7070
},
7171
},
7272
},
73-
func(ctx context.Context, request mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
73+
func(ctx context.Context, reqContext server.RequestContext, request mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
7474
return &mcp.GetPromptResult{
7575
Messages: []mcp.PromptMessage{
7676
{

client/sse_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ func TestSSEMCPClient(t *testing.T) {
3939
mcp.WithDestructiveHintAnnotation(false),
4040
mcp.WithIdempotentHintAnnotation(true),
4141
mcp.WithOpenWorldHintAnnotation(false),
42-
), func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
42+
), func(ctx context.Context, reqContext server.RequestContext, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
4343
return &mcp.CallToolResult{
4444
Content: []mcp.Content{
4545
mcp.TextContent{
@@ -52,7 +52,7 @@ func TestSSEMCPClient(t *testing.T) {
5252
mcpServer.AddTool(mcp.NewTool(
5353
"test-tool-for-http-header",
5454
mcp.WithDescription("Test tool for http header"),
55-
), func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
55+
), func(ctx context.Context, reqContext server.RequestContext, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
5656
// , X-Test-Header-Func
5757
return &mcp.CallToolResult{
5858
Content: []mcp.Content{

examples/custom_context/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ func makeRequest(ctx context.Context, message, token string) (*response, error)
7979
// using the token from the context.
8080
func handleMakeAuthenticatedRequestTool(
8181
ctx context.Context,
82+
reqContext server.RequestContext,
8283
request mcp.CallToolRequest,
8384
) (*mcp.CallToolResult, error) {
8485
message, ok := request.GetArguments()["message"].(string)

examples/dynamic_path/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ func main() {
1919
mcpServer := server.NewMCPServer("dynamic-path-example", "1.0.0")
2020

2121
// Add a trivial tool for demonstration
22-
mcpServer.AddTool(mcp.NewTool("echo"), func(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
22+
mcpServer.AddTool(mcp.NewTool("echo"), func(ctx context.Context, reqContext server.RequestContext, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
2323
return mcp.NewToolResultText(fmt.Sprintf("Echo: %v", req.GetArguments()["message"])), nil
2424
})
2525

examples/everything/main.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ func generateResources() []mcp.Resource {
191191

192192
func handleReadResource(
193193
ctx context.Context,
194+
reqContext server.RequestContext,
194195
request mcp.ReadResourceRequest,
195196
) ([]mcp.ResourceContents, error) {
196197
return []mcp.ResourceContents{
@@ -204,6 +205,7 @@ func handleReadResource(
204205

205206
func handleResourceTemplate(
206207
ctx context.Context,
208+
reqContext server.RequestContext,
207209
request mcp.ReadResourceRequest,
208210
) ([]mcp.ResourceContents, error) {
209211
return []mcp.ResourceContents{
@@ -217,6 +219,7 @@ func handleResourceTemplate(
217219

218220
func handleGeneratedResource(
219221
ctx context.Context,
222+
reqContext server.RequestContext,
220223
request mcp.ReadResourceRequest,
221224
) ([]mcp.ResourceContents, error) {
222225
uri := request.Params.URI
@@ -254,6 +257,7 @@ func handleGeneratedResource(
254257

255258
func handleSimplePrompt(
256259
ctx context.Context,
260+
reqContext server.RequestContext,
257261
request mcp.GetPromptRequest,
258262
) (*mcp.GetPromptResult, error) {
259263
return &mcp.GetPromptResult{
@@ -272,6 +276,7 @@ func handleSimplePrompt(
272276

273277
func handleComplexPrompt(
274278
ctx context.Context,
279+
reqContext server.RequestContext,
275280
request mcp.GetPromptRequest,
276281
) (*mcp.GetPromptResult, error) {
277282
arguments := request.Params.Arguments
@@ -310,6 +315,7 @@ func handleComplexPrompt(
310315

311316
func handleEchoTool(
312317
ctx context.Context,
318+
reqContext server.RequestContext,
313319
request mcp.CallToolRequest,
314320
) (*mcp.CallToolResult, error) {
315321
arguments := request.GetArguments()
@@ -329,6 +335,7 @@ func handleEchoTool(
329335

330336
func handleAddTool(
331337
ctx context.Context,
338+
reqContext server.RequestContext,
332339
request mcp.CallToolRequest,
333340
) (*mcp.CallToolResult, error) {
334341
arguments := request.GetArguments()
@@ -350,6 +357,7 @@ func handleAddTool(
350357

351358
func handleSendNotification(
352359
ctx context.Context,
360+
reqContext server.RequestContext,
353361
request mcp.CallToolRequest,
354362
) (*mcp.CallToolResult, error) {
355363

@@ -380,6 +388,7 @@ func handleSendNotification(
380388

381389
func handleLongRunningOperationTool(
382390
ctx context.Context,
391+
reqContext server.RequestContext,
383392
request mcp.CallToolRequest,
384393
) (*mcp.CallToolResult, error) {
385394
arguments := request.GetArguments()
@@ -445,6 +454,7 @@ func handleLongRunningOperationTool(
445454

446455
func handleGetTinyImageTool(
447456
ctx context.Context,
457+
reqContext server.RequestContext,
448458
request mcp.CallToolRequest,
449459
) (*mcp.CallToolResult, error) {
450460
return &mcp.CallToolResult{

examples/typed_tools/main.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ func main() {
6464
)
6565

6666
// Add tool handler using the typed handler
67-
s.AddTool(tool, mcp.NewTypedToolHandler(typedGreetingHandler))
67+
s.AddTool(tool, server.NewTypedToolHandler(typedGreetingHandler))
6868

6969
// Start the stdio server
7070
if err := server.ServeStdio(s); err != nil {
@@ -73,33 +73,33 @@ func main() {
7373
}
7474

7575
// Our typed handler function that receives strongly-typed arguments
76-
func typedGreetingHandler(ctx context.Context, request mcp.CallToolRequest, args GreetingArgs) (*mcp.CallToolResult, error) {
76+
func typedGreetingHandler(ctx context.Context, requestContext server.RequestContext, request mcp.CallToolRequest, args GreetingArgs) (*mcp.CallToolResult, error) {
7777
if args.Name == "" {
7878
return mcp.NewToolResultError("name is required"), nil
7979
}
8080

8181
// Build a personalized greeting based on the complex arguments
8282
greeting := fmt.Sprintf("Hello, %s!", args.Name)
83-
83+
8484
if args.Age > 0 {
8585
greeting += fmt.Sprintf(" You are %d years old.", args.Age)
8686
}
87-
87+
8888
if args.IsVIP {
8989
greeting += " Welcome back, valued VIP customer!"
9090
}
91-
91+
9292
if len(args.Languages) > 0 {
9393
greeting += fmt.Sprintf(" You speak %d languages: %v.", len(args.Languages), args.Languages)
9494
}
95-
95+
9696
if args.Metadata.Location != "" {
9797
greeting += fmt.Sprintf(" I see you're from %s.", args.Metadata.Location)
98-
98+
9999
if args.Metadata.Timezone != "" {
100100
greeting += fmt.Sprintf(" Your timezone is %s.", args.Metadata.Timezone)
101101
}
102102
}
103103

104104
return mcp.NewToolResultText(greeting), nil
105-
}
105+
}

mcp/typed_tools.go

Lines changed: 0 additions & 20 deletions
This file was deleted.

mcp/types.go

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ package mcp
55
import (
66
"encoding/json"
77
"fmt"
8-
"strconv"
98
"maps"
9+
"strconv"
1010

1111
"github.com/yosida95/uritemplate/v3"
1212
)
@@ -56,17 +56,29 @@ const (
5656

5757
// MethodNotificationResourcesListChanged notifies when the list of available resources changes.
5858
// https://modelcontextprotocol.io/specification/2025-03-26/server/resources#list-changed-notification
59-
MethodNotificationResourcesListChanged = "notifications/resources/list_changed"
59+
MethodNotificationResourcesListChanged MCPMethod = "notifications/resources/list_changed"
6060

61-
MethodNotificationResourceUpdated = "notifications/resources/updated"
61+
MethodNotificationResourceUpdated MCPMethod = "notifications/resources/updated"
6262

6363
// MethodNotificationPromptsListChanged notifies when the list of available prompt templates changes.
6464
// https://modelcontextprotocol.io/specification/2025-03-26/server/prompts#list-changed-notification
65-
MethodNotificationPromptsListChanged = "notifications/prompts/list_changed"
65+
MethodNotificationPromptsListChanged MCPMethod = "notifications/prompts/list_changed"
6666

6767
// MethodNotificationToolsListChanged notifies when the list of available tools changes.
6868
// https://spec.modelcontextprotocol.io/specification/2024-11-05/server/tools/list_changed/
69-
MethodNotificationToolsListChanged = "notifications/tools/list_changed"
69+
MethodNotificationToolsListChanged MCPMethod = "notifications/tools/list_changed"
70+
71+
// MethodNotificationMessage notifies when severs send log messages.
72+
// https://modelcontextprotocol.io/specification/2025-03-26/server/utilities/logging#log-message-notifications
73+
MethodNotificationMessage MCPMethod = "notifications/message"
74+
75+
// MethodNotificationProgress notifies progress updates for long-running operations.
76+
// https://modelcontextprotocol.io/specification/2025-03-26/basic/utilities/progress
77+
MethodNotificationProgress MCPMethod = "notifications/progress"
78+
79+
// MethodNotificationCancellation cancel a previously-issued request
80+
// https://modelcontextprotocol.io/specification/2025-03-26/basic/utilities/cancellation
81+
MethodNotificationCancellation MCPMethod = "notifications/cancelled"
7082
)
7183

7284
type URITemplate struct {
@@ -734,6 +746,29 @@ const (
734746
LoggingLevelEmergency LoggingLevel = "emergency"
735747
)
736748

749+
var (
750+
levelToSeverity = func() map[LoggingLevel]int {
751+
return map[LoggingLevel]int{
752+
LoggingLevelEmergency: 0,
753+
LoggingLevelAlert: 1,
754+
LoggingLevelCritical: 2,
755+
LoggingLevelError: 3,
756+
LoggingLevelWarning: 4,
757+
LoggingLevelNotice: 5,
758+
LoggingLevelInfo: 6,
759+
LoggingLevelDebug: 7,
760+
}
761+
}()
762+
)
763+
764+
// Allows is a helper function that decides a message could be sent to client or not according to the logging level
765+
func (subscribedLevel LoggingLevel) Allows(currentLevel LoggingLevel) (bool, error) {
766+
if _, ok := levelToSeverity[currentLevel]; !ok {
767+
return false, fmt.Errorf("illegal message logging level:%s", currentLevel)
768+
}
769+
return levelToSeverity[subscribedLevel] >= levelToSeverity[currentLevel], nil
770+
}
771+
737772
/* Sampling */
738773

739774
// CreateMessageRequest is a request from the server to sample an LLM via the

mcp/utils.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ func NewProgressNotification(
141141
) ProgressNotification {
142142
notification := ProgressNotification{
143143
Notification: Notification{
144-
Method: "notifications/progress",
144+
Method: string(MethodNotificationProgress),
145145
},
146146
Params: struct {
147147
ProgressToken ProgressToken `json:"progressToken"`

mcptest/mcptest_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ func TestServer(t *testing.T) {
5050
}
5151
}
5252

53-
func helloWorldHandler(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
53+
func helloWorldHandler(ctx context.Context, reqContext server.RequestContext, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
5454
// Extract name from request arguments
5555
name, ok := request.GetArguments()["name"].(string)
5656
if !ok {

0 commit comments

Comments
 (0)