上一篇已经使用 FastMCP 实现了一个城市旅行 MCP Server,其中包含 Tool、Resource 和 Prompt,并分别验证了 stdio、Streamable HTTP 和旧 HTTP+SSE。
这一篇不再通过 python xxx_agent.py 执行一次性 Agent,而是创建两个可以部署到 LangGraph 的 Agent:
http_mcp_agent:通过 Streamable HTTP 调用 MCP。sse_mcp_agent:通过旧 HTTP+SSE 调用 MCP。
启动 langgraph dev 后,可以在 LangGraph Studio 浏览器页面中选择 Agent、输入问题、查看 MCP Tool 调用过程和最终回答。
1. 完整调用链
浏览器中的一次请求会经过下面几个组件:
- 用户在 LangGraph Studio 中输入消息。
- Studio 把消息发送给本地 LangGraph Agent Server。
- Agent Server 运行
http_mcp_agent或sse_mcp_agent。 - Qwen3 根据问题和 Tool Schema 决定调用
calculate_trip_budget。 - LangChain MCP Adapter 将 LangChain Tool 调用转换为 MCP
tools/call。 - FastMCP Server 计算预算并返回结果。
- Qwen3 根据 MCP Resource、MCP Prompt 和 Tool 结果生成最终行程。
- Studio 展示模型消息、Tool 节点、Tool 结果和最终回答。
这里有两个不同的网络服务:
- FastMCP Server 运行在 18100 或 18101 端口,负责提供 MCP 能力。
- LangGraph Agent Server 默认运行在 2024 端口,负责接收浏览器请求并执行 Agent 图。
2. 项目结构
mcp/p03_langchain_mcp_agent/
├── server.py
├── 02_agent_with_http_mcp.py
├── 03_agent_with_sse_mcp.py
├── langgraph.json
├── requirements.txt
└── README.md
本例只保留 HTTP 和 SSE 两个 Agent。server.py 从 p02 复制而来,因此 p03 可以独立运行。
3. MCP Server
server.py 同时提供 Tool、Resource 和 Prompt:
"""定义一个简单的 FastMCP Server。
MCP 服务端对外暴露三类能力:
- Tool:可被 LLM / Client 调用的函数(如计算预算)
- Resource:可被读取的静态或动态资料(如城市介绍)
- Prompt:预置的提示词模板(如行程规划指令)
本示例用 FastMCP 装饰器注册能力,再分别通过 stdio / HTTP / SSE 传输。
"""
from fastmcp import FastMCP
# 第 1 步:创建 FastMCP 实例。
# name 和 instructions 会出现在 MCP 协议握手信息中,供 Client 识别服务用途。
mcp = FastMCP(
name="city-trip-mcp-server",
instructions="提供城市资料、旅行预算计算和行程规划提示词。",
)
# 演示用内存数据;真实项目可替换为数据库或外部 API。
CITY_DATA = {
"杭州": {
"attractions": ["西湖", "灵隐寺"],
"daily_budget": 500,
},
"北京": {
"attractions": ["故宫", "天坛"],
"daily_budget": 600,
},
}
# 第 2 步:注册 Tool —— Client 通过 call_tool 调用。
@mcp.tool
def calculate_trip_budget(city: str, days: int) -> str:
"""计算一个人的旅行预算。"""
city_info = CITY_DATA.get(city)
if city_info is None:
return f"暂时没有 {city} 的预算资料。"
total_budget = city_info["daily_budget"] * days
return f"{city}旅行 {days} 天,预计需要 {total_budget} 元。"
# 第 3 步:注册 Resource —— Client 通过 read_resource 读取。
# 固定 URI,返回服务说明文档。
@mcp.resource("guide://city-trip")
def service_guide() -> str:
"""返回服务使用说明。"""
return "支持杭州和北京,可以查询城市资料、计算预算和生成行程提示词。"
# 带路径参数的 Resource 模板:city://{city}
# FastMCP 会把 URI 中的 {city} 映射为函数参数。
@mcp.resource("city://{city}")
def city_profile(city: str) -> str:
"""根据 URI 中的城市名称返回城市资料。"""
city_info = CITY_DATA.get(city)
if city_info is None:
return f"暂时没有 {city} 的资料。"
attractions = "、".join(city_info["attractions"])
return f"{city}的推荐景点有:{attractions}。"
# 第 4 步:注册 Prompt —— Client 通过 get_prompt 获取消息模板。
# 返回的字符串会被包装成 MCP PromptMessage,供 Agent 直接使用。
@mcp.prompt
def plan_city_trip(city: str, days: int) -> str:
"""生成旅行规划提示词。"""
return (
f"请为我规划一次 {days} 天的{city}旅行。"
f"先读取 city://{city} 资源了解景点,"
"再调用 calculate_trip_budget 工具计算预算。"
)
# 直接运行 server.py 时,默认以 stdio 传输启动(供 Cursor / Claude Desktop 等本地集成)。
if __name__ == "__main__":
mcp.run(transport="stdio", show_banner=False)
4. 创建 Streamable HTTP Agent
LangGraph 可以加载普通的已编译图,也可以加载返回图的工厂函数。因为 MCP Client 的加载方法是异步的,所以这里定义异步 make_graph()。
02_agent_with_http_mcp.py:
"""创建通过 Streamable HTTP 调用 MCP 的 LangGraph Agent。"""
from langchain.agents import create_agent
from langchain_mcp_adapters.client import MultiServerMCPClient
from langchain_openai import ChatOpenAI
async def make_graph():
"""加载 HTTP MCP 能力并返回可部署的 Agent 图。"""
client = MultiServerMCPClient(
{
"travel": {
"transport": "http",
"url": "http://127.0.0.1:18100/mcp",
}
}
)
tools = await client.get_tools()
resources = await client.get_resources("travel", uris=["city://杭州"])
prompt_messages = await client.get_prompt(
"travel",
"plan_city_trip",
arguments={"city": "杭州", "days": "3"},
)
resource_text = resources[0].as_string()
prompt_text = prompt_messages[0].content
model = ChatOpenAI(
model="Qwen3-14B-AWQ-4bit-MLX",
base_url="http://127.0.0.1:18080/v1",
api_key="not-needed",
temperature=0,
max_tokens=512,
)
return create_agent(
model=model,
tools=tools,
system_prompt=(
"你是旅行助手。回答旅行规划问题前必须调用旅行预算工具。\n"
f"MCP Prompt:{prompt_text}\n"
f"MCP Resource:{resource_text}"
),
)
图加载时会完成三件事:
get_tools()将 MCP Tool 转换为 LangChain Tool。get_resources()读取杭州的城市 Resource。get_prompt()获取三日游 Prompt。
Resource 和 Prompt 被放进系统提示词,Tool 则交给 Agent。用户在浏览器中输入问题后,Agent 才会真正调用预算 Tool。
5. 创建旧 HTTP+SSE Agent
SSE Agent 的业务逻辑完全相同,只有 MCP 连接配置不同。
03_agent_with_sse_mcp.py:
"""创建通过旧 HTTP+SSE 调用 MCP 的 LangGraph Agent。"""
from langchain.agents import create_agent
from langchain_mcp_adapters.client import MultiServerMCPClient
from langchain_openai import ChatOpenAI
async def make_graph():
"""加载 SSE MCP 能力并返回可部署的 Agent 图。"""
client = MultiServerMCPClient(
{
"travel": {
"transport": "sse",
"url": "http://127.0.0.1:18101/sse",
}
}
)
tools = await client.get_tools()
resources = await client.get_resources("travel", uris=["city://杭州"])
prompt_messages = await client.get_prompt(
"travel",
"plan_city_trip",
arguments={"city": "杭州", "days": "3"},
)
resource_text = resources[0].as_string()
prompt_text = prompt_messages[0].content
model = ChatOpenAI(
model="Qwen3-14B-AWQ-4bit-MLX",
base_url="http://127.0.0.1:18080/v1",
api_key="not-needed",
temperature=0,
max_tokens=512,
)
return create_agent(
model=model,
tools=tools,
system_prompt=(
"你是旅行助手。回答旅行规划问题前必须调用旅行预算工具。\n"
f"MCP Prompt:{prompt_text}\n"
f"MCP Resource:{resource_text}"
),
)
旧 SSE 端点是 /sse。新项目应该使用 Streamable HTTP,这里保留 SSE Agent 只是为了验证兼容链路。
6. 注册两个 LangGraph
在项目目录中创建 langgraph.json:
{
"dependencies": ["."],
"graphs": {
"http_mcp_agent": "./02_agent_with_http_mcp.py:make_graph",
"sse_mcp_agent": "./03_agent_with_sse_mcp.py:make_graph"
},
"python_version": "3.12"
}
graphs 中的 Key 是 Studio 中显示的图名称,Value 由“Python 文件路径 + 导出变量或函数名称”组成。
这里注册的是两个 make_graph 工厂函数。LangGraph 创建 Assistant 时会执行对应函数,并取得函数返回的 Agent 图。
7. 安装 LangGraph CLI
p03 的 requirements.txt 内容如下:
fastmcp==3.2.4
httpx==0.28.1
langchain==1.2.13
langchain-mcp-adapters==0.2.2
langchain-openai==1.1.12
langgraph==1.1.3
langgraph-cli[inmem]==0.4.19
安装:
cd /Users/bianhn/Documents/git/llm-learning
uv pip install \
--python .venv_mcp/bin/python \
-r mcp/p03_langchain_mcp_agent/requirements.txt
uv pip check --python .venv_mcp/bin/python
source .venv_mcp/bin/activate
langgraph-cli[inmem] 提供本地 Agent Server。它使用内存存储,适合开发和浏览器测试,不是生产部署方案。
8. 启动所有服务
8.1 启动 Qwen3
首先启动本地模型服务:
source .venv_tool_server/bin/activate
"$VIRTUAL_ENV/bin/python" -m mlx_lm server \
--model Qwen3-14B-AWQ-4bit-MLX \
--host 127.0.0.1 \
--port 18080 \
--prompt-cache-size 0 \
--chat-template-args '{"enable_thinking": false}'
8.2 启动 Streamable HTTP MCP
新终端执行:
cd /Users/bianhn/Documents/git/llm-learning
source .venv_mcp/bin/activate
fastmcp run mcp/p03_langchain_mcp_agent/server.py \
--transport http \
--host 127.0.0.1 \
--port 18100
如果 p02 的同一个 HTTP Server 已经运行在 18100 端口,可以直接复用。
8.3 启动 HTTP+SSE MCP
再打开一个终端:
cd /Users/bianhn/Documents/git/llm-learning
source .venv_mcp/bin/activate
fastmcp run mcp/p03_langchain_mcp_agent/server.py \
--transport sse \
--host 127.0.0.1 \
--port 18101
8.4 启动 LangGraph Agent Server
必须进入包含 langgraph.json 的目录:
cd /Users/bianhn/Documents/git/llm-learning/mcp/p03_langchain_mcp_agent
source ../../.venv_mcp/bin/activate
langgraph dev \
--host 127.0.0.1 \
--port 2024
启动成功后,终端会显示:
API: http://127.0.0.1:2024
Studio UI: https://smith.langchain.com/studio/?baseUrl=http://127.0.0.1:2024
API Docs: http://127.0.0.1:2024/docs
如果 2024 已经被其他 LangGraph 项目占用,可以换一个端口:
langgraph dev --host 127.0.0.1 --port 2025
Studio URL 中的 baseUrl 也要相应改成 http://127.0.0.1:2025。
9. 在浏览器中测试



10. 总结
本篇完成了两个可在浏览器中测试的 LangGraph Agent:
http_mcp_agent使用 Streamable HTTP MCP。sse_mcp_agent使用旧 HTTP+SSE MCP。- 两个 Agent 在加载时读取相同的 MCP Resource 和 Prompt。
- 浏览器提交消息后,Qwen3 通过 LangChain MCP Tool 调用 FastMCP Server。
- LangGraph Studio 可以查看模型节点、Tool 节点、预算结果和最终回答。
部署结构中要同时区分三层:FastMCP 提供能力,LangGraph 部署 Agent,Studio 提供浏览器交互和调试界面。