### Install MCP-Go Library Source: https://mcp-go.dev/getting-started This command adds the MCP-Go library to your Go project, making its functionalities available for building MCP servers. ```Go go get github.com/mark3labs/mcp-go ``` -------------------------------- ### Configure Various Transport Methods for MCP-Go Server in Go Source: https://mcp-go.dev/getting-started This section outlines the different transport methods supported by MCP-Go for serving the server. It includes examples for setting up Stdio, Streamable HTTP, Server-Sent Events (SSE), and In-Process communication, providing flexibility for deployment and integration. ```Go server.ServeStdio(s) ``` ```Go server.NewStreamableHTTPServer(s).Start(":8080") ``` ```Go server.ServeSSE(s, ":8080") ``` ```Go client.NewInProcessClient(server) ``` -------------------------------- ### Execute the MCP Server Application in Go Source: https://mcp-go.dev/getting-started This command compiles and runs the Go source file containing the MCP server implementation, making it active and ready to accept connections via stdio. ```Go go run main.go ``` -------------------------------- ### Implement a Basic MCP Server with 'hello_world' Tool in Go Source: https://mcp-go.dev/getting-started This Go program sets up a minimal MCP server, defines a 'hello_world' tool that accepts a 'name' parameter, and includes a handler function to generate a greeting. The server is configured to operate over standard I/O (stdio) transport. ```Go package main import ( "context" "fmt" "github.com/mark3labs/mcp-go/mcp" "github.com/mark3labs/mcp-go/server" ) func main() { // Create a new MCP server s := server.NewMCPServer( "Demo 🚀", "1.0.0", server.WithToolCapabilities(false), ) // Add tool tool := mcp.NewTool("hello_world", mcp.WithDescription("Say hello to someone"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the person to greet"), ), ) // Add tool handler s.AddTool(tool, helloHandler) // Start the stdio server if err := server.ServeStdio(s); err != nil { fmt.Printf("Server error: %v\n", err) } } func helloHandler(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { name, err := request.RequireString("name") if err != nil { return mcp.NewToolResultError(err.Error()), nil } return mcp.NewToolResultText(fmt.Sprintf("Hello, %s!", name)), nil } ``` -------------------------------- ### Install and Run MCP Inspector for Debugging Source: https://mcp-go.dev/quick-start Instructions for installing the MCP Inspector globally via npm and running a Go server with it. The Inspector provides a web interface for interactive debugging and testing of MCP tools. ```Shell # Install the MCP Inspector npm install -g @modelcontextprotocol/inspector # Run your server with the inspector mcp-inspector go run main.go ``` -------------------------------- ### Go: Complete MCP Client Lifecycle Example Source: https://mcp-go.dev/clients/basics This snippet demonstrates the full lifecycle of an MCP client in Go, from creation and initialization to performing operations and ensuring proper cleanup. It includes functions for client setup and interaction with available tools. ```Go func demonstrateClientLifecycle() error { // 1. Creation c, err := client.NewSSEMCPClient("server-command") if err != nil { return fmt.Errorf("client creation failed: %w", err) } // Ensure cleanup happens defer func() { if closeErr := c.Close(); closeErr != nil { log.Printf("Error closing client: %v", closeErr) } }() ctx := context.Background() // 2. Initialization if err := c.Initialize(ctx); err != nil { return fmt.Errorf("client initialization failed: %w", err) } // 3. Operation if err := performClientOperations(ctx, c); err != nil { return fmt.Errorf("client operations failed: %w", err) } // 4. Cleanup (handled by defer) return nil } func performClientOperations(ctx context.Context, c client.Client) error { // List available tools tools, err := c.ListTools(ctx) if err != nil { return err } log.Printf("Found %d tools", len(tools.Tools)) // Use the tools for _, tool := range tools.Tools { result, err := c.CallTool(ctx, mcp.CallToolRequest{ Params: mcp.CallToolRequestParams{ Name: tool.Name, Arguments: map[string]interface{}{ "input": "example input", "format": "json", }, }, }) if err != nil { log.Printf("Tool %s failed: %v", tool.Name, err) continue } log.Printf("Tool %s result: %+v", tool.Name, result) } return nil } ``` -------------------------------- ### Configure Core MCP-Go Server Options in Go Source: https://mcp-go.dev/getting-started This snippet demonstrates how to initialize and customize an MCP-Go server using server.NewMCPServer. It covers setting the server name and version, and applying various server options such as enabling tool capabilities, recovery mechanisms, and custom hooks for extended functionality. ```Go s := server.NewMCPServer( "My Server", "1.0.0", server.WithToolCapabilities(true), server.WithRecovery(), server.WithHooks(myHooks), ) ``` -------------------------------- ### Creating a Basic MCP Server Instance Source: https://mcp-go.dev/servers/basics The `NewMCPServer()` function is the foundation for any MCP server, creating an instance with basic metadata (name and version). This snippet demonstrates a minimal server setup that starts with stdio transport. ```Go package main import ( "github.com/mark3labs/mcp-go/server" ) func main() { // Create a basic server s := server.NewMCPServer( "My MCP Server", // Server name "1.0.0" // Server version ) // Start the server (stdio transport) server.ServeStdio(s) } ``` -------------------------------- ### Quick Example: Complete MCP-Go Server with Tool, Resource, and Prompt Source: https://mcp-go.dev/servers This comprehensive Go example demonstrates how to initialize an MCP-Go server with specific capabilities, and then add a tool ('get_time'), a resource ('config://server'), and a prompt ('analyze_logs'). It includes handler functions for each, showcasing how to process requests and return results. The server is configured to serve over STDIO. ```Go package main import ( "context" "encoding/json" "fmt" "time" "github.com/mark3labs/mcp-go/mcp" "github.com/mark3labs/mcp-go/server" ) var start time.Time func main() { start = time.Now() // Create server with capabilities s := server.NewMCPServer( "Demo Server", "1.0.0", server.WithToolCapabilities(true), server.WithResourceCapabilities(false, true), server.WithPromptCapabilities(true), ) // Add a tool s.AddTool( mcp.NewTool("get_time", mcp.WithDescription("Get the current time"), mcp.WithString("format", mcp.Description("Time format (RFC3339, Unix, etc.)"), mcp.DefaultString("RFC3339"), ), ), handleGetTime, ) // Add a resource s.AddResource( mcp.NewResource( "config://server", "Server Configuration", mcp.WithResourceDescription("Current server configuration"), mcp.WithMIMEType("application/json"), ), handleConfig, ) // Add a prompt s.AddPrompt( mcp.NewPrompt("analyze_logs", mcp.WithPromptDescription("Analyze server logs for issues"), mcp.WithArgument("log_level", mcp.ArgumentDescription("Minimum log level to analyze"), ), ), handleAnalyzeLogs, ) // Start the server if err := server.ServeStdio(s); err != nil { fmt.Printf("Server error: %v\n", err) } } func handleGetTime(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { format := req.GetString("format", "RFC3339") var timeStr string switch format { case "Unix": timeStr = fmt.Sprintf("%d", time.Now().Unix()) default: timeStr = time.Now().Format(time.RFC3339) } return mcp.NewToolResultText(timeStr), nil } func handleConfig(ctx context.Context, req mcp.ReadResourceRequest) ([]mcp.ResourceContents, error) { config := map[string]interface{}{ "name": "Demo Server", "version": "1.0.0", "uptime": time.Since(start).String(), } configJSON, err := json.Marshal(config) if err != nil { return nil, err } return []mcp.ResourceContents{ mcp.TextResourceContents{ URI: req.Params.URI, MIMEType: "application/json", Text: string(configJSON), }, }, nil } func handleAnalyzeLogs(ctx context.Context, req mcp.GetPromptRequest) (*mcp.GetPromptResult, error) { logLevel := "error" // default value if args := req.Params.Arguments; args != nil { if level, ok := args["log_level"].(string); ok { logLevel = level } } return &mcp.GetPrompt ``` -------------------------------- ### Define LLM Resource to Expose Data in Go Source: https://mcp-go.dev/getting-started This snippet illustrates how to define a Resource using mcp.NewResource in Go. Resources expose data, such as static files or dynamic content, to Large Language Models (LLMs). The example shows defining a 'docs://readme' resource with a description and MIME type. ```Go resource := mcp.NewResource( "docs://readme", "Project README", mcp.WithResourceDescription("The project's README file"), mcp.WithMIMEType("text/markdown"), ) ``` -------------------------------- ### Build and run MCP-Go 'Hello World' server locally Source: https://mcp-go.dev/quick-start These commands initialize a Go module, fetch the `mcp-go` dependency, and then execute the 'hello-server' Go application. This prepares the server to run and listen for connections. ```Shell cd hello-server go mod init hello-server go get github.com/mark3labs/mcp-go go run main.go ``` -------------------------------- ### Create Basic MCP Go Stdio Client Source: https://mcp-go.dev/quick-start Demonstrates how to create a standard I/O (stdio) MCP client in Go. This client connects to another MCP server, initializes the connection, lists available tools, and calls a specific tool with arguments. It notes that NewStdioMCPClient starts the connection automatically. ```Go package main import ( "context" "fmt" "log" "github.com/mark3labs/mcp-go/client" "github.com/mark3labs/mcp-go/mcp" ) func main() { // Create a stdio client that connects to another MCP server // NTOE: NewStdioMCPClient will start the connection automatically. Don't call the Start method manually c, err := client.NewStdioMCPClient( "go", "run", "path/to/server/main.go", ) if err != nil { log.Fatal(err) } defer c.Close() ctx := context.Background() // Initialize the connection if err := c.Initialize(ctx); err != nil { log.Fatal(err) } // List available tools tools, err := c.ListTools(ctx) if err != nil { log.Fatal(err) } fmt.Printf("Available tools: %d\n", len(tools.Tools)) for _, tool := range tools.Tools { fmt.Printf("- %s: %s\n", tool.Name, tool.Description) } // Call a tool result, err := c.CallTool(ctx, mcp.CallToolRequest{ Params: mcp.CallToolParams{ Name: "hello_world", Arguments: map[string]interface{}{ "name": "World", }, }, }) if err != nil { log.Fatal(err) } // Print the result for _, content := range result.Content { if content.Type == "text" { fmt.Printf("Result: %s\n", content.Text) } } } ``` -------------------------------- ### Go: Implement a Basic SSE Server with MCP Tools and Resources Source: https://mcp-go.dev/transports/sse This Go code provides a complete example of an SSE server built with `mcp-go`. It illustrates the initialization of the server, the registration of two real-time tools (`stream_data` and `monitor_system`) with their respective parameter definitions, and the addition of a dynamic resource (`metrics://current`). The example also includes the handler functions for these tools and resources, demonstrating how to process requests, simulate data streaming with progress updates, and handle real-time system monitoring, including context cancellation and hypothetical notifier interactions. ```Go package main import ( "context" "fmt" "log" "time" "github.com/mark3labs/mcp-go/mcp" "github.com/mark3labs/mcp-go/server" ) func main() { s := server.NewMCPServer("SSE Server", "1.0.0", server.WithToolCapabilities(true), server.WithResourceCapabilities(true), ) // Add real-time tools s.AddTool( mcp.NewTool("stream_data", mcp.WithDescription("Stream data with real-time updates"), mcp.WithString("source", mcp.Required()), mcp.WithInteger("count", mcp.Default(10)), ), handleStreamData, ) s.AddTool( mcp.NewTool("monitor_system", mcp.WithDescription("Monitor system metrics in real-time"), mcp.WithInteger("duration", mcp.Default(60)), ), handleSystemMonitor, ) // Add dynamic resources s.AddResource( mcp.NewResource( "metrics://current", "Current System Metrics", mcp.WithResourceDescription("Real-time system metrics"), mcp.WithMIMEType("application/json"), ), handleCurrentMetrics, ) // Start SSE server log.Println("Starting SSE server on :8080") if err := server.ServeSSE(s, ":8080"); err != nil { log.Fatal(err) } } func handleStreamData(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { source := req.Params.Arguments["source"].(string) count := int(req.Params.Arguments["count"].(float64)) // Get notifier for real-time updates (hypothetical functions) // Note: These functions would be provided by the SSE transport implementation notifier := getNotifierFromContext(ctx) // Hypothetical function sessionID := getSessionIDFromContext(ctx) // Hypothetical function // Stream data with progress updates var results []map[string]interface{} for i := 0; i < count; i++ { // Check for cancellation select { case <-ctx.Done(): return nil, ctx.Err() default: } // Simulate data processing data := generateData(source, i) results = append(results, data) // Send progress notification if notifier != nil { // Note: ProgressNotification would be defined by the MCP protocol notifier.SendProgress(sessionID, map[string]interface{}{ "progress": i + 1, "total": count, "message": fmt.Sprintf("Processed %d/%d items from %s", i+1, count, source), }) } time.Sleep(100 * time.Millisecond) } return mcp.NewToolResultJSON(map[string]interface{}{ "source": source, "results": results, "count": len(results), }), nil } // Helper functions for the examples func generateData(source string, index int) map[string]interface{} { return map[string]interface{}{ "source": source, "index": index, "value": fmt.Sprintf("data_%d", index), } } func getNotifierFromContext(ctx context.Context) interface{} { // Placeholder implementation - would be provided by SSE transport return nil } func getSessionIDFromContext(ctx context.Context) string { // Placeholder implementation - would be provided by SSE transport return "session_123" } func handleSystemMonitor(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { duration := int(req.Params.Arguments["duration"].(float64)) notifier := getNotifierFromContext(ctx) sessionID := getSessionIDFromContext(ctx) // Monitor system for specified duration ticker := time.NewTicker(5 * time.Second) defer ticker.Stop() timeout := time.After(time.Duration(duration) * time.Second) var metrics []map[string]interface{} for { select { case <-ctx.Done(): return nil, ctx.Err() case <-timeout: return mcp.NewToolResultJSON(map[string]interface{}{ "duration": duration, "metrics": metrics, "samples": len(metrics), }), nil case <-ticker.C: // Collect current metrics currentMetrics := collectSystemMetrics() metrics = append(metrics, currentMetrics) // Send real-time update if notifier != nil { // Note: SendCustom would be a method on the notifier interface // notifier.SendCustom(sessionID, "system_metrics", currentMetrics) } } } } func collectSystemMetrics() map[string]interface{} { // Placeholder implementation return map[string]interface{}{ "cpu": 50.5, "memory": 75.2, "disk": 30.1, } } func handleCurrentMetrics(ctx context.Context, req mcp.ReadResourceRequest) (*mcp.ReadResourceResult ``` -------------------------------- ### Basic In-Process MCP-Go Server and Client Example Source: https://mcp-go.dev/transports/inprocess This Go code snippet illustrates the setup of an in-process MCP server and client. It defines a 'Calculator Server' with a 'calculate' tool that supports basic arithmetic operations (add, subtract, multiply, divide). The example then demonstrates how to initialize an in-process client, call the 'calculate' tool with specific arguments, and print the result, showcasing seamless direct integration within the same process. ```Go package main import ( "context" "fmt" "log" "github.com/mark3labs/mcp-go/mcp" "github.com/mark3labs/mcp-go/server" "github.com/mark3labs/mcp-go/client" ) func main() { // Create server s := server.NewMCPServer("Calculator Server", "1.0.0", server.WithToolCapabilities(true), ) // Add calculator tool s.AddTool( mcp.NewTool("calculate", mcp.WithDescription("Perform basic mathematical calculations"), mcp.WithString("operation", mcp.Required(), mcp.Enum("add", "subtract", "multiply", "divide"), mcp.Description("The operation to perform"), ), mcp.WithNumber("x", mcp.Required(), mcp.Description("First number")), mcp.WithNumber("y", mcp.Required(), mcp.Description("Second number")), ), handleCalculate, ) // Create in-process client client := client.NewInProcessClient(s) defer client.Close() ctx := context.Background() // Initialize if err := client.Initialize(ctx); err != nil { log.Fatal(err) } // Use the calculator result, err := client.CallTool(ctx, mcp.CallToolRequest{ Params: mcp.CallToolRequestParams{ Name: "calculate", Arguments: map[string]interface{}{ "operation": "add", "x": 10.0, "y": 5.0, }, }, }) if err != nil { log.Fatal(err) } fmt.Printf("Result: %s\n", result.Content[0].Text) } func handleCalculate(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { operation := req.Params.Arguments["operation"].(string) x := req.Params.Arguments["x"].(float64) y := req.Params.Arguments["y"].(float64) var result float64 switch operation { case "add": result = x + y case "subtract": result = x - y case "multiply": result = x * y case "divide": if y == 0 { return mcp.NewToolResultError("division by zero"), nil } result = x / y default: return nil, fmt.Errorf("unknown operation: %s", operation) } return mcp.NewToolResultText(fmt.Sprintf("%.2f", result)), nil } ``` -------------------------------- ### Define 'Hello World' MCP server with mcp-go in Go Source: https://mcp-go.dev/quick-start This Go program creates a basic MCP server exposing a 'hello_world' tool. It takes a 'name' parameter, returns a greeting, and serves over standard I/O using the `mcp-go` library. ```Go package main import ( "context" "errors" "fmt" "github.com/mark3labs/mcp-go/mcp" "github.com/mark3labs/mcp-go/server" ) func main() { // Create a new MCP server s := server.NewMCPServer( "Hello World Server", "1.0.0", server.WithToolCapabilities(false), ) // Define a simple tool tool := mcp.NewTool("hello_world", mcp.WithDescription("Say hello to someone"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the person to greet"), ), ) // Add tool handler s.AddTool(tool, helloHandler) // Start the stdio server if err := server.ServeStdio(s); err != nil { fmt.Printf("Server error: %v\n", err) } } func helloHandler(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { name, err := request.RequireString("name") if err != nil { return mcp.NewToolResultError(err.Error()), nil } return mcp.NewToolResultText(fmt.Sprintf("Hello, %s! 👋", name)), nil } ``` -------------------------------- ### Configure and Start Advanced MCP SSE Server Source: https://mcp-go.dev/transports/sse Illustrates the setup of an MCP server with advanced Server-Sent Events (SSE) configuration. It includes custom session start/end hooks, defines SSE-specific options like base path, allowed origins, heartbeat, and connection limits, and integrates collaborative tools. ```Go func main() { s := server.NewMCPServer("Advanced SSE Server", "1.0.0", server.WithAllCapabilities(), server.WithRecovery(), server.WithHooks(&server.Hooks{ OnSessionStart: func(sessionID string) { log.Printf("SSE client connected: %s", sessionID) broadcastUserCount() }, OnSessionEnd: func(sessionID string) { log.Printf("SSE client disconnected: %s", sessionID) broadcastUserCount() }, }), ) // Configure SSE-specific options sseOptions := server.SSEOptions{ BasePath: "/mcp", AllowedOrigins: []string{"http://localhost:3000", "https://myapp.com"}, HeartbeatInterval: 30 * time.Second, MaxConnections: 100, ConnectionTimeout: 5 * time.Minute, EnableCompression: true, } // Add collaborative tools addCollaborativeTools(s) addRealTimeResources(s) log.Println("Starting advanced SSE server on :8080") if err := server.ServeSSEWithOptions(s, ":8080", sseOptions); err != nil { log.Fatal(err) } } // Helper functions for the advanced example func broadcastUserCount() { // Placeholder implementation log.Println("Broadcasting user count update") } func addCollaborativeToolsPlaceholder(s *server.MCPServer) { // Placeholder implementation - would add collaborative tools } func addRealTimeResources(s *server.MCPServer) { // Placeholder implementation - would add real-time resources } ``` -------------------------------- ### Implement StreamableHTTP MCP Go Client Source: https://mcp-go.dev/quick-start Shows how to create and use a StreamableHTTP client in Go to connect to an MCP server over HTTP. This client is suitable for HTTP-based servers and demonstrates initialization and a tool call. ```Go package main import ( "context" "fmt" "log" "github.com/mark3labs/mcp-go/client" "github.com/mark3labs/mcp-go/mcp" ) func main() { // Create a StreamableHTTP client c := client.NewStreamableHttpClient("http://localhost:8080/mcp") defer c.Close() ctx := context.Background() // Initialize and use the client if err := c.Initialize(ctx); err != nil { log.Fatal(err) } // Call a tool result, err := c.CallTool(ctx, mcp.CallToolRequest{ Params: mcp.CallToolRequestParams{ Name: "hello_world", Arguments: map[string]interface{}{ "name": "StreamableHTTP World", }, }, }) if err != nil { log.Fatal(err) } fmt.Printf("Tool result: %+v\n", result) } ``` -------------------------------- ### Go Main Function for Production Server Setup Source: https://mcp-go.dev/servers/advanced This Go `main` function illustrates the comprehensive setup of a production-ready server. It initializes core components, applies various middleware (logging, rate limiting, authentication), integrates business and telemetry hooks, and configures server capabilities. The `startWithGracefulShutdown` helper demonstrates robust server startup and controlled shutdown upon receiving OS signals. ```Go func main() { // Initialize components logger := log.New(os.Stdout, "[MCP] ", log.LstdFlags) metrics := NewPrometheusMetrics() sessionManager := NewSessionManager() notifier := NewCustomNotifier() // Create middleware loggingMW := NewLoggingMiddleware(logger) rateLimitMW := NewRateLimitMiddleware(10.0, 20) // 10 req/sec, burst 20 authMW := NewAuthMiddleware(NewJWTValidator()) // Create hooks telemetryHooks := NewTelemetryHooks(metrics, logger) businessHooks := NewBusinessHooks(NewAuditLogger(), NewSlackNotifier()) // Create server with all features s := server.NewMCPServer("Production Server", "1.0.0", server.WithToolCapabilities(true), server.WithResourceCapabilities(false, true), server.WithPromptCapabilities(true), server.WithRecovery(), server.WithHooks(telemetryHooks), server.WithToolHandlerMiddleware(loggingMW.ToolMiddleware), server.WithToolFilter(NewPermissionFilter(sessionManager)), ) // Add tools and resources addProductionTools(s) addProductionResources(s) addProductionPrompts(s) // Start server with graceful shutdown startWithGracefulShutdown(s) } func startWithGracefulShutdown(s *server.MCPServer) { // Setup signal handling sigChan := make(chan os.Signal, 1) signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM) // Start server in goroutine go func() { if err := server.ServeStdio(s); err != nil { log.Printf("Server error: %v", err) } }() // Wait for shutdown signal <-sigChan log.Println("Shutting down server...") // Graceful shutdown with timeout ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() if err := s.Shutdown(ctx); err != nil { log.Printf("Shutdown error: %v", err) } log.Println("Server stopped") } ``` -------------------------------- ### Create and Configure an MCP-Go Server Source: https://mcp-go.dev/core-concepts This Go example demonstrates how to instantiate an MCP-Go server, add tools and resources to it, and then serve it over Stdio. Servers are designed to expose functionality like database access or custom business logic to LLMs. ```Go // Server example - exposes functionality s := server.NewMCPServer("Database Tools", "1.0.0") s.AddTool(queryTool, handleQuery) s.AddResource(tableResource, handleTableAccess) server.ServeStdio(s) ``` -------------------------------- ### Configure Claude Desktop to connect to a local MCP-Go server Source: https://mcp-go.dev/quick-start This JSON snippet configures Claude Desktop to recognize and connect to a local MCP server. It defines a server named 'hello-world' and specifies the command to run the Go application, enabling integration with Claude. ```JSON { "mcpServers": { "hello-world": { "command": "go", "args": ["run", "/path/to/your/hello-server/main.go"] } } } ``` -------------------------------- ### Configure and Start an Advanced StreamableHTTP MCP Server in Go Source: https://mcp-go.dev/transports/http This Go code demonstrates how to set up and start an MCP server with advanced StreamableHTTP configurations. It includes setting timeouts, body size limits, CORS, Gzip, trusted proxies, and adding custom hooks for tool calls and resource reads. It also shows how to add various types of tools (CRUD, Batch, Analytics) and implement custom middleware for authentication, rate limiting, and caching. ```Go func main() { s := server.NewMCPServer("Advanced StreamableHTTP Server", "1.0.0", server.WithAllCapabilities(), server.WithRecovery(), server.WithHooks(&server.Hooks{ OnToolCall: logToolCall, OnResourceRead: logResourceRead, }), ) // Configure StreamableHTTP-specific options streamableHTTPOptions := server.StreamableHTTPOptions{ BasePath: "/api/v1/mcp", ReadTimeout: 30 * time.Second, WriteTimeout: 30 * time.Second, IdleTimeout: 60 * time.Second, MaxBodySize: 10 * 1024 * 1024, // 10MB EnableCORS: true, AllowedOrigins: []string{"https://myapp.com", "http://localhost:3000"}, AllowedMethods: []string{"GET", "POST", "OPTIONS"}, AllowedHeaders: []string{"Content-Type", "Authorization"}, EnableGzip: true, TrustedProxies: []string{"10.0.0.0/8", "172.16.0.0/12"}, } // Add middleware addStreamableHTTPMiddleware(s) // Add comprehensive tools addCRUDTools(s) addBatchTools(s) addAnalyticsTools(s) log.Println("Starting advanced StreamableHTTP server on :8080") httpServer := server.NewStreamableHTTPServer(s, streamableHTTPOptions...) if err := httpServer.Start(":8080"); err != nil { log.Fatal(err) } } // Helper functions for the advanced example func addCRUDTools(s *server.MCPServer) { // Placeholder implementation - would add CRUD tools } func addBatchTools(s *server.MCPServer) { // Placeholder implementation - would add batch processing tools } func addAnalyticsTools(s *server.MCPServer) { // Placeholder implementation - would add analytics tools } func logToolCall(sessionID, toolName string, duration time.Duration, err error) { // Placeholder implementation if err != nil { log.Printf("Tool %s failed: %v", toolName, err) } else { log.Printf("Tool %s completed in %v", toolName, duration) } } func logResourceRead(sessionID, uri string, duration time.Duration, err error) { // Placeholder implementation if err != nil { log.Printf("Resource read %s failed: %v", uri, err) } else { log.Printf("Resource read %s completed in %v", uri, duration) } } func addStreamableHTTPMiddleware(s *server.MCPServer) { // Authentication middleware s.AddToolMiddleware(func(next server.ToolHandler) server.ToolHandler { return func(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Extract and validate auth token token := extractAuthToken(ctx) if token == "" { return nil, fmt.Errorf("authentication required") } user, err := validateToken(token) if err != nil { return nil, fmt.Errorf("invalid token: %w", err) } // Add user to context ctx = context.WithValue(ctx, "user", user) return next(ctx, req) } }) // Rate limiting middleware s.AddToolMiddleware(func(next server.ToolHandler) server.ToolHandler { return func(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { clientIP := getClientIP(ctx) if !rateLimiter.Allow(clientIP) { return nil, fmt.Errorf("rate limit exceeded") } return next(ctx, req) } }) // Caching middleware s.AddResourceMiddleware(func(next server.ResourceHandler) server.ResourceHandler { return func(ctx context.Context, req mcp.ReadResourceRequest) (*mcp.ReadResourceResult, error) { // Check cache first if cached := getFromCache(req.Params.URI); cached != nil { return cached, nil } result, err := next(ctx, req) if err == nil { // Cache successful results setCache(req.Params.URI, result, 5*time.Minute) } return result, err } }) } ``` -------------------------------- ### Define LLM Tool for Function Calling in Go Source: https://mcp-go.dev/getting-started This snippet demonstrates how to define a Tool using mcp.NewTool in Go. Tools allow Large Language Models (LLMs) to perform actions on your server. It includes specifying a description, required string and number parameters, and enum constraints for operations like arithmetic. ```Go calculatorTool := mcp.NewTool("calculate", mcp.WithDescription("Perform basic arithmetic operations"), mcp.WithString("operation", mcp.Required(), mcp.Enum("add", "subtract", "multiply", "divide"), ), mcp.WithNumber("x", mcp.Required()), mcp.WithNumber("y", mcp.Required()), ) ``` -------------------------------- ### Configuring an MCP Server with Options Source: https://mcp-go.dev/servers/basics Server options allow you to configure advanced capabilities and behavior during server creation. This example shows how to enable tool, resource, and prompt capabilities, add panic recovery, and include custom lifecycle hooks. ```Go s := server.NewMCPServer( "Advanced Server", "2.0.0", server.WithToolCapabilities(true), // Enable tools server.WithResourceCapabilities(true), // Enable resources server.WithPromptCapabilities(true), // Enable prompts server.WithRecovery(), // Add panic recovery server.WithHooks(myHooks) // Add lifecycle hooks ) ``` -------------------------------- ### Test MCP STDIO Server from Command Line Source: https://mcp-go.dev/transports/stdio Learn to interact with your MCP STDIO server directly from the command line. This snippet demonstrates how to start the server and then send JSON-RPC requests using `echo` piped to the server for initialization, listing tools, and calling specific tools. ```Bash # Start your server go run main.go # Send initialization request echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{"tools":{}},"clientInfo":{"name":"test","version":"1.0.0"}}}' | go run main.go # List tools echo '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}' | go run main.go # Call a tool echo '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"list_files","arguments":{"path":".","recursive":false}}}' | go run main.go ``` -------------------------------- ### Go STDIO Client Creation in MCP-Go Source: https://mcp-go.dev/clients/basics Illustrates how to create an MCP-Go client using the STDIO transport, which spawns a subprocess. Includes an example demonstrating how to configure the client with custom environment variables. ```Go package main import ( "context" "errors" "fmt" "log" "math" "net/http" "sync" "time" "github.com/mark3labs/mcp-go/client" "github.com/mark3labs/mcp-go/mcp" ) func createStdioClient() (client.Client, error) { // Create client that spawns a subprocess c, err := client.NewStdioMCPClient( "go", []string{}, "run", "/path/to/server/main.go", ) if err != nil { return nil, fmt.Errorf("failed to create STDIO client: %w", err) } return c, nil } // With custom environment variables func createStdioClientWithEnv() (client.Client, error) { env := []string{ "LOG_LEVEL=debug", "DATABASE_URL=sqlite://test.db", } c, err := client.NewStdioMCPClient( "go", env, "run", "/path/to/server/main.go", ) if err != nil { return nil, fmt.Errorf("failed to create STDIO client: %w", err) } return c, nil } ``` -------------------------------- ### Go SSE Client Creation in MCP-Go Source: https://mcp-go.dev/clients/basics Provides an example of creating an MCP-Go client using the Server-Sent Events (SSE) transport. This snippet demonstrates how to initialize the SSE client and configure it with custom headers. ```Go func createSSEClient() client.Client { // Basic SSE client c, err := NewSSEMCPClient(testServer.URL+"/sse", // Set custom headers WithHeaders(map[string]string{ "X-Custom-Header": "custom-value", "Y-Another-Header": "another-value", }), ) return c } ``` -------------------------------- ### Create In-Process MCP Client in Go Source: https://mcp-go.dev/clients Provides an example of initializing an in-process client, best for testing, embedded scenarios, or high-performance applications where the client and server run in the same process. ```go // Create in-process client client := client.NewInProcessClient(server) ``` -------------------------------- ### Implement StreamableHTTP Client Connection Pooling in Go Source: https://mcp-go.dev/clients/transports Defines `StreamableHTTPClientPool` for managing `StreamableHTTPClient` instances, improving resource efficiency. Includes methods for pool creation, client retrieval (`Get`), client return (`Put`), and an example of using the pool for `CallTool` operations. ```Go type StreamableHTTPClientPool struct { clients chan *client.Client factory func() *client.Client maxSize int } func NewStreamableHTTPClientPool(baseURL string, maxSize int) *StreamableHTTPClientPool { pool := &StreamableHTTPClientPool{ clients: make(chan *client.Client, maxSize), maxSize: maxSize, factory: func() *client.Client { return client.NewStreamableHttpClient(baseURL) }, } // Pre-populate pool for i := 0; i < maxSize; i++ { pool.clients <- pool.factory() } return pool } func (pool *StreamableHTTPClientPool) Get() *client.Client { select { case c := <-pool.clients: return c default: return pool.factory() } } func (pool *StreamableHTTPClientPool) Put(c *client.Client) { select { case pool.clients <- c: default: // Pool full, close client c.Close() } } func (pool *StreamableHTTPClientPool) CallTool(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { c := pool.Get() defer pool.Put(c) return c.CallTool(ctx, req) } ``` -------------------------------- ### Go MCP Server: Implement Logging Middleware Source: https://mcp-go.dev/servers/advanced This Go code provides an example of a `LoggingMiddleware` for an MCP server. It intercepts tool calls and resource reads to log their start, completion, and any errors, along with session and duration details. This middleware can be used for cross-cutting concerns like monitoring and debugging. ```Go type LoggingMiddleware struct { logger *log.Logger } func NewLoggingMiddleware(logger *log.Logger) *LoggingMiddleware { return &LoggingMiddleware{logger: logger} } func (m *LoggingMiddleware) ToolMiddleware(next server.ToolHandlerFunc) server.ToolHandlerFunc { return func(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { start := time.Now() sessionID := server.GetSessionID(ctx) m.logger.Printf("Tool call started: tool=%s", req.Params.Name) result, err := next(ctx, req) duration := time.Since(start) if err != nil { m.logger.Printf("Tool call failed: session=%s tool=%s duration=%v error=%v", sessionID, req.Params.Name, duration, err) } else { m.logger.Printf("Tool call completed: session=%s tool=%s duration=%v", sessionID, req.Params.Name, duration) } return result, err } } func (m *LoggingMiddleware) ResourceMiddleware(next server.ResourceHandler) server.ResourceHandler { return func(ctx context.Context, req mcp.ReadResourceRequest) (*mcp.ReadResourceResult, error) { start := time.Now() sessionID := server.GetSessionID(ctx) m.logger.Printf("Resource read started: session=%s uri=%s", sessionID, req.Params.URI) result, err := next(ctx, req) duration := time.Since(start) if err != nil { m.logger.Printf("Resource read failed: session=%s uri=%s duration=%v error=%v", sessionID, req.Params.URI, duration, err) } else { m.logger.Printf("Resource read completed: session=%s uri=%s duration=%v", sessionID, req.Params.URI, duration) } return result, err } } ``` -------------------------------- ### Go: Implement Resource Discovery and Listing Source: https://mcp-go.dev/servers/resources This Go `main` function illustrates how to set up an MCP server and register multiple resources for client discovery. It defines various resources with their URIs, names, descriptions, MIME types, and associated handlers, making them available through the server's resource capabilities. ```Go func main() { s := server.NewMCPServer("Resource Server", "1.0.0", server.WithResourceCapabilities(true), ) // Add multiple resources resources := []struct { uri string name string description string mimeType string handler server.ResourceHandler }{ {"docs://readme", "README", "Project documentation", "text/markdown", handleReadme}, {"config://app", "App Config", "Application settings", "application/json", handleConfig}, {"users://{id}", "User Profile", "User information", "application/json", handleUser}, } for _, r := range resources { s.AddResource( mcp.NewResource(r.uri, r.name, mcp.WithResourceDescription(r.description), mcp.WithMIMEType(r.mimeType), ), r.handler, ) } server.ServeStdio(s) } ``` -------------------------------- ### Add Debug Logging to MCP STDIO Go Server Source: https://mcp-go.dev/transports/stdio Implement robust debug logging for your MCP STDIO server written in Go. This example demonstrates setting up file-based logging, capturing session start events, and logging tool call successes or failures, including the ability to add a custom tool that logs its execution. ```Go func main() { // Setup debug logging logFile, err := os.OpenFile("mcp-server.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) if err != nil { log.Fatal(err) } defer logFile.Close() logger := log.New(logFile, "[MCP] ", log.LstdFlags|log.Lshortfile) s := server.NewMCPServer("Debug Server", "1.0.0", server.WithToolCapabilities(true), server.WithHooks(&server.Hooks{ OnSessionStart: func(sessionID string) { logger.Printf("Session started: %s", sessionID) }, OnToolCall: func(sessionID, toolName string, duration time.Duration, err error) { if err != nil { logger.Printf("Tool %s failed: %v", toolName, err) } else { logger.Printf("Tool %s completed in %v", toolName, duration) } }, }), ) // Add tools with debug logging s.AddTool( mcp.NewTool("debug_echo", mcp.WithDescription("Echo with debug logging"), mcp.WithString("message", mcp.Required()), ), func(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { message := req.Params.Arguments["message"].(string) logger.Printf("Echo tool called with message: %s", message) return mcp.NewToolResultText(fmt.Sprintf("Echo: %s", message)), nil }, ) logger.Println("Starting STDIO server...") if err := server.ServeStdio(s); err != nil { logger.Printf("Server error: %v", err) } } ``` -------------------------------- ### Create a Basic MCP Resource Structure Source: https://mcp-go.dev/servers/resources Demonstrates how to initialize a simple, static resource using `mcp.NewResource`. This snippet defines the resource's URI, human-readable name, description, and MIME type, serving as a fundamental building block for exposing data. ```Go // Create a simple resource resource := mcp.NewResource( "docs://readme", // URI - unique identifier "Project README", // Name - human-readable mcp.WithResourceDescription("Main project documentation"), mcp.WithMIMEType("text/markdown"), ) ```