字节笔记本
2026年2月23日
MCP 的第二波浪潮:为 LLM 构建,而非开发者
当 MCP 标准首次推出时,许多团队急于发布相关产品。许多服务器最终只是现有 API 的薄包装,改动极小。这是一种快速宣称"我们支持 MCP"的方式。
当时这种做法是合理的。MCP 是新技术,团队希望快速推出产品,而最直接的方法就是镜像现有的 API 结构。为什么要重新发明,当你可以重新包装?
但这种方法的问题在于 LLM 的工作方式与开发者不同。它们不会复用过去的代码或保持长期状态。每次对话都是全新的开始。LLM 必须重新发现哪些工具存在、如何使用它们以及使用顺序。使用低级 API 包装器时,这会导致重复的编排、不一致的行为和浪费的精力,因为 LLM 反复解决相同的难题。
当工具处理完整的用户意图而不是暴露单个 API 操作时,MCP 的效果最好。一个能够端到端部署项目的工具比四个分别处理部署管道不同部分的工具效果更好。
LLM 使用 API 的不同方式
关键区别在于上下文和状态管理。当你编写代码时,你会在 API 调用之间保持信息跟踪。你存储创建调用中的项目 ID,在添加域名之前检查部署状态,并在每个步骤周围包装错误处理,以防止失败破坏整个流程。
LLM 的工作方式不同。每次对话都是全新的开始,没有之前对话的记忆。虽然它们可以看到当前对话中的工具结果,但必须根据可用内容找出正确的工具使用顺序。当这些工具是低级 API 包装器时,LLM 必须编排多个调用并管理将它们链接在一起的复杂性。
例如,使用 Vercel API 部署项目。开发者可能会编写如下代码:
// 传统 API 使用:开发者管理序列
const project = await client.projects.create({
name: domain.replace(/\./g, '-'),
gitRepository: { repo: repoUrl }
});
await client.projects.createProjectEnv({
idOrName: project.id,
upsert: 'true',
requestBody: Object.entries(env).map(([key, value]) => ({
key, value,
target: ['production', 'preview', 'development'],
type: 'encrypted'
}))
});
const deployment = await client.deployments.createDeployment({
requestBody: {
name: project.name,
target: 'production',
gitSource: {
type: 'github',
repo: repo.replace('.git', ''),
ref: 'main'
}
}
});
await client.projects.addProjectDomain({
idOrName: project.id,
requestBody: { domain: domain }
});这种方法涉及嵌套配置、跨调用 ID 管理和解析仓库 URL。开发者只需解决一次就会复用。但 LLM 每次都面临这个难题,经常在嵌套上出错或忘记必填字段。
单工作流工具 vs 多端点
解决方案是围绕完整的用户目标而不是 API 能力来构建工具。不是四个单独的工具,而是创建一个在内部处理整个工作流的 deploy_project 工具。
这改变了工具设计的一切:
| API 形态工具 | 意图导向工具 |
|---|---|
| create_project, add_env, deploy, add_domain | deploy_project |
| 多调用与状态管理 | 单原子操作 |
| 返回技术状态码 | 返回对话式更新 |
| LLM 组装工作流 | 工具拥有完整流程 |
考虑实践中的差异。API 形态的 MCP 服务器可能会暴露这些工具:
create_project(name, repo)
add_environment_variables(project_id, variables)
create_deployment(project_id, branch)
add_domain(project_id, domain)LLM 必须按顺序调用每个工具,在调用之间传递 ID,并在每一步处理潜在的失败。
意图导向的工具看起来不同:
deploy_project(repo_url, domain, environment_variables, branch="main")
这个单一工具在内部处理完整的工作流并返回对话式响应。不是 { status: 200, data: { id: "proj_123" } },LLM 可以回应"项目已部署在 example.com。构建在 45 秒内完成。所有系统正常运行。"
设计基于工作流的 MCP 工具
在编写任何代码之前,先手动测试工作流。拿一个真实的用户请求,比如"用认证和数据库设置我的项目",并使用你现有的 API 逐步完成。那些感觉繁琐或重复的部分是单一 MCP 工具的好候选。
将 MCP 工具视为帮助 AI 完成特定任务的定制工具包,而不是 API 镜像。一个 MCP 工具背后可能有多个 API 和业务逻辑。如果用户将某事视为一个工作流,就将其设计为一个工具。
以下是构建完整工作流工具的方法:
server.tool(
"deploy_project",
"部署带有环境变量和自定义域名的项目",
{
repo_url: z.string(),
domain: z.string(),
environment_variables: z.record(z.string()),
branch: z.string().default("main")
},
async ({ repo_url, domain, environment_variables, branch }) => {
// 在内部处理完整工作流
const project = await createProject(repo_url, branch);
await addEnvironmentVariables(project.id, environment_variables);
const deployment = await deployProject(project.id);
await addCustomDomain(project.id, domain);
return {
content: [{
type: "text",
text: `项目成功部署在 ${domain}。构建在 ${deployment.duration} 秒内完成。`
}]
};
}
);对确定性部分使用普通代码。API 排序、错误恢复和状态管理等内容更适合常规编程。只在真正需要推理或自然语言处理的部分涉及 LLM。
用真实场景测试。通过你的工具运行实际的用户工作流。当你看到 LLM 进行多次尝试或要求澄清时,这是关于你工具设计的反馈。目标是让复杂工作流在第一次尝试时就成功。
工作流工具的性能提升
从 API 形态工具转向工作流形态工具的团队在可靠性和效率方面看到了有意义的改进。
这些工具设计的共同点是:
- 它们关注用户意图而不是 API 覆盖范围
- 它们处理完整的工作流而不是暴露单个操作
- 它们以对话方式响应而不是返回技术代码
当工具反映完整的用户目标时,MCP 的效果最好。LLM 管理状态的方式与开发者不同,因此围绕工作流构建工具会产生更好的结果。
尝试这种方法。MCP handler 使你能够轻松地将应用逻辑暴露为基于工作流的 MCP 工具。使用 Next.js MCP 模板 开始,或探索文档。