LangGraph 集成 MCP 实战:用 TaoToken 统一 Key 打通多工具调用链
1. LangGraph 接 MCP 的真实痛点工具一多Key 就乱LangGraph 做 Agent 编排时最舒服的写法是把「模型推理」和「工具执行」拆成两个节点用tools_condition做条件路由。但一旦工具来源从本地函数变成 MCP 服务问题就来了每个 MCP Server 背后可能挂着不同的模型供应商有的走本地 stdio有的走 streamable-httpKey 分散在.env、config.toml、settings.json三四个地方改一次要翻半天。这篇聚焦的场景很具体你有一个 LangGraph 工作流需要同时接入本地数学工具 MCP 和远程 BMI 计算 MCP并且希望所有模型调用统一走一个 Key不再为每个供应商单独配环境变量。适合已经在写 Agent、被多工具调用链折腾过的开发者。读完你能拿到config.toml和settings.json的可复制骨架、TaoToken 统一 Key 的填写位置以及一次本地调用链的验证动作和预期返回。我试过把 Key 硬编码在ChatDeepSeek(api_key...)里短期能跑但换模型或加工具时就得改代码。下面这套配置把 Key 抽到统一入口LangGraph 只负责编排MCP 只负责暴露工具职责清晰。2. TaoToken 前置统一 Key 与 MCP 配置入口TaoToken 在这里扮演的角色是「模型调用的统一出口」。你不需要在每个 MCP Server 里塞不同的供应商 Key而是让 LangGraph 里的 LLM 客户端指向同一个 API 地址和 Key。官网入口在 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 地址是 https://taotoken.net/api 。配置分两层一层是 MCP Server 的注册信息写在config.toml一层是 LangGraph 运行时的模型参数写在settings.json。两层都通过环境变量读取同一个 Key避免明文散落。先看config.toml的骨架它负责声明有哪些 MCP Server、各自用什么 transport# config.toml [llm] base_url https://taotoken.net/api api_key_env TAOTOKEN_API_KEY model deepseek-chat [mcp_servers.math] transport stdio command python args [mcp_servers/math_mcp_server.py] [mcp_servers.bmi] transport streamable_http url http://localhost:8000/mcp再看settings.json它给 LangGraph 运行时提供模型和会话参数{ llm: { base_url: https://taotoken.net/api, api_key: ${TAOTOKEN_API_KEY}, model: deepseek-chat, temperature: 0 }, graph: { thread_id: 1234, checkpointer: memory } }Key 的填写位置只有一个环境变量TAOTOKEN_API_KEY。在 Windows 的 cmd 里可以这样设set TAOTOKEN_API_KEY你的KeyLinux/macOS 用export TAOTOKEN_API_KEY你的Key。这样config.toml和settings.json都引用同一个变量换 Key 只改一处。如果你还没有 Key可以在控制台创建https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 具体 Key 管理在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。注意不要把 Key 直接写进config.toml或提交到 Git。用环境变量引用是底线。3. 可复制配置LangGraph 多 MCP Server 完整骨架这一节给出能直接跑的代码。先准备两个 MCP Server一个本地 stdio一个远程 streamable-http。本地数学 MCPmath_mcp_server.py# math_mcp_server.py from mcp.server.fastmcp import FastMCP mcp FastMCP(Math) mcp.prompt() def system_prompt() - str: return You are an AI assistant, use the tools if needed. mcp.tool() def add(a: int, b: int) - int: Add two numbers return a b mcp.tool() def multiply(a: int, b: int) - int: Multiply two numbers return a * b if __name__ __main__: mcp.run()远程 BMI MCPbmi_mcp_server.py用 streamable-http 启动# bmi_mcp_server.py from mcp.server.fastmcp import FastMCP mcp FastMCP(BMI) mcp.tool() def calculate_bmi(weight: int, height: int) - str: Calculate BMI, height in meters return BMI: str(weight / (height * height)) if __name__ __main__: mcp.run(transportstreamable-http)启动 BMI 服务它会监听 8000 端口python bmi_mcp_server.py看到Uvicorn running on http://127.0.0.1:8000就说明远程 MCP 起来了。接下来是 LangGraph 客户端用MultiServerMCPClient同时挂两个 ServerLLM 走 TaoToken 统一入口# langgraph_mcp_client.py import asyncio import os from typing import Annotated, List from typing_extensions import TypedDict from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder from langchain_mcp_adapters.client import MultiServerMCPClient from langchain_mcp_adapters.prompts import load_mcp_prompt from langchain_mcp_adapters.tools import load_mcp_tools from langchain_openai import ChatOpenAI from langgraph.checkpoint.memory import MemorySaver from langgraph.graph import StateGraph, START, END from langgraph.graph.message import AnyMessage, add_messages from langgraph.prebuilt import tools_condition, ToolNode client MultiServerMCPClient( { math: { command: python, args: [mcp_servers/math_mcp_server.py], transport: stdio, }, bmi: { url: http://localhost:8000/mcp, transport: streamable_http, }, } ) async def create_graph(math_session, bmi_session): llm ChatOpenAI( modeldeepseek-chat, base_urlhttps://taotoken.net/api, api_keyos.environ[TAOTOKEN_API_KEY], ) math_tools await load_mcp_tools(math_session) bmi_tools await load_mcp_tools(bmi_session) tools math_tools bmi_tools llm_with_tool llm.bind_tools(tools) system_prompt await load_mcp_prompt(math_session, system_prompt) prompt_template ChatPromptTemplate.from_messages([ (system, system_prompt[0].content), MessagesPlaceholder(messages), ]) chat_llm prompt_template | llm_with_tool class State(TypedDict): messages: Annotated[List[AnyMessage], add_messages] def chat_node(state: State) - State: state[messages] chat_llm.invoke({messages: state[messages]}) return state graph_builder StateGraph(State) graph_builder.add_node(chat_node, chat_node) graph_builder.add_node(tool_node, ToolNode(toolstools)) graph_builder.add_edge(START, chat_node) graph_builder.add_conditional_edges( chat_node, tools_condition, {tools: tool_node, __end__: END} ) graph_builder.add_edge(tool_node, chat_node) return graph_builder.compile(checkpointerMemorySaver()) async def main(): config {configurable: {thread_id: 1234}} async with client.session(math) as math_session, client.session(bmi) as bmi_session: agent await create_graph(math_session, bmi_session) while True: message input(User: ) response await agent.ainvoke({messages: message}, configconfig) print(AI: response[messages][-1].content) if __name__ __main__: asyncio.run(main())这里的关键点ChatOpenAI的base_url指向 TaoToken APIapi_key从环境变量读。两个 MCP Server 的工具被合并成一个tools列表ToolNode统一执行。load_mcp_prompt从 math session 拿系统提示保证 Agent 知道要用工具。4. 验证请求一次本地调用链的预期返回配置写完后跑一次最小闭环。先确保 BMI 服务在另一个终端运行然后执行客户端python langgraph_mcp_client.py依次输入三个问题观察返回User: 45等于多少 AI: 4 5 等于 9。 User: 3*5 AI: 3 * 5 等于 15。 User: 体重80kg身高1.7mBMI多少 AI: 您的 BMI 值为 27.68。同时 BMI 服务的终端会打印请求日志Processing request of type ListToolsRequest Processing request of type CallToolRequest INFO: 127.0.0.1:56947 - POST /mcp/ HTTP/1.1 200 OK看到CallToolRequest就说明 LangGraph 的tool_node确实调用了远程 MCP 工具。如果只看到ListToolsRequest没有CallToolRequest说明模型没有触发工具调用检查bind_tools是否绑定了合并后的tools列表。验证模型对话是否走通 TaoToken可以单独发一个请求from openai import OpenAI import os client OpenAI( base_urlhttps://taotoken.net/api, api_keyos.environ[TAOTOKEN_API_KEY], ) resp client.chat.completions.create( modeldeepseek-chat, messages[{role: user, content: 只回复OK}], ) print(resp.choices[0].message.content)返回OK就说明 Key 和 API 地址配置正确。这一步能快速排除「是模型没通还是 MCP 没通」的问题。5. 本篇常见错排查报错一ModuleNotFoundError: No module named langchain_mcp_adapters这是适配器包没装。执行pip install langchain-mcp-adapters mcp langgraph langchain-openai注意包名是langchain-mcp-adapters导入时用langchain_mcp_adapters。报错二Connection refused或httpx.ConnectError远程 BMI MCP 没启动或者端口不对。检查bmi_mcp_server.py是否在运行url是否写成http://localhost:8000/mcp。注意末尾的/mcp不能少少了会 404。报错三401 Unauthorized或invalid api keyTAOTOKEN_API_KEY没设或设错。在 cmd 里用echo %TAOTOKEN_API_KEY%确认Linux 用echo $TAOTOKEN_API_KEY。如果 Key 里有特殊字符确保没有多余空格。报错四模型不调用工具直接回答检查llm.bind_tools(tools)里的tools是否是合并后的列表。如果只绑了 math 的工具BMI 问题就不会触发远程调用。另外system_prompt里要明确「use the tools if needed」否则模型可能选择直接算。报错五stdio 路径问题args里的路径建议用相对路径或绝对路径不要在 VSCode 的集成终端里跑路径解析可能不一致。直接在 cmd 或 PowerShell 里执行python langgraph_mcp_client.py。提示如果工具调用链较长可以在chat_node里加日志打印state[messages]观察每一步的 tool_calls 字段。6. 下一步把统一 Key 用到长期编码与 Agent 场景跑通最小闭环后你可以把config.toml和settings.json的骨架直接复制到新项目只改 MCP Server 的注册信息。Key 始终从TAOTOKEN_API_KEY读LangGraph 的 LLM 客户端始终指向 https://taotoken.net/api 。如果你要长期跑编码类 Agent或者需要多轮工具调用的稳定会话可以看 Coding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 里面有各语言 SDK 的配置示例。模型对话调试可以用 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentchatutm_campaignrewrite 快速验证 Key 是否可用。实际用下来把 Key 抽到环境变量、MCP 注册信息抽到config.toml是让 LangGraph 工作流可维护的关键一步。工具越多这个习惯越值钱。

相关新闻

CodeCombat AP CSP 课程《Innovations and Society》活动教程:探究计算对社会的影响与不同群体的技术体验差异

CodeCombat AP CSP 课程《Innovations and Society》活动教程:探究计算对社会的影响与不同群体的技术体验差异

游戏开发教育前端后端 【免费下载链接】codecombat Game for learning how to code. 项目地址: https://gitcode.com/gh_mirrors/co/codecombat 点击查看 免费下载 本文基于 CodeCombat 开源仓库中 AP CSP 课程资料 apcsp-innovations-and-society.md 展开&#xf…

2026/9/25 5:39:30 阅读更多 →
智能轮椅自主导航实战:ROS2底盘控制、传感器融合与避坑指南

智能轮椅自主导航实战:ROS2底盘控制、传感器融合与避坑指南

简介:本资源为基于ROS2框架的智能轮椅自主导航系统完整工程包,面向机器人工程、自动化等专业的毕业设计、课程设计与期末大作业场景,也适合希望入门ROS2自主导航的中级开发者。项目整合传感器、执行器与导航算法,涵盖URDF建模、地…

2026/9/25 5:39:30 阅读更多 →
Atlas 300V Pro 24G上部署YOLOv5:从环境搭建到推理优化全攻略

Atlas 300V Pro 24G上部署YOLOv5:从环境搭建到推理优化全攻略

最近接手一个视频结构化的项目,边缘侧要同时对8路1080p视频做实时目标检测,要求每路不低于20帧,预算又被压得很低。折腾一圈后,最终选了Atlas 300V Pro 24G这张卡,把YOLOv5从PyTorch一路搬到昇腾推理环境。这中间踩了不…

2026/9/25 5:39:30 阅读更多 →

最新新闻

VisiData 列系统深度指南:Column 计算引擎、类型系统与聚合器实战

VisiData 列系统深度指南:Column 计算引擎、类型系统与聚合器实战

数据分析CLI数据可视化 【免费下载链接】visidata A terminal spreadsheet multitool for discovering and arranging data 项目地址: https://gitcode.com/gh_mirrors/vi/visidata 点击查看 免费下载 导读:本文围绕 VisiData 的 Column 体系展开&#…

2026/9/25 6:04:47 阅读更多 →
Plannotator External Annotations API:把外部工具的标注实时推送到活动评审会话

Plannotator External Annotations API:把外部工具的标注实时推送到活动评审会话

【免费下载链接】plannotator Annotate and review coding agent plans and code diffs visually, share with your team, send feedback to agents with one click. 项目地址: https://gitcode.com/gh_mirrors/pl/plannotator 点击查看 免费下载 Plannotator 的 E…

2026/9/25 6:04:47 阅读更多 →
pylibcudf 字符串 API 实战指南:capitalize / title / is_title 的用法与底层原理

pylibcudf 字符串 API 实战指南:capitalize / title / is_title 的用法与底层原理

数据分析数据工程机器学习 【免费下载链接】cudf cuDF - GPU DataFrame Library 项目地址: https://gitcode.com/gh_mirrors/cu/cudf 点击查看 免费下载 cuDF 的 pylibcudf 是 libcudf 的 Cython 绑定层,为 GPU 上的字符串处理提供直接且低开销的 Pyth…

2026/9/25 6:04:47 阅读更多 →
Kubebuilder 项目路线图全景解读:2024–2026 战略规划与源码落地

Kubebuilder 项目路线图全景解读:2024–2026 战略规划与源码落地

开发者工具代码生成CLI云原生后端 【免费下载链接】kubebuilder Kubebuilder - SDK for building Kubernetes APIs using CRDs 项目地址: https://gitcode.com/gh_mirrors/ku/kubebuilder 点击查看 免费下载 本指南以仓库 roadmap/ 目录中的官方路线图文档为核心&a…

2026/9/25 6:04:47 阅读更多 →
Xred木马深度剖析:传播链路、窃密行为与终端应急响应实战

Xred木马深度剖析:传播链路、窃密行为与终端应急响应实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/25 6:04:47 阅读更多 →
Atlas 300V Pro部署YOLO实战:昇腾推理卡模型转换与调优指南

Atlas 300V Pro部署YOLO实战:昇腾推理卡模型转换与调优指南

一块Atlas加速卡,到底算不算“运算加速卡”?这个问题我在不少群里见人问过,尤其是当你说到“atlas 300V 24G”这个型号的时候,很多人第一反应是:24G显存,那是不是类似游戏显卡那样做渲染加速的?…

2026/9/25 6:03:47 阅读更多 →

日新闻

AI元人文:从工具使用到思维重构的深度探索

AI元人文:从工具使用到思维重构的深度探索

最近半年我一直在琢磨一件事:AI元人文到底是什么?说白了,就是“用元视角重新审视人与AI的关系”,也在“探索AI如何反向逼着我们发现自己的思考边界”。标题里的“元探索”,在我看就是一层套一层的追问——当你用AI解决…

2026/9/25 0:00:41 阅读更多 →
Python+CNN车牌识别实战:从数据预处理到模型训练与部署

Python+CNN车牌识别实战:从数据预处理到模型训练与部署

简介:基于Python与卷积神经网络的车牌识别项目,面向计算机视觉初学者及智能交通开发者,目标是帮助用户掌握从数据预处理、模型构建到实际部署的完整流程。压缩包共25个文件,包含jpg/png图像样本、py训练脚本、md说明文档、dat数据…

2026/9/25 0:00:41 阅读更多 →
Vim基础操作全攻略:保存退出、模式切换与高频命令实战

Vim基础操作全攻略:保存退出、模式切换与高频命令实战

1. 项目概述1.1 核心需求解析今天聊聊Vim。写这个题目的原因是:几乎每个后端开发者、运维人员、数据工程师某天都会遇到一个场景——深夜加班,服务器登录界面只有黑底白字,编辑器只有vi/vim,你必须在五分钟内完成一次配置修改并保…

2026/9/25 0:00:41 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/24 14:34:13 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/24 9:10:42 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/24 14:33:56 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/24 12:50:34 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/24 14:33:48 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/24 12:49:17 阅读更多 →