文章摘要
企业接入多个MCP Server后,如果让每个Agent直接连接订单、仓储、客户、知识库和文件工具,会快速出现认证分散、工具重名、权限不一致、审计缺失和服务端地址泄露等问题。本文使用Spring Boot设计一个MCP工具网关:上游连接多个MCP Server,下游向Agent提供统一工具目录,并在调用前执行租户校验、工具白名单、风险审批、参数脱敏、超时和审计。文章给出核心数据模型、路由代码和生产配置思路。
一、为什么需要MCP工具网关
没有网关时:
Agent A ├─ 订单MCP ├─ 仓储MCP ├─ CRM MCP └─ 知识库MCP Agent B ├─ 订单MCP ├─ 仓储MCP └─ 财务MCP问题包括:
- 每个Agent保存多套凭证;
- MCP Server地址暴露给业务应用;
- 权限规则分散;
- 工具名称冲突;
- 无法统一限流;
- 无法统一审计;
- Server升级需要修改多个客户端;
- 模型可能看到不该看到的工具;
- 故障降级困难。
引入网关:
Agent → MCP Tool Gateway → Order MCP → WMS MCP → CRM MCP → Knowledge MCP网关成为控制面,而不是简单反向代理。
二、网关应该负责什么
MCP Server注册 工具发现 工具名称规范化 租户与用户权限 工具白名单 风险分级 审批 限流 超时 重试 幂等 审计 可观测性 降级网关不应该承载所有业务逻辑。
订单查询逻辑仍在订单服务,网关只负责是否允许调用以及如何安全路由。
三、项目结构
mcp-tool-gateway ├── config │ ├── McpClientConfig.java │ └── SecurityConfig.java ├── catalog │ ├── ToolCatalog.java │ ├── ToolDescriptor.java │ └── ToolCatalogRefresher.java ├── policy │ ├── ToolPolicyService.java │ ├── RiskLevel.java │ └── PermissionDecision.java ├── routing │ ├── ToolRouter.java │ └── UpstreamMcpServer.java ├── execution │ ├── ToolExecutionService.java │ ├── IdempotencyService.java │ └── ApprovalService.java ├── audit │ ├── ToolAuditService.java │ └── ToolAuditEvent.java └── web ├── ToolCatalogController.java └── ToolExecutionController.java四、依赖
<dependencyManagement><dependencies><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-bom</artifactId><version>2.0.0</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><dependencies><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-mcp-client-webflux</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency></dependencies>五、上游Server配置
enterprise:mcp:servers:order:url:https://internal.example.com/order/mcptimeout:20sname-prefix:orderwarehouse:url:https://internal.example.com/wms/mcptimeout:30sname-prefix:wmsknowledge:url:https://internal.example.com/knowledge/mcptimeout:15sname-prefix:knowledge不要把Token直接写进YAML。
使用:
- Vault;
- Kubernetes Secret;
- 云Secret Manager;
- OAuth客户端凭证;
- 工作负载身份。
六、统一工具描述模型
publicrecordToolDescriptor(StringgatewayToolName,StringupstreamServer,StringupstreamToolName,Stringdescription,StringinputSchema,RiskLevelriskLevel,Set<String>requiredScopes,booleanapprovalRequired,Durationtimeout){}风险等级:
publicenumRiskLevel{LOW,MEDIUM,HIGH,CRITICAL}示例:
knowledge_search_policy → LOW order_query_status → LOW order_cancel → HIGH finance_refund → CRITICAL七、工具名称规范化
上游可能都存在:
search get_status create网关统一命名:
order_get_status wms_get_inventory crm_search_customer knowledge_search_policy映射:
publicStringgatewayName(Stringprefix,StringupstreamName){returnnormalize(prefix)+"_"+normalize(upstreamName);}名称一旦对模型开放,应保持稳定。
上游改名时,网关可以保留旧别名,避免Prompt和评测集全部失效。
八、工具目录刷新
@ComponentpublicclassToolCatalogRefresher{privatefinalToolCatalogcatalog;privatefinalList<McpSyncClient>clients;@Scheduled(fixedDelayString="${enterprise.mcp.refresh:PT5M}")publicvoidrefresh(){for(McpSyncClientclient:clients){refreshClient(client);}}privatevoidrefreshClient(McpSyncClientclient){varresult=client.listTools();catalog.replace(client.getServerInfo().name(),result.tools());}}生产代码需要处理:
- 单个Server失败不清空旧目录;
- 保存最后成功版本;
- 记录刷新时间;
- 校验工具Schema;
- 检查高风险工具是否有策略;
- 支持
listChanged主动刷新。
九、租户和用户上下文
publicrecordGatewayRequestContext(StringrequestId,StringtenantId,StringuserId,Set<String>scopes,StringclientId){}这些信息应从认证系统获取,而不是信任模型生成的参数。
错误:
{"tenantId":"T002"}模型可以随意修改。
正确:
Access Token → SecurityContext → GatewayRequestContext十、工具白名单
每个租户可以配置:
允许工具 禁止工具 按环境允许 按用户角色允许数据模型:
publicrecordToolAccessPolicy(StringtenantId,StringtoolName,booleanenabled,Set<String>allowedRoles,Set<String>requiredScopes,intcallsPerMinute){}决策:
publicPermissionDecisiondecide(GatewayRequestContextcontext,ToolDescriptortool){if(!tenantPolicy.enabled(tool.gatewayToolName())){returnPermissionDecision.deny("租户未启用该工具");}if(!context.scopes().containsAll(tool.requiredScopes())){returnPermissionDecision.deny("缺少必要Scope");}returnPermissionDecision.allow();}十一、执行前参数校验
模型提交参数后先做:
JSON Schema校验 Bean Validation 业务范围校验 资源归属校验 敏感字段检测例如:
publicrecordCancelOrderArgs(@NotBlankStringorderId,@NotBlankStringreason){}还要验证:
订单是否属于当前租户 订单是否允许取消 当前用户是否有操作权限JSON Schema合法并不代表业务合法。
十二、高风险工具审批
if(tool.approvalRequired()){ApprovalRequestapproval=approvalService.create(context,tool,sanitizedArguments);returnToolExecutionResult.pendingApproval(approval.id());}审批页面展示:
- 工具名称;
- 业务影响;
- 参数;
- 当前用户;
- 当前租户;
- 风险原因;
- 幂等键;
- 预计执行结果。
批准后重新读取最新权限与业务状态,不能直接使用旧审批上下文永久执行。
十三、幂等设计
写操作需要幂等键:
tenantId +toolName +businessObjectId +requestIntentHashpublicStringbuildIdempotencyKey(GatewayRequestContextcontext,ToolDescriptortool,StringobjectId,StringargumentHash){returnString.join(":",context.tenantId(),tool.gatewayToolName(),objectId,argumentHash);}重复请求:
返回第一次执行结果 而不是再次取消订单或重复退款十四、调用路由
@ServicepublicclassToolRouter{privatefinalMap<String,McpSyncClient>clients;privatefinalToolCatalogcatalog;publicCallToolResultroute(StringgatewayToolName,Map<String,Object>arguments){ToolDescriptordescriptor=catalog.require(gatewayToolName);McpSyncClientclient=clients.get(descriptor.upstreamServer());returnclient.callTool(descriptor.upstreamToolName(),arguments);}}实际API方法应按使用的MCP Java SDK版本调整,但架构原则一致。
十五、超时与重试
查询类工具:
可有限重试写操作:
只有确认幂等后才能重试策略:
| 工具 | 超时 | 重试 |
|---|---|---|
| 知识检索 | 10秒 | 1次 |
| 订单查询 | 5秒 | 1次 |
| 取消订单 | 15秒 | 默认0次 |
| 退款 | 30秒 | 默认0次 |
不要让HTTP客户端、MCP客户端、网关和Agent四层同时重试。
十六、审计事件
publicrecordToolAuditEvent(StringrequestId,StringtenantId,StringuserId,StringtoolName,StringupstreamServer,StringargumentHash,StringresultStatus,longdurationMs,StringapprovalId,Instanttimestamp){}日志中不要直接记录:
- 密码;
- Token;
- 身份证;
- 银行卡;
- 完整客户隐私;
- 文件正文。
保存:
脱敏参数 参数Hash 结果状态 影响对象ID十七、向Agent暴露工具
网关可以有两种方式:
方式一:网关本身作为MCP Server
Agent MCP Client → Gateway MCP Server → Upstream MCP Servers优点是协议统一。
方式二:转换为Spring AI ToolCallback
ChatClient → ToolCallback → Gateway内部路由适合只服务Spring AI应用。
企业更通用的方式是让网关对外暴露标准MCP Server。
十八、健康检查
每个上游记录:
connected protocol_version tool_count last_refresh last_success error_rate P95_latency网关整体不能因为一个非核心Server失败就完全不可用。
工具级降级:
知识工具不可用 → 隐藏知识工具 订单查询不可用 → 返回明确错误 退款工具不可用 → 禁止执行并转人工十九、监控指标
mcp_gateway_tool_call_count mcp_gateway_tool_denied_count mcp_gateway_approval_count mcp_gateway_upstream_latency mcp_gateway_upstream_error mcp_gateway_catalog_tool_count mcp_gateway_catalog_refresh_failure mcp_gateway_idempotency_hit mcp_gateway_cross_tenant_denied二十、生产检查清单
□ 上游Server统一注册 □ 工具名称稳定且不冲突 □ 凭证不下发给业务Agent □ 工具目录按租户过滤 □ 执行时再次鉴权 □ 高风险工具要求审批 □ 写操作具有幂等键 □ 参数和结果日志已脱敏 □ 超时与重试按工具配置 □ 上游故障支持工具级降级 □ 每次调用可以追溯 □ 跨租户请求默认拒绝总结
企业MCP工具网关的价值不是把多个URL合并成一个URL,而是建立统一的工具控制面:
发现 +命名 +权限 +审批 +幂等 +审计 +观测当工具数量、Agent数量和租户数量增长后,这一层会成为MCP进入生产环境的关键基础设施。