Sponsored by Deepsite.site

GoMCP — Gin-like Framework for MCP Servers in Go

Created By
zhangpanda18 days ago
The fast, idiomatic way to build MCP servers in Go. Struct-tag auto schema, middleware chain, tool groups, auth, adapters for Gin/OpenAPI/gRPC, async tasks, Inspector UI, and more.
Overview

GoMCP

Go Version License Release gomcp MCP server

The fast, idiomatic way to build MCP servers in Go.

中文文档



🎯 What is GoMCP?

GoMCP is a framework for building Model Context Protocol (MCP) servers — not just an SDK. Think of it as "Gin for MCP".

MCP is the open protocol that lets AI applications (Claude Desktop, Cursor, Kiro, VS Code Copilot) call external tools, read data sources, and use prompt templates. GoMCP makes building those servers trivial.

Why GoMCP?

mcp-go (mark3labs)Official Go SDKGoMCP
LevelSDKSDKFramework
Schema generationManualjsonschema tagmcp tag + auto validation
MiddlewareBasic hooksNoneFull chain (Logger, Auth, RateLimit, OTel…)
Tool groupsNoNoYes (user.get, admin.delete)
Import Gin routesNoNo✅ One line
Import OpenAPI/SwaggerNoNo✅ One line
Import gRPC servicesNoNo
Built-in authNoNoBearer, API Key, Basic + RBAC
Inspector UINoNo
Test utilitiesBasicNomcptest package

🛠️ Tech Stack

Environment Requirements

RequirementVersion
Go≥ 1.25
MCP Protocol2024-11-05 (backward compatible with 2025-11-25)

Core Dependencies

TechnologyDescription
Go standard libraryCore framework — zero external dependencies
GinAdapter only — import existing Gin routes
gRPCAdapter only — import gRPC services
OpenTelemetryOptional — distributed tracing
YAML v3Provider only — hot-reload tool definitions

🌟 Core Features

🔧 Tool Development

  • Struct-tag auto schema — define parameters with Go structs and mcp tags, JSON Schema generated automatically
  • Typed handlersfunc(*Context, Input) (Output, error) — no manual parameter parsing
  • Parameter validation — required, min/max, enum, pattern — checked before your handler runs
  • Component versioning — register multiple versions, clients call name@version
  • Async tasks — long-running tools return task ID, with polling and cancellation

🔌 Adapters (Core Differentiator)

  • Gin adapter — import existing Gin routes as MCP tools with one line
  • OpenAPI adapter — generate tools from Swagger/OpenAPI 3.x docs
  • gRPC adapter — import gRPC service methods as MCP tools

🔐 Security

  • BearerAuth — JWT token validation
  • APIKeyAuth — API key validation via header
  • BasicAuth — HTTP Basic authentication
  • RequireRole / RequirePermission — RBAC authorization on tool groups

🧩 Framework Features

  • Middleware chain — Logger, Recovery, RequestID, Timeout, RateLimit, OpenTelemetry
  • Tool groups — organize tools with prefixes and group-level middleware
  • Resource & Prompt — full MCP support including URI templates and parameterized prompts
  • Auto-completions — suggest values for prompt/resource arguments

🚀 Production Ready

  • Multiple transports — stdio (Claude Desktop, Cursor, Kiro) and Streamable HTTP with SSE
  • MCP Inspector — built-in web debug UI for browsing and testing tools
  • Hot-reload — load tool definitions from YAML files with file watching
  • mcptest package — in-memory client for unit testing with snapshot support

🏗️ Architecture

┌──────────────────────────────────────────────────────────────┐
│                        User Code                             │
│   s.Tool() / s.ToolFunc() / s.Resource() / s.Prompt()        │
├──────────────────────────────────────────────────────────────┤
│                     Framework Core                           │
│   Router → Middleware Chain → Validation → Handler → Result   │
├────────────┬─────────────┬───────────────┬───────────────────┤
│   Schema   │  Validator  │   Adapters    │  Observability    │
│  Generator │   Engine    │ Gin/OpenAPI/  │  OTel / Logger    │
│ (mcp tags) │ (auto)      │ gRPC          │  / Inspector      │
├────────────┴─────────────┴───────────────┴───────────────────┤
│                     Protocol Layer                           │
│          JSON-RPC 2.0 / MCP / Capability Negotiation         │
├──────────────────────────────────────────────────────────────┤
│                     Transport Layer                          │
│              stdio  /  Streamable HTTP + SSE                 │
└──────────────────────────────────────────────────────────────┘

