### Run the OAuth Client Example Source: https://github.com/mark3labs/mcp-go/blob/main/examples/oauth_client/README.md Execute the main Go program to start the OAuth client example. ```bash # Run the example go run main.go ``` -------------------------------- ### Start the HTTP Sampling Server for Testing Source: https://github.com/mark3labs/mcp-go/blob/main/examples/sampling_http_server/README.md Execute this command to start the server when testing with the client example. ```bash go run examples/sampling_http_server/main.go ``` -------------------------------- ### Complete MCP Server with Sampling Example Source: https://github.com/mark3labs/mcp-go/blob/main/www/docs/pages/servers/advanced-sampling.mdx This Go code demonstrates a full MCP server setup that enables sampling, adds a tool for asking an LLM questions, and starts the server. It includes the necessary imports, server initialization, tool definition with input schema, sampling request handling, and a helper function to extract text from content. Use this as a blueprint for integrating LLM interactions via sampling into your applications. ```go package main import ( "context" "fmt" "log" "time" "github.com/mark3labs/mcp-go/mcp" "github.com/mark3labs/mcp-go/server" ) func main() { // Create server mcpServer := server.NewMCPServer("sampling-example-server", "1.0.0") // Enable sampling capability mcpServer.EnableSampling() // Add sampling tool mcpServer.AddTool(mcp.Tool{ Name: "ask_llm", Description: "Ask the LLM a question using sampling", InputSchema: mcp.ToolInputSchema{ Type: "object", Properties: map[string]any{ "question": map[string]any{ "type": "string", "description": "The question to ask the LLM", }, "system_prompt": map[string]any{ "type": "string", "description": "Optional system prompt", }, }, Required: []string{"question"}, }, }, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { question, err := request.RequireString("question") if err != nil { return nil, err } systemPrompt := request.GetString("system_prompt", "You are a helpful assistant.") // Create sampling request samplingRequest := mcp.CreateMessageRequest{ CreateMessageParams: mcp.CreateMessageParams{ Messages: []mcp.SamplingMessage{ { Role: mcp.RoleUser, Content: mcp.TextContent{ Type: "text", Text: question, }, }, }, SystemPrompt: systemPrompt, MaxTokens: 1000, Temperature: 0.7, }, } // Request sampling with timeout samplingCtx, cancel := context.WithTimeout(ctx, 30*time.Second) defer cancel() result, err := mcpServer.RequestSampling(samplingCtx, samplingRequest) if err != nil { return &mcp.CallToolResult{ Content: []mcp.Content{ mcp.TextContent{ Type: "text", Text: fmt.Sprintf("Error requesting sampling: %v", err), }, }, IsError: true, }, nil } // Return the LLM response return &mcp.CallToolResult{ Content: []mcp.Content{ mcp.TextContent{ Type: "text", Text: fmt.Sprintf("LLM Response (model: %s): %s", result.Model, getTextFromContent(result.Content))", }, }, }, nil }) // Start server log.Println("Starting sampling example server...") if err := server.ServeStdio(mcpServer); err != nil { log.Fatalf("Server error: %v", err) } } // Helper function to extract text from content func getTextFromContent(content interface{}) string { switch c := content.(type) { case mcp.TextContent: return c.Text case string: return c default: return fmt.Sprintf("%v", content) } } ``` -------------------------------- ### Basic SSE Server Setup in Go Source: https://github.com/mark3labs/mcp-go/blob/main/www/docs/pages/transports/sse.mdx Initializes an MCP-Go server with real-time capabilities and adds tools and resources. Starts an SSE server to handle client connections. ```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, 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.WithNumber("count", mcp.DefaultNumber(10)), ), handleStreamData, ) s.AddTool( mcp.NewTool("monitor_system", mcp.WithDescription("Monitor system metrics in real-time"), mcp.WithNumber("duration", mcp.DefaultNumber(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") sseServer := server.NewSSEServer(s) if err := sseServer.Start(":8080"); err != nil { log.Fatal(err) } } ``` -------------------------------- ### Create and Run MCP Server with a Tool Source: https://github.com/mark3labs/mcp-go/blob/main/README.md This example demonstrates how to create a new MCP server, define a tool with string arguments, add a handler for that tool, and start the server using stdio transport. Ensure the 'name' argument is provided in the tool call. ```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 } ``` -------------------------------- ### Basic StreamableHTTP Server Setup Source: https://github.com/mark3labs/mcp-go/blob/main/www/docs/pages/transports/http.mdx Sets up a new MCP server with tool and resource capabilities, adds RESTful tools, and starts a StreamableHTTP server. Requires importing necessary packages and defining handler functions. ```go package main import ( "context" "fmt" "log" "net/http" "strings" "time" "github.com/mark3labs/mcp-go/mcp" "github.com/mark3labs/mcp-go/server" ) func main() { s := server.NewMCPServer("StreamableHTTP API Server", "1.0.0", server.WithToolCapabilities(true), server.WithResourceCapabilities(true, true), ) // Add RESTful tools s.AddTool( mcp.NewTool("get_user", mcp.WithDescription("Get user information"), mcp.WithString("user_id", mcp.Required()), ), handleGetUser, ) s.AddTool( mcp.NewTool("create_user", mcp.WithDescription("Create a new user"), mcp.WithString("name", mcp.Required()), mcp.WithString("email", mcp.Required()), mcp.WithNumber("age", mcp.Min(0)), ), handleCreateUser, ) s.AddTool( mcp.NewTool("search_users", mcp.WithDescription("Search users with filters"), mcp.WithString("query", mcp.Description("Search query")), mcp.WithNumber("limit", mcp.DefaultNumber(10), mcp.Max(100)), mcp.WithNumber("offset", mcp.DefaultNumber(0), mcp.Min(0)), ), handleSearchUsers, ) // Add resources s.AddResource( mcp.NewResource( "users://{user_id}", "User Profile", mcp.WithResourceDescription("User profile data"), mcp.WithMIMEType("application/json"), ), handleUserResource, ) // Start StreamableHTTP server log.Println("Starting StreamableHTTP server on :8080") httpServer := server.NewStreamableHTTPServer(s) if err := httpServer.Start(":8080"); err != nil { log.Fatal(err) } } ``` -------------------------------- ### MCP-Go File Operations Tool Example Source: https://github.com/mark3labs/mcp-go/blob/main/www/docs/pages/servers/tools.mdx Defines and handles a 'create_file' tool. This example shows how to configure tool parameters with descriptions, defaults, and enums, and implement a handler that validates input, handles different encodings, and writes to a file. ```go func main() { s := server.NewMCPServer("File Tools", "1.0.0", server.WithToolCapabilities(true), ) // File creation tool createFileTool := mcp.NewTool("create_file", mcp.WithDescription("Create a new file with content"), mcp.WithString("path", mcp.Required(), mcp.Description("File path to create"), ), mcp.WithString("content", mcp.Required(), mcp.Description("File content"), ), mcp.WithString("encoding", mcp.DefaultString("utf-8"), mcp.Enum("utf-8", "ascii", "base64"), mcp.Description("File encoding"), ), ) s.AddTool(createFileTool, handleCreateFile) server.ServeStdio(s) } func handleCreateFile(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { path, err := req.RequireString("path") if err != nil { return mcp.NewToolResultError(err.Error()), nil } content, err := req.RequireString("content") if err != nil { return mcp.NewToolResultError(err.Error()), nil } encoding := req.GetString("encoding", "utf-8") // Validate path for security if strings.Contains(path, "..") { return mcp.NewToolResultError("invalid path: directory traversal not allowed"), nil } // Handle different encodings var data []byte switch encoding { case "utf-8": data = []byte(content) case "ascii": data = []byte(content) case "base64": var err error data, err = base64.StdEncoding.DecodeString(content) if err != nil { return mcp.NewToolResultError(fmt.Sprintf("invalid base64 content: %v", err)), nil } } // Create file if err := os.WriteFile(path, data, 0644); err != nil { return mcp.NewToolResultError(fmt.Sprintf("failed to create file: %v", err)), nil } return mcp.NewToolResultText(fmt.Sprintf("File created successfully: %s", path)), nil } ``` -------------------------------- ### Implement a Task-Enabled MCP Server Source: https://github.com/mark3labs/mcp-go/blob/main/www/docs/pages/servers/tasks.mdx A complete example demonstrating server initialization with task capabilities, observability hooks, and both required and optional task tools. ```go package main import ( "context" "fmt" "log" "time" "github.com/mark3labs/mcp-go/mcp" "github.com/mark3labs/mcp-go/server" ) func main() { // Set up observability hooks taskHooks := &server.TaskHooks{} taskHooks.AddOnTaskCreated(func(ctx context.Context, metrics server.TaskMetrics) { log.Printf("Task %s created for tool %s", metrics.TaskID, metrics.ToolName) }) taskHooks.AddOnTaskCompleted(func(ctx context.Context, metrics server.TaskMetrics) { log.Printf("Task %s completed in %v", metrics.TaskID, metrics.Duration) }) taskHooks.AddOnTaskFailed(func(ctx context.Context, metrics server.TaskMetrics) { log.Printf("Task %s failed: %v", metrics.TaskID, metrics.Error) }) // Create server s := server.NewMCPServer("Task Example", "1.0.0", server.WithToolCapabilities(true), server.WithTaskCapabilities(true, true, true), server.WithTaskHooks(taskHooks), server.WithMaxConcurrentTasks(10), ) // Task-required tool: must be invoked as a task batchTool := mcp.NewTool("process_batch", mcp.WithDescription("Process a batch of items asynchronously"), mcp.WithTaskSupport(mcp.TaskSupportRequired), mcp.WithArray("items", mcp.Description("Items to process"), mcp.Required(), ), ) s.AddTaskTool(batchTool, handleBatch) // Task-optional tool: can run sync or async analyzeTool := mcp.NewTool("analyze", mcp.WithDescription("Analyze data — runs async if invoked as a task"), mcp.WithTaskSupport(mcp.TaskSupportOptional), mcp.WithString("data", mcp.Required(), mcp.Description("Data to analyze")), ) s.AddTaskTool(analyzeTool, handleAnalyze) // Start server if err := server.ServeStdio(s); err != nil { log.Fatalf("Server error: %v", err) } } func handleBatch(ctx context.Context, req mcp.CallToolRequest) (*mcp.CreateTaskResult, error) { // Process items — check for cancellation for i := 0; i < 10; i++ { select { case <-ctx.Done(): return nil, ctx.Err() default: time.Sleep(1 * time.Second) } } return &mcp.CreateTaskResult{ Task: mcp.NewTask("batch-task", mcp.WithTaskStatusMessage("Batch processing complete"), ), }, nil } func handleAnalyze(ctx context.Context, req mcp.CallToolRequest) (*mcp.CreateTaskResult, error) { data := req.GetString("data", "") // Simulate analysis time.Sleep(2 * time.Second) return &mcp.CreateTaskResult{ Task: mcp.NewTask("analyze-task", mcp.WithTaskStatusMessage(fmt.Sprintf("Analyzed %d characters", len(data))), ), Result: mcp.Result{ Meta: mcp.WithModelImmediateResponse("Analysis is in progress. Results will be available shortly."), }, }, nil } ``` -------------------------------- ### Install MCP-Go Source: https://github.com/mark3labs/mcp-go/blob/main/www/docs/pages/getting-started.mdx Add MCP-Go to your Go project using the go get command. ```bash go get github.com/mark3labs/mcp-go ``` -------------------------------- ### Create a basic MCP server Source: https://github.com/mark3labs/mcp-go/blob/main/www/docs/pages/servers/basics.mdx Initializes a new server instance and starts it using the 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) } ``` -------------------------------- ### Start the HTTP Sampling Client for Testing Source: https://github.com/mark3labs/mcp-go/blob/main/examples/sampling_http_server/README.md Run this command in a separate terminal to start the client for testing the server. ```bash go run examples/sampling_http_client/main.go ``` -------------------------------- ### Configure MCP Client with Sampling Handler Source: https://github.com/mark3labs/mcp-go/blob/main/www/docs/pages/clients/advanced-sampling.mdx Enable sampling support in your MCP client by providing an instance of your `SamplingHandler` when creating the client. This example shows setting up the client with a stdio transport and starting its connection. ```go func main() { // Create sampling handler samplingHandler := &MySamplingHandler{} // Create stdio transport stdioTransport := transport.NewStdio("/path/to/mcp/server", nil) // Create client with sampling support mcpClient := client.NewClient(stdioTransport, client.WithSamplingHandler(samplingHandler)) // Start the client ctx := context.Background() if err := mcpClient.Start(ctx); err != nil { log.Fatalf("Failed to start client: %v", err) } defer mcpClient.Close() if err := mcpClient.Connect(ctx); err != nil { log.Fatalf("Failed to connect: %v", err) } // The client will now automatically handle sampling requests // from the server using your handler } ``` -------------------------------- ### Implement PromptCompletionProvider Source: https://github.com/mark3labs/mcp-go/blob/main/www/docs/pages/servers/completions.mdx Example implementation of the PromptCompletionProvider interface. ```go type MyPromptCompletionProvider struct { prompts map[string][]string // prompt name -> known argument values } func (p *MyPromptCompletionProvider) CompletePromptArgument( ctx context.Context, promptName string, argument mcp.CompleteArgument, compCtx mcp.CompleteContext, ) (*mcp.Completion, error) { // Return completions based on the prompt name and argument switch promptName { case "code_review": if argument.Name == "language" { languages := []string{"go", "python", "javascript", "rust", "java"} // Filter by what the user has typed so far var matches []string for _, lang := range languages { if strings.HasPrefix(lang, strings.ToLower(argument.Value)) { matches = append(matches, lang) } } return &mcp.Completion{ Values: matches, HasMore: false, }, nil } } return &mcp.Completion{Values: []string{}}, nil } ``` -------------------------------- ### Run InProcess Sampling Example Source: https://github.com/mark3labs/mcp-go/blob/main/examples/inprocess_sampling/README.md Execute the main Go program to run the in-process sampling example. ```bash go run main.go ``` -------------------------------- ### Run mcp-go Example Source: https://github.com/mark3labs/mcp-go/blob/main/otel/example/README.md Execute the example to observe OpenTelemetry tracing. Spans are printed to stderr via an inline SpanProcessor. ```bash go run ./otel/example ``` -------------------------------- ### StreamableHTTP Server Setup Source: https://github.com/mark3labs/mcp-go/blob/main/www/docs/pages/transports/http.mdx This snippet shows how to initialize and configure the StreamableHTTP server, add tools with their handlers, and add resources. ```APIDOC ## StreamableHTTP Server Setup ### Description This example demonstrates setting up a basic StreamableHTTP server. It includes adding RESTful tools like `get_user`, `create_user`, and `search_users`, each with its own handler function and parameter definitions. It also shows how to add a resource, `users://{user_id}`, with its corresponding handler. ### Tools Added: - **get_user**: Retrieves user information. Requires `user_id` (string). - **create_user**: Creates a new user. Requires `name` (string) and `email` (string). Optionally accepts `age` (number, min 0). - **search_users**: Searches users with filters. Accepts `query` (string), `limit` (number, default 10, max 100), and `offset` (number, default 0, min 0). ### Resources Added: - **users://{user_id}**: Represents a user profile. Accepts `application/json` MIME type. ### Server Start: The server is configured to start on port 8080. ``` -------------------------------- ### Serve Static File-Based Resource Source: https://github.com/mark3labs/mcp-go/blob/main/www/docs/pages/servers/resources.mdx This example demonstrates setting up an MCP server and adding a static file resource. It includes a handler function to read the file content and return it. ```go func main() { s := server.NewMCPServer("File Server", "1.0.0", server.WithResourceCapabilities(true), ) // Add a static file resource s.AddResource( mcp.NewResource( "file://README.md", "Project README", mcp.WithResourceDescription("Main project documentation"), mcp.WithMIMEType("text/markdown"), ), handleReadmeFile, ) server.ServeStdio(s) } func handleReadmeFile(ctx context.Context, req mcp.ReadResourceRequest) (*mcp.ReadResourceResult, error) { content, err := os.ReadFile("README.md") if err != nil { return nil, fmt.Errorf("failed to read README: %w", err) } return &mcp.ReadResourceResult{ Contents: []mcp.ResourceContent{ { URI: req.Params.URI, MIMEType: "text/markdown", Text: string(content), }, }, }, nil } ``` -------------------------------- ### Implement ResourceCompletionProvider Source: https://github.com/mark3labs/mcp-go/blob/main/www/docs/pages/servers/completions.mdx Example implementation of the ResourceCompletionProvider interface. ```go type MyResourceCompletionProvider struct{} func (p *MyResourceCompletionProvider) CompleteResourceArgument( ctx context.Context, uri string, argument mcp.CompleteArgument, compCtx mcp.CompleteContext, ) (*mcp.Completion, error) { // Provide completions for resource URI template parameters if strings.HasPrefix(uri, "db://") && argument.Name == "table" { tables := []string{"users", "orders", "products", "inventory"} var matches []string for _, t := range tables { if strings.HasPrefix(t, argument.Value) { matches = append(matches, t) } } return &mcp.Completion{ Values: matches, HasMore: false, }, nil } return &mcp.Completion{Values: []string{}}, nil } ``` -------------------------------- ### Demonstrate Resource Filtering Source: https://github.com/mark3labs/mcp-go/blob/main/www/docs/pages/clients/operations.mdx Provides usage examples for filtering resources by MIME type and URI pattern. Logs the number of found resources for each filter. ```go // Usage examples func demonstrateResourceFiltering(ctx context.Context, c client.Client) { // Find all JSON resources jsonResources, err := listResourcesByType(ctx, c, "application/json") if err != nil { log.Printf("Error listing JSON resources: %v", err) } else { fmt.Printf("Found %d JSON resources\n", len(jsonResources)) } // Find all user-related resources userResources, err := listResourcesByPattern(ctx, c, `users?://.*`) if err != nil { log.Printf("Error listing user resources: %v", err) } else { fmt.Printf("Found %d user resources\n", len(userResources)) } } ``` -------------------------------- ### OpenAI Integration Setup Source: https://github.com/mark3labs/mcp-go/blob/main/www/docs/pages/transports/inprocess.mdx Initialize an OpenAI sampling handler by providing your API key. This handler will be used to create an MCP client with real LLM capabilities. ```go import ( "github.com/sashabaranov/go-openai" ) type OpenAISamplingHandler struct { client *openai.Client } func NewOpenAISamplingHandler(apiKey string) *OpenAISamplingHandler { return &OpenAISamplingHandler{ client: openai.NewClient(apiKey), } } func (h *OpenAISamplingHandler) CreateMessage(ctx context.Context, request mcp.CreateMessageRequest) (*mcp.CreateMessageResult, error) { // Convert MCP messages to OpenAI format var messages []openai.ChatCompletionMessage // Add system message if provided if request.SystemPrompt != "" { messages = append(messages, openai.ChatCompletionMessage{ Role: openai.ChatMessageRoleSystem, Content: request.SystemPrompt, }) } // Convert MCP messages for _, msg := range request.Messages { var role string switch msg.Role { case mcp.RoleUser: role = openai.ChatMessageRoleUser case mcp.RoleAssistant: role = openai.ChatMessageRoleAssistant } if textContent, ok := msg.Content.(mcp.TextContent); ok { messages = append(messages, openai.ChatCompletionMessage{ Role: role, Content: textContent.Text, }) } } // Create OpenAI request req := openai.ChatCompletionRequest{ Model: openai.GPT3Dot5Turbo, Messages: messages, MaxTokens: request.MaxTokens, Temperature: float32(request.Temperature), } // Call OpenAI API resp, err := h.client.CreateChatCompletion(ctx, req) if err != nil { return nil, fmt.Errorf("OpenAI API call failed: %w", err) } if len(resp.Choices) == 0 { return nil, fmt.Errorf("no response from OpenAI") } choice := resp.Choices[0] // Convert stop reason var stopReason string switch choice.FinishReason { case "stop": stopReason = "endTurn" case "length": stopReason = "maxTokens" default: stopReason = "other" } return &mcp.CreateMessageResult{ SamplingMessage: mcp.SamplingMessage{ Role: mcp.RoleAssistant, Content: mcp.TextContent{ Type: "text", Text: choice.Message.Content, }, }, Model: resp.Model, StopReason: stopReason, }, nil } ``` -------------------------------- ### Server with Tool Capabilities Source: https://github.com/mark3labs/mcp-go/blob/main/www/docs/pages/servers/advanced.mdx Initialize an MCP server with tool capabilities enabled. This server setup includes adding a 'calculate' tool with specific input parameters and a handler function. ```go package main import ( "context" "fmt" "github.com/mark3labs/mcp-go/mcp" "github.com/mark3labs/mcp-go/server" ) func main() { s := server.NewMCPServer("Typed Server", "1.0.0", server.WithToolCapabilities(true), ) 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, ) server.ServeStdio(s) } func handleCalculate(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { session := server.ClientSessionFromContext(ctx) if session == nil { return nil, fmt.Errorf("no active session") } if clientSession, ok := session.(server.SessionWithClientInfo); ok { clientCapabilities := clientSession.GetClientCapabilities() if clientCapabilities.Sampling == nil { fmt.Println("sampling is not enabled in client") } } // TODO: implement calculation logic return mcp.NewToolResultError("not implemented"), nil } ``` -------------------------------- ### Create a complete MCP server Source: https://github.com/mark3labs/mcp-go/blob/main/www/docs/pages/servers/index.mdx Demonstrates the initialization of an MCP server with tools, resources, and prompts using the MCP-Go library. ```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.GetPromptResult{ Description: "Analyze server logs for potential issues", Messages: []mcp.PromptMessage{ { Role: mcp.RoleUser, Content: mcp.NewTextContent(fmt.Sprintf( "Please analyze the server logs for entries at %s level or higher. "+ "Look for patterns, errors, and potential issues that need attention.", logLevel, )), }, }, }, nil } ``` -------------------------------- ### Initialize and Run the Go Project Source: https://github.com/mark3labs/mcp-go/blob/main/www/docs/pages/quick-start.mdx Commands to initialize the Go module, fetch dependencies, and execute the server. ```bash cd hello-server go mod init hello-server go get github.com/mark3labs/mcp-go go run main.go ``` -------------------------------- ### Create a Basic MCP Server with a Tool Source: https://github.com/mark3labs/mcp-go/blob/main/www/docs/pages/getting-started.mdx This Go code demonstrates how to create a new MCP server, define a 'hello_world' tool, add a handler for it, and start the server using 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 MCP Inspector Source: https://github.com/mark3labs/mcp-go/blob/main/www/docs/pages/transports/stdio.mdx Command to install the MCP Inspector tool for visual debugging. ```bash # Install MCP Inspector npm install -g @modelcontextprotocol/inspector ``` -------------------------------- ### Require and Get Parameters Source: https://github.com/mark3labs/mcp-go/blob/main/www/docs/pages/servers/tools.mdx Use Require methods to get mandatory parameters, which return an error if missing or of the wrong type. Use Get methods for optional parameters, providing default values if they are not present. ```go // Required parameters (return error if missing or wrong type) name, err := req.RequireString("name") age, err := req.RequireInt("age") price, err := req.RequireFloat("price") enabled, err := req.RequireBool("enabled") ``` ```go // Optional parameters with defaults name := req.GetString("name", "default") count := req.GetInt("count", 10) price := req.GetFloat("price", 0.0) enabled := req.GetBool("enabled", false) ``` -------------------------------- ### Basic Prompt Usage in Go Source: https://github.com/mark3labs/mcp-go/blob/main/www/docs/pages/clients/operations.mdx Demonstrates how to list available prompts and use a specific prompt with arguments. Ensure the client is initialized before use. ```go func getPrompt(ctx context.Context, c client.Client, name string, args map[string]interface{}) (*mcp.GetPromptResult, error) { result, err := c.GetPrompt(ctx, mcp.GetPromptRequest{ Params: mcp.GetPromptRequestParams{ Name: name, Arguments: args, }, }) if err != nil { return nil, fmt.Errorf("failed to get prompt: %w", err) } return result, nil } func demonstratePromptUsage(ctx context.Context, c client.Client) { // List available prompts prompts, err := c.ListPrompts(ctx, mcp.ListPromptsRequest{}) if err != nil { log.Printf("Failed to list prompts: %v", err) return } fmt.Printf("Available prompts: %d\n", len(prompts.Prompts)) for _, prompt := range prompts.Prompts { fmt.Printf("- %s: %s\n", prompt.Name, prompt.Description) if len(prompt.Arguments) > 0 { fmt.Printf(" Arguments:\n") for _, arg := range prompt.Arguments { fmt.Printf(" - %s: %s\n", arg.Name, arg.Description) } } } // Use a specific prompt if len(prompts.Prompts) > 0 { prompt := prompts.Prompts[0] fmt.Printf("\nUsing prompt: %s\n", prompt.Name) result, err := getPrompt(ctx, c, prompt.Name, map[string]interface{}{ // Add appropriate arguments based on prompt schema }) if err != nil { log.Printf("Failed to get prompt: %v", err) return } fmt.Printf("Prompt result:\n") fmt.Printf("Description: %s\n", result.Description) fmt.Printf("Messages: %d\n", len(result.Messages)) for i, message := range result.Messages { fmt.Printf("Message %d (%s): %s\n", i+1, message.Role, message.Content.Text) } } } ``` -------------------------------- ### Standard MCP Request Example Source: https://github.com/mark3labs/mcp-go/blob/main/www/docs/pages/transports/http.mdx This is an example of a standard MCP request payload for calling a tool. ```json POST /mcp/tools/call Content-Type: application/json { "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": "search_users", "arguments": { "query": "john", "limit": 10, "offset": 0 } } } ``` -------------------------------- ### MCP Error Response Example Source: https://github.com/mark3labs/mcp-go/blob/main/www/docs/pages/transports/http.mdx This is an example of an MCP error response, indicating an issue with the request parameters. ```json { "jsonrpc": "2.0", "id": 1, "error": { "code": -32602, "message": "Invalid params", "data": { "details": "user_id is required" } } } ``` -------------------------------- ### Create and Use an MCP Client Source: https://github.com/mark3labs/mcp-go/blob/main/www/docs/pages/clients/index.mdx Demonstrates creating an STDIO MCP client, initializing the connection, and performing basic operations like listing tools and resources, calling a tool, and reading a resource. ```go package main import ( "context" "fmt" "log" "github.com/mark3labs/mcp-go/client" "github.com/mark3labs/mcp-go/mcp" ) func main() { // Create STDIO client c, err := client.NewStdioMCPClient( "go", []string{} , "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, initRequest); err != nil { log.Fatal(err) } // Discover available capabilities if err := demonstrateClientOperations(ctx, c); err != nil { log.Fatal(err) } } func demonstrateClientOperations(ctx context.Context, c client.Client) error { // List available tools tools, err := c.ListTools(ctx, mcp.ListToolsRequest{}) if err != nil { return fmt.Errorf("failed to list tools: %w", err) } fmt.Printf("Available tools: %d\n", len(tools.Tools)) for _, tool := range tools.Tools { fmt.Printf("- %s: %s\n", tool.Name, tool.Description) } // List available resources resources, err := c.ListResources(ctx, mcp.ListResourcesRequest{}) if err != nil { return fmt.Errorf("failed to list resources: %w", err) } fmt.Printf("\nAvailable resources: %d\n", len(resources.Resources)) for _, resource := range resources.Resources { fmt.Printf("- %s: %s\n", resource.URI, resource.Name) } // Call a tool if available if len(tools.Tools) > 0 { tool := tools.Tools[0] fmt.Printf("\nCalling tool: %s\n", tool.Name) result, err := c.CallTool(ctx, mcp.CallToolRequest{ Params: mcp.CallToolRequestParams{ Name: tool.Name, Arguments: map[string]interface{}{ "input": "example input", "format": "text", }, }, }) if err != nil { return fmt.Errorf("tool call failed: %w", err) } fmt.Printf("Tool result: %+v\n", result) } // Read a resource if available if len(resources.Resources) > 0 { resource := resources.Resources[0] fmt.Printf("\nReading resource: %s\n", resource.URI) content, err := c.ReadResource(ctx, mcp.ReadResourceRequest{ Params: mcp.ReadResourceRequestParams{ URI: resource.URI, }, }) if err != nil { return fmt.Errorf("resource read failed: %w", err) } fmt.Printf("Resource content: %+v\n", content) } return nil } ``` -------------------------------- ### Basic In-Process MCP Server with Calculator Tool Source: https://github.com/mark3labs/mcp-go/blob/main/www/docs/pages/transports/inprocess.mdx This Go code demonstrates setting up an MCP server that runs in-process, adding a 'calculate' tool, and then using an in-process client to interact with it. It includes initialization, tool calls, and result handling. ```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 mcpClient, err := client.NewInProcessClient(s) if err != nil { log.Fatal(err) } defer mcpClient.Close() ctx := context.Background() // Initialize _, err = mcpClient.Initialize(ctx, mcp.InitializeRequest{ Params: mcp.InitializeRequestParams{ ProtocolVersion: "2024-11-05", Capabilities: mcp.ClientCapabilities{ Tools: &mcp.ToolsCapability{}, }, ClientInfo: mcp.Implementation{ Name: "test-client", Version: "1.0.0", }, }, }) if err != nil { log.Fatal(err) } // Use the calculator result, err := mcpClient.CallTool(ctx, mcp.CallToolRequest{ Params: mcp.CallToolParams{ Name: "calculate", Arguments: map[string]interface{}{ "operation": "add", "x": 10.0, "y": 5.0, }, }, }) if err != nil { log.Fatal(err) } // Extract text from the first content item if len(result.Content) > 0 { if textContent, ok := mcp.AsTextContent(result.Content[0]); ok { fmt.Printf("Result: %s\n", textContent.Text) } } } func handleCalculate(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { operation := req.GetString("operation", "") x := req.GetFloat("x", 0) y := req.GetFloat("y", 0) 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 } ``` -------------------------------- ### Standard MCP Response Example Source: https://github.com/mark3labs/mcp-go/blob/main/www/docs/pages/transports/http.mdx This is an example of a standard MCP response payload, typically containing results from a tool call. ```json { "jsonrpc": "2.0", "id": 1, "result": { "content": [ { "type": "text", "text": "{\"users\":[...],\"total\":25,\"limit\":10,\"offset\":0}" } ] } } ``` -------------------------------- ### Initialize Server with Experimental Capabilities Source: https://github.com/mark3labs/mcp-go/blob/main/www/docs/pages/servers/basics.mdx Use `server.WithExperimental` to set non-standard, experimental capabilities for the server. These are included in the server's capabilities during initialization. ```go s := server.NewMCPServer("My Server", "1.0.0", // Set experimental capabilities server.WithExperimental(map[string]any{ "claude/channel": map[string]any{ "supported": true, }, }), ) ``` -------------------------------- ### Build a Custom MCP Client in Go Source: https://github.com/mark3labs/mcp-go/blob/main/www/docs/pages/transports/stdio.mdx Demonstrates initializing a connection to an MCP server, listing available tools, and executing a tool call. ```go package main import ( "context" "log" "time" "github.com/mark3labs/mcp-go/client" "github.com/mark3labs/mcp-go/mcp" ) func main() { // Create STDIO client c, err := client.NewStdioClient( "go", nil /* inherit env */, "run", "/path/to/server/main.go", ) if err != nil { log.Fatal(err) } defer c.Close() ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() // Initialize connection _, err = c.Initialize(ctx, mcp.InitializeRequest{ Params: mcp.InitializeRequestParams{ ProtocolVersion: mcp.LATEST_PROTOCOL_VERSION, ClientInfo: mcp.Implementation{ Name: "test-client", Version: "1.0.0", }, }, }) if err != nil { log.Fatal(err) } // List available tools tools, err := c.ListTools(ctx, mcp.ListToolsRequest{}) if err != nil { log.Fatal(err) } log.Printf("Available tools: %d", len(tools.Tools)) for _, tool := range tools.Tools { log.Printf("- %s: %s", tool.Name, tool.Description) } // Call a tool result, err := c.CallTool(ctx, mcp.CallToolRequest{ Params: mcp.CallToolParams{ Name: "list_files", Arguments: map[string]interface{}{ "path": ".", "recursive": false, }, }, }) if err != nil { log.Fatal(err) } log.Printf("Tool result: %+v", result) } ``` -------------------------------- ### Start MCP Server with StreamableHTTP Transport Source: https://github.com/mark3labs/mcp-go/blob/main/www/docs/pages/getting-started.mdx This Go code snippet shows how to start an MCP server using the StreamableHTTP transport on a specified port. ```go server.NewStreamableHTTPServer(s).Start(":8080") ```