go-sdk/mcp/example_middleware_test.go
Jonathan Amsterdam 6e03217c83
mcp: introduce Requests (#267)
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.
2025-08-12 17:49:50 -04:00

139 lines
4.1 KiB
Go

// Copyright 2025 The Go MCP SDK Authors. All rights reserved.
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
package mcp_test
import (
"context"
"fmt"
"log/slog"
"os"
"time"
"github.com/google/jsonschema-go/jsonschema"
"github.com/modelcontextprotocol/go-sdk/mcp"
)
// This example demonstrates server side logging using the mcp.Middleware system.
func Example_loggingMiddleware() {
// Create a logger for demonstration purposes.
logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
Level: slog.LevelInfo,
ReplaceAttr: func(_ []string, a slog.Attr) slog.Attr {
// Simplify timestamp format for consistent output.
if a.Key == slog.TimeKey {
return slog.String("time", "2025-01-01T00:00:00Z")
}
return a
},
}))
loggingMiddleware := func(next mcp.MethodHandler) mcp.MethodHandler {
return func(
ctx context.Context,
method string,
req mcp.Request,
) (mcp.Result, error) {
logger.Info("MCP method started",
"method", method,
"session_id", req.GetSession().ID(),
"has_params", req.GetParams() != nil,
)
start := time.Now()
result, err := next(ctx, method, req)
duration := time.Since(start)
if err != nil {
logger.Error("MCP method failed",
"method", method,
"session_id", req.GetSession().ID(),
"duration_ms", duration.Milliseconds(),
"err", err,
)
} else {
logger.Info("MCP method completed",
"method", method,
"session_id", req.GetSession().ID(),
"duration_ms", duration.Milliseconds(),
"has_result", result != nil,
)
}
return result, err
}
}
// Create server with middleware
server := mcp.NewServer(&mcp.Implementation{Name: "logging-example"}, nil)
server.AddReceivingMiddleware(loggingMiddleware)
// Add a simple tool
server.AddTool(
&mcp.Tool{
Name: "greet",
Description: "Greet someone with logging.",
InputSchema: &jsonschema.Schema{
Type: "object",
Properties: map[string]*jsonschema.Schema{
"name": {
Type: "string",
Description: "Name to greet",
},
},
Required: []string{"name"},
},
},
func(
ctx context.Context,
req *mcp.ServerRequest[*mcp.CallToolParamsFor[map[string]any]],
) (*mcp.CallToolResultFor[any], error) {
name, ok := req.Params.Arguments["name"].(string)
if !ok {
return nil, fmt.Errorf("name parameter is required and must be a string")
}
message := fmt.Sprintf("Hello, %s!", name)
return &mcp.CallToolResultFor[any]{
Content: []mcp.Content{
&mcp.TextContent{Text: message},
},
}, nil
},
)
// Create client-server connection for demonstration
client := mcp.NewClient(&mcp.Implementation{Name: "test-client"}, nil)
clientTransport, serverTransport := mcp.NewInMemoryTransports()
ctx := context.Background()
// Connect server and client
serverSession, _ := server.Connect(ctx, serverTransport, nil)
defer serverSession.Close()
clientSession, _ := client.Connect(ctx, clientTransport, nil)
defer clientSession.Close()
// Call the tool to demonstrate logging
result, _ := clientSession.CallTool(ctx, &mcp.CallToolParams{
Name: "greet",
Arguments: map[string]any{
"name": "World",
},
})
fmt.Printf("Tool result: %s\n", result.Content[0].(*mcp.TextContent).Text)
// Output:
// time=2025-01-01T00:00:00Z level=INFO msg="MCP method started" method=initialize session_id="" has_params=true
// time=2025-01-01T00:00:00Z level=INFO msg="MCP method completed" method=initialize session_id="" duration_ms=0 has_result=true
// time=2025-01-01T00:00:00Z level=INFO msg="MCP method started" method=notifications/initialized session_id="" has_params=true
// time=2025-01-01T00:00:00Z level=INFO msg="MCP method completed" method=notifications/initialized session_id="" duration_ms=0 has_result=false
// time=2025-01-01T00:00:00Z level=INFO msg="MCP method started" method=tools/call session_id="" has_params=true
// time=2025-01-01T00:00:00Z level=INFO msg="MCP method completed" method=tools/call session_id="" duration_ms=0 has_result=true
// Tool result: Hello, World!
}