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

流程很简单:
call_model让模型判断直接回答,还是调用 Gitee 工具。tools节点由ToolNode执行 MCP 工具。tools_condition根据模型是否产生tool_calls决定结束或继续循环。
2. 安装与配置
建议使用 Python 3.10 或更高版本:
bash
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 中填写两个密钥:
dotenv
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 已包含同样逻辑):
python
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("\n最终回答:")
result["messages"][-1].pretty_print()
if __name__ == "__main__":
try:
asyncio.run(main())
except (RuntimeError, KeyboardInterrupt) as error:
print(f"\n运行失败:{error}", file=sys.stderr)
raise SystemExit(1) from error
4. 运行
命令行直接传入问题:
bash
python index.py "请列出我最近更新的 5 个 Gitee 仓库"
也可以不带参数,启动后交互输入。
5. 输出示例
工具列表和仓库内容取决于当前账号,下面是一次成功运行的输出格式:
text
已从 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、持久化检查点,或在工具节点前加入人工审核。