# mcp-weaver **Repository Path**: fushoujiang/mcp-weaver ## Basic Information - **Project Name**: mcp-weaver - **Description**: mcp-weaver 是基于 Spring Boot 的 MCP(Model Context Protocol)网关:只靠配置就能把普通 REST API 变成 MCP 工具。每个业务域拥有独立的 Stateless Streamable HTTP MCP 端点,全部运行时管理——新增工具秒级生效,无需重建、无需重启。 - **Primary Language**: Java - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2026-09-21 - **Last Updated**: 2026-09-27 ## Categories & Tags **Categories**: Uncategorized **Tags**: MCP, AI, AI网关 ## README # mcp-weaver

mcp-weaver —— 把任意 API 织入 MCP 工具(HTTP、Dubbo、MCP 一网收口)

License Java 21 Spring Boot 3.5 MCP 协议版本

> **Java 生态里功能最全的 MCP 网关:把 HTTP REST、Dubbo 服务织成受治理的 MCP 工具,把存量 MCP server 挂为上游——纯配置、毫秒级热更新、一个 fat jar 跑起来。**

mcp-weaver 控制台实录 —— 浏览织入工具、试调用真实执行、审计落痕

真实控制台、真实调用:选中 MySQL 支撑的织入工具 → 控制台试调用(92ms)→ 调用落审计(脱敏)。录制脚本见 docs/record-demo.mjs。

