hypermcp

package module
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 13, 2025 License: MIT Imports: 9 Imported by: 0

README

hypermcp - Reusable MCP Server Infrastructure

hypermcp is a reusable package that provides common infrastructure for building Model Context Protocol (MCP) servers. It handles all the boilerplate so you can focus on implementing your custom tools and resources.

Features

  • ✅ MCP server setup and lifecycle management
  • ✅ HTTP client with logging
  • ✅ Caching layer (with optional disable)
  • ✅ Transport abstraction (stdio, future: Streamable HTTP)
  • ✅ Structured logging with zap
  • ✅ Helper methods for registering tools and resources
  • ✅ Automatic stats tracking

Quick Start

1. Create a New MCP Server
package main

import (
    "context"
    "github.com/rayprogramming/hypermcp"
    "github.com/rayprogramming/hypermcp/cache"
    "go.uber.org/zap"
)

func main() {
    // Setup logger
    logger, _ := zap.NewProduction()
    defer logger.Sync()

    // Configure server
    cfg := hypermcp.Config{
        Name:         "my-mcp-server",
        Version:      "1.0.0",
        CacheEnabled: true,
        CacheConfig: cache.Config{
            MaxCost:     100 * 1024 * 1024, // 100MB
            NumCounters: 10_000,
            BufferItems: 64,
        },
    }

    // Create base server
    srv, err := hypermcp.New(cfg, logger)
    if err != nil {
        logger.Fatal("failed to create server", zap.Error(err))
    }

    // Register your tools and resources
    registerFeatures(srv)

    // Log registration stats
    srv.LogRegistrationStats()

    // Run with stdio transport
    ctx := context.Background()
    if err := hypermcp.RunWithTransport(ctx, srv, hypermcp.TransportStdio, logger); err != nil {
        logger.Fatal("server failed", zap.Error(err))
    }
}
2. Implement Your Providers

Create providers that use the shared infrastructure:

package providers

import (
    "context"
    "github.com/modelcontextprotocol/go-sdk/mcp"
    "github.com/rayprogramming/hypermcp"
    "github.com/rayprogramming/hypermcp/cache"
    "github.com/rayprogramming/hypermcp/httpx"
    "go.uber.org/zap"
)

type MyProvider struct {
    httpClient *httpx.Client
    cache      *cache.Cache
    logger     *zap.Logger
}

func NewMyProvider(srv *hypermcp.Server) *MyProvider {
    return &MyProvider{
        httpClient: srv.HTTPClient(),
        cache:      srv.Cache(),
        logger:     srv.Logger(),
    }
}

func (p *MyProvider) MyTool(
    ctx context.Context,
    req *mcp.CallToolRequest,
    input MyToolInput,
) (*mcp.CallToolResult, MyToolOutput, error) {
    // Your implementation here
    // Use p.httpClient, p.cache, p.logger as needed
}
3. Register Your Features
func registerFeatures(srv *hypermcp.Server) {
    // Create providers
    myProvider := providers.NewMyProvider(srv)

    // Register tools using the helper function
    hypermcp.AddTool(
        srv,
        &mcp.Tool{
            Name:        "my_tool",
            Description: "Does something cool",
        },
        myProvider.MyTool,
    )

    // Register resources using the helper method
    srv.AddResource(
        &mcp.Resource{
            URI:         "myresource://data",
            Name:        "My Resource",
            Description: "Provides some data",
            MIMEType:    "application/json",
        },
        func(ctx context.Context, req *mcp.ReadResourceRequest) (*mcp.ReadResourceResult, error) {
            // Your resource implementation
        },
    )
}

API Reference

Server Creation
func New(cfg Config, logger *zap.Logger) (*Server, error)

Creates a new MCP server with common infrastructure.

Configuration
type Config struct {
    Name         string        // Server name
    Version      string        // Server version
    CacheEnabled bool          // Enable caching
    CacheConfig  cache.Config  // Cache configuration
}
Server Methods
  • HTTPClient() *httpx.Client - Get the shared HTTP client
  • Cache() *cache.Cache - Get the cache instance
  • Logger() *zap.Logger - Get the logger
  • Metrics() *Metrics - Get metrics instance for tracking
  • GetMetrics() MetricsSnapshot - Get snapshot of current metrics
  • MCP() *mcp.Server - Get the underlying MCP server
  • AddResource(resource, handler) - Register a resource (auto-increments counter)
  • AddResourceTemplate(template, handler) - Register a resource template (auto-increments counter)
  • LogRegistrationStats() - Log tool/resource counts
  • Run(ctx, transport) - Start the server
  • Shutdown(ctx) - Gracefully shutdown (closes cache, logs final stats)
Package-Level Functions
  • AddTool[In, Out](srv, tool, handler) - Register a tool (auto-increments counter)
  • New(cfg, logger) - Create a new server instance
  • RunWithTransport(ctx, srv, transportType, logger) - Start server with specified transport
Transport
func RunWithTransport(ctx context.Context, srv *Server, transportType TransportType, logger *zap.Logger) error

Starts the server with the specified transport.

Available transports:

  • TransportStdio - Standard input/output (recommended for most use cases)
  • TransportStreamableHTTP - Streamable HTTP (for servers handling multiple client connections, not yet implemented)

Transport Types

hypermcp supports the MCP specification's recommended transports:

  • Default choice for most MCP servers
  • Client launches server as subprocess
  • Communication over stdin/stdout
  • Simpler setup and deployment
  • Clients SHOULD support stdio whenever possible (per MCP spec)
Streamable HTTP Transport
  • For servers handling multiple concurrent clients
  • HTTP-based with optional Server-Sent Events
  • Replaces the deprecated HTTP+SSE transport
  • More complex but supports advanced scenarios
  • Note: Not yet implemented in this package

Benefits

For You
  • 🚀 Fast Setup: Get a server running in minutes, not hours
  • 🔧 Focus on Features: Spend time on tools, not boilerplate
  • 📦 Batteries Included: HTTP client, caching, logging all configured
  • 🎯 Best Practices: Follows MCP patterns and Go idioms
For Your Users
  • Performance: Built-in caching and connection pooling
  • 📊 Observability: Structured logging with zap
  • 🛡️ Reliability: Proper error handling and graceful shutdown

Examples

The examples/ directory contains complete, working examples:

hello - Basic Server

Minimal example showing:

  • Server setup with configuration
  • Simple tool registration
  • Graceful shutdown handling
weather - Caching Demo

Demonstrates:

  • Enabling and using the cache
  • Cache hit/miss patterns
  • Multiple tools in one server
  • Metrics logging on shutdown
metrics - Metrics & Monitoring

Shows how to:

  • Track tool invocations
  • Monitor cache performance
  • Expose metrics via tools
  • Log periodic statistics
  • Access cache-specific metrics
fileserver - Resource Provider

Example of:

  • Resource registration
  • Resource templates with parameters
  • Working with files and data

Run any example:

cd examples/hello && go run main.go
cd examples/weather && go run main.go
cd examples/metrics && go run main.go

Performance Metrics

hypermcp includes built-in performance tracking:

// Track operations
srv.Metrics().IncrementToolInvocations()
srv.Metrics().IncrementCacheHits()
srv.Metrics().IncrementCacheMisses()
srv.Metrics().IncrementErrors()

// Get snapshot
metrics := srv.GetMetrics()
fmt.Printf("Uptime: %v\n", metrics.Uptime)
fmt.Printf("Cache hit rate: %.2f%%\n", metrics.CacheHitRate*100)

Metrics tracked:

  • Server uptime
  • Tool invocations
  • Resource reads
  • Cache hits/misses and hit rate
  • Error counts

Best Practices

Graceful Shutdown

Always implement graceful shutdown to ensure resources are properly cleaned up:

// Setup signal handling
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)

go func() {
    <-sigChan
    logger.Info("shutting down...")
    cancel()
}()

// Run server
if err := hypermcp.RunWithTransport(ctx, srv, hypermcp.TransportStdio, logger); err != nil {
    logger.Error("server error", zap.Error(err))
    os.Exit(1)
}

// Graceful shutdown with timeout
shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 5*time.Second)
defer shutdownCancel()

if err := srv.Shutdown(shutdownCtx); err != nil {
    logger.Error("shutdown error", zap.Error(err))
}
Cache Usage

Use caching for expensive operations:

cacheKey := fmt.Sprintf("data:%s", id)

