关于 Gin-MCP: Zero-Config Gin to MCP Bridge
Gin-MCP 是一个面向 Go Gin 框架的库,无需修改现有代码即可把 Gin 接口自动暴露为 MCP 工具。它面向希望让已有 Gin API 被 MCP 客户端调用的开发者,并支持通过注释和配置调整工具的生成与筛选。
主要功能
- 01自动发现已注册的 Gin 路由
- 02从路由参数与请求类型推断工具模式
- 03通过 @tags 与操作 ID 筛选暴露的接口
- 04转发客户端 Authorization 头
- 05支持 Streamable HTTP 传输
适用场景
- 01让现有 Gin API 被 Cursor 或 Claude Desktop 调用
- 02为受 JWT 保护的 API 提供 MCP 访问
- 03在代理环境中动态解析 BaseURL
MCP 相关
该项目是一个 MCP 服务端库,把 Gin 接口转换为 MCP 工具,并通过 /mcp 等路径提供 Streamable HTTP 或旧版 SSE 端点。它支持多个 MCP 协议版本的协商。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
我们还没有获取到这个服务的安装包或远程地址,请按项目 README 中的说明安装。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
Gin-MCP:Gin 到 MCP 的零配置桥接器
|
只需一行代码,即可为任意 Gin API 启用 MCP 功能。
Gin-MCP 是一个主张鲜明、零配置的库,可自动将现有 Gin 端点公开为 Model Context Protocol (MCP) 工具,供 Cursor、Claude Desktop、Continue、Zed 等兼容 MCP 的客户端和其他支持 MCP 的工具立即使用。 我们的理念很简单:最少配置,最高效率。只需将 Gin-MCP 接入你的 Gin 应用,剩下的工作交给它处理。 |
|
为什么选择 Gin-MCP?
- 轻松集成: 无需编写繁琐的样板代码,即可将 Gin API 连接到 MCP 客户端。
- 零配置(默认): 即刻上手。Gin-MCP 会自动发现路由并推断架构。
- 提升开发效率: 少花时间配置工具,多花时间构建功能。
- 灵活性: 默认采用零配置,需要时也可以自定义架构和端点公开方式。
- 现有 API: 可与现有 Gin API 配合使用,无需更改任何代码。
演示
功能
- 自动发现: 智能查找所有已注册的 Gin 路由。
- 架构推断: 根据路由参数和请求/响应类型(如可行)自动生成 MCP 工具架构。
- 直接集成 Gin: 将 MCP 服务直接挂载到现有的
gin.Engine上。 - 保留参数: 在生成的 MCP 工具中准确反映 Gin 路由参数(路径、查询)。
- 动态解析 BaseURL: 支持代理环境(Quicknode、RAGFlow),并提供按用户/部署区分的端点。
- 可自定义架构: 使用
RegisterSchema为特定路由手动注册架构,实现精细控制。 - 选择性公开: 使用操作 ID 或标签筛选要公开的端点。
- 灵活部署: 可将 MCP 服务挂载在同一个 Gin 应用中,也可单独部署。
- 现代 MCP 传输: 默认使用 Streamable HTTP,并支持协议版本协商(2026-07-28 至 2025-03-26)、预先调用
server/discover,以及选择退出并改用旧版 HTTP+SSE。 - 转发授权标头: 自动将客户端的
Authorization标头转发给每次内部工具执行调用,使 MCP 能够访问受 JWT 保护的 API。
安装
go get github.com/ckanthony/gin-mcp
基本用法:即时创建 MCP 服务
只需编写少量代码,即可在几分钟内运行 MCP 服务:
package main
import (
"net/http"
server "github.com/ckanthony/gin-mcp/"
"github.com/gin-gonic/gin"
)
func main() {
// 1. Create your Gin engine
r := gin.Default()
// 2. Define your API routes (Gin-MCP will discover these)
r.GET("/ping", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"message": "pong"})
})
r.GET("/users/:id", func(c *gin.Context) {
// Example handler...
userID := c.Param("id")
c.JSON(http.StatusOK, gin.H{"user_id": userID, "status": "fetched"})
})
// 3. Create and configure the MCP server
// Provide essential details for the MCP client.
mcp := server.New(r, &server.Config{
Name: "My Simple API",
Description: "An example API automatically exposed via MCP.",
// BaseURL is crucial! It tells MCP clients where to send requests.
BaseURL: "http://localhost:8080",
})
// 4. Mount the MCP server endpoint
mcp.Mount("/mcp") // MCP clients will connect here
// 5. Run your Gin server
r.Run(":8080") // Gin server runs as usual
}
就这么简单!现在,你的 MCP 工具已可通过 http://localhost:8080/mcp 使用。Gin-MCP 已自动为 /ping 和 /users/:id 创建工具。
关于
BaseURL的说明:请始终提供明确的BaseURL。这样,当客户端执行工具时,MCP 服务就能知道应将 API 请求转发到哪个地址。如果不提供,在某些环境中自动检测可能会失败,尤其是使用代理或内外部 URL 不同的环境。
高级用法
Gin-MCP 力求实现零配置,但你也可以自定义其行为。
使用注释为处理函数添加注解
Gin-MCP 会自动从处理函数注释中提取元数据,生成详尽的工具描述。使用这些注解可以让其他人更容易发现和使用你的 MCP 工具:
// listProducts retrieves a paginated list of products
// @summary List all products
// @description Returns a paginated list of products with optional filtering by price, tags, and availability
// @param page Page number for pagination (default: 1)
// @param limit Number of items per page (default: 10, max: 100)
// @param minPrice Minimum price filter
// @param tag Filter products by tag
// @tags public catalog
func listProducts(c *gin.Context) {
// Handler implementation...
}
支持的注解:
@summary- 简短的一行描述,将作为工具的主要说明@description- 补充的详细说明,将附加在摘要之后@param <name> <text>- 为生成的架构中的特定输入参数添加描述文本@tags- 用于筛选工具的标签,以空格或逗号分隔(请参阅下文的“筛选公开的端点”)@operationId <id>- 工具的自定义操作 ID(覆盖默认的METHOD_path命名方案)。所有路由中的 ID 必须唯一;重复项将被跳过(以首次声明为准),并记录警告。
所有注解都是可选的,但使用它们可以让 API 工具在 Claude Desktop 和 Cursor 等 MCP 客户端中更易于使用。
自定义操作 ID:
默认情况下,Gin-MCP 使用 METHOD_path 格式生成操作 ID(例如 GET_users_id)。对于路径特别长的路由,可以使用 @operationId 指定更短、更易管理的名称:
// getUserProfile retrieves a user's profile with extended metadata
// @summary Get user profile
// @operationId getUserProfile
// @param id User identifier
func getUserProfile(c *gin.Context) {
// Instead of the default "GET_api_v2_users_userId_profile_extended"
// this tool will be named "getUserProfile"
}
**重要提示:**操作 ID 必须唯一。如果两个处理函数使用相同的 @operationId,重复项将被完全跳过(以首次声明为准),并始终记录警告。这可以确保工具列表与操作映射保持一致。
使用 RegisterSchema 精细控制架构
有时,自动推断架构并不足够。RegisterSchema 允许你为特定路由显式定义查询参数或请求正文的架构。适用于以下情况:
- 使用复杂结构体作为查询参数(
ShouldBindQuery)。 - 希望为请求正文定义不同的架构(例如 POST/PUT)。
- 自动推断无法捕获你希望在 MCP 工具定义中公开的特定约束(枚举、描述等)。
package main
import (
// ... other imports
"github.com/ckanthony/gin-mcp/pkg/server"
"github.com/gin-gonic/gin"
)
// Example struct for query parameters
type ListProductsParams struct {
Page int `form:"page,default=1" json:"page,omitempty" jsonschema:"description=Page number,minimum=1"`
Limit int `form:"limit,default=10" json:"limit,omitempty" jsonschema:"description=Items per page,maximum=100"`
Tag string `form:"tag" json:"tag,omitempty" jsonschema:"description=Filter by tag"`
}
// Example struct for POST request body
type CreateProductRequest struct {
Name string `json:"name" jsonschema:"required,description=Product name"`
Price float64 `json:"price" jsonschema:"required,minimum=0,description=Product price"`
}
func main() {
r := gin.Default()
// --- Define Routes ---
r.GET("/products", func(c *gin.Context) { /* ... handler ... */ })
r.POST("/products", func(c *gin.Context) { /* ... handler ... */ })
r.PUT("/products/:id", func(c *gin.Context) { /* ... handler ... */ })
// --- Configure MCP Server ---
mcp := server.New(r, &server.Config{
Name: "Product API",
Description: "API for managing products.",
BaseURL: "http://localhost:8080",
})
// --- Register Schemas ---
// Register ListProductsParams as the query schema for GET /products
mcp.RegisterSchema("GET", "/products", ListProductsParams{}, nil)
// Register CreateProductRequest as the request body schema for POST /products
mcp.RegisterSchema("POST", "/products", nil, CreateProductRequest{})
// You can register schemas for other methods/routes as needed
// e.g., mcp.RegisterSchema("PUT", "/products/:id", nil, UpdateProductRequest{})
mcp.Mount("/mcp")
r.Run(":8080")
}
说明:
mcp.RegisterSchema(method, path, querySchema, bodySchema)method:HTTP 方法(例如 “GET”、“POST”)。path:Gin 路由路径(例如 “/products”、“/products/:id”)。querySchema:用于查询参数的结构体实例(如果没有,则为nil)。Gin-MCP 会使用反射和jsonschema标签生成架构。bodySchema:用于请求正文的结构体实例(如果没有,则为nil)。
筛选公开的端点
使用操作 ID 或标签来控制哪些 Gin 端点会成为 MCP 工具。标签来自处理函数注释中的 @tags 注解(请参阅上文的“使用注释为处理函数添加注解”)。
基于标签筛选
在处理函数注释中使用 @tags 注解指定标签。标签可以用空格、逗号或两者分隔:
// listUsers handles user listing
// @summary List all users
// @tags public users
func listUsers(c *gin.Context) {
// Implementation...
}
// deleteUser handles user deletion
// @summary Delete a user
// @tags admin, internal
func deleteUser(c *gin.Context) {
// Implementation...
}
过滤配置
// Only include specific operations by their Operation ID
mcp := server.New(r, &server.Config{
// ... other config ...
IncludeOperations: []string{"GET_users", "POST_users"},
})
// Exclude specific operations
mcp := server.New(r, &server.Config{
// ... other config ...
ExcludeOperations: []string{"DELETE_users_id"}, // Don't expose delete tool
})
// Only include operations tagged with "public" or "users"
// A tool is included if it has ANY of the specified tags
mcp := server.New(r, &server.Config{
// ... other config ...
IncludeTags: []string{"public", "users"},
})
// Exclude operations tagged with "admin" or "internal"
// A tool is excluded if it has ANY of the specified tags
mcp := server.New(r, &server.Config{
// ... other config ...
ExcludeTags: []string{"admin", "internal"},
})
过滤规则:
- 只能使用一个包含过滤器(
IncludeOperations或IncludeTags)。- 如果两者都设置,则
IncludeOperations优先,并会记录警告。
- 如果两者都设置,则
- 只能使用一个排除过滤器(
ExcludeOperations或ExcludeTags)。- 如果两者都设置,则
ExcludeOperations优先,并会记录警告。
- 如果两者都设置,则
- 可以组合使用包含过滤器和排除过滤器(例如,包含标签 "public",但排除操作 "legacyPublicOp")。
- 排除始终优先:如果某个工具同时匹配包含过滤器和排除过滤器,则会被排除。
- 标签匹配:工具只要具有任意一个指定标签,就会被包含或排除(OR 逻辑)。
示例:
// Include all "public" endpoints but exclude those also tagged "internal"
mcp := server.New(r, &server.Config{
IncludeTags: []string{"public"},
ExcludeTags: []string{"internal"},
})
// Include specific operations but exclude admin endpoints
mcp := server.New(r, &server.Config{
IncludeOperations: []string{"GET_users", "GET_products"},
ExcludeTags: []string{"admin"}, // This will be ignored (precedence rule)
})
自定义架构描述(较少使用)
如需高级控制生成的工具中响应架构的描述方式(通常不需要):
mcp := server.New(r, &server.Config{
// ... other config ...
DescribeAllResponses: true, // Include *all* possible response schemas (e.g., 200, 404) in tool descriptions
DescribeFullResponseSchema: true, // Include the full JSON schema object instead of just a reference
})
示例
请参阅 examples 目录,查看演示各种功能的完整可运行示例:
基本用法示例
examples/simple/main.go- 使用静态 BaseURL 配置的完整产品商店 APIexamples/simple/quicknode.go- 适用于 Quicknode 代理环境的动态 BaseURL 配置examples/simple/ragflow.go- 适用于 RAGFlow 部署场景的动态 BaseURL 配置
代理场景的动态 BaseURL
对于每个用户或部署使用不同端点的环境(如 Quicknode 或 RAGFlow),可以配置动态 BaseURL 解析:
// Quicknode example - resolves user-specific endpoints
mcp := server.New(r, &server.Config{
Name: "Your API",
Description: "API with dynamic Quicknode endpoints",
// No static BaseURL needed!
})
resolver := server.NewQuicknodeResolver("http://localhost:8080")
mcp.SetExecuteToolFunc(func(operationID string, parameters map[string]interface{}) (interface{}, error) {
return mcp.ExecuteToolWithResolver(operationID, parameters, resolver)
})
支持的环境变量:
- Quicknode:
QUICKNODE_USER_ENDPOINT、USER_ENDPOINT、HOST - RAGFlow:
RAGFLOW_ENDPOINT、RAGFLOW_WORKFLOW_URL、RAGFLOW_BASE_URL+WORKFLOW_ID
这样就无需在启动时配置静态 BaseURL,非常适合多租户代理环境!
MCP 传输方式与协议版本
破坏性变更: 默认传输方式现为 Streamable HTTP。旧版 HTTP+SSE 传输(协议版本
2024-11-05,已被 MCP 规范弃用)仍可通过选择退出启用:TransportType: server.TransportTypeSSE。
Gin-MCP 默认使用现代的无状态 MCP Streamable HTTP 传输:每次向挂载路径发送 POST 请求,都会直接在 HTTP 请求体中返回 JSON-RPC 响应,无需持久 GET 连接或 Pod 亲和性,因此兼容水平自动扩缩容和无法实现会话亲和性的托管负载均衡器(例如 GCP、AWS ALB)。可选的 GET 端点会为服务器发起的通知(例如 tools/listChanged)提供 SSE 会话;基本的请求-响应操作不需要此功能。
旧版 SSE 传输(MCP 规范 2024-11-05)要求持久 GET 连接与后续 POST 请求路由到同一个 Pod,因此必须使用粘性会话——只有在客户端不支持 Streamable HTTP 时才选择退出并使用该传输方式。
支持的协议版本(Streamable HTTP,按从新到旧排列):
| 版本 | 说明 |
|---|---|
2026-07-28 | 当前版本。无状态:无需 initialize 握手。每个请求的 _meta 都包含 io.modelcontextprotocol/protocolVersion 和 clientCapabilities;Mcp-Method/Mcp-Name 标头会经过验证(见下文)。 |
2025-11-25 | 最后一个包含 initialize 握手的版本。 |
2025-06-18 | 支持。 |
2025-03-26 | 支持;也是请求完全未携带版本时使用的回退版本。 |
2024-11-05 | 仅用于旧版 HTTP+SSE(已弃用)。 |
mcp := server.New(r, &server.Config{
Name: "My API",
Description: "An example API exposed via MCP.",
BaseURL: "https://api.example.com",
// Transport selection (default: Streamable HTTP).
TransportType: server.TransportTypeStreamableHTTP, // or server.TransportTypeSSE
// DNS-rebinding protection: requests with an Origin header not in this list
// get HTTP 403. Empty = allow all. Requests without an Origin header
// (server-to-server) are always allowed.
AllowedOrigins: []string{"https://app.example.com"},
// Pin a single protocol version. Empty = all versions supported by the transport.
ProtocolVersion: "",
// Advertised in serverInfo (default "0.1.0").
ServerVersion: "1.0.0",
// Cache hints advertised on tools/list for 2026-07-28 clients
// (defaults: 60000 ms, "public").
CacheTTLMs: 60000,
CacheScope: "public",
})
mcp.Mount("/mcp")
MCP 客户端只需发送单个 POST /mcp 即可连接,无需事先发送 GET 请求。
版本协商。 协议版本由 MCP-Protocol-Version 标头和 params._meta["io.modelcontextprotocol/protocolVersion"] 确定。如果两者都存在,则必须一致(否则返回 HTTP 400、-32020)。如果两者都不存在,则默认使用 2025-03-26。不支持的版本会被拒绝,并返回 HTTP 400 和 -32022;error.data.supported 列表会告知客户端此服务支持的版本。客户端也可以预先调用 server/discover RPC,在无需握手的情况下获取 supportedVersions、capabilities 和服务器信息。旧版 initialize 握手永远不会协商到 2026-07-28,而会回退到最后一个支持握手的版本 2025-11-25。
2026-07-28 标头验证。 协商使用 2026-07-28 的请求还必须发送 Mcp-Method 标头(纯 ASCII),其值必须与 JSON-RPC method 匹配;对于 tools/call,还必须发送与 params.name 匹配的 Mcp-Name 标头。对于不符合标头安全要求的 Mcp-Name 值,可使用 =?base64?...?= 标记进行 Base64 编码后发送,服务器端会对其解码。任何缺失、无效或不匹配的标头都会被拒绝,并返回 HTTP 400 和 -32020。
Origin 验证(DNS 重绑定防护)
根据 MCP 规范 2025-03-26 §Security,服务器应验证 Origin 标头。使用 AllowedOrigins 限制源自浏览器的请求(参见上文配置示例):
- 请求携带的
Origin标头不在列表中 →403 Forbidden。 - 请求不携带
Origin标头(服务器到服务器:curl、Node.js 等)→ 始终允许。 AllowedOrigins为空或为 nil → 允许所有源(适用于要求 Bearer 令牌的场景)。
Authorization 标头转发
当 Gin 端点受到 JWT Bearer 令牌保护时,可以将客户端的 Authorization 标头转发到每次内部工具执行的 HTTP 调用:
mcp := server.New(r, &server.Config{
Name: "My API",
BaseURL: "https://api.example.com",
ForwardAuthHeaders: true,
})
mcp.Mount("/mcp")
- SSE 传输: 在建立 SSE 连接时捕获一次该标头,并在该连接上的所有后续工具调用中重复使用。
- Streamable HTTP 传输: 每个 POST 请求都会单独捕获该标头(每次调用相互独立)。
- 默认值:
false(禁用,以保持向后兼容)。
连接 MCP 客户端
运行集成了 Gin-MCP 的 Gin 应用后:
- 启动应用。
- 在 MCP 客户端中,提供挂载 MCP 服务的 URL(例如,
http://localhost:8080/mcp):- Streamable HTTP 传输(默认):作为普通 HTTP 端点连接(仅 POST)。
- SSE 传输(仅在通过
TransportType: server.TransportTypeSSE明确配置时):作为 SSE 端点连接(先 GET,再向同一路径发送 POST)。 - Cursor:设置 → MCP → 添加服务
- Claude Desktop:添加到 MCP 配置文件
- Continue:在 VS Code 设置中配置
- Zed:添加到 MCP 设置
- 客户端将连接并自动发现可用的 API 工具。
贡献
欢迎贡献!欢迎提交问题或 Pull Request。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。