Timing Jeju FastAPI MCP
제주 하루 여행 MCP
공식·승인 데이터와 결정론적 검증만으로 제주 하루 일정을 생성하고 평가하는 로컬 stdio
MCP 서버입니다. 공개 계약 버전은 0.7.0이며, 성공 시 balanced, relaxed,
experience_max 일정 세 개를 모두 반환합니다. 세 개를 만들 수 없으면 부분 결과 없이
insufficient_feasible_routes로 종료합니다.
요구사항
Python 3.12 이상
격리 통합 테스트 또는 로컬 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-mcpCodex에는 수동 실행점 대신 jeju-trip-mcp-codex 보안 실행점을 등록합니다. 이 실행점은
저장소 루트의 .env symlink를 최종 대상까지 해석한 뒤 regular file, 현재 사용자 소유,
group/other 권한 없음, 64 KiB 이하, UTF-8 조건을 모두 검사합니다. 기본 파일을 바꾸는
JEJU_MCP_ENV_FILE은 테스트·별도 배포에만 사용하며 MCP 서버 환경에는 남기지 않습니다.
파일에서 런타임으로 전달하는 값은 다음 세 개뿐입니다.
JEJU_RUNTIME_DSNJEJU_TMAP_API_KEYJEJU_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를 등록합니다. --env나
uv --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-liveMCP_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.md와
JSON_CONTRACT.md를 참고합니다. 운영 데이터 활성화·외부 live 인수는
docs/reports의 최신 날짜 보고서와 함께 확인합니다.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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