MCP Server 管理
第 3 周收官。MCP(Model Context Protocol)让大模型能调用外部工具。今天看 Console 怎么管理 MCP Server:三种类型、双策略工厂(开闭原则的漂亮范例),以及它"不是独立 CRD"的存储设计。
MCP 是什么
OpenAPI/Swagger 文档 → 经 swaggerToMcpConfig 转换 → 输出一份 MCP 工具配置,里面多了个 queryOrder(orderId) 工具 → 大模型就能"调用 queryOrder 查 3 号订单"了。McpServerController 8 端点
controller/mcp/McpServerController.java(/v1/mcpServer,:53-57,注入 McpServerService + McpServerHelper):
POST /swaggerToMcpConfig :65 // Swagger/OpenAPI → MCP 工具配置
PUT / :73 // addOrUpdateWithAuthorization
GET / :82 // list
GET /{name} :90
DELETE /{name} :98
PUT /consumers :107 // 加允许的消费者
DELETE /consumers :117
GET /consumers :127
三种 MCP 类型
McpServerTypeEnum(sdk/model/mcp/):
- OPEN_API:把 REST API 转成 MCP 工具,走 mcp-server Wasm 插件。
- DATABASE:把数据库暴露成固定的工具集(query / execute / list tables / describe table)。
- DIRECT_ROUTE:上游本身就是 MCP 服务,只做直路由/重写。
McpServerDBTypeEnum 支持 mysql/postgres/sqlite/clickhouse。双策略工厂(本课设计亮点)
if type==OPEN_API … else if … 就完了?👨🏫:能跑,但每加一种类型就要回去改那个大方法,越改越乱、越容易改坏别人。
👶:那"策略工厂"好在哪?
👨🏫:每种类型一个策略类,工厂用
support() 挑出匹配的那个。加第四种类型 = 新增一个策略类 + 注册,老代码一行不动——这就是开闭原则(对扩展开放、对修改关闭)。回想 Day 11 的 Handler 注册表,是同一招。McpServiceContextImpl.java(:67)构造时装配两个工厂(:85-87):McpServerSaveStrategyFactory(保存)和 McpServerDetailStrategyFactory(查详情)。
保存策略(mcp/save/):工厂用 getService(McpServer) 遍历各策略的 support() 找到匹配的。三种实现:OpenApiSaveStrategy / DatabaseSaveStrategy / DirectRoutingSaveStrategy。详情策略(mcp/detail/)对称三个。
save = saveRoute + saveMcpServerConfig,saveWithAuthorization 再加 saveAuthInfo。存储 = Route + ConfigMap(非独立 CRD)
MCP Server 不是独立 CRD,而是"内部 Route(底层 Ingress,前缀 mcp-server-)+ higress-config ConfigMap 的 mcpServer 段"。McpServiceContextImpl:query(:101-111)、list(:113-130,label higress.io/resource-biz-type=mcp-server)、delete(:132-137)。
McpServerConfigMapHelper.updateMcpConfig2ConfigMap(:146-224)增量合并不覆盖用户字段;data key higress,段 mcpServer(含 sse_path_suffix=/sse、enable、redis 占位、match_list、servers)。
Swagger → MCP 转换
McpServerHelper.swaggerToMcpConfig(:65-113)通过 ProcessBuilder 调外部脚本 openapiToMcpserver.sh(Day 19 会看到它被打进 Docker 镜像),把 OpenAPI 文档转成 MCP 工具配置,并带命令注入防护 trimCmdWithCh(:115-130)。
ProcessBuilder 启动这个进程、传入 OpenAPI、读回结果——不重复造轮子。trimCmdWithCh 是安全护栏:拼命令行时过滤危险字符,防"命令注入"攻击(别人在参数里塞 ; rm -rf 之类)。MCP 消费者
MCP 也能配"谁能访问"。addAllowConsumers/deleteAllowConsumers(:139-153)最终落到该 MCP 对应 Route 的 key-auth allow list(ADD/REMOVE),保存时 saveAuthInfo 用 REPLACE 全量替换。无独立存储。
ConsumerAuthInfo(type/enable/allowedConsumers)承载这些信息。今日小结 + 动手(第 3 周收官)
🧠 第 3 周你应该能回答
- MCP 是什么?三种类型分别包装什么?
- 双策略工厂怎么体现开闭原则?
- MCP Server 存储为什么不是独立 CRD?
- Swagger→MCP 为什么调外部脚本?命令注入怎么防?
- MCP 鉴权和消费者鉴权是不是一套机制?
✋ 动手
cd /Users/bitmart/work/codes/github/higress-group/higress-console/backend
find . -path '*/service/mcp/*' -name '*.java' | head -30
sed -n '65,130p' sdk/src/main/java/com/alibaba/higress/sdk/service/mcp/McpServerHelper.java 2>/dev/null || \
grep -rn "swaggerToMcpConfig\|trimCmdWithCh" sdk/