20 - MCP 模型上下文协议


本章课程目标:

  • 理解 MCP(Model Context Protocol,模型上下文协议) 是什么、解决什么痛点,以及它与 ToolRAGAgent 的定位区别。
  • 掌握 MCP 的主机 / 客户端 / 服务器架构、核心能力、常见传输方式,以及 mcp.json、FastMCP、LangChain MCP 适配器在项目中的作用。
  • 跑通并理解本章全部案例:极简教学版服务端、FastMCP 服务端、天气 MCP 服务、同进程客户端、基于 mcp.json + LangChain Agent 的 MCP 客户端,为后续学习 第 21 章 Agent 智能体 打基础。

学习建议: MCP 先别当成一堆协议名背,它的核心是把外部能力接入模型应用时变得更标准。第一遍只抓三组关系:Tools / Resources / Prompts 是暴露的能力,Host / Client / Server 是通信角色,stdio / Streamable HTTP 是传输方式。学完 第 21 章 Agent 智能体 后再回来看 Agent + MCP,会更容易理解它为什么重要。

官方文档与资源:详见 工具导航与参考资料索引 - 工具调用、MCP与智能体


1、为什么需要 MCP

1.1 真实项目里的接入痛点

很多同学第一次接触 MCP 时,会把它理解成“让大模型联网”或“让大模型能调用工具”。这只说对了一部分。
更核心的问题其实不是“模型能不能用工具”,而是“不同 AI 应用怎样用统一方式接入外部工具和上下文”。

在没有 MCP 时,真实项目里常见的痛点主要有三类:

  • 每个 AI 应用都要重复接一遍外部系统
    例如同样是接 GitHub、Slack、数据库、文件系统,Cursor 要写一套,Claude Desktop 要写一套,自研 Agent 平台又要写一套。

  • 每个框架和宿主各有自己的接法
    即使大家都支持 Tool / Function Calling,真正落地时仍然要处理:服务如何发现、参数 schema 怎么描述、鉴权怎么传、进程怎么启动、结果怎么返回。

  • 工具很难复用成“生态能力”
    没有统一协议时,一个工具即使写得很好,也往往只能服务于某个特定应用,迁移和复用成本很高。

无 MCP 时:各 AI 应用需分别对接 GitHub、Slack、数据库等,重复开发与适配成本高

所以,MCP 出现的背景,不是“以前没人会写工具”,而是:

大家都在写工具,但缺少一套跨应用、跨框架、跨宿主都能复用的统一连接标准。

1.2 MCP 的核心问题

MCP 解决的问题可以概括成一句话:让“外部工具、资源、提示词模板”等能力,能够按统一协议被不同 AI 应用发现和使用。

举个更贴近项目的例子。假设你在 IDE 里有一个 AI 编程助手,希望它能:

  • 读取本地代码仓库
  • 查 GitHub Issue
  • 调内部文档系统
  • 查询云服务配置
  • 调用数据库辅助排查问题

如果没有 MCP,你往往要为这个 AI 助手单独实现很多连接器。如果这些能力都已经按 MCP 标准暴露,那么这个 AI 助手只需要支持 MCP,就可以统一接入这些服务。

这时,MCP 的价值就很明显了:一次暴露,多处复用统一 schema,降低适配成本更容易形成工具生态

1.3 直观类比:AI 世界的统一插口

很多同学都记得钢铁侠的助手「贾维斯」:它不是只会聊天,而是能连接战甲、实验室、摄像头、数据库、控制系统等各种外部能力。

现实中的 AI 应用也是一样。一个真正有用的 AI 助手,往往不仅要“说”,还要能:查本地文件、查数据库、搜 GitHub Issue、调天气接口、发消息到 Slack / 微信 / 邮件、调用内部业务系统。

若缺乏统一协议,每接一类系统都要单独实现连接与鉴权,维护成本陡增

如果每接一个系统都单独写一套连接逻辑,成本会非常高。MCP 的思路,就是给 AI 应用提供一个更像“统一插口”的东西。

