MCP + LangChain 实战:从零搭建 Agent 工具调用链路
2026/8/30 5:49:08 网站建设 项目流程

在真实业务里,Agent 最大的痛点往往不是“模型不够聪明”,而是工具接得太痛苦。OpenAI Function Calling 刚出来时大家都觉得方便,可真要在一个项目里接五六个外部系统,函数定义、参数校验、鉴权、错误处理全都堆在业务代码里,越写越重。MCP 的出现在很大程度上改变了这个局面,它给“大模型调用工具”这件事提供了一套统一协议,而 LangChain 作为最常用的 Agent 编排框架,也很快补齐了对 MCP 的原生支持。这篇文章会从概念讲起,一步步带你把 MCP Server 搭起来,再通过 LangChain 把它加载成 Agent 工具,最终跑通调用链路。文章会覆盖 LangGraph 与 LangChain 的关系、DeepSeek API 接入、Claude Code 配置 MCP 等内容,适合正在做 AI Agent 开发、想统一工具接入方式的开发者阅读。

1. 背景与核心概念

1.1 从“大模型生成文本”到“大模型动手干活”

先回顾一下 Agent 进化的路径。最初我们使用大模型只是做文本生成、摘要、翻译,模型和外部世界没有任何交互。后来出现了 Function Calling,模型可以根据用户问题输出一个结构化的工具调用指令,再由代码去执行真实函数。再往后,LangChain 等框架把这些调用逻辑包装成 Agent,让模型能够在一次对话中多次决策:是否需要调用工具、调用哪个工具、拿到结果之后如何继续推理。

但这套流程有一个很现实的问题:不同框架、不同模型、不同工具库,Function Calling 的格式都不一样。你写了一个 Python 函数,想在 Claude Code 里用,又想在另一个 Agent 框架里用,就得分别适配。每接一个新的外部系统,都要重新做一遍胶水代码,而且这些代码往往没有复用价值。MCP 就是在这个背景下产生的。

1.2 什么是 MCP

MCP(Model Context Protocol,模型上下文协议)是 Anthropic 在 2024 年底提出的一种开放协议,目标是为大模型应用提供一套标准化的“工具接入”方式。它的核心设计思路是把“能力提供方”和“能力消费方”解耦。

你可以把 MCP 理解为 AI 应用世界的 USB-C 接口。一个 MCP Server 对外暴露工具、资源、提示词三种能力,任何支持 MCP 的客户端(Host)都可以通过标准协议去发现并调用这些能力,而不需要关心对方是用什么语言写的、部署在哪台机器上。目前主流的 Agent 客户端,比如 Claude Desktop、Claude Code、LangChain、Cursor 等,都已经支持 MCP 协议。

1.3 LangChain 和 LangGraph 分别是什么

很多新手容易把 LangChain 和 LangGraph 搞混,这里做个梳理。

LangChain 是一个生态型的开发框架,提供大模型调用、提示词管理、文档加载、向量检索、工具调用、Agent 编排等模块。它的主要价值是让开发者不用重复造轮子,把常用能力都封装好了。

LangGraph 是 LangChain 团队推出的一个低层编排框架,它把 Agent 的执行流程建模成一张图,节点(Node)表示计算单元,边(Edge)表示流转逻辑。相比 LangChain 早期版本的 AgentExecutor,LangGraph 提供了更好的可控性、可观测性和状态管理能力,适合生产级 Agent 开发。

在 LangGraph 中有一个非常实用的预置组件叫 create_react_agent,它用 ReAct 范式实现了一个完整的 Agent 循环:模型接收输入、判断是否调用工具、执行工具、返回结果、再交给模型推理。本文的实战部分就会基于这个组件来实现。

1.4 为什么需要 MCP + LangChain

LangChain 支持 Agent 工具已经不是新鲜事,关键是如何把 MCP 生态中的工具加载进来。通过 langchain-mcp-adapters,LangChain 可以直接加载远程或本地的 MCP Server 暴露的工具,自动把 MCP 工具转换为 LangChain 的 Tool 对象,然后交给 Agent 调用。

这样一来,工具侧只需要开发一次 MCP Server,就能同时服务于 LangChain Agent、Claude Code、Claude Desktop 等多个客户端。这也是为什么 MCP 被很多人视为 Agent 时代的“标准基础设施”。

