Skip to content

Commit ea32fb1

Browse files
committed
MCP transports supports Streamable HTTP
1 parent 6ee1996 commit ea32fb1

File tree

11 files changed

+184
-64
lines changed

11 files changed

+184
-64
lines changed

controller/mcp/iml.go

Lines changed: 71 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,14 @@ import (
2121
var _ IMcpController = (*imlMcpController)(nil)
2222

2323
type imlMcpController struct {
24-
settingModule system.ISettingModule `autowired:""`
25-
authorizationModule application_authorization.IAuthorizationModule `autowired:""`
26-
appModule service.IAppModule `autowired:""`
27-
mcpModule mcp.IMcpModule `autowired:""`
28-
sessionKeys sync.Map
29-
server map[string]http.Handler
30-
openServer http.Handler
24+
settingModule system.ISettingModule `autowired:""`
25+
authorizationModule application_authorization.IAuthorizationModule `autowired:""`
26+
appModule service.IAppModule `autowired:""`
27+
mcpModule mcp.IMcpModule `autowired:""`
28+
sessionKeys sync.Map
29+
sseServers map[string]http.Handler
30+
openSseServer http.Handler
31+
openStreamableServer http.Handler
3132
}
3233

3334
func (i *imlMcpController) AppMCPHandle(ctx *gin.Context) {
@@ -42,12 +43,12 @@ func (i *imlMcpController) AppMCPHandle(ctx *gin.Context) {
4243
paths := strings.Split(req.URL.Path, "/")
4344
req.URL.Path = fmt.Sprintf("/api/v1/%s/%s", mcp_server.GlobalBasePath, paths[len(paths)-1])
4445
locale := utils.I18n(ctx)
45-
if v, ok := i.server[locale]; ok {
46+
if v, ok := i.sseServers[locale]; ok {
4647
v.ServeHTTP(ctx.Writer, req)
4748
return
4849
}
4950

50-
i.server[languageEnUs].ServeHTTP(ctx.Writer, req)
51+
i.sseServers[languageEnUs].ServeHTTP(ctx.Writer, req)
5152
}
5253

5354
func (i *imlMcpController) AppHandleSSE(ctx *gin.Context) {
@@ -68,7 +69,7 @@ func (i *imlMcpController) AppHandleSSE(ctx *gin.Context) {
6869
}
6970

7071
ctx.Request.URL.Path = fmt.Sprintf("/openapi/v1/%s/sse", mcp_server.GlobalBasePath)
71-
i.handleSSE(ctx, i.openServer, SessionInfo{
72+
i.handleSSE(ctx, i.openSseServer, SessionInfo{
7273
Apikey: apikey,
7374
App: appId,
7475
})
@@ -81,8 +82,29 @@ func (i *imlMcpController) AppHandleMessage(ctx *gin.Context) {
8182
return
8283
}
8384
ctx.Request.URL.Path = fmt.Sprintf("/openapi/v1/%s/message", mcp_server.GlobalBasePath)
84-
ctx.Request = ctx.Request.WithContext(utils.SetLabel(ctx.Request.Context(), "app", appId))
85-
i.handleMessage(ctx, i.openServer)
85+
//ctx.Request = ctx.Request.WithContext(utils.SetLabel(ctx.Request.Context(), "app", appId))
86+
i.handleMessage(ctx, i.openSseServer)
87+
}
88+
89+
func (i *imlMcpController) AppHandleStreamHTTP(ctx *gin.Context) {
90+
apikey := ctx.Request.Header.Get("Authorization")
91+
apikey = strings.TrimPrefix(apikey, "Bearer ")
92+
if apikey == "" {
93+
ctx.AbortWithStatusJSON(403, gin.H{"code": -1, "msg": "invalid apikey", "success": "fail"})
94+
return
95+
}
96+
appId := ctx.Request.Header.Get("X-Application-Id")
97+
if appId == "" {
98+
ctx.AbortWithStatusJSON(403, gin.H{"code": -1, "msg": "invalid app id", "success": "fail"})
99+
return
100+
}
101+
cfg := i.settingModule.Get(ctx)
102+
req := ctx.Request.WithContext(utils.SetGatewayInvoke(ctx.Request.Context(), cfg.InvokeAddress))
103+
104+
req = req.WithContext(utils.SetLabel(req.Context(), "apikey", apikey))
105+
req = req.WithContext(utils.SetLabel(req.Context(), "app", appId))
106+
req.URL.Path = mcp_server.OpenGlobalMCPPath
107+
i.openStreamableServer.ServeHTTP(ctx.Writer, req)
86108
}
87109

88110
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,
94116
if err != nil {
95117
return "", fmt.Errorf("get app info error: %v", err)
96118
}
97-
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
98-
}
99119

100-
var mcpDefaultConfig = `{
101-
"mcpServers": {
102-
"%s": {
103-
"url": "%s"
104-
}
105-
}
120+
return mcp_server.NewMCPConfig(
121+
mcp_server.TransportTypeStreamableHTTP,
122+
fmt.Sprintf("%s%s", strings.TrimSuffix(cfg.SitePrefix, "/"), mcp_server.OpenAppMCPPath),
123+
map[string]string{
124+
"Authorization": "Bearer {your_api_key}",
125+
"X-Application-Id": appId,
126+
},
127+
nil,
128+
).ToString(appInfo.Name), nil
106129
}
107-
`
108130

109131
func (i *imlMcpController) GlobalMCPConfig(ctx *gin.Context) (string, error) {
110132
cfg := i.settingModule.Get(ctx)
111133
if cfg.SitePrefix == "" {
112134
return "", fmt.Errorf("site prefix is empty")
113135
}
114-
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
136+
return mcp_server.NewMCPConfig(
137+
mcp_server.TransportTypeStreamableHTTP,
138+
fmt.Sprintf("%s%s", strings.TrimSuffix(cfg.SitePrefix, "/"), mcp_server.OpenGlobalMCPPath),
139+
map[string]string{
140+
"Authorization": "Bearer {your_api_key}",
141+
},
142+
nil,
143+
).ToString("APIPark-MCP-Server"), nil
115144
}
116145

117146
func (i *imlMcpController) OnComplete() {
118-
i.server = make(map[string]http.Handler)
147+
i.sseServers = make(map[string]http.Handler)
119148
for language, tools := range mcpToolsByLanguage {
120149
s := server.NewMCPServer("APIPark MCP Server", "1.0.0", server.WithLogging())
121150
s.AddTool(tools[ToolServiceList], i.mcpModule.Services)
122151
s.AddTool(tools[ToolOpenAPIDocument], i.mcpModule.APIs)
123152
s.AddTool(tools[ToolInvokeAPI], i.mcpModule.Invoke)
124-
i.server[language] = server.NewSSEServer(s, server.WithStaticBasePath(fmt.Sprintf("/api/v1/%s", mcp_server.GlobalBasePath)))
153+
i.sseServers[language] = server.NewSSEServer(s, server.WithStaticBasePath(fmt.Sprintf("/api/v1/%s", mcp_server.GlobalBasePath)))
125154
if language == languageEnUs {
126-
i.openServer = server.NewSSEServer(s, server.WithStaticBasePath(fmt.Sprintf("/openapi/v1/%s", strings.Trim(mcp_server.GlobalBasePath, "/"))))
155+
i.openSseServer = server.NewSSEServer(s, server.WithStaticBasePath(fmt.Sprintf("/openapi/v1/%s", strings.Trim(mcp_server.GlobalBasePath, "/"))))
156+
i.openStreamableServer = server.NewStreamableHTTPServer(s, server.WithEndpointPath(mcp_server.OpenGlobalMCPPath))
127157
}
128158
}
129159
}
@@ -132,16 +162,16 @@ func (i *imlMcpController) GlobalMCPHandle(ctx *gin.Context) {
132162
cfg := i.settingModule.Get(ctx)
133163
req := ctx.Request.WithContext(utils.SetGatewayInvoke(ctx.Request.Context(), cfg.InvokeAddress))
134164
locale := utils.I18n(ctx)
135-
if v, ok := i.server[locale]; ok {
165+
if v, ok := i.sseServers[locale]; ok {
136166
v.ServeHTTP(ctx.Writer, req)
137167
return
138168
}
139-
i.server[languageEnUs].ServeHTTP(ctx.Writer, req)
169+
i.sseServers[languageEnUs].ServeHTTP(ctx.Writer, req)
140170
}
141171

142172
func (i *imlMcpController) GlobalHandleSSE(ctx *gin.Context) {
143173
apikey := ctx.Request.URL.Query().Get("apikey")
144-
i.handleSSE(ctx, i.openServer, SessionInfo{
174+
i.handleSSE(ctx, i.openSseServer, SessionInfo{
145175
Apikey: apikey,
146176
})
147177
}
@@ -167,7 +197,16 @@ func (i *imlMcpController) handleSSE(ctx *gin.Context, server http.Handler, sIn
167197
}
168198

169199
func (i *imlMcpController) GlobalHandleMessage(ctx *gin.Context) {
170-
i.handleMessage(ctx, i.openServer)
200+
i.handleMessage(ctx, i.openSseServer)
201+
}
202+
203+
func (i *imlMcpController) GlobalHandleStreamHTTP(ctx *gin.Context) {
204+
apikey := ctx.Request.Header.Get("Authorization")
205+
apikey = strings.TrimPrefix(apikey, "Bearer ")
206+
cfg := i.settingModule.Get(ctx)
207+
req := ctx.Request.WithContext(utils.SetGatewayInvoke(ctx.Request.Context(), cfg.InvokeAddress))
208+
req = req.WithContext(utils.SetLabel(req.Context(), "apikey", apikey))
209+
i.openStreamableServer.ServeHTTP(ctx.Writer, req)
171210
}
172211

173212
func (i *imlMcpController) MCPHandle(ctx *gin.Context) {
@@ -204,12 +243,13 @@ func (i *imlMcpController) ServiceHandleMessage(ctx *gin.Context) {
204243
}
205244

206245
func (i *imlMcpController) ServiceHandleStreamHTTP(ctx *gin.Context) {
207-
apikey := ctx.Request.URL.Query().Get("apikey")
208-
serviceId := ctx.Param("serviceId")
246+
apikey := ctx.Request.Header.Get("Authorization")
247+
serviceId := ctx.Request.Header.Get("X-Service-Id")
209248
if serviceId == "" {
210249
ctx.AbortWithStatusJSON(403, gin.H{"code": -1, "msg": "invalid service id", "success": "fail"})
211250
return
212251
}
252+
apikey = strings.TrimPrefix(apikey, "Bearer ")
213253
ok, err := i.authorizationModule.CheckAPIKeyAuthorizationByService(ctx, serviceId, apikey)
214254
if err != nil {
215255
ctx.AbortWithStatusJSON(403, gin.H{"code": -1, "msg": err.Error(), "success": "fail"})

controller/mcp/mcp.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,13 @@ type IMcpController interface {
1313
GlobalMCPHandle(ctx *gin.Context)
1414
GlobalHandleSSE(ctx *gin.Context)
1515
GlobalHandleMessage(ctx *gin.Context)
16+
GlobalHandleStreamHTTP(ctx *gin.Context)
1617
GlobalMCPConfig(ctx *gin.Context) (string, error)
1718

1819
AppMCPHandle(ctx *gin.Context)
1920
AppHandleSSE(ctx *gin.Context)
2021
AppHandleMessage(ctx *gin.Context)
22+
AppHandleStreamHTTP(ctx *gin.Context)
2123
AppMCPConfig(ctx *gin.Context, appId string) (string, error)
2224

2325
ServiceHandleSSE(ctx *gin.Context)

go.mod

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ require (
1515
github.com/go-sql-driver/mysql v1.7.0
1616
github.com/google/uuid v1.6.0
1717
github.com/influxdata/influxdb-client-go/v2 v2.14.0
18-
github.com/mark3labs/mcp-go v0.33.0
18+
github.com/mark3labs/mcp-go v0.42.0-beta.3
1919
github.com/mitchellh/mapstructure v1.5.0
2020
github.com/nsqio/go-nsq v1.1.0
2121
github.com/ollama/ollama v0.5.8
@@ -27,6 +27,8 @@ require (
2727

2828
require (
2929
github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
30+
github.com/bahlo/generic-list-go v0.2.0 // indirect
31+
github.com/buger/jsonparser v1.1.1 // indirect
3032
github.com/bytedance/sonic v1.11.6 // indirect
3133
github.com/bytedance/sonic/loader v0.1.1 // indirect
3234
github.com/cespare/xxhash/v2 v2.2.0 // indirect
@@ -46,6 +48,7 @@ require (
4648
github.com/golang/snappy v0.0.4 // indirect
4749
github.com/gorilla/websocket v1.4.2 // indirect
4850
github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 // indirect
51+
github.com/invopop/jsonschema v0.13.0 // indirect
4952
github.com/jinzhu/inflection v1.0.0 // indirect
5053
github.com/jinzhu/now v1.1.5 // indirect
5154
github.com/josharian/intern v1.0.0 // indirect
@@ -67,6 +70,7 @@ require (
6770
github.com/spf13/cast v1.7.1 // indirect
6871
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
6972
github.com/ugorji/go/codec v1.2.12 // indirect
73+
github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
7074
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
7175
go.etcd.io/etcd/client/pkg/v3 v3.5.13 // indirect
7276
go.uber.org/atomic v1.7.0 // indirect
@@ -87,6 +91,4 @@ require (
8791
//)
8892

8993
//replace github.com/eolinker/ap-account => ../../eolinker/ap-account
90-
91-
//
9294
//replace github.com/eolinker/go-common => ../../eolinker/go-common

go.sum

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,17 @@ github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2
22
github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk=
33
github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ=
44
github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk=
5+
github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
6+
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
57
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
68
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
79
github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
810
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
911
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
1012
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
1113
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
14+
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
15+
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
1216
github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
1317
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
1418
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
8084
github.com/influxdata/influxdb-client-go/v2 v2.14.0/go.mod h1:Ahpm3QXKMJslpXl3IftVLVezreAUtBOTZssDrjZEFHI=
8185
github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 h1:W9WBk7wlPfJLvMCdtV4zPulc4uCPrlywQOmbFOhgQNU=
8286
github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo=
87+
github.com/invopop/jsonschema v0.13.0 h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcIi21E=
88+
github.com/invopop/jsonschema v0.13.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0=
8389
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
8490
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
8591
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=
101107
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
102108
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
103109
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
104-
github.com/mark3labs/mcp-go v0.33.0 h1:naxhjnTIs/tyPZmWUZFuG0lDmdA6sUyYGGf3gsHvTCc=
105-
github.com/mark3labs/mcp-go v0.33.0/go.mod h1:rXqOudj/djTORU/ThxYx8fqEVj/5pvTuuebQ2RC7uk4=
110+
github.com/mark3labs/mcp-go v0.42.0-beta.3 h1:nmOg1HFgSOgy0bZkAQ+E6qVpPMPmE8hIkM0BO94Ks9k=
111+
github.com/mark3labs/mcp-go v0.42.0-beta.3/go.mod h1:YnJfOL382MIWDx1kMY+2zsRHU/q78dBg9aFb8W6Thdw=
106112
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
107113
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
108114
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
159165
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
160166
github.com/urfave/cli v1.22.16 h1:MH0k6uJxdwdeWQTwhSO42Pwr4YLrNLwBtg1MRgTqPdQ=
161167
github.com/urfave/cli v1.22.16/go.mod h1:EeJR6BKodywf4zciqrdw6hpCPk68JO9z5LazXZMn5Po=
168+
github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc=
169+
github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
162170
github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4=
163171
github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4=
164172
go.etcd.io/etcd/client/pkg/v3 v3.5.13 h1:RVZSAnWWWiI5IrYAXjQorajncORbS0zI48LQlE2kQWg=

mcp-server/config.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package mcp_server
2+
3+
import "encoding/json"
4+
5+
type TransportType string
6+
7+
const (
8+
TransportTypeStreamableHTTP TransportType = "streamable-http"
9+
TransportTypeSSE TransportType = "sse"
10+
)
11+
12+
func NewMCPConfig(typ TransportType, url string, headers map[string]string, alwaysAllow []string) *MCPConfig {
13+
return &MCPConfig{
14+
Type: typ,
15+
URL: url,
16+
Headers: headers,
17+
AlwaysAllow: alwaysAllow,
18+
}
19+
}
20+
21+
type MCPConfig struct {
22+
Type TransportType `json:"type"`
23+
URL string `json:"url"`
24+
Headers map[string]string `json:"headers,omitempty"`
25+
AlwaysAllow []string `json:"alwaysAllow,omitempty"`
26+
}
27+
28+
func (c *MCPConfig) ToString(name string) string {
29+
m := map[string]interface{}{
30+
"mcpServers": map[string]interface{}{
31+
name: c,
32+
},
33+
}
34+
data, _ := json.MarshalIndent(m, "", "\t")
35+
return string(data)
36+
}

mcp-server/server.go

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ var (
1717
ServiceBasePath = "mcp/service"
1818
GlobalBasePath = "mcp/global"
1919
AppBasePath = "mcp/app"
20+
21+
OpenGlobalMCPPath = "/openapi/v1/global/mcp"
22+
OpenAppMCPPath = "/openapi/v1/app/mcp"
23+
OpenServiceMCPPath = "/openapi/v1/service/mcp"
2024
)
2125

2226
func NewServer() *Server {
@@ -61,7 +65,7 @@ func (s *Server) Set(id string, ser *server.MCPServer) {
6165
}
6266
tmp.handlers["api-sse"] = server.NewSSEServer(ser, server.WithStaticBasePath(fmt.Sprintf("/api/v1/%s/%s", ServiceBasePath, id)))
6367
tmp.handlers["openapi-sse"] = server.NewSSEServer(ser, server.WithStaticBasePath(fmt.Sprintf("/openapi/v1/%s/%s", ServiceBasePath, id)))
64-
tmp.handlers["openapi-stream"] = server.NewStreamableHTTPServer(ser, server.WithEndpointPath(fmt.Sprintf("/openapi/v1/%s/%s/mcp", ServiceBasePath, id)))
68+
tmp.handlers["openapi-stream"] = server.NewStreamableHTTPServer(ser, server.WithEndpointPath(OpenServiceMCPPath))
6569
s.servers[id] = tmp
6670

6771
}
@@ -91,12 +95,23 @@ func (s *Server) Get(id string) (*Handler, bool) {
9195
}
9296

9397
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
94-
sid, err := genPath(r.URL.Path)
95-
if err != nil {
96-
w.WriteHeader(http.StatusBadRequest)
97-
w.Write([]byte(err.Error()))
98-
return
98+
var sid string
99+
if r.URL.Path == OpenServiceMCPPath {
100+
sid = r.Header.Get("X-Service-Id")
101+
if sid == "" {
102+
http.NotFound(w, r)
103+
return
104+
}
105+
} else {
106+
id, err := genPath(r.URL.Path)
107+
if err != nil {
108+
w.WriteHeader(http.StatusBadRequest)
109+
w.Write([]byte(err.Error()))
110+
return
111+
}
112+
sid = id
99113
}
114+
100115
ser, has := s.Get(sid)
101116
if has {
102117
ser.ServeHTTP(w, r)

0 commit comments

Comments
 (0)