Compare commits

...

7 Commits

Author SHA1 Message Date
ningyv 6d611de382 Merge pull request #439 from APIParkLab/fix/issue-#437
fix: incorrect Swagger display in service details
Fixes #437
2026-04-27 12:00:01 +08:00
lcx e484dbd55b fix: incorrect Swagger display in service details 2026-04-27 11:37:46 +08:00
Dot.L 9192b3995f Merge pull request #409 from APIParkLab/feature/liujian-1.9
fix bug
2025-10-26 22:28:24 +08:00
Liujian 7b54e12950 fix bug 2025-10-24 17:18:29 +08:00
Dot.L 8857fc4f33 Merge pull request #407 from APIParkLab/fix/cx
fix: issue#395
2025-10-21 18:38:58 +08:00
Dot.L 6bed4f7672 Merge pull request #406 from APIParkLab/feature/liujian-1.9
MCP transports supports Streamable HTTP
2025-10-21 18:00:12 +08:00
Liujian ea32fb1cd6 MCP transports supports Streamable HTTP 2025-10-21 17:52:50 +08:00
15 changed files with 263 additions and 123 deletions
+5 -1
View File
@@ -113,9 +113,13 @@ func (i *imlAPIController) Edit(ctx *gin.Context, serviceId string, apiId string
if input.AiModel.Type != "local" { if input.AiModel.Type != "local" {
provider = input.AiModel.Provider provider = input.AiModel.Provider
} }
modelName := input.AiModel.Name
if modelName == "" {
modelName = input.AiModel.Id
}
proxy.Plugins["ai_formatter"] = api.PluginSetting{ proxy.Plugins["ai_formatter"] = api.PluginSetting{
Config: plugin_model.ConfigType{ Config: plugin_model.ConfigType{
"model": input.AiModel.Name, "model": modelName,
"provider": provider, "provider": provider,
"config": input.AiModel.Config, "config": input.AiModel.Config,
}, },
+71 -31
View File
@@ -21,13 +21,14 @@ import (
var _ IMcpController = (*imlMcpController)(nil) var _ IMcpController = (*imlMcpController)(nil)
type imlMcpController struct { type imlMcpController struct {
settingModule system.ISettingModule `autowired:""` settingModule system.ISettingModule `autowired:""`
authorizationModule application_authorization.IAuthorizationModule `autowired:""` authorizationModule application_authorization.IAuthorizationModule `autowired:""`
appModule service.IAppModule `autowired:""` appModule service.IAppModule `autowired:""`
mcpModule mcp.IMcpModule `autowired:""` mcpModule mcp.IMcpModule `autowired:""`
sessionKeys sync.Map sessionKeys sync.Map
server map[string]http.Handler sseServers map[string]http.Handler
openServer http.Handler openSseServer http.Handler
openStreamableServer http.Handler
} }
func (i *imlMcpController) AppMCPHandle(ctx *gin.Context) { func (i *imlMcpController) AppMCPHandle(ctx *gin.Context) {
@@ -42,12 +43,12 @@ func (i *imlMcpController) AppMCPHandle(ctx *gin.Context) {
paths := strings.Split(req.URL.Path, "/") paths := strings.Split(req.URL.Path, "/")
req.URL.Path = fmt.Sprintf("/api/v1/%s/%s", mcp_server.GlobalBasePath, paths[len(paths)-1]) req.URL.Path = fmt.Sprintf("/api/v1/%s/%s", mcp_server.GlobalBasePath, paths[len(paths)-1])
locale := utils.I18n(ctx) locale := utils.I18n(ctx)
if v, ok := i.server[locale]; ok { if v, ok := i.sseServers[locale]; ok {
v.ServeHTTP(ctx.Writer, req) v.ServeHTTP(ctx.Writer, req)
return return
} }
i.server[languageEnUs].ServeHTTP(ctx.Writer, req) i.sseServers[languageEnUs].ServeHTTP(ctx.Writer, req)
} }
func (i *imlMcpController) AppHandleSSE(ctx *gin.Context) { func (i *imlMcpController) AppHandleSSE(ctx *gin.Context) {
@@ -68,7 +69,7 @@ func (i *imlMcpController) AppHandleSSE(ctx *gin.Context) {
} }
ctx.Request.URL.Path = fmt.Sprintf("/openapi/v1/%s/sse", mcp_server.GlobalBasePath) ctx.Request.URL.Path = fmt.Sprintf("/openapi/v1/%s/sse", mcp_server.GlobalBasePath)
i.handleSSE(ctx, i.openServer, SessionInfo{ i.handleSSE(ctx, i.openSseServer, SessionInfo{
Apikey: apikey, Apikey: apikey,
App: appId, App: appId,
}) })
@@ -81,8 +82,29 @@ func (i *imlMcpController) AppHandleMessage(ctx *gin.Context) {
return return
} }
ctx.Request.URL.Path = fmt.Sprintf("/openapi/v1/%s/message", mcp_server.GlobalBasePath) ctx.Request.URL.Path = fmt.Sprintf("/openapi/v1/%s/message", mcp_server.GlobalBasePath)
ctx.Request = ctx.Request.WithContext(utils.SetLabel(ctx.Request.Context(), "app", appId)) //ctx.Request = ctx.Request.WithContext(utils.SetLabel(ctx.Request.Context(), "app", appId))
i.handleMessage(ctx, i.openServer) i.handleMessage(ctx, i.openSseServer)
}
func (i *imlMcpController) AppHandleStreamHTTP(ctx *gin.Context) {
apikey := ctx.Request.Header.Get("Authorization")
apikey = strings.TrimPrefix(apikey, "Bearer ")
if apikey == "" {
ctx.AbortWithStatusJSON(403, gin.H{"code": -1, "msg": "invalid apikey", "success": "fail"})
return
}
appId := ctx.Request.Header.Get("X-Application-Id")
if appId == "" {
ctx.AbortWithStatusJSON(403, gin.H{"code": -1, "msg": "invalid app id", "success": "fail"})
return
}
cfg := i.settingModule.Get(ctx)
req := ctx.Request.WithContext(utils.SetGatewayInvoke(ctx.Request.Context(), cfg.InvokeAddress))
req = req.WithContext(utils.SetLabel(req.Context(), "apikey", apikey))
req = req.WithContext(utils.SetLabel(req.Context(), "app", appId))
req.URL.Path = mcp_server.OpenGlobalMCPPath
i.openStreamableServer.ServeHTTP(ctx.Writer, req)
} }
func (i *imlMcpController) AppMCPConfig(ctx *gin.Context, appId string) (string, error) { func (i *imlMcpController) AppMCPConfig(ctx *gin.Context, appId string) (string, error) {
@@ -94,36 +116,44 @@ func (i *imlMcpController) AppMCPConfig(ctx *gin.Context, appId string) (string,
if err != nil { if err != nil {
return "", fmt.Errorf("get app info error: %v", err) return "", fmt.Errorf("get app info error: %v", err)
} }
return fmt.Sprintf(mcpDefaultConfig, appInfo.Name, fmt.Sprintf("%s/openapi/v1/mcp/app/%s/sse?apikey={your_api_key}", strings.TrimSuffix(cfg.SitePrefix, "/"), appId)), nil
}
var mcpDefaultConfig = `{ return mcp_server.NewMCPConfig(
"mcpServers": { mcp_server.TransportTypeStreamableHTTP,
"%s": { fmt.Sprintf("%s%s", strings.TrimSuffix(cfg.SitePrefix, "/"), mcp_server.OpenAppMCPPath),
"url": "%s" map[string]string{
} "Authorization": "Bearer {your_api_key}",
} "X-Application-Id": appId,
},
nil,
).ToString(appInfo.Name), nil
} }
`
func (i *imlMcpController) GlobalMCPConfig(ctx *gin.Context) (string, error) { func (i *imlMcpController) GlobalMCPConfig(ctx *gin.Context) (string, error) {
cfg := i.settingModule.Get(ctx) cfg := i.settingModule.Get(ctx)
if cfg.SitePrefix == "" { if cfg.SitePrefix == "" {
return "", fmt.Errorf("site prefix is empty") return "", fmt.Errorf("site prefix is empty")
} }
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 return mcp_server.NewMCPConfig(
mcp_server.TransportTypeStreamableHTTP,
fmt.Sprintf("%s%s", strings.TrimSuffix(cfg.SitePrefix, "/"), mcp_server.OpenGlobalMCPPath),
map[string]string{
"Authorization": "Bearer {your_api_key}",
},
nil,
).ToString("APIPark-MCP-Server"), nil
} }
func (i *imlMcpController) OnComplete() { func (i *imlMcpController) OnComplete() {
i.server = make(map[string]http.Handler) i.sseServers = make(map[string]http.Handler)
for language, tools := range mcpToolsByLanguage { for language, tools := range mcpToolsByLanguage {
s := server.NewMCPServer("APIPark MCP Server", "1.0.0", server.WithLogging()) s := server.NewMCPServer("APIPark MCP Server", "1.0.0", server.WithLogging())
s.AddTool(tools[ToolServiceList], i.mcpModule.Services) s.AddTool(tools[ToolServiceList], i.mcpModule.Services)
s.AddTool(tools[ToolOpenAPIDocument], i.mcpModule.APIs) s.AddTool(tools[ToolOpenAPIDocument], i.mcpModule.APIs)
s.AddTool(tools[ToolInvokeAPI], i.mcpModule.Invoke) s.AddTool(tools[ToolInvokeAPI], i.mcpModule.Invoke)
i.server[language] = server.NewSSEServer(s, server.WithStaticBasePath(fmt.Sprintf("/api/v1/%s", mcp_server.GlobalBasePath))) i.sseServers[language] = server.NewSSEServer(s, server.WithStaticBasePath(fmt.Sprintf("/api/v1/%s", mcp_server.GlobalBasePath)))
if language == languageEnUs { if language == languageEnUs {
i.openServer = server.NewSSEServer(s, server.WithStaticBasePath(fmt.Sprintf("/openapi/v1/%s", strings.Trim(mcp_server.GlobalBasePath, "/")))) i.openSseServer = server.NewSSEServer(s, server.WithStaticBasePath(fmt.Sprintf("/openapi/v1/%s", strings.Trim(mcp_server.GlobalBasePath, "/"))))
i.openStreamableServer = server.NewStreamableHTTPServer(s, server.WithEndpointPath(mcp_server.OpenGlobalMCPPath))
} }
} }
} }
@@ -132,16 +162,16 @@ func (i *imlMcpController) GlobalMCPHandle(ctx *gin.Context) {
cfg := i.settingModule.Get(ctx) cfg := i.settingModule.Get(ctx)
req := ctx.Request.WithContext(utils.SetGatewayInvoke(ctx.Request.Context(), cfg.InvokeAddress)) req := ctx.Request.WithContext(utils.SetGatewayInvoke(ctx.Request.Context(), cfg.InvokeAddress))
locale := utils.I18n(ctx) locale := utils.I18n(ctx)
if v, ok := i.server[locale]; ok { if v, ok := i.sseServers[locale]; ok {
v.ServeHTTP(ctx.Writer, req) v.ServeHTTP(ctx.Writer, req)
return return
} }
i.server[languageEnUs].ServeHTTP(ctx.Writer, req) i.sseServers[languageEnUs].ServeHTTP(ctx.Writer, req)
} }
func (i *imlMcpController) GlobalHandleSSE(ctx *gin.Context) { func (i *imlMcpController) GlobalHandleSSE(ctx *gin.Context) {
apikey := ctx.Request.URL.Query().Get("apikey") apikey := ctx.Request.URL.Query().Get("apikey")
i.handleSSE(ctx, i.openServer, SessionInfo{ i.handleSSE(ctx, i.openSseServer, SessionInfo{
Apikey: apikey, Apikey: apikey,
}) })
} }
@@ -167,7 +197,16 @@ func (i *imlMcpController) handleSSE(ctx *gin.Context, server http.Handler, sIn
} }
func (i *imlMcpController) GlobalHandleMessage(ctx *gin.Context) { func (i *imlMcpController) GlobalHandleMessage(ctx *gin.Context) {
i.handleMessage(ctx, i.openServer) i.handleMessage(ctx, i.openSseServer)
}
func (i *imlMcpController) GlobalHandleStreamHTTP(ctx *gin.Context) {
apikey := ctx.Request.Header.Get("Authorization")
apikey = strings.TrimPrefix(apikey, "Bearer ")
cfg := i.settingModule.Get(ctx)
req := ctx.Request.WithContext(utils.SetGatewayInvoke(ctx.Request.Context(), cfg.InvokeAddress))
req = req.WithContext(utils.SetLabel(req.Context(), "apikey", apikey))
i.openStreamableServer.ServeHTTP(ctx.Writer, req)
} }
func (i *imlMcpController) MCPHandle(ctx *gin.Context) { func (i *imlMcpController) MCPHandle(ctx *gin.Context) {
@@ -204,12 +243,13 @@ func (i *imlMcpController) ServiceHandleMessage(ctx *gin.Context) {
} }
func (i *imlMcpController) ServiceHandleStreamHTTP(ctx *gin.Context) { func (i *imlMcpController) ServiceHandleStreamHTTP(ctx *gin.Context) {
apikey := ctx.Request.URL.Query().Get("apikey") apikey := ctx.Request.Header.Get("Authorization")
serviceId := ctx.Param("serviceId") serviceId := ctx.Request.Header.Get("X-Service-Id")
if serviceId == "" { if serviceId == "" {
ctx.AbortWithStatusJSON(403, gin.H{"code": -1, "msg": "invalid service id", "success": "fail"}) ctx.AbortWithStatusJSON(403, gin.H{"code": -1, "msg": "invalid service id", "success": "fail"})
return return
} }
apikey = strings.TrimPrefix(apikey, "Bearer ")
ok, err := i.authorizationModule.CheckAPIKeyAuthorizationByService(ctx, serviceId, apikey) ok, err := i.authorizationModule.CheckAPIKeyAuthorizationByService(ctx, serviceId, apikey)
if err != nil { if err != nil {
ctx.AbortWithStatusJSON(403, gin.H{"code": -1, "msg": err.Error(), "success": "fail"}) ctx.AbortWithStatusJSON(403, gin.H{"code": -1, "msg": err.Error(), "success": "fail"})
+2
View File
@@ -13,11 +13,13 @@ type IMcpController interface {
GlobalMCPHandle(ctx *gin.Context) GlobalMCPHandle(ctx *gin.Context)
GlobalHandleSSE(ctx *gin.Context) GlobalHandleSSE(ctx *gin.Context)
GlobalHandleMessage(ctx *gin.Context) GlobalHandleMessage(ctx *gin.Context)
GlobalHandleStreamHTTP(ctx *gin.Context)
GlobalMCPConfig(ctx *gin.Context) (string, error) GlobalMCPConfig(ctx *gin.Context) (string, error)
AppMCPHandle(ctx *gin.Context) AppMCPHandle(ctx *gin.Context)
AppHandleSSE(ctx *gin.Context) AppHandleSSE(ctx *gin.Context)
AppHandleMessage(ctx *gin.Context) AppHandleMessage(ctx *gin.Context)
AppHandleStreamHTTP(ctx *gin.Context)
AppMCPConfig(ctx *gin.Context, appId string) (string, error) AppMCPConfig(ctx *gin.Context, appId string) (string, error)
ServiceHandleSSE(ctx *gin.Context) ServiceHandleSSE(ctx *gin.Context)
+16 -10
View File
@@ -520,16 +520,21 @@ func (i *imlServiceController) createAIService(ctx *gin.Context, teamID string,
modelId := "" modelId := ""
modelCfg := "" modelCfg := ""
modelType := "online" modelType := "online"
if input.Model != nil {
modelId = *input.Model
}
if *input.Provider == ai_provider_local.ProviderLocal { if *input.Provider == ai_provider_local.ProviderLocal {
modelType = "local" modelType = "local"
list, err := i.aiLocalModel.SimpleList(ctx) if modelId == "" {
if err != nil { list, err := i.aiLocalModel.SimpleList(ctx)
return nil, err if err != nil {
return nil, err
}
if len(list) == 0 {
return nil, fmt.Errorf("no local model")
}
modelId = list[0].Id
} }
if len(list) == 0 {
return nil, fmt.Errorf("no local model")
}
modelId = list[0].Id
modelCfg = ai_provider_local.LocalConfig modelCfg = ai_provider_local.LocalConfig
} else { } else {
pv, err := i.providerModule.Provider(ctx, *input.Provider) pv, err := i.providerModule.Provider(ctx, *input.Provider)
@@ -540,14 +545,15 @@ func (i *imlServiceController) createAIService(ctx *gin.Context, teamID string,
if !has { if !has {
return nil, fmt.Errorf("provider not found") return nil, fmt.Errorf("provider not found")
} }
m, has := p.GetModel(pv.DefaultLLM) if modelId == "" {
modelId = pv.DefaultLLM
}
m, has := p.GetModel(modelId)
if !has { if !has {
return nil, fmt.Errorf("model %s not found", pv.DefaultLLM) return nil, fmt.Errorf("model %s not found", pv.DefaultLLM)
} }
//modelId = m.ID()
modelId = m.Name() modelId = m.Name()
modelCfg = m.DefaultConfig() modelCfg = m.DefaultConfig()
} }
var info *service_dto.Service var info *service_dto.Service
@@ -74,15 +74,11 @@ const ServiceHubDetail = () => {
// 添加servers部分 // 添加servers部分
if (!apiDoc.includes('servers:')) { if (!apiDoc.includes('servers:')) {
const serverConfig = `info: const serverConfig = `servers:
title: API Space API
version: 1.0.0
openapi: 3.0.1
servers:
- url: ${apiPrefix} - url: ${apiPrefix}
description: 默认服务器 description: 默认服务器
` `
result = serverConfig + result.substring(result.indexOf('paths:')) result = apiDoc.substring(0, pathsIndex) + serverConfig + apiDoc.substring(pathsIndex, pathsIndex + 6)
} }
// 处理路径 // 处理路径
@@ -93,11 +89,19 @@ servers:
const trimmedLine = line.trim() const trimmedLine = line.trim()
// 检测是否是路径行 // 检测是否是路径行
if (trimmedLine.match(/^\//)) { if (trimmedLine.match(/^['"]?\/.*['"]?:/)) {
// 这是一个路径行 // 这是一个路径行
const indentation = line.substring(0, line.indexOf('/')) const pathMatch = line.match(/^(\s*)['"]?(\/[^'"]*)['"]?:\s*$/)
const pathWithoutIndent = line.substring(line.indexOf('/')) if (pathMatch) {
lines[i] = indentation + apiPrefix + pathWithoutIndent const indentation = pathMatch[1]
const actualPath = pathMatch[2]
lines[i] = `${indentation}'${apiPrefix}${actualPath}':`
} else {
const indentation = line.substring(0, line.indexOf('/'))
const pathWithoutIndent = line.substring(line.indexOf('/'))
const cleanPath = pathWithoutIndent.replace(/:\s*$/, '').replace(/['"]/g, '')
lines[i] = `${indentation}'${apiPrefix}${cleanPath}':`
}
} }
} }
+5 -3
View File
@@ -15,7 +15,7 @@ require (
github.com/go-sql-driver/mysql v1.7.0 github.com/go-sql-driver/mysql v1.7.0
github.com/google/uuid v1.6.0 github.com/google/uuid v1.6.0
github.com/influxdata/influxdb-client-go/v2 v2.14.0 github.com/influxdata/influxdb-client-go/v2 v2.14.0
github.com/mark3labs/mcp-go v0.33.0 github.com/mark3labs/mcp-go v0.42.0-beta.3
github.com/mitchellh/mapstructure v1.5.0 github.com/mitchellh/mapstructure v1.5.0
github.com/nsqio/go-nsq v1.1.0 github.com/nsqio/go-nsq v1.1.0
github.com/ollama/ollama v0.5.8 github.com/ollama/ollama v0.5.8
@@ -27,6 +27,8 @@ require (
require ( require (
github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
github.com/bahlo/generic-list-go v0.2.0 // indirect
github.com/buger/jsonparser v1.1.1 // indirect
github.com/bytedance/sonic v1.11.6 // indirect github.com/bytedance/sonic v1.11.6 // indirect
github.com/bytedance/sonic/loader v0.1.1 // indirect github.com/bytedance/sonic/loader v0.1.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect
@@ -46,6 +48,7 @@ require (
github.com/golang/snappy v0.0.4 // indirect github.com/golang/snappy v0.0.4 // indirect
github.com/gorilla/websocket v1.4.2 // indirect github.com/gorilla/websocket v1.4.2 // indirect
github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 // indirect github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 // indirect
github.com/invopop/jsonschema v0.13.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect github.com/jinzhu/now v1.1.5 // indirect
github.com/josharian/intern v1.0.0 // indirect github.com/josharian/intern v1.0.0 // indirect
@@ -67,6 +70,7 @@ require (
github.com/spf13/cast v1.7.1 // indirect github.com/spf13/cast v1.7.1 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect github.com/ugorji/go/codec v1.2.12 // indirect
github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
go.etcd.io/etcd/client/pkg/v3 v3.5.13 // indirect go.etcd.io/etcd/client/pkg/v3 v3.5.13 // indirect
go.uber.org/atomic v1.7.0 // indirect go.uber.org/atomic v1.7.0 // indirect
@@ -87,6 +91,4 @@ require (
//) //)
//replace github.com/eolinker/ap-account => ../../eolinker/ap-account //replace github.com/eolinker/ap-account => ../../eolinker/ap-account
//
//replace github.com/eolinker/go-common => ../../eolinker/go-common //replace github.com/eolinker/go-common => ../../eolinker/go-common
+10 -2
View File
@@ -2,6 +2,8 @@ github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2
github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk= github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk=
github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ= github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ=
github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk= github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk=
github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w= github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
@@ -9,6 +11,8 @@ github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0= github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4= github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM= github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
@@ -80,6 +84,8 @@ github.com/influxdata/influxdb-client-go/v2 v2.14.0 h1:AjbBfJuq+QoaXNcrova8smSjw
github.com/influxdata/influxdb-client-go/v2 v2.14.0/go.mod h1:Ahpm3QXKMJslpXl3IftVLVezreAUtBOTZssDrjZEFHI= github.com/influxdata/influxdb-client-go/v2 v2.14.0/go.mod h1:Ahpm3QXKMJslpXl3IftVLVezreAUtBOTZssDrjZEFHI=
github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 h1:W9WBk7wlPfJLvMCdtV4zPulc4uCPrlywQOmbFOhgQNU= github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 h1:W9WBk7wlPfJLvMCdtV4zPulc4uCPrlywQOmbFOhgQNU=
github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo=
github.com/invopop/jsonschema v0.13.0 h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcIi21E=
github.com/invopop/jsonschema v0.13.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
@@ -101,8 +107,8 @@ github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mark3labs/mcp-go v0.33.0 h1:naxhjnTIs/tyPZmWUZFuG0lDmdA6sUyYGGf3gsHvTCc= github.com/mark3labs/mcp-go v0.42.0-beta.3 h1:nmOg1HFgSOgy0bZkAQ+E6qVpPMPmE8hIkM0BO94Ks9k=
github.com/mark3labs/mcp-go v0.33.0/go.mod h1:rXqOudj/djTORU/ThxYx8fqEVj/5pvTuuebQ2RC7uk4= github.com/mark3labs/mcp-go v0.42.0-beta.3/go.mod h1:YnJfOL382MIWDx1kMY+2zsRHU/q78dBg9aFb8W6Thdw=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
@@ -159,6 +165,8 @@ github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65E
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/urfave/cli v1.22.16 h1:MH0k6uJxdwdeWQTwhSO42Pwr4YLrNLwBtg1MRgTqPdQ= github.com/urfave/cli v1.22.16 h1:MH0k6uJxdwdeWQTwhSO42Pwr4YLrNLwBtg1MRgTqPdQ=
github.com/urfave/cli v1.22.16/go.mod h1:EeJR6BKodywf4zciqrdw6hpCPk68JO9z5LazXZMn5Po= github.com/urfave/cli v1.22.16/go.mod h1:EeJR6BKodywf4zciqrdw6hpCPk68JO9z5LazXZMn5Po=
github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc=
github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4= github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4=
github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4= github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4=
go.etcd.io/etcd/client/pkg/v3 v3.5.13 h1:RVZSAnWWWiI5IrYAXjQorajncORbS0zI48LQlE2kQWg= go.etcd.io/etcd/client/pkg/v3 v3.5.13 h1:RVZSAnWWWiI5IrYAXjQorajncORbS0zI48LQlE2kQWg=
+36
View File
@@ -0,0 +1,36 @@
package mcp_server
import "encoding/json"
type TransportType string
const (
TransportTypeStreamableHTTP TransportType = "streamable-http"
TransportTypeSSE TransportType = "sse"
)
func NewMCPConfig(typ TransportType, url string, headers map[string]string, alwaysAllow []string) *MCPConfig {
return &MCPConfig{
Type: typ,
URL: url,
Headers: headers,
AlwaysAllow: alwaysAllow,
}
}
type MCPConfig struct {
Type TransportType `json:"type"`
URL string `json:"url"`
Headers map[string]string `json:"headers,omitempty"`
AlwaysAllow []string `json:"alwaysAllow,omitempty"`
}
func (c *MCPConfig) ToString(name string) string {
m := map[string]interface{}{
"mcpServers": map[string]interface{}{
name: c,
},
}
data, _ := json.MarshalIndent(m, "", "\t")
return string(data)
}
+21 -6
View File
@@ -17,6 +17,10 @@ var (
ServiceBasePath = "mcp/service" ServiceBasePath = "mcp/service"
GlobalBasePath = "mcp/global" GlobalBasePath = "mcp/global"
AppBasePath = "mcp/app" AppBasePath = "mcp/app"
OpenGlobalMCPPath = "/openapi/v1/global/mcp"
OpenAppMCPPath = "/openapi/v1/app/mcp"
OpenServiceMCPPath = "/openapi/v1/service/mcp"
) )
func NewServer() *Server { func NewServer() *Server {
@@ -61,7 +65,7 @@ func (s *Server) Set(id string, ser *server.MCPServer) {
} }
tmp.handlers["api-sse"] = server.NewSSEServer(ser, server.WithStaticBasePath(fmt.Sprintf("/api/v1/%s/%s", ServiceBasePath, id))) tmp.handlers["api-sse"] = server.NewSSEServer(ser, server.WithStaticBasePath(fmt.Sprintf("/api/v1/%s/%s", ServiceBasePath, id)))
tmp.handlers["openapi-sse"] = server.NewSSEServer(ser, server.WithStaticBasePath(fmt.Sprintf("/openapi/v1/%s/%s", ServiceBasePath, id))) tmp.handlers["openapi-sse"] = server.NewSSEServer(ser, server.WithStaticBasePath(fmt.Sprintf("/openapi/v1/%s/%s", ServiceBasePath, id)))
tmp.handlers["openapi-stream"] = server.NewStreamableHTTPServer(ser, server.WithEndpointPath(fmt.Sprintf("/openapi/v1/%s/%s/mcp", ServiceBasePath, id))) tmp.handlers["openapi-stream"] = server.NewStreamableHTTPServer(ser, server.WithEndpointPath(OpenServiceMCPPath))
s.servers[id] = tmp s.servers[id] = tmp
} }
@@ -91,12 +95,23 @@ func (s *Server) Get(id string) (*Handler, bool) {
} }
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
sid, err := genPath(r.URL.Path) var sid string
if err != nil { if r.URL.Path == OpenServiceMCPPath {
w.WriteHeader(http.StatusBadRequest) sid = r.Header.Get("X-Service-Id")
w.Write([]byte(err.Error())) if sid == "" {
return http.NotFound(w, r)
return
}
} else {
id, err := genPath(r.URL.Path)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
return
}
sid = id
} }
ser, has := s.Get(sid) ser, has := s.Get(sid)
if has { if has {
ser.ServeHTTP(w, r) ser.ServeHTTP(w, r)
+44 -38
View File
@@ -219,19 +219,19 @@ func (i *imlAuthorizationModule) initGateway(ctx context.Context, partitionId st
return clientDriver.Application().Online(ctx, applications...) return clientDriver.Application().Online(ctx, applications...)
} }
func (i *imlAuthorizationModule) online(ctx context.Context, s *service.Service) error { func (i *imlAuthorizationModule) getApplicationRelease(ctx context.Context, s *service.Service) (*gateway.ApplicationRelease, error) {
clusters, err := i.clusterService.List(ctx)
if err != nil {
return err
}
if len(clusters) < 1 {
return nil
}
authorizations, err := i.authorizationService.ListByApp(ctx, s.Id) authorizations, err := i.authorizationService.ListByApp(ctx, s.Id)
if err != nil { if err != nil {
return err return nil, err
} }
app := &gateway.ApplicationRelease{ if len(authorizations) < 1 {
return &gateway.ApplicationRelease{
BasicItem: &gateway.BasicItem{
ID: s.Id,
},
}, nil
}
return &gateway.ApplicationRelease{
BasicItem: &gateway.BasicItem{ BasicItem: &gateway.BasicItem{
ID: s.Id, ID: s.Id,
Description: s.Description, Description: s.Description,
@@ -256,10 +256,40 @@ func (i *imlAuthorizationModule) online(ctx context.Context, s *service.Service)
}, },
} }
}), }),
}, nil
}
func (i *imlAuthorizationModule) doOffline(ctx context.Context, clusterId string, app *gateway.ApplicationRelease) error {
client, err := i.clusterService.GatewayClient(ctx, clusterId)
if err != nil {
return err
} }
defer func() {
_ = client.Close(ctx)
}()
return client.Application().Offline(ctx, app)
}
func (i *imlAuthorizationModule) online(ctx context.Context, s *service.Service) error {
clusters, err := i.clusterService.List(ctx)
if err != nil {
return err
}
if len(clusters) < 1 {
return nil
}
release, err := i.getApplicationRelease(ctx, s)
if err != nil {
return err
}
for _, c := range clusters { for _, c := range clusters {
err := i.doOnline(ctx, c.Uuid, app) if len(release.Authorizations) < 1 {
err = i.doOffline(ctx, c.Uuid, release)
if err != nil {
log.Warnf("service authorization offline for cluster[%s] %v", c.Name, err)
}
continue
}
err = i.doOnline(ctx, c.Uuid, release)
if err != nil { if err != nil {
log.Warnf("service authorization online for cluster[%s] %v", c.Name, err) log.Warnf("service authorization online for cluster[%s] %v", c.Name, err)
} }
@@ -375,7 +405,7 @@ func (i *imlAuthorizationModule) EditAuthorization(ctx context.Context, appId st
} }
func (i *imlAuthorizationModule) DeleteAuthorization(ctx context.Context, pid string, aid string) error { func (i *imlAuthorizationModule) DeleteAuthorization(ctx context.Context, pid string, aid string) error {
_, err := i.serviceService.Get(ctx, pid) s, err := i.serviceService.Get(ctx, pid)
if err != nil { if err != nil {
return err return err
} }
@@ -385,35 +415,11 @@ func (i *imlAuthorizationModule) DeleteAuthorization(ctx context.Context, pid st
if err != nil { if err != nil {
return err return err
} }
clusters, err := i.clusterService.List(ctx)
if err != nil { return i.online(ctx, s)
return err
}
app := &gateway.ApplicationRelease{
BasicItem: &gateway.BasicItem{
ID: pid,
},
}
for _, c := range clusters {
err := i.doOffline(ctx, c.Uuid, app)
if err != nil {
log.Warnf("service authorization offline for cluster[%s] %v", c.Name, err)
}
}
return nil
}) })
} }
func (i *imlAuthorizationModule) doOffline(ctx context.Context, clusterId string, app *gateway.ApplicationRelease) error {
client, err := i.clusterService.GatewayClient(ctx, clusterId)
if err != nil {
return err
}
defer func() {
_ = client.Close(ctx)
}()
return client.Application().Offline(ctx, app)
}
func (i *imlAuthorizationModule) Authorizations(ctx context.Context, pid string) ([]*application_authorization_dto.AuthorizationItem, error) { func (i *imlAuthorizationModule) Authorizations(ctx context.Context, pid string) ([]*application_authorization_dto.AuthorizationItem, error) {
_, err := i.serviceService.Get(ctx, pid) _, err := i.serviceService.Get(ctx, pid)
if err != nil { if err != nil {
+11 -13
View File
@@ -9,10 +9,10 @@ import (
"strings" "strings"
"time" "time"
service_overview "github.com/APIParkLab/APIPark/service/service-overview"
mcp_server "github.com/APIParkLab/APIPark/mcp-server" mcp_server "github.com/APIParkLab/APIPark/mcp-server"
service_overview "github.com/APIParkLab/APIPark/service/service-overview"
"github.com/APIParkLab/APIPark/module/monitor/driver" "github.com/APIParkLab/APIPark/module/monitor/driver"
"github.com/APIParkLab/APIPark/service/monitor" "github.com/APIParkLab/APIPark/service/monitor"
@@ -326,15 +326,6 @@ func (i *imlCatalogueModule) Subscribe(ctx context.Context, subscribeInfo *catal
}) })
} }
var mcpDefaultConfig = `{
"mcpServers": {
"%s": {
"url": "%s"
}
}
}
`
func (i *imlCatalogueModule) ServiceDetail(ctx context.Context, sid string) (*catalogue_dto.ServiceDetail, error) { func (i *imlCatalogueModule) ServiceDetail(ctx context.Context, sid string) (*catalogue_dto.ServiceDetail, error) {
// 获取服务的基本信息 // 获取服务的基本信息
s, err := i.serviceService.Get(ctx, sid) s, err := i.serviceService.Get(ctx, sid)
@@ -400,8 +391,15 @@ func (i *imlCatalogueModule) ServiceDetail(ctx context.Context, sid string) (*ca
mcpAccessConfig := "" mcpAccessConfig := ""
if s.EnableMCP { if s.EnableMCP {
if sitePrefix != "" { if sitePrefix != "" {
mcpAccessAddress = fmt.Sprintf("%s/openapi/v1/%s/%s/sse?apikey={your_api_key}", strings.TrimSuffix(sitePrefix, "/"), mcp_server.ServiceBasePath, s.Id) mcpAccessConfig = mcp_server.NewMCPConfig(
mcpAccessConfig = fmt.Sprintf(mcpDefaultConfig, fmt.Sprintf("APIPark/%s", s.Name), mcpAccessAddress) mcp_server.TransportTypeStreamableHTTP,
fmt.Sprintf("%s/openapi/v1/service/mcp", strings.TrimSuffix(sitePrefix, "/")),
map[string]string{
"Authorization": "Bearer {your_api_key}",
"X-Service-Id": s.Id,
},
nil,
).ToString(fmt.Sprintf("APIPark/%s", s.Name))
} }
} }
invokeMap, err := i.ProviderStatistics(ctx, time.Now().Add(-24*30*time.Hour), time.Now(), s.Id) invokeMap, err := i.ProviderStatistics(ctx, time.Now().Add(-24*30*time.Hour), time.Now(), s.Id)
+4
View File
@@ -17,12 +17,16 @@ func (p *plugin) mcpAPIs() []pm3.Api {
globalMessagePath := fmt.Sprintf("/api/v1/%s/message", mcp_server.GlobalBasePath) globalMessagePath := fmt.Sprintf("/api/v1/%s/message", mcp_server.GlobalBasePath)
appSSEPath := fmt.Sprintf("/api/v1/%s/sse", mcp_server.AppBasePath) appSSEPath := fmt.Sprintf("/api/v1/%s/sse", mcp_server.AppBasePath)
appMessagePath := fmt.Sprintf("/api/v1/%s/message", mcp_server.AppBasePath) appMessagePath := fmt.Sprintf("/api/v1/%s/message", mcp_server.AppBasePath)
globalMcpPath := fmt.Sprintf("/api/v1/%s/mcp", mcp_server.GlobalBasePath)
appMcpPath := fmt.Sprintf("/api/v1/%s/mcp", mcp_server.AppBasePath)
ignore.IgnorePath("login", http.MethodGet, serviceSSEPath) ignore.IgnorePath("login", http.MethodGet, serviceSSEPath)
ignore.IgnorePath("login", http.MethodPost, serviceMessagePath) ignore.IgnorePath("login", http.MethodPost, serviceMessagePath)
ignore.IgnorePath("login", http.MethodGet, globalSSEPath) ignore.IgnorePath("login", http.MethodGet, globalSSEPath)
ignore.IgnorePath("login", http.MethodPost, globalMessagePath) ignore.IgnorePath("login", http.MethodPost, globalMessagePath)
ignore.IgnorePath("login", http.MethodGet, appSSEPath) ignore.IgnorePath("login", http.MethodGet, appSSEPath)
ignore.IgnorePath("login", http.MethodPost, appMessagePath) ignore.IgnorePath("login", http.MethodPost, appMessagePath)
ignore.IgnorePath("login", http.MethodGet, globalMcpPath)
ignore.IgnorePath("login", http.MethodGet, appMcpPath)
return []pm3.Api{ return []pm3.Api{
pm3.CreateApiSimple(http.MethodGet, serviceSSEPath, p.mcpController.MCPHandle), pm3.CreateApiSimple(http.MethodGet, serviceSSEPath, p.mcpController.MCPHandle),
pm3.CreateApiSimple(http.MethodPost, serviceMessagePath, p.mcpController.MCPHandle), pm3.CreateApiSimple(http.MethodPost, serviceMessagePath, p.mcpController.MCPHandle),
+1
View File
@@ -60,6 +60,7 @@ func (o *openapiCheck) Handler(ginCtx *gin.Context) {
} }
authorization = apikey authorization = apikey
} }
authorization = strings.TrimPrefix(authorization, "Bearer ")
if authorization == o.apikey { if authorization == o.apikey {
return return
} }
+21 -8
View File
@@ -19,17 +19,22 @@ func (p *plugin) mcpAPIs() []pm3.Api {
serviceSSEPath := fmt.Sprintf("/openapi/v1/%s/:serviceId/sse", strings.Trim(mcp_server.ServiceBasePath, "/")) serviceSSEPath := fmt.Sprintf("/openapi/v1/%s/:serviceId/sse", strings.Trim(mcp_server.ServiceBasePath, "/"))
serviceMessagePath := fmt.Sprintf("/openapi/v1/%s/:serviceId/message", strings.Trim(mcp_server.ServiceBasePath, "/")) serviceMessagePath := fmt.Sprintf("/openapi/v1/%s/:serviceId/message", strings.Trim(mcp_server.ServiceBasePath, "/"))
serviceStreamablePath := fmt.Sprintf("/openapi/v1/%s/:serviceId/mcp", strings.Trim(mcp_server.ServiceBasePath, "/")) //serviceStreamablePath := fmt.Sprintf("/openapi/v1/%s/:serviceId/mcp", strings.Trim(mcp_server.ServiceBasePath, "/"))
ignore.IgnorePath("openapi", http.MethodPost, globalMessagePath) ignore.IgnorePath("openapi", http.MethodPost, globalMessagePath)
ignore.IgnorePath("openapi", http.MethodGet, globalSSEPath) //ignore.IgnorePath("openapi", http.MethodGet, globalSSEPath)
ignore.IgnorePath("openapi", http.MethodPost, appMessagePath) ignore.IgnorePath("openapi", http.MethodPost, appMessagePath)
ignore.IgnorePath("openapi", http.MethodGet, appSSEPath) ignore.IgnorePath("openapi", http.MethodGet, appSSEPath)
ignore.IgnorePath("openapi", http.MethodGet, serviceSSEPath) ignore.IgnorePath("openapi", http.MethodGet, serviceSSEPath)
ignore.IgnorePath("openapi", http.MethodPost, serviceMessagePath) ignore.IgnorePath("openapi", http.MethodPost, serviceMessagePath)
ignore.IgnorePath("openapi", http.MethodGet, serviceStreamablePath)
ignore.IgnorePath("openapi", http.MethodPost, serviceStreamablePath) ignore.IgnorePath("openapi", http.MethodGet, mcp_server.OpenAppMCPPath)
ignore.IgnorePath("openapi", http.MethodDelete, serviceStreamablePath) ignore.IgnorePath("openapi", http.MethodPost, mcp_server.OpenAppMCPPath)
ignore.IgnorePath("openapi", http.MethodDelete, mcp_server.OpenAppMCPPath)
ignore.IgnorePath("openapi", http.MethodGet, mcp_server.OpenServiceMCPPath)
ignore.IgnorePath("openapi", http.MethodPost, mcp_server.OpenServiceMCPPath)
ignore.IgnorePath("openapi", http.MethodDelete, mcp_server.OpenServiceMCPPath)
return []pm3.Api{ return []pm3.Api{
pm3.CreateApiSimple(http.MethodGet, globalSSEPath, p.mcpController.GlobalHandleSSE), pm3.CreateApiSimple(http.MethodGet, globalSSEPath, p.mcpController.GlobalHandleSSE),
@@ -41,9 +46,17 @@ func (p *plugin) mcpAPIs() []pm3.Api {
pm3.CreateApiSimple(http.MethodGet, serviceSSEPath, p.mcpController.ServiceHandleSSE), pm3.CreateApiSimple(http.MethodGet, serviceSSEPath, p.mcpController.ServiceHandleSSE),
pm3.CreateApiSimple(http.MethodPost, serviceMessagePath, p.mcpController.ServiceHandleMessage), pm3.CreateApiSimple(http.MethodPost, serviceMessagePath, p.mcpController.ServiceHandleMessage),
pm3.CreateApiSimple(http.MethodPost, serviceStreamablePath, p.mcpController.ServiceHandleStreamHTTP), pm3.CreateApiSimple(http.MethodGet, mcp_server.OpenGlobalMCPPath, p.mcpController.GlobalHandleStreamHTTP),
pm3.CreateApiSimple(http.MethodDelete, serviceStreamablePath, p.mcpController.ServiceHandleStreamHTTP), pm3.CreateApiSimple(http.MethodPost, mcp_server.OpenGlobalMCPPath, p.mcpController.GlobalHandleStreamHTTP),
pm3.CreateApiSimple(http.MethodGet, serviceStreamablePath, p.mcpController.ServiceHandleStreamHTTP), pm3.CreateApiSimple(http.MethodDelete, mcp_server.OpenGlobalMCPPath, p.mcpController.GlobalHandleStreamHTTP),
pm3.CreateApiSimple(http.MethodGet, mcp_server.OpenAppMCPPath, p.mcpController.AppHandleStreamHTTP),
pm3.CreateApiSimple(http.MethodPost, mcp_server.OpenAppMCPPath, p.mcpController.AppHandleStreamHTTP),
pm3.CreateApiSimple(http.MethodDelete, mcp_server.OpenAppMCPPath, p.mcpController.AppHandleStreamHTTP),
pm3.CreateApiSimple(http.MethodPost, mcp_server.OpenServiceMCPPath, p.mcpController.ServiceHandleStreamHTTP),
pm3.CreateApiSimple(http.MethodDelete, mcp_server.OpenServiceMCPPath, p.mcpController.ServiceHandleStreamHTTP),
pm3.CreateApiSimple(http.MethodGet, mcp_server.OpenServiceMCPPath, p.mcpController.ServiceHandleStreamHTTP),
} }
} }
+2 -1
View File
@@ -3,10 +3,11 @@ package commit
import ( import (
"context" "context"
"errors" "errors"
"github.com/eolinker/go-common/utils"
"strings" "strings"
"time" "time"
"github.com/eolinker/go-common/utils"
"github.com/eolinker/go-common/store" "github.com/eolinker/go-common/store"
"github.com/google/uuid" "github.com/google/uuid"
"gorm.io/gorm" "gorm.io/gorm"