Skip to content

Higress 2.1.2 + Nacos MCP Registry 生成的 MCP 路由匹配顺序不符合预期 #2173

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
1 task done
CH3CHO opened this issue May 6, 2025 · 2 comments
Open
1 task done
Assignees

Comments

@CH3CHO
Copy link
Collaborator

CH3CHO commented May 6, 2025

If you are reporting any crash or any potential security issue, do not
open an issue in this repo. Please report the issue via ASRC(Alibaba Security Response Center) where the issue will be triaged appropriately.

  • I have searched the issues of this repository and believe that this is not a duplicate.

Ⅰ. Issue Description

Higress 为 Nacos MCP Registry 中注册的服务所生成的路由使用的是前缀匹配方式,且路由顺序未经过合理排序,导致 A 服务名称被 B 服务名称所包含时,发往 B 服务的请求匹配到 A 服务的路由。

Ⅱ. Describe what happened

重现流程:

  1. 在 Nacos Console 上配置两个 MCP Server,名称分别为 sayhellosayhello-2
    Image
  2. 在 Higress Console 为 Nacos 添加一个 Nacos 3.x 类型的服务来源,并设置为 MCP 类型
    Image
  3. 尝试请求 http://higress-gateway-ip/mcp/sayhello-2,发现请求关联到了 sayhello 的 cluster
    Image

配置信息:

通过请求 http://pilot:15014/debug/configzhttp://gateway:15000/debug/configz 获取线上配置数据发现,sayhello 的路由排在 sayhello-2 的路由前面,并且它们都用的是 prefix 的匹配方式。这可能就是导致本问题的原因。

http://pilot:15014/debug/configz 返回数据节选(顺序未调整):

{
  "apiVersion": "networking.istio.io/v1alpha3",
  "kind": "VirtualService",
  "metadata": {
    "annotations": {
      "ResourceVersion": ""
    },
    "creationTimestamp": null,
    "name": "istio-autogenerated-mcp-vs-mcp-server-sayhello-mcp-server.json",
    "namespace": "higress-system",
    "resourceVersion": "2025-05-06 10:43:28.470445038 +0000 UTC m=+1567.039305796"
  },
  "spec": {
    "gateways": [
      "higress-system/61af79b04c9c8e70",
      "istio-autogenerated-k8s-ingress-61af79b04c9c8e70"
    ],
    "hosts": [
      "*"
    ],
    "http": [
      {
        "match": [
          {
            "uri": {
              "prefix": "/mcp/sayhello"
            }
          }
        ],
        "name": "istio-autogenerated-mcp-httproute-mcp-server-sayhello-mcp-server",
        "rewrite": {
          "uri": "/"
        },
        "route": [
          {
            "destination": {
              "host": "sayhello.mcp-endpoints.nacos-default-mcp.nacos",
              "port": {
                "number": 80
              }
            }
          }
        ]
      }
    ]
  }
},
{
  "apiVersion": "networking.istio.io/v1alpha3",
  "kind": "VirtualService",
  "metadata": {
    "annotations": {
      "ResourceVersion": ""
    },
    "creationTimestamp": null,
    "name": "istio-autogenerated-mcp-vs-mcp-server-sayhello-2-mcp-server.json",
    "namespace": "higress-system",
    "resourceVersion": "2025-05-06 10:43:28.470455288 +0000 UTC m=+1567.039316046"
  },
  "spec": {
    "gateways": [
      "higress-system/61af79b04c9c8e70",
      "istio-autogenerated-k8s-ingress-61af79b04c9c8e70"
    ],
    "hosts": [
      "*"
    ],
    "http": [
      {
        "match": [
          {
            "uri": {
              "prefix": "/mcp/sayhello-2"
            }
          }
        ],
        "name": "istio-autogenerated-mcp-httproute-mcp-server-sayhello-2-mcp-server",
        "rewrite": {
          "uri": "/"
        },
        "route": [
          {
            "destination": {
              "host": "sayhello-2.mcp-endpoints.nacos-default-mcp.nacos",
              "port": {
                "number": 8080
              }
            }
          }
        ]
      }
    ]
  }
}

http://gateway:15000/debug/configz 返回数据节选(顺序未调整):