本文的完整实战链路如下图:

用户提问 ↓ LangChain Agent(create_react_agent) ↓ 模型决定调用工具 langchain-mcp-adapters ↓ 通过 MCP 协议通信 MCP Server(FastMCP) ↓ 执行真实逻辑 外部系统 / 业务函数 / 数据库

2. 环境准备与版本说明

2.1 基础环境

本文的代码以 Python 3.10 及以上版本为例,操作系统没有特殊限制,Windows、macOS、Linux 均可。建议新建一个独立的 Python 虚拟环境,避免把依赖装到全局环境里造成冲突。

python -m venv .venv source .venv/bin/activate # Windows 下使用 .venv\Scripts\activate

2.2 安装依赖

需要安装的核心依赖如下:

pip install langchain langchain-openai langgraph langchain-mcp-adapters mcp fastmcp

各包的作用如下:

依赖包用途
langchainLangChain 核心库
langchain-openai通过 OpenAI 兼容接口调用模型(DeepSeek 也走这个方式)
langgraphAgent 编排框架,提供 create_react_agent
langchain-mcp-adapters将 MCP 工具加载为 LangChain Tool 的适配层
mcpMCP 官方 Python SDK
fastmcp快速开发 MCP Server 的高层框架

这里要特别提醒:MCP 协议和相关 SDK 更新速度很快,不同版本之间 API 可能会有差异。上面命令安装的是当前 PyPI 上的最新稳定版本。如果你在运行时遇到模块找不到或参数不兼容的问题,优先检查各包的版本,并根据项目实际情况调整。

2.3 项目结构

为了演示方便,本文使用下面的项目结构:

langchain-mcp-demo/ ├── .venv/ # 虚拟环境 ├── mcp_server.py # MCP Server 定义 ├── agent_client.py # LangChain Agent 客户端 ├── deepseek_agent.py # DeepSeek + MCP 示例 └── requirements.txt # 依赖清单

3. 核心原理拆解

3.1 Agent 调用工具的本质

一个 Agent 调用工具,本质上是在“模型推理”和“外部执行”之间循环。以 ReAct 范式为例,完整的循环是:

  1. 用户输入问题。
  2. 模型根据当前对话内容和可用工具的描述,决定下一步动作。
  3. 如果模型认为需要调用工具,就输出一个结构化动作,包含工具名和参数。
  4. 框架执行对应工具,并把执行结果返回给模型。
  5. 模型根据工具结果继续推理,可能再次调用工具,也可能直接输出最终答案。

在这个过程中,模型的“工具感知”完全依赖工具的描述信息。工具名、参数说明、返回值格式写得越清晰,模型就越不容易调用错。这也是为什么在 MCP Server 里,tool 的 docstring 和参数注解非常重要。

3.2 MCP 协议的核心模型

MCP 采用客户端—服务器架构,涉及三个角色:

  • Host:宿主程序,通常就是用户正在使用的 AI 应用,比如 Claude Desktop、Claude Code,或者你自己开发的 Agent 程序。
  • Client:Host 内部的连接组件,负责与 Server 建立会话、发起请求。
  • Server:能力提供方,暴露工具、资源、提示词。

通信层支持两种传输方式:

  • stdio:Server 作为子进程启动,和客户端之间通过标准输入输出通信,适合本地开发。
  • Streamable HTTP:Server 作为一个 HTTP 服务运行,客户端通过网络请求调用,适合远程部署。

在 LangChain 集成中,两种方式都支持。本文的示例先走 stdio,因为最简单;后面会给出远程 Mode 的思路。

3.3 MCP 与 Function Calling 的区别

很多读者会问:我直接用 Function Calling 不就行了吗?为什么要引入 MCP?

两者的定位并不冲突。Function Calling 是模型的一种输出能力,它解决的是“模型如何表达调用意图”的问题,但表达之后,谁来解析、谁来执行、执行结果如何传回,每个框架都不一样。MCP 解决的是“工具能力如何标准化暴露和发现”的问题。

换句话说,Function Calling 是模型侧的功能,而 MCP 是工具侧的协议。用 MCP Server 暴露工具之后,到了执行层仍然需要底层模型具备 Function Calling 能力,只是框架层面的适配被统一了。