Project Structure

gomcp/
├── server.go              # Server core, tool/resource/prompt registration
├── context.go             # Request context with typed accessors
├── group.go               # Tool groups with prefix naming
├── middleware.go           # Middleware interface and chain execution
├── middleware_builtin.go   # Logger, Recovery, RequestID, Timeout, RateLimit
├── middleware_auth.go      # BearerAuth, APIKeyAuth, BasicAuth, RBAC
├── middleware_otel.go      # OpenTelemetry tracing
├── schema/                # struct tag → JSON Schema generator + validator
├── transport/             # stdio + Streamable HTTP
├── adapter/               # Gin, OpenAPI, gRPC adapters
├── mcptest/               # Testing utilities
├── task.go                # Async task support
├── completion.go          # Auto-completions
├── inspector.go           # Web debug UI
├── provider.go            # Hot-reload from YAML
└── examples/              # Working examples

📦 Installation

go get github.com/zhangpanda/gomcp

⚡ Quick Start

5 lines to a working MCP server

package main

import (
    "fmt"
    "github.com/zhangpanda/gomcp"
)

type SearchInput struct {
    Query string `json:"query" mcp:"required,desc=Search keyword"`
    Limit int    `json:"limit" mcp:"default=10,min=1,max=100"`
}

type SearchResult struct {
    Items []string `json:"items"`
    Total int      `json:"total"`
}

func main() {
    s := gomcp.New("my-server", "1.0.0")

    s.ToolFunc("search", "Search documents by keyword", func(ctx *gomcp.Context, in SearchInput) (SearchResult, error) {
        items := []string{fmt.Sprintf("Result for %q", in.Query)}
        return SearchResult{Items: items, Total: len(items)}, nil
    })

    s.Stdio()
}

The SearchInput struct automatically generates this JSON Schema:

{
  "type": "object",
  "properties": {
    "query": { "type": "string", "description": "Search keyword" },
    "limit": { "type": "integer", "default": 10, "minimum": 1, "maximum": 100 }
  },
  "required": ["query"]
}

Invalid parameters are rejected before your handler runs:

validation failed: query: required; limit: must be <= 100

📖 Usage Guide

Struct Tag Reference

TagTypeDescriptionExample
requiredflagField must be providedmcp:"required"
descstringHuman-readable descriptionmcp:"desc=Search keyword"
defaultanyDefault valuemcp:"default=10"
minnumberMinimum value (inclusive)mcp:"min=0"
maxnumberMaximum value (inclusive)mcp:"max=100"
enumstringPipe-separated allowed valuesmcp:"enum=asc|desc"
patternstringRegex validationmcp:"pattern=^[a-z]+$"

Combine: mcp:"required,desc=User email,pattern=^[^@]+@[^@]+$"

Supported types: string, int, float64, bool, []T, nested structs.

Tools

Simple handler:

s.Tool("hello", "Say hello", func(ctx *gomcp.Context) (*gomcp.CallToolResult, error) {
    return ctx.Text("Hello, " + ctx.String("name")), nil
})

Typed handler (recommended):

type Input struct {
    Name  string `json:"name"  mcp:"required,desc=User name"`
    Email string `json:"email" mcp:"required,pattern=^[^@]+@[^@]+$"`
}

s.ToolFunc("create_user", "Create user", func(ctx *gomcp.Context, in Input) (User, error) {
    return db.CreateUser(in.Name, in.Email)
})

Resources

// Static
s.Resource("config://app", "App config", func(ctx *gomcp.Context) (any, error) {
    return map[string]any{"version": "1.0"}, nil
})

// Dynamic URI template
s.ResourceTemplate("db://{table}/{id}", "DB record", func(ctx *gomcp.Context) (any, error) {
    return db.Find(ctx.String("table"), ctx.String("id")), nil
})

Prompts

