在传统AI应用中,大语言模型往往只能提供建议而无法直接执行操作,这种"只说不做"的模式严重限制了AI的实际应用价值。MCP Tools机制的引入彻底改变了这一局面,它通过标准化的协议让AI获得了与现实世界交互的能力。
MCP Tools的工作流程可以分解为三个关键阶段,每个阶段都有其特定的协议规范:
在这个阶段,Server需要向Client明确声明其能力范围。通过ListToolsRequestSchema协议,Server会返回一个包含所有可用工具的列表,每个工具的定义都遵循严格的JSON-Schema规范。例如,一个Jira任务创建工具的定义可能包含以下关键字段:
typescript复制{
name: "create_jira_task",
description: "在指定项目中创建新的Jira任务",
inputSchema: {
type: "object",
properties: {
projectKey: { type: "string", description: "Jira项目标识符" },
summary: { type: "string", description: "任务摘要" },
description: { type: "string", description: "详细说明" },
issueType: {
type: "string",
enum: ["Task", "Bug", "Story"],
description: "问题类型"
}
},
required: ["projectKey", "summary"]
}
}
关键点:description字段的质量直接影响AI对工具的理解和使用准确性。建议采用"动词+宾语"的句式明确说明工具的用途。
当AI决定使用某个工具时,会根据工具定义的schema构造调用参数。这个过程实际上是一个动态的JSON生成过程,AI需要:
Server执行完成后,需要通过CallToolResult返回结构化结果。良好的反馈应该包含:
JSON-Schema在MCP Tools中扮演着"操作手册"的角色,其设计需要考虑AI和开发者的双重需求:
在实践中我们发现,定义复合类型可以显著提升AI的使用准确性。例如:
typescript复制{
definitions: {
User: {
type: "object",
properties: {
id: { type: "string" },
name: { type: "string" }
}
}
},
properties: {
assignee: { $ref: "#/definitions/User" }
}
}
MCP Tools的强大之处在于其动态发现机制。当新的MCP Server接入系统时,AI会立即获得其提供的所有工具能力。这种设计带来了几个重要优势:
在实际应用中,我们建议为工具名称添加命名空间前缀(如jira/create_issue),避免不同系统的工具名称冲突。
一个健壮的MCP Server应该具备以下核心能力:
我们推荐使用TypeScript构建MCP Server,原因如下:
以下是MCP Server的骨架代码:
typescript复制import { Server } from "@modelcontextprotocol/sdk/server";
import { z } from "zod";
class AutomationController {
private server: Server;
private tools: Map<string, ToolHandler> = new Map();
constructor() {
this.server = new Server(
{ name: "automation-controller", version: "1.0.0" },
{ capabilities: { tools: {} } }
);
this.setupHandlers();
}
private setupHandlers() {
// 工具列表查询
this.server.setRequestHandler(ListToolsRequestSchema, () => ({
tools: Array.from(this.tools.values()).map(t => t.descriptor)
}));
// 工具调用
this.server.setRequestHandler(CallToolRequestSchema, async (req) => {
const handler = this.tools.get(req.params.name);
if (!handler) throw new Error(`Tool ${req.params.name} not found`);
return handler.execute(req.params.arguments);
});
}
registerTool(handler: ToolHandler) {
this.tools.set(handler.descriptor.name, handler);
}
start() {
const transport = new StdioServerTransport();
return this.server.connect(transport);
}
}
让我们实现一个完整的"创建任务并通知"工具:
typescript复制interface Task {
title: string;
priority: 'low' | 'medium' | 'high';
assignee?: string;
}
interface Notification {
channel: string;
message: string;
}
class CreateAndNotifyHandler implements ToolHandler {
readonly descriptor = {
name: "create_and_notify_task",
description: "创建任务并发送通知到指定频道",
inputSchema: {
type: "object",
properties: {
title: { type: "string", minLength: 5, description: "任务标题" },
priority: {
type: "string",
enum: ["low", "medium", "high"],
default: "medium",
description: "任务优先级"
},
channel: {
type: "string",
pattern: "^#[a-z0-9-_]+$",
description: "通知频道,格式如 #team-backend"
},
assignee: {
type: "string",
description: "任务负责人邮箱前缀"
}
},
required: ["title", "channel"]
}
};
async execute(args: unknown): Promise<CallToolResult> {
// 参数校验
const schema = z.object({
title: z.string().min(5),
priority: z.enum(['low', 'medium', 'high']).optional(),
channel: z.string().regex(/^#[a-z0-9-_]+$/),
assignee: z.string().email().optional()
});
const params = schema.parse(args);
// 执行业务逻辑
try {
const task = await this.createTask(params);
const notification = await this.sendNotification(params.channel, task);
return {
content: [{
type: "text",
text: `✅ 任务创建成功 (ID: ${task.id}),通知已发送至 ${params.channel}`
}]
};
} catch (error) {
return {
content: [{
type: "text",
text: `❌ 操作失败: ${error instanceof Error ? error.message : String(error)}`
}],
isError: true
};
}
}
private async createTask(params: Task): Promise<{ id: string }> {
// 实际调用Jira/Trello API
// 这里简化为模拟实现
return { id: `TASK-${Date.now()}` };
}
private async sendNotification(channel: string, task: Task): Promise<void> {
// 实际调用Slack/Teams API
console.log(`通知 ${channel}: 新任务 "${task.title}" 已创建`);
}
}
typescript复制const controller = new AutomationController();
controller.registerTool(new CreateAndNotifyHandler());
controller.start().then(() => {
console.log("MCP Server 已启动");
});
对于耗时较长的操作(如部署应用),应该实现异步处理模式:
typescript复制async execute(args: unknown): Promise<CallToolResult> {
// 启动异步任务
const jobId = startBackgroundJob(args);
return {
content: [{
type: "text",
text: `⌛ 任务已开始处理,跟踪ID: ${jobId}。稍后可使用 check_job_status 工具查询进度。`
}],
metadata: {
jobId,
statusUrl: `/jobs/${jobId}`
}
};
}
复杂操作可以分解为多个步骤,通过中间结果引导AI:
typescript复制async execute(args: unknown): Promise<CallToolResult> {
const step = args.step || 1;
switch(step) {
case 1:
return {
content: [{
type: "text",
text: "请确认要部署的分支名称:"
}],
metadata: {
nextStep: 2
}
};
case 2:
// 处理分支选择
// ...
}
}
不同工具应该有不同的访问权限,建议实现基于角色的访问控制:
| 工具类别 | 所需权限 | 风险等级 | 典型审批流程 |
|---|---|---|---|
| 信息查询 | read-only | 低 | 自动批准 |
| 数据修改 | read-write | 中 | 团队领导审批 |
| 系统管理 | admin | 高 | CTO审批 |
实现示例:
typescript复制class PermissionChecker {
async checkPermission(user: User, tool: string): Promise<boolean> {
const policy = await getSecurityPolicy(user);
return policy.allowedTools.includes(tool);
}
}
// 在调用处理器前检查权限
const hasPermission = await permissionChecker.checkPermission(context.user, req.params.name);
if (!hasPermission) {
throw new Error(`无权访问工具 ${req.params.name}`);
}
所有工具调用都应该记录详尽的审计日志,包含:
建议使用结构化日志系统(如ELK)存储和分析这些数据。
为防止滥用,应该实现:
示例实现:
typescript复制class RateLimiter {
private counters = new Map<string, number>();
check(key: string, limit: number): boolean {
const count = this.counters.get(key) || 0;
if (count >= limit) return false;
this.counters.set(key, count + 1);
setTimeout(() => {
this.counters.set(key, (this.counters.get(key) || 0) - 1);
}, 60 * 1000); // 1分钟窗口
return true;
}
}
// 使用示例
if (!rateLimiter.check(`user:${userId}:tool:${toolName}`, 10)) {
throw new Error("调用频率过高,请稍后再试");
}
关键监控指标包括:
建议设置以下告警阈值:
常见问题及解决方法:
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| AI不使用工具 | schema描述不清晰 | 优化description字段 |
| 参数总是错误 | 校验规则太严格 | 放宽type/enum限制 |
| 执行结果不理想 | 反馈格式不佳 | 提供更结构化的结果 |
| 权限错误 | 角色配置错误 | 检查RBAC设置 |
调试工具推荐:
随着业务发展,工具可能需要升级。建议采用以下策略:
版本路由示例:
typescript复制// v1工具
controller.registerTool({
name: "create_task_v1",
// ...
});
// v2工具
controller.registerTool({
name: "create_task_v2",
// ...
});
通过组合多个工具,可以实现复杂的业务流程自动化。例如客户反馈处理流程:
利用工具的inputSchema可以动态生成数据收集表单:
typescript复制function generateForm(schema: JSONSchema): FormField[] {
return Object.entries(schema.properties).map(([name, prop]) => ({
name,
label: prop.description || name,
type: mapType(prop.type),
required: schema.required?.includes(name) || false,
options: prop.enum
}));
}
将MCP Tools与测试框架结合,实现:
通过分析工具使用记录,可以构建组织内的知识图谱:
设想一个MCP工具市场,开发者可以:
基于API文档自动生成MCP工具定义,减少手动编码工作。
通过分析工具使用效果,AI可以学习:
将部分工具部署到边缘设备,实现:
在实际项目中,我们发现最成功的MCP应用往往遵循"80%自动化+20%人工监督"的原则。建议初次实施时从低风险场景开始,逐步建立团队对AI自动化的信任。记住,工具不是要取代人类,而是放大人类的决策能力。