Skip to main content
Glama
Timing-Jeju

Timing Jeju FastAPI MCP

by Timing-Jeju

제주 하루 여행 MCP

공식·승인 데이터와 결정론적 검증만으로 제주 하루 일정을 생성하고 평가하는 로컬 stdio MCP 서버입니다. 공개 계약 버전은 0.7.0이며, 성공 시 balanced, relaxed, experience_max 일정 세 개를 모두 반환합니다. 세 개를 만들 수 없으면 부분 결과 없이 insufficient_feasible_routes로 종료합니다.

요구사항

  • Python 3.12 이상

  • uv

  • 격리 통합 테스트 또는 로컬 publication 작업 시 Docker와 Docker Compose

  • 외부 API live 실행 시 승인 source에 대응하는 개별 API key

설치와 기본 검증

uv sync --locked
uv run python scripts/check_korean_test_descriptions.py
uv run ruff check .
uv run pyright
uv run pytest

동일한 순서의 offline gate와 격리 PostGIS·MinIO 테스트가 GitHub Actions에서 PR과 main push마다 실행됩니다.

로컬 MCP 실행

기존 jeju-trip-mcp는 개발자가 환경을 직접 관리하는 수동 실행점입니다. 운영용 read-only DSN과 필요한 API key를 현재 프로세스 환경에만 설정하며, 저장소나 로그에 실제 값을 기록하지 않습니다.

export JEJU_RUNTIME_DSN='postgresql://jeju_runtime:...@127.0.0.1:55432/jeju_trip'
export JEJU_TMAP_API_KEY='...'
export JEJU_TAGO_SERVICE_KEY='...'
uv run jeju-trip-mcp

Codex에는 수동 실행점 대신 jeju-trip-mcp-codex 보안 실행점을 등록합니다. 이 실행점은 저장소 루트의 .env symlink를 최종 대상까지 해석한 뒤 regular file, 현재 사용자 소유, group/other 권한 없음, 64 KiB 이하, UTF-8 조건을 모두 검사합니다. 기본 파일을 바꾸는 JEJU_MCP_ENV_FILE은 테스트·별도 배포에만 사용하며 MCP 서버 환경에는 남기지 않습니다.

파일에서 런타임으로 전달하는 값은 다음 세 개뿐입니다.

  • JEJU_RUNTIME_DSN

  • JEJU_TMAP_API_KEY

  • JEJU_TAGO_SERVICE_KEY

importer/migrator DSN, TourAPI·Holiday, OpenAI, S3/AWS, proxy, PYTHONPATH, Codex 내부 변수와 그 밖의 JEJU_* 값은 전달하지 않습니다. JEJU_RUNTIME_DSN이 importer, migrator 또는 관리자 성격 역할을 가리키거나 필수 세 값이 비어 있으면 종료 코드 78로 fail-closed 합니다. dotenv는 shell로 실행하지 않으며 변수·명령 치환 문법을 거부합니다.

Private Streamable HTTP MCP

Spring worker 연동은 jeju-trip-mcp-http 실행점의 stateless JSON Streamable HTTP /mcp를 사용합니다. stdio와 HTTP는 같은 여섯 도구와 schema checksum을 노출합니다. HTTP launcher는 owner-only .env.http에서 runtime 세 값과 bind, issuer, audience, local JWKS, TLS 인증서·키 경로만 선택합니다. 최대 5분 RS256 JWT에 jeju:mcp:invoke scope와 JTI가 필요합니다.

기본 bind는 127.0.0.1:8000입니다. 컨테이너에서 0.0.0.0을 사용할 때는 public port를 publish하지 않은 private network임을 확인하고 JEJU_MCP_PRIVATE_NETWORK_CONFIRMED=true를 명시해야 합니다. /health/ready는 인증 정보나 provider 상태 원문을 반환하지 않습니다. 배포 예시는 infra/compose.private-http.yml, 운영 상세 계약은 FASTAPI_MCP_CONTRACT.md를 참고합니다.

Codex 등록과 롤백

코드가 main에 병합된 뒤 다음처럼 local stdio MCP를 등록합니다. --envuv --env-file을 사용하지 않으므로 Codex 전역 설정에 secret이 저장되지 않습니다.

REPOSITORY_DIR=/absolute/path/to/jeju_AI

codex mcp add jeju-day-trip-planner -- \
  /opt/homebrew/bin/uv \
  --directory "$REPOSITORY_DIR" \
  run --frozen --no-env-file \
  jeju-trip-mcp-codex

