Skip to content

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

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.