s.Prompt("code_review", "Code review",
    []gomcp.PromptArgument{gomcp.PromptArg("language", "Language", true)},
    func(ctx *gomcp.Context) ([]gomcp.PromptMessage, error) {
        return []gomcp.PromptMessage{
            gomcp.UserMsg(fmt.Sprintf("Review this %s code for bugs.", ctx.String("language"))),
        }, nil
    },
)

Middleware

s.Use(gomcp.Logger())                              // Log tool name + duration
s.Use(gomcp.Recovery())                            // Recover from panics
s.Use(gomcp.RequestID())                           // Unique request ID
s.Use(gomcp.Timeout(10 * time.Second))             // Deadline enforcement
s.Use(gomcp.RateLimit(100))                        // 100 calls/minute
s.Use(gomcp.OpenTelemetry())                       // Distributed tracing
s.Use(gomcp.BearerAuth(tokenValidator))            // JWT auth
s.Use(gomcp.APIKeyAuth("X-API-Key", keyValidator)) // API key auth

Custom middleware:

func AuditLog() gomcp.Middleware {
    return func(ctx *gomcp.Context, next func() error) error {
        start := time.Now()
        err := next()
        log.Printf("tool=%s duration=%s err=%v", ctx.String("_tool_name"), time.Since(start), err)
        return err
    }
}

Tool Groups

user := s.Group("user", authMiddleware)
user.Tool("get", "Get user", getUser)              // → user.get
user.Tool("update", "Update user", updateUser)      // → user.update

admin := user.Group("admin", gomcp.RequireRole("admin"))
admin.Tool("delete", "Delete user", deleteUser)     // → user.admin.delete

Adapters

Gin — one line to import your existing API:

adapter.ImportGin(s, ginRouter, adapter.ImportOptions{
    IncludePaths: []string{"/api/v1/"},
})
// GET /api/v1/users/:id → Tool get_api_v1_users_by_id (id = required param)

OpenAPI — generate from Swagger docs:

adapter.ImportOpenAPI(s, "./swagger.yaml", adapter.OpenAPIOptions{
    TagFilter: []string{"pets"},
    ServerURL: "https://api.example.com",
})

gRPC:

adapter.ImportGRPC(s, grpcConn, adapter.GRPCOptions{
    Services: []string{"user.UserService"},
})

Component Versioning

s.ToolFunc("search", "v1", searchV1, gomcp.Version("1.0"))
s.ToolFunc("search", "v2 with embeddings", searchV2, gomcp.Version("2.0"))
// "search" → latest, "search@1.0" → exact version

Async Tasks

s.AsyncTool("report", "Generate report", func(ctx *gomcp.Context) (*gomcp.CallToolResult, error) {
    // long-running work
    return ctx.Text("done"), nil
})
// Client gets taskId immediately, polls tasks/get, can tasks/cancel

Hot-Reload

s.LoadDir("./tools/", gomcp.DirOptions{Watch: true})

MCP Inspector

s.Dev(":9090") // http://localhost:9090 — browse and test all tools

Testing

func TestSearch(t *testing.T) {
    c := mcptest.NewClient(t, setupServer())
    c.Initialize()

    result := c.CallTool("search", map[string]any{"query": "golang"})
    result.AssertNoError(t)
    result.AssertContains(t, "golang")

    mcptest.MatchSnapshot(t, "search_result", result)
}

Transports

s.Stdio()          // Claude Desktop, Cursor, Kiro
s.HTTP(":8080")    // Remote deployment with SSE
s.Handler()        // Embed in existing HTTP server

Use with AI Clients

{
  "mcpServers": {
    "my-server": {
      "command": "/path/to/your/binary"
    }
  }
}

Works with Claude Desktop, Cursor, Kiro, Windsurf, VS Code Copilot, and any MCP-compatible client.


