在企业级 AI 落地中,一个关键问题是:如何让大模型安全、稳定地调用业务能力 。
实践中,通常的做法是:
将业务接口封装为 MCP Server 的 Tool,由 MCP 层统一承担安全控制与协议适配。
相比直接暴露 API,这种方式具备更好的可控性、可观测性与模型适配能力。
一、设计思路:从"接口"到"能力"
在编码之前,需要完成一次抽象转换:
text
HTTP API → 业务能力 → MCP Tool
1. API 到 Tool 的映射
原始接口:
http
POST /api/order/query
{
"orderId": "123"
}
不建议简单映射为:
text
call_api(orderId)
而应转换为:
text
query_order(orderId)
👉 核心区别:
- API:面向"系统调用"
- Tool:面向"模型理解与决策"
2. Tool 三要素(设计核心)
text
name 工具名(动词 + 业务语义)
description 工具用途描述(供模型决策)
input schema 输入参数结构(JSON Schema)
这三者会被 MCP Server 转换为标准元数据,供模型选择和调用。
3. MCP Server 的职责边界
MCP Server 不只是"转发层",而是能力治理层:
text
参数校验(防止模型误用)
鉴权(用户 / token / 租户)
限流(防止滥用)
日志审计(AI调用可追踪)
异常转换(结构化错误)
字段过滤(敏感信息脱敏)
二、Python 实现(快速原型)
适合场景:AI 原型、工具服务、轻量网关
python
from mcp.server.fastmcp import FastMCP
import httpx
mcp = FastMCP("order-mcp-server")
@mcp.tool()
async def query_order(order_id: str) -> dict:
"""根据订单 ID 查询订单"""
async with httpx.AsyncClient(timeout=5) as client:
resp = await client.post(
"https://api.example.com/order/query",
json={"orderId": order_id},
headers={"Authorization": "Bearer TOKEN"}
)
resp.raise_for_status()
data = resp.json()
return {
"order_id": data["orderId"],
"status": data["status"],
"amount": data["amount"]
}
if __name__ == "__main__":
mcp.run()
实现要点
@mcp.tool()自动注册 Tool- 函数签名 → 输入 schema
- docstring → description
- 返回 dict → Tool 输出
三、TypeScript 实现(生产推荐)
适合场景:Node.js 网关、BFF、中台服务
ts
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
const server = new McpServer({
name: "order-mcp-server",
version: "1.0.0",
});
server.tool(
"query_order",
"根据订单 ID 查询订单",
{
orderId: z.string().describe("订单唯一标识"),
},
async ({ orderId }) => {
const resp = await fetch("https://api.example.com/order/query", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer TOKEN",
},
body: JSON.stringify({ orderId }),
});
if (!resp.ok) {
throw new Error(`接口调用失败: ${resp.status}`);
}
const data = await resp.json();
return {
content: [
{
type: "text",
text: JSON.stringify({
orderId: data.orderId,
status: data.status,
amount: data.amount,
}),
},
],
};
}
);
server.start();
实现要点
- 使用
zod定义 schema(强类型 + 描述) - Tool 元数据显式声明
- 输出结构统一为
content[] - 易于扩展鉴权、限流、链路追踪
四、Java 实现(企业级接入)
适合场景:已有微服务体系、Spring Boot 项目
基于 Spring AI:
1. 依赖
xml
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
</dependency>
2. 业务层(保持不变)
java
@Service
public class OrderService {
public OrderDTO queryOrder(String orderId) {
return new OrderDTO(orderId, "PAID", 199.0);
}
}
3. MCP Tool 封装
java
@Component
public class OrderMcpTools {
private final OrderService orderService;
public OrderMcpTools(OrderService orderService) {
this.orderService = orderService;
}
@Tool(description = "根据订单 ID 查询订单")
public OrderDTO queryOrder(String orderId) {
return orderService.queryOrder(orderId);
}
}
4. 注册工具
java
@Configuration
public class McpConfig {
@Bean
public ToolCallbackProvider tools(OrderMcpTools t) {
return MethodToolCallbackProvider.builder()
.toolObjects(t)
.build();
}
}
实现要点
text
@Tool → Tool 描述
方法签名 → 输入 schema
Service → 业务逻辑复用
DTO → 输出结构
五、推荐架构(关键实践)
text
MCP Tool
↓
Service(业务逻辑)
↓
Repository / RPC / HTTP
为什么不要这样?
text
MCP Tool → Controller ❌
原因:
- Controller 属于 HTTP 协议层(多余转换)
- 返回结构不适合模型(code/msg/data)
- 依赖 Request/Session 上下文
- 可能导致"自调用 HTTP"的性能问题
👉 本质:Tool 是能力入口,不是接口入口
六、Tool 设计最佳实践
1. 粒度设计
text
✔ query_order
✔ cancel_order
✔ create_invoice
❌ call_api
❌ execute_request
2. 输入输出设计
text
输入:明确字段 + 类型约束 + description
输出:裁剪字段(避免冗余)
3. 错误处理
text
业务异常 → 可读语义
系统异常 → 标准错误
4. 安全设计
text
鉴权(Token / 用户)
多租户隔离
敏感字段脱敏
调用审计
七、进阶实践方向
1. MCP 聚合网关
text
多个系统 → 一个 MCP Server
统一治理 Tool
2. Tool 编排
text
query_order → check_status → refund_order
3. Agent 自动调用
text
用户输入 → 模型选择 Tool → 执行
八、总结
MCP Tool 本质是"面向模型设计的业务能力接口",而不是传统 API 的简单封装。
核心落地原则
text
抽象业务能力(而非接口)
通过 MCP 层做安全与治理
保持 Service 复用
设计模型友好的 schema
最终理解
text
Controller → 给前端使用
Tool → 给模型使用
Service → 统一业务逻辑
如果你后续要深入,可以继续扩展:
- Tool schema 设计规范(高成功率)
- MCP 网关架构(企业级)
- Tool 调用调试与可观测性
这些才是 MCP 在工程化落地中的关键竞争力。