diff --git a/controller/mcp/iml.go b/controller/mcp/iml.go index aa27cfe1..dfd1eac2 100644 --- a/controller/mcp/iml.go +++ b/controller/mcp/iml.go @@ -21,13 +21,14 @@ import ( var _ IMcpController = (*imlMcpController)(nil) type imlMcpController struct { - settingModule system.ISettingModule `autowired:""` - authorizationModule application_authorization.IAuthorizationModule `autowired:""` - appModule service.IAppModule `autowired:""` - mcpModule mcp.IMcpModule `autowired:""` - sessionKeys sync.Map - server map[string]http.Handler - openServer http.Handler + settingModule system.ISettingModule `autowired:""` + authorizationModule application_authorization.IAuthorizationModule `autowired:""` + appModule service.IAppModule `autowired:""` + mcpModule mcp.IMcpModule `autowired:""` + sessionKeys sync.Map + sseServers map[string]http.Handler + openSseServer http.Handler + openStreamableServer http.Handler } func (i *imlMcpController) AppMCPHandle(ctx *gin.Context) { @@ -42,12 +43,12 @@ func (i *imlMcpController) AppMCPHandle(ctx *gin.Context) { paths := strings.Split(req.URL.Path, "/") req.URL.Path = fmt.Sprintf("/api/v1/%s/%s", mcp_server.GlobalBasePath, paths[len(paths)-1]) locale := utils.I18n(ctx) - if v, ok := i.server[locale]; ok { + if v, ok := i.sseServers[locale]; ok { v.ServeHTTP(ctx.Writer, req) return } - i.server[languageEnUs].ServeHTTP(ctx.Writer, req) + i.sseServers[languageEnUs].ServeHTTP(ctx.Writer, req) } 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) - i.handleSSE(ctx, i.openServer, SessionInfo{ + i.handleSSE(ctx, i.openSseServer, SessionInfo{ Apikey: apikey, App: appId, }) @@ -81,8 +82,29 @@ func (i *imlMcpController) AppHandleMessage(ctx *gin.Context) { return } 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)) - i.handleMessage(ctx, i.openServer) + //ctx.Request = ctx.Request.WithContext(utils.SetLabel(ctx.Request.Context(), "app", appId)) + 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) { @@ -94,36 +116,44 @@ func (i *imlMcpController) AppMCPConfig(ctx *gin.Context, appId string) (string, if err != nil { 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 = `{ - "mcpServers": { - "%s": { - "url": "%s" - } - } + return mcp_server.NewMCPConfig( + mcp_server.TransportTypeStreamableHTTP, + fmt.Sprintf("%s%s", strings.TrimSuffix(cfg.SitePrefix, "/"), mcp_server.OpenAppMCPPath), + 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) { cfg := i.settingModule.Get(ctx) if cfg.SitePrefix == "" { 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() { - i.server = make(map[string]http.Handler) + i.sseServers = make(map[string]http.Handler) for language, tools := range mcpToolsByLanguage { s := server.NewMCPServer("APIPark MCP Server", "1.0.0", server.WithLogging()) s.AddTool(tools[ToolServiceList], i.mcpModule.Services) s.AddTool(tools[ToolOpenAPIDocument], i.mcpModule.APIs) 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 { - 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) req := ctx.Request.WithContext(utils.SetGatewayInvoke(ctx.Request.Context(), cfg.InvokeAddress)) locale := utils.I18n(ctx) - if v, ok := i.server[locale]; ok { + if v, ok := i.sseServers[locale]; ok { v.ServeHTTP(ctx.Writer, req) return } - i.server[languageEnUs].ServeHTTP(ctx.Writer, req) + i.sseServers[languageEnUs].ServeHTTP(ctx.Writer, req) } func (i *imlMcpController) GlobalHandleSSE(ctx *gin.Context) { apikey := ctx.Request.URL.Query().Get("apikey") - i.handleSSE(ctx, i.openServer, SessionInfo{ + i.handleSSE(ctx, i.openSseServer, SessionInfo{ Apikey: apikey, }) } @@ -167,7 +197,16 @@ func (i *imlMcpController) handleSSE(ctx *gin.Context, server http.Handler, sIn } 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) { @@ -204,12 +243,13 @@ func (i *imlMcpController) ServiceHandleMessage(ctx *gin.Context) { } func (i *imlMcpController) ServiceHandleStreamHTTP(ctx *gin.Context) { - apikey := ctx.Request.URL.Query().Get("apikey") - serviceId := ctx.Param("serviceId") + apikey := ctx.Request.Header.Get("Authorization") + serviceId := ctx.Request.Header.Get("X-Service-Id") if serviceId == "" { ctx.AbortWithStatusJSON(403, gin.H{"code": -1, "msg": "invalid service id", "success": "fail"}) return } + apikey = strings.TrimPrefix(apikey, "Bearer ") ok, err := i.authorizationModule.CheckAPIKeyAuthorizationByService(ctx, serviceId, apikey) if err != nil { ctx.AbortWithStatusJSON(403, gin.H{"code": -1, "msg": err.Error(), "success": "fail"}) diff --git a/controller/mcp/mcp.go b/controller/mcp/mcp.go index a2064ae7..06722bce 100644 --- a/controller/mcp/mcp.go +++ b/controller/mcp/mcp.go @@ -13,11 +13,13 @@ type IMcpController interface { GlobalMCPHandle(ctx *gin.Context) GlobalHandleSSE(ctx *gin.Context) GlobalHandleMessage(ctx *gin.Context) + GlobalHandleStreamHTTP(ctx *gin.Context) GlobalMCPConfig(ctx *gin.Context) (string, error) AppMCPHandle(ctx *gin.Context) AppHandleSSE(ctx *gin.Context) AppHandleMessage(ctx *gin.Context) + AppHandleStreamHTTP(ctx *gin.Context) AppMCPConfig(ctx *gin.Context, appId string) (string, error) ServiceHandleSSE(ctx *gin.Context) diff --git a/go.mod b/go.mod index 42515ee9..b17b6d8a 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( github.com/go-sql-driver/mysql v1.7.0 github.com/google/uuid v1.6.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/nsqio/go-nsq v1.1.0 github.com/ollama/ollama v0.5.8 @@ -27,6 +27,8 @@ require ( require ( 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/loader v0.1.1 // 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/gorilla/websocket v1.4.2 // 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/now v1.1.5 // indirect github.com/josharian/intern v1.0.0 // indirect @@ -67,6 +70,7 @@ require ( github.com/spf13/cast v1.7.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // 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 go.etcd.io/etcd/client/pkg/v3 v3.5.13 // 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/go-common => ../../eolinker/go-common diff --git a/go.sum b/go.sum index fa215679..a244eac5 100644 --- a/go.sum +++ b/go.sum @@ -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/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/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/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= 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/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= 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/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4= 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/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/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/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= 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/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= 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.33.0/go.mod h1:rXqOudj/djTORU/ThxYx8fqEVj/5pvTuuebQ2RC7uk4= +github.com/mark3labs/mcp-go v0.42.0-beta.3 h1:nmOg1HFgSOgy0bZkAQ+E6qVpPMPmE8hIkM0BO94Ks9k= +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/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 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/urfave/cli v1.22.16 h1:MH0k6uJxdwdeWQTwhSO42Pwr4YLrNLwBtg1MRgTqPdQ= 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/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4= go.etcd.io/etcd/client/pkg/v3 v3.5.13 h1:RVZSAnWWWiI5IrYAXjQorajncORbS0zI48LQlE2kQWg= diff --git a/mcp-server/config.go b/mcp-server/config.go new file mode 100644 index 00000000..18b19cbc --- /dev/null +++ b/mcp-server/config.go @@ -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) +} diff --git a/mcp-server/server.go b/mcp-server/server.go index 0dad3cb9..c72c4f5d 100644 --- a/mcp-server/server.go +++ b/mcp-server/server.go @@ -17,6 +17,10 @@ var ( ServiceBasePath = "mcp/service" GlobalBasePath = "mcp/global" AppBasePath = "mcp/app" + + OpenGlobalMCPPath = "/openapi/v1/global/mcp" + OpenAppMCPPath = "/openapi/v1/app/mcp" + OpenServiceMCPPath = "/openapi/v1/service/mcp" ) 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["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 } @@ -91,12 +95,23 @@ func (s *Server) Get(id string) (*Handler, bool) { } func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { - sid, err := genPath(r.URL.Path) - if err != nil { - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte(err.Error())) - return + var sid string + if r.URL.Path == OpenServiceMCPPath { + sid = r.Header.Get("X-Service-Id") + if sid == "" { + 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) if has { ser.ServeHTTP(w, r) diff --git a/module/catalogue/iml.go b/module/catalogue/iml.go index ee0aa942..4952c911 100644 --- a/module/catalogue/iml.go +++ b/module/catalogue/iml.go @@ -9,10 +9,10 @@ import ( "strings" "time" - service_overview "github.com/APIParkLab/APIPark/service/service-overview" - 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/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) { // 获取服务的基本信息 s, err := i.serviceService.Get(ctx, sid) @@ -400,8 +391,15 @@ func (i *imlCatalogueModule) ServiceDetail(ctx context.Context, sid string) (*ca mcpAccessConfig := "" if s.EnableMCP { if sitePrefix != "" { - mcpAccessAddress = fmt.Sprintf("%s/openapi/v1/%s/%s/sse?apikey={your_api_key}", strings.TrimSuffix(sitePrefix, "/"), mcp_server.ServiceBasePath, s.Id) - mcpAccessConfig = fmt.Sprintf(mcpDefaultConfig, fmt.Sprintf("APIPark/%s", s.Name), mcpAccessAddress) + mcpAccessConfig = mcp_server.NewMCPConfig( + 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) diff --git a/plugins/core/mcp.go b/plugins/core/mcp.go index e1837ade..b76781ee 100644 --- a/plugins/core/mcp.go +++ b/plugins/core/mcp.go @@ -17,12 +17,16 @@ func (p *plugin) mcpAPIs() []pm3.Api { globalMessagePath := fmt.Sprintf("/api/v1/%s/message", mcp_server.GlobalBasePath) appSSEPath := fmt.Sprintf("/api/v1/%s/sse", 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.MethodPost, serviceMessagePath) ignore.IgnorePath("login", http.MethodGet, globalSSEPath) ignore.IgnorePath("login", http.MethodPost, globalMessagePath) ignore.IgnorePath("login", http.MethodGet, appSSEPath) ignore.IgnorePath("login", http.MethodPost, appMessagePath) + ignore.IgnorePath("login", http.MethodGet, globalMcpPath) + ignore.IgnorePath("login", http.MethodGet, appMcpPath) return []pm3.Api{ pm3.CreateApiSimple(http.MethodGet, serviceSSEPath, p.mcpController.MCPHandle), pm3.CreateApiSimple(http.MethodPost, serviceMessagePath, p.mcpController.MCPHandle), diff --git a/plugins/openapi/check.go b/plugins/openapi/check.go index b05031e5..7f227854 100644 --- a/plugins/openapi/check.go +++ b/plugins/openapi/check.go @@ -60,6 +60,7 @@ func (o *openapiCheck) Handler(ginCtx *gin.Context) { } authorization = apikey } + authorization = strings.TrimPrefix(authorization, "Bearer ") if authorization == o.apikey { return } diff --git a/plugins/openapi/mcp.go b/plugins/openapi/mcp.go index 3c167efc..4a045731 100644 --- a/plugins/openapi/mcp.go +++ b/plugins/openapi/mcp.go @@ -19,17 +19,22 @@ func (p *plugin) mcpAPIs() []pm3.Api { 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, "/")) - 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.MethodGet, globalSSEPath) + //ignore.IgnorePath("openapi", http.MethodGet, globalSSEPath) ignore.IgnorePath("openapi", http.MethodPost, appMessagePath) ignore.IgnorePath("openapi", http.MethodGet, appSSEPath) ignore.IgnorePath("openapi", http.MethodGet, serviceSSEPath) ignore.IgnorePath("openapi", http.MethodPost, serviceMessagePath) - ignore.IgnorePath("openapi", http.MethodGet, serviceStreamablePath) - ignore.IgnorePath("openapi", http.MethodPost, serviceStreamablePath) - ignore.IgnorePath("openapi", http.MethodDelete, serviceStreamablePath) + + ignore.IgnorePath("openapi", http.MethodGet, mcp_server.OpenAppMCPPath) + 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{ 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.MethodPost, serviceMessagePath, p.mcpController.ServiceHandleMessage), - pm3.CreateApiSimple(http.MethodPost, serviceStreamablePath, p.mcpController.ServiceHandleStreamHTTP), - pm3.CreateApiSimple(http.MethodDelete, serviceStreamablePath, p.mcpController.ServiceHandleStreamHTTP), - pm3.CreateApiSimple(http.MethodGet, serviceStreamablePath, p.mcpController.ServiceHandleStreamHTTP), + pm3.CreateApiSimple(http.MethodGet, mcp_server.OpenGlobalMCPPath, p.mcpController.GlobalHandleStreamHTTP), + pm3.CreateApiSimple(http.MethodPost, mcp_server.OpenGlobalMCPPath, p.mcpController.GlobalHandleStreamHTTP), + 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), } } diff --git a/stores/universally/commit/store.go b/stores/universally/commit/store.go index bfd250d9..278b8e2d 100644 --- a/stores/universally/commit/store.go +++ b/stores/universally/commit/store.go @@ -3,10 +3,11 @@ package commit import ( "context" "errors" - "github.com/eolinker/go-common/utils" "strings" "time" + "github.com/eolinker/go-common/utils" + "github.com/eolinker/go-common/store" "github.com/google/uuid" "gorm.io/gorm"