Skip to content

Server Basics

Learn how to create, configure, and start MCP servers with different transport options.

Creating a Server

The foundation of any MCP server is the NewMCPServer() function. This creates a server instance with basic metadata and optional configuration.

Basic Server Creation

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)
}

Server with Options

Use server options to configure capabilities and behavior:

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
)

Server Configuration

Capabilities

Capabilities tell clients what features your server supports:

// Enable specific capabilities
s := server.NewMCPServer(
    "Specialized Server",
    "1.0.0",
    server.WithToolCapabilities(true),      // Can execute tools
    server.WithResourceCapabilities(true),  // Can provide resources
    server.WithPromptCapabilities(true),    // Can provide prompts
)
 
// Or enable all capabilities
s := server.NewMCPServer(
    "Full-Featured Server", 
    "1.0.0",
    server.WithToolCapabilities(true),
    server.WithResourceCapabilities(true),
    server.WithPromptCapabilities(true),
)
Capability types:
  • Tools: Server can execute function calls from LLMs
  • Resources: Server can provide data/content to LLMs
  • Prompts: Server can provide prompt templates

Recovery Middleware

Add automatic panic recovery to prevent server crashes:

s := server.NewMCPServer(
    "Robust Server",
    "1.0.0", 
    server.WithRecovery(), // Automatically recover from panics
)

This catches panics in handlers and returns proper error responses instead of crashing.

Custom Metadata

Add additional server information:

s := server.NewMCPServer(
    "My Server",
    "1.0.0",
    server.WithInstructions("A server that does amazing things"),
)

Starting Servers

MCP-Go supports multiple transport methods for different deployment scenarios.

Stdio Transport

Standard input/output - most common for local tools:

func main() {
    s := server.NewMCPServer("My Server", "1.0.0")
    
    // Start stdio server (blocks until terminated)
    if err := server.ServeStdio(s); err != nil {
        log.Fatal(err)
    }
}
Best for:
  • Local development tools
  • CLI integrations
  • Desktop applications
  • Single-client scenarios

HTTP Transport

Traditional HTTP request/response:

func main() {
    s := server.NewMCPServer("HTTP Server", "1.0.0")
    
    // Create HTTP server
    httpServer := server.NewStreamableHTTPServer(s)
    
    // Start HTTP server on port 8080
    if err := httpServer.Start(":8080"); err != nil {
        log.Fatal(err)
    }
}
Best for:
  • Web services
  • Load-balanced deployments
  • REST-like APIs
  • Caching scenarios

Server-Sent Events (SSE)

HTTP-based streaming for real-time updates:

func main() {
    s := server.NewMCPServer("SSE Server", "1.0.0")
    
    // Create SSE server
    sseServer := server.NewSSEServer(s)
    
    // Start SSE server on port 8080
    if err := sseServer.Start(":8080"); err != nil {
        log.Fatal(err)
    }
}
Best for:
  • Web applications
  • Real-time notifications
  • Multiple concurrent clients
  • Browser-based tools

Custom Transport Options

Configure transport-specific options:

// HTTP with custom options
httpServer := server.NewStreamableHTTPServer(s,
    server.WithEndpointPath("/mcp"),
    server.WithStateless(true),
)
 
if err := httpServer.Start(":8080"); err != nil {
    log.Fatal(err)
}
 
// SSE with custom options
sseServer := server.NewSSEServer(s,
    server.WithSSEEndpoint("/events"),
    server.WithMessageEndpoint("/message"),
    server.WithKeepAlive(true),
)
 
if err := sseServer.Start(":8080"); err != nil {
    log.Fatal(err)
}

Environment-Based Configuration

Configure servers based on environment variables:

func main() {
    s := server.NewMCPServer("Configurable Server", "1.0.0")
    
    // Choose transport based on environment
    transport := os.Getenv("MCP_TRANSPORT")
    port := os.Getenv("PORT")
    if port == "" {
        port = "8080"
    }
    
    switch transport {
    case "http":
        httpServer := server.NewStreamableHTTPServer(s)
        httpServer.Start(":"+port)
    case "sse":
        sseServer := server.NewSSEServer(s)
        sseServer.Start(":"+port)
    default:
        server.ServeStdio(s)
    }
}
}

Server Lifecycle

Understanding the server lifecycle helps with proper resource management:

func main() {
    hooks := &server.Hooks{}
    
    // Add session lifecycle hooks
    hooks.AddOnRegisterSession(func(ctx context.Context, session server.ClientSession) {
        log.Printf("Client %s connected", session.ID())
    })
    
    hooks.AddOnUnregisterSession(func(ctx context.Context, session server.ClientSession) {
        log.Printf("Client %s disconnected", session.ID())
    })
    
    // Add request hooks
    hooks.AddBeforeAny(func(ctx context.Context, id any, method mcp.MCPMethod, message any) {
        log.Printf("Processing %s request", method)
    })
    
    hooks.AddOnError(func(ctx context.Context, id any, method mcp.MCPMethod, message any, err error) {
        log.Printf("Error in %s: %v", method, err)
    })
    
    s := server.NewMCPServer("Lifecycle Server", "1.0.0",
        server.WithHooks(hooks),
    )
    
    // Graceful shutdown
    c := make(chan os.Signal, 1)
    signal.Notify(c, os.Interrupt, syscall.SIGTERM)
    
    go func() {
        <-c
        log.Println("Shutting down server...")
        s.Shutdown()
    }()
    
    server.ServeStdio(s)
}

Error Handling

Proper error handling ensures robust server operation:

func main() {
    s := server.NewMCPServer("Error-Safe Server", "1.0.0",
        server.WithRecovery(), // Panic recovery
    )
    
    // Add error handling for server startup
    if err := server.ServeStdio(s); err != nil {
        if errors.Is(err, server.ErrServerClosed) {
            log.Println("Server closed gracefully")
        } else {
            log.Fatalf("Server error: %v", err)
        }
    }
}

Next Steps

Now that you understand server basics, learn how to add functionality: