Building MCP Servers
Learn how to build powerful MCP servers with MCP-Go. This section covers everything from basic server setup to advanced features like typed tools and session management.
Overview
MCP servers expose tools, resources, and prompts to LLM clients. MCP-Go makes it easy to build robust servers with minimal boilerplate while providing full control over advanced features.
What You'll Learn
- Server Basics - Creating and configuring servers
- Resources - Exposing data to LLMs
- Tools - Providing functionality to LLMs
- Prompts - Creating reusable interaction templates
- Advanced Features - Typed tools, middleware, hooks, and more
Quick Example
Here's a complete MCP server that demonstrates the key concepts:
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
}
Next Steps
Start with Server Basics to learn how to create and configure your first MCP server, then explore the other sections to add resources, tools, and advanced features.