// Check cache first
if cached, ok := srv.Cache().Get(cacheKey); ok {
    srv.Metrics().IncrementCacheHits()
    return cached
}
srv.Metrics().IncrementCacheMisses()

// Fetch data...
result := fetchExpensiveData(id)

// Cache for 5 minutes
srv.Cache().Set(cacheKey, result, 5*time.Minute)
HTTP Client Usage

The provided HTTP client includes retries and proper timeouts:

type Response struct {
    Status string `json:"status"`
}

var resp Response
if err := srv.HTTPClient().Get(ctx, apiURL, &resp); err != nil {
    srv.Metrics().IncrementErrors()
    return err
}

Examples

Dependencies

  • github.com/modelcontextprotocol/go-sdk - MCP SDK
  • go.uber.org/zap - Structured logging
  • github.com/dgraph-io/ristretto - Caching (via pkg/cache)

Documentation

Overview

Package hypermcp provides reusable MCP server infrastructure.

This package simplifies building Model Context Protocol (MCP) servers by providing common infrastructure components including HTTP client with retry logic, caching, structured logging, and transport abstraction.

Example usage:

cfg := hypermcp.Config{
    Name:         "my-server",
    Version:      "1.0.0",
    CacheEnabled: true,
}
srv, err := hypermcp.New(cfg, logger)
if err != nil {
    log.Fatal(err)
}
hypermcp.AddTool(srv, tool, handler)
srv.AddResource(resource, handler)
hypermcp.RunWithTransport(ctx, srv, hypermcp.TransportStdio, logger)

Package hypermcp provides reusable MCP server infrastructure

Package hypermcp provides reusable MCP server infrastructure

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrInvalidConfig indicates that the server configuration is invalid.
	ErrInvalidConfig = errors.New("invalid configuration")

	// ErrServerNotRunning indicates an operation was attempted on a non-running server.
	ErrServerNotRunning = errors.New("server not running")

	// ErrShutdownTimeout indicates the server shutdown exceeded the timeout.
	ErrShutdownTimeout = errors.New("shutdown timeout exceeded")

	// ErrTransportNotSupported indicates the requested transport type is not implemented.
	ErrTransportNotSupported = errors.New("transport not supported")
)

Common error variables for type checking.

Functions

func AddTool added in v0.2.0

func AddTool[In, Out any](s *Server, tool *mcp.Tool, handler mcp.ToolHandlerFor[In, Out])

AddTool registers a tool with the MCP server and automatically increments the tool counter.

This is a generic function that provides type-safe tool registration. The input and output types are inferred from the handler function signature. If the tool's input or output schema is nil, it will be automatically generated from the type parameters.

Example:

type Input struct {
    Message string `json:"message"`
}
type Output struct {
    Result string `json:"result"`
}
hypermcp.AddTool(srv, &mcp.Tool{Name: "echo"}, func(ctx context.Context, req *mcp.CallToolRequest, input Input) (*mcp.CallToolResult, Output, error) {
    return nil, Output{Result: input.Message}, nil
})

func RunWithTransport

func RunWithTransport(ctx context.Context, srv *Server, transportType TransportType, logger *zap.Logger) error

RunWithTransport starts the MCP server with the specified transport.

The function logs the selected transport and blocks until the context is canceled or an error occurs. Currently only stdio transport is implemented.

Types

type Config

type Config struct {
	HTTPConfig   *httpx.Config // Optional: uses defaults if nil
	CacheConfig  cache.Config
	Name         string
	Version      string
	CacheEnabled bool
}

Config holds server configuration.

Name and Version are required fields and will be validated. CacheEnabled determines whether to initialize a full cache instance. HTTPConfig allows customization of HTTP client behavior (optional, uses defaults if not set).

func (Config) Validate added in v0.2.0

func (c Config) Validate() error

Validate checks if the configuration is valid.

Returns an error if Name or Version is empty.

type ConfigError added in v1.0.0

type ConfigError struct {
	Err   error
	Field string
}

ConfigError wraps configuration validation errors with context.

func NewConfigError added in v1.0.0

func NewConfigError(field string, err error) *ConfigError

NewConfigError creates a new configuration error.

func (*ConfigError) Error added in v1.0.0

func (e *ConfigError) Error() string

func (*ConfigError) Unwrap added in v1.0.0

func (e *ConfigError) Unwrap() error

