LangGraph + MCP(Model Context Protocol)完整讲解

1. 引言

随着大语言模型(LLM)应用从「单次问答」走向「复杂多步任务」,开发者面临两个核心挑战:如何让模型可靠地编排多个步骤,以及如何让模型安全地接入外部工具与数据。LangGraph 与 MCP(Model Context Protocol)分别从「流程编排」和「工具接入标准化」两个维度给出了答案。

LangGraph 是 LangChain 团队推出的低层级编排框架,它将 Agent 的推理过程建模为一张有向图:节点(Node)负责执行具体逻辑,边(Edge)负责控制流转,从而让开发者对 Agent 的行为拥有细粒度的控制力。MCP 则是由 Anthropic 于 2024 年底开源的一套开放协议,它统一了 LLM 应用与外部工具、数据源之间的交互方式,让「一次接入、处处复用」成为可能。

本文将从一个可运行的示例出发,完整讲解 LangGraph 与 MCP 的核心概念、集成方式与实战落地,帮助你快速上手这套现代 LLM 应用开发组合。

2. 核心概念速览

在动手写代码之前,我们先厘清两个框架各自解决什么问题。

2.1 LangGraph 是什么

LangGraph 的核心思想是「把 Agent 当图来写」。它提供以下关键抽象:

  • State(状态):贯穿整个图执行的共享数据结构,所有节点读写同一份状态。
  • Node(节点):图中的基本执行单元,接收当前状态,返回状态的部分更新。
  • Edge(边):定义节点之间的流转关系,支持条件分支(Conditional Edge)。
  • Checkpointer(检查点):保存每一步执行快照,支持断点续跑、人工介入与时间旅行。

相比 LangChain 早期的 AgentExecutor,LangGraph 让循环、分支、并行、人工审批等复杂控制流变得显式且可控。

2.2 MCP 是什么

MCP(Model Context Protocol)采用客户端-服务器架构,解决「工具接入碎片化」问题:

  • MCP Host:LLM 应用本身(如 Claude Desktop、我们的 LangGraph Agent)。
  • MCP Client:Host 内部与 Server 建立连接的组件。
  • MCP Server:暴露工具、资源与提示词的独立服务,可以是本地进程,也可以是远程 HTTP 服务。

MCP 的价值在于:工具提供方只需实现一次 Server,就能被所有支持 MCP 的 Host 复用;应用方也无需为每个工具定制集成代码。

2.3 两者如何配合

LangGraph 负责「大脑的决策流程」,MCP 负责「手脚的标准化接入」。LangGraph Agent 在某个节点需要调用外部工具时,通过 MCP Client 向 Server 发起请求,拿到结果后写回 State,再决定下一步走向。

3. 环境准备

本文示例使用 Python 3.11+,需要安装以下依赖:

bash 复制代码
pip install langgraph langchain-mcp-adapters mcp

其中 langchain-mcp-adapters 是 LangChain 官方提供的桥接库,它能把 MCP Server 暴露的工具转换为 LangChain 的 Tool 对象,从而无缝接入 LangGraph。

4. 构建一个最简单的 MCP Server

我们先写一个提供「天气查询」与「计算器」两个工具的 MCP Server。新建 weather_server.py

python 复制代码
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("demo-server")


@mcp.tool()
def get_weather(city: str) -> str:
    """查询指定城市的天气情况"""
    # 这里替换为真实天气 API 调用
    return f"{city} 今天晴,气温 22~28℃,微风。"


@mcp.tool()
def add(a: float, b: float) -> float:
    """计算两个数字之和"""
    return a + b


if __name__ == "__main__":
    mcp.run(transport="stdio")

启动该服务:

bash 复制代码
python weather_server.py

此时服务会通过标准输入输出(stdio)等待 MCP Client 的连接。

5. 在 LangGraph 中接入 MCP 工具

接下来我们创建一个 LangGraph Agent,让它通过 MCP 调用上面两个工具。

5.1 创建 MCP Client 并加载工具

python 复制代码
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
from langchain_mcp_adapters.tools import load_mcp_tools
from langchain_openai import ChatOpenAI
from langgraph.prebuilt import create_react_agent

# 1. 配置 MCP Server 的启动参数
server_params = StdioServerParameters(
    command="python",
    args=["weather_server.py"],
)

# 2. 建立会话并加载工具
async with stdio_client(server_params) as (read, write):
    async with ClientSession(read, write) as session:
        await session.initialize()
        tools = await load_mcp_tools(session)

        # 3. 创建 LLM
        llm = ChatOpenAI(model="gpt-4o-mini")

        # 4. 创建 LangGraph Agent
        agent = create_react_agent(llm, tools)

        # 5. 运行
        result = await agent.ainvoke(
            {"messages": [{"role": "user", "content": "北京天气怎么样?顺便算一下 12 加 35。"}]}
        )
        print(result["messages"][-1].content)

运行这段代码,Agent 会自主决定先调用 get_weather 再调用 add,最后汇总答案。

