<!-- title: 工具之外：MCP资源与提示词开发 -->

# 工具之外：MCP资源与提示词开发

## 概述

绝大多数 Claude Code 的 MCP 教程都只教一件事：用 `@mcp.tool()` 暴露一个函数给 AI 调用。但 MCP 协议其实定义了**三大原语**——Tools（工具）、Resources（资源）、Prompts（提示词）。本教程聚焦被严重低估的 Resources 与 Prompts，带你搞清楚三者本质区别、控制层级的差异，并通过一个可运行的"团队周报知识库 MCP"实战项目，掌握何时该用工具、何时该用资源、何时该用提示词。适合已经能写出基本 Tool 类 MCP、想进阶理解协议全貌的开发者。

## 前置条件

- 已安装 Node.js 18+ 和 Python 3.10+
- 已安装 Claude Code 并完成首次配置（能正常对话）
- 用过 `claude mcp add` 接入过至少一个 MCP 服务器
- 了解 Python 装饰器、`async/await` 基本语法
- 建议先读过 MCP 官方文档的 Quickstart 章节

## 一、核心认知：MCP 不止有工具

打开任何一篇"如何写第一个 MCP 服务器"的教程，你大概率会看到这样的代码：

```python
@mcp.tool()
def get_weather(city: str) -> str:
    return f"{city} 今天晴"
```

这给你一个错觉：**MCP = 给 AI 一堆可调用的函数**。这只说对了三分之一。

MCP（Model Context Protocol，模型上下文协议）定义的服务器能力其实分三类，每类的**控制方不同**，这是整个协议最精妙的设计——也是新手最容易忽视的地方：

| 原语 | 英文 | 控制方 | 本质 | 典型用途 |
|------|------|--------|------|----------|
| 工具 | Tools | **模型（AI）** | 可执行的动词，有副作用 | 查数据库、发请求、写文件 |
| 资源 | Resources | **应用 / 用户** | 只读的名词，提供上下文 | 暴露文件、配置、文档全文 |
| 提示词 | Prompts | **用户** | 结构化交互模板 | 代码评审、周报复盘等固定流程 |

关键洞察：**"谁决定用它"决定了它应该设计成哪一类原语。**

- 工具是 AI 自主决定调用的——所以工具必须有副作用、有返回值，像函数调用。
- 资源是应用（Claude Code 这样的宿主）或用户主动挂载到上下文的——它纯粹是数据，AI 不该"决定"读它，而是被动接收。
- 提示词是用户主动选用的——它是一段预制的指令模板，把"怎么问"标准化。

这个三方划分不是为了炫技，而是为了**权限边界**：你不希望 AI 自己决定把整个数据库 dump 进上下文（那应该用 Resource 由你控制），也不希望它自动执行写操作而不经你确认（Tool 的副作用需要审慎）。

```mermaid
flowchart LR
    U([用户]) -->|"选用 Prompt"| P[Prompt 模板]
    U -->|"挂载 Resource"| R[Resource 数据]
    CC[Claude Code 宿主]
    R --> CC
    AI[AI 模型] -->|"自主调用"| T[Tool 工具]
    T -->|执行/副作用| W[(外部系统)]
    CC -->|上下文| AI
    P -->|注入指令| CC
    style T fill:#ffe4e1,stroke:#c44
    style R fill:#e1f0ff,stroke:#248
    style P fill:#e8ffe1,stroke:#282
```

## 二、三种原语的本质区别（决策树）

写 MCP 服务器前，先问自己三个问题，决定用哪种原语：

```mermaid
flowchart TD
    Start([要暴露一个能力]) --> Q1{AI 需要执行<br/>有副作用的动作吗?}
    Q1 -->|是| Tool[✅ 用 Tool]
    Q1 -->|否| Q2{它是一段只读数据,<br/>希望按需注入上下文?}
    Q2 -->|是| Resource[✅ 用 Resource]
    Q2 -->|否| Q3{它是一套固定的<br/>提问/工作流模板?}
    Q3 -->|是| Prompt[✅ 用 Prompt]
    Q3 -->|否| Rethink[重新审视需求]
    style Tool fill:#ffe4e1,stroke:#c44
    style Resource fill:#e1f0ff,stroke:#248
    style Prompt fill:#e8ffe1,stroke:#282
```