type Metrics added in v0.3.0

type Metrics struct {
	// contains filtered or unexported fields
}

Metrics tracks server performance and usage statistics.

All counters are thread-safe using atomic operations and can be safely incremented from multiple goroutines.

func (*Metrics) IncrementCacheHits added in v0.3.0

func (m *Metrics) IncrementCacheHits()

IncrementCacheHits increments the cache hit counter.

func (*Metrics) IncrementCacheMisses added in v0.3.0

func (m *Metrics) IncrementCacheMisses()

IncrementCacheMisses increments the cache miss counter.

func (*Metrics) IncrementErrors added in v0.3.0

func (m *Metrics) IncrementErrors()

IncrementErrors increments the error counter.

func (*Metrics) IncrementResourceReads added in v0.3.0

func (m *Metrics) IncrementResourceReads()

IncrementResourceReads increments the resource read counter.

func (*Metrics) IncrementToolInvocations added in v0.3.0

func (m *Metrics) IncrementToolInvocations()

IncrementToolInvocations increments the tool invocation counter.

func (*Metrics) Snapshot added in v0.3.0

func (m *Metrics) Snapshot() MetricsSnapshot

Snapshot creates a point-in-time snapshot of current metrics.

type MetricsSnapshot added in v0.3.0

type MetricsSnapshot struct {
	// Server uptime
	Uptime time.Duration

	// Tool and resource usage
	ToolInvocations int64
	ResourceReads   int64

	// Cache statistics
	CacheHits    int64
	CacheMisses  int64
	CacheHitRate float64 // Calculated as hits / (hits + misses)

	// Error tracking
	Errors int64
}

MetricsSnapshot provides a point-in-time view of server metrics.

This struct is returned by Server.GetMetrics() and contains copied values that won't change, making it safe to use without synchronization.

type Server

type Server struct {
	// contains filtered or unexported fields
}

Server wraps the MCP server with common infrastructure.

It provides access to shared resources like HTTP client, cache, and logger, along with helper methods for registering tools and resources with automatic counter tracking.

func New

func New(cfg Config, logger *zap.Logger) (*Server, error)

New creates a new MCP server with common infrastructure.

It initializes the HTTP client with retry logic, creates a cache instance (if enabled), and sets up the underlying MCP server. The configuration is validated before creating the server.

Returns an error if the configuration is invalid or if cache creation fails.

func (*Server) AddResource added in v0.2.0

func (s *Server) AddResource(resource *mcp.Resource, handler mcp.ResourceHandler)

AddResource registers a resource with the MCP server and automatically increments the resource counter.

Resources provide static or dynamic content that can be read by MCP clients.

Example:

srv.AddResource(&mcp.Resource{
    URI: "myapp://data",
    Name: "Application Data",
}, func(ctx context.Context, req *mcp.ReadResourceRequest) (*mcp.ReadResourceResult, error) {
    return &mcp.ReadResourceResult{...}, nil
})

func (*Server) AddResourceTemplate added in v0.2.0

func (s *Server) AddResourceTemplate(template *mcp.ResourceTemplate, handler mcp.ResourceHandler)

AddResourceTemplate registers a resource template with the MCP server and automatically increments the resource counter.

Resource templates allow parameterized URIs using URI template syntax (RFC 6570).

Example:

srv.AddResourceTemplate(&mcp.ResourceTemplate{
    URITemplate: "myapp://users/{userId}",
    Name: "User Data",
}, func(ctx context.Context, req *mcp.ReadResourceRequest) (*mcp.ReadResourceResult, error) {
    userId := req.Params.URI // Extract from actual request
    return &mcp.ReadResourceResult{...}, nil
})

func (*Server) Cache

func (s *Server) Cache() *cache.Cache

Cache returns the cache instance.

Even when CacheEnabled is false, a minimal cache instance is returned.

func (*Server) GetMetrics added in v0.3.0

func (s *Server) GetMetrics() MetricsSnapshot

GetMetrics returns a snapshot of current server metrics.

The returned snapshot is a copy of the current metrics and can be safely used without worrying about concurrent modifications.

Example:

metrics := srv.GetMetrics()
fmt.Printf("Uptime: %v\n", metrics.Uptime)
fmt.Printf("Tool invocations: %d\n", metrics.ToolInvocations)
fmt.Printf("Cache hit rate: %.2f%%\n", metrics.CacheHitRate*100)