5.2 关键点说明

  • load_mcp_tools 会把 MCP Server 暴露的所有工具一次性加载为 LangChain Tool。
  • create_react_agent 是 LangGraph 预置的 ReAct 风格 Agent,内部自动完成「思考-调用-观察」循环。
  • 整个 MCP 会话生命周期由 async with 管理,确保资源正确释放。

6. 自定义 LangGraph 图:更精细的控制流

预置 Agent 适合快速上手,但真实项目往往需要自定义图结构。下面我们手动构建一个包含「规划-执行-总结」三个阶段的图。

python 复制代码
from typing import TypedDict, Annotated
from langgraph.graph import StateGraph, START, END
from langgraph.checkpoint.memory import InMemorySaver
import operator


class AgentState(TypedDict):
    messages: Annotated[list, operator.add]
    plan: str
    result: str


# 节点 1:规划
def plan_node(state: AgentState) -> dict:
    return {"plan": "先查询天气,再计算数字"}


# 节点 2:执行(调用 MCP 工具)
async def execute_node(state: AgentState) -> dict:
    # 实际项目中这里调用 MCP 工具
    weather = await call_mcp_tool("get_weather", {"city": "北京"})
    total = await call_mcp_tool("add", {"a": 12, "b": 35})
    return {"result": f"{weather};求和结果:{total}"}


# 节点 3:总结
def summarize_node(state: AgentState) -> dict:
    return {"messages": [{"role": "assistant", "content": state["result"]}]}


# 组装图
builder = StateGraph(AgentState)
builder.add_node("plan", plan_node)
builder.add_node("execute", execute_node)
builder.add_node("summarize", summarize_node)

builder.add_edge(START, "plan")
builder.add_edge("plan", "execute")
builder.add_edge("execute", "summarize")
builder.add_edge("summarize", END)

# 启用检查点,支持断点续跑
graph = builder.compile(checkpointer=InMemorySaver())

自定义图的价值在于:你可以精确控制每个节点的输入输出、在任意边加入条件分支、在节点之间插入人工审批,这些能力是预置 Agent 难以直接提供的。

7. 进阶:条件分支与人工介入

7.1 条件分支

当工具调用失败或结果异常时,我们可以让图走不同的路径:

python 复制代码
def should_retry(state: AgentState) -> str:
    if "错误" in state["result"]:
        return "retry"
    return "summarize"


builder.add_conditional_edges(
    "execute",
    should_retry,
    {"retry": "execute", "summarize": "summarize"},
)

7.2 人工审批

在敏感操作(如发送邮件、执行删除)前插入人工确认节点:

python 复制代码
from langgraph.types import interrupt

def human_approval(state: AgentState) -> dict:
    decision = interrupt({"question": "是否允许执行该操作?"})
    return {"approved": decision == "yes"}

当图执行到 interrupt 时,执行会暂停并等待外部输入,恢复后继续流转。这为生产环境提供了关键的安全保障。

8. 完整架构图

下面是 LangGraph + MCP 的整体协作流程:
#mermaid-svg-tuAykIDimHQzHmZM{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-tuAykIDimHQzHmZM .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-tuAykIDimHQzHmZM .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-tuAykIDimHQzHmZM .error-icon{fill:#552222;}#mermaid-svg-tuAykIDimHQzHmZM .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-tuAykIDimHQzHmZM .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-tuAykIDimHQzHmZM .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-tuAykIDimHQzHmZM .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-tuAykIDimHQzHmZM .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-tuAykIDimHQzHmZM .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-tuAykIDimHQzHmZM .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-tuAykIDimHQzHmZM .marker{fill:#333333;stroke:#333333;}#mermaid-svg-tuAykIDimHQzHmZM .marker.cross{stroke:#333333;}#mermaid-svg-tuAykIDimHQzHmZM svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-tuAykIDimHQzHmZM p{margin:0;}#mermaid-svg-tuAykIDimHQzHmZM .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-tuAykIDimHQzHmZM .cluster-label text{fill:#333;}#mermaid-svg-tuAykIDimHQzHmZM .cluster-label span{color:#333;}#mermaid-svg-tuAykIDimHQzHmZM .cluster-label span p{background-color:transparent;}#mermaid-svg-tuAykIDimHQzHmZM .label text,#mermaid-svg-tuAykIDimHQzHmZM span{fill:#333;color:#333;}#mermaid-svg-tuAykIDimHQzHmZM .node rect,#mermaid-svg-tuAykIDimHQzHmZM .node circle,#mermaid-svg-tuAykIDimHQzHmZM .node ellipse,#mermaid-svg-tuAykIDimHQzHmZM .node polygon,#mermaid-svg-tuAykIDimHQzHmZM .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-tuAykIDimHQzHmZM .rough-node .label text,#mermaid-svg-tuAykIDimHQzHmZM .node .label text,#mermaid-svg-tuAykIDimHQzHmZM .image-shape .label,#mermaid-svg-tuAykIDimHQzHmZM .icon-shape .label{text-anchor:middle;}#mermaid-svg-tuAykIDimHQzHmZM .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-tuAykIDimHQzHmZM .rough-node .label,#mermaid-svg-tuAykIDimHQzHmZM .node .label,#mermaid-svg-tuAykIDimHQzHmZM .image-shape .label,#mermaid-svg-tuAykIDimHQzHmZM .icon-shape .label{text-align:center;}#mermaid-svg-tuAykIDimHQzHmZM .node.clickable{cursor:pointer;}#mermaid-svg-tuAykIDimHQzHmZM .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-tuAykIDimHQzHmZM .arrowheadPath{fill:#333333;}#mermaid-svg-tuAykIDimHQzHmZM .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-tuAykIDimHQzHmZM .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-tuAykIDimHQzHmZM .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-tuAykIDimHQzHmZM .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-tuAykIDimHQzHmZM .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-tuAykIDimHQzHmZM .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-tuAykIDimHQzHmZM .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-tuAykIDimHQzHmZM .cluster text{fill:#333;}#mermaid-svg-tuAykIDimHQzHmZM .cluster span{color:#333;}#mermaid-svg-tuAykIDimHQzHmZM div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-tuAykIDimHQzHmZM .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-tuAykIDimHQzHmZM rect.text{fill:none;stroke-width:0;}#mermaid-svg-tuAykIDimHQzHmZM .icon-shape,#mermaid-svg-tuAykIDimHQzHmZM .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-tuAykIDimHQzHmZM .icon-shape p,#mermaid-svg-tuAykIDimHQzHmZM .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-tuAykIDimHQzHmZM .icon-shape .label rect,#mermaid-svg-tuAykIDimHQzHmZM .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-tuAykIDimHQzHmZM .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-tuAykIDimHQzHmZM .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-tuAykIDimHQzHmZM :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 否

