gin.Engine 上。RegisterSchema 手动注册特定路由的模式以进行细粒度控制。go get github.com/ckanthony/gin-mcp
几分钟内运行您的 MCP 服务器,只需少量代码:
package main
import (
"net/http"
server "github.com/ckanthony/gin-mcp/"
"github.com/gin-gonic/gin"
)
func main() {
// 1. 创建您的 Gin 引擎
r := gin.Default()
// 2. 定义您的 API 路由(Gin-MCP 将发现这些)
r.GET("/ping", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"message": "pong"})
})
r.GET("/users/:id", func(c *gin.Context) {
// 示例处理器...
userID := c.Param("id")
c.JSON(http.StatusOK, gin.H{"user_id": userID, "status": "fetched"})
})
// 3. 创建并配置 MCP 服务器
// 提供 MCP 客户端所需的基本信息。
mcp := server.New(r, &server.Config{
Name: "我的简单 API",
Description: "一个通过 MCP 自动暴露的示例 API。",
// BaseURL 至关重要!它告诉 MCP 客户端在哪里发送请求。
BaseURL: "http://localhost:8080",
})
// 4. 挂载 MCP 服务器端点
mcp.Mount("/mcp") // MCP 客户端将连接到这里
// 5. 运行您的 Gin 服务器
r.Run(":8080") // Gin 服务器按常规运行
}
就这样!您的 MCP 工具现在可以在 http://localhost:8080/mcp 访问。Gin-MCP 自动为 /ping 和 /users/:id 创建了工具。
**关于
BaseURL的注意事项:**始终提供显式的BaseURL。这告诉 MCP 服务器当客户端执行工具时应转发 API 请求到哪个地址。没有它,在代理环境或内部/外部 URL 不同的情况下,自动检测可能会失败。
虽然 Gin-MCP 力求零配置,但您可以自定义其行为。
Gin-MCP 自动从处理器函数注释中提取元数据以生成丰富的工具描述。使用这些注释使您的 MCP 工具更易于发现和使用:
// listProducts 获取分页的产品列表
// @summary 列出所有产品
// @description 返回带有可选价格、标签和可用性过滤器的分页产品列表
// @param page 分页的页码(默认:1)
// @param limit 每页项目数(默认:10,最大:100)
// @param minPrice 最小价格过滤器
// @param tag 通过标签过滤产品
// @tags public catalog
func listProducts(c *gin.Context) {
// 处理程序实现...
}
支持的注释:
@summary - 成为工具主要描述的一行简短描述@description - 追加到摘要的附加详细解释@param <name> <text> - 在生成的模式中为特定输入参数附加描述性文本@tags - 用于过滤工具的空间或逗号分隔标签(参见“过滤暴露的端点”下方)@operationId <id> - 工具的自定义操作 ID(覆盖默认的 METHOD_path 命名方案)。必须在整个路由中唯一;重复会被跳过(首次声明获胜)并记录警告。所有注释都是可选的,但使用它们会使您的 API 工具在 MCP 客户端(如 Claude Desktop 和 Cursor)中更加用户友好。
自定义操作 ID:
默认情况下,Gin-MCP 使用 METHOD_path 格式(例如,GET_users_id)生成操作 ID。对于路径非常长的路由,可以使用 @operationId 指定一个更短、更易管理的名字:
// getUserProfile 获取用户的扩展元数据资料
// @summary 获取用户资料
// @operationId getUserProfile
// @param id 用户标识符
func getUserProfile(c *gin.Context) {
// 而不是默认的 "GET_api_v2_users_userId_profile_extended"
// 这个工具将命名为 "getUserProfile"
}
**重要:**操作 ID 必须是唯一的。如果两个处理器使用相同的 @operationId,重复将完全被跳过(首次声明获胜),并且总是记录警告。这确保了工具列表和操作映射之间的一致性。
RegisterSchema 进行细粒度模式控制有时,自动模式推断不够。RegisterSchema 允许您明确定义特定路由的查询参数或请求体模式。这在以下情况下很有用:
ShouldBindQuery)。package main
import (
// ... 其他导入
"github.com/ckanthony/gin-mcp/pkg/server"
"github.com/gin-gonic/gin"
)
// 查询参数示例结构体
type ListProductsParams struct {
Page int `form:"page,default=1" json:"page,omitempty" jsonschema:"description=页码,minimum=1"`
Limit int `form:"limit,default=10" json:"limit,omitempty" jsonschema:"description=每页项目数,maximum=100"`
Tag string `form:"tag" json:"tag,omitempty" jsonschema:"description=通过标签过滤"`
}
// POST 请求体示例结构体
type CreateProductRequest struct {
Name string `json:"name" jsonschema:"required,description=产品名称"`
Price float64 `json:"price" jsonschema:"required,minimum=0,description=产品价格"`
}
func main() {
r := gin.Default()
// --- 定义路由 ---
r.GET("/products", func(c *gin.Context) { /* ... 处理程序 ... */ })
r.POST("/products", func(c *gin.Context) { /* ... 处理程序 ... */ })
r.PUT("/products/:id", func(c *gin.Context) { /* ... 处理程序 ... */ })
// --- 配置 MCP 服务器 ---
mcp := server.New(r, &server.Config{
Name: "产品 API",
Description: "管理产品的 API。",
BaseURL: "http://localhost:8080",
})
// --- 注册模式 ---
// 注册 ListProductsParams 作为 GET /products 的查询模式
mcp.RegisterSchema("GET", "/products", ListProductsParams{}, nil)
// 注册 CreateProductRequest 作为 POST /products 的请求体模式
mcp.RegisterSchema("POST", "/products", nil, CreateProductRequest{})
// 按需为其他方法/路由注册模式
// 例如,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 处理用户列表
// @summary 列出所有用户
// @tags public users
func listUsers(c *gin.Context) {
// 实现...
}
// deleteUser 处理用户删除
// @summary 删除用户
// @tags admin, internal
func deleteUser(c *gin.Context) {
// 实现...
}
// 仅包括特定的操作 ID
mcp := server.New(r, &server.Config{
// ... 其他配置 ...
IncludeOperations: []string{"GET_users", "POST_users"},
})
// 排除特定的操作 ID
mcp := server.New(r, &server.Config{
// ... 其他配置 ...
ExcludeOperations: []string{"DELETE_users_id"}, // 不暴露删除工具
})
// 仅包括标记为 "public" 或 "users" 的操作
// 如果工具具有指定的任何标签,则会被包括
mcp := server.New(r, &server.Config{
// ... 其他配置 ...
IncludeTags: []string{"public", "users"},
})
// 排除标记为 "admin" 或 "internal" 的操作
// 如果工具具有指定的任何标签,则会被排除
mcp := server.New(r, &server.Config{
// ... 其他配置 ...
ExcludeTags: []string{"admin", "internal"},
})
过滤规则:
IncludeOperations 或 IncludeTags)。
IncludeOperations 优先,并记录警告。ExcludeOperations 或 ExcludeTags)。
ExcludeOperations 优先,并记录警告。示例:
// 包括所有 "public" 端点但排除也标记为 "internal" 的端点
mcp := server.New(r, &server.Config{
IncludeTags: []string{"public"},
ExcludeTags: []string{"internal"},
})
// 包括特定操作但排除管理员端点
mcp := server.New(r, &server.Config{
IncludeOperations: []string{"GET_users", "GET_products"},
ExcludeTags: []string{"admin"}, // 这将被忽略(优先规则)
})
对于高级控制如何在生成的工具中描述响应模式(通常不需要):
mcp := server.New(r, &server.Config{
// ... 其他配置 ...
DescribeAllResponses: true, // 在工具描述中包含所有可能的响应模式(例如,200,404)
DescribeFullResponseSchema: true, // 包含完整的 JSON 模式对象而不是仅仅引用
})
查看 示例 目录以获取演示各种功能的完整、可运行示例:
对于每个用户/部署都有不同端点的环境(如 Quicknode 或 RAGFlow),您可以配置动态 BaseURL 解析:
// Quicknode 示例 - 解析用户特定端点
mcp := server.New(r, &server.Config{
Name: "您的 API",
Description: "具有动态 Quicknode 端点的 API",
// 不需要静态 BaseURL!
})
resolver := server.NewQuicknodeResolver("http://localhost:8080")
mcp.SetExecuteToolFunc(func(operationID string, parameters map[string]interface{}) (interface{}, error) {
return mcp.ExecuteToolWithResolver(operationID, parameters, resolver)
})
支持的环境变量:
QUICKNODE_USER_ENDPOINT,USER_ENDPOINT,HOSTRAGFLOW_ENDPOINT,RAGFLOW_WORKFLOW_URL,RAGFLOW_BASE_URL + WORKFLOW_ID这消除了启动时静态 BaseURL 配置的需求,非常适合多租户代理环境!
一旦您的 Gin 应用程序与 Gin-MCP 正在运行:
http://localhost:8080/mcp)作为 SSE 端点:
欢迎贡献!请随时提交问题或拉取请求。