DanLevy.net

没有它,你的 AI 代理毫无用处

为什么 MCP 是人工智能领域的 USB-C。

你已经构建了一个AI代理。也许甚至是个好代理。提示词写得精炼,模型响应快,回复也很自然。

但接着有人让它去检查Salesforce里的客户记录,或者拉取最新的Jira工单,又或者搜索内部文档。

而你漂亮的代理却……做不到。

这是每个AI平台最终都会撞上的集成问题。你的代理需要手,需要眼睛,需要能真正接入你的业务系统。没有这些,你只是在运行一个昂贵的聊天机器人。

传统解决方案?为每一个想连接的服务编写自定义API包装器:读他们的文档,处理他们的认证,对付他们的速率限制,祈祷他们下个月别改端点。然后对下一个服务重复,再下一个。

Model Context Protocol 彻底改变了这个局面。


MCP真正解决了什么

想想USB-C出现之前的USB。你有Mini-USB、Micro-USB、苹果专用接口,还有一抽屉只对特定设备管用的线缆。USB-C不只是增加了一个新接头——它建立了一个标准,从此任何线缆都能用在任何设备上。

MCP正在为AI工具集成做同样的事。

不需要编写自定义代码来把代理连到Salesforce、HubSpot、GitHub或其他任何服务;你只需要实现一次这个协议(或者下载一个预构建的服务器),任何兼容MCP的代理就能立刻跟它通信。

协议负责通信层。你只需要定义你的工具做什么,以及它们需要什么数据。


设置多个集成

Mastra通过 MCPClient 原生支持MCP。你可以连接本地工具(以子进程运行)和远程服务(运行在自己的基础设施上)。

下面是一个连接地图、天气和本地Wikipedia搜索的典型配置:

src/mastra/mcp/index.ts
import { MCPClient } from '@mastra/mcp';
export const mcpClient = new MCPClient({
id: 'navigation-mcp',
servers: {
// Local tool (Stdio)
wikipedia: {
command: 'npx',
args: ['-y', 'wikipedia-mcp'],
},
// Maps & Navigation (Remote/HTTP)
googleMaps: {
url: new URL(process.env.GOOGLE_MAPS_MCP_URL!),
requestInit: {
headers: {
Authorization: `Bearer ${process.env.GOOGLE_MAPS_API_KEY}`,
},
},
},
// Weather Service Integration
weather: {
url: new URL(process.env.WEATHER_MCP_URL!),
requestInit: {
headers: {
'X-API-Key': process.env.WEATHER_API_KEY!,
},
},
},
},
});

客户端管理连接生命周期,处理本地工具的进程生成,并维护远程服务器的HTTP连接。你不需要直接操作socket或stdio。

将工具连接到智能体

一旦配置好 MCP 客户端,将这些工具交给智能体就很简单了:

src/mastra/agents/navigation-agent.ts
import { Agent } from '@mastra/core/agent';
import { mcpClient } from '../mcp';
export const navigationDirectionsAgent = new Agent({
id: 'navigation-directions-agent',
name: 'Navigation & Directions Assistant',
instructions: `You are a helpful navigation assistant that provides route planning and travel advice.
- Always confirm the start and destination locations
- Use Google Maps tools to find optimal routes
- Check weather conditions along the route
- Provide estimated travel times and suggest alternatives if weather is poor
- Include relevant details like traffic, road conditions, and points of interest
- Keep responses clear and actionable`,
model: 'openai/gpt-5.5',
tools: await mcpClient.listTools(), // <--- This is the magic line
});

当用户询问:“从旧金山到太浩湖的最佳路线是什么,我需要担心天气吗?”

智能体读取可用的工具定义,意识到它拥有 Google Maps 路线规划和天气预报工具,用正确的参数执行它们,并回答出最佳路线以及沿途的当前天气状况。

你没有编写一行 Google Maps API 代码或天气服务集成。


按用户认证

这里有一个容易犯的安全错误:硬编码凭据。

如果你在环境变量中放入一个 Google Maps API 密钥然后收工,每个用户共享相同的配额和速率限制。更重要的是,如果你使用存储用户偏好(如保存的地点或常用路线)的服务,每个人都会看到相同的数据。这在演示中没问题。但在生产环境中是隐患。

Mastra 支持你动态创建带有用户特定凭据的 MCP 客户端,并在请求时传递它们的工具集。你仍然处理常规的 SaaS 管道工作:安全地存储令牌、刷新令牌,以及决定哪些用户可以连接哪些服务。

