← 返回AI教程
🌐 其他

LangGraph 入门实战(12)--使用MCP

来源:掘金 · 发布于 2026-08-20 20:53:14
LangGraph 入门实战(
LangGraph 调用 Gitee MCP:一个可运行的最小示例 MCP(Model Context Protocol)可以把远程服务提供的能力包装成模型可调用的工具

LangGraph 入门实战(12)--使用MCP

北斗落凡尘 2026-08-20 0 阅读3分钟

LangGraph 调用 Gitee MCP:一个可运行的最小示例

MCP(Model Context Protocol)可以把远程服务提供的能力包装成模型可调用的工具。本例使用 LangGraph 编排 DeepSeek,通过 Gitee 官方 MCP Server 查询仓库信息。

1. 工作流

langgraph_mcp.png

流程很简单:

  1. call_model 让模型判断直接回答,还是调用 Gitee 工具。
  2. tools 节点由 ToolNode 执行 MCP 工具。
  3. tools_condition 根据模型是否产生 tool_calls 决定结束或继续循环。

2. 安装与配置

建议使用 Python 3.10 或更高版本:

cd docs/掘金langgraph12使用mcp
python -m venv .venv
source .venv/bin/activate
python -m pip install -U python-dotenv langgraph langchain-core langchain-deepseek langchain-mcp-adapters pydantic

在 docs/掘金langgraph12使用mcp/.env 中填写两个密钥:

GITEE_ACCESS_TOKEN=你的 Gitee 访问令牌
DEEPSEEK_API_KEY=你的 DeepSeek API Key

Gitee MCP 地址是 https://api.gitee.com/mcp,代码使用 streamable_http 连接,因此不需要在本机启动 MCP Server。

3. 完整代码

将下面代码保存为 index.py(项目中的 docs/掘金langgraph12使用mcp/index.py 已包含同样逻辑):

import asyncio
import os
import sys

from dotenv import load_dotenv
from langchain_core.messages import HumanMessage, SystemMessage
from langchain_deepseek import ChatDeepSeek
from langchain_mcp_adapters.client import MultiServerMCPClient
from langchain_mcp_adapters.sessions import StreamableHttpConnection
from langgraph.graph import END, START, MessagesState, StateGraph
from langgraph.prebuilt import ToolNode, tools_condition
from pydantic import SecretStr

GITEE_MCP_URL = "https://api.gitee.com/mcp"


async def build_graph():
    gitee_token = os.getenv("GITEE_ACCESS_TOKEN")
    if not gitee_token:
        raise RuntimeError("缺少 GITEE_ACCESS_TOKEN,请先配置 Gitee 访问令牌。")

    # 通过流式 HTTP 连接 Gitee 官方 MCP Server。
    connection: StreamableHttpConnection = {
        "transport": "streamable_http",
        "url": GITEE_MCP_URL,
        "headers": {"Authorization": f"Bearer {gitee_token}"},
    }
    client = MultiServerMCPClient({"gitee": connection})
    tools = await client.get_tools()
    if not tools:
        raise RuntimeError("MCP Server 没有返回可用工具。")
    print(f"已从 Gitee MCP Server 加载 {len(tools)} 个工具。")
    print("部分工具:", ", ".join(tool.name for tool in tools[:8]))

    deepseek_api_key = os.getenv("DEEPSEEK_API_KEY")
    if not deepseek_api_key:
        raise RuntimeError("缺少 DEEPSEEK_API_KEY,请先配置 DeepSeek API Key。")
    model = ChatDeepSeek(
        model="deepseek-v4-flash",
        temperature=0,
        base_url="https://api.deepseek.com",
        api_key=SecretStr(deepseek_api_key),
    )
    model_with_tools = model.bind_tools(tools)

    async def call_model(state: MessagesState):
        # 模型读取历史消息,生成普通回答或 tool_calls。
        response = await model_with_tools.ainvoke(state["messages"])
        return {"messages": [response]}

    builder = StateGraph(MessagesState)
    builder.add_node("call_model", call_model)
    builder.add_node("tools", ToolNode(tools))
    builder.add_edge(START, "call_model")
    builder.add_conditional_edges(
        "call_model", tools_condition, {"tools": "tools", END: END}
    )
    builder.add_edge("tools", "call_model")
    return builder.compile()


async def main():
    load_dotenv()
    question = " ".join(sys.argv[1:]).strip()
    if not question:
        question = input("请输入关于 Gitee 的问题:").strip()
    if not question:
        raise RuntimeError("问题不能为空。")

    graph = await build_graph()
    state: MessagesState = {
        "messages": [
            SystemMessage(
                content=(
                    "你是 Gitee 助手。请根据 Gitee MCP 工具返回的真实数据回答,"
                    "不要编造仓库、Issue 或 Pull Request。除非用户明确要求,"
                    "否则只执行读取操作。回答使用简体中文。"
                )
            ),
            HumanMessage(content=question),
        ]
    }
    result = await graph.ainvoke(state)
    print(" 最终回答:")
    result["messages"][-1].pretty_print()


if __name__ == "__main__":
    try:
        asyncio.run(main())
    except (RuntimeError, KeyboardInterrupt) as error:
        print(f" 运行失败:{error}", file=sys.stderr)
        raise SystemExit(1) from error

4. 运行

命令行直接传入问题:

python index.py "请列出我最近更新的 5 个 Gitee 仓库"

也可以不带参数,启动后交互输入。

5. 输出示例

工具列表和仓库内容取决于当前账号,下面是一次成功运行的输出格式:

已从 Gitee MCP Server 加载 8 个工具。
部分工具: list_user_repos, get_user_info, get_repo, list_repo_issues

最终回答:
================================== Ai Message ==================================
你最近更新的 5 个 Gitee 仓库如下:
1. demo-project
2. langgraph-example
3. notes
...

如果密钥没有配置,程序会提前提示 缺少 GITEE_ACCESS_TOKEN 或 缺少 DEEPSEEK_API_KEY,不会把无效请求发送到远程服务。

6. 关键 API

  • MultiServerMCPClient.get_tools():发现 MCP Server 暴露的工具。
  • model.bind_tools(tools):把工具描述交给模型,由模型决定是否调用。
  • ToolNode(tools):实际执行工具调用并生成 ToolMessage。
  • tools_condition:有 tool_calls 时进入工具节点,否则结束图。
  • MessagesState:保存系统、用户、模型和工具消息。

这个模式还可以继续扩展多个 MCP Server、持久化检查点,或在工具节点前加入人工审核。

本系列即将停更,后续我也在学习中