用户输入
LangGraph Agent
需要外部工具?
直接生成回复
MCP Client
MCP Server
天气 API / 计算器 / 数据库
最终输出

9. 常见问题与最佳实践

9.1 工具数量过多怎么办

当 MCP Server 暴露的工具超过几十个时,全部塞给 LLM 会显著增加 Token 消耗并降低选择准确率。建议:

  • 按业务域拆分多个 MCP Server,按需加载。
  • 在工具描述中写清楚使用场景与参数含义。
  • 必要时在 LangGraph 中增加「工具路由」节点,先让模型选择工具组,再加载具体工具。

9.2 长任务如何保证可靠性

  • 使用 Checkpointer 持久化状态,任务中断后可恢复。
  • 为关键节点设置超时与重试机制。
  • 对不可逆操作强制加入人工审批节点。

9.3 远程 MCP Server

除了本地 stdio 传输,MCP 还支持 Streamable HTTP 传输,适合部署在服务器上的远程工具服务。只需将 StdioServerParameters 替换为对应的 HTTP 客户端配置即可。

10. 总结

LangGraph 与 MCP 的组合,为 LLM 应用开发提供了一套「可控编排 + 标准接入」的现代范式:

  • LangGraph 让你以图的方式精确控制 Agent 的每一步决策与流转,支持分支、循环、并行与人工介入。
  • MCP 让工具接入标准化,一次实现、处处复用,大幅降低集成成本。
  • 两者结合,既能应对复杂业务逻辑,又能保持工具生态的开放与可扩展。

建议你从本文的天气示例入手,先跑通「MCP Server → LangGraph Agent」的最小闭环,再逐步加入条件分支、人工审批与远程服务,最终构建出适合自己业务的生产级 Agent 应用。

相关推荐
凡泰AI1 小时前
小程序容器技术解析:一个能够同时在多端APP运行同一个小程序的SDK需要关注哪些内容?
开发语言·小程序·mpaas·uni·技术实践
小灰灰搞电子1 小时前
Rust+Slint 实现抽屉式侧边栏源码分享
开发语言·rust·侧边栏
lemon_sjdk1 小时前
JavaFX 源码深度剖析:揭开 StringBinding 的神秘面纱
java·javafx·源码解析·绑定框架
quantdash_cc1 小时前
如何设计高效率的批量股票数据获取程序?QuantDash Python SDK 全市场行情拉取实战指南
开发语言·python·数据分析·量化交易·股票数据·quantdash
我不是程序员三三1 小时前
怎么监控电脑?企业办公终端监控建设实战与合规要点
服务器·数据库·电脑
这个DBA有点耶1 小时前
时间序列数据库选型2026:5款主流产品深度对比与场景适配
大数据·数据库·程序人生·架构·时序数据库·dba·数据库管理员
Jul1en_1 小时前
Matt 与 Uncle Bob 的播客访谈有感
开发语言·经验分享·笔记·ai·开源·github·ai编程
砚底藏山河1 小时前
拉数管道设计:从一次性脚本到可重启的数据流水线(魔码量化实战 #01)
java·数据库·python·金融·maven
玖玥拾1 小时前
Lua 基础语法(五)Unity xLua基础配置与 C# 访问 Lua
开发语言·unity·c#·lua