Track MCP LogoTrack MCP
Track MCP LogoTrack MCP

The world's largest repository of Model Context Protocol servers. Discover, explore, and submit MCP tools.

Product

  • Categories
  • Top MCP
  • New & Updated
  • Submit MCP

Company

  • About

Legal

  • Privacy Policy
  • Terms of Service
  • Cookie Policy

© 2026 TrackMCP. All rights reserved.

Built with ❤️ by Krishna Goyal

    Gomcp

    gomcp provides a Go implementation of the Model Context Protocol (MCP), enabling communication between language models/agents and external tools or resources via a standardized protocol.

    46 stars
    Go
    Updated Sep 18, 2025

    Table of Contents

    • MCP Specification Compliance
    • Table of Contents
    • Overview
    • Key Features
    • API Stability
    • 🔒 API Lock Guarantee (v1.5.0+)
    • ✅ Full Protocol Compliance
    • ✅ Production Ready
    • 🚀 Future Development
    • Installation
    • Quickstart
    • Client Example
    • Client with Automatic Server Management
    • Server Example
    • Advanced Server Example
    • Core Concepts
    • Clients and Servers
    • Tools
    • Resources
    • Prompts
    • Batch Operations
    • Event System
    • Available Event Types
    • Server-Side Event Usage
    • Client-Side Event Usage
    • Event System Integration Patterns
    • Event Structure Reference
    • Transports
    • Server Management
    • Proper Cleanup Patterns
    • ✅ Correct Pattern: Use registry.StopAll()
    • ❌ Incorrect Pattern: Manual client.Close() before registry.StopAll()
    • Best Practices
    • Session Management
    • Server-Side Session Access
    • Transport-Aware Session Data
    • Automated Workspace Root Discovery
    • MCP Protocol Compliance
    • ClientInfo Structure
    • Session Convenience Methods
    • Benefits
    • Examples
    • Documentation
    • Contributing
    • License

    Table of Contents

    • MCP Specification Compliance
    • Table of Contents
    • Overview
    • Key Features
    • API Stability
    • 🔒 API Lock Guarantee (v1.5.0+)
    • ✅ Full Protocol Compliance
    • ✅ Production Ready
    • 🚀 Future Development
    • Installation
    • Quickstart
    • Client Example
    • Client with Automatic Server Management
    • Server Example
    • Advanced Server Example
    • Core Concepts
    • Clients and Servers
    • Tools
    • Resources
    • Prompts
    • Batch Operations
    • Event System
    • Available Event Types
    • Server-Side Event Usage
    • Client-Side Event Usage
    • Event System Integration Patterns
    • Event Structure Reference
    • Transports
    • Server Management
    • Proper Cleanup Patterns
    • ✅ Correct Pattern: Use registry.StopAll()
    • ❌ Incorrect Pattern: Manual client.Close() before registry.StopAll()
    • Best Practices
    • Session Management
    • Server-Side Session Access
    • Transport-Aware Session Data
    • Automated Workspace Root Discovery
    • MCP Protocol Compliance
    • ClientInfo Structure
    • Session Convenience Methods
    • Benefits
    • Examples
    • Documentation
    • Contributing
    • License

    Documentation

    GoMCP - Go Model Context Protocol Library

    Go Reference

    Go Report Card

    MCP Specification Compliance

    Draft Spec: 100%

    2024-11-05 Spec: 100%

    2025-03-26 Spec: 100%

    ✅ Full compliance across all MCP specification versions - See COMPLIANCE.md for detailed verification.

    GoMCP is a complete Go implementation of the Model Context Protocol (MCP), designed to facilitate seamless interaction between applications and Large Language Models (LLMs). The library supports all specification versions with automatic negotiation and provides a clean, idiomatic API for both clients and servers.

    Table of Contents

    • Overview
    • Key Features
    • API Stability
    • Installation
    • Quickstart
    • Client Example
    • Client with Automatic Server Management
    • Server Example
    • Advanced Server Example
    • Core Concepts
    • Clients and Servers
    • Tools
    • Resources
    • Prompts
    • Batch Operations
    • Event System
    • Transports
    • Server Management
    • Session Management
    • Examples
    • Documentation
    • Contributing
    • License

    Overview

    The Model Context Protocol (MCP) standardizes communication between applications and LLMs, enabling:

    • Tool Calling: Execute actions and functions through LLMs
    • Resource Access: Provide structured data to LLMs with workspace context
    • Prompt Rendering: Create reusable templates for LLM interactions
    • Sampling: Generate text from LLMs with control over parameters
    • Session Management: Rich context and workspace root access for enhanced tool capabilities

    GoMCP provides an idiomatic Go implementation that handles all the protocol details while offering a clean, developer-friendly API.

    Key Features

    • Complete Protocol Implementation: Full support for all MCP specification versions
    • Automatic Version Negotiation: Seamless compatibility between clients and servers
    • Multiple Transport Options: Support for stdio, HTTP, WebSocket, and Server-Sent Events
    • Type-Safe API: Leverages Go's type system for safety and expressiveness
    • Server Process Management: Automatically start, manage, and stop external MCP servers
    • Server Configuration: Load server definitions from configuration files
    • MCP Session Architecture: Comprehensive session management with transport-aware data extraction
    • Automated Root Fetching: Automatic workspace root discovery following MCP protocol
    • Flexible Architecture: Modular design for easy extension and customization

    API Stability

    GoMCP v1.5.0 represents a stable, production-ready release with locked APIs. The library has reached full maturity with a comprehensive feature set and battle-tested implementations.

    🔒 API Lock Guarantee (v1.5.0+)

    • Client API: All client methods (CallTool, GetResource, GetPrompt, etc.) are locked and stable
    • Server API: Server registration methods (Tool, Resource, Prompt) and handler patterns are finalized
    • Transport Layer: All transport implementations follow stable, locked interfaces
    • Event System: Event types and subscription patterns are standardized and locked
    • Server Management: Process lifecycle and configuration management APIs are stable

    ✅ Full Protocol Compliance

    • Complete MCP Specification Support: Full implementation of all protocol versions (2024-11-05, 2025-03-26, draft)
    • Automatic Version Negotiation: Seamless compatibility handling between different specification versions
    • Transport Compliance: All transport layers properly implement their respective MCP specifications
    • Type Safety: Strong typing throughout ensures API contracts are maintained

    ✅ Production Ready

    • Comprehensive Testing: Extensive test coverage across all major components
    • Error Handling: Robust error handling with proper MCP error codes and messages
    • Performance: Optimized for production workloads with efficient resource management
    • Complete Documentation: Full API documentation and usage examples

    🚀 Future Development

    With v1.5.0's API lock, future releases will focus on:

    • Additive Features: New functionality that extends but doesn't break existing APIs
    • Performance Optimizations: Internal improvements that maintain API compatibility
    • Enhanced Documentation: Expanded examples and integration guides
    • New Transport Options: Additional transport implementations using the stable transport interface

    Commitment: The v1.5.0 APIs are locked in and will not change. Any future enhancements will be additive and maintain full backward compatibility. GoMCP is ready for enterprise production deployments.

    Installation

    bash
    go get github.com/localrivet/gomcp

    Quickstart

    Client Example

    go
    package main
    
    import (
    	"log"
    	"github.com/localrivet/gomcp/client"
    )
    
    func main() {
    	// Create a new client with stdio transport
    	c, err := client.NewClient("stdio:///",
    		client.WithStdio(),
    		client.WithProtocolVersion("2025-03-26"),
    		client.WithProtocolNegotiation(true),
    	)
    	if err != nil {
    		log.Fatalf("Failed to create client: %v", err)
    	}
    	defer c.Close()
    
    	// Call a tool on the MCP server
    	result, err := c.CallTool("say_hello", map[string]interface{}{
    		"name": "World",
    	})
    	if err != nil {
    		log.Fatalf("Tool call failed: %v", err)
    	}
    
    	log.Printf("Result: %v", result)
    }

    Note: This example uses stdio transport, which means the client expects to communicate with an MCP server via stdin/stdout. For a complete working example that automatically manages the server process, see the "Client with Automatic Server Management" section below.

    Client with Automatic Server Management

    What this does: This example demonstrates GoMCP's powerful automatic server management feature. Instead of manually starting and stopping MCP server processes, the client can automatically:

    • Launch server processes on demand using system commands
    • Establish connections to those servers via stdio/pipes
    • Environment variable injection for configuration (API keys, etc.)
    • Automatic cleanup - server processes are terminated when the client closes
    • Process lifecycle management - handles server startup, health checks, and shutdown

    Why this matters: This pattern eliminates the operational complexity of managing MCP servers. You can distribute a single binary that automatically spins up the required MCP servers, making deployment and integration much simpler. It's especially useful for:

    • Development environments - automatically start dependent services
    • CI/CD pipelines - spin up servers for testing without manual setup
    • Desktop applications - embed MCP servers without requiring separate installation
    • Microservice architectures - manage server dependencies declaratively
    go
    package main
    
    import (
    	"log"
    	"github.com/localrivet/gomcp/client"
    )
    
    func main() {
    	// Define server configuration
    	config := client.ServerConfig{
    		MCPServers: map[string]client.ServerDefinition{
    			"govibe": {
    				Command: "govibe",
    				Args: []string{},
    				Env: map[string]string{
    					"ANTHROPIC_API_KEY": "${ANTHROPIC_API_KEY}",
    				},
    			},
    		},
    	}
    
    	// Create a client with automatic server management
    	c, err := client.NewClient("my-client",
    		client.WithServers(config, "govibe"),
    	)
    	if err != nil {
    		log.Fatalf("Failed to create client: %v", err)
    	}
    	defer c.Close() // Automatically stops the server process
    
    	// Call a tool on the managed server
    	result, err := c.CallTool("add_task", map[string]interface{}{
    		"prompt": "Create a login page with authentication",
    	})
    	if err != nil {
    		log.Fatalf("Tool call failed: %v", err)
    	}
    
    	log.Printf("Task created: %v", result)
    
    	// Add project roots for the server to access
    	err = c.AddRoot("/path/to/project", "project-root")
    	if err != nil {
    		log.Fatalf("Failed to add root: %v", err)
    	}
    
    	// Get a resource that might use the project context
    	resource, err := c.GetResource("/project/files/src/main.go")
    	if err != nil {
    		log.Fatalf("Resource request failed: %v", err)
    	}
    
    	log.Printf("Resource content: %v", resource)
    }

    Key Implementation Details:

    • The ${ANTHROPIC_API_KEY} syntax automatically injects environment variables from the current process
    • Server processes communicate via stdio pipes for secure, high-performance IPC
    • The client waits for server initialization before accepting requests
    • Graceful shutdown ensures servers are properly terminated, preventing orphaned processes
    • Multiple servers can be managed simultaneously with different configurations

    Server Example

    go
    package main
    
    import (
    	"fmt"
    	"log/slog"
    	"os"
    	"github.com/localrivet/gomcp/server"
    )
    
    func main() {
    	// Create a logger
    	logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
    		Level: slog.LevelInfo,
    	}))
    
    	// Create a new server
    	srv := server.NewServer("example-server",
    		server.WithLogger(logger),
    	).AsStdio()
    
    	// Register a tool with inline struct
    	srv.Tool("say_hello", "Greet someone", func(ctx *server.Context, args struct {
    		Name string `json:"name"`
    	}) (interface{}, error) {
    		return map[string]interface{}{
    			"message": fmt.Sprintf("Hello, %s!", args.Name),
    		}, nil
    	})
    
    	// Start the server
    	if err := srv.Run(); err != nil {
    		log.Fatalf("Failed to run server: %v", err)
    	}
    }

    Advanced Server Example

    go
    package main
    
    import (
    	"fmt"
    	"log/slog"
    	"os"
    	"path/filepath"
    	"strings"
    	"github.com/localrivet/gomcp/server"
    	"github.com/localrivet/gomcp/transport/sse"
    )
    
    func main() {
    	// Create a logger
    	logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
    		Level: slog.LevelInfo,
    	}))
    
    	// Create a new server with comprehensive functionality
    	srv := server.NewServer("advanced-server",
    		server.WithLogger(logger),
    	).AsStdio()
    
    	// Register multiple tools with different parameter types
    	srv.Tool("calculator", "Perform mathematical calculations", func(ctx *server.Context, args struct {
    		Operation string  `json:"operation"`
    		A         float64 `json:"a"`
    		B         float64 `json:"b"`
    	}) (interface{}, error) {
    		switch args.Operation {
    		case "add":
    			return map[string]interface{}{"result": args.A + args.B}, nil
    		case "multiply":
    			return map[string]interface{}{"result": args.A * args.B}, nil
    		case "divide":
    			if args.B == 0 {
    				return nil, fmt.Errorf("division by zero")
    			}
    			return map[string]interface{}{"result": args.A / args.B}, nil
    		default:
    			return nil, fmt.Errorf("unsupported operation: %s", args.Operation)
    		}
    	})
    
    	srv.Tool("create_file", "Create a file with content", func(ctx *server.Context, args struct {
    		Path    string `json:"path"`
    		Content string `json:"content"`
    	}) (interface{}, error) {
    		// In a real implementation, you'd validate paths and permissions
    		return map[string]interface{}{
    			"message": fmt.Sprintf("File created at %s with %d bytes", args.Path, len(args.Content)),
    			"path":    args.Path,
    			"size":    len(args.Content),
    		}, nil
    	})
    
    	// Register resources with different patterns
    	srv.Resource("/config", "Get server configuration", func(ctx *server.Context, args *struct{}) (interface{}, error) {
    		return map[string]interface{}{
    			"version":     "1.0.0",
    			"environment": "development",
    			"features":    []string{"tools", "resources", "prompts"},
    		}, nil
    	})
    
    	// Templated resource for file access
    	srv.Resource("/files/{path*}", "Access file system resources", func(ctx *server.Context, args *struct {
    		Path string `path:"path"`
    	}) (interface{}, error) {
    		// Extract file extension for content type detection
    		ext := strings.ToLower(filepath.Ext(args.Path))
    		
    		return map[string]interface{}{
    			"path":      args.Path,
    			"extension": ext,
    			"type":      getFileType(ext),
    			"content":   fmt.Sprintf("Mock content for file: %s", args.Path),
    		}, nil
    	})
    
    	// User profile resource with parameters
    	srv.Resource("/users/{id}", "Get user profile information", func(ctx *server.Context, args *struct {
    		ID       string `path:"id"`
    		IncludePosts bool `json:"include_posts"`
    	}) (interface{}, error) {
    		user := map[string]interface{}{
    			"id":       args.ID,
    			"name":     fmt.Sprintf("User %s", args.ID),
    			"email":    fmt.Sprintf("user%s@example.com", args.ID),
    			"active":   true,
    		}
    		
    		if args.IncludePosts {
    			user["posts"] = []map[string]interface{}{
    				{"id": 1, "title": "Hello World", "content": "First post"},
    				{"id": 2, "title": "Second Post", "content": "Another post"},
    			}
    		}
    		
    		return user, nil
    	})
    
    	// Register prompts for different use cases
    	srv.Prompt("code_review", "Provide code review assistance",
    		server.User("Please review this {{language}} code for best practices, potential bugs, and improvements:\n\n```{{language}}\n{{code}}\n```"),
    		server.Assistant("I'll analyze your {{language}} code and provide detailed feedback on best practices, potential issues, and suggested improvements."),
    	)
    
    	srv.Prompt("email_template", "Generate professional email content",
    		server.Assistant("I'll help you create a professional email."),
    		server.User("Write a {{tone}} email to {{recipient}} about {{subject}}. Include these key points: {{key_points}}"),
    	)
    
    	srv.Prompt("documentation", "Generate technical documentation",
    		server.User("Create documentation for this {{type}} with the following details:\n\nName: {{name}}\nPurpose: {{purpose}}\nParameters: {{parameters}}\nExample: {{example}}"),
    		server.Assistant("I'll create comprehensive technical documentation following best practices for clarity and completeness."),
    	)
    
    	// Start the server
    	if err := srv.Run(); err != nil {
    		logger.Error("Failed to run server", "error", err)
    		os.Exit(1)
    	}
    }
    
    // Helper function to determine file type from extension
    func getFileType(ext string) string {
    	switch ext {
    	case ".go":
    		return "go_source"
    	case ".js", ".ts":
    		return "javascript"
    	case ".py":
    		return "python"
    	case ".md":
    		return "markdown"
    	case ".json":
    		return "json"
    	case ".yaml", ".yml":
    		return "yaml"
    	default:
    		return "text"
    	}
    }

    Core Concepts

    Clients and Servers

    • **client.Client**: Interface for communicating with MCP servers. Handles protocol negotiation, request/response management, and server lifecycle.
    • **server.Server**: Core component for implementing MCP servers. Provides registration methods for tools, resources, and prompts with automatic schema generation.

    Tools

    Tools expose functions that LLMs can call to perform actions. GoMCP supports:

    • Type-safe parameters using inline struct definitions
    • Automatic schema generation from Go struct tags
    • Error handling with proper MCP error responses
    • Cancellation support for long-running operations

    Server Side (Implementation):

    go
    // Simple tool with inline struct
    srv.Tool("say_hello", "Greet someone", func(ctx *server.Context, args struct {
        Name string `json:"name"`
    }) (interface{}, error) {
        return map[string]interface{}{
            "message": fmt.Sprintf("Hello, %s!", args.Name),
        }, nil
    })
    
    // Tool with complex parameters
    srv.Tool("calculate", "Perform calculations", func(ctx *server.Context, args struct {
        Operation string  `json:"operation"`
        A         float64 `json:"a"`
        B         float64 `json:"b"`
    }) (interface{}, error) {
        switch args.Operation {
        case "add":
            return map[string]interface{}{"result": args.A + args.B}, nil
        case "multiply":
            return map[string]interface{}{"result": args.A * args.B}, nil
        default:
            return nil, fmt.Errorf("unsupported operation: %s", args.Operation)
        }
    })

    Client Side (Usage):

    go
    // Call a simple tool
    result, err := client.CallTool("say_hello", map[string]interface{}{
        "name": "Alice",
    })
    if err != nil {
        log.Fatalf("Tool call failed: %v", err)
    }
    fmt.Printf("Result: %v\n", result)
    
    // Call a tool with complex parameters
    calcResult, err := client.CallTool("calculate", map[string]interface{}{
        "operation": "add",
        "a": 10.5,
        "b": 20.3,
    })
    if err != nil {
        log.Fatalf("Calculation failed: %v", err)
    }
    fmt.Printf("Calculation result: %v\n", calcResult)

    Resources

    Resources provide structured data to LLMs in various formats:

    • Static resources with fixed URIs (e.g., /config, /status)
    • Templated resources with path parameters (e.g., /files/{path*}, /users/{id})
    • Dynamic resources that can accept additional parameters from request bodies
    • Multiple content types including text, images, links, and binary data

    Server Side (Implementation):

    go
    // Static resource
    srv.Resource("/config", "Get configuration", func(ctx *server.Context, args *struct{}) (interface{}, error) {
        return map[string]interface{}{
            "version": "1.0.0",
            "environment": "production",
        }, nil
    })
    
    // Templated resource with path parameters
    srv.Resource("/files/{path*}", "Access files", func(ctx *server.Context, args *struct {
        Path string `path:"path"`
    }) (interface{}, error) {
        return map[string]interface{}{
            "path": args.Path,
            "content": fmt.Sprintf("Content of %s", args.Path),
        }, nil
    })
    
    // Resource with additional parameters
    srv.Resource("/users/{id}", "Get user info", func(ctx *server.Context, args *struct {
        ID          string `path:"id"`
        IncludePosts bool   `json:"include_posts"`
    }) (interface{}, error) {
        user := map[string]interface{}{
            "id": args.ID,
            "name": fmt.Sprintf("User %s", args.ID),
        }
        if args.IncludePosts {
            user["posts"] = []string{"Post 1", "Post 2"}
        }
        return user, nil
    })

    Client Side (Usage):

    go
    // Get a static resource
    config, err := client.GetResource("/config")
    if err != nil {
        log.Fatalf("Failed to get config: %v", err)
    }
    fmt.Printf("Config: %v\n", config)
    
    // Get a templated resource
    fileContent, err := client.GetResource("/files/src/main.go")
    if err != nil {
        log.Fatalf("Failed to get file: %v", err)
    }
    fmt.Printf("File content: %v\n", fileContent)
    
    // Get a resource with additional parameters
    user, err := client.GetResource("/users/123", client.WithResourceParams(map[string]interface{}{
        "include_posts": true,
    }))
    if err != nil {
        log.Fatalf("Failed to get user: %v", err)
    }
    fmt.Printf("User: %v\n", user)

    Prompts

    Prompts define reusable message templates for LLM interactions:

    • Template variables using {{variable}} syntax
    • Multiple message types (User, Assistant, System)
    • Role-based conversations for complex interaction patterns
    • Argument validation for template parameters

    Server Side (Implementation):

    go
    // Simple prompt template
    srv.Prompt("email_template", "Generate emails",
        server.User("Write a {{tone}} email to {{recipient}} about {{subject}}"),
    )
    
    // Multi-message conversation prompt
    srv.Prompt("code_review", "Code review assistant",
        server.Assistant("I'll help you review code for best practices and bugs."),
        server.User("Please review this {{language}} code:\n\n```{{language}}\n{{code}}\n```"),
    )
    
    // Complex prompt with multiple variables
    srv.Prompt("documentation", "Generate docs",
        server.User("Create {{type}} documentation for:\nName: {{name}}\nPurpose: {{purpose}}\nExample: {{example}}"),
        server.Assistant("I'll create comprehensive {{type}} documentation."),
    )

    Client Side (Usage):

    go
    // Get a simple prompt
    emailPrompt, err := client.GetPrompt("email_template", map[string]interface{}{
        "tone": "professional",
        "recipient": "team",
        "subject": "project update",
    })
    if err != nil {
        log.Fatalf("Failed to get prompt: %v", err)
    }
    fmt.Printf("Email prompt: %v\n", emailPrompt)
    
    // Get a complex prompt with multiple variables
    docPrompt, err := client.GetPrompt("documentation", map[string]interface{}{
        "type": "API",
        "name": "UserService",
        "purpose": "Manage user accounts",
        "example": "userService.CreateUser()",
    })
    if err != nil {
        log.Fatalf("Failed to get doc prompt: %v", err)
    }
    fmt.Printf("Documentation prompt: %v\n", docPrompt)

    Batch Operations

    GoMCP supports JSON-RPC batch operations for improved performance:

    • Reduced network round-trips by sending multiple requests at once
    • Maintained request ordering in responses
    • Mixed request types (tools, resources, prompts) in a single batch
    • Partial failure handling with individual response errors
    • Fluent builder interface for easy batch construction

    Client Side (Usage):

    go
    // Create a batch request
    batch := client.NewBatch().
        CallTool("say_hello", map[string]interface{}{"name": "Alice"}).
        GetResource("/config").
        GetPrompt("email_template", map[string]interface{}{
            "tone": "professional",
            "recipient": "team",
            "subject": "project update",
        })
    
    // Execute the batch
    results, err := c.ExecuteBatch(batch)
    if err != nil {
        log.Fatalf("Batch execution failed: %v", err)
    }
    
    // Process results
    for i, result := range results {
        if result.Error != nil {
            log.Printf("Request %d failed: %v", i, result.Error)
        } else {
            log.Printf("Request %d result: %v", i, result.Result)
        }
    }

    Event System

    GoMCP provides a comprehensive event system that allows you to monitor and react to various activities within your MCP server or client. The event system uses a type-safe, channel-based architecture for maximum performance and reliability.

    Key Benefits:

    • Real-time monitoring of server operations and client interactions
    • Type-safe event handling with strongly-typed event structs
    • Channel-based architecture for high-performance, non-blocking event processing
    • Comprehensive coverage of all server lifecycle and operation events
    • Easy integration with logging, metrics, and monitoring systems

    Available Event Types

    GoMCP emits events for all major operations and lifecycle changes:

    Server Lifecycle Events:

    • server.initialized - Server has started and is ready to accept requests
    • server.shutdown - Server is shutting down

    Client Connection Events:

    • client.connected - A client connected to the server
    • client.disconnected - A client disconnected from the server
    • client.initializing - Client is starting to connect (client-side)
    • client.initialized - Client successfully connected (client-side)
    • client.error - Client operation failed (client-side)

    Registration Events:

    • tool.registered - A tool was registered with the server
    • resource.registered - A resource was registered with the server

    Operation Events:

    • tool.executed - A tool was executed (successful operation)
    • resource.accessed - A resource was accessed
    • prompt.executed - A prompt was executed
    • request.failed - Any MCP request failed

    Server-Side Event Usage

    Setting Up Event Subscriptions:

    go
    package main
    
    import (
        "context"
        "log/slog"
        "os"
        "github.com/localrivet/gomcp/events"
        "github.com/localrivet/gomcp/server"
    )
    
    func main() {
        // Create server
        srv := server.NewServer("my-server")
        logger := slog.New(slog.NewTextHandler(os.Stdout, nil))
    
        // Subscribe to server lifecycle events
        events.Subscribe[events.ServerInitializedEvent](srv.Events(), events.TopicServerInitialized,
            func(ctx context.Context, evt events.ServerInitializedEvent) error {
                logger.Info("🚀 Server initialized",
                    "name", evt.ServerName,
                    "version", evt.ProtocolVersion,
                    "tools", evt.ToolCount,
                    "resources", evt.ResourceCount)
                return nil
            })
    
        events.Subscribe[events.ServerShutdownEvent](srv.Events(), events.TopicServerShutdown,
            func(ctx context.Context, evt events.ServerShutdownEvent) error {
                logger.Info("🛑 Server shutting down",
                    "name", evt.ServerName,
                    "graceful", evt.GracefulExit,
                    "reason", evt.Reason)
                return nil
            })
    
        // Subscribe to client connection events
        events.Subscribe[events.ClientConnectedEvent](srv.Events(), events.TopicClientConnected,
            func(ctx context.Context, evt events.ClientConnectedEvent) error {
                logger.Info("🔌 Client connected",
                    "sessionId", evt.SessionID,
                    "clientName", evt.ClientInfo.Name,
                    "clientVersion", evt.ClientInfo.Version,
                    "protocolVersion", evt.ProtocolVersion)
                return nil
            })
    
        events.Subscribe[events.ClientDisconnectedEvent](srv.Events(), events.TopicClientDisconnected,
            func(ctx context.Context, evt events.ClientDisconnectedEvent) error {
                logger.Info("🔌 Client disconnected",
                    "sessionId", evt.SessionID,
                    "duration", time.Since(evt.ConnectedAt))
                return nil
            })
    
        // Subscribe to tool events
        events.Subscribe[events.ToolRegisteredEvent](srv.Events(), events.TopicToolRegistered,
            func(ctx context.Context, evt events.ToolRegisteredEvent) error {
                logger.Info("🔧 Tool registered",
                    "name", evt.ToolName,
                    "description", evt.Description)
                return nil
            })
    
        events.Subscribe[events.ToolExecutedEvent](srv.Events(), events.TopicToolExecuted,
            func(ctx context.Context, evt events.ToolExecutedEvent) error {
                logger.Info("⚡ Tool executed",
                    "method", evt.Method,
                    "success", len(evt.ResponseJSON) > 0)
                return nil
            })
    
        // Subscribe to resource events
        events.Subscribe[events.ResourceRegisteredEvent](srv.Events(), events.TopicResourceRegistered,
            func(ctx context.Context, evt events.ResourceRegisteredEvent) error {
                logger.Info("📄 Resource registered",
                    "uri", evt.URI,
                    "name", evt.Name,
                    "mimeType", evt.MimeType)
                return nil
            })
    
        events.Subscribe[events.ResourceAccessedEvent](srv.Events(), events.TopicResourceAccessed,
            func(ctx context.Context, evt events.ResourceAccessedEvent) error {
                logger.Info("📖 Resource accessed",
                    "uri", evt.URI,
                    "success", evt.Success,
                    "responseSize", evt.ResponseSize)
                return nil
            })
    
        // Subscribe to error events  
        events.Subscribe[events.RequestFailedEvent](srv.Events(), events.TopicRequestFailed,
            func(ctx context.Context, evt events.RequestFailedEvent) error {
                logger.Error("❌ Request failed",
                    "method", evt.Method,
                    "error", evt.Error)
                return nil
            })
    
        // Register tools and resources
        srv.Tool("greet", "Say hello", func(ctx *server.Context, args struct {
            Name string `json:"name"`
        }) (interface{}, error) {
            return fmt.Sprintf("Hello, %s!", args.Name), nil
        })
    
        srv.Resource("/status", "Server status", func(ctx *server.Context, args *struct{}) (interface{}, error) {
            return map[string]interface{}{
                "status": "healthy",
                "uptime": time.Since(startTime),
            }, nil
        })
    
        // Start server
        srv.AsStdio().Run()
    }

    Client-Side Event Usage

    Monitoring Client Operations:

    go
    package main
    
    import (
        "context"
        "log/slog" 
        "github.com/localrivet/gomcp/client"
        "github.com/localrivet/gomcp/events"
    )
    
    func main() {
        // Create client
        c, err := client.NewClient("my-client")
        if err != nil {
            log.Fatalf("Failed to create client: %v", err)
        }
        defer c.Close()
    
        logger := slog.Default()
    
        // Subscribe to client lifecycle events
        events.Subscribe[events.ClientInitializingEvent](c.Events(), events.TopicClientInitializing,
            func(ctx context.Context, evt events.ClientInitializingEvent) error {
                logger.Info("🔄 Client connecting", "url", evt.URL)
                return nil
            })
    
        events.Subscribe[events.ClientInitializedEvent](c.Events(), events.TopicClientInitialized,
            func(ctx context.Context, evt events.ClientInitializedEvent) error {
                logger.Info("✅ Client connected", "url", evt.URL)
                return nil
            })
    
        events.Subscribe[events.ClientErrorEvent](c.Events(), events.TopicClientError,
            func(ctx context.Context, evt events.ClientErrorEvent) error {
                logger.Error("❌ Client error", "error", evt.Error)
                return nil
            })
    
        events.Subscribe[events.ClientDisconnectedEvent](c.Events(), events.TopicClientDisconnected,
            func(ctx context.Context, evt events.ClientDisconnectedEvent) error {
                logger.Info("🔌 Client disconnected", "url", evt.URL)
                return nil
            })
    
        // Subscribe to operation events
        events.Subscribe[events.ToolExecutedEvent](c.Events(), events.TopicToolExecuted,
            func(ctx context.Context, evt events.ToolExecutedEvent) error {
                logger.Info("⚡ Tool called", "method", evt.Method)
                return nil
            })
    
        events.Subscribe[events.RequestFailedEvent](c.Events(), events.TopicRequestFailed,
            func(ctx context.Context, evt events.RequestFailedEvent) error {
                logger.Error("❌ Request failed", "method", evt.Method, "error", evt.Error)
                return nil
            })
    
        // Connect to server and perform operations
        err = c.ConnectStdio("./my-mcp-server")
        if err != nil {
            log.Fatalf("Failed to connect: %v", err)
        }
    
        // Tool calls and other operations will now emit events
        result, err := c.CallTool("greet", map[string]interface{}{"name": "World"})
        if err != nil {
            log.Fatalf("Tool call failed: %v", err)
        }
        
        fmt.Printf("Result: %v\n", result)
    }

    Event System Integration Patterns

    Metrics Collection:

    go
    type MetricsCollector struct {
        toolCallCount     int64
        errorCount        int64
        connectedClients  int64
    }
    
    func (m *MetricsCollector) SetupEventSubscriptions(srv server.Server) {
        // Track tool executions
        events.Subscribe[events.ToolExecutedEvent](srv.Events(), events.TopicToolExecuted,
            func(ctx context.Context, evt events.ToolExecutedEvent) error {
                atomic.AddInt64(&m.toolCallCount, 1)
                return nil
            })
    
        // Track errors
        events.Subscribe[events.RequestFailedEvent](srv.Events(), events.TopicRequestFailed,
            func(ctx context.Context, evt events.RequestFailedEvent) error {
                atomic.AddInt64(&m.errorCount, 1)
                return nil
            })
    
        // Track connections
        events.Subscribe[events.ClientConnectedEvent](srv.Events(), events.TopicClientConnected,
            func(ctx context.Context, evt events.ClientConnectedEvent) error {
                atomic.AddInt64(&m.connectedClients, 1)
                return nil
            })
    
        events.Subscribe[events.ClientDisconnectedEvent](srv.Events(), events.TopicClientDisconnected,
            func(ctx context.Context, evt events.ClientDisconnectedEvent) error {
                atomic.AddInt64(&m.connectedClients, -1)
                return nil
            })
    }

    Audit Logging:

    go
    type AuditLogger struct {
        logger *slog.Logger
    }
    
    func (a *AuditLogger) SetupAuditSubscriptions(srv server.Server) {
        // Log all tool executions for security audit
        events.Subscribe[events.ToolExecutedEvent](srv.Events(), events.TopicToolExecuted,
            func(ctx context.Context, evt events.ToolExecutedEvent) error {
                a.logger.Info("AUDIT: Tool executed",
                    "method", evt.Method,
                    "requestJSON", evt.RequestJSON,
                    "responseJSON", evt.ResponseJSON,
                    "timestamp", time.Now())
                return nil
            })
    
        // Log all failed requests
        events.Subscribe[events.RequestFailedEvent](srv.Events(), events.TopicRequestFailed,
            func(ctx context.Context, evt events.RequestFailedEvent) error {
                a.logger.Warn("AUDIT: Request failed",
                    "method", evt.Method,
                    "error", evt.Error,
                    "requestJSON", evt.RequestJSON,
                    "timestamp", time.Now())
                return nil
            })
    }

    Health Monitoring:

    go
    type HealthMonitor struct {
        lastToolExecution time.Time
        errorRate         float64
        isHealthy         bool
    }
    
    func (h *HealthMonitor) SetupHealthSubscriptions(srv server.Server) {
        events.Subscribe[events.ToolExecutedEvent](srv.Events(), events.TopicToolExecuted,
            func(ctx context.Context, evt events.ToolExecutedEvent) error {
                h.lastToolExecution = time.Now()
                h.updateHealthStatus()
                return nil
            })
    
        events.Subscribe[events.RequestFailedEvent](srv.Events(), events.TopicRequestFailed,
            func(ctx context.Context, evt events.RequestFailedEvent) error {
                h.calculateErrorRate()
                h.updateHealthStatus()
                return nil
            })
    }
    
    func (h *HealthMonitor) updateHealthStatus() {
        h.isHealthy = time.Since(h.lastToolExecution)  0 {
            primaryRoot = roots[0]
        }
        
        // Access client capabilities
        caps := ctx.Session.Capabilities()
        
        return map[string]interface{}{
            "primary_workspace": primaryRoot,
            "all_roots": roots,
            "has_api_access": apiKey != "",
            "supports_sampling": caps.Sampling.Supported,
            "analysis_type": args.AnalysisType,
        }, nil
    })

    Transport-Aware Session Data

    GoMCP automatically extracts session data from the transport layer per MCP specification:

    • stdio: Environment from process environment variables
    • HTTP: Environment from request headers (X-Env-* pattern)
    • WebSocket: Environment from connection headers
    • SSE: Environment from initial request headers

    Automated Workspace Root Discovery

    The server automatically detects when clients support the roots capability and:

    1. Initial Extraction: Extracts workspace roots from clientInfo.roots during initialization

    2. Capability Detection: Detects if client advertises roots capability

    3. Automated Fetching: Sends roots/list requests after notifications/initialized

    4. Response Handling: Processes roots/list responses with proper request tracking

    5. Context Integration: Makes roots available via ctx.Session.Roots()

    MCP Protocol Compliance

    Full compliance across all three MCP protocol versions:

    • 2024-11-05: Basic root extraction and capability detection
    • 2025-03-26: Enhanced session management with audio support detection
    • draft: Latest features with full session architecture

    ClientInfo Structure

    Enhanced ClientInfo provides comprehensive session data:

    go
    type ClientInfo struct {
        Name              string                 `json:"name"`
        Version           string                 `json:"version"`
        SamplingSupported bool                   `json:"sampling_supported,omitempty"`
        SamplingCaps      *SamplingCapabilities  `json:"sampling_caps,omitempty"`
        ProtocolVersion   string                 `json:"protocol_version,omitempty"`
        Env               map[string]string      `json:"env,omitempty"`           // NEW: Environment data from transport
        Roots             []string               `json:"roots,omitempty"`         // NEW: Workspace roots from init + roots/list
    }

    Session Convenience Methods

    The ClientSession interface provides easy access to session data:

    go
    // In tool handlers
    func MyTool(ctx *server.Context, args MyArgs) (interface{}, error) {
        session := ctx.Session
        
        // Get environment variables (from transport)
        env := session.Env()
        dbUrl := env["DATABASE_URL"]
        
        // Get workspace roots (from init + automated roots/list)
        roots := session.Roots()
        
        // Get client capabilities  
        caps := session.Capabilities()
        supportsSampling := caps.Sampling.Supported
        supportsAudio := caps.Audio.Supported
        
        // Use session data in tool logic...
    }

    Benefits

    • Zero Configuration: Automatic session data extraction with no manual setup
    • MCP Compliant: Follows official MCP specification for session handling
    • Transport Agnostic: Works consistently across all transport types
    • Backward Compatible: No breaking changes to existing tool handlers

    Examples

    The examples/ directory contains complete examples demonstrating various features:

    • examples/minimal/: Basic client and server examples
    • examples/sampling/: Examples of text generation via the sampling API
    • examples/server_config/: Server management and configuration examples
    • examples/server/: Various server implementation patterns

    Documentation

    • GoDoc: API reference documentation
    • docs/: Additional documentation and guides
    • docs/examples/: Detailed feature guides
    • docs/getting-started/: Getting started guides
    • docs/api-reference/: Detailed API documentation

    Contributing

    Contributions are welcome! Please feel free to submit a Pull Request.

    License

    This project is licensed under the MIT License - see the LICENSE file for details.

    Similar MCP

    Based on tags & features

    • MC

      Mcp Cyclops

      Go·
      29
    • PO

      Portainer Mcp

      Go·
      72
    • MK

      Mkp

      Go·
      53
    • MC

      Mcpjungle

      Go·
      617

    Trending MCP

    Most active this week

    • PL

      Playwright Mcp

      TypeScript·
      22.1k
    • SE

      Serena

      Python·
      14.5k
    • MC

      Mcp Playwright

      TypeScript·
      4.9k
    • MC

      Mcp Server Cloudflare

      TypeScript·
      3.0k
    View All MCP Servers

    Similar MCP

    Based on tags & features

    • MC

      Mcp Cyclops

      Go·
      29
    • PO

      Portainer Mcp

      Go·
      72
    • MK

      Mkp

      Go·
      53
    • MC

      Mcpjungle

      Go·
      617

    Trending MCP

    Most active this week

    • PL

      Playwright Mcp

      TypeScript·
      22.1k
    • SE

      Serena

      Python·
      14.5k
    • MC

      Mcp Playwright

      TypeScript·
      4.9k
    • MC

      Mcp Server Cloudflare

      TypeScript·
      3.0k