## 为什么选 mcp-weaver —— 一份诚实的对比 | | **mcp-weaver** | Higress | Spring AI Alibaba MCP | IBM ContextForge | |---|---|---|---|---| | 运行时 / 部署 | **单个 Spring Boot fat jar**,有 Java 就能跑 | Go + Envoy + Wasm(K8s 原生) | Spring Boot,以 Nacos 为中心 | Python,多服务组合 | | HTTP REST → MCP | ✅ OpenAPI 3 声明 + 批量导入 | ✅ | ✅ | ✅ | | **Dubbo → MCP** | ✅ **泛化调用,无需提供方 JAR**(2.7 / 3.x) | — | — | — | | 存量 MCP server 挂为**受治理上游** | ✅ stdio / Streamable HTTP / SSE,连接池 + 退避 + 自愈 | ✅ mcp-server 插件 | — | ✅ federation | | 管理控制台 | ✅ **内置零构建、中/英双语**,试调用、审计查看一体 | 独立 console 组件 | — | ✅ Admin UI | | 客户端认证 | ✅ API Key + JWT、scopes、**按 server 覆盖** | ✅ 插件化 | 基础能力 | ✅ | | 客户端限流 / 配额 | ✅ QPS + 并发在途 + 日配额,超限 429 + 审计事件 | ✅ | — | ✅ | | **审计追踪** | ✅ 调用 / 注册 / 凭证全事件,脱敏 + Token 哈希,MySQL / Langfuse,CSV 导出 | 偏 metrics / tracing | — | ✅ | | 配置存储 | ✅ MySQL **与** Nacos 可组合,SPI 可扩展 | Nacos / K8s CRD | Nacos | 可插拔 DB | | 热更新 | ✅ **事件驱动,写入毫秒级生效** | ✅ xDS | ✅ Nacos 推送 | ✅ | | 最适合谁 | 有存量 Spring / Dubbo / Nacos 系统的 Java 企业 | K8s 原生流量入口 | Spring AI Alibaba 用户 | Python 技术栈平台团队 | 「—」= 截至 2026-09 公开文档未见支持;如有出入,欢迎 PR 指正。 一句话:技术栈是 Java + Dubbo + Nacos 的组织,mcp-weaver 是按你的体质造的。 ## 60 秒一键体验 ```bash docker compose -f docker/docker-compose.demo.yml up ``` 自包含、零外网依赖:种子含 MySQL + 演示订单库 + 4 个织入的 MySQL 工具,调用在网关内部自环。 - **控制台** → `http://localhost:8080`,登录 `demo-admin` / `mwsec-demo-admin-key`(演示凭证,仅限本地体验) - **MCP 端点** → `http://localhost:8080/mysql-demo/mcp`,API Key `mcp-demo-agent-key`,Cursor / Claude / 任意 MCP 客户端直连 - 8080 被占?`MW_DEMO_PORT=18081 docker compose -f docker/docker-compose.demo.yml up` 更多搭建方式(手动播种 MySQL、普通 compose)见下方[快速开始](#快速开始)。 ## 特性 - **零代码织入工具** —— OpenAPI 3 规范声明(`in` / `schema` / `requestBody` / `responses`),自动生成 MCP schema 并代理调用 - **上游 MCP 聚合** —— 把存量 MCP server(stdio / Streamable HTTP / 旧 SSE)挂为上游,工具经网关代理输出:live-mount 自动派生到服务,或导入为持久化工具,详见 [docs/example-mcp-upstream.md](docs/example-mcp-upstream.md) - **三协议织入:HTTP + Dubbo + MCP** —— 工具声明 `protocol: dubbo` 经泛化调用接入 Dubbo 2.7/3.x 服务(**无需提供方 JAR**),声明 `protocol: mcp` 即代理已挂的上游 server,详见 [docs/example-dubbo.md](docs/example-dubbo.md) - **多端点** —— 每个配置的 server 暴露独立 `/{name}/mcp` Streamable HTTP 端点 - **热更新** —— 配置变更事件驱动:控制台 / REST 写入**立即生效**;直改表 ≤2 秒轮询感知。带字段级变更摘要 - **控制台 AI 助手** —— 登录后全页面悬浮球(可拖拽、位置记忆),点开即对话:回答项目问题与实时实例状态;LLM 配置三种改法(对话里发「设置 api-key …」、设置页卡片、env 兜底),存 `mcp_weaver_setting` 表**运行时生效**;未配置时本地兜底照常答实例状态 - **演进路线页** —— 控制台侧栏「演进路线」:时间线展示项目从 HTTP 织入起点到上游聚合 / 事件驱动 / 智能控制台的每一步(双语),以及进行中与规划中的方向 - **可插拔配置存储(SPI)** —— 默认 **MySQL**(规范化表),可选 Nacos,实现 `ConfigStore` 接口即可自定义 - **只保留标准认证** —— `api_key` / `jwt` / `none`,**按 server 独立配置**可组合;客户端凭证 + scopes 权限(`tool:read|write|execute`、`admin`);RFC 9728 / RFC 8414 OAuth 元数据端点、JWKS - **网关身份标识头** —— 每次下游调用携带 `X-Call-Source: mcp-weaver` + 防伪造的 `X-Mcp-Caller`(网关解析的调用方身份),后端无需解析凭证 - **审计** —— 工具调用/结果、工具注册变更、Server 配置变更(新增/更新/删除)与生命周期、客户端凭证操作(Key/Secret 分配、重置、明文查看)与认证签发(Token/API Key,含失败尝试)落 MySQL 和/或 Langfuse(OpenTelemetry),脱敏 + Token 哈希;每条管理类事件携带操作人(operator 为「来源/操作人」,如 `api:jwt/demo-admin`,控制台按列展示);Key 仅以掩码入审计,Secret 永不落审计;保留期可配(`mcp.weaver.audit.retention-days`,默认永久保留,启用后按 cron 分批清理过期事件) - **SSRF 防护** —— 私有网段拦截 + CIDR 白名单、禁用重定向跟随、query 参数强制编码 - **客户端限流配额** —— 每客户端 QPS / 并发在途 / 日配额三维限额(全部 0 = 不限),MCP 端点请求粒度生效,超限 429(JSON-RPC `-32063`)并落审计(AUTH / RATE_LIMITED);控制台客户端弹窗直接编辑,MySQL 需执行 `docs/sql/migration-client-rate-limit.sql`(可选,缺列时不限流) - **工具调用韧性** —— 每工具并发在途上限(`maxConcurrent`,0 = 不限)+ 连续失败熔断(默认 5 次跳闸、30s 冷静期后半开探测,异常或错误信封均计失败,与指标口径一致);拒绝零排队快速失败,以 `error.type=circuit_open / concurrency_limit` 落指标 - **OpenAPI 批量导入** —— 粘贴或抓取 OpenAPI v3 文档(JSON / YAML),本地 `$ref` 递归内联,每个操作生成一个 HTTP 工具(operationId 命名、query/path 参数转 inputSchema、requestBody/responses 透传),控制台先预览后导入;URL 抓取经网关 SSRF 策略,不另开门 - **安全默认值(2026-09 收口)** —— 审计敏感值掩码与 SSRF 防护默认开启(`MCP_WEAVER_AUDIT_MASK_ENABLED` / `MCP_WEAVER_SSRF_ENABLED`,默认 true);显式关闭时启动即打 WARN 并给出恢复路径;内网后端请用 `allowed-internal-cidrs` 白名单收敛而非整体关闭 - **控制台试调用** —— 工具详情「试调用」以网关身份真实执行一次(走 ToolExecutor 全链路:守卫 / 指标 / 审计漏斗不变,指标 client 维度记 `console/<操作者>`),参数 JSON 即填即跑,结果原文回显并标错误信封;ADMIN 权限 - **文件上传工具** —— MCP 参数 Base64 文件(`contentEncoding: base64`)转 multipart 转发 - **内置管理控制台** —— 登录、概览、服务/工具/客户端管理、审计追踪、配置文档、系统设置(零前端构建依赖) - **可选 Nacos MCP Registry 同步** —— REF 模式 + Naming 实例注册(`McpRegistrySync` SPI) ## 模块 | 模块 | 职责 | |---|---| | `mcp-weaver-core` | 引擎:多 Server 启动器、动态工具注册、工具执行器(SSRF 安全 HTTP 客户端)、安全、审计、管理 REST API、`ConfigStore` / `McpRegistrySync` SPI | | `mcp-weaver-store-mysql` | 默认存储:规范化表(`mcp_weaver_server` / `mcp_weaver_tool` / `mcp_weaver_client` / `mcp_weaver_setting`),server/工具/客户端各一行,checksum CAS 写入 + 行级轮询感知外部变更 | | `mcp-weaver-store-nacos` | 可选存储:Nacos 配置中心(推送)+ Nacos MCP Registry 同步 | | `mcp-weaver-invoker-dubbo` | 可选协议执行器:Dubbo 泛化调用(`protocol: dubbo` 的工具走此模块,含引用缓存与安全白名单) | | `mcp-weaver-server` | Spring Boot 组装件:内置管理控制台,默认 MySQL,一个配置切到 Nacos | ## 快速开始 ### 一键体验(推荐,自包含无外网依赖) ```bash docker compose -f docker/docker-compose.demo.yml up ``` 起来后浏览器开 `http://localhost:8080`,登录 **`demo-admin` / `mwsec-demo-admin-key`**;MCP 客户端连 `http://localhost:8080/mysql-demo/mcp`(API Key `mcp-demo-agent-key`)。种子内容:演示订单库 + 4 个 MySQL 工具(查询/列表/统计/创建),工具调用在网关内部自环(网关 → 内置 demo REST → MySQL),零外部依赖;SSRF 默认开,compose 里只放行了容器回环段。8080 被占就 `MW_DEMO_PORT=18081 docker compose -f docker/docker-compose.demo.yml up`。演示凭证仅限本地体验。 ### 预构建镜像(免构建,国内匿名可拉) ```bash docker pull crpi-p53lyu34f0g6x20q.cn-beijing.personal.cr.aliyuncs.com/fushoujiang/mcp-weaver:1.0.0 ``` 运行所需环境变量(MySQL 连接 + JWT 密钥)参照 [docker/docker-compose.yml](docker/docker-compose.yml)。Java 构件同步发布在 Maven Central,groupId `io.gitee.fushoujiang`。 ### 手动搭建(了解各部件) ```bash # 1. 启动 MySQL + 初始化表 docker run -d --name mcp-weaver-mysql -e MYSQL_ROOT_PASSWORD=root \ -e MYSQL_DATABASE=mcp_weaver -p 3306:3306 mysql:8 mysql -h127.0.0.1 -uroot -proot mcp_weaver < docs/sql/mysql-schema.sql # 2. 种子数据:一个 server + 一个工具 + 一个客户端凭证(行级存储) mysql -h127.0.0.1 -uroot -proot mcp_weaver <<'SQL' INSERT INTO mcp_weaver_server (name, config_key, instructions, auth_type, sort_order) VALUES ('demo-service', 'demo-service-tools', 'Demo service', 'none', 0); INSERT INTO mcp_weaver_tool (config_key, tool_name, definition, sort_order) VALUES ('demo-service-tools', 'hello', '{"name":"hello","description":"Say hello","apiEndpoint":"https://httpbin.org/get","httpMethod":"get","parameters":[{"name":"name","in":"query","required":true,"description":"Your name","schema":{"type":"string"}}]}', 0); INSERT INTO mcp_weaver_client (client_id, client_secret, name, allowed_scopes, sort_order) VALUES ('my-admin', 'change-me-secret', 'Admin', '["tool:read","tool:write","admin"]', 0); SQL # 3. 运行 export MCP_WEAVER_DATASOURCE_PASSWORD=root export MCP_WEAVER_JWT_SECRET=$(openssl rand -hex 32) mvn -pl mcp-weaver-server spring-boot:run # 4. 打开控制台(登录:my-admin / change-me-secret) open http://localhost:8080/ # 5. MCP 客户端连接 http://localhost:8080/demo-service/mcp ``` 变更传播是**事件驱动**的:控制台 / REST API 的写入**立即生效**(上层统一在每次写入成功后发布 `ConfigStoreChangedEvent` Spring 事件,对所有存储实现一视同仁);直接改表(裸 `INSERT INTO mcp_weaver_tool`、其他节点的写入)由行级轮询在 `mcp.weaver.store.mysql.poll-interval-ms`(默认 2 秒)内感知热生效。存储实现会抑制自身写入的回声通知——一次写入只触发一轮重载。 ### 性能基线(M1 单机,Apple ab) | 路径 | c=50 RPS | c=50 P99 | |---|---:|---:| | 裸框架 health | 14,628 | 13ms | | MCP ping(认证 + JSON-RPC) | 7,880 | 44ms | | tools/list | 5,986 | 54ms | | tools/call 全环(含内环 HTTP + SQL,实例总负载≈2×压力) | 756 | 1.9s* | 治理链路全开下协议开销 ~1ms/请求;完整织入调用网关净增 ~2.6ms;HTTP invoker 已换 HttpClient5 连接池(2026-09-26 复测:c=50 P99 从 ~1.9s 收敛到 ~0.1-0.3s,吞吐 2-3 倍,单线程成本无回归,详见 benchmark.md 复测节)。方法与复跑脚本见 [docs/benchmark.md](docs/benchmark.md) / [benchmark.sh](docs/benchmark.sh)。 或 `docker compose -f docker/docker-compose.yml up --build`。 ### 认证接入 ```bash # 签发 Token(clientId + clientSecret) curl -X POST http://localhost:8080/api/auth/token \ -H 'Content-Type: application/json' \ -d '{"clientId":"my-agent","clientSecret":"xxx"}' # API Key 模式(?key= 或 X-API-Key) curl -H 'X-API-Key: mcp-xxxx' http://localhost:8080/demo-service/mcp ``` 客户端凭证存于 `clients` 文档(`mcp_weaver_config_doc` 表 `doc_key='clients'`): ```json { "clients": [{ "clientId": "my-agent", "clientSecret": "xxx", "name": "My Agent", "tokenType": "CLI", "allowedScopes": ["tool:read", "tool:execute"], "allowedServers": [], "enabled": true, "apiKeys": [ { "key": "mcp-aaaa", "remark": "Cursor-工作电脑" }, { "key": "mcp-bbbb", "remark": "生产网关-01" } ] }] } ``` > 一个客户端可配置**多把 API Key**(各带备注),任一把均可通过 `?key=` / `X-API-Key` 认证; > 控制台「客户端 → Key 管理」支持逐把新增(填备注)/ 查看 / 重置 / 删除。 > 兼容旧格式:仅有 `apiKey` 单字段时视为一把无备注 Key;MySQL 存储使用子表 > `mcp_weaver_client_api_key`(见 `docs/sql/migration-client-api-keys.sql`)。 ### REST API 总览 | 方法 | 路径 | 权限 | 说明 | |------|------|------|------| | GET/POST/PUT/DELETE | `/api/servers` | `tool:read` / `admin` | Server 配置管理(支持 checksum 乐观锁 `X-Expected-Md5`) | | GET/POST/DELETE | `/api/tools/servers/{name}/tools` | `tool:read` / `tool:write` | 工具管理 | | GET/POST/DELETE | `/api/clients` | `admin` | 客户端凭证管理 / 吊销(更新时 Secret 可留空保持不变,Key 列表以存储为准) | | GET/POST | `/api/clients/{id}/api-keys` | `admin` | 查看全部 Key(含备注)/ 新增一把(带备注) | | POST | `/api/clients/{id}/api-keys/{key}/regenerate` | `admin` | 按把重置(旧 Key 立即失效) | | DELETE | `/api/clients/{id}/api-keys/{key}` | `admin` | 按把删除 | | POST | `/api/clients/{id}/regenerate-secret` | `admin` | 重置 Secret(旧 Secret 立即失效,新值仅返回一次) | | POST | `/api/auth/token` `/api/auth/apikey` `/api/auth/refresh` | 公开 | Token 签发 / API Key(返回第一把)/ 刷新 | | GET | `/api/audit/logs` | 需认证 | 审计日志分页查询 | | GET | `/.well-known/*` | 公开 | OAuth 元数据 / JWKS | ### 切换到 Nacos 存储 ```yaml mcp: weaver: store: type: nacos nacos: servers-data-id: mcp-servers-config.json clients-data-id: mcp-clients.json spring: ai: alibaba: mcp: nacos: server-addr: localhost:8848 namespace: your-ns username: nacos password: nacos ``` 工具文档的 dataId = server 配置中的 `configDataId`(可选,默认自动派生为 `{serverName}-tools`),格式与 MySQL 存储一致;同时自动启用 Nacos MCP Registry 同步(REF 模式 + Naming 实例注册)。 ### 案例:MySQL 变 MCP 工具 见 [docs/example-mysql.md](docs/example-mysql.md)——业务表 → REST → MCP 工具全流程(查询/列表/统计/创建),含热更新演示与 curl/Python 接入示例。 ### 案例:存量 MCP server 聚合 见 [docs/example-mcp-upstream.md](docs/example-mcp-upstream.md)——stdio / Streamable HTTP / 旧 SSE 三种上游挂载,live-mount 自动派生与 import-mcp 导入两条路,防环、退避自愈与白名单治理一应俱全。 ### 复合存储(一个项目同时用 MySQL + Nacos) 路由型组合——**每个文档唯一归属一个存储**(按文档键前缀路由,绝不双写合并,CAS 语义在每个存储内保持完整): ```yaml mcp: weaver: store: type: composite stores: mysql: { enabled: true } # 平台侧:servers / clients / 默认工具 nacos: { enabled: true } # 业务侧:需配置 Nacos 连接 store: composite: default-store: mysql routes: - doc-prefix: "tools:order" # configKey 以 order 开头的工具组归 Nacos store: nacos ``` 典型分工:平台在 MySQL 管理 server 注册与客户端凭证;各业务团队在 Nacos 自管自己的工具配置(推送秒级生效)。控制台「配置文档」页联合展示两个存储的文档,并**按文档标注归属存储**(MySQL / Nacos 徽章);概览页显示当前存储组合。 完整实战案例见 [docs/example-composite.md](docs/example-composite.md)——MySQL 注册 + Nacos 工具发布 + 启动配置 + 热推送演示 + 配置参考与排错清单。 ### 自定义存储 实现两个接口即可接入任意配置源(Git / etcd / Apollo / 文件……): ```java public interface ConfigStore { String loadServersDoc(); // servers 文档 JSON boolean saveServersDoc(String json, String expectedChecksum); Set toolsKeys(); String loadToolsDoc(String configKey); // 工具文档 JSON boolean saveToolsDoc(String configKey, String json, String expectedChecksum); String loadClientsDoc(); // 客户端凭证文档 JSON boolean saveClientsDoc(String json, String expectedChecksum); void watch(String docKey); // 推送型存储注册监听,轮询型可忽略 void addListener(ConfigStoreListener listener); // ... } ``` 打包为 Spring Boot starter,注册 `AutoConfiguration.imports`,设置 `mcp.weaver.store.type` 指向你的实现即可。 **变更通知规范(上层统一)**:业务服务不直接实现 `ConfigStoreListener`,统一经 `ConfigStoreEventBridge` 把 SPI 回调转成 `ConfigStoreChangedEvent` Spring 事件(`WATCH` = 存储感知的外部变更);你的实现的 `save*Doc` 被调用成功后,上层会立即发布 `WRITE` 事件——本节点写入零延迟生效。存储实现只需保证「感知外部变更时回调 listener」一件事,并建议抑制自身写入的回声(如 MySQL 刷新对账快照、Nacos 比对本地写内容),避免重复重载。 ## Dubbo 工具(泛化调用) 除 HTTP 代理外,工具可声明 `protocol: dubbo` 直接调用 Dubbo 服务 —— 网关使用**泛化调用(GenericService)**,无需引入提供方 JAR: ```json { "name": "orderCreate", "description": "创建订单", "protocol": "dubbo", "dubbo": { "interfaceName": "com.example.OrderService", "method": "createOrder", "version": "1.0.0", "address": "nacos://127.0.0.1:8848", "paramTypes": ["java.lang.String", "com.example.OrderDTO"] }, "parameters": [ { "name": "userId", "required": true, "schema": { "type": "string" }, "dubboArgIndex": 0 }, { "name": "order", "required": true, "schema": { "type": "object" }, "dubboArgIndex": 1 } ], "responses": { "200": { "content": { "application/json": { "schema": { "type": "object" } } } } } } ``` 要点: - `address` 支持 `nacos://` / `zookeeper://` 注册中心与 `dubbo://ip:port` 直连;`dubboArgIndex` 声明参数到方法形参的映射(缺省按声明顺序) - 网关身份以 RPC 附件透传(`X-Call-Source` / `X-Mcp-Caller`),与 HTTP 路径语义一致 - 安全治理(对标 SSRF 防护):接口通配白名单 `mcp.weaver.dubbo.security.allowed-interfaces`(配合 `interface-whitelist-enabled`)、地址白名单 `mcp.weaver.dubbo.allowed-registries`;**`dubbo://` 直连默认拒绝**,须显式加白 - 总开关 `mcp.weaver.dubbo.enabled`(默认 true);超时/重试默认值 `mcp.weaver.dubbo.default-timeout-ms` / `default-retries`(可被工具级 `timeoutMs` / `retries` 覆盖) 完整示例与参数类型映射规则见 [docs/example-dubbo.md](docs/example-dubbo.md)。 ## 上游 MCP server(聚合模式) 存量 MCP server 无需重新织入:挂为**上游**即可——对网关来说它只是另一种 ToolInvoker 目标,认证、限流、审计、指标、熔断全量复用,零新增概念。完整实操见 [docs/example-mcp-upstream.md](docs/example-mcp-upstream.md)。 - **三种传输** —— `stdio`(拉起本地命令)、`http`(Streamable HTTP,推荐)、`sse`(旧 HTTP+SSE)。凭证值支持 `${ENV}` 展开,只存网关侧,所有响应掩码(`mcp-****`),永不向下游暴露 - **两种挂法,同一机制** - **live-mount** —— server 配置 `upstreamRefs` 引用上游,网关自动向该服务派生 `protocol:"mcp"` 代理工具;派生不落库,上游工具变更秒级跟随,解除挂载即清空 - **import** —— `POST /api/tools/servers/{s}/import-mcp` 把上游工具快照为普通持久化工具(`dryRun` 预览缺省开;重复导入 = 原地刷新,不加重复) - **REST** —— `GET/POST /api/upstreams`、`PUT/DELETE /api/upstreams/{name}`、`POST /api/upstreams/test`(试探未保存配置)、`POST /api/upstreams/{name}/test`(试探已保存)、`POST /api/upstreams/{name}/refresh`(重同步所有挂载 server);写 ADMIN / 读 TOOL_READ - **连接池 + 指数退避 + 自愈** —— 每上游独立池(stdio 单进程多路复用,HTTP 按 `poolSize`);建连失败指数退避 5s→60s(成功清零),stdio 子进程被杀后冷却结束自动重启拉起;状态/连败/冷却经 `GET /api/upstreams` 与 gauge 暴露 - **防环** —— 指向网关自身端点的上游在导入时拒绝;静态自环检测覆盖本机 + 同端口 + 同 mcp 路径 - **stdio 命令白名单** —— `mcp.weaver.upstream.stdio.allowed-commands`(如 `node,npx,uvx,docker`);缺省空 = 不限但启动 WARN;名单外命令**永不拉起**(borrow 与 probe 均先校验) - **可观测** —— 每上游 `mcp_weaver_upstream_state`(-1 停用 / 0 空闲 / 1 已连接 / 2 失败)与 `mcp_weaver_upstream_connections` 双 gauge;工具调用走标准 `protocol="mcp"` 指标与 TOOL_CALL 单行审计;上游增删改落 SERVER_REGISTRY 审计(header 值不入库,仅键名) MySQL 存储执行 [docs/sql/migration-mcp-upstream.sql](docs/sql/migration-mcp-upstream.sql)(幂等:新表 `mcp_weaver_upstream` + `mcp_weaver_server.upstream_refs` 列;缺列仅关闭 live-mount 持久化,其余功能不受影响)。 ## MCP 协议兼容 | 客户端代次 | 接入方式 | |---|---| | 2025-06-18 / 2025-11-25 | 完整支持 —— SDK 原生握手(`initialize`),Streamable HTTP | | 2026-07-28(无状态版) | 经兼容层支持:`server/discover` → 客户端降级到双方支持的版本 | MCP 规范 2026-07-28 版删除了 `initialize` 握手与 `Mcp-Session-Id`,版本协商改为无状态的 `server/discover` RPC + 每请求 `Mcp-Method` / `MCP-Protocol-Version` 头。官方 Java SDK 尚未实现该版本,mcp-weaver 内置兼容过滤器补齐: - **`server/discover`**:按 DiscoverResult schema 返回 `supportedVersions`、能力与服务器身份(缓存建议时长可配 `mcp.com.weaver.mcp.discover-ttl-ms`,默认 60s);规范要求的 `Mcp-Method` 头缺头时按请求体 method 宽容识别 - **版本守卫**:不支持的版本按规范返回 `UnsupportedProtocolVersionError`(`-32022`,HTTP 400,`data` 含 `requested` / `supported`) - **诚实广播**:只列出 SDK 实际实现的版本(`mcp.com.weaver.mcp.protocol-versions` 配置,默认 `2025-06-18,2025-11-25`),2026-only 客户端先发现、再降级接入 - **未知方法**:按 JSON-RPC 规范回 `-32601`,而不是 SDK 的裸 500 + 堆栈 - **响应线格式补齐**:所有 JSON-RPC result 补 `resultType: "complete"`;list 类结果(`tools/list` 等)补 `ttlMs` + `cacheScope: "public"`(缓存建议时长可配 `mcp.com.weaver.mcp.list-ttl-ms`,默认 30s);`tools/list` 按 name 确定性排序,跨实例/重启顺序稳定,提升客户端 prompt cache 命中。SSE 流式响应逐字节直通不受影响,2025-06-18 / 2025-11-25 老客户端零感知。 真客户端实测(官方 TypeScript SDK `@modelcontextprotocol/client` 2.0.0,双时代协商):`legacy` 握手、`auto` 探测降级、`pin` 现代版本三种协商模式均连通;`demo-service`(JWT 认证)与 `order-service`(免认证 + Nacos 存储)真实调用往返,`X-Call-Source` 网关身份透传,TOOL_CALL / TOOL_RESULT 审计成对落库。冒烟脚本见 `docs/verify-mcp-client.mjs`。 ## 可观测性 网关自带工具调用指标(Micrometer,经 `/actuator/prometheus` 输出 Prometheus 格式): | Prometheus 系列 | 仪器 | 标签 | 约定 | |---|---|---|---| | `mcp_server_operation_duration_seconds` | 直方图(秒) | `mcp.method.name=tools/call`、`gen_ai.tool.name`、`gen_ai.operation.name=execute_tool`、`error.type`(仅失败时携带) | 对齐 [OTel GenAI MCP 语义约定](https://github.com/open-telemetry/semantic-conventions-genai),生态现成面板可直接使用 | | `mcp_weaver_tool_calls_total` | 计数器 | `tool`、`protocol`(后端协议 http/dubbo/…)、`server`、`client`、`outcome` | 网关自有维度 —— GenAI 约定不建模「API 织入网关」这层 | 说明: - 标准直方图只在真实 MCP 请求路径记录,控制台调试调用不污染它;网关计数器覆盖全部路径。 - `/actuator/health` 公开(存活探针);`/actuator/prometheus` 仅 ADMIN 凭证可访问(JWT Bearer 或 API Key,受 `api-auth-type` 约束)。建议为 Prometheus 建专用抓取客户端并用 `tokenTtlOverride` 发长效 Token。门禁是 Servlet Filter——actuator 端点由独立 HandlerMapping 派发,MVC 拦截器够不着。 - 计时与审计 `TOOL_RESULT.durationMs` 同源,标签维度与审计页过滤器对齐——Grafana 面板上的尖刺可直接下钻到审计查询。 - 语义约定仅以字符串字面量对齐(该约定仓库尚处 `development` 状态),日后改名只动一个常量。 - 想用网络隔离替代鉴权时,设置 `management.server.port` 把 actuator 挪到独立端口即可。 ## 管理控制台 server 模块内置 Web 控制台(零前端构建依赖),启动后直接访问根路径: ``` open http://localhost:8080/ ``` - 使用 clients 文档中的 clientId + clientSecret 登录(走 `/api/auth/token` 签发 JWT) - **概览**:服务/工具/客户端统计 + 24h 调用图表 + 最近调用 - **MCP 服务**:新增 / 编辑 / 删除(热更新生效),每张服务卡提供该端点的接入配置(MCP 地址 / Cursor / Claude Code / Claude Desktop 格式,认证头自动带上) - **工具管理**:JSON 编辑器式工具增删改,保存即热加载 - **客户端**:凭证管理、多把 API Key(各带备注)的查看/重置/删除、吊销 - **审计日志**:按类型/服务/工具/状态筛选,分页展示调用链路(时间可读化、操作人列),行点击查看详情;支持按当前条件**导出 CSV**(Excel 兼容,上限 1 万条) - **工具编辑器**:结构化表单(协议切换 / HTTP 与 Dubbo 分区 / 参数表格)为默认,可一键切换 JSON 专家模式,双向同步且保留表单未暴露的高级字段 - **多语言**:中文 / English 双语界面,侧栏一键切换,按浏览器语言自动初始 - **配置文档**:直查/直改存储中的原始 JSON 文档(servers / tools: / clients),校验和 CAS,任意存储实现通用;每行标注归属存储(MySQL / Nacos) - **调用统计**:概览页 24 小时调用量/成功率/平均耗时 + 工具调用 Top 榜 - **系统设置**:运行时配置总览(存储类型、认证配置、SSRF、超时;密钥只显示是否已配置) ### 工具定义:OpenAPI 3 规范 工具定义采用 **OpenAPI 3** 风格(`in` / `schema` / `requestBody` / `responses`),支持热更新: ```json { "tools": [{ "name": "getUser", "description": "按 ID 查询用户", "apiEndpoint": "https://api.example.com/users/{userId}", "httpMethod": "get", "parameters": [ {"name": "userId", "in": "path", "required": true, "description": "用户 ID", "schema": {"type": "integer", "minimum": 1}}, {"name": "fields", "in": "query", "required": false, "schema": {"type": "array", "items": {"type": "string"}}} ], "responses": { "200": {"content": {"application/json": {"schema": { "type": "object", "properties": {"id": {"type": "integer"}, "name": {"type": "string"}} }}}} } }] } ``` - `in`:`query` / `path` / `header` / `body`——显式路由参数(`path` 会替换 `apiEndpoint` 中的 `{占位符}`);未声明时按方法 / requestBody 默认路由 - `schema`:标准 JSON Schema 对象,原样透传给 MCP(integer/number/enum/minimum 等不降级) - `requestBody`:OpenAPI 请求体——`content` 的 media type 决定 POST 的 Content-Type(`application/json`、`multipart/form-data`、`text/plain` 等);POST 未声明 requestBody 时全部参数走 query string - `responses`:`200` 的 JSON schema 自动成为工具 outputSchema(MCP structuredContent) - 文件上传参数:`schema: {"type": "string", "contentEncoding": "base64"}` ## 网关身份标识头 每次下游工具调用都会携带: | Header | 值 | 来源 | |---|---|---| | `X-Call-Source: mcp-weaver` | 网关身份 | 执行器固定注入,客户端不可控 | | `X-Mcp-Caller: ` | 解析后的调用方身份 | 认证过滤器鉴权成功后**覆盖写入**(防伪造),透传给后端——后端无需解析凭证即可识别调用方 | 公开端点(`authType: none`)不携带 `X-Mcp-Caller`。 ## 贡献 欢迎 PR,见 [CONTRIBUTING.md](CONTRIBUTING.md);安全漏洞按 [SECURITY.md](SECURITY.md) 报告。 ## 许可证 [Apache License 2.0](LICENSE)