Skip to main content
Glama

에이전트 MCP 여정 — 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개의 깔끔한 도구만 보지만, 그 뒤에는 메모리, 병렬 팬아웃, 지속적인 상태를 갖춘 에이전트가 있습니다.


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 Authorization Code Flow + 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 Authorization Code Flow

전체 흐름

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 Authorization Code

정적 Bearer 토큰

Claude Desktop은 네이티브 OAuth를 관리하며, 프로덕션 준비가 더 잘 되어 있음

메모리 내 JWT HS256

토큰 DB

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 등)로 교체

  • [ ] 다중 사용자 — 환경 변수 대신 사용자 DB 사용

  • [ ] 속도 제한 — JWT 토큰별 제한

  • [ ] 텔레메트리 — 내부 에이전트 추적을 위한 LangSmith 등 사용

Related MCP Connectors

Related MCP Servers