fix: add match list and wasm mcp-server message pub in redis (#1963)

This commit is contained in:
Jingze
2025-03-27 17:00:32 +08:00
committed by GitHub
parent 6f762b5e4c
commit 8495d17070
11 changed files with 991 additions and 68 deletions

View File

@@ -53,6 +53,16 @@ type SSEServer struct {
Config map[string]interface{} `json:"config,omitempty"`
}
// MatchRule defines a rule for matching requests
type MatchRule struct {
// Domain pattern, supports wildcards
MatchRuleDomain string `json:"match_rule_domain,omitempty"`
// Path pattern to match
MatchRulePath string `json:"match_rule_path,omitempty"`
// Type of match rule: exact, prefix, suffix, contains, regex
MatchRuleType string `json:"match_rule_type,omitempty"`
}
// McpServer defines the configuration for MCP (Model Context Protocol) server
type McpServer struct {
// Flag to control whether MCP server is enabled
@@ -63,10 +73,16 @@ type McpServer struct {
SsePathSuffix string `json:"sse_path_suffix,omitempty"`
// List of SSE servers Configs
Servers []*SSEServer `json:"servers,omitempty"`
// List of match rules for filtering requests
MatchList []*MatchRule `json:"match_list,omitempty"`
}
func NewDefaultMcpServer() *McpServer {
return &McpServer{Enable: false}
return &McpServer{
Enable: false,
Servers: make([]*SSEServer, 0),
MatchList: make([]*MatchRule, 0),
}
}
const (
@@ -82,6 +98,26 @@ func validMcpServer(m *McpServer) error {
return errors.New("redis config cannot be empty when mcp server is enabled")
}
// Validate match rule types
if m.MatchList != nil {
validTypes := map[string]bool{
"exact": true,
"prefix": true,
"suffix": true,
"contains": true,
"regex": true,
}
for _, rule := range m.MatchList {
if rule.MatchRuleType == "" {
return errors.New("match_rule_type cannot be empty, must be one of: exact, prefix, suffix, contains, regex")
}
if !validTypes[rule.MatchRuleType] {
return fmt.Errorf("invalid match_rule_type: %s, must be one of: exact, prefix, suffix, contains, regex", rule.MatchRuleType)
}
}
}
return nil
}
@@ -134,6 +170,17 @@ func deepCopyMcpServer(mcp *McpServer) (*McpServer, error) {
}
}
if len(mcp.MatchList) > 0 {
newMcp.MatchList = make([]*MatchRule, len(mcp.MatchList))
for i, rule := range mcp.MatchList {
newMcp.MatchList[i] = &MatchRule{
MatchRuleDomain: rule.MatchRuleDomain,
MatchRulePath: rule.MatchRulePath,
MatchRuleType: rule.MatchRuleType,
}
}
}
return newMcp, nil
}
@@ -268,7 +315,7 @@ func (m *McpServerController) ConstructEnvoyFilters() ([]*config.Config, error)
}
func (m *McpServerController) constructMcpServerStruct(mcp *McpServer) string {
// 构建 servers 配置
// Build servers configuration
servers := "[]"
if len(mcp.Servers) > 0 {
serverConfigs := make([]string, len(mcp.Servers))
@@ -291,7 +338,21 @@ func (m *McpServerController) constructMcpServerStruct(mcp *McpServer) string {
servers = fmt.Sprintf("[%s]", strings.Join(serverConfigs, ","))
}
// 构建完整的配置结构
// Build match_list configuration
matchList := "[]"
if len(mcp.MatchList) > 0 {
matchConfigs := make([]string, len(mcp.MatchList))
for i, rule := range mcp.MatchList {
matchConfigs[i] = fmt.Sprintf(`{
"match_rule_domain": "%s",
"match_rule_path": "%s",
"match_rule_type": "%s"
}`, rule.MatchRuleDomain, rule.MatchRulePath, rule.MatchRuleType)
}
matchList = fmt.Sprintf("[%s]", strings.Join(matchConfigs, ","))
}
// Build complete configuration structure
structFmt := `{
"name": "envoy.filters.http.golang",
"typed_config": {
@@ -310,6 +371,7 @@ func (m *McpServerController) constructMcpServerStruct(mcp *McpServer) string {
"db": %d
},
"sse_path_suffix": "%s",
"match_list": %s,
"servers": %s
}
}
@@ -323,5 +385,6 @@ func (m *McpServerController) constructMcpServerStruct(mcp *McpServer) string {
mcp.Redis.Password,
mcp.Redis.DB,
mcp.SsePathSuffix,
matchList,
servers)
}

View File

@@ -31,7 +31,9 @@ func Test_validMcpServer(t *testing.T) {
{
name: "default",
mcp: &McpServer{
Enable: false,
Enable: false,
MatchList: []*MatchRule{},
Servers: []*SSEServer{},
},
wantErr: nil,
},
@@ -43,8 +45,10 @@ func Test_validMcpServer(t *testing.T) {
{
name: "enabled but no redis config",
mcp: &McpServer{
Enable: true,
Redis: nil,
Enable: true,
Redis: nil,
MatchList: []*MatchRule{},
Servers: []*SSEServer{},
},
wantErr: errors.New("redis config cannot be empty when mcp server is enabled"),
},
@@ -59,6 +63,13 @@ func Test_validMcpServer(t *testing.T) {
DB: 0,
},
SsePathSuffix: "/sse",
MatchList: []*MatchRule{
{
MatchRuleDomain: "*",
MatchRulePath: "*",
MatchRuleType: "exact",
},
},
Servers: []*SSEServer{
{
Name: "test-server",
@@ -104,6 +115,8 @@ func Test_compareMcpServer(t *testing.T) {
Redis: &RedisConfig{
Address: "localhost:6379",
},
MatchList: []*MatchRule{},
Servers: []*SSEServer{},
},
new: nil,
wantResult: ResultDelete,
@@ -116,12 +129,16 @@ func Test_compareMcpServer(t *testing.T) {
Redis: &RedisConfig{
Address: "localhost:6379",
},
MatchList: []*MatchRule{},
Servers: []*SSEServer{},
},
new: &McpServer{
Enable: true,
Redis: &RedisConfig{
Address: "localhost:6379",
},
MatchList: []*MatchRule{},
Servers: []*SSEServer{},
},
wantResult: ResultNothing,
wantErr: nil,
@@ -133,12 +150,22 @@ func Test_compareMcpServer(t *testing.T) {
Redis: &RedisConfig{
Address: "localhost:6379",
},
MatchList: []*MatchRule{},
Servers: []*SSEServer{},
},
new: &McpServer{
Enable: true,
Redis: &RedisConfig{
Address: "redis:6379",
},
MatchList: []*MatchRule{
{
MatchRuleDomain: "*",
MatchRulePath: "/test",
MatchRuleType: "exact",
},
},
Servers: []*SSEServer{},
},
wantResult: ResultReplace,
wantErr: nil,
@@ -171,6 +198,8 @@ func Test_deepCopyMcpServer(t *testing.T) {
Password: "password",
DB: 0,
},
MatchList: []*MatchRule{},
Servers: []*SSEServer{},
},
wantMcp: &McpServer{
Enable: true,
@@ -180,6 +209,8 @@ func Test_deepCopyMcpServer(t *testing.T) {
Password: "password",
DB: 0,
},
MatchList: []*MatchRule{},
Servers: []*SSEServer{},
},
wantErr: nil,
},
@@ -194,6 +225,13 @@ func Test_deepCopyMcpServer(t *testing.T) {
DB: 0,
},
SsePathSuffix: "/sse",
MatchList: []*MatchRule{
{
MatchRuleDomain: "*",
MatchRulePath: "*",
MatchRuleType: "exact",
},
},
Servers: []*SSEServer{
{
Name: "test-server",
@@ -214,6 +252,13 @@ func Test_deepCopyMcpServer(t *testing.T) {
DB: 0,
},
SsePathSuffix: "/sse",
MatchList: []*MatchRule{
{
MatchRuleDomain: "*",
MatchRulePath: "*",
MatchRuleType: "exact",
},
},
Servers: []*SSEServer{
{
Name: "test-server",
@@ -280,6 +325,8 @@ func TestMcpServerController_AddOrUpdateHigressConfig(t *testing.T) {
Password: "password",
DB: 0,
},
Servers: []*SSEServer{},
MatchList: []*MatchRule{},
},
},
wantErr: nil,
@@ -292,6 +339,8 @@ func TestMcpServerController_AddOrUpdateHigressConfig(t *testing.T) {
Password: "password",
DB: 0,
},
Servers: []*SSEServer{},
MatchList: []*MatchRule{},
},
},
{
@@ -302,6 +351,8 @@ func TestMcpServerController_AddOrUpdateHigressConfig(t *testing.T) {
Redis: &RedisConfig{
Address: "localhost:6379",
},
Servers: []*SSEServer{},
MatchList: []*MatchRule{},
},
},
new: &HigressConfig{
@@ -310,6 +361,8 @@ func TestMcpServerController_AddOrUpdateHigressConfig(t *testing.T) {
Redis: &RedisConfig{
Address: "redis:6379",
},
Servers: []*SSEServer{},
MatchList: []*MatchRule{},
},
},
wantErr: nil,
@@ -319,6 +372,8 @@ func TestMcpServerController_AddOrUpdateHigressConfig(t *testing.T) {
Redis: &RedisConfig{
Address: "redis:6379",
},
Servers: []*SSEServer{},
MatchList: []*MatchRule{},
},
},
{
@@ -329,6 +384,8 @@ func TestMcpServerController_AddOrUpdateHigressConfig(t *testing.T) {
Redis: &RedisConfig{
Address: "localhost:6379",
},
Servers: []*SSEServer{},
MatchList: []*MatchRule{},
},
},
new: &HigressConfig{