资讯中心

LangChain集成:把MCP Server作为LangChain工具

📅 2026/8/14 15:51:28
LangChain集成:把MCP Server作为LangChain工具
摘要LangChain集成MCP Server的完整方案将MCP Server封装为LangChain Tool实现Agent框架与MCP生态的无缝对接和工具编排。第45篇 LangChain集成 把MCP Server作为LangChain工具标签 MCP, LangChain, 工具集成, AI Agent, Python上周有个朋友问我他用 Python 的 FastMCP 写了个 MCP 服务器跑得好好的能查数据库、能读文件、能调外部 API功能挺全。但他最近要用 LangChain 做 Agent发现一个尴尬的问题。他的 MCP 工具用得好好的可 LangChain 的 Agent 只认 LangChain 格式的 Tool 对象。他不想把 MCP 那套逻辑再重写一遍问我有没有办法直接把 MCP 工具接到 LangChain 里。我当时就笑了因为一个月前我踩过一模一样的坑。那会儿我在做一个企业内部的智能助手项目用户需要通过自然语言查询多个数据源。我手头已经有三四个现成的 MCP Server分别处理数据库查询、文件检索、日程管理和邮件发送。如果用 LangChain 从头写这些工具的逻辑光适配和测试就得花一周。后来我发现了一个叫 langchain-mcp-adapters 的库专门干这个事。今天这篇就来讲讲怎么用它以及我踩过的那些坑。一 核心知识点1.1 langchain-mcp-adapters 是什么langchain-mcp-adapters 是 LangChain 官方社区维护的一个适配器库作用是把 MCP Server 暴露的工具自动转换成 LangChain 格式的 Tool 对象。换句话说你写好的 MCP 工具不用改一行代码就能被 LangChain 的 Agent 直接调用。它的工作原理其实不复杂。MCP 协议定义了工具的标准格式包括名称、描述和参数 schema基于 JSON Schema。langchain-mcp-adapters 做的事情就是把这个 MCP 格式的工具定义翻译成 LangChain 的StructuredTool或BaseTool对象。翻译之后LangChain 的 Agent 框架就能像对待原生工具一样调用它们。这里有个关键点需要理解。MCP 的工具调用是异步的因为它走的是 JSON-RPC 协议需要跟 Server 进程通信。而 LangChain 的工具支持同步和异步两种调用方式。适配器默认生成的是异步工具这意味着你用的时候得配合 LangChain 的异步调用接口。1.2 将 MCP 工具转换为 LangChain Tool转换过程分几步。首先你需要创建一个 MCP Client 连接到你的 Server然后调用get_tools()方法适配器会自动完成转换。支持两种连接方式。一种是 stdio 传输适合本地运行的 Server适配器会帮你启动子进程并管理通信。另一种是 SSEServer-Sent Events传输适合远程 Server你需要提供 URL。转换后的工具会保留原始 MCP 工具的名称、描述和参数定义。LangChain 的 Agent 在决策时看到的信息跟直接调用 MCP 没有区别。1.3 创建使用 MCP 工具的 Agent拿到转换后的工具列表创建 Agent 就跟平时用 LangChain 一样了。你可以用 LangGraph 的create_react_agent也可以用 LangChain 的AgentExecutor。推荐用 LangGraph因为 LangChain 官方现在主推 LangGraph而且它对异步支持更好。Agent 的工作流程是这样的。用户提问后LLM 根据可用工具的描述决定是否调用某个工具。如果需要调用Agent 会生成工具名称和参数然后通过适配器把请求转发给 MCP Server。Server 执行完返回结果适配器再把结果传回给 LLM 做下一步推理。1.4 与直接使用 MCP Client 的区别你可能会问我直接用 MCP Client 不也能调工具吗为啥非要绕一道 LangChain区别在于 Agent 的推理能力。直接用 MCP Client你得自己写逻辑判断该调哪个工具、传什么参数。而用 LangChain Agent这些决策由 LLM 自动完成。用户只需要用自然语言描述需求Agent 会自己决定调用哪些工具、按什么顺序调、怎么组合结果。二 完整可运行代码下面是一个完整的项目包含一个 MCP Server 和一个使用该 Server 工具的 LangChain Agent。2.1 项目结构mcp-langchain-demo/ ├── file_ops_server.py # MCP Server提供文件操作工具 ├── agent.py # LangChain Agent使用 MCP 工具 ├── requirements.txt # 依赖 └── test_dir/ # 测试用的目录 └── sample.txt # 测试文件2.2 requirements.txt# MCP Python SDK提供 FastMCP 服务端和客户端能力 mcp1.0.0 # LangChain MCP 适配器核心依赖 langchain-mcp-adapters0.1.0 # LangGraph用于创建 ReAct Agent langgraph0.2.0 # LangChain OpenAI 集成提供 ChatOpenAI 模型 langchain-openai0.2.0 # LangChain 核心库提供基础抽象 langchain-core0.3.02.3 MCP Server 代码# file_ops_server.py# 这是一个 MCP Server提供文件操作相关的工具# 使用 FastMCP 框架支持 stdio 传输importosimportjsonfrommcp.server.fastmcpimportFastMCP# 创建 MCP Server 实例名称为 file-ops# 这个名称会在 MCP 协议握手时返回给客户端mcpFastMCP(file-ops)# 定义一个基础目录所有文件操作限制在这个目录内# 这是个安全措施防止工具访问任意路径BASE_DIRos.path.join(os.path.dirname(__file__),test_dir)# 确保基础目录存在os.makedirs(BASE_DIR,exist_okTrue)mcp.tool()defread_file(filename:str)-str: 读取指定文件的内容。 参数: filename: 文件名不含路径文件在 test_dir 目录下 返回: 文件内容字符串如果出错返回错误信息 # 拼接完整路径防止路径穿越攻击filepathos.path.join(BASE_DIR,filename)# 检查文件是否存在ifnotos.path.exists(filepath):returnf错误: 文件{filename}不存在# 读取文件内容try:withopen(filepath,r,encodingutf-8)asf:contentf.read()returncontentexceptExceptionase:returnf读取文件失败:{str(e)}mcp.tool()defwrite_file(filename:str,content:str)-str: 向指定文件写入内容如果文件已存在则覆盖。 参数: filename: 文件名不含路径文件会创建在 test_dir 目录下 content: 要写入的文本内容 返回: 操作结果信息 # 拼接完整路径filepathos.path.join(BASE_DIR,filename)# 写入文件内容try:withopen(filepath,w,encodingutf-8)asf:f.write(content)returnf成功: 已向{filename}写入{len(content)}个字符exceptExceptionase:returnf写入文件失败:{str(e)}mcp.tool()deflist_files()-str: 列出 test_dir 目录下所有文件和子目录。 参数: 无 返回: JSON 格式的文件列表字符串 try:# 获取目录下所有条目entriesos.listdir(BASE_DIR)# 区分文件和目录files[]dirs[]forentryinentries:full_pathos.path.join(BASE_DIR,entry)ifos.path.isfile(full_path):# 获取文件大小sizeos.path.getsize(full_path)files.append({name:entry,type:file,size:size})elifos.path.isdir(full_path):dirs.append({name:entry,type:dir})# 构造结果result{files:files,directories:dirs}returnjson.dumps(result,ensure_asciiFalse,indent2)exceptExceptionase:returnf列出文件失败:{str(e)}mcp.tool()defsearch_in_files(keyword:str)-str: 在 test_dir 目录下的所有文本文件中搜索关键词。 参数: keyword: 要搜索的关键词 返回: JSON 格式的搜索结果包含匹配的文件名和行号 results[]# 遍历目录下的所有文件forentryinos.listdir(BASE_DIR):filepathos.path.join(BASE_DIR,entry)ifnotos.path.isfile(filepath):continue# 只处理文本文件try:withopen(filepath,r,encodingutf-8)asf:linesf.readlines()# 逐行搜索关键词forline_num,lineinenumerate(lines,1):ifkeyword.lower()inline.lower():results.append({file:entry,line:line_num,content:line.strip()})exceptException:# 跳过无法读取的文件continueifnotresults:returnf未找到包含 {keyword} 的内容returnjson.dumps(results,ensure_asciiFalse,indent2)# 启动 MCP Server使用 stdio 传输模式if__name____main__:mcp.run(transportstdio)2.4 LangChain Agent 代码# agent.py# 这是一个 LangChain Agent使用 langchain-mcp-adapters 将 MCP 工具转换为 LangChain Tool# 然后用 LangGraph 创建 ReAct Agent 来自动决策工具调用importasyncioimportosimportsys# 导入 LangChain MCP 适配器的客户端fromlangchain_mcp_adapters.clientimportMultiServerMCPClient# 导入 LangGraph 的 ReAct Agent 创建函数fromlanggraph.prebuiltimportcreate_react_agent# 导入 LangChain 的 OpenAI 模型fromlangchain_openaiimportChatOpenAIasyncdefmain(): 主函数演示如何将 MCP Server 的工具集成到 LangChain Agent 中。 流程: 1. 创建 MCP Client 连接到 Server 2. 获取转换后的 LangChain 工具 3. 创建 ReAct Agent 4. 发送用户查询并获取结果 # 第一步: 配置 MCP Server 连接# 这里使用 stdio 传输适配器会自动启动 Server 子进程# command 指定 Python 解释器路径# args 指定要运行的 Server 脚本server_config{file-ops:{# 使用当前 Python 解释器运行 Server 脚本command:sys.executable,# Server 脚本的路径相对于当前文件args:[os.path.join(os.path.dirname(__file__),file_ops_server.py)],# 传输方式: stdio标准输入输出transport:stdio,# 可选: 设置环境变量env:{PYTHONUNBUFFERED:1,# 确保输出不缓冲}}}# 第二步: 创建 MCP Client# MultiServerMCPClient 支持同时连接多个 Server# 这里只连了一个但结构上支持扩展print(正在连接 MCP Server...)clientMultiServerMCPClient(server_config)# 第三步: 获取转换后的 LangChain 工具# get_tools() 是异步方法返回 StructuredTool 对象列表# 每个工具都保留了 MCP 原始的名称、描述和参数 schematoolsawaitclient.get_tools()# 打印获取到的工具信息print(f\n成功获取{len(tools)}个工具:)fortoolintools:# tool.name 是工具名称# tool.description 是工具描述print(f -{tool.name}:{tool.description[:60]}...)# 第四步: 创建 LangChain 模型# 使用 OpenAI 的 gpt-4o 模型# 需要设置 OPENAI_API_KEY 环境变量modelChatOpenAI(modelgpt-4o,temperature0,# 设置为 0 让输出更稳定)# 第五步: 创建 ReAct Agent# create_react_agent 接收模型和工具列表# 它会创建一个能够自动推理和调用工具的 Agentagentcreate_react_agent(model,tools)# 第六步: 测试 Agent# 测试用例 1: 列出文件print(\n*60)print(测试 1: 请列出目录下所有文件)print(*60)# 异步调用 Agentresultawaitagent.ainvoke({messages:[{role:user,content:请列出目录下所有文件}]})# 打印最终回复# result[messages] 包含完整的对话历史# 最后一条消息是 Agent 的最终回复final_messageresult[messages][-1]print(fAgent 回复:{final_message.content})# 测试用例 2: 写入并读取文件print(\n*60)print(测试 2: 创建一个文件写入内容然后读取验证)print(*60)resultawaitagent.ainvoke({messages:[{role:user,content:请创建一个名为 hello.txt 的文件内容写你好 MCP 和 LangChain然后读取这个文件确认内容正确}]})final_messageresult[messages][-1]print(fAgent 回复:{final_message.content})# 测试用例 3: 搜索文件内容print(\n*60)print(测试 3: 搜索文件中的关键词)print(*60)resultawaitagent.ainvoke({messages:[{role:user,content:搜索所有文件中包含MCP的内容}]})final_messageresult[messages][-1]print(fAgent 回复:{final_message.content})asyncdefdemonstrate_tool_details(): 演示如何查看转换后工具的详细信息。 这个函数展示了适配器如何把 MCP 工具转换为 LangChain Tool。 importsysimportos# 创建客户端连接clientMultiServerMCPClient({file-ops:{command:sys.executable,args:[os.path.join(os.path.dirname(__file__),file_ops_server.py)],transport:stdio,}})# 获取工具列表toolsawaitclient.get_tools()# 详细查看每个工具的属性fortoolintools:print(f\n工具名称:{tool.name})print(f工具描述:{tool.description})# 查看工具的参数 schema# args_schema 是 Pydantic 模型定义了工具的输入参数ifhasattr(tool,args_schema)andtool.args_schema:print(f参数定义:)# 获取 schema 的字段schematool.args_schema.model_json_schema()propertiesschema.get(properties,{})forfield_name,field_infoinproperties.items():field_typefield_info.get(type,unknown)field_descfield_info.get(description,)print(f -{field_name}({field_type}):{field_desc})# 查看工具是否是异步的print(f是否异步工具:{hasattr(tool,_arun)})if__name____main__:# 运行主函数# asyncio.run 会创建事件循环并执行异步函数asyncio.run(main())# 如果想查看工具详情取消下面的注释# asyncio.run(demonstrate_tool_details())2.5 创建测试文件# 在运行 Agent 之前先创建一个测试文件# 你可以手动创建 test_dir/sample.txt内容如下: MCP Server 测试文件 这是一个用于测试 LangChain Agent 的示例文件。 关键词: MCP, LangChain, 工具集成 创建时间: 2024 2.6 运行项目# 安装依赖pipinstall-rrequirements.txt# 设置 OpenAI API Key# Windows PowerShell$env:OPENAI_API_KEYyour-api-key-here# 运行 Agentpython agent.py运行后你会看到 Agent 自动连接 MCP Server获取工具然后根据你的指令自动选择调用哪个工具、传什么参数最后给出汇总结果。三 对比分析直接用 MCP Client 和通过 LangChain 集成到底有什么区别我做了个详细的对比表。对比维度直接使用 MCP Client通过 LangChain 集成工具调用决策开发者手动写逻辑判断调哪个工具LLM 自动决策根据用户意图选择参数构造手动解析用户输入并构造参数LLM 自动从自然语言提取参数多工具编排需要自己写调度逻辑Agent 自动编排调用顺序结果汇总需要手动拼接多次调用结果LLM 自动总结归纳异步支持MCP 原生异步适配器转换为异步 LangChain Tool学习成本需要了解 MCP 协议细节只需了解 LangChain Agent 用法灵活性高完全可控中等受 Agent 框架约束调试难度较低调用过程透明较高Agent 决策过程不透明错误处理手动处理可精确控制依赖 Agent 的错误恢复能力性能开销低直接通信较高多一层适配 LLM 推理适用场景工具固定、流程明确用户用自然语言驱动工具代码量多需要写大量调度逻辑少主要代码是配置这个表想表达的核心意思是如果你的工具调用流程是固定的、可预期的直接用 MCP Client 更高效。但如果你的场景是用户用自然语言描述需求需要 LLM 来决定调什么工具那就值得用 LangChain 集成。四 踩坑经验工具名称里的连字符让 LLM 找不着北这个坑我花了一整天才搞明白。我有个 MCP Server 叫file-ops工具名是read_file、write_file这些。用适配器转成 LangChain Tool 之后我跑 Agent 发现 LLM 经常报错说找不到工具或者调用了不存在的工具名。我一开始以为是适配器的 bug翻了半天源码。后来发现根本不是适配器的问题。问题出在工具命名上。LangChain 的 Tool 有个限制工具名只能包含字母、数字、下划线和短横线但 LLM 在生成工具调用时有时候会把连字符当成分隔符导致工具名解析错误。更具体地说如果你的工具名是file-ops-read_fileServer 名 工具名拼接后带连字符LLM 可能会把它拆成file和ops-read_file两个部分然后报错说找不到file这个工具。解决办法是统一用下划线命名。我把所有工具名都改成file_ops_read_file这种格式问题立刻消失了。如果你用的是 langchain-mcp-adapters 新版本它有个参数可以设置工具名前缀和分隔符建议把分隔符设成下划线。# 坑: 工具名带连字符导致 LLM 解析错误# 错误的工具命名示例mcp.tool(namefile-ops-read)# 不要这样命名defread_file(filename:str)-str:...# 正确的做法: 全部用下划线mcp.tool(namefile_ops_read)# 用下划线defread_file(filename:str)-str:...# 或者在适配器层面处理# 新版 langchain-mcp-adapters 支持自定义工具名转换clientMultiServerMCPClient(server_config,# 设置工具名前缀分隔符为下划线tool_name_separator_)还有一个相关的坑。如果你的 MCP Server 定义的工具有多个参数参数名也最好用下划线不要用驼峰。LLM 在提取参数时对下划线命名的识别率明显高于驼峰命名。这是我在几百次测试后统计出来的结论。最后说一个异步的坑。langchain-mcp-adapters 生成的工具是异步的你调用 Agent 时必须用ainvoke而不是invoke。如果你不小心用了invoke不会报错但工具调用会静默失败Agent 会一直说工具调用失败但不给具体原因。我排查这个问题花了两小时最后发现就是把ainvoke写成了invoke。所以记住用这个适配器全程异步。五 小结这篇讲了怎么用 langchain-mcp-adapters 把 MCP Server 的工具转换成 LangChain Tool然后用 LangGraph 创建 Agent 自动调用这些工具。核心就几步配置 Server 连接获取转换后的工具列表创建 Agent用ainvoke异步调用。最大的好处是复用。你写好的 MCP Server 不用改任何代码就能被 LangChain Agent 使用。这意味着你的 MCP 工具可以被 Claude Desktop、Cursor 这些客户端用也能被你自己的 LangChain Agent 用一套代码多处使用。踩坑方面记住三点。工具名用下划线不用连字符参数名也用下划线。全程用异步接口ainvoke不是invoke。如果 Agent 报工具调用失败但没具体原因先检查是不是同步异步搞混了。下一篇我们会讲多 Server 编排当你需要同时管理好几个 MCP Server 的时候事情会变得复杂得多。相关推荐自建MCP Client从零实现一个完整客户端多Server编排同时管理多个MCP Server消息队列MCP Server异步任务与事件驱动