func (*Server) HTTPClient

func (s *Server) HTTPClient() *httpx.Client

HTTPClient returns the shared HTTP client.

The client includes retry logic, proper timeouts, and is safe for concurrent use.

func (*Server) IncrementResourceCount

func (s *Server) IncrementResourceCount()

IncrementResourceCount increments the resource counter.

This is called automatically by AddResource and AddResourceTemplate, so you typically don't need to call it manually.

func (*Server) IncrementToolCount

func (s *Server) IncrementToolCount()

IncrementToolCount increments the tool counter.

This is called automatically by AddTool, so you typically don't need to call it manually.

func (*Server) LogRegistrationStats

func (s *Server) LogRegistrationStats()

LogRegistrationStats logs the number of registered tools and resources.

This is useful for debugging and verifying that all expected features were registered. Also includes cache configuration information if caching is enabled.

func (*Server) Logger

func (s *Server) Logger() *zap.Logger

Logger returns the logger instance.

This is the same logger passed to New() during server creation.

func (*Server) MCP

func (s *Server) MCP() *mcp.Server

MCP returns the underlying MCP server for direct access if needed.

Most users should prefer using the helper methods (AddTool, AddResource, etc.) rather than accessing the MCP server directly.

func (*Server) Metrics added in v0.3.0

func (s *Server) Metrics() *Metrics

Metrics returns the raw Metrics instance for direct access.

This is useful for custom metric tracking or integration with monitoring systems. Most users should use GetMetrics() instead, which returns a safe snapshot.

func (*Server) Run

func (s *Server) Run(ctx context.Context, transport mcp.Transport) error

Run starts the server with the given transport.

This method blocks until the context is canceled or an error occurs. Most users should use RunWithTransport instead of calling this directly.

func (*Server) Shutdown

func (s *Server) Shutdown(ctx context.Context) error

Shutdown performs cleanup and gracefully shuts down the server.

This method performs the following cleanup operations in order: 1. Logs final registration statistics (tools and resources) 2. Closes the cache instance (stops background goroutines) 3. Checks for context cancellation or timeout

It's safe to call Shutdown multiple times, though subsequent calls will have no effect (except checking context status).

Example with timeout:

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := srv.Shutdown(ctx); err != nil {
    log.Printf("shutdown error: %v", err)
}

Returns an error if the context was canceled or timed out during cleanup.

type ServerInfo

type ServerInfo struct {
	Name      string
	Version   string
	Commit    string
	BuildDate string
}

ServerInfo holds version and build information for the MCP server.

This struct can be populated at build time using ldflags:

go build -ldflags="-X main.version=1.0.0 -X main.commit=abc123 -X main.buildDate=2025-01-15"

func (ServerInfo) String

func (si ServerInfo) String() string

String returns a formatted version string with commit and build date information.

Format: "version (commit: hash, built: date)"

type TransportError added in v1.0.0

type TransportError struct {
	Err       error
	Transport TransportType
}

TransportError wraps transport-related errors.

func NewTransportError added in v1.0.0

func NewTransportError(transport TransportType, err error) *TransportError

NewTransportError creates a new transport error.

func (*TransportError) Error added in v1.0.0

func (e *TransportError) Error() string

func (*TransportError) Unwrap added in v1.0.0

func (e *TransportError) Unwrap() error

type TransportType

type TransportType string

TransportType defines the type of transport to use.

The MCP specification defines two standard transports: stdio and Streamable HTTP.

const (
	// TransportStdio uses standard input/output for communication.
	// This is the recommended transport for most MCP servers where the client
	// launches the server as a subprocess.
	TransportStdio TransportType = "stdio"

	// TransportStreamableHTTP uses HTTP-based transport for multiple client connections.
	// This replaces the deprecated HTTP+SSE transport and is suitable for servers
	// that need to handle multiple concurrent clients.
	// Note: Not yet implemented in this library.
	TransportStreamableHTTP TransportType = "streamable-http"
)

Directories

Path Synopsis
examples
fileserver command
hello command
metrics command
weather command
Package httpx provides a shared HTTP client with retry logic, timeouts, and helpers
Package httpx provides a shared HTTP client with retry logic, timeouts, and helpers

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL