十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

MCP协议实战:从零搭建Server并接入LangChain Agent

MCP协议实战:从零搭建Server并接入LangChain Agent MCP 现在是 AI 应用开发里绕不开的协议级技能。如果你已经接触过 LangChain、Agent 或者 Function Calling却还没弄明白 MCP 和它们之间的关系那这篇文章可以帮你把整条链路打通。本文会用一套本地可运行的保姆级示例从零搭建一个 MCP Server再通过 LangChain Agent 调用它完成真实任务全程不依赖 GPU只要电脑能跑 Python 就能复现。文章不会只讲概念。我们先看 MCP 到底解决了什么问题然后用 FastMCP 快速写一个带多个工具的 Server再使用langchain-mcp-adapters把工具加载进 LangChain最后让 Agent 完成一个涉及多次工具调用的完整任务。文末会附上常见报错排查清单、批量任务思路和工程化建议。如果你之后要做的不是玩具 demo而是想接入数据库、内部系统或远程 MCP 服务这部分更有参考价值。如果你之前只写过单个 Function Calling 工具调用那么重点看三件事第一MCP 与 LangChain 的衔接方式第二一个 MCP Server 如何被多个 Agent 复用第三工具从本地 stdio 模式迁移到远程 HTTP 模式需要改哪些代码。1. MCP 核心能力速览能力项说明协议全称Model Context Protocol模型上下文协议发起方Anthropic 发起并开源OpenAI、Google 等生态逐步兼容核心作用统一 AI 应用访问外部工具、数据源和业务流程的标准接口传输方式本地 stdio、远程 Streamable HTTP / SSE 等工具暴露方式Server 注册工具Client 通过 Session 获取工具列表并调用与 LangChain 配合通过langchain-mcp-adapters将 MCP 工具转为 LangChain Tool是否支持多个工具是单个 Server 可注册多个工具是否支持多 Server 接入是一个 Agent 可同时加载多个 MCP Server是否支持远程调用是MCP Server 可部署为独立远程服务语言生态Python、TypeScript / Node.js、Java、Go 等均有官方或社区 SDK典型场景让 Agent 查询数据库、操作文件、调用内部 API、访问知识库这张表先给结论MCP 并不是某个具体框架它是一层协议。LangChain 负责编排 AgentMCP 负责统一工具和数据源的暴露方式。两者不是替代关系而是配合关系。2. 为什么 MCP 会改变 AI 应用开发方式在没有 MCP 之前一个 Agent 要调用三套外部能力通常要写三套逻辑数据库连接写一套、文件读取写一套、内部 API 写一套。每一套都有独立的鉴权、参数格式、错误处理和返回结构。当工具数量增加代码里会出现大量“胶水层”而且这些胶水层几乎无法跨项目复用。换个项目连接逻辑又要重新实现。MCP 把这个问题拆成了标准三层MCP Server 负责暴露工具和数据源MCP Client 负责与 Server 建立会话大模型或 Agent 只负责决策要调用哪个工具。工具的具体实现留在 Server 内部调用方不需要关心它是 Python 写的还是 Node.js 写的也不需要知道它背后连的是 MySQL 还是本地文件。这里要区分两个容易混淆的概念。Function Calling 是一种模型能力它让模型学会输出结构化的工具调用参数MCP 是一种协议它规定工具应该如何被注册、发现和调用。MCP 不改变模型的推理方式但改变了工具的分发方式。你仍然需要模型具备 Function Calling 能力只是工具从哪里来、怎么调用现在由 MCP 统一管理。另一个热门概念是 Agent Skill。Skill 通常偏重“技能包”的封装包含提示词、脚本、校验逻辑MCP 更偏重“工具接口”的标准化。实际项目中两者可以共存MCP Server 提供原子工具Agent 通过编排把这些原子工具组合成复杂的技能。3. 适用场景与使用边界MCP 适合解决这些问题内部工具数量多、接口格式不统一Agent 需要统一调度数据源经常变化希望工具接口与实现解耦多人团队协作不想每个人都写一份连接代码需要把 Agent 能力暴露给多个前端或上层应用。MCP 也适合团队内部做工具复用。你可以先写一个数据库 MCP Server再把文件系统 Server 部署成远程服务业务侧的 Agent 只需要配置 Server 地址就能拿到工具列表不需要关心底层实现。使用边界也要说清楚。MCP 不是用来替代 RAG 的。RAG 解决的是知识检索问题MCP 解决的是工具调用问题。两者经常配合使用RAG 负责从知识库检索上下文MCP 负责把检索结果或外部系统操作暴露给模型。如果项目里已经有稳定的 Function Calling 体系并且没有跨系统复用需求迁移到 MCP 并不紧急。还有一类情况不适合直接用 MCP工具调用逻辑非常简单、只有一两个函数并且不会跨项目复用。这时引入 MCP 反而增加部署成本。从工程角度先判断痛点是否来自“工具接入方式不统一”再决定是否引入 MCP。合规方面需要注意工具会访问本地文件、数据库和内部系统必须确保这些访问是用户明确授权的涉及用户隐私数据时要遵循最小权限原则用 MCP 调用第三方服务时要遵守服务方的使用条款。本地测试也不要随意运行来源不明的 MCP Server 代码尤其是包含eval、exec或危险系统命令的实现。4. 环境准备与前置条件本文示例以 Python 为主操作系统的限制很小。Windows、macOS 和 Linux 都能跑通。推荐使用 Python 3.10 及以上版本MCP 官方 SDK 在其中运行最稳定。如果是在服务器环境Linux 是更常见的选择日常开发调试则不必纠结桌面版还是服务器版能跑 Python 和 Node 就行。先创建项目目录和虚拟环境mkdir mcp-langchain-demo cd mcp-langchain-demo python -m venv .venv source .venv/bin/activateWindows PowerShell 环境下激活命令为.venv\Scripts\activate然后安装依赖pip install --upgrade pip pip install mcp[cli] langchain langchain-openai langchain-mcp-adapters如果安装速度较慢或需要更严格的依赖管理可以直接使用uvuv venv .venv source .venv/bin/activate uv pip install mcp[cli] langchain langchain-openai langchain-mcp-adapters这里需要说明mcp[cli]会安装 MCP 官方 Python SDK并提供mcp命令行工具用来调试 Serverlangchain是 LangChain 核心库langchain-openai让 LangChain 能调用 OpenAI 格式的模型接口langchain-mcp-adapters是 LangChain 官方提供的 MCP 适配层后续加载工具就靠它。如果你使用的是本地模型服务比如 Ollama 或 vLLM只需要把模型客户端的示例地址改成对应的本地服务即可下面的代码结构不用大改。为了示例稳定本文先按 OpenAI 兼容接口来写。5. 搭建一个可运行的 MCP Server在项目根目录创建server.py用 FastMCP 快速实现三个工具获取当前时间、四则运算计算、读取文本文件内容。FastMCP 是 MCP Python SDK 提供的高层封装写法和装饰器风格与 FastAPI 很像上手成本很低。import ast from datetime import datetime from pathlib import Path from mcp.server.fastmcp import FastMCP mcp FastMCP(demo-tools) mcp.tool() def get_current_time() - str: 返回服务器当前本地时间格式为 YYYY-MM-DD HH:MM:SS。 return datetime.now().strftime(%Y-%m-%d %H:%M:%S) mcp.tool() def calculator(expression: str) - str: 计算四则运算表达式例如 12 * 3 5。 注意本函数仅用于本地教学演示不要直接用于生产环境。 tree ast.parse(expression, modeeval) result eval(compile(tree, expr, eval)) return str(result) mcp.tool() def read_text_file(filepath: str) - str: 读取一个文本文件的内容并返回。 参数 filepath 必须是绝对路径并且只能读取项目目录内的文件。 path Path(filepath).resolve() project_root Path(__file__).parent.resolve() if not str(path).startswith(str(project_root)): return Error: 路径超出允许访问范围 if not path.exists(): return Error: 文件不存在 return path.read_text(encodingutf-8) if __name__ __main__: mcp.run()这里有一个重要的设计点read_text_file做了目录白名单校验限制只能读取项目根目录下的文件。在开发本地 MCP Server 时文件访问一定要做路径校验避免 Agent 在模型误导或提示词注入的情况下读取任意系统文件。calculator中的eval也存在安全风险仅限本机实验使用不能直接发布到不受信任的网络环境。启动 Server 并不需要直接运行这个文件。因为默认传输方式是 stdioServer 是作为子进程被 MCP Client 启动的。我们可以用 MCP 官方调试命令单独验证mcp dev server.py这个命令会启动一个本地调试面板自动列出 Server 注册的工具并允许手动调用。如果一切正常能看到get_current_time、calculator、read_text_file三个工具。如果不想用官方调试面板也可以写一个最小的 MCP Client 来验证。但更方便的方式是直接进入下一节让 LangChain 帮我们加载工具并测试。6. 使用 LangChain 连接 MCP 工具现在创建agent_demo.py把刚才的server.py作为 stdio 子进程启动并将 MCP 工具加载为 LangChain 的 Tool。import asyncio from langchain.agents import create_agent from langchain_mcp_adapters.tools import load_mcp_tools from langchain_openai import ChatOpenAI from mcp import ClientSession, StdioServerParameters from mcp.client.stdio import stdio_client server_params StdioServerParameters( commandpython, args[server.py], ) async def main(): model ChatOpenAI( modelgpt-4o, temperature0, ) async with stdio_client(server_params) as (read, write): async with ClientSession(read, write) as session: tools await load_mcp_tools(session) print(成功加载工具:) for tool in tools: print(f - {tool.name}) agent create_agent( modelmodel, toolstools, prompt你是本地助手可以调用 MCP 工具完成任务。, ) response await agent.ainvoke({ messages: [ { role: user, content: 现在是什么时间顺便计算一下 12 * 3 5 的结果。, } ] }) print(最终回答:) print(response[messages][-1].content) if __name__ __main__: asyncio.run(main())运行前需要配置模型接口的环境变量。这里以 OpenAI 兼容接口为例export OPENAI_API_KEY你的密钥 export OPENAI_BASE_URLhttps://api.openai.com/v1如果使用本地模型例如 Ollama可以在代码中替换为model ChatOpenAI( modelqwen2.5, temperature0, base_urlhttp://127.0.0.1:11434/v1, api_keyollama, )不同本地服务的模型名称和端口需要按实际环境调整。运行脚本python agent_demo.py预期输出会分成两部分第一部分打印出从 MCP Server 加载的三个工具名称第二部分是 Agent 的最终回答内容应该包含当前时间和计算结果。如果 Agent 没有自动调用工具可以检查模型是否开启了工具调用能力或者换个更强的模型再试。这段代码的关键点是load_mcp_tools它会与 MCP Server 建立会话然后把 Server 暴露的工具转换成 LangChain 可以直接使用的 Tool 对象。从此之后这些工具和 LangChain 原生工具没有任何使用差异Agent 可以像使用普通工具一样调度它们。7. LangChain Agent 多轮任务与多 Server 接入上一节的示例只能调用一个 MCP Server。实际项目经常需要同时访问文件系统、数据库、外部 API 等多个数据源。解决方案是同时启动多个 MCP Server Session再把工具列表合并起来交给 Agent。下面这个示例演示如何同时加载两个 MCP Server。先在项目根目录创建db_server.pyfrom mcp.server.fastmcp import FastMCP mcp FastMCP(fake-db-server) FAKE_USER { id: 1, name: 张三, role: 后端工程师, } mcp.tool() def get_user_info(user_id: int) - str: 根据用户 ID 返回用户信息。当前仅支持 id1 的演示数据。 if user_id ! FAKE_USER[id]: return 未找到该用户 return f用户: {FAKE_USER[name]}, 角色: {FAKE_USER[role]} if __name__ __main__: mcp.run()然后创建multi_server_demo.pyimport asyncio from langchain.agents import create_agent from langchain_mcp_adapters.tools import load_mcp_tools from langchain_openai import ChatOpenAI from mcp import ClientSession, StdioServerParameters from mcp.client.stdio import stdio_client server_file_params StdioServerParameters( commandpython, args[server.py], ) server_db_params StdioServerParameters( commandpython, args[db_server.py], ) async def main(): model ChatOpenAI(modelgpt-4o, temperature0) async with stdio_client(server_file_params) as (rf, wf): async with ClientSession(rf, wf) as session_file: file_tools await load_mcp_tools(session_file) async with stdio_client(server_db_params) as (rd, wd): async with ClientSession(rd, wd) as session_db: db_tools await load_mcp_tools(session_db) tools file_tools db_tools print(合并后的工具列表:) for tool in tools: print(f - {tool.name}) agent create_agent( modelmodel, toolstools, prompt你可以使用 MCP 工具查询文件和信息。, ) response await agent.ainvoke({ messages: [ { role: user, content: 读取 project_info.txt 文件内容并查询用户 ID 为 1 的用户信息最后一句话总结两者的关系。, } ] }) print(最终回答:) print(response[messages][-1].content) if __name__ __main__: asyncio.run(main())在项目根目录创建测试文件project_info.txt项目状态开发中 技术栈Python LangChain MCP运行后Agent 需要先调用read_text_file读取文件再调用get_user_info查询用户信息最后整合答案。这就是一次典型的多工具多轮 Agent 任务。嵌套的async with虽然看起来层级较深但这是为了让所有 Session 在 Agent 执行期间保持存活。如果提前退出 Session 上下文工具调用就会失败。因此必须保证 Agent 的调用发生在所有 Session 上下文内部。8. 远程 MCP Server 与批量任务方向本地 stdio 模式适合开发调试生产环境更常见的是把 MCP Server 部署为远程服务。FastMCP 支持通过streamable-http传输方式启动远程 Server。在server.py的入口改为if __name__ __main__: mcp.run(transportstreamable-http)启动后Server 会监听 HTTP 端口具体的端口和路径以 FastMCP 版本输出为准。这样其他机器上的 Agent 就可以通过 HTTP 方式连接from mcp.client.streamable_http import streamablehttp_client async with streamablehttp_client(http://127.0.0.1:8000/mcp) as (read, write): async with ClientSession(read, write) as session: tools await load_mcp_tools(session)远程模式下认证和网络访问控制变得非常重要。生产环境至少要加上 API Key 或 OAuth 鉴权并用反向代理限制访问来源。MCP Server 暴露的任何工具都可能被外部调用必须在 Server 内部做权限校验。批量任务方面MCP 本身不提供任务队列但 Agent 层可以自己实现。使用asyncio.gather可以并发执行多个独立任务async def run_task(agent, task_text): response await agent.ainvoke({ messages: [{role: user, content: task_text}] }) return response[messages][-1].content async def batch_run(agent, tasks): results await asyncio.gather( *[run_task(agent, task) for task in tasks] ) return results并发执行有几个前提MCP Server 的底层依赖要支持并发调用比如数据库连接池足够大工具本身不能有共享的可变状态模型接口要有足够的并发配额。如果不确定先用单线程循环批量执行再根据耗时决定是否需要并发。批量任务一定要加日志和失败重试。建议在设计批量流程时每条任务记录输入文本、输出结果、模型 token 消耗、调用耗时和错误信息。这样出现问题才能快速定位。9. 常见问题与排查方法问题现象可能原因排查方式解决方案load_mcp_tools加载不到任何工具MCP Server 未正确注册工具或启动失败检查 Agent 运行时日志确认 server.py 的 stdio 是否正常输出先用mcp dev server.py单独测 Server工具加载成功但 Agent 不调用模型不支持工具调用或 prompt 没有引导换支持 Function Calling 的模型或检查 prompt 是否允许调用工具使用最新版 gpt-4o 或 Claude 系列模型报错ModuleNotFoundError: mcp依赖没有安装到当前虚拟环境执行 pip listgrep mcp 确认版本stdio 模式启动后直接卡住本机 Python 路径在子进程中不一致检查StdioServerParameters中的 command 配置在 Windows 上尝试commandpython在 Linux 上尝试commandpython3远程 MCP 连接超时网络不通、CORS 未配置、鉴权失败查看服务端日志用 curl 测试 HTTP 端点确认端口开放和反向代理配置Agent 调用工具后返回解析错误工具返回格式不是纯文本模型无法理解在工具返回值中追加字段说明让每个工具返回结构化的纯文本或 JSON批量任务中某个任务失败导致整体中断asyncio.gather 默认会传递异常使用return_exceptionsTrue或在内部捕获异常为每条任务单独捕获异常并记录日志另外需要留意 Python 版本兼容性。MCP SDK 和 LangChain 的更新频率都比较高如果安装的是不同时期发布的版本可能会出现 API 不兼容。保险做法是在项目里固定关键依赖版本或使用uv锁定依赖树。10. 最佳实践与使用建议第一MCP Server 的工具数量不要贪多。每个工具都会占用模型的部分上下文窗口工具过多会导致模型选择困难。建议一个 Server 聚焦一类能力比如文件操作一个 Server、数据库一个 Server、外部 API 一个 Server。工具命名要包含动词描述要写清楚参数含义和返回值格式。模型没有“看代码”的能力它只能通过工具名和描述来决策。第二所有 MCP 工具要做输入校验。本文中read_text_file的路径白名单就是典型做法。其他场景下SQL 工具要限制只读查询文件工具要限制允许访问的目录HTTP 工具要限制允许调用的域名。不要把数据库账号密码、API Key 写进 MCP Server 代码尽量使用环境变量或独立的配置中心。第三Agent 执行过程要留痕。LangChain 的消息列表中会保留工具调用链建议在日志里输出每一步的思考过程、工具入参和返回结果。出现问题时这些日志是定位根因的唯一线索。第四调优顺序是先小后大。第一次接入 MCP Server先只注册一个工具并跑通全链路确认无误后再添加第二个工具。如果一开始就注册十个工具出了问题很难判断是 Agent 决策问题还是 MCP 连接问题。同样批量任务先跑 10 条再逐步扩展到 100 条、1000 条。第五关注安全合规。任何 MCP 工具都可能被 Agent 调用而 Agent 的行为可能受到用户输入的间接影响。提示词注入是一个真实风险当 Agent 把外部文本作为输入时文本中可能带着恶意指令诱导模型调用危险的 MCP 工具。对于能改写数据或操作系统的工具在执行前必须增加人工确认环节或通过权限系统做二次校验。11. 总结与下一步MCP 在 2026 年的 AI 开发生态里已经不是“新技术”而是基础设施。它统一了工具接入方式让 Agent 不需要关心底层实现也让工具可以在不同 AI 应用之间复用。本文从零搭建了一个本地 MCP Server演示了如何用langchain-mcp-adapters把 MCP 工具加载进 LangChain并通过 Agent 完成了多工具多轮任务最后扩展到多 Server 接入、远程部署和批量任务方向。建议你先跑通第 5 节和第 6 节的完整示例这是整个链路的最小验证单元。然后把自己最常用的一个内部 API 改造成 MCP Server用 Agent 调用一次体会工具从“代码里写死”到“运行时动态加载”的差别。最容易踩的坑基本集中在依赖版本、stdio 子进程启动和模型工具调用能力这三处遇到问题先按第 9 节的表格排查。后面可以继续深入 LangGraph 做复杂编排或者研究 MCP Server 的远程部署和鉴权机制这两条路都是生产级 AI 应用开发常用的方向。
返回列表