3.4 MCP Server 中 Tool 的定义方式

使用 FastMCP 框架,定义一个工具非常简单:只需要在函数上加上装饰器,并写清楚 docstring 和类型注解。FastMCP 会根据函数的签名自动生成工具的描述信息,包括参数的 JSON Schema。

from fastmcp import FastMCP mcp = FastMCP("demo-server") @mcp.tool() def get_order_status(order_id: str) -> str: """查询订单状态 Args: order_id: 订单号 """ # 这里只是示例,实际项目中替换为真实业务逻辑 orders = { "1001": "已发货", "1002": "待支付", "1003": "已完成", } return orders.get(order_id, "订单不存在")

工具注册好之后,MCP Server 会在握手阶段把所有工具列表返还给客户端,客户端再把这些工具交给模型供其决策。

4. 完整实战:手写 MCP Server 并接入 LangChain Agent

4.1 创建 MCP Server

我们写一个简单的“订单查询 + 天气查询”服务,虽然业务逻辑是模拟的,但完整覆盖了 MCP Server 的注册、启动、与客户端交互的关键步骤。

# 文件路径:mcp_server.py from fastmcp import FastMCP mcp = FastMCP("order-server") @mcp.tool() def get_order_info(order_id: str) -> str: """查询订单基本信息 Args: order_id: 订单号,例如 1001 """ orders = { "1001": "用户A 的订单,金额 199 元,状态:已发货", "1002": "用户B 的订单,金额 59 元,状态:待支付", "1003": "用户C 的订单,金额 899 元,状态:已完成", } return orders.get(order_id, "未查询到该订单") @mcp.tool() def get_weather(city: str) -> str: """查询指定城市的当前天气 Args: city: 城市名称,例如 北京、上海 """ weather_map = { "北京": "晴,25℃", "上海": "多云,28℃", "广州": "雷阵雨,30℃", } return weather_map.get(city, "暂未收录该城市的天气数据") if __name__ == "__main__": mcp.run(transport="stdio")

按 Ctrl+C 结束服务即可。这个文件单独运行不会打印任何业务输出,因为 stdio 模式下它是在等待客户端的握手和数据请求。

4.2 验证 MCP Server 能正常工作

在写客户端之前,可以先用 mcp 官方提供的集成测试方式做一次快速验证。更常见的做法是直接通过 MCP Inspector 调试:

mcp dev mcp_server.py

MCP Inspector 会在浏览器里打开一个调试面板,你可以直接查看 Server 暴露了哪些工具,并手动输入参数进行调用测试。生产开发中这一步非常推荐,它能让你在接入 Agent 之前先确认工具本身没有逻辑错误。

4.3 在 LangChain 中加载 MCP 工具

接下来是整体链路中最关键的一步:使用 langchain-mcp-adapters 连接 MCP Server,并获取工具列表。

这里有两种常见用法:

  • 使用MultiServerMCPClient同时连接多个 MCP Server。
  • 使用load_mcp_tools针对单个 Server 做快速加载。

下面我们以 MultiServerMCPClient 为例,因为在一个真正的 Agent 项目中,通常会有多个 MCP Server 提供不同领域的能力。以 stdio 方式启动时,需要指定命令和参数:

# 文件路径:agent_client.py import asyncio from langchain_mcp_adapters.client import MultiServerMCPClient from langchain_openai import ChatOpenAI from langgraph.prebuilt import create_react_agent async def main(): # 1. 创建 MCP 客户端 async with MultiServerMCPClient( { "order": { "command": "python", "args": ["mcp_server.py"], "transport": "stdio", } } ) as client: # 2. 获取 MCP Server 暴露的工具 tools = client.get_tools() print("===== 可用工具 =====") for tool in tools: print(f"- {tool.name}: {tool.description[:50]}") print("====================\n") # 3. 创建模型实例 model = ChatOpenAI( model="deepseek-chat", api_key="your-api-key", base_url="https://api.deepseek.com", ) # 4. 创建 Agent agent = create_react_agent(model, tools) # 5. 测试对话 result = await agent.ainvoke( {"messages": [{"role": "user", "content": "订单1001现在是什么状态?"}]} ) print("===== 回复内容 =====") print(result["messages"][-1].content) if __name__ == "__main__": asyncio.run(main())

4.4 运行与验证

先确保 mcp_server.py 和 agent_client.py 在同一个目录下,然后运行:

python agent_client.py

如果一切正常,你会看到控制台先打印出从 MCP Server 拉取到的工具列表:

===== 可用工具 ===== - get_order_info: 查询订单基本信息 - get_weather: 查询指定城市的当前天气 ==================== ===== 回复内容 ===== 订单 1001 当前状态为:已发货。该订单属于用户A,金额为199元。

到这里,一条完整的链路已经跑通了:

用户问题 → DeepSeek 模型 → 判断需要调用工具 → LangChain Agent → langchain-mcp-adapters → MCP Server → 返回结果 → 模型组织最终回答

4.5 远程 MCP Server 怎么连

除了本地 stdio 方式,MCP Server 也可以作为一个 HTTP 服务启动,部署在远程服务器上。FastMCP 只需切换 transport 即可:

# 远程部署模式 if __name__ == "__main__": mcp.run(transport="http", host="0.0.0.0", port=8000)

客户端连接方式需要调整:

async with MultiServerMCPClient( { "order": { "url": "http://localhost:8000/mcp", "transport": "streamable-http", } } ) as client: tools = client.get_tools()

需要说明的是,不同版本的 langchain-mcp-adapters 对远程 HTTP 传输的参数写法可能有差异。如果你的版本不识别transport参数,请以对应版本文档为准。远程部署时还需要考虑鉴权、HTTPS、超时设置等问题,建议先在本地跑通再部署到线上。

5. 实战进阶:DeepSeek 接入与 Claude Code 配置

5.1 DeepSeek API 的基础调用方式

DeepSeek 的 API 采用了 OpenAI 兼容格式,这是它接入 LangChain 很方便的原因。

在 LangChain 中,不需要额外安装 deepseek 专用包,直接用 ChatOpenAI 并指定 base_url 即可。核心参数有三个:

  • model:模型名称,常用的是 deepseek-chat 和 deepseek-reasoner。
  • api_key:从 DeepSeek 开放平台申请。
  • base_url:https://api.deepseek.com

一个最小调用示例如下:

from langchain_openai import ChatOpenAI model = ChatOpenAI( model="deepseek-chat", api_key="your-api-key", base_url="https://api.deepseek.com", ) resp = model.invoke("你好,请介绍一下你自己") print(resp.content)

在本文的 Agent 示例中,DeepSeek 扮演的是“决策大脑”的角色:它负责理解用户意图、决定是否调用 MCP 工具、解析工具返回的结果。因为 Agent 循环需要多次调用模型,所以建议把超时时间和最大重试次数配置得合理一些。

5.2 使用 DeepSeek 的实用建议

在实际项目里,把 DeepSeek 接进 Agent 时建议考虑以下几点:

第一,system prompt 要写清楚工具使用的边界。比如“查询订单信息时,必须优先使用 get_order_info 工具”“如果工具返回‘未查询到’,不要编造订单状态”。在 Agent 应用中,模型幻觉的风险依然存在,尤其是工具返回空结果时,模型倾向于凭想象补全答案。

第二,deepseek-reasoner 适合需要深度推理的场景,但在 Agent 循环中它的响应时间更长、token 消耗也更大。如果只是做工具调用,deepseek-chat 往往性价比更高。

第三,为了节约 API 调用,可以在 prompt 里要求模型只在必要时调用工具。对于简单问候,不需要走工具链路。

5.3 Claude Code 如何配置 MCP

Claude Code 是 Anthropic 推出的命令行 AI 编程助手,它支持配置 MCP Server。安装好 Claude Code 之后,可以通过 MCP 相关命令来添加工具。常见的命令格式是:

claude mcp add demo-server -- python mcp_server.py

执行后在 Claude Code 会话中,你就可以直接让 AI 使用这个 MCP Server 暴露的工具。

这里要提醒一点:Claude Code 的 CLI 版本更新非常频繁,MCP 命令的参数格式在过去几次版本中都有调整。如果你使用的版本提示命令不存在或参数不合法,优先运行 claude mcp --help 查看当前版本支持的命令。另外,生产项目中不要直接在全局配置里乱加 Server,建议每个 Server 使用独立的配置文件,并在项目级目录下管理。

5.4 关于“无法识别模型”类报错

在配置 Claude Code 接入第三方模型时,可能会遇到类似下面的报错:

"deepseek-v4-pro" is not a model this version of claude code recognizes

这类问题的根本原因通常有两类:

一种是模型名称在当前 Claude Code 版本中还未被内置识别。Claude Code 会对模型白名单做校验,如果录入的模型名不在列表里,就会报错。针对这种情况,需要先确认 Model Name 是否填写正确,再确认 CLI 版本是否需要更新。

另一种是第三方模型的接入方式本身需要额外的兼容配置,而不只是改一个模型名。不同版本的 Claude Code 对第三方模型的环境变量要求不同,建议仔细阅读对应版本的官方配置说明,不要轻易相信社区的“更名大法”。

5.5 VSCode 中配置 Claude Code 的 MCP

很多开发者会把 Claude Code 集成到 VSCode 中使用。基本思路是在 VSCode 的终端里启动 Claude Code,然后在项目根目录维护 MCP 配置文件。当 MCP Server 发生变化时,需要在 Claude Code 中重新加载配置。

到这一步,你已经掌握了 Claude Code 使用 MCP 的最基本流程。更复杂的多 Server 管理、权限控制等能力,需要结合具体项目进一步探索。

6. 常见问题与排查思路

MCP + LangChain 的组合虽然简化了工具接入,但涉及 Agent、协议、模型三层依赖,踩坑点依然很多。下面整理几个高频问题。

问题现象常见原因解决思路
Agent 提示没有可用工具MCP Server 启动失败或握手超时先单独运行 MCP Server,确认没有异常;再通过 MCP Inspector 验证工具列表
模型一直不调用工具工具描述不清晰,或模型不支持 function calling优化工具 name 和 docstring,确认模型参数支持工具调用
工具执行成功但回答不准确工具返回结果被模型忽略检查工具返回格式,尽量返回结构化文本,并在 prompt 中强制要求结合工具结果回答
the agent execution provider did not respond in timeAgent 执行环境超时,模型响应过慢检查模型 API 延迟,适当调大超时时间,必要时更换更快的模型
MCP Server 使用 stdio 时客户端卡住Server 进程输出非协议内容到 stdout确保 Server 中不要随意 print 内容,所有日志走 stderr
远程 MCP 连接失败URL 不正确、端口未开放、鉴权缺失用 curl 或浏览器访问 Server 端点验证联通性
DeepSeek 报模型不存在模型名拼写错误或账号无权限从平台确认实际可用的模型名,不要使用推测的名称

下面针对几个重点问题展开说明。

6.1 模型不调用工具

这是 Agent 开发中最常见的问题。出现这个现象时,可以按顺序排查:

第一步,检查工具是否真的被加载到了 Agent 中。在代码里打印 tools 列表,确认 get_tools() 返回了预期的 Tool 对象。

第二步,检查模型是否支持 Function Calling。目前主流的 OpenAI 兼容模型基本都支持,但一些轻量模型表现不稳定。

第三步,检查工具的 description 是否足够具体。模型是通过描述来判断“什么时候用这个工具”的,如果你写的是“订单工具”,模型根本不知道里面到底是什么逻辑。更合理的写法是:“当用户询问订单状态、订单金额、发货进度时,使用该工具查询订单信息”。

6.2 Agent 循环超时

在 langgraph 的 create_react_agent 中,超时问题通常表现为整个节点长时间没有返回。可能是模型 API 响应慢,也可能是工具本身执行慢。

常用做法有:

  • 给模型配置合理超时,比如 ChatOpenAI 中的 timeout 参数。
  • 在工具函数内部实现自己的超时保护,避免外部服务无响应拖垮整个 Agent。
  • 给 Agent 节点设置最大执行步数,防止模型陷入反复调用工具的循环。

6.3 MCP Client 获取不到工具

如果你确认 MCP Server 本身能跑通,但客户端始终拿不到工具,优先检查两件事:

一是 transport 类型是否匹配。Server 端用的 stdio,客户端却配置成 streamable-http,那一定连不上。

二是 Python 环境是否一致。使用 stdio 方式时,客户端会尝试用python命令启动 Server。如果客户端运行在虚拟环境 A,而命令python指向的是全局环境 B,且 B 中没有安装 fastmcp,Server 就会启动失败。

