代理MCP行程——PoC
一个MCP服务器,内部运行一个LLM代理(Gemini Flash+Langgraph),并协调多个MCP服务器下游。客户端(Claude Desktop,ChatGPT)看到一个干净的界面,在迭代之间保持状态。
概念
Claude Desktop / ChatGPT
│
│ MCP (HTTP/SSE + OAuth 2.1)
▼
┌─────────────────────────────────────┐
│ travel-agent (este repo) │
│ FastMCP server + LangGraph agent │
│ │
│ ┌──────┐ ┌────────┐ ┌──────────┐│
│ │Vuelos│ │Hoteles │ │Actividad.││ ← MCP mocks STDIO
│ └──────┘ └────────┘ └──────────┘│
└─────────────────────────────────────┘为什么这是不同的? 目前还没有公司提供“封装为MCP服务器的垂直代理”。这个POC展示了这种模式:客户只看到4-5个干净的工具,但背后有一个具有内存、并行扇出和持久状态的代理。
______________________________________________________________________
堆栈
| 组件 | 技术 |
|---|---|
| 暴露的MCP服务器 | FastMCP 3.1.1(streamable-http) |
| 内部代理 | LangGraph (StateGraph +平行扇出)。 |
| LLM型号 | 双子座闪光灯(gemini-2.0-flash) |
| Auth | OAuth 2.1授权码流+JWT HS256 |
| 检查点 | MemorySaver (在内存中,足以进行POC) |
| MCP下游 | MCP SDK官方(mcp.client.stdio) |
| MOCKS | 3 FASTMCP服务器STDIO(航班、酒店、活动) |
| 部署 | 铁路(RAILPACK+pyproject.toml) |
______________________________________________________________________
公开工具(公共API)
| 工具 | 参数 | 描述 |
|---|---|---|
create_itinerary | requirements: str | 创建完整的草稿(航班+酒店+平行活动) |
refine_itinerary | itinerary_id: str, change_request: str | 完善现有草案 |
get_itinerary | itinerary_id: str | 恢复当前状态 |
list_itineraries | - | 列出所有活动行程 |
confirm_itinerary | itinerary_id: str | 确认并生成 confirmation_code |
______________________________________________________________________
部署铁路
网址
- 健康: https://travel-agent-production-c1c4.up.railway.app/health
- MCP端点: https://travel-agent-production-c1c4.up.railway.app/mcp
- OAuth元数据: https://travel-agent-production-c1c4.up.railway.app/.well-known/oauth-authorization-server
- 登录表格: https://travel-agent-production-c1c4.up.railway.app/oauth/authorize
ID铁路
- 项目:
e50da57f-ee0b-47a3-81a3-55556fe6de0d - 服务:
09065312-ac84-4876-b9c9-dd5d6439f1d4 - 环境:
09b3f0c9-e5ad-4f61-b351-275bbcffd5ad
所需环境变量
| 变量 | 描述 |
|---|---|
GEMINI_API_KEY | API密钥de Google Gemini |
MCP_USERNAME | OAUTH登录用户 |
MCP_PASSWORD | OAuth登录密码 |
MCP_JWT_SECRET | 签名的秘密 secrets.token_urlsafe(32)) |
MCP_BASE_URL | 服务器的公共URL(用于构建重定向URI) |
______________________________________________________________________
Auth:Auth2.1授权码流
全流程
1. Claude Desktop detecta el MCP server
2. Descubre /.well-known/oauth-authorization-server
3. Redirige al usuario a /authorize
4. El servidor redirige a /oauth/authorize (form de login HTML)
5. Usuario introduce user/pass → POST /oauth/authorize
6. Servidor valida credenciales (MCP_USERNAME / MCP_PASSWORD)
7. Emite auth code → redirect a Claude Desktop
8. Claude Desktop intercambia code → JWT en /token
9. JWT usado como Bearer en todas las llamadas MCP实施
server/auth.py:SimpleOAuthProvider(延伸)OAuthProviderFastMCP)- JWT HS256,1H有效
- 身份验证代码:5分钟验证
- PKCE (S256) 支持
/health未经授权公开
______________________________________________________________________
配置器Claude桌面
编辑 ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"travel-agent": {
"type": "http",
"url": "https://travel-agent-production-c1c4.up.railway.app/mcp"
}
}
}罪 headers -Claude Desktop自动管理OAuth流。第一次,它将打开浏览器进行登录。______________________________________________________________________
地方发展
要求
pip install -e ".[dev]"启动服务器
PYTHONPATH=server MCP_USERNAME=alexguerra MCP_PASSWORD=tu_pass \
MCP_JWT_SECRET=dev_secret python3 server/main.py冒烟测试
PYTHONPATH=server python3 tests/smoke_test.py检查语法
PYTHONPATH=server python3 -m py_compile server/main.py server/auth.py server/agent.py______________________________________________________________________
项目结构
agentic-mcp-itinerary/
├── server/
│ ├── main.py # FastMCP server (4 tools + OAuth + /health)
│ ├── auth.py # SimpleOAuthProvider (OAuth 2.1 + JWT)
│ ├── agent.py # LangGraph graph con fan-out paralelo
│ ├── state.py # ItineraryState TypedDict + checkpointer
│ └── tools/
│ ├── flights.py # Cliente MCP → mock vuelos
│ ├── hotels.py # Cliente MCP → mock hoteles
│ └── activities.py # Cliente MCP → mock actividades
├── mocks/
│ ├── flights_mcp.py # Mock server vuelos (FastMCP STDIO)
│ ├── hotels_mcp.py # Mock server hoteles (FastMCP STDIO)
│ └── activities_mcp.py # Mock server actividades (FastMCP STDIO)
├── tests/
│ └── smoke_test.py # Test end-to-end básico
├── docs/
│ └── OAUTH_PLAN.md # Spec del OAuth (referencia de diseño)
├── pyproject.toml # Deps para RAILPACK
├── railway.toml # Builder=RAILPACK, startCommand
└── claude_desktop_config.json # Config para Claude Desktop (sin Bearer manual)______________________________________________________________________
关键决策历史
| 决定 | 排除的替代方案 | 原因 |
|---|---|---|
| railpack+pyproject.toml | nixpacks | nixpacks在env不变的情况下在pip中失败 |
| OAuth 2.1授权代码 | 静态承载器令牌 | Claude Desktop管理本地OAuth;更多生产-准备就绪 |
| 内存中的JWT HS256 | 令牌DB | POC-重启之间没有持久状态 |
FastMCP 3.1.1 OAuthProvider | Auth Manual with Starlette | FastMCP将Flow与Transport MCP集成 |
MemorySaver | SQLite/Redis | 适用于本地 PoC;轻松迁移到SqliteSaver。 |
| 双子座闪光 | 克劳德俳句 | 法典与人类有证书冲突 |
______________________________________________________________________
下一步(POC后)
- \[ \] 克劳德桌面测试 检查完整的 OAuth 流程
- \[ \] 实际持久性 —
SqliteSaver或在重新启动之间状态的postgres - \[ \] 下游MCP现实 -用真正的API(Amadeus、Booking等)替换Mocks
- \[ \] 多用户 -用户数据库而不是env vars
- \[ \] 速率限制 -通过令牌JWT
- \[ \] 遥测 -Langsmith或类似的内部追踪剂