{
  "decorator": {
    "operation": "sayhello.mcp-endpoints.nacos-default-mcp.nacos:80/mcp/sayhello*"
  },
  "match": {
    "case_sensitive": true,
    "prefix": "/mcp/sayhello"
  },
  "metadata": {
    "filter_metadata": {
      "istio": {
        "config": "/apis/networking.istio.io/v1alpha3/namespaces/higress-system/virtual-service/istio-autogenerated-mcp-vs-mcp-server-sayhello-mcp-server.json"
      }
    }
  },
  "name": "istio-autogenerated-mcp-httproute-mcp-server-sayhello-mcp-server",
  "route": {
    "cluster": "outbound|80||sayhello.mcp-endpoints.nacos-default-mcp.nacos",
    "max_grpc_timeout": "0s",
    "prefix_rewrite": "/",
    "retry_policy": {
      "host_selection_retry_max_attempts": "5",
      "num_retries": 2,
      "retriable_request_headers": [
        {
          "invert_match": true,
          "name": ":method",
          "string_match": {
            "safe_regex": {
              "google_re2": {},
              "regex": "POST|PATCH|LOCK"
            }
          }
        }
      ],
      "retriable_status_codes": [
        503
      ],
      "retry_host_predicate": [
        {
          "name": "envoy.retry_host_predicates.previous_hosts",
          "typed_config": {
            "@type": "type.googleapis.com/envoy.extensions.retry.host.previous_hosts.v3.PreviousHostsPredicate"
          }
        }
      ],
      "retry_on": "connect-failure,refused-stream,unavailable,cancelled,retriable-status-codes"
    },
    "timeout": "0s"
  }
},
{
  "decorator": {
    "operation": "sayhello-2.mcp-endpoints.nacos-default-mcp.nacos:8080/mcp/sayhello-2*"
  },
  "match": {
    "case_sensitive": true,
    "prefix": "/mcp/sayhello-2"
  },
  "metadata": {
    "filter_metadata": {
      "istio": {
        "config": "/apis/networking.istio.io/v1alpha3/namespaces/higress-system/virtual-service/istio-autogenerated-mcp-vs-mcp-server-sayhello-2-mcp-server.json"
      }
    }
  },
  "name": "istio-autogenerated-mcp-httproute-mcp-server-sayhello-2-mcp-server",
  "route": {
    "cluster": "outbound|8080||sayhello-2.mcp-endpoints.nacos-default-mcp.nacos",
    "max_grpc_timeout": "0s",
    "prefix_rewrite": "/",
    "retry_policy": {
      "host_selection_retry_max_attempts": "5",
      "num_retries": 2,
      "retriable_request_headers": [
        {
          "invert_match": true,
          "name": ":method",
          "string_match": {
            "safe_regex": {
              "google_re2": {},
              "regex": "POST|PATCH|LOCK"
            }
          }
        }
      ],
      "retriable_status_codes": [
        503
      ],
      "retry_host_predicate": [
        {
          "name": "envoy.retry_host_predicates.previous_hosts",
          "typed_config": {
            "@type": "type.googleapis.com/envoy.extensions.retry.host.previous_hosts.v3.PreviousHostsPredicate"
          }
        }
      ],
      "retry_on": "connect-failure,refused-stream,unavailable,cancelled,retriable-status-codes"
    },
    "timeout": "0s"
  }
}

Ⅲ. Describe what you expected to happen

MCP 请求应关联到正确的后端服务集群。

Ⅳ. How to reproduce it (as minimally and precisely as possible)

见 Ⅱ

Ⅴ. Anything else we need to know?

修复时可以参考现在一般 Ingress 路由生成 VirtualService 时所使用的匹配规则:

{
  "match": [
    {
      "uri": {
        "exact": "/home"
      }
    },
    {
      "uri": {
        "prefix": "/home/"
      }
    }
  ]
}

Ⅵ. Environment:

  • Higress version: 2.1.2
    • higress-registry.cn-hangzhou.cr.aliyuncs.com/higress/higress 镜像使用 latest tag(目的是修复 Nacos 3.x 的认证问题)
    • 其余镜像均使用 2.1.2 tag。
  • Nacos version: 3.0.0
  • OS: Windows 10
  • Others: K8s 1.32.3+k3s1(Rancher Desktop)
@CH3CHO
Copy link
Collaborator Author

CH3CHO commented May 6, 2025

CC @johnlanni @Erica177

@Erica177
Copy link
Collaborator

Erica177 commented May 7, 2025

CC @johnlanni @Erica177

按照现在的设计来说,可以通过添加后缀((/).*)?,将前缀匹配改写成正则匹配来解决这个问题,比如:

{
  "match": [
    {
      "uri": {
        "regex": "/say/hello((\/).*)?"
      }
    },
    {
      "uri": {
        "regex": "/say/hello2((\/).*)?"
      }
    }
  ]
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants