Skip to content

第 17 章 · 核心原语:Tools/Resources/Prompts

本章目标:掌握 MCP Server 可暴露的三大原语——Tools、Resources、Prompts 的分工与控制权归属,理解发现机制,学会按场景为能力选择正确的原语。

11.1 三大原语与控制权归属

MCP 定义了 Server 可以向 Client 暴露的三种核心原语。记住它们的分工固然重要,但更重要的是记住谁决定何时使用(control 权归属):

原语一句话定义控制权典型交互
Tools模型可调用的可执行函数模型控制(model-controlled)模型根据上下文自主决定调用
Resources为模型提供上下文的数据源应用控制(application-driven)Host 应用决定如何纳入上下文
Prompts结构化的提示模板用户控制(user-controlled)用户显式选择触发(如斜杠命令)

官方文档反复强调这个三角关系:Tools 面向"让模型做事",Resources 面向"给应用喂数据",Prompts 面向"让用户一键触发预设流程"。每个原语都配有 */list(发现)、*/get(获取)方法,Tools 还多一个 tools/call(执行)。这种设计让列表可以是动态的

11.2 Tools:模型的双手

Tools 让模型能够执行动作——查数据库、调 API、做计算。每个工具由唯一名称和描述其参数 schema 的元数据标识。

支持 Tools 的 Server 必须在能力中声明 tools.listChanged: true,表示"工具列表可能变化,客户端应监听 notifications/tools/list_changed 通知后重新拉取"。一次完整的调用流程如下:

json
// ① 客户端发现工具
{ "jsonrpc": "2.0", "id": 1, "method": "tools/list" }

// ② 服务端返回工具清单(含 JSON Schema 参数描述)
{
  "jsonrpc": "2.0", "id": 1,
  "result": {
    "tools": [{
      "name": "get_weather",
      "description": "查询指定城市的当前天气",
      "inputSchema": {
        "type": "object",
        "properties": { "city": { "type": "string" } },
        "required": ["city"]
      }
    }]
  }
}

// ③ 模型决定调用后,客户端发起执行
{
  "jsonrpc": "2.0", "id": 2,
  "method": "tools/call",
  "params": { "name": "get_weather", "arguments": { "city": "上海" } }
}

安全红线

规范明确:出于信任与安全考虑,应当始终保留人工在环(human in the loop)的能力来拒绝工具调用。应用应该向用户清晰展示暴露了哪些工具、在工具被调用时给出可视化指示、对敏感操作弹出确认。

11.3 Resources:应用的原料库

Resources 是由 URI 唯一标识的数据源——文件内容、数据库 schema、API 响应等。它的关键特征是应用驱动:Server 把数据摆出来,由 Host 应用决定如何使用(比如通过 UI 让用户挑选哪些文件挂进对话),而不是让模型自主抓取。

python
# mcp_server_resources.py —— 用 FastMCP 声明资源
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("knowledge-base")

@mcp.resource("docs://{doc_name}")
def get_doc(doc_name: str) -> str:
    """暴露静态文档资源,URI 形如 docs://readme"""
    return open(f"./docs/{doc_name}.md").read()

@mcp.resource("config://app-settings")
def get_settings() -> str:
    """动态资源:每次获取时读取最新配置"""
    import json
    return json.dumps(load_settings(), ensure_ascii=False)

Resources 支持订阅机制:客户端可以对某个资源调用 resources/subscribe,当资源变化时收到 notifications/resources/updated 通知再重新拉取——避免轮询浪费。

11.4 Prompts:用户的快捷指令

Prompts 是 Server 提供的可复用提示模板,带参数、可定制。"user-controlled"指的是由用户决定何时使用(模板内容仍是 Server 作者写的)。最自然的呈现方式是聊天输入框里的斜杠命令:

text
/code-review PR#123     ← 用户敲入,Client 取回 prompt 模板并填充参数
python
# mcp_server_prompts.py —— FastMCP 声明提示模板
@mcp.prompt()
def review_code(code: str, focus: str = "安全性") -> str:
    """代码审查模板:用户在界面中选择并填参后触发"""
    return f"""请审查以下代码,重点关注{focus}问题:


输出格式:问题列表(按严重程度排序)+ 修改建议。"""

注意区分:Prompts 是用户主动选的模板;而第 6 章讲过的 system prompt 是应用写死的。前者是 Server 提供给用户的"快捷方式"。

11.5 原语选型决策表与综合案例

面对一个新能力,用这张表快速定原语:

你的需求选什么
模型需要执行某个动作(查询/写入/计算)Tool
应用想把某份数据作为上下文提供给模型,且由应用/用户决定时机Resource
用户经常要触发一段固定的复杂提问流程Prompt
数据 + 执行都要(如"数据库")组合使用三者

官方架构文档给出的综合案例正是一个数据库 MCP Server:

python
# db_server.py —— 一个 Server 同时暴露三种原语
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("company-db")

# Tool:模型可调用的查询动作(model-controlled)
@mcp.tool()
def run_query(sql: str) -> str:
    """对只读副本执行 SELECT 查询,返回结果表格"""
    return execute_readonly_sql(sql)

# Resource:数据库 schema 作为上下文数据(application-driven)
@mcp.resource("db://schema/users")
def users_schema() -> str:
    return open("./schemas/users.sql").read()

# Prompt:封装"分析用户增长"的标准问法(user-controlled)
@mcp.prompt()
def growth_analysis(metric: str) -> str:
    return f"""请基于 users 表(schema 见已加载的资源)分析近 90 天的{metric}趋势,
先用 run_query 工具获取数据,再给出三个关键结论。"""

if __name__ == "__main__":
    mcp.run()   # 默认 stdio 传输启动

三种原语协作:用户敲 /growth-analysis 日活 触发 Prompt → Client 加载 Resource 中的 schema 进上下文 → 模型看到 run_query 工具并决定调用 → 结果回流生成最终分析。

本章小结

  • 三大原语的控制权三角:Tools 模型控制、Resources 应用驱动、Prompts 用户触发;
  • 所有原语都有 */list 动态发现;Tools 额外有 tools/call 执行与 listChanged 变更通知;
  • Resources 用 URI 标识、支持订阅更新;Prompts 以斜杠命令等形式由用户显式触发;
  • 规范要求保留 human-in-the-loop 拒绝工具调用的能力,高危操作必须确认;
  • 复杂场景组合使用三原语:Tool 管动作、Resource 管上下文数据、Prompt 管标准流程。

🛠️ 动手实践

  1. 用 FastMCP 写一个"笔记库" Server:暴露 add_note / search_notes 两个 Tool 和一个 notes://all 资源,用 MCP Inspector 测试全部功能。
  2. 给你的笔记 Server 加一个 weekly-summary Prompt 模板,参数为日期范围,验证它在 Inspector 中的呈现形式。
  3. 思考并写下你工作中的一个内部系统:把它的功能逐一分类到 Tool/Resource/Prompt 三类中,标注每项的控制权归属,找出分类模糊的边界情况。

完成练习后,进入。

完成后进入下一章:传输层与生命周期