Enable MCP features for any Gin API with a line of code. Gin-MCP is an opinionated, zero-configuration library that automatically exposes your existing Gin endpoints as Model Context Protocol (MCP) tools, making them instantly usable by MCP-compatible clients like Cursor , Claude Desktop , Continue , Zed , and other MCP-enabled tools. Our philosophy is simple: minimal setup, maximum productivity .
Add this skill
npx mdskills install ckanthony/gin-mcpComprehensive Go library bridge enabling zero-config MCP tool exposure for Gin APIs with excellent docs
**Enable MCP features for any Gin API with a line of code.**
Gin-MCP is an **opinionated, zero-configuration** library that automatically exposes your existing Gin endpoints as [Model Context Protocol (MCP)](https://modelcontextprotocol.io/introduction) tools, making them instantly usable by MCP-compatible clients like [Cursor](https://cursor.sh/), [Claude Desktop](https://claude.ai/desktop), [Continue](https://continue.dev/), [Zed](https://zed.dev/), and other MCP-enabled tools.
Our philosophy is simple: **minimal setup, maximum productivity**. Just plug Gin-MCP into your Gin application, and it handles the rest.

gin.Engine.RegisterSchema for fine-grained control.go get github.com/ckanthony/gin-mcp
Get your MCP server running in minutes with minimal code:
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
}
That's it! Your MCP tools are now available at http://localhost:8080/mcp. Gin-MCP automatically created tools for /ping and /users/:id.
Note on
BaseURL: Always provide an explicitBaseURL. This tells the MCP server the correct address to forward API requests to when a tool is executed by the client. Without it, automatic detection might fail, especially in environments with proxies or different internal/external URLs.
While Gin-MCP strives for zero configuration, you can customize its behavior.
Gin-MCP automatically extracts metadata from handler function comments to generate rich tool descriptions. Use these annotations to make your MCP tools more discoverable and easier to use:
// 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...
}
Supported Annotations:
@summary - Brief one-line description that becomes the tool's primary description@description - Additional detailed explanation appended to the summary@param - Attaches descriptive text to specific input parameters in the generated schema@tags - Space or comma-separated tags used for filtering tools (see "Filtering Exposed Endpoints" below)@operationId - Custom operation ID for the tool (overrides the default METHOD_path naming scheme). Must be unique across all routes; duplicates will be skipped (first declaration wins) with a warning logged.All annotations are optional, but using them makes your API tools much more user-friendly in MCP clients like Claude Desktop and Cursor.
Custom Operation IDs:
By default, Gin-MCP generates operation IDs using the format METHOD_path (e.g., GET_users_id). For routes with very long paths, you can use @operationId to specify a shorter, more manageable name:
// 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"
}
Important: Operation IDs must be unique. If two handlers use the same @operationId, the duplicate will be skipped entirely (first declaration wins), and a warning will always be logged. This ensures consistency between the tool list and operations map.
RegisterSchemaSometimes, automatic schema inference isn't enough. RegisterSchema allows you to explicitly define schemas for query parameters or request bodies for specific routes. This is useful when:
ShouldBindQuery).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")
}
Explanation:
mcp.RegisterSchema(method, path, querySchema, bodySchema)method: HTTP method (e.g., "GET", "POST").path: Gin route path (e.g., "/products", "/products/:id").querySchema: An instance of the struct used for query parameters (or nil if none). Gin-MCP uses reflection and jsonschema tags to generate the schema.bodySchema: An instance of the struct used for the request body (or nil if none).Control which Gin endpoints become MCP tools using operation IDs or tags. Tags come from the @tags annotation in your handler comments (see "Annotating Handlers" above).
Tags are specified in handler function comments using the @tags annotation. You can specify tags separated by spaces, commas, or both:
// 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"},
})
Filtering Rules:
IncludeOperations OR IncludeTags).
IncludeOperations takes precedence and a warning is logged.ExcludeOperations OR ExcludeTags).
ExcludeOperations takes precedence and a warning is logged.Examples:
// 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)
})
For advanced control over how response schemas are described in the generated tools (often not needed):
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
})
See the examples directory for complete, runnable examples demonstrating various features:
examples/simple/main.go - Complete product store API with static BaseURL configurationexamples/simple/quicknode.go - Dynamic BaseURL configuration for Quicknode proxy environmentsexamples/simple/ragflow.go - Dynamic BaseURL configuration for RAGFlow deployment scenariosFor environments where each user/deployment has a different endpoint (like Quicknode or RAGFlow), you can configure dynamic BaseURL resolution:
// 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)
})
Environment Variables Supported:
QUICKNODE_USER_ENDPOINT, USER_ENDPOINT, HOSTRAGFLOW_ENDPOINT, RAGFLOW_WORKFLOW_URL, RAGFLOW_BASE_URL + WORKFLOW_IDThis eliminates the need for static BaseURL configuration at startup, perfect for multi-tenant proxy environments!
Once your Gin application with Gin-MCP is running:
http://localhost:8080/mcp) as the SSE endpoint:
Contributions are welcome! Please feel free to submit issues or Pull Requests.
Install via CLI
npx mdskills install ckanthony/gin-mcpGin-MCP: Zero-Config Gin to MCP Bridge is a free, open-source AI agent skill. Enable MCP features for any Gin API with a line of code. Gin-MCP is an opinionated, zero-configuration library that automatically exposes your existing Gin endpoints as Model Context Protocol (MCP) tools, making them instantly usable by MCP-compatible clients like Cursor , Claude Desktop , Continue , Zed , and other MCP-enabled tools. Our philosophy is simple: minimal setup, maximum productivity .
Install Gin-MCP: Zero-Config Gin to MCP Bridge with a single command:
npx mdskills install ckanthony/gin-mcpThis downloads the skill files into your project and your AI agent picks them up automatically.
Gin-MCP: Zero-Config Gin to MCP Bridge works with Claude Code, Claude Desktop, Cursor, Vscode Copilot, Windsurf, Continue Dev, Gemini Cli, Amp, Roo Code, Goose. Skills use the open SKILL.md format which is compatible with any AI coding agent that reads markdown instructions.