把它理解成一层统一插口会更直观:它像 AI 世界的 USB-C,也像 大模型版的 OpenFeign / gRPC 协议层,本质上承担的是 AI 应用和外部能力之间的通用适配层

把这层直觉和上一节连起来理解会更顺:MCP 统一的不是模型本身,而是 AI 应用发现、理解、调用和复用外部能力的方式。


2、MCP 简介

2.1 定义

MCP(Model Context Protocol,模型上下文协议)是一套开放的标准协议,用于规范 AI 应用 / Agent / IDE / 聊天客户端 如何与 外部工具、资源和上下文提供方 交互。

官方的核心表述可以概括成:

  • MCP 标准化了应用程序向 LLM 提供上下文的方式
  • 它让 AI 应用可以用统一方式连接不同的数据源和工具

入门阶段可先把握这一点:

MCP 的关键词是“标准协议、统一接入、跨宿主复用”。

2.2 和 Tool、RAG、Agent 有什么区别

概念 解决什么问题 典型关注点
Tool / Function Calling 模型如何调用一个具体工具 工具 schema、参数、调用结果
RAG 模型如何拿到外部知识上下文 文档加载、切块、检索、上下文拼接
MCP 外部能力如何被标准化暴露与接入 Host / Client / Server、协议、传输、发现
Agent 谁来规划、决策、调用这些能力 推理、编排、记忆、执行闭环

一句话速记:

术语约定: 本章里表格写作 Tool / Function Calling,是为了兼容不同文档语境;和 第 17 章 一样,你可以把它们先看成同一层“模型如何表达工具调用意图”的机制。

  • Tool 解决“能不能调用”
  • RAG 解决“能不能拿到知识”
  • MCP 解决“怎么统一接入”
  • Agent 解决“谁来决定何时调用”

3、MCP 能做什么

3.1 统一接入与抽象

MCP 最直观的价值,就是把原本分散的外部能力,用统一方式暴露给 AI 应用。

分散接入:各工具、服务、客户端各自约定协议与 schema,重复适配多

说明:「分」——各应用、各数据源各自对接,重复开发、难以复用。

MCP 统一层:标准化暴露后,由 Host 侧按同一套方式发现与调用能力

说明:「合」——通过 MCP 等统一协议,一次开发、多端复用。

所以,MCP 不是在替代 Tool,而是在 Tool 之上再向上抽象了一层“协议层”。

3.2 MCP 服务器通常能暴露什么

根据官方文档,MCP 服务器最核心的三类能力是:

类型 作用 控制方式 对应案例
Tools 可执行动作,例如查天气、查数据库、发请求 模型可触发 McpServer.pyMcpServerWeatherByFastMCP.py
Resources 可读取内容,例如文件、配置、数据库 schema、API 响应 应用 / 宿主决定如何使用 McpServerByFastMCP.py@mcp.resource()
Prompts 可复用的提示词模板 / 工作流模板 用户显式选择更常见 McpServerByFastMCP.py@mcp.prompt()

官方对三者的控制方式有明确区分:

  • Tools 是 model-controlled
  • Resources 是 application-driven
  • Prompts 更偏 user-controlled

也就是说:

  • Tool 更适合让模型自动决定何时调用
  • Resource 更适合由宿主决定如何纳入上下文
  • Prompt 更适合由用户显式触发某种模板化工作流

这也是为什么不能把 MCP 简单理解成“就是工具协议”。工具是 MCP 的一部分,但不是全部。

3.3 容易忽略的另外几类能力

除了 Tools / Resources / Prompts,官方协议里还有一些更进阶的客户端 / 会话能力,例如:

  • Sampling:服务器通过客户端向宿主侧的 LLM 请求一次生成(把“算力在哪一侧”也纳入协议协作)
  • Elicitation:服务器通过客户端向用户请求补充信息
  • Logging:服务器向客户端发送结构化日志
  • Progress / Notifications:长任务过程中的进度和通知

这些内容在当前仓库案例里没有作为主线展开,但对理解 MCP 很重要,因为它说明:

MCP 不只是“列出工具然后调用工具”,它还定义了更完整的人机协作和上下文交换机制。

不过对本章来说,先重点掌握:

  • Tool 如何暴露
  • 服务器和客户端怎么连
  • LangChain / Agent 如何拿到 MCP 工具

就已经足够了。

3.4 在实际项目的常见用途

在真实项目里,MCP 最常见的落地方向通常有三种:

  1. 给现成 AI 应用接能力
    例如让 Cursor、Claude Desktop、VS Code、ChatGPT 类客户端接入文件系统、代码库、浏览器、内部系统。

  2. 给自研 Agent 平台做统一工具接入层
    这样 Agent 平台就不用为 GitHub、数据库、知识库、Slack、云平台各写一套不同协议。

  3. 让企业内部能力变成可复用的 AI 接口层
    例如把“查工单”“查订单”“查配置”“发通知”这些能力封装成 MCP 服务,供多个 AI 应用共享。

安全与信任边界(落地必知): MCP Server 往往能以较高权限访问本机文件、内网 API 或密钥;生产环境应控制来源可信(仅安装审计过的服务)、最小权限网络隔离,并记录调用审计。这与“能接什么”同样重要。


4、怎么用 MCP

4.1 直接使用现成的 MCP 服务

如果你的目标不是“学习怎么实现协议”,而是“先把能力接进来”,最直接的方式通常是:

  • 找到现成的 MCP Server
  • 在宿主应用里配置连接方式
  • 让客户端自动发现其 Tools / Resources / Prompts

当前官方已经有 Registry 方向的能力和生态,公共 MCP 服务器的发现也越来越规范化。这意味着:

很多能力无需一开始就自己写服务端,先学会怎么接、怎么配、怎么调试也很有必要。

通过 Registry 或目录浏览、发现已发布的 MCP 服务与能力(示意)

4.2 本地自建 MCP 服务端

如果你要接的是:本地文件系统、内部数据库、企业私有 API、自己的业务系统。

那通常就要自己写 MCP Server。这也是本章案例的重点:我们会通过本地天气服务、FastMCP 示例和 mcp.json 客户端配置,理解一个 MCP 服务是如何被暴露、被发现、再被 Agent 使用的。

4.2.1 什么是 FastMCP

这里很适合顺手把 FastMCP 这个词讲清楚,因为后面的案例文件名里会频繁出现它。

**FastMCP 是 MCP 官方 Python 生态里用来快速编写 MCP Server 的高层封装。**它帮你把很多底层样板工作收起来,让你可以更接近“写 Python 函数”的方式去暴露 MCP 能力。

先把它和 MCP 的关系看成下面这组对应:

  • MCP 是协议标准,解决“AI 应用怎么统一接入外部能力”
  • FastMCP 是 Python 里的服务端开发工具,解决“我怎么更方便地把能力按 MCP 标准暴露出去”

也就是说:MCP 是规则FastMCP 是实现这些规则的一种工具。这就像:HTTP 是协议,FastAPI / Flask 是帮助你实现 HTTP 服务的框架。

放到这一章里也是一样:MCP 决定 Host、Client、Server 之间怎么协作,FastMCP 帮你更轻松地写出一个 MCP Server。

4.2.2 本章为什么讲 FastMCP

在真实项目里,如果你准备自己写一个 MCP 服务端,通常有两条常见路线:

  1. 自己直接按 SDK / 协议细节去实现
  2. 借助 FastMCP 这种更高层的封装来实现

第二条路线通常更友好,因为它能把注意力放回到“我要暴露什么能力”上,而不是一开始就陷进大量底层细节。

这也是为什么本章案例会分成两类:

  • McpServer.py
    这是教学版极简实现,帮助你理解“服务端注册工具”这个最小概念。

  • McpServerByFastMCP.pyMcpServerWeatherByFastMCP.py
    这是更贴近真实 Python MCP 开发体验的写法,帮助你理解 Tool / Resource / Prompt 怎么按官方 SDK 风格暴露出去。

