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),
)
- 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)
}
}
- 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)
}
}
- 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)
}
}
- 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:
- Resources - Expose data to LLMs
- Tools - Provide functionality to LLMs
- Prompts - Create reusable interaction templates
- Advanced Features - Hooks, middleware, and more