Skip to content

Commit 1bddef2

Browse files
authored
Merge pull request #334 from APIParkLab/feature/liujian-1.8
Optimizing the parameter tiling of MCP Tool to facilitate AI understanding
2 parents b1b9f49 + 58d02bc commit 1bddef2

File tree

16 files changed

+498
-372
lines changed

16 files changed

+498
-372
lines changed

controller/mcp/iml.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ func (i *imlMcpController) OnComplete() {
190190
i.server["ja-JP"] = server.NewSSEServer(i.generateJPMCPServer(), server.WithBasePath(fmt.Sprintf("/api/v1/%s", mcp_server.GlobalBasePath)))
191191

192192
i.openServer = server.NewSSEServer(enSer, server.WithBasePath(fmt.Sprintf("/openapi/v1/%s", strings.Trim(mcp_server.GlobalBasePath, "/"))))
193+
193194
}
194195

195196
func (i *imlMcpController) GlobalMCPHandle(ctx *gin.Context) {
@@ -263,6 +264,28 @@ func (i *imlMcpController) ServiceHandleMessage(ctx *gin.Context) {
263264
i.handleMessage(ctx, mcp_server.DefaultMCPServer())
264265
}
265266

267+
func (i *imlMcpController) ServiceHandleStreamHTTP(ctx *gin.Context) {
268+
apikey := ctx.Request.URL.Query().Get("apikey")
269+
serviceId := ctx.Param("serviceId")
270+
if serviceId == "" {
271+
ctx.AbortWithStatusJSON(403, gin.H{"code": -1, "msg": "invalid service id", "success": "fail"})
272+
return
273+
}
274+
ok, err := i.authorizationModule.CheckAPIKeyAuthorization(ctx, serviceId, apikey)
275+
if err != nil {
276+
ctx.AbortWithStatusJSON(403, gin.H{"code": -1, "msg": err.Error(), "success": "fail"})
277+
return
278+
}
279+
if !ok {
280+
ctx.AbortWithStatusJSON(403, gin.H{"code": -1, "msg": "invalid apikey", "success": "fail"})
281+
return
282+
}
283+
cfg := i.settingModule.Get(ctx)
284+
req := ctx.Request.WithContext(utils.SetGatewayInvoke(ctx.Request.Context(), cfg.InvokeAddress))
285+
req = req.WithContext(utils.SetLabel(req.Context(), "apikey", apikey))
286+
mcp_server.DefaultMCPServer().ServeHTTP(ctx.Writer, req)
287+
}
288+
266289
func (i *imlMcpController) handleMessage(ctx *gin.Context, server http.Handler) {
267290
sessionId := ctx.Request.URL.Query().Get("sessionId")
268291
apikey, ok := i.sessionKeys.Load(sessionId)

controller/mcp/mcp.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ type IMcpController interface {
1515
ServiceHandleSSE(ctx *gin.Context)
1616
ServiceHandleMessage(ctx *gin.Context)
1717
GlobalMCPConfig(ctx *gin.Context) (string, error)
18+
ServiceHandleStreamHTTP(ctx *gin.Context)
1819
}
1920

2021
func init() {

go.mod

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@ require (
99
github.com/eolinker/eosc v0.18.3
1010
github.com/eolinker/go-common v1.1.7
1111
github.com/gabriel-vasile/mimetype v1.4.4
12-
github.com/getkin/kin-openapi v0.127.0
12+
github.com/getkin/kin-openapi v0.132.0
1313
github.com/gin-contrib/gzip v1.0.1
1414
github.com/gin-gonic/gin v1.10.0
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.17.0
18+
github.com/mark3labs/mcp-go v0.33.0
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
@@ -46,7 +46,6 @@ require (
4646
github.com/golang/snappy v0.0.4 // indirect
4747
github.com/gorilla/websocket v1.4.2 // indirect
4848
github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 // indirect
49-
github.com/invopop/yaml v0.3.1 // indirect
5049
github.com/jinzhu/inflection v1.0.0 // indirect
5150
github.com/jinzhu/now v1.1.5 // indirect
5251
github.com/josharian/intern v1.0.0 // indirect
@@ -59,10 +58,13 @@ require (
5958
github.com/modern-go/reflect2 v1.0.2 // indirect
6059
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
6160
github.com/oapi-codegen/runtime v1.0.0 // indirect
61+
github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect
62+
github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect
6263
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
6364
github.com/perimeterx/marshmallow v1.1.5 // indirect
6465
github.com/redis/go-redis/v9 v9.5.3 // indirect
6566
github.com/russross/blackfriday/v2 v2.1.0 // indirect
67+
github.com/spf13/cast v1.7.1 // indirect
6668
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
6769
github.com/ugorji/go/codec v1.2.12 // indirect
6870
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect

go.sum

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,12 @@ github.com/eolinker/eosc v0.18.3 h1:3IK5HkAPnJRfLbQ0FR7kWsZr6Y/OiqqGazvN1q2BL5A=
3434
github.com/eolinker/eosc v0.18.3/go.mod h1:O9PQQXFCpB6fjHf+oFt/LN6EOAv779ItbMixMKCfTfk=
3535
github.com/eolinker/go-common v1.1.7 h1:bi7wDmlCYQGjS3k8Bz/o+Mo9aMJAzmPsBLXWurxPfwk=
3636
github.com/eolinker/go-common v1.1.7/go.mod h1:Kb/jENMN1mApnodvRgV4YwO9FJby1Jkt2EUjrBjvSX4=
37+
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
38+
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
3739
github.com/gabriel-vasile/mimetype v1.4.4 h1:QjV6pZ7/XZ7ryI2KuyeEDE8wnh7fHP9YnQy+R0LnH8I=
3840
github.com/gabriel-vasile/mimetype v1.4.4/go.mod h1:JwLei5XPtWdGiMFB5Pjle1oEeoSeEuJfJE+TtfvdB/s=
39-
github.com/getkin/kin-openapi v0.127.0 h1:Mghqi3Dhryf3F8vR370nN67pAERW+3a95vomb3MAREY=
40-
github.com/getkin/kin-openapi v0.127.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM=
41+
github.com/getkin/kin-openapi v0.132.0 h1:3ISeLMsQzcb5v26yeJrBcdTCEQTag36ZjaGk7MIRUwk=
42+
github.com/getkin/kin-openapi v0.132.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58=
4143
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
4244
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
4345
github.com/gin-contrib/gzip v1.0.1 h1:HQ8ENHODeLY7a4g1Au/46Z92bdGFl74OhxcZble9WJE=
@@ -78,8 +80,6 @@ github.com/influxdata/influxdb-client-go/v2 v2.14.0 h1:AjbBfJuq+QoaXNcrova8smSjw
7880
github.com/influxdata/influxdb-client-go/v2 v2.14.0/go.mod h1:Ahpm3QXKMJslpXl3IftVLVezreAUtBOTZssDrjZEFHI=
7981
github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 h1:W9WBk7wlPfJLvMCdtV4zPulc4uCPrlywQOmbFOhgQNU=
8082
github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo=
81-
github.com/invopop/yaml v0.3.1 h1:f0+ZpmhfBSS4MhG+4HYseMdJhoeeopbSKbq5Rpeelso=
82-
github.com/invopop/yaml v0.3.1/go.mod h1:PMOp3nn4/12yEZUFfmOuNHJsZToEEOwoWsT+D81KkeA=
8383
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
8484
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
8585
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
@@ -101,8 +101,8 @@ github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
101101
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
102102
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
103103
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
104-
github.com/mark3labs/mcp-go v0.17.0 h1:5Ps6T7qXr7De/2QTqs9h6BKeZ/qdeUeGrgM5lPzi930=
105-
github.com/mark3labs/mcp-go v0.17.0/go.mod h1:KmJndYv7GIgcPVwEKJjNcbhVQ+hJGJhrCCB/9xITzpE=
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=
106106
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
107107
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
108108
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
@@ -118,6 +118,10 @@ github.com/nsqio/go-nsq v1.1.0 h1:PQg+xxiUjA7V+TLdXw7nVrJ5Jbl3sN86EhGCQj4+FYE=
118118
github.com/nsqio/go-nsq v1.1.0/go.mod h1:vKq36oyeVXgsS5Q8YEO7WghqidAVXQlcFxzQbQTuDEY=
119119
github.com/oapi-codegen/runtime v1.0.0 h1:P4rqFX5fMFWqRzY9M/3YF9+aPSPPB06IzP2P7oOxrWo=
120120
github.com/oapi-codegen/runtime v1.0.0/go.mod h1:LmCUMQuPB4M/nLXilQXhHw+BLZdDb18B34OO356yJ/A=
121+
github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY=
122+
github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw=
123+
github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c=
124+
github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o=
121125
github.com/ollama/ollama v0.5.8 h1:b2S6YdZ18/ntCsWzoy/HmB3BHGW4GX0Qp7RARrJtJXU=
122126
github.com/ollama/ollama v0.5.8/go.mod h1:ibdmDvb/TjKY1OArBWIazL3pd1DHTk8eG2MMjEkWhiI=
123127
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
@@ -134,6 +138,8 @@ github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU
134138
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
135139
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
136140
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
141+
github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y=
142+
github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
137143
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0=
138144
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
139145
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=

log-driver/loki/loki_test.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,12 @@ func TestLoki(t *testing.T) {
3333
// headers["Content-Type"] = "application/json"
3434
// headers["X-Scope-OrgID"] = "tenant1"
3535
// queries := url.Values{}
36-
// queries.Set("query", "{cluster=\"apinto\"} | json | request_id = `c9f6b19c-7dfe-496b-9b39-4d049232fe95`")
36+
// queries.SetMCPServer("query", "{cluster=\"apinto\"} | json | request_id = `c9f6b19c-7dfe-496b-9b39-4d049232fe95`")
3737
// now := time.Now()
3838
// start := now.Add(-time.Hour * 24 * 30)
39-
// queries.Set("start", strconv.FormatInt(start.UnixNano(), 10))
40-
// queries.Set("end", strconv.FormatInt(now.UnixNano(), 10))
41-
// queries.Set("limit", "100")
39+
// queries.SetMCPServer("start", strconv.FormatInt(start.UnixNano(), 10))
40+
// queries.SetMCPServer("end", strconv.FormatInt(now.UnixNano(), 10))
41+
// queries.SetMCPServer("limit", "100")
4242
// a := time.Now()
4343
// result, err := send[LogInfo](http.MethodGet, "http://localhost:3100/loki/api/v1/query_range", headers, queries, "")
4444
// if err != nil {
@@ -57,8 +57,8 @@ func TestLoki(t *testing.T) {
5757
// headers["Content-Type"] = "application/json"
5858
// headers["X-Scope-OrgID"] = "tenant1"
5959
// queries := url.Values{}
60-
// //queries.Set("query", "sum(count_over_time({cluster=\"apinto\"}[24h])) by (strategy)")
61-
// queries.Set("query", "sum(count_over_time({cluster=\"apinto\"}[24h]))")
60+
// //queries.SetMCPServer("query", "sum(count_over_time({cluster=\"apinto\"}[24h])) by (strategy)")
61+
// queries.SetMCPServer("query", "sum(count_over_time({cluster=\"apinto\"}[24h]))")
6262
// result, err := send[LogCount](http.MethodGet, "http://localhost:3100/loki/api/v1/query", headers, queries, "")
6363
// if err != nil {
6464
// t.Fatalf("failed to send request: %v", err)
@@ -75,12 +75,12 @@ func TestLoki(t *testing.T) {
7575
// headers["Content-Type"] = "application/json"
7676
// headers["X-Scope-OrgID"] = "tenant1"
7777
// queries := url.Values{}
78-
// queries.Set("query", "{cluster=\"apinto\"} | json | strategy=\"03899736-5d79-4f26-bd6a-c312a5880780\"")
78+
// queries.SetMCPServer("query", "{cluster=\"apinto\"} | json | strategy=\"03899736-5d79-4f26-bd6a-c312a5880780\"")
7979
// now := time.Now()
8080
// start := now.Add(-time.Hour * 24 * 30)
81-
// queries.Set("start", strconv.FormatInt(start.UnixNano(), 10))
82-
// queries.Set("end", strconv.FormatInt(now.UnixNano(), 10))
83-
// queries.Set("limit", "1")
81+
// queries.SetMCPServer("start", strconv.FormatInt(start.UnixNano(), 10))
82+
// queries.SetMCPServer("end", strconv.FormatInt(now.UnixNano(), 10))
83+
// queries.SetMCPServer("limit", "1")
8484
// now = time.Now()
8585
// result, err := send[map[string]interface{}](http.MethodGet, "http://localhost:3100/loki/api/v1/query_range", headers, queries, "")
8686
// t.LogItem(time.Now().Sub(now))

mcp-server/param.go

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package mcp_server
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"net/http"
7+
"net/url"
8+
)
9+
10+
var client = http.Client{}
11+
12+
type Position string
13+
14+
const (
15+
PositionHeader Position = "header"
16+
PositionBody Position = "body"
17+
PositionQuery Position = "query"
18+
PositionPath Position = "path"
19+
)
20+
21+
type ContentType string
22+
23+
const (
24+
ContentTypeJSON ContentType = "application/json"
25+
ContentTypeXML ContentType = "application/xml"
26+
ContentTypeHTML ContentType = "text/html"
27+
ContentTypeText ContentType = "text/plain"
28+
ContentTypeForm ContentType = "application/x-www-form-urlencoded"
29+
ContentTypeFile ContentType = "multipart/form-data"
30+
)
31+
32+
func NewParam(position Position, required bool, description string) *Param {
33+
return &Param{position: position, required: required, description: description}
34+
}
35+
36+
type Param struct {
37+
position Position
38+
required bool
39+
description string
40+
}
41+
42+
func (p *Param) Description() string {
43+
return p.description
44+
}
45+
46+
func (p *Param) Required() bool {
47+
return p.required
48+
}
49+
50+
type BodyParam struct {
51+
contentType ContentType
52+
params map[string]interface{}
53+
}
54+
55+
func NewBodyParam(contentType string) *BodyParam {
56+
t := ContentType(contentType)
57+
if t == "" {
58+
t = ContentTypeJSON
59+
}
60+
return &BodyParam{contentType: t}
61+
}
62+
63+
func (p *BodyParam) Set(k string, v interface{}) {
64+
if p.params == nil {
65+
p.params = make(map[string]interface{})
66+
}
67+
p.params[k] = v
68+
}
69+
70+
func (p *BodyParam) Encode() (string, error) {
71+
switch p.contentType {
72+
case ContentTypeJSON:
73+
data, err := json.Marshal(p.params)
74+
if err != nil {
75+
return "", fmt.Errorf("body param encode error: %w", err)
76+
}
77+
return string(data), nil
78+
case ContentTypeForm, ContentTypeFile:
79+
data := url.Values{}
80+
for k, v := range p.params {
81+
data.Set(k, fmt.Sprintf("%v", v))
82+
}
83+
return data.Encode(), nil
84+
default:
85+
return "", fmt.Errorf("unsupported content type: %s", p.contentType)
86+
}
87+
}

0 commit comments

Comments
 (0)