解决方案是在客户端配置中把 command 写清楚。例如在虚拟环境中可以使用/path/to/.venv/bin/python这样的绝对路径,而不是笼统的 python。

7. 最佳实践与工程建议

7.1 工具设计要“小而专”

一个工具只做一件事,工具名和描述要面向“模型能理解”来写。不要写一个“万能工具”,参数又长又复杂,模型很容易给错参数。比如把“查订单”和“退款”拆成两个工具,就比定义一个带 action 参数的 order_tool 更可靠。

在 MCP Server 中,docstring 的写法直接影响工具描述质量。建议采用以下模板:

@mcp.tool() def cancel_order(order_id: str, reason: str = "") -> str: """取消一个尚未发货的订单 Args: order_id: 需要取消的订单号 reason: 取消原因,可选 """ # 业务逻辑 ...

7.2 日志与错误处理

MCP Server 在 stdio 模式下,所有标准输出都会被协议消息占用,所以日志只能输出到 stderr。你在 Server 内部使用 print 调试时可能不会立刻报错,但会导致客户端解析消息异常。建议统一使用 logging 模块输出到 stderr。

工具函数内部要做好异常捕获,把错误信息转换成模型能读懂的描述。不要直接把 Python traceback 返回给模型,模型会被大量报错信息干扰,正确的做法是返回一句话描述,比如“订单取消失败:订单状态不允许取消”。

7.3 环境变量与密钥管理

在 Agent 项目中,模型 API Key、MCP Server 的访问密钥都属于敏感信息,不要硬编码在代码里。可以使用 .env 文件配合 dotenv 管理,也可以通过 CI/CD 的密钥管理能力注入。

# .env DEEPSEEK_API_KEY=sk-xxxx MCP_SERVER_TOKEN=xxxx

在实际项目中要遵循最小权限原则:Agent 能访问的工具范围必须控制,不是所有工具都应该暴露给所有用户。尤其是在涉及支付、退款、删除类操作时,必须在上层做鉴权和二次确认。

7.4 LangGraph 状态与可观测性

相比简单的 AgentExecutor,LangGraph 最大的优势是状态可观测。你可以给 Agent 加上节点级别的日志,打印每次模型输出和工具调用结果,这样定位“模型为什么答错”会容易很多。生产环境建议把工具调用的入参和出参记录到日志平台,方便后续分析和审计。

7.5 多 MCP Server 的隔离管理

当一个项目需要连接多个 MCP Server 时,不要把所有工具一股脑塞给 Agent。工具越多,模型选择错误工具的概率越大。建议按 Domain 拆分组,比如“订单域一组”“用户域一组”,然后根据具体任务决定加载哪些组。LangChain 的 MultiServerMCPClient 天然支持这种隔离方式,每个 Server 对应一个命名空间。

8. 总结与学习路线

写完这个 Demo,你已经完整走过了 MCP Server 开发、LangChain Tool 加载、Agent 编排、第三方模型接入、客户端配置这几条核心路径。回顾一下,本文的价值不在于那几十行代码,而在于把 MCP 放进了一个真实的 Agent 体系中,让你知道每一步发生在协议层的哪个位置。

如果你接下来要继续深入,建议按这个顺序学习:

第一,把 MCP Server 接入真实业务系统。替换订单查询里的模拟数据,接入数据库或后端 API,试试鉴权、超时、错误恢复这些真实场景。

第二,深入研究 LangGraph 的复杂编排。create_react_agent 只是起点,生产中会遇到多轮工具调用、条件分支、状态持久化等问题,这些都需要对 LangGraph 的图结构有更深入的理解。

第三,对比不同 Agent 框架的设计取舍。你可以在 LangChain、Claude Code、自研 Agent 框架中各自接入同一个 MCP Server,体会协议带来的“一次开发、多处复用”这一核心价值。

最后分享一个落地经验:在把 Agent 接入线上系统之前,一定要先为每个工具写好边界说明和失败预案。Agent 的能力上限由模型决定,但可靠性下限由工具设计和异常处理决定。把工具这层做扎实了,后续换模型、加能力都会轻松很多。如果这篇文章对你有帮助,欢迎收藏备用,也欢迎在评论区聊聊你在 MCP 接入过程中遇到的具体问题。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询