因此这一章里,FastMCP 不是主角,MCP 协议本身才是主角;但 FastMCP 很适合作为 Python 侧的入门实现工具。

4.3 在 LangChain / Agent 里使用 MCP

这一点也和当前项目主线非常贴近。

LangChain 官方已经提供了对 MCP 的适配支持。常见路线是:

  1. MultiServerMCPClient 连接一台或多台 MCP 服务器
  2. 通过 get_tools() 取回 MCP 工具
  3. 把这些工具交给 create_tool_calling_agentcreate_agent
  4. 让 Agent 在对话中实际调用它们(Agent 的创建与执行细节见 第 21 章 Agent 智能体

这也说明了 MCP 和 LangChain 的关系:

  • MCP 负责“标准化接入”
  • LangChain / Agent 负责“把接进来的能力真正用起来”

5、MCP 架构知识

5.1 主机、客户端、服务器定义

MCP 采用典型的 Host - Client - Server 架构。

MCP 架构:Host(用户应用)内的 Client 与远端或子进程中的 Server 通信,Server 再访问本地/远程资源

角色 含义
MCP Host(MCP 主机) 用户真正交互的应用,例如 IDE、桌面客户端、聊天应用、自研 AI 平台
MCP Client(MCP 客户端) Host 内部负责和某个 MCP Server 建立协议连接的组件
MCP Server(MCP 服务器) 对外暴露 Tools / Resources / Prompts 等能力的服务
本地 / 远程资源 服务器可访问的文件、数据库、API、内部系统等

官方文档里需要分清一个点:

  • Host 是你在用的应用
  • Client 是 Host 内部的协议连接组件

这也是为什么“一个 Host 可以连多台 Server”,但“一个具体 Client 通常对应一条到某台 Server 的直接连接”。

多 Server 拓扑:同一 Host 可挂多个 Client,各 Client 分别维护到一台 Server 的会话

5.2 MCP 协议层面大致怎么工作

MCP 不只是“发 HTTP 请求”这么简单,它在协议层有自己的一套约定。
学习本章时,先理解下面这条主线即可:

  1. Host / Client 发起连接
  2. Client 和 Server 做初始化
  3. 双方声明各自支持的 capabilities
  4. 客户端发现服务器提供的 tools / resources / prompts
  5. 按需调用或读取
  6. 结果返回给 Host,再由模型 / UI 使用

MCP 的底层消息格式基于 JSON-RPC 2.0(请求 / 响应 / 通知)。这也是为什么你会在很多资料里看到:

  • request / response / notification
  • capabilities negotiation
  • initialize

MCP 更像是:**“AI 应用与外部能力之间的协议层 + 能力发现层 + 调用层”**而不只是某个单纯的 SDK。

5.2.1 用 5 个动作理解一次完整 MCP 调用

如果把 MCP 放回一轮真实问答里,可以把它拆成下面 5 个动作:

  1. 握手与能力发现(Handshake & Discovery)
    Host 启动后,会根据配置连接 MCP Server,并完成初始化。此时客户端会知道:这台服务器提供了哪些 Tools、Resources、Prompts,以及它支持哪些 capabilities。

  2. 用户提问与上下文注入(Context Injection)
    用户提出问题后,Host 会把“用户问题 + 已发现的工具说明 / 资源信息 / 提示词信息”一并提供给模型或应用逻辑。

  3. 模型或应用做决策(Reasoning / Decision)
    模型决定是否需要调用某个 Tool,或者应用决定是否读取某个 Resource、选用某个 Prompt。

  4. 路由与执行(Routing & Execution)
    Host / Client 按协议把请求发给 MCP Server。Server 在自己的进程或远端服务中执行真正的逻辑,例如查天气、读文件、查数据库。

  5. 结果回传与继续生成(Result Feedback)
    Server 把结果返回给 Client,Client 再把结果交回 Host,由 Host 继续让模型生成最终回答,或者直接展示给用户。

可以把这个过程和第 17 章 Tool 调用对比着理解:

  • Tool 调用 更像“模型知道怎么调一个函数”
  • MCP 更像“这个函数来自哪里、怎么发现、怎么连接、怎么按协议调”

这也是为什么在 Agent 场景里,MCP 常常出现在 Tool 之前一层。

5.3 两类常见传输:STDIO 与 HTTP 系列

这一节先把新旧叫法分清楚。

根据 MCP 官方传输规范(文档以 Transports 等页面为准,版本会迭代),当前主线标准传输是:

  1. stdio
  2. Streamable HTTP

官方还明确说明:

  • Streamable HTTP 取代了 2024-11-05 版本中的 HTTP+SSE transport
  • 新的 HTTP 传输里,服务器仍然可以使用 SSE 作为流式返回机制

也就是说,今天更准确的理解应该是:

  • STDIO:本地子进程通信
  • Streamable HTTP:独立服务进程,通过 HTTP 通信,必要时可配合 SSE 流式返回

而你在很多旧资料、旧案例、适配器配置里看到的 sse,通常属于:

  • 旧的 HTTP+SSE transport 叫法
  • 或兼容写法
  • 或具体库层面对历史接口的保留

传输方式对照:stdio(子进程管道)与 Streamable HTTP(独立 HTTP 服务,可含 SSE 流式)及历史 SSE 兼容语境

结合仓库现有案例,可以这样看:

传输方式 更适合什么场景 对应案例
STDIO 本地、轻量、由客户端拉起服务端进程 McpServerByFastMCP.py
SSE / HTTP 兼容教学写法 理解历史资料、理解远程服务形态 McpServerWeatherByFastMCP.pymcp.json
当前规范重点 优先理解为 Streamable HTTP 新项目应以官方规范为准

读仓库案例时记住两点:

  • 本章案例保留 sse 写法,是为了兼容仓库现有代码
  • 当前规范重点应理解为 stdio + Streamable HTTP

5.3.1 传输之外,还要注意安全边界

MCP 真正落地时,传输方式只是第一层,安全边界同样重要。结合官方安全实践,先记住下面几条:

  • 写操作要有人确认:删除、外呼、支付、批量修改这类 Tool,不要默认让模型静默执行。
  • HTTP 服务要做鉴权和来源校验:至少要考虑 token、会话身份、Origin / 来源校验,而不是“能连上就算接入成功”。
  • 本地服务尽量收口暴露范围:能只监听本机就不要默认对公网开放,避免把调试用 MCP Server 直接变成外网入口。
  • 日志与业务数据要分级处理:进度、错误、调试日志很有用,但不要把敏感配置、私有数据原样暴露给模型或不可信客户端。

5.4 FastMCP 的基本写法与常用 API

仓库里的 MCP 服务端案例,主要围绕 FastMCP / 官方 Python SDK 这条路线展开。看案例前,先把这几个 API 的职责记住:

5.4.1 创建服务实例

1
2
3
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("Demo")

这一步是在创建一个 MCP Server 实例。

5.4.2 注册 Tool

1
2
3
@mcp.tool()
def add(a: int, b: int) -> int:
return a + b

这表示把一个普通 Python 函数暴露成 MCP Tool。

5.4.3 注册 Resource

1
2
3
@mcp.resource("greeting://default")
def get_greeting() -> str:
return "Hello from static resource!"

这表示服务器对外暴露一个可读资源,客户端可以按 URI 读取。

5.4.4 注册 Prompt

1
2
3
@mcp.prompt()
def greet_user(name: str, style: str = "friendly") -> str:
return f"为{name}生成问候语"

这表示服务器对外暴露一个可复用提示词模板。

5.4.5 启动服务

1
mcp.run(transport="stdio")

或者:

1
mcp.run(transport="streamable-http")

在当前仓库案例里,还保留了:

1
mcp.run(transport="sse", host="127.0.0.1", port=8000)

这类写法用于保留仓库现有案例。阅读时把它放在“历史兼容 / 教学保留”的语境里即可。

5.4.6 从底层 SDK 视角看客户端

McpClientAgent.py 用的是更高层的 MultiServerMCPClient,它把很多底层细节都封装掉了。
但从学习角度,知道底层客户端大概在做什么,会更有助于你理解 MCP。

以官方 SDK 思路来看,一个 MCP 客户端的典型动作通常是:

  1. 建立传输连接
  2. 创建 ClientSession
  3. 调用 initialize()
  4. list_tools() / list_resources() / list_prompts()
  5. call_tool() / read_resource() / get_prompt()

如果是 STDIO,大致会是这样的顺序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import asyncio
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client

async def main():
server_params = StdioServerParameters(
command="python",
args=["mcp_server_stdio.py"],
)
async with stdio_client(server_params) as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
tools = await session.list_tools()
result = await session.call_tool("add", {"a": 1, "b": 2})
print(tools)
print(result)

asyncio.run(main())

如果是 Streamable HTTP,核心差异主要在“连接方式”变成了远程 URL:

1
2
3
4
5
6
7
8
9
10
11
12
import asyncio
from mcp import ClientSession
from mcp.client.streamable_http import streamable_http_client

async def main():
async with streamable_http_client("http://127.0.0.1:8000/mcp") as (read, write, _):
async with ClientSession(read, write) as session:
await session.initialize()
tools = await session.list_tools()
print(tools)

asyncio.run(main())

你不需要一上来就背这些底层 API,但知道这层动作很有价值,因为它能帮助你理解:为什么要先 initialize();为什么客户端能“列出”工具、资源和提示词;为什么 MultiServerMCPClient 本质上是在帮你封装这些底层过程。

5.5 完整调用过程理解

把协议层想象成一条完整链路,会更容易理解:

  1. 用户在 Host 中发起请求
  2. Host 内部某个 MCP Client 与对应 Server 建立会话
  3. Client 发现 Server 暴露的能力
  4. 模型或应用决定是否调用某个 Tool / 读取某个 Resource / 获取某个 Prompt
  5. Server 执行或返回结果
  6. Host 把结果展示给用户,或继续交给模型推理

如果这个流程再落到 LangChain Agent 里,就会变成:

  1. MultiServerMCPClient 连接 MCP 服务
  2. get_tools() 获取工具
  3. Agent 拿到工具列表
  4. 用户提问
  5. Agent 选择工具
  6. 工具返回结果
  7. 模型基于结果继续生成最终回答

6、案例实战:本地 MCP 天气服务与客户端

6.1 本章案例在项目中的位置

核心文件如下:

文件 作用 你应该怎样理解它
McpServer.py 极简教学版服务端 概念演示版,帮助理解“工具如何注册和暴露”
McpServerByFastMCP.py FastMCP 正式写法示例 展示 tool / resource / prompt + stdio
McpServerWeatherByFastMCP.py 天气服务端 展示天气 Tool 和 HTTP/SSE 兼容写法
McpClient.py 简化版客户端 同进程教学版,不是严格意义上的协议网络客户端
mcp.json 客户端连接配置 声明要连接哪些 MCP 服务、怎么连接
McpClientAgent.py LangChain + MCP 客户端 更贴近真实项目,读取 mcp.json 后把 MCP 工具交给 Agent

6.2 服务端案例区分理解

6.2.1 极简教学版:McpServer.py

【案例源码】案例与源码-2-LangChain框架/11-mcp/McpServer.py

McpServer.py

这个文件最重要的价值,不是“严格协议完整实现”,而是帮助你先看懂 MCP 服务端到底在干什么

它做的核心事情只有两件:

  1. 维护一个 _tools 容器
  2. @mcp.tool()get_weather 注册进去

所以它更像一个“MCP 思想演示版”。

你应该把它理解成:

  • 帮你先理解“服务器暴露工具”这件事
  • 帮你理解客户端为什么能发现工具
  • 帮你理解 MCP 和普通 @tool 的关系

但也要明确:它不是一个严格意义上完整、标准、可独立对外服务的 MCP 服务器实现。

6.2.2 标准写法入门版:McpServerByFastMCP.py

【案例源码】案例与源码-2-LangChain框架/11-mcp/McpServerByFastMCP.py

McpServerByFastMCP.py

这个文件更接近“官方 Python SDK / FastMCP 的正常使用方式”,它同时演示了:

  • @mcp.tool()
  • @mcp.resource()
  • @mcp.prompt()
  • mcp.run(transport="stdio")

它很适合用来回答一个关键问题:MCP 服务器不只是暴露工具,它还可以暴露资源和提示词模板。

这也是本章里最适合拿来建立“Tools / Resources / Prompts 三分法”直觉的案例。

6.2.3 天气服务端:McpServerWeatherByFastMCP.py

【案例源码】案例与源码-2-LangChain框架/11-mcp/McpServerWeatherByFastMCP.py

McpServerWeatherByFastMCP.py

这个文件主要展示两件事:

  1. 如何把天气查询封装成 MCP Tool
  2. 如何把服务端作为“独立服务”运行起来

这个文件仍使用仓库中的 transport="sse" 写法。阅读时把它当作“独立服务形态”的教学案例即可;新项目的传输方式,仍优先对照前面 5.3 节里的 stdio / Streamable HTTP

6.3 mcp.json 简介

【配置文件】案例与源码-2-LangChain框架/11-mcp/mcp.json

mcp.json

这一节我特别想帮你纠正一个常见误区:

mcp.json 不是 MCP 协议本身,也不是“唯一契约”。

它更准确的定位是:某些 MCP Host / Client / 适配器常用的客户端连接配置文件。

也就是说,它解决的是:

  • 要连接哪几台服务器
  • 每台服务器用什么 transport
  • URL / command / args 是什么

而不是:

  • MCP 协议本体如何定义
  • Tool schema 的完整定义如何写

这里的 mcp.json 主要读三类信息:

  • weather
    • sse
    • 指向本地天气服务
  • fetch
    • stdio
    • 通过命令启动一个本地 MCP Server

这也很好地体现了 MCP 的一个现实特点:同一个客户端完全可以同时连接多台 MCP Server,而且每台服务器可以用不同传输方式。

6.4 客户端案例怎么区分理解

6.4.1 同进程教学版客户端:McpClient.py

【案例源码】案例与源码-2-LangChain框架/11-mcp/McpClient.py

McpClient.py

这个文件容易让人误会,这里需要讲清楚:它的重点是演示:

  • 服务端如何暴露工具
  • 客户端如何发现工具
  • 工具如何被调用

但它的实现方式是:

  • from McpServer import mcp
  • 直接读 mcp._tools
  • 同进程内直接调用函数

所以它更像:MCP 思路演示版客户端,而不是:真正按协议通过网络或子进程传输连接到独立服务端的客户端。也正因为如此,它很适合入门,但不适合被误当成“正式 MCP 网络调用案例”。

6.4.2 更贴近真实项目的客户端:McpClientAgent.py

【案例源码】案例与源码-2-LangChain框架/11-mcp/McpClientAgent.py

McpClientAgent.py

这个案例更贴近真实项目,因为它做了下面这条完整链路:

  1. 读取 mcp.json
  2. MultiServerMCPClient 连接服务
  3. 通过 get_tools() 拿到 MCP 工具
  4. 把工具交给 LangChain Agent
  5. 让 Agent 在对话中实际使用这些工具

这个文件最值得学习的地方有两个:

第一,它说明 MCP 和 Agent 是怎么接起来的。
MCP 不负责帮你规划,也不负责帮你推理;它负责把工具接进来。真正决定“什么时候调用天气工具”的,是 Agent。

第二,它说明 LangChain 对 MCP 的支持已经不只停留在工具发现。
根据 LangChain 官方文档,除了 get_tools(),现在还可以:

  • get_resources()
  • get_prompt()
  • 使用 stateful session
  • 处理 logging / elicitation / structured content

不过本章主线,还是以 MCP 工具接入 Agent 为重点,这也是最适合入门先掌握的第一步。

这里再补一个会话相关的细节:

不少适配器会把“获取工具并调用工具”封装成按需连接的路径。多数普通工具这样用就够了;如果 Server 依赖长期会话状态,就要按文档使用 async with client.session(...) 等写法维持会话,再在这个会话里读取资源、提示词或调用工具。

6.5 测试建议与学习顺序

建议按下面顺序跑这一章案例:

  1. 先看 McpServer.py + McpClient.py
    先建立“服务端暴露工具、客户端发现并调用”的直觉。

  2. 再看 McpServerByFastMCP.py
    建立对 tool / resource / prompt 三类能力的整体认识。

  3. 再看 McpServerWeatherByFastMCP.py + mcp.json
    理解独立服务和客户端配置。

  4. 最后跑 McpClientAgent.py
    看 LangChain Agent 怎么把 MCP 工具真正用起来。

如果你想更贴近官方生态调试方式,还可以了解 MCP Inspector

它适合做这些事情:

  • 查看服务器有哪些 Tools / Resources / Prompts
  • 手工测试工具参数
  • 看服务端日志和通知

这对排查“到底是服务端没暴露出来,还是客户端没连上”非常有帮助。


章节思考题:

  1. MCP 解决的问题,和“写一个本地工具函数”有什么不同?

    参考思路: 本地工具函数只服务当前代码;MCP 让工具、资源、提示词以统一协议暴露给不同 AI 应用复用。它的重点是标准化接入和跨应用复用,而不是多写一个函数。

  2. Host、Client、Server 三个角色如果搞混,会造成什么理解偏差?

    参考思路: 会分不清谁运行应用、谁负责协议通信、谁暴露能力。Host 是应用宿主,Client 负责连接 MCP Server,Server 提供 Tools / Resources / Prompts。角色清楚后,配置和排障才有方向。

  3. Tool、Resource、Prompt 三类能力应该怎么划分?

    参考思路: Tool 适合可执行动作,Resource 适合被读取的上下文资料,Prompt 适合可复用提示模板。不要把所有东西都做成 Tool,否则权限和语义都会变乱。

  4. 什么时候用 stdio,什么时候更关注 Streamable HTTP?

    参考思路: 本地进程、桌面工具、开发调试常见 stdio;跨进程、服务化、远程访问更需要 HTTP 形态。传输方式服务于部署场景,不是单纯背协议名。

本章小结:

  • MCP 的本质:不是模型、不是工具本身,而是 AI 应用与外部能力之间的标准化连接协议。
  • MCP 的核心价值:统一发现、统一描述、统一接入,让工具、资源、提示词模板更容易跨应用复用。
  • 和其他概念的区别:Tool 解决“调用能力”,RAG 解决“检索知识”,Agent 解决“规划和决策”,MCP 解决“标准化接入”。
  • 当前规范重点:标准传输优先理解为 stdioStreamable HTTP;仓库中的 sse 写法保留为案例兼容与教学理解用途。
  • 本章案例主线:从极简版教学服务端,到 FastMCP 服务端,再到 mcp.json + LangChain Agent 的 MCP 客户端,已经构成了完整的入门路线。
  • 安全边界不能省略:MCP 让接入更统一,不代表接入就天然安全。真实项目里仍要考虑服务器来源可信、认证授权、最小权限、敏感能力隔离,以及不要把本不该暴露的内部资源直接开放给模型侧。
  • 学完本章后,你至少应该能分清四件事:MCP 是协议层;Host / Client / Server 是通信角色;Tools / Resources / Prompts 是服务端暴露的能力;统一接入不等于自动解决安全问题。

建议下一步: 建议先把本章的本地服务端和客户端都亲手跑通,再回看 第 17 章 Tools 工具调用第 21 章 Agent 智能体,你会更容易看清“本地 Tool、MCP Tool、Agent 决策层”三者在工程上的分工。