Skip to main content
Glama

Agentic MCP Itinerary — PoC

一个内部运行 LLM 代理(Gemini Flash + LangGraph)并编排多个下游 MCP 服务器的 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 个简洁的工具,但背后是一个具有记忆、并行扇出(fan-out)和持久状态的代理。


Related MCP server: ts-travel-mcp-server

技术栈

组件

技术

暴露的 MCP 服务器

FastMCP 3.1.1 (streamable-http)

内部代理

LangGraph (StateGraph + 并行扇出)

LLM 模型

Gemini Flash (gemini-2.0-flash)

认证

OAuth 2.1 授权码流程 + JWT HS256

检查点

MemorySaver (内存中,足以用于 PoC)

下游 MCP

官方 MCP SDK (mcp.client.stdio)

模拟数据

3 个 FastMCP 服务器 STDIO(航班、酒店、活动)

部署

Railway (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


在 Railway 上部署

URL

Railway ID

  • 项目: e50da57f-ee0b-47a3-81a3-55556fe6de0d

  • 服务: 09065312-ac84-4876-b9c9-dd5d6439f1d4

  • 环境: 09b3f0c9-e5ad-4f61-b351-275bbcffd5ad

所需环境变量

变量

描述

GEMINI_API_KEY

Google Gemini 的 API 密钥

MCP_USERNAME

OAuth 登录用户名

MCP_PASSWORD

OAuth 登录密码

MCP_JWT_SECRET

用于签署 JWT 的密钥(使用 secrets.token_urlsafe(32) 生成)

MCP_BASE_URL

服务器的公共 URL(用于构建重定向 URI)


认证:OAuth 2.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 (扩展 FastMCP 的 OAuthProvider)

  • JWT HS256,有效期 1 小时

  • 授权码:有效期 5 分钟

  • 支持 PKCE (S256)

  • /health 保持公开,无需认证


配置 Claude Desktop

编辑 ~/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 在不可变环境中的 pip 安装失败

OAuth 2.1 授权码

静态 Bearer 令牌

Claude Desktop 原生支持 OAuth;更具生产就绪性

内存中 JWT HS256

令牌数据库

PoC — 重启后无需持久状态

FastMCP 3.1.1 OAuthProvider

使用 Starlette 手动认证

FastMCP 将流程与 MCP 传输层集成

MemorySaver

SQLite/Redis

足以用于本地 PoC;易于迁移到 SqliteSaver

Gemini Flash

Claude Haiku

Codex 与 Anthropic 的凭据存在冲突


后续步骤 (PoC 之后)

  • [ ] Claude Desktop 测试 — 验证完整的 OAuth 流程

  • [ ] 真实持久化 — 使用 SqliteSaver 或 Postgres 实现重启后的状态保持

  • [ ] 真实的下游 MCP — 将模拟数据替换为真实 API(Amadeus, Booking 等)

  • [ ] 多用户 — 使用用户数据库代替环境变量

  • [ ] 速率限制 — 基于 JWT 令牌

  • [ ] 遥测 — 使用 LangSmith 或类似工具追踪内部代理

Related MCP Connectors

Related MCP Servers