# MCP 旅行规划作业教程

这份教程对应课件最后的作业：使用 LangGraph 构建一个多角色协作旅行规划 Agent，并通过 MCP 动态调用工具，生成包含行程、住宿和景点推荐的个性化旅行方案。

## 你最终要交什么

建议交三部分：

1. 一段说明：解释你的 Agent 架构、MCP 工具来源、每个角色负责什么。
2. 一份运行截图：展示 MCP 工具被发现、Agent 输出最终旅行方案。
3. 代码文件：`travel_mcp_server.py`、`travel_agent_langgraph.py`、`.env.example`、`requirements.txt`。

## 先把 MCP 和 Function Calling 分清

一句话：

- Function Calling 解决的是：模型怎么表达“我想调用哪个工具、参数是什么”。
- MCP 解决的是：工具怎么被发现、怎么被调用、结果怎么通过标准协议返回。

可以把它们放到一条链路里看：

```text
用户提问
→ 大模型判断需要工具
→ Function Calling 生成工具调用意图
→ MCP Client 把这个意图发给 MCP Server
→ MCP Server 真正执行工具
→ 工具结果返回给模型
→ 模型组织自然语言答案
```

所以 MCP 不是 Function Calling 的替代品。它们是上下游协作关系：Function Calling 更靠近模型，MCP 更靠近工具基础设施。

## 本作业的推荐实现路线

因为你还没有注册高德 API Key，第一版不要卡在高德那里。我们先做一个本地模拟旅行 MCP Server：

- `travel_mcp_server.py`：提供交通、酒店、景点、预算 4 个 MCP Tool。
- `travel_agent_langgraph.py`：用 LangGraph 编排 4 个角色：
  - 交通规划师
  - 住宿规划师
  - 景点体验规划师
  - 预算规划师
  - 最后由总规划师汇总

这样能完整体现：

- MCP Server 暴露工具
- MCP Client 动态发现工具
- LangGraph 组织多角色协作
- 大模型根据角色目标调用 MCP 工具

## 第 1 步：安装依赖

在当前目录执行：

```powershell
python -m pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
```

如果你使用 uv：

```powershell
uv pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
```

## 第 2 步：配置大模型 Key

复制 `.env.example` 为 `.env`：

```powershell
Copy-Item .env.example .env
```

然后打开 `.env`，填写：

```text
DEEPSEEK_API_KEY=你的 DeepSeek API Key
```

注意，这里需要的是 DeepSeek 的大模型 Key，不是高德地图 Key。

## 第 3 步：理解本地 MCP Server

打开 `travel_mcp_server.py`。核心是：

```python
mcp = FastMCP(name="travel-tools")
```

然后用：

```python
@mcp.tool()
def search_transport(...):
    ...
```

把普通 Python 函数注册成 MCP Tool。

这个 Server 最后用 stdio 启动：

```python
mcp.run(transport="stdio")
```

stdio 的好处是：不需要你单独打开一个服务窗口，Client 会自动启动它。

## 第 4 步：运行作业主程序

执行：

```powershell
python travel_agent_langgraph.py
```

正常情况下你会先看到：

```text
已从 MCP Server 动态发现工具： ['search_transport', 'search_hotels', ...]
```

这就说明 MCP Client 已经从 Server 拉到了工具列表。

然后程序会输出最终旅行方案。

## 第 5 步：换成你自己的题目

在 `travel_agent_langgraph.py` 里找到：

```python
user_request = (
    "我想从成都出发去重庆玩 3 天 2 晚..."
)
```

你可以改成：

```python
user_request = (
    "我想从上海出发去杭州玩 2 天 1 晚，2 个人，预算 1800 元以内。"
    "喜欢自然风景、拍照和慢节奏城市漫步。"
)
```

如果你换了代码里没有收录的城市，工具会给出通用策略；这不是错误，而是模拟数据不完整。

## 第 6 步：作业说明怎么写

你可以这样写：

```text
本项目实现了一个基于 LangGraph 的多角色旅行规划 Agent。
系统包含交通规划师、住宿规划师、景点体验规划师、预算规划师四个角色，
每个角色都通过 MCP Client 动态获取 travel-tools MCP Server 暴露的工具。

MCP Server 提供 search_transport、search_hotels、recommend_attractions、
estimate_trip_budget 等工具。Agent 不需要在代码里手写工具 schema，
而是在运行时通过 MCP 动态发现工具，再由大模型通过 Function Calling 判断何时调用。

最终，总规划师节点汇总各角色结果，生成包含行程、住宿、景点和预算的个性化旅行方案。
```

## 后续升级：接入高德或 ModelScope MCP

等你注册高德 API Key 后，可以把本地模拟工具替换为高德官方 MCP。

常见的高德 MCP Streamable HTTP 地址格式是：

```text
https://mcp.amap.com/mcp?key=你的高德key
```

如果高德或 ModelScope 服务页面给了不同 endpoint，以服务页面为准。对应配置参考 `travel_agent_amap_example.py`。

老师给的 ModelScope MCP 广场地址是：

```text
https://modelscope.cn/mcp
```

你可以在里面搜索地图、搜索、酒店、火车票等 MCP 服务。如果服务页面提供 SSE 或 HTTP Endpoint，就能放进 `MultiServerMCPClient`。

## 你交作业时可以强调的亮点

- 我没有直接在 Agent 里写死工具，而是通过 MCP 动态发现工具。
- 工具运行在独立 MCP Server 中，Agent 只负责调用。
- LangGraph 把任务拆成多个角色节点，最后统一汇总。
- Function Calling 负责模型的调用决策，MCP 负责工具发现和执行链路。