一个反直觉的结论：**不要把所有东西都做成 Tool。** 很多人把"读取配置文件"做成 `@mcp.tool()`，这是典型的滥用——配置是只读数据，AI 每次"调用工具"读取都浪费一次往返，而且无法被宿主预加载或缓存。正确的做法是做成 Resource，让 Claude Code 在需要时一次性挂载。

## 三、步骤一：搭建 FastMCP 骨架

我们用 FastMCP——这是 2026 年 Python 生态构建 MCP 服务器的事实标准，语法风格类似 FastAPI。它同时被官方 MCP Python SDK 作为高层封装集成。

创建项目目录并安装依赖：

```bash
mkdir weekly-kb-mcp && cd weekly-kb-mcp
python -m venv .venv && source .venv/bin/activate
pip install fastmcp
```

创建 `server.py`，先写最简骨架：

```python
from fastmcp import FastMCP

# 服务器名称会显示在 Claude Code 的 /mcp 列表中
mcp = FastMCP("weekly-kb")

# 内嵌示例数据，让代码复制即可运行（真实场景改为读文件/数据库）
REPORTS = {
    "week-28": {
        "author": "张三",
        "content": "# 第28周周报\n\n- 完成 MCP 资源模块开发\n- 修复 3 个 SQL 探针 bug\n- 重构日志诊断模块",
    },
    "week-29": {
        "author": "张三",
        "content": "# 第29周周报\n\n- 上线周报知识库 MCP\n- 编写三原语文档\n- Code Review 5 次",
    },
}

if __name__ == "__main__":
    # 默认以 stdio 传输运行，适合 Claude Code 本地接入
    mcp.run()
```

**预期结果**：`python server.py` 启动后挂起等待，无报错。stdio 传输意味着 Claude Code 会把它作为子进程拉起，通过标准输入输出通信。

**常见问题**：
- `ModuleNotFoundError: No module named 'fastmcp'`——确认激活了虚拟环境（`source .venv/bin/activate`）。
- 端口占用——`mcp.run()` 默认 stdio 不占端口；若你误传了 `transport="http"` 才会监听端口。

## 四、步骤二：实现 Tools（快速回顾）

工具是最熟悉的一类，这里只放对比用的实现——一个**带副作用/计算**的能力：

```python
@mcp.tool()
def summarize_author(author: str) -> str:
    """统计某人在所有周报中的出现情况并返回汇总。

    Args:
        author: 作者姓名
    """
    hits = [wk for wk, r in REPORTS.items() if r["author"] == author]
    return f"{author} 共提交 {len(hits)} 篇周报：{', '.join(hits)}"
```

注意工具的标志：它有**计算逻辑**、有**结构化返回**，且 AI 会**自主决定**何时调用它（比如你问"张三这阵子都干了啥"，AI 自己判断要调这个工具）。

## 五、步骤三：实现 Resources（重点之一）

资源是把**只读数据**通过 URI 暴露出去。这是本教程的核心增量。

### 1. 静态资源：一个 URI 对应一份数据

```python
@mcp.resource("kb://latest")
def latest_report() -> str:
    """最新一篇周报全文"""
    last_week = list(REPORTS.keys())[-1]
    return REPORTS[last_week]["content"]
```

### 2. 模板资源（动态 URI）：参数化路径

这是资源最强大的特性——用 `{占位符}` 声明 URI 模板，FastMCP 会自动注册成可变资源：

```python
@mcp.resource("report://2026/{week}")
def get_report(week: str) -> str:
    """获取指定周次的周报全文。

    Args:
        week: 周次标识，如 week-28
    """
    if week not in REPORTS:
        raise ValueError(f"未找到周报: {week}")
    return REPORTS[week]["content"]
```

声明后，Claude Code 会识别出 `report://2026/week-28`、`report://2026/week-29` 等所有合法实例。**FastMCP 会自动从函数签名和 docstring 推断参数类型**，无需手写 schema。

### 3. 资源在 Claude Code 中如何使用

这是 Resources 与 Tools 体验差异最大的地方：

- 在对话中输入 **`@`**，会弹出资源选择器，列出 `kb://latest`、`report://2026/week-28` 等。选中后，其内容被**注入上下文**。
- 这就是"application/user-controlled"的体现——**你或宿主决定挂载哪份数据**，AI 不会自作主张把所有周报都读进来。

