Gin-MCP: Zero-Config Gin to MCP Bridge について
Gin-MCP は、既存の Gin エンドポイントをハンドラーのコードを変更せずに MCP ツールとして公開する Go ライブラリです。Gin API を MCP クライアントから利用したい開発者向けです。アノテーションと設定により、生成されるツールを調整できます。
主な機能
- 01登録済み Gin ルートの自動検出
- 02ルートパラメーターからのツールスキーマ推論
- 03オペレーション ID やタグによるエンドポイントの絞り込み
- 04クライアントの Authorization ヘッダーの転送
- 05デフォルトの Streamable HTTP トランスポート
活用シーン
- 01既存の Gin API を Cursor や Claude Desktop から呼び出す
- 02JWT で保護された API への MCP アクセスの提供
- 03プロキシ環境での BaseURL の動的解決
MCP 対応
本プロジェクトは、Gin エンドポイントを MCP ツールに変換する MCP サーバーのライブラリです。/mcp などのマウントパスで Streamable HTTP を提供し、旧版の SSE はオプトアウトで利用できます。複数の MCP プロトコルバージョンをネゴシエーションします。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
このサーバーのパッケージやリモートエンドポイントはまだ取得できていません。プロジェクトの README の手順に従ってください。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
Gin-MCP:設定不要の Gin から MCP へのブリッジ
|
1 行のコードで、あらゆる Gin API に MCP 機能を追加できます。
Gin-MCP は、既存の Gin エンドポイントをModel Context Protocol(MCP)のツールとして自動的に公開する、独自の方針に基づいた設定不要のライブラリです。これにより、Cursor、Claude Desktop、Continue、Zedなど、MCP 対応クライアントですぐに利用できるようになります。 私たちの考え方はシンプルです。最小限のセットアップで最大限の生産性を実現します。Gin-MCP を Gin アプリケーションに組み込むだけで、あとはすべて Gin-MCP が処理します。 |
|
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 トランスポート: プロトコルバージョンのネゴシエーション(2026-07-28 から 2025-03-26 まで)、事前の
server/discover、および従来の HTTP+SSE を無効化するオプションに対応した、ストリーミング可能な HTTP(デフォルト)。 - 認証ヘッダーの転送: クライアントの
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を指定してください。これにより、クライアントがツールを実行したときに、API リクエストを転送する正しいアドレスを MCP サーバーに伝えられます。指定しない場合、自動検出に失敗することがあります。特に、プロキシを使用する環境や、内部 URL と外部 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-@summaryに追加される、詳しい説明です。@param <name> <text>- 生成されたスキーマ内の特定の入力パラメーターに、説明文を追加します。@tags- ツールのフィルタリングに使う、スペースまたはカンマ区切りのタグです(下記の「公開するエンドポイントのフィルタリング」を参照)。@operationId <id>- ツール用のカスタム operation ID です(デフォルトのMETHOD_path命名規則を上書きします)。すべてのルートで一意である必要があります。重複がある場合は警告がログに記録され、後から宣言されたものはスキップされます(最初の宣言が優先されます)。
すべてのアノテーションは省略可能ですが、使用すると Claude Desktop や Cursor などの MCP クライアントで、API ツールをより使いやすくできます。
カスタム operation ID:
デフォルトでは、Gin-MCP は METHOD_path 形式で operation 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"
}
重要: operation ID は一意である必要があります。2 つのハンドラーで同じ @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)。
公開するエンドポイントのフィルタリング
operation 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"},
})
フィルタリングルール:
- 使用できる包含フィルターは1つだけです(
IncludeOperationsまたはIncludeTags)。- 両方が設定されている場合は、
IncludeOperationsが優先され、警告がログに記録されます。
- 両方が設定されている場合は、
- 使用できる除外フィルターは1つだけです(
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 を静的に設定する商品ストア API の完全な例examples/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 は、JSON-RPC レスポンスを HTTP ボディに直接返します。永続的な GET 接続もポッドアフィニティも不要なため、水平オートスケーリングや、セッションアフィニティに対応できないマネージドロードバランサー(GCP、AWS ALB など)と互換性があります。サーバー起点の通知(例:tools/listChanged)用に、オプションの GET エンドポイントで SSE セッションを提供できます。基本的なリクエスト/レスポンスの処理には必要ありません。
旧来の SSE トランスポート(MCP 仕様 2024-11-05)では、後続の POST リクエストを同じポッドにルーティングする永続的な GET 接続が必要となるため、スティッキーセッションが必要です。クライアントが 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 クライアントは、事前の GET なしで単一の POST /mcp を使って接続できます。
バージョンネゴシエーション。 プロトコルバージョンは、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 としてネゴシエートされたリクエストでは、JSON-RPC の method と一致する Mcp-Method ヘッダー(プレーンな ASCII)も送信する必要があります。また、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:Settings → MCP → Add Server
- Claude Desktop:MCP 設定ファイルに追加します
- Continue:VS Code の設定で構成します
- Zed:MCP 設定に追加します
- クライアントが接続し、利用可能な API ツールを自動的に検出します。
コントリビューション
コントリビューションを歓迎します。お気軽に Issue や Pull Request をお送りください。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。