async function handleUserRequest(userPrompt: string, userCredentials: UserCreds) {
// Create a client for THIS specific user
const userMcp = new MCPClient({
id: `maps-${userCredentials.userId}`,
servers: {
googleMaps: {
url: new URL(process.env.GOOGLE_MAPS_MCP_URL!),
requestInit: {
headers: {
// User's specific API key or token
Authorization: `Bearer ${userCredentials.mapsApiKey}`,
'X-User-ID': userCredentials.userId,
},
},
},
},
});
try {
const agent = mastra.getAgent('navigationDirectionsAgent');
// Inject tools at runtime
const response = await agent.generate(userPrompt, {
toolsets: await userMcp.listToolsets(),
});
return response;
} finally {
await userMcp.disconnect();
}
}

每个用户获得自己独立的工具集,带自己的 API 配额和偏好。用户 A 的保存位置保持私有,用户 B 的路线历史分开。这就是多租户 SaaS 智能体在实际中的工作方式。


构建复合工具

有时你需要将多个 MCP 工具组合成一个单一操作。或许你想规划一条路线,同时考虑实时交通和沿途天气状况。

你可以将 MCP 工具包装在自定义工具定义中:

import { createTool } from '@mastra/core/tools';
import { z } from 'zod';
type DirectionsResult = {
waypoints: Array<{ latitude: number; longitude: number }>;
[key: string]: unknown;
};
type ForecastResult = {
alerts?: unknown[];
severe?: boolean;
};
export const smartRouteTool = createTool({
id: 'smart-route-planner',
description: 'Plans optimal route considering traffic and weather conditions',
inputSchema: z.object({
origin: z.string(),
destination: z.string(),
}),
outputSchema: z.object({
route: z.record(z.string(), z.unknown()),
weatherAlerts: z.array(z.unknown()),
recommendation: z.string(),
}),
execute: async ({ origin, destination }, executionContext) => {
const tools = await mcpClient.listTools();
// 1. Get base route from Google Maps
const routeData = await tools.googleMaps_getDirections.execute(
{ origin, destination },
executionContext,
) as DirectionsResult;
// 2. Check weather along the route
const weatherData = await tools.weather_getForecast.execute(
{ coordinates: routeData.waypoints },
executionContext,
) as ForecastResult;
// 3. Return enhanced route with weather warnings
return {
route: routeData,
weatherAlerts: weatherData.alerts ?? [],
recommendation: weatherData.severe
? 'Consider delaying trip'
: 'Safe to travel',
};
},
});

当前的 Mastra 工具首先接收经过验证的输入,然后接收执行上下文。将该上下文传递给发现到的 MCP 工具可以保留请求范围内的状态、追踪和取消。上面的名称和结果类型只是示例约定;请使用你实际连接的 MCP 服务器所通告的名称和模式。

这为你提供了细粒度的控制,精确控制工具之间如何交互,同时仍然利用 MCP 协议完成繁重的工作。


审批应在工具边界进行

MCP 让工具连接更简单。但这并不意味着每个工具都应该无摩擦运行。

Mastra 的 MCPClient 可以在服务器级别要求审批,可以是针对该服务器上的每个工具,也可以按调用动态要求审批:

export const githubMcp = new MCPClient({
id: 'github-mcp',
servers: {
github: {
url: new URL(process.env.GITHUB_MCP_URL!),
requireToolApproval: ({ toolName, annotations }) => {
if (annotations?.readOnlyHint) return false;
if (toolName.includes('delete_')) return true;
return annotations?.destructiveHint ?? true;
},
},
},
});

这种审批仍应被视为应用策略,而非魔法咒语。MCP 工具注解来自受信任的服务器,是有用的提示;但它们本身并非安全边界。对于第三方服务器,请将默认行为设为保守,在智能体修改任何重要内容之前进行询问。


由此延伸

为 AI 智能体需要交互的每个服务编写自定义 API 客户端从来都不是可持续的做法。它扩展性差、频繁出错,并且将你的平台与特定实现绑定在一起。

MCP 并不能解决所有集成难题——认证依然复杂,速率限制仍然重要,而且并非所有服务都已提供 MCP 服务器。但它奠定了一个基础,让构建智能体平台的痛苦大大减少。

如果你正在设计一个需要与外部服务交互的 AI 系统,理解 MCP 很可能值得你花时间。

资源

系列文章

  1. LLM 路由
  2. 安全与护栏
  3. MCP 与工具集成(本文)
  4. 工作流与记忆