MCP 核心能力:工具、资源与提示
MCP 核心能力:工具、资源与提示
三大核心原语
MCP Server 通过三种原语(Primitives) 向 Client 暴露自身能力。每种原语有不同的控制模型和用途:
| 原语 | 控制方 | 核心用途 | 类比 |
|---|---|---|---|
| Tools(工具) | 模型(LLM) | 执行操作、调用 API、查询数据 | 员工的手,能干活 |
| Resources(资源) | 应用(Client) | 暴露结构化数据供读取 | 员工的资料库,能查阅 |
| Prompts(提示词) | 用户 | 提供可复用的提示词模板 | 员工的话术模板,能套用 |
[!tip] 理解控制方的含义
- 模型控制:LLM 在对话中自主决定是否调用,用户通常不需要手动触发
- 应用控制:Client 代码决定何时读取,通常作为上下文注入到对话中
- 用户控制:用户从列表中选择并主动使用
Tools(工具)
什么是 Tool
Tool 是 MCP 中最重要的原语。它是 Server 暴露给 LLM 的可调用函数,让 AI 能够执行实际操作。
Tool 的结构
每个 Tool 由三部分组成:
| 字段 | 类型 | 说明 |
|---|---|---|
name | string | 工具名称,在 Server 内唯一标识 |
description | string | 工具描述,LLM 根据它决定是否调用 |
inputSchema | object | 输入参数的 JSON Schema 定义 |
tools/list 响应示例:
{
"tools": [
{
"name": "read_file",
"description": "读取指定路径的文件内容",
"inputSchema": {
"type": "object",
"properties": {
"path": {
"type": "string",
"description": "要读取的文件路径"
},
"encoding": {
"type": "string",
"description": "文件编码,默认 utf-8",
"default": "utf-8"
}
},
"required": ["path"]
}
}
]
}
tools/call 交互流程
tools/call 请求:
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "read_file",
"arguments": {
"path": "/tmp/data.txt"
}
}
}
tools/call 成功响应:
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"content": [
{
"type": "text",
"text": "这是文件的内容..."
}
]
}
}
tools/call 错误响应:
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"content": [
{
"type": "text",
"text": "Error: File not found: /tmp/data.txt"
}
],
"isError": true
}
}
Content 类型
Tool 返回的 content 支持多种类型:
| 类型 | 说明 | 示例 |
|---|---|---|
text | 纯文本 | {"type": "text", "text": "Hello"} |
image | 图片(Base64) | {"type": "image", "data": "base64...", "mimeType": "image/png"} |
resource | 嵌入资源引用 | {"type": "resource", "resource": {"uri": "file:///...", ...}}} |
代码示例
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("demo-tools")
# 简单工具 — 自动从函数签名和 docstring 生成定义
@mcp.tool()
async def add(a: int, b: int) -> str:
"""计算两个数的和"""
return str(a + b)
# 带 Optional 参数的工具
@mcp.tool()
async def search_files(
directory: str,
pattern: str,
max_results: int = 10,
) -> str:
"""在指定目录搜索匹配的文件
Args:
directory: 搜索目录路径
pattern: 文件名匹配模式(支持 glob 语法)
max_results: 最大返回结果数,默认 10
"""
# 实际实现...
return f"在 {directory} 中找到匹配 '{pattern}' 的文件"
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
const server = new McpServer({ name: "demo-tools", version: "1.0.0" });
// 使用 Zod 定义输入 Schema
server.registerTool(
"add",
{
description: "计算两个数的和",
inputSchema: {
a: z.number().describe("第一个数"),
b: z.number().describe("第二个数"),
},
},
async ({ a, b }) => {
return {
content: [{ type: "text", text: String(a + b) }],
};
}
);
server.registerTool(
"search_files",
{
description: "在指定目录搜索匹配的文件",
inputSchema: {
directory: z.string().describe("搜索目录路径"),
pattern: z.string().describe("文件名匹配模式"),
max_results: z.number().default(10).describe("最大返回结果数"),
},
},
async ({ directory, pattern, max_results }) => {
return {
content: [
{ type: "text", text: `在 ${directory} 中找到匹配 '${pattern}' 的文件` },
],
};
}
);
Resources(资源)
什么是 Resource
Resource 是 Server 暴露给 Client 的结构化数据,类似于文件系统中的文件。Client 可以读取这些数据作为上下文提供给 LLM。
Resource 的结构
每个 Resource 由以下字段描述:
| 字段 | 类型 | 说明 |
|---|---|---|
uri | string | 资源的唯一标识符(URI 格式) |
name | string | 资源的人类可读名称 |
description | string | 资源描述(可选) |
mimeType | string | MIME 类型(可选) |
resources/list 响应示例:
{
"resources": [
{
"uri": "file:///project/README.md",
"name": "项目 README",
"description": "项目说明文档",
"mimeType": "text/markdown"
},
{
"uri": "db://users/schema",
"name": "用户表结构",
"description": "数据库用户表的 Schema 定义",
"mimeType": "application/json"
}
]
}
Resource URI 设计
Resource 使用 URI 标识,常见的 URI 方案:
| URI 方案 | 用途 | 示例 |
|---|---|---|
file:// | 文件系统资源 | file:///docs/api.md |
config:// | 配置信息 | config://database |
db:// | 数据库资源 | db://users/schema |
http:// / https:// | Web 资源 | https://api.example.com/data |
| 自定义方案 | 任意自定义 | myapp://settings |
静态资源 vs 动态资源
资源订阅
Client 可以订阅资源变更通知,当资源内容发生变化时,Server 会主动通知 Client:
[!tip] Resources vs Tools
常见疑问:什么时候用 Resource,什么时候用 Tool?
- 用 Resource:当你需要暴露数据供 Client 读取(如配置文件、文档、表结构)
- 用 Tool:当你需要暴露操作供 LLM 执行(如发送邮件、写入文件、查询数据库)
代码示例
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("demo-resources")
# 静态资源
@mcp.resource("config://app-info")
def get_app_info() -> str:
"""获取应用信息"""
return "应用名称: Demo Server\n版本: 1.0.0"
# 动态资源(URI 模板)
@mcp.resource("users://{user_id}/profile")
def get_user_profile(user_id: str) -> str:
"""获取用户档案"""
return f"用户 {user_id} 的档案信息"
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
const server = new McpServer({ name: "demo-resources", version: "1.0.0" });
// 静态资源
server.registerResource(
"app-info",
"config://app-info",
{ description: "获取应用信息" },
async (uri) => ({
contents: [
{
uri: uri.href,
text: "应用名称: Demo Server\n版本: 1.0.0",
},
],
})
);
Prompts(提示词)
什么是 Prompt
Prompt 是 Server 暴露给用户的可复用提示词模板。用户可以从 Prompt 列表中选择一个模板,填入参数后使用。
Prompt 的结构
每个 Prompt 包含:
| 字段 | 类型 | 说明 |
|---|---|---|
name | string | 提示词名称 |
description | string | 提示词描述 |
arguments | array | 可选参数列表 |
prompts/list 响应示例:
{
"prompts": [
{
"name": "code-review",
"description": "审查代码并给出改进建议",
"arguments": [
{
"name": "code",
"description": "要审查的代码片段",
"required": true
},
{
"name": "language",
"description": "编程语言",
"required": false
}
]
}
]
}
prompts/get 交互流程
prompts/get 请求:
{
"jsonrpc": "2.0",
"id": 1,
"method": "prompts/get",
"params": {
"name": "code-review",
"arguments": {
"code": "def add(a, b): return a + b",
"language": "python"
}
}
}
prompts/get 响应:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"description": "审查代码并给出改进建议",
"messages": [
{
"role": "user",
"content": {
"type": "text",
"text": "请审查以下 Python 代码,给出改进建议:\n\n```python\ndef add(a, b): return a + b\n```"
}
}
]
}
}
Prompt 中的消息类型
Prompt 的 messages 数组可以包含多种内容类型:
| 类型 | 说明 | 用途 |
|---|---|---|
text | 纯文本消息 | 普通的提示词内容 |
image | 图片消息 | 传入图片供 LLM 分析 |
resource | 嵌入资源 | 自动读取 Server 的 Resource 作为上下文 |
[!tip] Prompt 中嵌入 Resource
Prompt 可以引用 Server 的 Resources,实现「模板 + 数据」的组合。例如,一个"代码审查"提示词可以自动读取项目的代码规范文档作为参考。
代码示例
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("demo-prompts")
# 带参数的提示词模板
@mcp.prompt()
def code_review(code: str, language: str = "python") -> str:
"""代码审查提示词 — 审查代码并给出改进建议"""
return f"""请审查以下 {language} 代码,从以下维度给出建议:
1. 代码质量与可读性
2. 潜在 Bug 和边界情况
3. 性能优化建议
4. 安全隐患检查
代码如下:
```{language}
{code}
```"""
# 不带参数的简单提示词
@mcp.prompt()
def explain_concept() -> str:
"""概念解释提示词 — 用通俗语言解释技术概念"""
return "请用通俗易懂的语言,结合生活实例来解释以下技术概念:"
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
const server = new McpServer({ name: "demo-prompts", version: "1.0.0" });
server.registerPrompt(
"code-review",
{
description: "审查代码并给出改进建议",
argsSchema: {
code: z.string().describe("要审查的代码片段"),
language: z.string().default("python").describe("编程语言"),
},
},
async ({ code, language }) => {
return {
messages: [
{
role: "user",
content: {
type: "text",
text: `请审查以下 ${language} 代码,给出改进建议:\n\n\`\`\`${language}\n${code}\n\`\`\``,
},
},
],
};
}
);
高级能力:Sampling
什么是 Sampling
Sampling 是一种反向通信机制:Server 可以通过 Client 请求 LLM 进行推理。这允许 Server 实现 Agent 式的复杂行为,而自身不需要内置 LLM 能力。
应用场景
| 场景 | 说明 |
|---|---|
| 智能数据处理 | Server 在处理数据时,需要 LLM 帮助理解和分类 |
| 多步推理 | Server 在执行复杂任务时,需要 LLM 辅助决策 |
| 内容生成 | Server 在工作流中需要 LLM 生成文本内容 |
| 自适应行为 | Server 根据 LLM 的推理结果动态调整行为 |
[!warning] 安全注意
Sampling 需要 Client 声明支持该能力,且用户可以配置审批策略。Server 的 Sampling 请求受 Client 的策略限制,包括允许的最大 Token 数等。
高级能力:Roots
什么是 Roots
Roots 是 Client 向 Server 暴露的工作区根目录或 URI。它告诉 Server:"这些是我的工作空间,你的操作应该限制在这些范围内。"
应用场景
- IDE 插件:告诉文件系统 Server 当前打开的项目目录
- 代码分析:Server 只在指定目录范围内搜索和分析代码
- 安全边界:限制 Server 的操作范围,防止越权访问
三种原语的选择指南
总结
| 原语 | 控制方 | 核心方法 | 用途 |
|---|---|---|---|
| Tool | 模型 | tools/list, tools/call | 暴露可执行的操作 |
| Resource | 应用 | resources/list, resources/read | 暴露可读取的数据 |
| Prompt | 用户 | prompts/list, prompts/get | 暴露可复用的提示词模板 |
| Sampling | Server→Client | sampling/createMessage | Server 请求 LLM 推理 |
| Roots | Client→Server | roots/list | 暴露工作区根目录 |