# zhangpanda/gomcp [Health: Active]

**Category:** 🛠️ Other Tools and Integrations  
**Repository:** https://github.com/zhangpanda/gomcp  
**GitHub Stars:** 14  
**Views:** 1  
**Installs:** 0  
**Upvotes:** 0  
**Directory Page:** https://allmcps.com/mcp/zhangpanda-gomcp

## Description
A Gin-like framework for building MCP servers in Go. Struct-tag auto schema, middleware chain, auth, tool groups, adapters for Gin/OpenAPI/gRPC, async tasks, Inspector UI.

## Claude Desktop Quick Installation
Heuristic fallback — verify the package name and runner against the repository README before running it. Uses `npx` (confidence: low):

```json
"mcpServers": {
  "gomcp": {
    "command": "npx",
    "args": ["-y","zhangpanda-gomcp"]
  }
}
```

## Documentation & README

# GoMCP

[![Go Version](https://img.shields.io/badge/Go-1.25+-00ADD8?style=flat&logo=go)](https://go.dev)
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE)
[![Release](https://img.shields.io/badge/Release-v1.3.0-green.svg)](https://github.com/zhangpanda/gomcp/releases)
[![gomcp MCP server](https://glama.ai/mcp/servers/zhangpanda/gomcp/badges/score.svg)](https://glama.ai/mcp/servers/zhangpanda/gomcp)

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

[中文文档](https://github.com/zhangpanda/gomcp/blob/HEAD/README_CN.md)

---

## 🚀 Quick Links

- **GitHub**: https://github.com/zhangpanda/gomcp
- **Gitee**: https://gitee.com/rilegouasas/gomcp
- **MCP Protocol**: https://modelcontextprotocol.io

---

## 🎯 What is GoMCP?

GoMCP is a **framework** for building [Model Context Protocol (MCP)](https://modelcontextprotocol.io) 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 SDK | **GoMCP** |
|---|---|---|---|
| Level | SDK | SDK | **Framework** |
| Schema generation | Manual | `jsonschema` tag | **`mcp` tag + auto validation** |
| Middleware | Basic hooks | None | **Full chain (Logger, Auth, RateLimit, OTel…)** |
| Tool groups | No | No | **Yes (`user.get`, `admin.delete`)** |
| Import Gin routes | No | No | **✅ One line** |
| Import OpenAPI/Swagger | No | No | **✅ One line** |
| Import gRPC services | No | No | **✅** |
| Built-in auth | No | No | **Bearer / API Key / Basic + RBAC** (Bearer = your token/JWT validator) |
| Inspector UI | No | No | **✅** |
| Test utilities | Basic | No | **mcptest package** |

---

## 🛠️ Tech Stack

### Environment Requirements

| Requirement | Version |
|-------------|---------|
| **Go** | ≥ 1.25 |
| **MCP Protocol** | 2024-11-05 (backward compatible with 2025-11-25) |

> **Note on the Go 1.25 requirement.** GoMCP's `go.mod` declares `go 1.25.0` so the project always builds with the toolchain that ships current security and runtime fixes. If you are running Go 1.21+ locally with the default `GOTOOLCHAIN=auto`, Go will automatically download and use the matching toolchain for you — no manual upgrade is needed. If you have pinned `GOTOOLCHAIN=local`, install Go 1.25+ or unset the pin.

### Core Dependencies

| Technology | Description |
|------------|-------------|
| **Go standard library** | Framework routing, JSON-RPC, transports — no forced DB/ORM deps |
| **Gin** | Adapter only — import existing Gin routes |
| **gRPC** | Adapter only — import gRPC services |
| **OpenTelemetry** | Optional — distributed tracing |
| **YAML v3** | Provider 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 handlers** — `func(*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** — Bearer token check via your validator (JWT parsing is up to you; this library does not decode JWTs)
- **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
- **Lifecycle** — `Close()`, session idle eviction, async concurrency — see [**Server lifecycle, sessions & async tasks**](#server-lifecycle).

---

## 🏗️ 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 chain helpers (SkipAuthForMCPMethods, handshake skips)
├── middleware_builtin.go   # Logger, Recovery, RequestID, Timeout, RateLimit
├── middleware_auth.go      # Bearer/API key/Basic auth, RBAC, SSE auth helpers
├── middleware_otel.go      # OpenTelemetry tracing
├── schema/                # struct tag → JSON Schema generator + validator
├── transport/             # stdio + Streamable HTTP + optional CORS helper
├── 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
    ├── basic/             # Minimal stdio server
    ├── filesystem/        # Real-world file ops
    ├── gin-adapter/       # Import Gin routes
    ├── openapi-adapter/   # Import Swagger/OpenAPI
    └── grpc-adapter/      # Import gRPC services
```

### 📖 Cookbook

Step-by-step guides for common tasks (5 minutes each):

- [Build a search tool](https://github.com/zhangpanda/gomcp/blob/HEAD/docs/cookbook/01-search-tool.md) — zero to Claude Desktop
- [Import an existing API](https://github.com/zhangpanda/gomcp/blob/HEAD/docs/cookbook/02-import-existing-api.md) — Gin / OpenAPI / gRPC in one line
- [Add auth + RBAC](https://github.com/zhangpanda/gomcp/blob/HEAD/docs/cookbook/03-auth-and-rbac.md) — Bearer tokens + role-based access

---

## 📦 Installation

```bash
go get github.com/zhangpanda/gomcp
```

---

## ⚡ Quick Start

### 5 lines to a working MCP server

```go
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:

```json
{
  "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

| Tag | Type | Description | Example |
|-----|------|-------------|---------|
| `required` | flag | Field must be provided | `mcp:"required"` |
| `desc` | string | Human-readable description | `mcp:"desc=Search keyword"` |
| `default` | any | Default value | `mcp:"default=10"` |
| `min` | number | Minimum value (inclusive) | `mcp:"min=0"` |
| `max` | number | Maximum value (inclusive) | `mcp:"max=100"` |
| `enum` | string | Pipe-separated allowed values | `mcp:"enum=asc\|desc"` |
| `pattern` | string | Regex validation | `mcp:"pattern=^[a-z]+$"` |

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

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

### Tools

**Simple handler:**

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

**Typed handler (recommended):**

```go
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

```go
// 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

```go
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

```go
s.Use(gomcp.Logger())                              // Log MCP method + 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
// Pick one: BearerAuth (token required on initialize too) or BearerAuthSkipHandshake (initialize/ping anonymous).
s.Use(gomcp.BearerAuthSkipHandshake(tokenValidator))
s.Use(gomcp.APIKeyAuthSkipHandshake("X-API-Key", keyValidator))
```

> **Auth error shape.** When a BearerAuth / APIKeyAuth / BasicAuth /
> RequireRole / RequirePermission middleware rejects a call, the
> framework returns a regular JSON-RPC `result` with
> `isError = true` and the reason in `content[0].text` — **not** a
> JSON-RPC `error` object, and **not** an HTTP 401/403. Clients must
> inspect the tool-call result's `isError` to detect auth failures.

**Custom middleware:**

```go
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

```go
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:**

```go
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:**

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

**gRPC:**

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

### Component Versioning

```go
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

```go
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

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

YAML tool file shape:

```yaml
name: search
description: Full-text document search
version: "1.0"            # OPTIONAL — non-empty renames the tool to "search@1.0"
method: GET
handler: https://example.com/search
params:
  - {name: query, type: string, required: true, description: Query text}
```

> **Heads up — `version` renames the tool.** A non-empty `version`
> field makes the Provider register the tool as `name@version`
> (e.g. `search@1.0`), following the same convention as
> [`gomcp.Version()`](#component-versioning). That is the name
> clients must pass to `tools/call`, and the name that shows up in
> `tools/list`. Drop the `version` field entirely if you want an
> unversioned tool called plain `search`.

<a id="server-lifecycle"></a>

### Server lifecycle, sessions & async tasks

- **`Server.Close()`** — When your process or test tears down a server that uses **`LoadDir(..., Watch: true)`** or long-lived HTTP, call **`Close()`** once. It stops the YAML watch loop, the **session eviction** background goroutine, and the **async task manager** eviction loop. The call is **idempotent**.
- **Sessions** — Session state is **in-memory only**. Identifiers come from the client `Mcp-Session-Id` header (see Streamable HTTP). **Sessions idle for 30 minutes** (no access via that ID) are **removed**; the next request with the same ID gets a **new empty session**. Do not rely on `Session` storage across long idle periods unless the client keeps traffic or you refresh state yourself.
- **`SetMaxConcurrentTasks(n)`** — Set this **before** the first **`AsyncTool` / `AsyncToolFunc`**. After the internal task manager is created, later calls are a **no-op** (avoids races with in-flight work).
- **Shutdown vs async work** — `Close()` does **not** wait for async tool handlers that are still running; add your own **timeout / wait** if you need hard guarantees before exit.

### MCP Inspector

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

### Testing

```go
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

```go
s.Stdio()          // Claude Desktop, Cursor, Kiro
s.HTTP(":8080")    // Remote deployment with SSE
s.Handler()        // Embed in existing HTTP server
// Browser clients: wrap the handler with transport.WrapCORS(h, []string{"https://your.app"}) when needed
```

### Use with AI Clients

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

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

---

## 📋 Roadmap

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

---

## 🤝 Feedback & Support

- **Bug Reports**: [GitHub Issues](https://github.com/zhangpanda/gomcp/issues)
- **Feature Requests**: [GitHub Issues](https://github.com/zhangpanda/gomcp/issues)
- **Discussions**: [GitHub Discussions](https://github.com/zhangpanda/gomcp/discussions)

> 💡 Recommended reading: [How To Ask Questions The Smart Way](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way)

---

## 🔒 Security

### HTTP transport and authentication

- **`Use` middleware runs for every JSON-RPC method** (except the notification `notifications/initialized`, which has no response): `initialize`, `tools/list`, `tools/call`, `resources/read`, `prompts/get`, `tasks/*`, `completion/complete`, etc. Use `BearerAuth` / `APIKeyAuth` / `BasicAuth` when exposing **`POST /mcp`**. For **`APIKeyAuth`**, `api_key` (and other merged params) come from **`tools/call` arguments**, **`prompts/get` arguments**, or **`resources/read` params** JSON when no header is sent—prefer headers for production.
- **`BearerAuthSkipHandshake` / `APIKeyAuthSkipHandshake` / `BasicAuthSkipHandshake`** (or `SkipAuthForMCPMethods`) let `initialize` and `ping` run without credentials while keeping other methods protected—typical for MCP HTTP clients that negotiate before sending tokens.
- **Request context propagates** into tool, resource, and prompt handlers (deadlines, `Authorization`, and injected headers from Streamable HTTP).
- **SSE (`GET /mcp`)** does not execute MCP middleware. Use **`WithSSEAuth`** with **`SSEBearerAuth`**, **`SSEAPIKeyAuth`**, **`SSEBasicAuth`**, or your own gate. Without `WithSSEAuth`, any client that can open `GET` receives broadcast notifications.
- **Browser `fetch`**: wrap your `/mcp` handler with **`transport.WrapCORS(h, allowedOrigins)`** from `github.com/zhangpanda/gomcp/transport`; never use `*` with credentials—only list trusted origins.

When deploying Streamable HTTP in production, combine TLS, authentication middleware on `POST`, and **`WithSSEAuth`** when notifications must not be public.

To report security vulnerabilities, see [SECURITY.md](https://github.com/zhangpanda/gomcp/blob/HEAD/SECURITY.md).

---

## ⚖️ Copyright & License

Copyright © 2026 GoMCP Contributors

Licensed under the [Apache License 2.0](https://github.com/zhangpanda/gomcp/blob/HEAD/LICENSE).

### 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.