**常见问题**：
- 资源不显示在 `@` 列表——检查 URI scheme 是否合法（必须是 `scheme://path` 形式，如 `report://`、`config://`、`file://`）。
- 模板资源参数推断失败——给函数参数加上类型注解（`week: str`），并在 docstring 里写清楚含义。
- 想返回富文本——返回类型可声明为带 MIME 的字符串，FastMCP 支持指定 `text/markdown` 等。

## 六、步骤四：实现 Prompts（重点之二）

提示词是**预制的工作流模板**，由用户主动选用。它把"怎么提问"标准化，避免每次手敲长指令。

```python
@mcp.prompt()
def performance_review(author: str, week: str = "week-29") -> str:
    """生成绩效复盘：阅读指定周报，总结贡献并给出改进建议。

    使用方式：在 Claude Code 斜杠命令中选用此 prompt，填入作者与周次。
    """
    return f"""请扮演资深技术管理者，对以下信息做绩效复盘：

1. 先读取资源 report://2026/{week}
2. 重点评估 {author} 在该周的产出
3. 输出三段：本周亮点、风险事项、下周建议

要求语气客观，用 bullet 列点，避免空话套话。"""
```

注意这个 Prompt 内部**引用了前面定义的 Resource**（`report://2026/{week}`）——这正是三原语协同的威力：Prompt 是工作流编排，它指挥 Claude 去读 Resource、必要时调 Tool。

### Prompt 在 Claude Code 中的使用

MCP prompts 在 Claude Code 里会以**斜杠命令**形式出现，命名规则是 `/mcp__<服务器名>__<prompt名>`。所以上面的 prompt 会显示为：

```
/mcp__weekly-kb__performance_review
```

输入它会弹出参数表单（`author`、`week`），填好后整段模板被注入为新对话的起始指令。这就是"user-controlled"——**只有你主动选用，它才会触发**，AI 不会自作主张套用模板。

**常见问题**：
- 斜杠命令不出现——确认服务器已成功加载（`/mcp` 查看状态），且 prompt 函数无语法错误。
- 参数表单没字段——FastMCP 依赖类型注解和默认值推断；给参数加 `: str` 和默认值。
- 想返回多轮消息——`@mcp.prompt()` 也支持返回消息列表（`list[dict]`），可构造 system + user 多条消息。

## 七、步骤五：在 Claude Code 中配置并使用

在项目根目录创建 `.mcp.json`（团队共享）或用命令行添加（个人）：

```bash
claude mcp add weekly-kb -- python /绝对路径/weekly-kb-mcp/server.py
```

或编辑 `.mcp.json`：

```json
{
  "mcpServers": {
    "weekly-kb": {
      "command": "python",
      "args": ["/绝对路径/weekly-kb-mcp/server.py"]
    }
  }
}
```

**注意**：`command` 用绝对路径更稳妥；若用虚拟环境，写成 `.venv/bin/python` 可避免依赖缺失。

验证连接：在 Claude Code 中输入 `/mcp`，应看到 `weekly-kb` 状态为 `connected`，并展开显示其暴露的 tools、resources、prompts 三类能力。

三种典型用法对照：

| 你想做的事 | 在 Claude Code 里的操作 | 触发的原语 |
|-----------|----------------------|-----------|
| 看最新周报内容 | 输入 `@` 选 `kb://latest` | Resource |
| 看 28 周详情 | 输入 `@` 选 `report://2026/week-28` | Resource（模板） |
| 让 AI 统计张三产出 | 直接问"张三提交了几篇周报" | Tool（AI 自主调用） |
| 做一次绩效复盘 | 输入 `/mcp__weekly-kb__performance_review` | Prompt |

## 八、步骤六：用 MCP Inspector 调试

调试时不要每次都开 Claude Code，用 Inspector 可视化测试三类原语最快：

```bash
# 方式一：FastMCP 内置（推荐）
fastmcp dev server.py

# 方式二：官方 Inspector
npx @modelcontextprotocol/inspector python server.py
```

Inspector 会打开一个网页，左侧列出该服务器的 **Tools / Resources / Prompts / Templates** 四个标签页：

- **Tools 标签**：填参数 → 点调用 → 看返回值。
- **Resources 标签**：直接点 URI 看内容，验证模板资源的路径展开是否正确。
- **Prompts 标签**：填模板参数 → 预览生成的完整指令文本。

这是排查"为什么我的资源/提示词没出现在 Claude Code 里"最快的工具——如果 Inspector 里能看到，说明服务器没问题，问题在配置或缓存（试试重启 Claude Code）。

## 九、实战案例：完整的团队周报知识库 MCP

下面是整合三种原语的完整 `server.py`，复制即可运行。它演示了一个真实知识库 MCP 该有的分层：数据层（Resources）、计算层（Tools）、工作流层（Prompts）。

```python
from fastmcp import FastMCP

mcp = FastMCP("weekly-kb")

# ============ 数据源（真实场景替换为读文件 / 查 DB）============
REPORTS = {
    "week-28": {"author": "张三", "tags": ["mcp", "bugfix"],
                "content": "# 第28周周报\n- 完成 MCP 资源模块\n- 修复 SQL 探针 3 个 bug\n- 重构日志诊断模块"},
    "week-29": {"author": "张三", "tags": ["mcp", "doc", "review"],
                "content": "# 第29周周报\n- 上线周报知识库 MCP\n- 编写三原语文档\n- Code Review 5 次"},
    "week-29-lisi": {"author": "李四", "tags": ["frontend", "perf"],
                "content": "# 第29周周报\n- 优化首屏加载\n- 修复白屏问题\n- 引入懒加载"},
}

# ============ Resource：只读数据层（application/user-controlled）============
@mcp.resource("kb://latest")
def latest_report() -> str:
    """最新一篇周报全文"""
    return REPORTS["week-29"]["content"]

@mcp.resource("report://2026/{week}")
def get_report(week: str) -> str:
    """获取指定周次的周报全文"""
    if week not in REPORTS:
        raise ValueError(f"未找到: {week}")
    return REPORTS[week]["content"]

# ============ Tool：计算/聚合层（model-controlled，有副作用语义）============
@mcp.tool()
def search_by_tag(tag: str) -> str:
    """按标签搜索周报，返回匹配的周次列表。

    Args:
        tag: 标签名，如 mcp / frontend / bugfix
    """
    hits = [wk for wk, r in REPORTS.items() if tag in r["tags"]]
    if not hits:
        return f"没有周报包含标签 {tag}"
    return f"标签 [{tag}] 命中：{', '.join(hits)}"

@mcp.tool()
def count_by_author(author: str) -> str:
    """统计某人提交的周报数量"""
    n = sum(1 for r in REPORTS.values() if r["author"] == author)
    return f"{author} 共提交 {n} 篇周报"

# ============ Prompt：工作流层（user-controlled，斜杠命令）============
@mcp.prompt()
def performance_review(author: str, week: str = "week-29") -> str:
    """绩效复盘：读周报 → 评估贡献 → 给建议"""
    return f"""请扮演技术管理者做绩效复盘：
1. 读取资源 report://2026/{week}
2. 评估 {author} 的产出
3. 输出：本周亮点 / 风险事项 / 下周建议
语气客观，bullet 列点。"""

@mcp.prompt()
def weekly_digest() -> str:
    """生成全员本周摘要：先按标签搜索，再汇总"""
    return """生成本周全员工作摘要：
1. 用 search_by_tag 逐个查找 mcp / frontend / bugfix 标签
2. 汇总各人产出，按人分组
3. 用一段话总结本周团队重心"""

if __name__ == "__main__":
    mcp.run()
```

这个设计的精髓在于**职责清晰**：

- 用户想"看某一篇"→ 用 Resource（精确、按需、不浪费 token）。
- 用户想"搜/统计"→ 用 Tool（AI 自主判断聚合逻辑）。
- 用户想"走一套固定流程"→ 用 Prompt（标准化、可复用、可传承给团队新人）。

```mermaid
sequenceDiagram
    participant U as 用户
    participant CC as Claude Code
    participant AI as AI 模型
    participant S as weekly-kb MCP
    U->>CC: /mcp__weekly-kb__performance_review(张三, week-29)
    Note over CC: Prompt 被注入为指令<br/>(user-controlled)
    CC->>AI: 携带指令开始对话
    AI->>S: 读取 Resource report://2026/week-29
    S-->>AI: 返回周报全文(application-controlled 数据)
    AI->>S: 调用 Tool count_by_author(张三)
    Note over AI: model-controlled,<br/>AI 自主决定是否调
    S-->>AI: 返回 "张三共提交 2 篇"
    AI-->>U: 输出绩效复盘(亮点/风险/建议)
```

## 十、常见问题与最佳实践

**Q：一个能力该做成 Tool 还是 Resource？**
A：有副作用、需要计算/聚合 → Tool；纯只读、希望按需注入 → Resource。记住：把"读文件"做成 Tool 是最常见的反模式。

**Q：Prompt 和 CLAUDE.md 里写指令有什么区别？**
A：CLAUDE.md 是常驻的全局指令，永远在上下文里；Prompt 是按需触发的工作流模板，只在用户主动选用时注入。频繁流程用 Prompt，长期规则用 CLAUDE.md。

**Q：模板资源 `{week}` 和 Tool 参数 `week` 有何不同？**
A：模板资源是**宿主预先枚举成多个独立 URI**，适合有限、稳定的命名空间（周次、ID）；Tool 参数是**运行时动态传入**，适合开放查询（搜索关键词）。前者可被 `@` 选择器列出，后者不能。

**Q：发布给别人用时，stdio 还是 HTTP 传输？**
A：本地命令行用 stdio（`mcp.run()`）；要部署成云端服务供多人/多客户端连接，用 `mcp.run(transport="http")` 跑 Streamable HTTP，并配合鉴权。

## 延伸阅读

- MCP 官方规范（含三大原语正式定义）：`modelcontextprotocol.io`
- FastMCP 文档（Resources / Prompts 章节）：`gofastmcp.com`
- Claude Code 接入 MCP 的配置详解：`code.claude.com/docs/en/mcp`
- 官方 MCP Inspector 工具与示例服务器：`github.com/modelcontextprotocol`

## 训练营适用性评估

- **适合类型**：MCP 进阶开发训练营、AI 工程师工具链训练营、企业内部 AI 平台建设培训。不适合零基础——需先掌握 Tool 类 MCP。
- **教学时长**：建议 3–4 学时。其中概念辨析（三种原语控制层级）1 学时、FastMCP 编码实战 1.5 学时、Inspector 调试与课堂练习 1 学时。
- **配套练习建议**：让学员把一个"公司内网文档检索"需求拆成三原语——文档全文做 Resource、检索做 Tool、按部门做总结做 Prompt，并答辩为什么这么拆。
- **前置课程**：建议放在"基础 Tool 类 MCP"之后、"远程 HTTP MCP / 鉴权"之前，作为理解协议全貌的承上启下章节。

## 参考来源

1. [Connect Claude Code to tools via MCP — Claude Code Docs](https://code.claude.com/docs/en/mcp) — Claude Code 官方 MCP 接入文档，含 `.mcp.json` 配置与 `claude mcp add` 命令说明。
2. [MCP Server Patterns: Tools vs Resources vs Prompts (When to Use Each) — DEV Community](https://dev.to/webbywisp/mcp-server-patterns-tools-vs-resources-vs-prompts-when-to-use-each-5bgp) — 深入对比三种原语的本质区别与使用场景，本文决策树的主要依据。
3. [MCP Tools vs Resources vs Prompts — RapidDev Tutorial](https://www.rapidevelopers.com/mcp-tutorial/mcp-tools-vs-resources-vs-prompts) — 明确指出 Tools 为 model-controlled、Resources 为 application-controlled、Prompts 为 user-controlled 的控制层级划分。
4. [MCP Server Setup — Learn to Prompt](https://learntoprompt.org/guides/mcp-servers.html) — 面向 Claude Code 等 CLI Agent 的 MCP 服务器搭建指南，覆盖 Tools/Resources/Prompts 三原语配置。
5. [MCP Developer Guide 2026: Build, Deploy & Secure AI Tool Integrations](https://lushbinary.com/blog/mcp-model-context-protocol-developer-guide-2026/) — 2026 年 MCP 开发者全景指南，含架构、部署与安全实践。

> [!tip] 51学通信知识星球
> **星主：爱卫生**（微信：gprshome201101）——公众号「51学通信」创办者，19 年通信行业运维与讲师经验，著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书（各大电商平台有售）。
> **星球定位**：深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域，主打运维岗位与信令分析。
> **当前规模**：5200 篇主题 / 990 个回答，198 元/年。
> **加入福利**：加入星球后请加爱卫生微信，拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题，另有群内分享。
> **AI 加持**：51学通信知识星球已作为 skill 接入 WorkBuddy，使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例，做总结、找文档和 PPT 等场景全覆盖。

![51学通信知识星球海报-扫码加入](https://wiki.500nian.com/images/zhixingqiu_qrcode.png)
