66 "strings"
77 "sync"
88
9+ application_authorization "github.com/APIParkLab/APIPark/module/application-authorization"
10+
911 mcp_server "github.com/APIParkLab/APIPark/mcp-server"
1012 "github.com/APIParkLab/APIPark/module/mcp"
1113 "github.com/APIParkLab/APIPark/module/system"
@@ -18,11 +20,12 @@ import (
1820var _ IMcpController = (* imlMcpController )(nil )
1921
2022type imlMcpController struct {
21- settingModule system.ISettingModule `autowired:""`
22- mcpModule mcp.IMcpModule `autowired:""`
23- sessionKeys sync.Map
24- server http.Handler
25- openServer http.Handler
23+ settingModule system.ISettingModule `autowired:""`
24+ authorizationModule application_authorization.IAuthorizationModule `autowired:""`
25+ mcpModule mcp.IMcpModule `autowired:""`
26+ sessionKeys sync.Map
27+ server map [string ]http.Handler
28+ openServer http.Handler
2629}
2730
2831var mcpDefaultConfig = `{
@@ -42,7 +45,75 @@ func (i *imlMcpController) GlobalMCPConfig(ctx *gin.Context) (string, error) {
4245 return fmt .Sprintf (mcpDefaultConfig , "APIPark-MCP-Server" , fmt .Sprintf ("%s/openapi/v1/%s/sse?apikey={your_api_key}" , strings .TrimSuffix (cfg .SitePrefix , "/" ), mcp_server .GlobalBasePath )), nil
4346}
4447
45- func (i * imlMcpController ) OnComplete () {
48+ func (i * imlMcpController ) generateZhCNMCPServer () * server.MCPServer {
49+ s := server .NewMCPServer ("APIPark MCP Server" , "1.0.0" , server .WithLogging ())
50+ s .AddTool (
51+ mcp2 .NewTool (
52+ "service_list" ,
53+ mcp2 .WithDescription ("此工具用于获取 APIPark 中已注册服务的列表。每个服务包含其唯一标识(service ID)、名称、描述及包含的 API 列表等关键信息。支持通过关键词进行模糊搜索,以便快速缩小查找范围。在获得某个服务的 ID 后,可以调用 openapi_document 工具来获取该服务的 OpenAPI 文档,以便后续调用其提供的 API 接口。" ),
54+ mcp2 .WithString ("keyword" , mcp2 .Description ("关键词,用于模糊搜索服务" )),
55+ ),
56+ i .mcpModule .Services ,
57+ )
58+ s .AddTool (
59+ mcp2 .NewTool (
60+ "openapi_document" ,
61+ mcp2 .WithDescription ("此工具用于获取指定服务的 OpenAPI 接口文档。返回内容支持 OpenAPI v3 与 v2 两种规范格式。通过传入服务 ID,可以查看该服务的所有 API 定义、参数结构、请求方式等详细信息,为后续构造请求做准备。" ),
62+ mcp2 .WithString ("service" , mcp2 .Description ("服务的唯一标识 ID" )),
63+ ),
64+ i .mcpModule .APIs ,
65+ )
66+ s .AddTool (
67+ mcp2 .NewTool (
68+ "invoke_api" ,
69+ mcp2 .WithDescription ("此工具用于直接调用指定的 API 接口。调用前需根据该接口的 OpenAPI 文档构造必要的请求参数,如请求路径、方法、查询参数、请求头、请求体等。调用过程中无需传递认证信息,例如请求头中的 Authorization 字段不需要提供。" ),
70+ mcp2 .WithString ("path" , mcp2 .Description ("API 请求路径" ), mcp2 .Required ()),
71+ mcp2 .WithString ("method" , mcp2 .Description ("API 请求方法,例如 GET、POST、PUT" ), mcp2 .Required ()),
72+ mcp2 .WithString ("content-type" , mcp2 .Description ("请求的 Content-Type 类型。如果方法为 POST、PUT 或 PATCH,则必须指定该字段。" )),
73+ mcp2 .WithObject ("query" , mcp2 .Description ("请求的查询参数,类型为 map[string]string" )),
74+ mcp2 .WithObject ("header" , mcp2 .Description ("请求的头部参数,类型为 map[string]string" )),
75+ mcp2 .WithString ("body" , mcp2 .Description ("请求体内容,通常为 JSON 字符串" )),
76+ ),
77+ i .mcpModule .Invoke ,
78+ )
79+ return s
80+ }
81+
82+ func (i * imlMcpController ) generateZhTWMCPServer () * server.MCPServer {
83+ s := server .NewMCPServer ("APIPark MCP Server" , "1.0.0" , server .WithLogging ())
84+ s .AddTool (
85+ mcp2 .NewTool (
86+ "service_list" ,
87+ mcp2 .WithDescription ("此工具用於獲取 APIPark 中已註冊服務的清單。每個服務包含其唯一識別碼(service ID)、名稱、描述以及該服務所包含的 API 列表。支援關鍵字模糊搜尋,可快速縮小查詢範圍。獲取到服務 ID 後,可使用 openapi_document 工具來查詢該服務對應的 OpenAPI 文件,為後續 API 呼叫做準備。" ),
88+ mcp2 .WithString ("keyword" , mcp2 .Description ("關鍵字,用於模糊搜尋服務" )),
89+ ),
90+ i .mcpModule .Services ,
91+ )
92+ s .AddTool (
93+ mcp2 .NewTool (
94+ "openapi_document" ,
95+ mcp2 .WithDescription ("此工具用於查詢指定服務的 OpenAPI 文件。返回的格式支援 OpenAPI v3 與 v2 標準。透過輸入服務 ID,可查閱該服務所有 API 的定義、參數結構、請求方式等細節,有助於後續構造 API 呼叫請求。" ),
96+ mcp2 .WithString ("service" , mcp2 .Description ("欲查詢的服務唯一識別碼" )),
97+ ),
98+ i .mcpModule .APIs ,
99+ )
100+ s .AddTool (
101+ mcp2 .NewTool (
102+ "invoke_api" ,
103+ mcp2 .WithDescription ("此工具可直接發送 API 請求。在呼叫此工具之前,需根據該 API 的 OpenAPI 文件構造所需的請求參數,如請求路徑、方法、查詢參數、標頭、主體等。使用此工具時不需傳送任何認證資訊,例如 Authorization 標頭可省略。" ),
104+ mcp2 .WithString ("path" , mcp2 .Description ("API 的請求路徑" ), mcp2 .Required ()),
105+ mcp2 .WithString ("method" , mcp2 .Description ("API 的請求方法,例如 GET、POST、PUT" ), mcp2 .Required ()),
106+ mcp2 .WithString ("content-type" , mcp2 .Description ("請求的 Content-Type。若方法為 POST、PUT 或 PATCH,則必須指定" )),
107+ mcp2 .WithObject ("query" , mcp2 .Description ("請求的查詢參數,類型為 map[string]string" )),
108+ mcp2 .WithObject ("header" , mcp2 .Description ("請求的標頭,類型為 map[string]string" )),
109+ mcp2 .WithString ("body" , mcp2 .Description ("請求主體內容,通常為 JSON 字串" )),
110+ ),
111+ i .mcpModule .Invoke ,
112+ )
113+ return s
114+ }
115+
116+ func (i * imlMcpController ) generateEnMCPServer () * server.MCPServer {
46117 s := server .NewMCPServer ("APIPark MCP Server" , "1.0.0" , server .WithLogging ())
47118 s .AddTool (
48119 mcp2 .NewTool (
@@ -73,23 +144,72 @@ func (i *imlMcpController) OnComplete() {
73144 ),
74145 i .mcpModule .Invoke ,
75146 )
76- i .server = server .NewSSEServer (s , server .WithBasePath (fmt .Sprintf ("/api/v1/%s" , mcp_server .GlobalBasePath )))
77- i .openServer = server .NewSSEServer (s , server .WithBasePath (fmt .Sprintf ("/openapi/v1/%s" , strings .Trim (mcp_server .GlobalBasePath , "/" ))))
147+ return s
148+ }
149+
150+ func (i * imlMcpController ) generateJPMCPServer () * server.MCPServer {
151+ s := server .NewMCPServer ("APIPark MCP Server" , "1.0.0" , server .WithLogging ())
152+ s .AddTool (
153+ mcp2 .NewTool (
154+ "service_list" ,
155+ mcp2 .WithDescription ("このツールは、APIPark に登録されているサービスの一覧を取得するためのものです。各サービスには、サービスID、名称、説明、およびそのサービスに含まれるAPI一覧といった重要な情報が含まれます。キーワードによるあいまい検索が可能で、目的のサービスを素早く絞り込むことができます。取得したサービスIDを使用して openapi_document ツールを呼び出すことで、そのサービスの OpenAPI ドキュメントを取得でき、APIの利用準備が整います。" ),
156+ mcp2 .WithString ("keyword" , mcp2 .Description ("キーワード。サービスをあいまい検索するための文字列" )),
157+ ),
158+ i .mcpModule .Services ,
159+ )
160+ s .AddTool (
161+ mcp2 .NewTool (
162+ "openapi_document" ,
163+ mcp2 .WithDescription ("指定されたサービスの OpenAPI ドキュメントを取得するためのツールです。OpenAPI v3 および v2 のフォーマットに対応しています。このドキュメントを使用することで、APIのエンドポイント、リクエスト方法、パラメータなどの詳細を確認でき、API呼び出しの準備に役立ちます。" ),
164+ mcp2 .WithString ("service" , mcp2 .Description ("対象のサービスID" )),
165+ ),
166+ i .mcpModule .APIs ,
167+ )
168+ s .AddTool (
169+ mcp2 .NewTool (
170+ "invoke_api" ,
171+ mcp2 .WithDescription ("このツールは、指定された API を直接呼び出すためのものです。呼び出し前に、OpenAPI ドキュメントに基づいて必要なパラメータ(パス、メソッド、クエリ、ヘッダー、ボディなど)を構築する必要があります。呼び出し時に認証情報(例:Authorization ヘッダー)を送信する必要はありません。" ),
172+ mcp2 .WithString ("path" , mcp2 .Description ("API のリクエストパス" ), mcp2 .Required ()),
173+ mcp2 .WithString ("method" , mcp2 .Description ("HTTPメソッド(GET、POST、PUTなど)。" ), mcp2 .Required ()),
174+ mcp2 .WithString ("content-type" , mcp2 .Description ("リクエストの Content-Type。メソッドが POST、PUT、PATCH の場合に必須。" )),
175+ mcp2 .WithObject ("query" , mcp2 .Description ("リクエストのクエリパラメータ。型は map[string]string" )),
176+ mcp2 .WithObject ("header" , mcp2 .Description ("リクエストヘッダー。型は map[string]string" )),
177+ mcp2 .WithString ("body" , mcp2 .Description ("リクエストボディ。通常はJSON文字列" )),
178+ ),
179+ i .mcpModule .Invoke ,
180+ )
181+ return s
182+ }
183+
184+ func (i * imlMcpController ) OnComplete () {
185+ i .server = make (map [string ]http.Handler )
186+ enSer := i .generateEnMCPServer ()
187+ i .server ["en-US" ] = server .NewSSEServer (enSer , server .WithBasePath (fmt .Sprintf ("/api/v1/%s" , mcp_server .GlobalBasePath )))
188+ i .server ["zh-CN" ] = server .NewSSEServer (i .generateZhCNMCPServer (), server .WithBasePath (fmt .Sprintf ("/api/v1/%s" , mcp_server .GlobalBasePath )))
189+ i .server ["zh-TW" ] = server .NewSSEServer (i .generateZhTWMCPServer (), server .WithBasePath (fmt .Sprintf ("/api/v1/%s" , mcp_server .GlobalBasePath )))
190+ i .server ["ja-JP" ] = server .NewSSEServer (i .generateJPMCPServer (), server .WithBasePath (fmt .Sprintf ("/api/v1/%s" , mcp_server .GlobalBasePath )))
191+
192+ i .openServer = server .NewSSEServer (enSer , server .WithBasePath (fmt .Sprintf ("/openapi/v1/%s" , strings .Trim (mcp_server .GlobalBasePath , "/" ))))
78193}
79194
80195func (i * imlMcpController ) GlobalMCPHandle (ctx * gin.Context ) {
81196 cfg := i .settingModule .Get (ctx )
82197 req := ctx .Request .WithContext (utils .SetGatewayInvoke (ctx .Request .Context (), cfg .InvokeAddress ))
83-
84- i .server .ServeHTTP (ctx .Writer , req )
198+ locale := utils .I18n (ctx )
199+ if v , ok := i .server [locale ]; ok {
200+ v .ServeHTTP (ctx .Writer , req )
201+ return
202+ }
203+ i .server ["en-US" ].ServeHTTP (ctx .Writer , req )
85204}
86205
87206func (i * imlMcpController ) GlobalHandleSSE (ctx * gin.Context ) {
88- i .handleSSE (ctx , i .openServer )
207+ apikey := ctx .Request .URL .Query ().Get ("apikey" )
208+ i .handleSSE (ctx , i .openServer , apikey )
89209}
90210
91- func (i * imlMcpController ) handleSSE (ctx * gin.Context , server http.Handler ) {
92- apikey := ctx . Request . URL . Query (). Get ( "apikey" )
211+ func (i * imlMcpController ) handleSSE (ctx * gin.Context , server http.Handler , apikey string ) {
212+
93213 writer := & ResponseWriter {
94214 Writer : ctx .Writer ,
95215 sessionId : make (chan string ),
@@ -120,7 +240,23 @@ func (i *imlMcpController) MCPHandle(ctx *gin.Context) {
120240}
121241
122242func (i * imlMcpController ) ServiceHandleSSE (ctx * gin.Context ) {
123- i .handleSSE (ctx , mcp_server .DefaultMCPServer ())
243+ apikey := ctx .Request .URL .Query ().Get ("apikey" )
244+ serviceId := ctx .Param ("serviceId" )
245+ if serviceId == "" {
246+ ctx .AbortWithStatusJSON (403 , gin.H {"code" : - 1 , "msg" : "invalid service id" , "success" : "fail" })
247+ return
248+ }
249+ ok , err := i .authorizationModule .CheckAPIKeyAuthorization (ctx , serviceId , apikey )
250+ if err != nil {
251+ ctx .AbortWithStatusJSON (403 , gin.H {"code" : - 1 , "msg" : err .Error (), "success" : "fail" })
252+ return
253+ }
254+ if ! ok {
255+ ctx .AbortWithStatusJSON (403 , gin.H {"code" : - 1 , "msg" : "invalid apikey" , "success" : "fail" })
256+ return
257+ }
258+
259+ i .handleSSE (ctx , mcp_server .DefaultMCPServer (), apikey )
124260}
125261
126262func (i * imlMcpController ) ServiceHandleMessage (ctx * gin.Context ) {
0 commit comments