refactor: migrate MCP SDK to main repo (#3516)

This commit is contained in:
澄潭
2026-02-16 23:39:18 +08:00
committed by GitHub
parent 87c6cc9c9f
commit 9346f1340b
75 changed files with 10117 additions and 3392 deletions

View File

@@ -1,10 +1,14 @@
module jsonrpc-converter
go 1.24.3
go 1.24.1
replace github.com/alibaba/higress/plugins/wasm-go/pkg/mcp => ../../pkg/mcp
require (
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20250822030947-8345453fddd0
github.com/higress-group/wasm-go v1.0.4
github.com/alibaba/higress/plugins/wasm-go/pkg/mcp v0.0.0
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20251103120604-77e9cce339d2
github.com/higress-group/wasm-go v1.0.10-0.20260115123534-84ef43c39dc9
github.com/stretchr/testify v1.9.0
github.com/tidwall/gjson v1.18.0
)
@@ -15,6 +19,7 @@ require (
github.com/Masterminds/sprig/v3 v3.3.0 // indirect
github.com/bahlo/generic-list-go v0.2.0 // indirect
github.com/buger/jsonparser v1.1.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/higress-group/gjson_template v0.0.0-20250413075336-4c4161ed428b // indirect
github.com/huandu/xstrings v1.5.0 // indirect
@@ -22,8 +27,10 @@ require (
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/shopspring/decimal v1.4.0 // indirect
github.com/spf13/cast v1.7.0 // indirect
github.com/tetratelabs/wazero v1.7.2 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
github.com/tidwall/resp v0.1.1 // indirect

View File

@@ -20,10 +20,10 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/higress-group/gjson_template v0.0.0-20250413075336-4c4161ed428b h1:rRI9+ThQbe+nw4jUiYEyOFaREkXCMMW9k1X2gy2d6pE=
github.com/higress-group/gjson_template v0.0.0-20250413075336-4c4161ed428b/go.mod h1:rU3M+Tq5VrQOo0dxpKHGb03Ty0sdWIZfAH+YCOACx/Y=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20250822030947-8345453fddd0 h1:YGdj8KBzVjabU3STUfwMZghB+VlX6YLfJtLbrsWaOD0=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20250822030947-8345453fddd0/go.mod h1:tRI2LfMudSkKHhyv1uex3BWzcice2s/l8Ah8axporfA=
github.com/higress-group/wasm-go v1.0.4 h1:/GqbzCw4oWqJc8UbKEfF94E3/+4CPZGbzxpKo2L3Ldk=
github.com/higress-group/wasm-go v1.0.4/go.mod h1:B8C6+OlpnyYyZUBEdUXA7tYZYD+uwZTNjfkE5FywA+A=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20251103120604-77e9cce339d2 h1:NY33OrWCJJ+DFiLc+lsBY4Ywor2Ik61ssk6qkGF8Ypo=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20251103120604-77e9cce339d2/go.mod h1:tRI2LfMudSkKHhyv1uex3BWzcice2s/l8Ah8axporfA=
github.com/higress-group/wasm-go v1.0.10-0.20260115123534-84ef43c39dc9 h1:sUuUXZwr50l3W1St7MESlFmxmUAu+QUNNfJXx4P6bas=
github.com/higress-group/wasm-go v1.0.10-0.20260115123534-84ef43c39dc9/go.mod h1:uKVYICbRaxTlKqdm8E0dpjbysxM8uCPb9LV26hF3Km8=
github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI=
github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/invopop/jsonschema v0.13.0 h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcIi21E=
@@ -49,6 +49,8 @@ github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tetratelabs/wazero v1.7.2 h1:1+z5nXJNwMLPAWaTePFi49SSTL0IMx/i3Fg8Yc25GDc=
github.com/tetratelabs/wazero v1.7.2/go.mod h1:ytl6Zuh20R/eROuyDaGPkp82O9C/DJfXAwJfQ3X6/7Y=
github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=

View File

@@ -9,8 +9,8 @@ import (
"github.com/higress-group/proxy-wasm-go-sdk/proxywasm"
"github.com/higress-group/proxy-wasm-go-sdk/proxywasm/types"
"github.com/higress-group/wasm-go/pkg/log"
"github.com/higress-group/wasm-go/pkg/mcp"
"github.com/higress-group/wasm-go/pkg/mcp/utils"
"github.com/alibaba/higress/plugins/wasm-go/pkg/mcp"
"github.com/alibaba/higress/plugins/wasm-go/pkg/mcp/utils"
"github.com/higress-group/wasm-go/pkg/wrapper"
"github.com/tidwall/gjson"
)

View File

@@ -1,9 +1,15 @@
package main
import (
"encoding/json"
"testing"
"github.com/higress-group/proxy-wasm-go-sdk/proxywasm/types"
"github.com/higress-group/wasm-go/pkg/test"
"github.com/stretchr/testify/require"
)
// TestTruncateString tests the truncateString function
func TestTruncateString(t *testing.T) {
tests := []struct {
name string
@@ -14,6 +20,8 @@ func TestTruncateString(t *testing.T) {
{"Short String", "Higress Is an AI-Native API Gateway", 1000, "Higress Is an AI-Native API Gateway"},
{"Exact Length", "Higress Is an AI-Native API Gateway", 35, "Higress Is an AI-Native API Gateway"},
{"Truncated String", "Higress Is an AI-Native API Gateway", 20, "Higress Is...(truncated)...PI Gateway"},
{"Empty String", "", 10, ""},
{"Single Char", "A", 10, "A"},
}
for _, tt := range tests {
@@ -26,3 +34,248 @@ func TestTruncateString(t *testing.T) {
})
}
}
// TestIsPreRequestStage tests the isPreRequestStage function
func TestIsPreRequestStage(t *testing.T) {
config := McpConverterConfig{Stage: ProcessRequest}
require.True(t, isPreRequestStage(config))
config = McpConverterConfig{Stage: ProcessResponse}
require.False(t, isPreRequestStage(config))
}
// TestIsPreResponseStage tests the isPreResponseStage function
func TestIsPreResponseStage(t *testing.T) {
config := McpConverterConfig{Stage: ProcessResponse}
require.True(t, isPreResponseStage(config))
config = McpConverterConfig{Stage: ProcessRequest}
require.False(t, isPreResponseStage(config))
}
// TestIsMethodAllowed tests the isMethodAllowed function
func TestIsMethodAllowed(t *testing.T) {
config := McpConverterConfig{AllowedMethods: []string{MethodToolList, MethodToolCall}}
require.True(t, isMethodAllowed(config, MethodToolList))
require.True(t, isMethodAllowed(config, MethodToolCall))
require.False(t, isMethodAllowed(config, "invalid/method"))
}
// TestConstants tests the constant values
func TestConstants(t *testing.T) {
require.Equal(t, "x-envoy-jsonrpc-id", JsonRpcId)
require.Equal(t, "x-envoy-jsonrpc-method", JsonRpcMethod)
require.Equal(t, "x-envoy-jsonrpc-params", JsonRpcParams)
require.Equal(t, "x-envoy-jsonrpc-result", JsonRpcResult)
require.Equal(t, "x-envoy-jsonrpc-error", JsonRpcError)
require.Equal(t, "x-envoy-mcp-tool-name", McpToolName)
require.Equal(t, "x-envoy-mcp-tool-arguments", McpToolArguments)
require.Equal(t, "x-envoy-mcp-tool-response", McpToolResponse)
require.Equal(t, "x-envoy-mcp-tool-error", McpToolError)
require.Equal(t, 4000, DefaultMaxHeaderLength)
require.Equal(t, "tools/list", MethodToolList)
require.Equal(t, "tools/call", MethodToolCall)
require.Equal(t, ProcessStage("request"), ProcessRequest)
require.Equal(t, ProcessStage("response"), ProcessResponse)
}
// TestMcpConverterConfigDefaults tests config default values
func TestMcpConverterConfigDefaults(t *testing.T) {
config := McpConverterConfig{}
require.Equal(t, 0, config.MaxHeaderLength)
require.Equal(t, ProcessStage(""), config.Stage)
require.Nil(t, config.AllowedMethods)
}
// TestProcessStage tests ProcessStage type
func TestProcessStage(t *testing.T) {
require.Equal(t, ProcessStage("request"), ProcessRequest)
require.Equal(t, ProcessStage("response"), ProcessResponse)
}
// TestRemoveJsonRpcHeadersFunction tests removeJsonRpcHeaders function logic
func TestRemoveJsonRpcHeadersFunction(t *testing.T) {
headersToRemove := []string{
JsonRpcId,
JsonRpcMethod,
JsonRpcParams,
JsonRpcResult,
McpToolName,
McpToolArguments,
McpToolResponse,
McpToolError,
}
require.Len(t, headersToRemove, 8)
}
// TestTruncateStringLong tests truncation of very long strings
func TestTruncateStringLong(t *testing.T) {
longString := ""
for i := 0; i < 5000; i++ {
longString += "a"
}
config := McpConverterConfig{MaxHeaderLength: 1000}
result := truncateString(longString, config)
require.Contains(t, result, "...(truncated)...")
require.LessOrEqual(t, len(result), 1020)
}
// TestTruncateStringWithSmallMaxLength tests truncation with small max length
func TestTruncateStringWithSmallMaxLength(t *testing.T) {
config := McpConverterConfig{MaxHeaderLength: 10}
result := truncateString("This is a very long string", config)
require.Contains(t, result, "...(truncated)...")
}
// TestPluginInit tests plugin initialization
func TestPluginInit(t *testing.T) {
configBytes, _ := json.Marshal(McpConverterConfig{
Stage: ProcessRequest,
MaxHeaderLength: DefaultMaxHeaderLength,
AllowedMethods: []string{MethodToolList, MethodToolCall},
})
host, status := test.NewTestHost(configBytes)
defer host.Reset()
require.Equal(t, types.OnPluginStartStatusOK, status)
}
// TestProcessJsonRpcRequest tests processJsonRpcRequest function
func TestProcessJsonRpcRequest(t *testing.T) {
configBytes, _ := json.Marshal(McpConverterConfig{
Stage: ProcessRequest,
MaxHeaderLength: DefaultMaxHeaderLength,
AllowedMethods: []string{MethodToolList, MethodToolCall},
})
host, status := test.NewTestHost(configBytes)
defer host.Reset()
require.Equal(t, types.OnPluginStartStatusOK, status)
host.InitHttp()
host.CallOnHttpRequestHeaders([][2]string{
{":authority", "mcp-server.example.com"},
{":method", "POST"},
{":path", "/mcp"},
{"content-type", "application/json"},
})
toolsListRequest := `{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list",
"params": {}
}`
action := host.CallOnHttpRequestBody([]byte(toolsListRequest))
require.Equal(t, types.ActionContinue, action)
host.CompleteHttp()
}
// TestProcessToolCallRequest tests processToolCallRequest function
func TestProcessToolCallRequest(t *testing.T) {
configBytes, _ := json.Marshal(McpConverterConfig{
Stage: ProcessRequest,
MaxHeaderLength: DefaultMaxHeaderLength,
AllowedMethods: []string{MethodToolCall},
})
host, status := test.NewTestHost(configBytes)
defer host.Reset()
require.Equal(t, types.OnPluginStartStatusOK, status)
host.InitHttp()
host.CallOnHttpRequestHeaders([][2]string{
{":authority", "mcp-server.example.com"},
{":method", "POST"},
{":path", "/mcp"},
{"content-type", "application/json"},
})
toolCallRequest := `{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "test_tool",
"arguments": {"arg1": "value1"}
}
}`
action := host.CallOnHttpRequestBody([]byte(toolCallRequest))
require.Equal(t, types.ActionContinue, action)
host.CompleteHttp()
}
// TestProcessJsonRpcResponse tests processJsonRpcResponse function
func TestProcessJsonRpcResponse(t *testing.T) {
configBytes, _ := json.Marshal(McpConverterConfig{
Stage: ProcessResponse,
MaxHeaderLength: DefaultMaxHeaderLength,
AllowedMethods: []string{MethodToolList, MethodToolCall},
})
host, status := test.NewTestHost(configBytes)
defer host.Reset()
require.Equal(t, types.OnPluginStartStatusOK, status)
host.InitHttp()
host.CallOnHttpRequestHeaders([][2]string{
{":authority", "mcp-server.example.com"},
{":method", "POST"},
{":path", "/mcp"},
{"content-type", "application/json"},
})
responseBody := `{
"jsonrpc": "2.0",
"id": 1,
"result": {
"tools": [{"name": "test_tool"}]
}
}`
host.CallOnHttpResponseHeaders([][2]string{
{":status", "200"},
{"content-type", "application/json"},
})
host.CallOnHttpResponseBody([]byte(responseBody))
host.CompleteHttp()
}
// TestProcessToolListResponse tests processToolListResponse function
func TestProcessToolListResponse(t *testing.T) {
configBytes, _ := json.Marshal(McpConverterConfig{
Stage: ProcessResponse,
MaxHeaderLength: DefaultMaxHeaderLength,
AllowedMethods: []string{MethodToolList},
})
host, status := test.NewTestHost(configBytes)
defer host.Reset()
require.Equal(t, types.OnPluginStartStatusOK, status)
host.InitHttp()
host.CallOnHttpRequestHeaders([][2]string{
{":authority", "mcp-server.example.com"},
{":method", "POST"},
{":path", "/mcp"},
{"content-type", "application/json"},
})
responseBody := `{
"jsonrpc": "2.0",
"id": 1,
"result": {
"tools": [{"name": "test_tool"}]
}
}`
host.CallOnHttpResponseHeaders([][2]string{
{":status", "200"},
{"content-type", "application/json"},
})
host.CallOnHttpResponseBody([]byte(responseBody))
host.CompleteHttp()
}

View File

@@ -0,0 +1,89 @@
# MCP Router Plugin
## Feature Description
The `mcp-router` plugin provides a routing capability for MCP (Model Context Protocol) `tools/call` requests. It inspects the tool name in the request payload, and if the name is prefixed with a server identifier (e.g., `server-name/tool-name`), it dynamically reroutes the request to the appropriate backend MCP server.
This enables the creation of a unified MCP endpoint that can aggregate tools from multiple, distinct MCP servers. A client can make a `tools/call` request to a single endpoint, and the `mcp-router` will ensure it reaches the correct underlying server where the tool is actually hosted.
## Configuration Fields
| Name | Data Type | Required | Default Value | Description |
|-----------|---------------|----------|---------------|---------------------------------------------------------------------------------------------------------|
| `servers` | array of objects | Yes | - | A list of routing configurations for each backend MCP server. |
| `servers[].name` | string | Yes | - | The unique identifier for the MCP server. This must match the prefix used in the `tools/call` request's tool name. |
| `servers[].domain` | string | No | - | The domain (authority) of the backend MCP server. If omitted, the original request's domain will be kept. |
| `servers[].path` | string | Yes | - | The path of the backend MCP server to which the request will be routed. |
## How It Works
When a `tools/call` request is processed by a route with the `mcp-router` plugin enabled, the following occurs:
1. **Tool Name Parsing**: The plugin inspects the `name` parameter within the `params` object of the JSON-RPC request.
2. **Prefix Matching**: It checks if the tool name follows the `server-name/tool-name` format.
- If it does not match this format, the plugin takes no action, and the request proceeds normally.
- If it matches, the plugin extracts the `server-name` and the actual `tool-name`.
3. **Route Lookup**: The extracted `server-name` is used to look up the corresponding routing configuration (domain and path) from the `servers` list in the plugin's configuration.
4. **Header Modification**:
- The `:authority` request header is replaced with the `domain` from the matched server configuration.
- The `:path` request header is replaced with the `path` from the matched server configuration.
5. **Request Body Modification**: The `name` parameter in the JSON-RPC request body is updated to be just the `tool-name` (the `server-name/` prefix is removed).
6. **Rerouting**: After the headers are modified, the gateway's routing engine processes the request again with the new destination information, sending it to the correct backend MCP server.
### Example Configuration
Here is an example of how to configure the `mcp-router` plugin in a `higress-plugins.yaml` file:
```yaml
servers:
- name: random-user-server
domain: mcp.example.com
path: /mcp-servers/mcp-random-user-server
- name: rest-amap-server
domain: mcp.example.com
path: /mcp-servers/mcp-rest-amap-server
```
### Example Usage
Consider a `tools/call` request sent to an endpoint where the `mcp-router` is active:
**Original Request:**
```json
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "rest-amap-server/get-weather",
"arguments": {
"location": "New York"
}
}
}
```
**Plugin Actions:**
1. The plugin identifies the tool name as `rest-amap-server/get-weather`.
2. It extracts `server-name` as `rest-amap-server` and `tool-name` as `get-weather`.
3. It finds the matching configuration: `domain: mcp.example.com`, `path: /mcp-servers/mcp-rest-amap-server`.
4. It modifies the request headers to:
- `:authority`: `mcp.example.com`
- `:path`: `/mcp-servers/mcp-rest-amap-server`
5. It modifies the request body to:
```json
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "get-weather",
"arguments": {
"location": "New York"
}
}
}
```
The request is then rerouted to the `rest-amap-server`.

View File

@@ -0,0 +1,89 @@
# MCP Router 插件
## 功能说明
`mcp-router` 插件为 MCP (Model Context Protocol) 的 `tools/call` 请求提供了路由能力。它会检查请求负载中的工具名称,如果名称带有服务器标识符前缀(例如 `server-name/tool-name`),它会动态地将请求重新路由到相应的后端 MCP 服务器。
这使得创建一个统一的 MCP 端点成为可能,该端点可以聚合来自多个不同 MCP 服务器的工具。客户端可以向单个端点发出 `tools/call` 请求,`mcp-router` 将确保请求到达托管该工具的正确底层服务器。
## 配置字段
| 名称 | 数据类型 | 填写要求 | 默认值 | 描述 |
|---|---|---|---|---|
| `servers` | 对象数组 | 是 | - | 每个后端 MCP 服务器的路由配置列表。 |
| `servers[].name` | 字符串 | 是 | - | MCP 服务器的唯一标识符。这必须与 `tools/call` 请求的工具名称中使用的前缀相匹配。 |
| `servers[].domain` | 字符串 | 否 | - | 后端 MCP 服务器的域名 (authority)。如果省略,将保留原始请求的域名。 |
| `servers[].path` | 字符串 | 是 | - | 请求将被路由到的后端 MCP 服务器的路径。 |
## 工作原理
当一个启用了 `mcp-router` 插件的路由处理 `tools/call` 请求时,会发生以下情况:
1. **工具名称解析**:插件检查 JSON-RPC 请求中 `params` 对象的 `name` 参数。
2. **前缀匹配**:它检查工具名称是否遵循 `server-name/tool-name` 格式。
- 如果不匹配此格式,插件不执行任何操作,请求将正常继续。
- 如果匹配,插件将提取 `server-name` 和实际的 `tool-name`
3. **路由查找**:提取的 `server-name` 用于从插件配置的 `servers` 列表中查找相应的路由配置domain 和 path
4. **Header 修改**
- `:authority` 请求头被替换为匹配的服务器配置中的 `domain`
- `:path` 请求头被替换为匹配的服务器配置中的 `path`
5. **请求体修改**JSON-RPC 请求体中的 `name` 参数被更新为仅包含 `tool-name`(移除了 `server-name/` 前缀)。
6. **重新路由**:在 Header 修改后,网关的路由引擎会使用新的目标信息再次处理请求,将其发送到正确的后端 MCP 服务器。
### 配置示例
以下是在 `higress-plugins.yaml` 文件中配置 `mcp-router` 插件的示例:
```yaml
servers:
- name: random-user-server
domain: mcp.example.com
path: /mcp-servers/mcp-random-user-server
- name: rest-amap-server
domain: mcp.example.com
path: /mcp-servers/mcp-rest-amap-server
```
### 使用示例
假设一个 `tools/call` 请求被发送到激活了 `mcp-router` 的端点:
**原始请求:**
```json
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "rest-amap-server/get-weather",
"arguments": {
"location": "New York"
}
}
}
```
**插件行为:**
1. 插件识别出工具名称为 `rest-amap-server/get-weather`
2. 它提取出 `server-name``rest-amap-server``tool-name``get-weather`
3. 它找到匹配的配置:`domain: mcp.example.com`, `path: /mcp-servers/mcp-rest-amap-server`
4. 它将请求头修改为:
- `:authority`: `mcp.example.com`
- `:path`: `/mcp-servers/mcp-rest-amap-server`
5. 它将请求体修改为:
```json
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "get-weather",
"arguments": {
"location": "New York"
}
}
}
```
请求随后被重新路由到 `rest-amap-server`。

View File

@@ -0,0 +1,38 @@
module mcp-router
go 1.24.1
replace github.com/alibaba/higress/plugins/wasm-go/pkg/mcp => ../../pkg/mcp
require (
github.com/alibaba/higress/plugins/wasm-go/pkg/mcp v0.0.0
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20251103120604-77e9cce339d2
github.com/higress-group/wasm-go v1.0.10-0.20260115123534-84ef43c39dc9
github.com/tidwall/gjson v1.18.0
github.com/tidwall/sjson v1.2.5
)
require (
dario.cat/mergo v1.0.1 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.3.0 // indirect
github.com/Masterminds/sprig/v3 v3.3.0 // indirect
github.com/bahlo/generic-list-go v0.2.0 // indirect
github.com/buger/jsonparser v1.1.1 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/higress-group/gjson_template v0.0.0-20250413075336-4c4161ed428b // indirect
github.com/huandu/xstrings v1.5.0 // indirect
github.com/invopop/jsonschema v0.13.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/shopspring/decimal v1.4.0 // indirect
github.com/spf13/cast v1.7.0 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
github.com/tidwall/resp v0.1.1 // indirect
github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
golang.org/x/crypto v0.26.0 // indirect
google.golang.org/protobuf v1.36.6 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

View File

@@ -0,0 +1,73 @@
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0=
github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs=
github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0=
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/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/higress-group/gjson_template v0.0.0-20250413075336-4c4161ed428b h1:rRI9+ThQbe+nw4jUiYEyOFaREkXCMMW9k1X2gy2d6pE=
github.com/higress-group/gjson_template v0.0.0-20250413075336-4c4161ed428b/go.mod h1:rU3M+Tq5VrQOo0dxpKHGb03Ty0sdWIZfAH+YCOACx/Y=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20251103120604-77e9cce339d2 h1:NY33OrWCJJ+DFiLc+lsBY4Ywor2Ik61ssk6qkGF8Ypo=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20251103120604-77e9cce339d2/go.mod h1:tRI2LfMudSkKHhyv1uex3BWzcice2s/l8Ah8axporfA=
github.com/higress-group/wasm-go v1.0.10-0.20260115123534-84ef43c39dc9 h1:sUuUXZwr50l3W1St7MESlFmxmUAu+QUNNfJXx4P6bas=
github.com/higress-group/wasm-go v1.0.10-0.20260115123534-84ef43c39dc9/go.mod h1:uKVYICbRaxTlKqdm8E0dpjbysxM8uCPb9LV26hF3Km8=
github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI=
github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/invopop/jsonschema v0.13.0 h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcIi21E=
github.com/invopop/jsonschema v0.13.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tidwall/resp v0.1.1 h1:Ly20wkhqKTmDUPlyM1S7pWo5kk0tDu8OoC/vFArXmwE=
github.com/tidwall/resp v0.1.1/go.mod h1:3/FrruOBAxPTPtundW0VXgmsQ4ZBA0Aw714lVYgwFa0=
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
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=
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@@ -0,0 +1,162 @@
// Copyright (c) 2022 Alibaba Group Holding Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"encoding/json"
"fmt"
"strings"
"github.com/higress-group/proxy-wasm-go-sdk/proxywasm"
"github.com/higress-group/proxy-wasm-go-sdk/proxywasm/types"
"github.com/higress-group/wasm-go/pkg/log"
"github.com/alibaba/higress/plugins/wasm-go/pkg/mcp"
"github.com/alibaba/higress/plugins/wasm-go/pkg/mcp/consts"
"github.com/higress-group/wasm-go/pkg/wrapper"
"github.com/tidwall/gjson"
"github.com/tidwall/sjson"
)
func main() {}
func init() {
mcp.LoadMCPFilter(
mcp.FilterName("mcp-router"),
mcp.SetConfigOverrideParser(ParseGlobalConfig, ParseOverrideConfig),
mcp.SetToolCallRequestFilter(ProcessRequest),
)
mcp.InitMCPFilter()
}
// ServerConfig represents the routing configuration for a single MCP server
type ServerConfig struct {
Name string `json:"name"`
Domain string `json:"domain,omitempty"`
Path string `json:"path"`
}
// McpRouterGlobalConfig represents the global configuration for the mcp-router filter
type McpRouterGlobalConfig struct {
Servers []ServerConfig `json:"servers"`
}
type McpRouterConfig struct {
global *McpRouterGlobalConfig
enable bool
}
func ParseGlobalConfig(configBytes []byte, globalConfig *any) error {
var config McpRouterGlobalConfig
if err := json.Unmarshal(configBytes, &config); err != nil {
return fmt.Errorf("failed to parse mcp-router config: %v", err)
}
log.Infof("Parsed mcp-router config with %d servers", len(config.Servers))
for _, server := range config.Servers {
log.Debugf("Server: %s -> %s%s", server.Name, server.Domain, server.Path)
}
*globalConfig = config
return nil
}
func ParseOverrideConfig(configBytes []byte, globalConfig any, ruleConfig *any) error {
var config McpRouterConfig
if globalConfig == nil {
config.global = &McpRouterGlobalConfig{}
config.enable = false
*ruleConfig = config
log.Error("globalConfig not found, mcp router will not work")
return nil
}
parent, ok := globalConfig.(McpRouterGlobalConfig)
if !ok {
return fmt.Errorf("invalid globalConfig: %v", globalConfig)
}
config.global = &parent
config.enable = gjson.GetBytes(configBytes, "enable").Bool()
*ruleConfig = config
return nil
}
func ProcessRequest(context wrapper.HttpContext, config any, toolName string, toolArgs gjson.Result, rawBody []byte) types.Action {
routerConfig, ok := config.(McpRouterConfig)
if !ok {
log.Errorf("Invalid config type for mcp-router")
return types.ActionContinue
}
if !routerConfig.enable {
return types.ActionContinue
}
// Extract server name from tool name (format: "${serverName}___${toolName}")
parts := strings.SplitN(toolName, consts.ToolSetNameSplitter, 2)
if len(parts) != 2 {
log.Debugf("Tool name '%s' does not contain server prefix, continuing without routing", toolName)
return types.ActionContinue
}
serverName := parts[0]
actualToolName := parts[1]
log.Debugf("Routing tool call: server=%s, tool=%s", serverName, actualToolName)
// Find the server configuration
var targetServer *ServerConfig
for _, server := range routerConfig.global.Servers {
if server.Name == serverName {
targetServer = &server
break
}
}
if targetServer == nil {
log.Warnf("No routing configuration found for server '%s'", serverName)
return types.ActionContinue
}
log.Infof("Routing to server '%s': domain=[%s], path=[%s]", serverName, targetServer.Domain, targetServer.Path)
// Modify the :authority header (domain) if it's configured
if targetServer.Domain != "" {
if err := proxywasm.ReplaceHttpRequestHeader(":authority", targetServer.Domain); err != nil {
log.Errorf("Failed to set :authority header to '%s': %v", targetServer.Domain, err)
return types.ActionContinue
}
}
proxywasm.ReplaceHttpRequestHeader("x-envoy-internal-route", "true")
// Modify the :path header
if err := proxywasm.ReplaceHttpRequestHeader(":path", targetServer.Path); err != nil {
log.Errorf("Failed to set :path header to '%s': %v", targetServer.Path, err)
return types.ActionContinue
}
// Create a new JSON with the modified tool name
modifiedBody, err := sjson.SetBytes(rawBody, "params.name", actualToolName)
if err != nil {
log.Errorf("Failed to modify tool name, body: %s, err: %v", rawBody, err)
return types.ActionContinue
}
// Replace the request body
if err := proxywasm.ReplaceHttpRequestBody([]byte(modifiedBody)); err != nil {
log.Errorf("Failed to replace request body: %v", err)
return types.ActionContinue
}
log.Infof("Successfully routed request for tool '%s' to server '%s'. New tool name is '%s'.",
toolName, serverName, actualToolName)
return types.ActionContinue
}

View File

@@ -0,0 +1,48 @@
module mcp-server
go 1.24.1
replace (
amap-tools => ../../mcp-servers/amap-tools
github.com/alibaba/higress/plugins/wasm-go/pkg/mcp => ../../pkg/mcp
quark-search => ../../mcp-servers/quark-search
)
require (
amap-tools v0.0.0-00010101000000-000000000000
github.com/alibaba/higress/plugins/wasm-go/pkg/mcp v0.0.0
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20251103120604-77e9cce339d2
github.com/higress-group/wasm-go v1.0.10-0.20260115123534-84ef43c39dc9
github.com/stretchr/testify v1.9.0
quark-search v0.0.0-00010101000000-000000000000
)
require (
dario.cat/mergo v1.0.1 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.3.0 // indirect
github.com/Masterminds/sprig/v3 v3.3.0 // indirect
github.com/bahlo/generic-list-go v0.2.0 // indirect
github.com/buger/jsonparser v1.1.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/higress-group/gjson_template v0.0.0-20250413075336-4c4161ed428b // indirect
github.com/huandu/xstrings v1.5.0 // indirect
github.com/invopop/jsonschema v0.13.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/shopspring/decimal v1.4.0 // indirect
github.com/spf13/cast v1.7.0 // indirect
github.com/tetratelabs/wazero v1.7.2 // indirect
github.com/tidwall/gjson v1.18.0 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
github.com/tidwall/resp v0.1.1 // indirect
github.com/tidwall/sjson v1.2.5 // indirect
github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
golang.org/x/crypto v0.26.0 // indirect
google.golang.org/protobuf v1.36.6 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

View File

@@ -0,0 +1,75 @@
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0=
github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs=
github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0=
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/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/higress-group/gjson_template v0.0.0-20250413075336-4c4161ed428b h1:rRI9+ThQbe+nw4jUiYEyOFaREkXCMMW9k1X2gy2d6pE=
github.com/higress-group/gjson_template v0.0.0-20250413075336-4c4161ed428b/go.mod h1:rU3M+Tq5VrQOo0dxpKHGb03Ty0sdWIZfAH+YCOACx/Y=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20251103120604-77e9cce339d2 h1:NY33OrWCJJ+DFiLc+lsBY4Ywor2Ik61ssk6qkGF8Ypo=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20251103120604-77e9cce339d2/go.mod h1:tRI2LfMudSkKHhyv1uex3BWzcice2s/l8Ah8axporfA=
github.com/higress-group/wasm-go v1.0.10-0.20260115123534-84ef43c39dc9 h1:sUuUXZwr50l3W1St7MESlFmxmUAu+QUNNfJXx4P6bas=
github.com/higress-group/wasm-go v1.0.10-0.20260115123534-84ef43c39dc9/go.mod h1:uKVYICbRaxTlKqdm8E0dpjbysxM8uCPb9LV26hF3Km8=
github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI=
github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/invopop/jsonschema v0.13.0 h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcIi21E=
github.com/invopop/jsonschema v0.13.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tetratelabs/wazero v1.7.2 h1:1+z5nXJNwMLPAWaTePFi49SSTL0IMx/i3Fg8Yc25GDc=
github.com/tetratelabs/wazero v1.7.2/go.mod h1:ytl6Zuh20R/eROuyDaGPkp82O9C/DJfXAwJfQ3X6/7Y=
github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tidwall/resp v0.1.1 h1:Ly20wkhqKTmDUPlyM1S7pWo5kk0tDu8OoC/vFArXmwE=
github.com/tidwall/resp v0.1.1/go.mod h1:3/FrruOBAxPTPtundW0VXgmsQ4ZBA0Aw714lVYgwFa0=
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
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=
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@@ -0,0 +1,32 @@
// Copyright (c) 2022 Alibaba Group Holding Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
amap "amap-tools/tools"
quark "quark-search/tools"
"github.com/alibaba/higress/plugins/wasm-go/pkg/mcp"
)
func main() {}
func init() {
mcp.LoadMCPServer(mcp.AddMCPServer("quark-search",
quark.LoadTools(mcp.NewMCPServer())))
mcp.LoadMCPServer(mcp.AddMCPServer("amap-tools",
amap.LoadTools(mcp.NewMCPServer())))
mcp.InitMCPServer()
}

View File

File diff suppressed because it is too large Load Diff