如果你最近在 CSDN、GitHub 或者 B 站刷到“MCP”这个词,大概率会和我一样有个困惑:MCP 是不是又一个要替代 LangChain 的框架?为什么 LangChain 的教程里满屏都是 MCP,LangGraph 的示例里也在讲 MCP?
先给一个结论:MCP 不是 LangChain 的替代品,它解决的是“工具接入标准化”这个更底层的问题。LangChain 仍然是那个帮你编排 Prompt、模型、工具和 Agent 的高层框架,而 MCP 让“接入外部工具”这件事不再每个框架写一套适配器。把这两者放在一起学,才是 2026 年做 Agent 开发比较合理的技术栈。
这篇文章不是概念罗列,而是一条从 LangChain 基础到 MCP 代码实战的完整路线。我会先讲清楚 LangChain、LangGraph、MCP 之间的关系,再用可以直接复制的代码,带你跑通一个 Agent 调用 MCP Server 的示例。读完你能回答下面几个问题:
- LangChain 和 MCP 到底哪一层负责什么事?
- 为什么说 MCP 让工具接入从“私有格式”变成“公开协议”?
- 如何用 LangChain 的 Agent 动态调用 MCP Server 暴露的工具?
- 实际项目中接入 MCP 有哪些坑,怎么做才不容易翻车?
如果你已经学过一点 LangChain,但一直没想清楚怎么把 MCP 用起来,这篇文章建议收藏起来照着做。
1. LangChain、LangGraph、MCP:先分清这三个概念
很多教程把 LangChain、LangGraph、MCP 混在一起讲,导致初学者以为它们是同类框架。实际上三者处于不同抽象层级。
1.1 LangChain 解决什么问题
LangChain 是一套面向 LLM 应用的高层开发框架,提供了模型调用、Prompt 管理、输出解析、文档加载、向量存储、Retrieval、Agent 等模块。你可以把 LangChain 理解成一个“零件库 + 组装手册”,它把开发 LLM 应用时反复出现的通用逻辑封装成组件。
典型场景包括:
- 模型接入:
ChatOpenAI、ChatOllama等。 - RAG 流水线:加载文档、切分、向量化、检索、生成。
- Agent 编排:让模型决定调用哪些工具。
1.2 LangGraph 解决什么问题
LangGraph 是 LangChain 官方团队推出的编排库,核心是“图状态机”。它允许你把 Agent 内部流程建模成节点和边的有向图,节点可以执行工具调用、模型调用、条件分支,边负责状态流转。
一个常见的误解是 LangGraph 是 LangChain 的升级版。更准确的说法是:LangChain 提供组件,LangGraph 提供流程控制。在复杂 Agent 场景里,LangGraph 比旧的AgentExecutor更适合生产环境,因为它对状态流转、循环、记忆和分支的控制更精确。
1.3 MCP 解决什么问题
MCP(Model Context Protocol)是一个开放协议,由 Anthropic 提出,后来逐步成为 AI 工具接入领域的事实标准之一。它定义了一套标准化的通信方式,让 LLM 应用通过客户端连接外部“工具服务器”。
MCP 本身不是一个 LLM 框架,也不关心你的应用是 LangChain、LangGraph、Dify 还是自定义代码。它只管一件事:用统一的协议描述工具、发现工具、调用工具、返回结果。
1.4 三者对比
| 技术 | 抽象层级 | 核心作用 | 典型问题 |
|---|---|---|---|
| LangChain | LLM 应用框架 | 模型、Prompt、RAG、Agent 组件 | “零件从哪来” |
| LangGraph | Agent 编排框架 | 状态图、节点、分支、循环 | “流程怎么控制” |
| MCP | 工具接入协议 | 发现与调用外部工具 | “工具怎么连” |
所以当你看到“langchain 过时了吗”这类讨论时,其实问错了方向。LangChain 作为一个重量级框架当然有争议,但 MCP 只是在工具层做标准化,两者并不冲突。更好的做法是:用 LangGraph 控制流程,用 MCP 接工具,用 LangChain 的组件做 RAG 和模型调用。
2. 为什么要用 MCP:从“写死工具”到“协议接入”
在没有 MCP 之前,我们接入一个工具通常这样做:在 LangChain 里用@tool装饰器定义一个函数,写上参数类型和 description,然后绑定给 Agent。这种方法在单应用内很好用,但问题也很明显:
- 工具逻辑和应用代码耦合在一起。
- 如果另一个应用也想用这个工具,要么复制代码,要么重新实现。
- 每个框架都有自己的工具格式,脚本工具、浏览器工具、数据库工具,接入方式各不相同。
MCP 改变了这个模式。它把工具放到独立的 Server 进程中,通过标准协议暴露。客户端只需要知道 Server 的启动方式,就能动态获取工具列表,并直接调用。
我举几个现实例子,你就能理解为什么 MCP 会火:
- Playwright MCP:把浏览器自动化能力封装成 MCP Server,LLM 可以通过它控制浏览器做端到端测试。
- Figma MCP:让 Agent 读取设计稿结构,辅助生成前端代码。
- Chat2DB MCP:把数据库查询能力开放给 AI 助手。
- IDE 类工具:例如通过 MCP 把 IDE 的编辑、搜索能力暴露给 Agent。
甚至安全分析、科学计算领域的工具,也陆续有人编写 MCP Server。这说明 MCP 正在成为工具接入的“通用语言”。
从 LangChain 开发者的角度看,MCP 带来的最大变化是:你不再需要为每个工具单独写胶水代码,只需要用官方 Adapter 把 MCP Server 暴露的工具转换成 LangChain 工具,剩下的工作交给 Agent。这个思路下面会通过代码完整演示。
3. 环境准备与前置条件
开始写代码之前,先把环境准备好。本文示例以 Python 为主,建议使用 Python 3.10 及以上版本,并创建独立虚拟环境,避免依赖冲突。
3.1 创建虚拟环境
python -m venv .venv source .venv/bin/activate # Windows 环境执行: # .venv\Scripts\activate3.2 安装依赖
需要安装以下包:
mcp:MCP 官方 Python SDK,包含 Server 和 Client。langchain:LangChain 核心框架。langchain-openai:统一接入 OpenAI 兼容接口。langgraph:用于创建 Agent。langchain-mcp-adapters:MCP 工具转 LangChain 工具的适配层。
安装命令:
pip install --upgrade pip pip install mcp langchain langchain-openai langgraph langchain-mcp-adapters如果你的网络环境访问 PyPI 较慢,可以使用镜像安装:
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple mcp langchain langchain-openai langgraph langchain-mcp-adapters安装完成后,先确认关键包版本:
pip show mcp langchain langgraph langchain-mcp-adapters版本无需完全一致,但建议都使用较新的版本。如果安装过程中出现依赖冲突,优先在干净虚拟环境中重试。
4. LangChain 工具调用基础:先跑通 Agent
在接入 MCP 之前,先花几分钟跑通一个最基础的 LangChain Agent,确保模型调用和工具绑定环节没有问题。
4.1 编写一个普通工具
新建文件tools_demo.py:
# 文件路径:tools_demo.py from datetime import datetime from langchain_core.tools import tool @tool def get_current_time() -> str: """获取当前时间。""" return datetime.now().strftime("%Y-%m-%d %H:%M:%S") @tool def multiply(a: int, b: int) -> int: """计算两个整数的乘积。""" return a * b这里定义了两个工具:一个返回当前时间,一个做乘法。工具函数本身不依赖 MCP,但我们会用同样的模式,把 MCP Server 里的工具包装成 LangChain 工具。
4.2 创建 Agent
新建文件agent_demo.py:
# 文件路径:agent_demo.py import os from langchain_openai import ChatOpenAI from langgraph.prebuilt import create_agent from tools_demo import get_current_time, multiply # 使用 OpenAI 兼容接口,可以替换为你自己的模型服务 model = ChatOpenAI( model=os.getenv("MODEL_NAME", "gpt-4o-mini"), temperature=0, base_url=os.getenv("OPENAI_BASE_URL", "https://api.openai.com/v1"), ) agent = create_agent( model=model, tools=[get_current_time, multiply], system_prompt="你是一个帮助用户处理问题的助手,请优先使用工具获取信息。", ) def main(): result = agent.invoke( {"messages": [{"role": "user", "content": "现在是几点?计算 8 乘以 12。"}]} ) for message in result["messages"]: print(message.type, "=>", message.content) if __name__ == "__main__": main()运行前需要配置模型访问凭证。如果你使用的是 OpenAI 官方服务,需要设置环境变量OPENAI_API_KEY;如果你使用国产模型或企业内部模型,只要它兼容 OpenAI 接口,都可以通过base_url指向对应地址。
运行:
export OPENAI_API_KEY="你的合法API Key" # Windows 系统: # set OPENAI_API_KEY=你的合法API Key python agent_demo.py如果一切正常,你会看到模型决定先调用get_current_time和multiply,最后返回组合结果。这一步验证了“模型工具调用”链路是通的。
5. MCP 核心原理与最小 Server
现在进入 MCP 部分。先抛开 LangChain,亲手写一个 MCP Server,再用 MCP 客户端调用它。
5.1 MCP 的三层结构
MCP 通常包含三层:
- Host(宿主):运行 LLM 应用的程序,比如 LangChain Agent、Dify、Claude Desktop。
- Client(客户端):在 Host 内部负责与 MCP Server 建立连接、发现工具、调用工具。
- Server(服务端):独立进程或服务,真正执行工具逻辑。
传输方式有两种很常见:
- stdio:本地子进程通信,LangChain 通过
python mcp_server.py启动一个 Server 进程。 - HTTP / SSE:远程服务通信,适合部署在服务器上的共享工具。
需要强调的是,MCP Server 只是工具背后的执行进程,它不负责“思考”。选择工具、决定调用顺序,仍然是模型的职责。
5.2 编写一个最简单的 MCP Server
新建文件mcp_server.py:
# 文件路径:mcp_server.py import sqlite3 from datetime import datetime from mcp.server.fastmcp import FastMCP # 创建一个 MCP Server,名称为 demo mcp = FastMCP("demo-server") @mcp.tool() def get_current_time() -> str: """获取当前时间。""" return datetime.now().strftime("%Y-%m-%d %H:%M:%S") @mcp.tool() def query_users() -> str: """ 查询本地 demo.db 中 users 表的所有用户。 使用前请确保已创建 demo.db 并导入数据。 """ conn = sqlite3.connect("demo.db") try: rows = conn.execute("SELECT id, name FROM users").fetchall() finally: conn.close() return "\n".join(f"{id}:{name}" for id, name in rows) if __name__ == "__main__": # 默认以 stdio 模式运行 mcp.run()这里包含了两个工具:一个返回当前时间,一个查询 SQLite 数据库。代码很直观,关键是mcp.tool()装饰器,它把普通函数变成了 MCP 工具。
5.3 准备本地 SQLite 测试数据
执行下面的命令,生成demo.db:
python -c "import sqlite3; conn=sqlite3.connect('demo.db'); conn.execute('CREATE TABLE IF NOT EXISTS users(id INTEGER PRIMARY KEY, name TEXT)'); conn.executemany('INSERT OR IGNORE INTO users(id,name) VALUES (?,?)', [(1, 'Alice'), (2, 'Bob')]); conn.commit(); conn.close()"5.4 用 MCP Client 直接调用
新建文件mcp_client_demo.py:
# 文件路径:mcp_client_demo.py import asyncio from mcp import ClientSession, StdioServerParameters from mcp.client.stdio import stdio_client async def main(): # 指定启动 MCP Server 的命令 server_params = StdioServerParameters( command="python", args=["mcp_server.py"], ) async with stdio_client(server_params) as (read, write): async with ClientSession(read, write) as session: # 建立连接并初始化 await session.initialize() # 列出 Server 暴露了哪些工具 tools = await session.list_tools() print("MCP Server 工具列表:") for tool in tools.tools: print(f" - {tool.name}: {tool.description}") # 调用 get_current_time result = await session.call_tool("get_current_time", {}) print("当前时间结果:", result.content[0].text) # 调用 query_users result = await session.call_tool("query_users", {}) print("用户列表结果:") print(result.content[0].text) if __name__ == "__main__": asyncio.run(main())运行:
python mcp_client_demo.py预期会输出类似下面的内容:
MCP Server 工具列表: - get_current_time: 获取当前时间。 - query_users: 查询本地 demo.db 中 users 表的所有用户。 当前时间结果: 2026-01-01 10:00:00 用户列表结果: 1:Alice 2:Bob到这里,你已经完成了 MCP 的“最小闭环”:Server 暴露工具,Client 发现并调用工具。接下来要做的是把这段逻辑接入 LangChain Agent。
6. LangChain + MCP 完整实战:让 Agent 动态调用 MCP 工具
这一节的最终目标是:LangChain Agent 不直接定义工具函数,而是通过 MCP 获取工具,并根据用户问题自动选择调用。
6.1 用 Adapter 快速接入
langchain-mcp-adapters提供了load_mcp_tools,可以直接把 MCP Server 里的工具转换成 LangChain 工具列表。
新建文件langchain_mcp_agent.py:
# 文件路径:langchain_mcp_agent.py import asyncio import os from langchain_mcp_adapters.tools import load_mcp_tools from langchain_openai import ChatOpenAI from langgraph.prebuilt import create_agent from mcp import ClientSession, StdioServerParameters from mcp.client.stdio import stdio_client model = ChatOpenAI( model=os.getenv("MODEL_NAME", "gpt-4o-mini"), temperature=0, base_url=os.getenv("OPENAI_BASE_URL", "https://api.openai.com/v1"), ) async def run(): server_params = StdioServerParameters( command="python", args=["mcp_server.py"], ) async with stdio_client(server_params) as (read, write): async with ClientSession(read, write) as session: await session.initialize() # 关键:把 MCP Server 暴露的工具加载成 LangChain 工具 tools = await load_mcp_tools(session) print("已加载工具数量:", len(tools)) for tool in tools: print("工具名称:", tool.name) agent = create_agent( model=model, tools=tools, system_prompt="你是一个本地助手,需要调用工具时请直接调用。", ) result = await agent.ainvoke( {"messages": [{"role": "user", "content": "现在几点了?顺便帮我查一下 users 表里有哪些用户。"}]} ) for message in result["messages"]: print(message.type, "=>", message.content) if __name__ == "__main__": asyncio.run(run())这段代码最核心的一行是:
tools = await load_mcp_tools(session)它把 MCP 协议里的工具定义,统一转换成了 LangChain Agent 能够理解的BaseTool对象。转换完成之后,创建 Agent 的方式和普通 LangChain 工具没有任何区别。
6.2 理解 Adapter 背后的原理
如果你不想依赖 Adapter,也可以手动包装。MCP Client 返回的工具调用结果,本质上就是一段文本或结构化内容。我们可以用 LangChain 的@tool包装一个调用函数:
# 伪代码:手动包装 MCP 工具 from langchain_core.tools import tool async def build_tools(session): @tool async def get_current_time() -> str: """从 MCP Server 获取当前时间。""" result = await session.call_tool("get_current_time", {}) return result.content[0].text @tool async def query_users() -> str: """从 MCP Server 查询用户列表。""" result = await session.call_tool("query_users", {}) return result.content[0].text return [get_current_time, query_users]这种写法更适合理解 MCP 的本质:工具就是一个“函数”,MCP 负责传输。但在实际项目中,一个 Server 可能暴露很多工具,手动写包装函数维护成本很高,所以官方 Adapter 更方便。
6.3 运行完整示例
启动前确认三件事:
mcp_server.py和langchain_mcp_agent.py在同一个目录下。demo.db已经创建好。- 模型服务配置正确,已设置
OPENAI_API_KEY或对应的环境变量。
执行:
python langchain_mcp_agent.py预期你会看到:
- 程序先启动本地 MCP Server 进程;
- Client 与 Server 建立连接;
- Agent 打印已加载的工具列表;
- 模型根据用户问题,先后调用
get_current_time和query_users; - 最终返回包含时间和用户列表的回答。
如果模型没有调用工具,而是直接硬答,请检查模型是否支持 Function Calling。很多轻量模型不支持工具调用,这时候 Agent 不会产生tool_calls,而是直接生成文本回答。
7. 运行结果与效果验证
演示示例没有固定的 JSON 输出,但我们可以从日志和消息流判断 Agent 是否正常。
7.1 判断成功的标准
一次成功的 LangChain + MCP 调用,会在result["messages"]中出现以下消息类型:
human:用户输入。ai:模型第一次输出,可能包含tool_calls。tool:工具执行结果。ai:模型拿到工具结果后生成的最终回答。
只要日志中出现tool类型的消息,说明 Agent 确实走了 MCP 工具调用链路。
7.2 验证 MCP Server 是否工作
如果运行mcp_client_demo.py能正常列出工具并输出结果,说明问题不在 MCP 层,而在模型配置或 Adapter 层。
7.3 如果失败先看哪里
在将 Agent 和 MCP 组合起来之前,建议分步验证:
- 先单独运行
mcp_client_demo.py,确认 MCP Server 能被客户端发现和调用。 - 再运行
agent_demo.py,确认普通 LangChain Agent 能正常使用工具。 - 最后运行
langchain_mcp_agent.py,把两层串起来。
这种“先分后合”的方式,可以快速定位问题在 MCP 层还是 LangChain 层。
8. 常见问题与排查思路
下面是实际开发中比较容易踩的坑。
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| MCP Server 启动后立即退出 | Server 中混用了print,把额外信息输出到 stdout,破坏了 stdio 协议 | 在客户端打印错误日志,或者在服务端用logging替代print | 将工具中的调试输出改为logging,确保 stdout 只传输协议数据 |
| 加载工具数量为 0 | MCP Server 路径错误,或 Server 没有正常注册工具 | 先运行mcp_client_demo.py查看工具列表 | 确保 Server 文件可执行,且工具使用了@mcp.tool()装饰器 |
| Agent 不调用任何工具 | 模型不支持 Function Calling,或工具 description 不清晰 | 直接请求模型,观察是否有tool_calls | 更换支持工具调用的模型,改进工具描述 |
| 连接远程 MCP Server 超时 | 服务端未启动、认证 token 错误、网络不通 | 先使用curl或浏览器访问服务端点 | 确认服务端进程正常,检查地址和认证配置 |
| Windows 下无法启动 MCP Client | 路径中的反斜杠或中文目录导致解析失败 | 打印启动命令,观察报错 | 使用绝对路径,并统一为正斜杠 |
load_mcp_tools报错导入失败 | langchain-mcp-adapters版本不兼容 | 检查 pip freeze 中的包版本 | 升级langchain-mcp-adapters,或参考官方文档调整 import 路径 |
| Agent 返回内容格式异常 | 工具返回了非字符串结构,模型解析时出现问题 | 打印原始工具结果 | 在 MCP Server 中统一返回规范化字符串或 JSON 结构 |
排查时记住一个原则:MCP 负责工具通信,LangChain 负责 Agent 编排,模型负责决策。出问题时先判断是哪一层,再对症下药。
9. 最佳实践与工程建议
如果要把 LangChain + MCP 用到实际项目里,下面这些建议值得认真对待。
9.1 一个 MCP Server 只做一类事情
不要把文件操作、数据库查询、HTTP 请求全部塞进一个 Server。MCP Server 应该遵循单一职责原则,这样工具列表清晰、权限边界容易控制,也方便后续复用。
9.2 工具命名和描述要规范
MCP 工具的描述会直接进入模型上下文,影响模型是否选择调用。建议遵循:
- 工具名用动词开头,例如
query_users、send_email。 - 描述写明用途、适用场景、参数含义。
- 需要参数时,尽量给参数添加说明。
9.3 本地开发用 stdio,生产环境用远程传输
本地调试时,stdio 模式最简单,不需要额外端口和认证。但生产环境一般会把 MCP Server 部署到独立服务,通过 HTTP 或 SSE 暴露。远程传输必须增加鉴权,比如 Token 或 API Key,避免任何未授权请求调用敏感工具。
9.4 敏感操作必须有授权和审计
MCP 工具本质上是一个有本地权限的进程,可以读文件、连数据库、执行命令。如果 Server 被恶意调用,后果会很严重。在工程上建议:
- 工具按权限分级,敏感操作增加二次确认。
- Server 日志记录每一次工具调用。
- 对第三方 MCP Server 保持警惕,不要轻易安装来历不明的 Server。
9.5 正确看待 Skill 与 MCP 的区别
社区里常有人问“Agent Skill 和 MCP 有什么区别”。这两个概念解决的问题不完全一样。
- Skill 偏向“能力包”,包含提示词、代码逻辑、甚至业务流程。
- MCP 偏向“工具通信协议”,解决多个应用如何统一接入同一个工具。
实际项目中,你可能会同时用 Skill 来封装复杂业务能力,用 MCP 来接入通用工具。两者不是替代关系,而是互补关系。
9.6 不要为了用 MCP 而用 MCP
如果你的工具只在本地 LangChain 项目中使用,不打算给其他应用复用,直接用@tool定义反而更简单。MCP 的价值在于标准化、复用和跨应用共享,当你有多个应用需要调用同一组工具,再引入 MCP 才更划算。
10. 后续学习方向:别停在能跑通
跑通上面的示例,意味着你已经理解了 LangChain 和 MCP 协作的最小闭环。但这只是起点,想要深入,建议按这个顺序继续:
- 学透 MCP 协议本身:资源、Prompt、Sampling 等概念,以及 HTTP 传输和认证方式。
- 掌握 LangGraph:把 Agent 流程改造成显式状态图,以便处理复杂分支、人工确认和循环。
- 尝试在 Dify 或低代码平台中接 MCP:很多平台已经支持通过配置连接本地或远程 MCP Server,这会进一步加深你对协议的理解。
- 研究多 Agent 与 MCP 的组合:不同 Agent 共享同一组 MCP 工具,是未来团队协作式 Agent 系统的一个重要方向。
如果时间允许,可以写一个自己的 MCP Server,比如封装公司内部接口或常用的测试环境操作。自己完整实现一遍 Server,比看几十篇教程都更有效。
打开终端,先跑通mcp_client_demo.py,再把它接到 Agent 上。真正让你的 Agent 产生一次tool_calls,你会对这个技术栈有完全不同的理解。