codex mcp get jeju-day-trip-planner --json
codex mcp list

등록 결과의 command, directory, --frozen, --no-env-file, 빈 Env, enabled local stdio 상태를 확인한 뒤 Codex를 재시작하거나 새 세션을 열어 여섯 도구를 다시 발견해야 합니다. 등록만 되돌릴 때는 코드나 DB를 변경하지 않고 다음 명령을 사용합니다.

codex mcp remove jeju-day-trip-planner

라이브 MCP 인수

기본 pytest와 CI는 외부 API를 호출하지 않습니다. 실제 KST 당일 DB·TMAP·TAGO를 검증할 때만 다음 명시적 명령을 사용합니다.

uv run --frozen --no-env-file python scripts/run_live_mcp_acceptance.py --confirm-live

MCP_LIVE_ACCEPTANCE_PASS는 장소 검색, confirmed 정류장, TMAP 미리보기, 서로 다른 버스 전용 추천 세 개, Evaluate, 선택 버스의 same-day TAGO fact 결합까지 모두 통과했다는 뜻입니다. TAGO 운행 종료나 현재 도착정보 부재 시 최대 세 stop/route만 확인하고 MCP_SETUP_PASS / LIVE_TAGO_WINDOW_DEFERRED로 기록합니다. 세 추천을 만들 수 없으면 추천을 비우고 insufficient_feasible_routes를 유지하며 live availability 실패를 성공으로 바꾸지 않습니다.

인수 출력과 보고서에는 상태, 도구명, 추천 수, 전략, transfer mode, fact category, 호출 수만 남깁니다. 좌표·상세 경로·정류장/노선 ID·API key·DSN·provider raw response·geometry·사용자 원문은 기록하지 않습니다.

JEJU_RUNTIME_DSN 또는 경로 adapter가 없으면 도구는 사실을 추정하지 않고 구조화된 데이터 부족 응답을 반환합니다. 검색·정류장 조회·생성·판정·재판정·이동 미리보기는 모두 config/data_sources.toml의 source별 freshness를 통과한 활성 snapshot만 사용합니다. 버스와 택시 요금 readiness는 서로 분리되어 한 수단의 stale 정책이 다른 수단 전용 요청을 막지 않습니다.

격리 통합 테스트

개발 DB와 MinIO를 테스트에 사용하지 않습니다. test profile은 tmpfs 기반 jeju_trip_test와 별도 MinIO endpoint만 엽니다.

docker compose -f infra/compose.local.yml --profile test up -d postgres-test minio-test

JEJU_TEST_ADMIN_DSN='postgresql://postgres:local-postgres-test-only@127.0.0.1:55433/jeju_trip_test' \
JEJU_TEST_S3_ENDPOINT='http://127.0.0.1:59010' \
JEJU_TEST_S3_ACCESS_KEY='jeju-test-admin' \
JEJU_TEST_S3_SECRET_KEY='jeju-test-password-only' \
uv run pytest tests/integration -q -rs

docker compose -f infra/compose.local.yml --profile test down

테스트 fixture는 DSN의 DB 이름이 jeju_trip_test가 아니거나 MinIO endpoint가 127.0.0.1:59010이 아니면 시작 자체를 거부합니다.

데이터와 보안 경계

  • 공개 JSON Schema의 유일한 원본은 src/jeju_trip/domain/models.py입니다.

  • 외부 네트워크는 config/data_sources.toml의 승인 상태·HTTPS host·정규화 path·응답 크기 제한을 모두 통과해야 합니다.

  • TMAP/TAGO 원문, TMAP 상세 geometry, 사용자 원문·일정·GPS는 영속 저장하거나 로그로 남기지 않습니다.

  • 시간·거리·비용 및 계산값은 응답 내부 evidence ledger에 존재하는 fact ID로 완전히 추적돼야 하며, 모든 SourceRef.source_id는 같은 응답의 data_sources에 존재해야 합니다.

  • 활성 snapshot이 freshness 계약을 넘으면 readiness를 닫고 source metadata를 STALE로 표시합니다.

제품 범위와 공개 계약은 PROJECT_PLAN.mdJSON_CONTRACT.md를 참고합니다. 운영 데이터 활성화·외부 live 인수는 docs/reports의 최신 날짜 보고서와 함께 확인합니다.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Timing-Jeju/jeju_AI'

If you have feedback or need assistance with the MCP directory API, please join our Discord server