Tools / Resources / Prompts
问题
MCP 的三种核心原语(Tools、Resources、Prompts)分别是什么?如何定义?
答案
一、三种原语对比
| 原语 | 控制方 | 用途 | 是否有副作用 | 类比 |
|---|---|---|---|---|
| Tools | 模型调用(LLM 决策) | 执行操作 | 可能有 | POST API |
| Resources | 用户/应用选择 | 读取数据 | 无(只读) | GET API |
| Prompts | 用户触发 | 交互模板 | 无 | API 文档模板 |
二、Tools(工具)
工具是模型可以调用的操作,由 LLM 根据上下文自主决策是否调用:
// Server 端定义工具
server.setRequestHandler("tools/list", async () => ({
tools: [
{
name: "query_database",
description: "执行只读 SQL 查询",
inputSchema: {
type: "object",
properties: {
sql: {
type: "string",
description: "SELECT 查询语句"
},
database: {
type: "string",
enum: ["users", "orders", "products"]
}
},
required: ["sql"]
}
}
]
}));
// 工具调用处理
server.setRequestHandler("tools/call", async (request) => {
const { name, arguments: args } = request.params;
if (name === "query_database") {
const result = await db.query(args.sql);
return {
content: [
{ type: "text", text: JSON.stringify(result, null, 2) }
]
};
}
});
工具设计原则
- 命名清晰:
query_database优于do_stuff - 描述精确:让 LLM 理解何时该调用此工具
- inputSchema 完整:类型、枚举、必填字段都要定义
- 错误处理:返回
isError: true而非抛异常
三、Resources(资源)
资源是 Server 暴露的只读数据,由用户或应用决定加载哪些:
// 列出可用资源
server.setRequestHandler("resources/list", async () => ({
resources: [
{
uri: "file:///project/README.md",
name: "项目说明",
mimeType: "text/markdown"
},
{
uri: "db://users/schema",
name: "用户表结构",
mimeType: "application/json"
}
]
}));
// 读取资源内容
server.setRequestHandler("resources/read", async (request) => {
const { uri } = request.params;
if (uri === "file:///project/README.md") {
const content = await fs.readFile("/project/README.md", "utf-8");
return {
contents: [
{
uri,
mimeType: "text/markdown",
text: content
}
]
};
}
});
资源模板支持动态 URI:
{
uriTemplate: "db://{table}/schema",
name: "数据表结构",
description: "获取指定表的 Schema"
}
资源订阅
Client 可以订阅资源变更通知:
// Client 订阅
client.send("resources/subscribe", { uri: "file:///config.json" });
// Server 发送变更通知
server.notify("notifications/resources/updated", {
uri: "file:///config.json"
});
四、Prompts(提示模板)
Prompts 是预定义的交互模板,由用户主动选择:
// 列出 Prompt 模板
server.setRequestHandler("prompts/list", async () => ({
prompts: [
{
name: "code_review",
description: "代码审查模板",
arguments: [
{
name: "language",
description: "编程语言",
required: true
},
{
name: "code",
description: "待审查的代码",
required: true
}
]
}
]
}));
// 获取 Prompt 内容
server.setRequestHandler("prompts/get", async (request) => {
const { name, arguments: args } = request.params;
if (name === "code_review") {
return {
messages: [
{
role: "user",
content: {
type: "text",
text: `请审查以下 ${args.language} 代码:\n\n${args.code}\n\n
请从以下维度评审:
1. 代码质量与可读性
2. 潜在 Bug
3. 性能问题
4. 安全漏洞`
}
}
]
};
}
});
五、三者协作示例
常见面试问题
Q1: Tools 和 Resources 有什么本质区别?
答案:
- Tools 由模型决策调用,可能有副作用(修改数据、发送请求)
- Resources 由用户/应用选择加载,是只读的数据
- 类比:Tools 像 POST/PUT,Resources 像 GET
Q2: 为什么需要 Prompts?直接写 prompt 不行吗?
答案:
- Prompts 提供可复用的交互模板,避免每次手写
- 模板支持参数化,可动态填充
- 可以嵌入 Resources 引用,自动加载相关数据
- 让非技术用户也能使用复杂的 AI 工作流