📋 Roadmap

  • Core: Tool, Resource, Prompt with full MCP protocol support
  • Struct-tag auto schema generation + parameter validation
  • Middleware chain (Logger, Recovery, RateLimit, Timeout, RequestID)
  • Auth middleware (Bearer / API Key / Basic) + RBAC authorization
  • Tool groups with prefix naming and nested groups
  • stdio + Streamable HTTP transports with SSE notifications
  • Gin adapter — import existing Gin routes as MCP tools
  • OpenAPI adapter — generate tools from Swagger/OpenAPI docs
  • gRPC adapter — import gRPC services as MCP tools
  • OpenTelemetry integration
  • mcptest package with snapshot testing
  • Component versioning + deprecation
  • Async tasks with polling and cancellation
  • MCP Inspector web debug UI
  • Hot-reload provider from YAML
  • Auto-completions for prompt/resource arguments

🤝 Feedback & Support

💡 Recommended reading: How To Ask Questions The Smart Way


Copyright © 2026 GoMCP Contributors

Licensed under the Apache License 2.0.

Important Notes

  1. This project is open source and free for both personal and commercial use under the Apache 2.0 license.
  2. You must retain the copyright notice, license text, and any attribution notices in all copies or substantial portions of the software.
  3. The Apache 2.0 license includes an express grant of patent rights from contributors to users.
  4. Contributions to this project are licensed under the same Apache 2.0 license.
  5. Unauthorized removal of copyright notices may result in legal action.

Patent Notice

Certain features of this framework (struct-tag schema generation, HTTP-to-MCP automatic adapter, OpenAPI-to-MCP automatic adapter) are the subject of pending patent applications. The Apache 2.0 license grants you a perpetual, worldwide, royalty-free patent license to use these features as part of this software.


⭐ Star History

If you find GoMCP useful, please consider giving it a star! It helps others discover the project.

Server Config

{
  "mcpServers": {
    "gomcp": {
      "command": "go",
      "args": [
        "run",
        "github.com/zhangpanda/gomcp/examples/basic@latest"
      ]
    }
  }
}
Recommend Servers
TraeBuild with Free GPT-4.1 & Claude 3.7. Fully MCP-Ready.
Visual Studio Code - Open Source ("Code - OSS")Visual Studio Code
Serper MCP ServerA Serper MCP Server
Baidu Map百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
EdgeOne Pages MCPAn MCP service designed for deploying HTML content to EdgeOne Pages and obtaining an accessible public URL.
Y GuiA web-based graphical interface for AI chat interactions with support for multiple AI models and MCP (Model Context Protocol) servers.
AiimagemultistyleA Model Context Protocol (MCP) server for image generation and manipulation using fal.ai's Stable Diffusion model.
Amap Maps高德地图官方 MCP Server
Jina AI MCP ToolsA Model Context Protocol (MCP) server that integrates with Jina AI Search Foundation APIs.
WindsurfThe new purpose-built IDE to harness magic
RedisA Model Context Protocol server that provides access to Redis databases. This server enables LLMs to interact with Redis key-value stores through a set of standardized tools.
ChatWiseThe second fastest AI chatbot™
MCP AdvisorMCP Advisor & Installation - Use the right MCP server for your needs
BlenderBlenderMCP connects Blender to Claude AI through the Model Context Protocol (MCP), allowing Claude to directly interact with and control Blender. This integration enables prompt assisted 3D modeling, scene creation, and manipulation.
Howtocook Mcp基于Anduin2017 / HowToCook (程序员在家做饭指南)的mcp server,帮你推荐菜谱、规划膳食,解决“今天吃什么“的世纪难题; Based on Anduin2017/HowToCook (Programmer's Guide to Cooking at Home), MCP Server helps you recommend recipes, plan meals, and solve the century old problem of "what to eat today"
DeepChatYour AI Partner on Desktop
Tavily Mcp
Zhipu Web SearchZhipu Web Search MCP Server is a search engine specifically designed for large models. It integrates four search engines, allowing users to flexibly compare and switch between them. Building upon the web crawling and ranking capabilities of traditional search engines, it enhances intent recognition capabilities, returning results more suitable for large model processing (such as webpage titles, URLs, summaries, site names, site icons, etc.). This helps AI applications achieve "dynamic knowledge acquisition" and "precise scenario adaptation" capabilities.
MiniMax MCPOfficial MiniMax Model Context Protocol (MCP) server that enables interaction with powerful Text to Speech, image generation and video generation APIs.
CursorThe AI Code Editor
Playwright McpPlaywright MCP server