Agentic Travel Recommendations Service
Agentic Travel Recommendations Service
이 프로젝트는 다중 테넌트 여행 추천 서비스를 위한 TypeScript 및 Node.js 개념 증명입니다. REST API, Streamable HTTP MCP 엔드포인트, 명령줄 인터페이스를 통해 공유 추천 기능을 노출합니다.
주요 기능
상태 확인, 회원 프로필, 추천을 위한 REST API
Streamable HTTP MCP 엔드포인트
MCP 도구:
get_member_profileMCP 도구:
get_recommendations권위 있는 회원 기반 테넌트 결정
파트너별 추천 상한
파트너별 카테고리 제외
결정적 추천 생성
실패 시 차단(fail-closed)되는 파트너 구성 동작
요청 ID 및 구조화된 JSON 로그
최소 CLI 데모
다단계 Docker 빌드
자동화된 테스트
아키텍처 개요
REST / MCP / CLI
|
v
RecommendationService
|
v
MemberDataService
|
| member.partnerId
v
PartnerConfigurationService
|
v
CandidateGenerator
|
v
RecommendationPolicy
|
| exclusions then cap
v
Final Recommendations호출자는 memberId만 제공하며, 권위 있는 partnerId를 선택하지 않습니다. 회원 프로필이 파트너 구성을 결정하며, REST, MCP, CLI는 모두 동일한 비즈니스 계층을 재사용합니다.
빠른 시작
npm ci
npm run dev서비스는 기본적으로 http://localhost:3000에서 사용할 수 있습니다.
타입 검사
npm run typecheck
npm run typecheck:test
npm run typecheck:all테스트
npm test현재 검증된 기준은 6개 파일에 걸쳐 46개의 통과 테스트입니다.
프로덕션 빌드
npm run build
npm startREST API
GET /health
GET /api/members/:memberId
GET /api/recommendations/:memberId예시 요청:
curl http://localhost:3000/api/members/MEMBER-001
curl http://localhost:3000/api/recommendations/MEMBER-001MCP
MCP 서버는 다음을 통해 노출됩니다:
POST /mcp다음 도구를 제공합니다:
get_member_profileget_recommendations
두 도구 모두 회원 식별자만 받습니다:
{
"memberId": "MEMBER-001"
}구현은 공식 @modelcontextprotocol/sdk Streamable HTTP 전송을 사용합니다. 호출자는 partnerId를 제공하지 않으며, 권위 있는 회원 프로필에서 해당 값이 결정됩니다.
CLI
npm run cli -- MEMBER-001데모 회원:
MEMBER-001→BANK_AMEMBER-002→BANK_BMEMBER-003→CREDIT_UNION_C
Docker
docker build -t agentic-travel-recommendations .
docker run --rm -p 3000:3000 agentic-travel-recommendations이미지는 다단계 빌드, Node 24 런타임, 비루트 런타임 사용자를 사용합니다. HTTP 서버는 정상 종료 신호를 처리합니다.
Section A — 아키텍처 및 트레이드오프
아키텍처 개요
이 서비스는 REST, Streamable HTTP MCP, CLI를 통해 동일한 추천 워크플로를 노출하는 상태 비저장 TypeScript 및 Node.js 애플리케이션입니다. 각 전송은 입력을 검증하고 공유 RecommendationService에 위임합니다. 전송 핸들러는 파트너 정책을 직접 구현하지 않습니다.
권위 있는 테넌트 흐름은 다음과 같습니다:
memberId
→ MemberDataService
→ MemberProfile.partnerId
→ PartnerConfigurationService
→ CandidateGenerator
→ RecommendationPolicy
→ final recommendations호출자는 memberId를 제공하며 권위 있는 partnerId를 선택하지 않습니다. MemberDataService가 반환한 회원 프로필이 검색할 파트너 구성을 결정합니다. 또한 두 업스트림 서비스 모두 응답에 포함된 식별자를 요청된 식별자와 대조하며, RecommendationService는 생성 전에 추가적인 파트너 식별자 확인을 수행합니다.
후보 생성은 의도적으로 파트너 정책과 독립적입니다. 결정적 생성기는 먼저 회원 프로필에서 원시 후보를 생성합니다. 그런 다음 일반 정책 계층이 excludedCategories의 후보를 제거하고 recommendationCap을 적용하며, 순서는 이와 같습니다. 결과로 얻은 추천만 반환됩니다. 이 개념 증명을 위해 Member Data Service와 Partner Configuration Service는 모의(mock)로 제공되며, 파트너 구성 접근은 읽기 전용입니다.
설계 트레이드오프
정확성 우선, 가용성보다. 권위 있는 파트너 구성이 누락되었거나, 사용 불가능하거나, 스키마가 잘못되었거나, 식별자가 일치하지 않으면 요청은 실패 시 차단(fail closed)됩니다. 서비스는 허용적인 기본값을 대체하거나 무제한 추천을 반환하지 않습니다. 이는 업스트림 장애 중 가용성을 낮출 수 있지만, 추천이 올바른 테넌트 정책을 벗어나지 않도록 방지합니다.
캐싱보다 신선한 구성. 첫 번째 릴리스는 캐시 인프라를 추가하는 대신 모든 추천 요청에 대해 파트너 구성을 검색합니다. 이는 동작을 단순하게 유지하고 각 성공적인 요청이 현재 정책을 사용하도록 보장합니다. 추가적인 업스트림 지연과 부하를 감수합니다. 단기 캐시는 측정된 성능이 일관성 트레이드오프를 정당화하는 경우에만 나중에 적합합니다.
외부 LLM보다 결정적 생성. 후보 생성은 재현 가능하고, 테스트 가능하며, 비용이 들지 않고, 운영상 예측 가능합니다. 이는 개인화의 정교함을 제한하지만, 정책 동작과 평가 결과를 쉽게 검증할 수 있게 합니다. 향후 LLM 또는 순위 구성 요소가 결정적 정책 시행을 변경하지 않고 후보 생성을 대체할 수 있습니다.
파트너 구성 변경 처리
Partner Configuration Service는 읽기 전용 의존성입니다. 파트너가 추천 상한을 무제한에서 3으로 변경하거나 excludedCategories에 cruise를 추가하면 추천 서비스는 코드 변경이나 테넌트별 분기가 필요하지 않습니다. 다음 성공적인 요청이 현재 구성을 읽고, 일반 정책 로직이 새 제외 및 상한 값을 적용합니다.
구성이 기존 스키마와 호환되는 한 애플리케이션은 재배포가 필요하지 않습니다. 나중에 구성 캐싱을 도입하는 경우, 오래된 구성이 파트너의 현재 정책을 일시적으로 위반할 수 있으므로 의도적으로 짧은 TTL 또는 신뢰할 수 있는 무효화 전략이 있어야 합니다.
Section B — 프로덕션 대비 및 장애 대응
장애 대응 런북 항목
시나리오: 회원이 자신의 파트너가 크루즈를 제외함에도 AI Concierge가 크루즈 추천을 표시했다고 보고합니다.
식별 및 상관 관계. 가능하면 보고에서 요청 또는 상관 관계 ID를 확보하고 해당 구조화된 로그를 찾습니다.
operation,memberId, 권위 있는partnerId(확인된 후),resultCode, 적용 가능한 경우 HTTP 상태를 기록합니다. 여행 이력 및 추천 페이로드는 의도적으로 기록되지 않으므로 식별자와 결과 메타데이터를 상관 관계에 사용합니다.권위 있는 테넌트 확인.
MemberDataService를 통해 영향을 받는 회원을 검색하고 요청된memberId가 반환된member.memberId와 같은지 확인합니다. 테넌트는member.partnerId에서만 파생합니다. 프런트엔드, MCP 호출자, 쿼리 매개변수 또는 지원 보고서에서 제공된 파트너 ID는 신뢰하지 마십시오.파트너 구성 확인.
member.partnerId를 사용하여 구성을 검색한 다음configuration.partnerId === member.partnerId인지 확인합니다.excludedCategories와recommendationCap을 검사하고 현재 권위 있는 구성에서cruise가 제외되는지 결정합니다. 누락되었거나, 사용 불가능하거나, 형식이 잘못되었거나, 식별자가 일치하지 않는 구성은 허용적인 기본값을 사용하는 대신 서비스가 실패 시 차단되도록 해야 합니다.파이프라인 재현. 동일한 추천 워크플로를 통해 회원을 실행합니다. 원시
CandidateGenerator출력의 크루즈는 생성이 의도적으로 파트너 정책을 무시하므로 그 자체로 결함이 아닙니다.RecommendationPolicy가raw candidates → remove excluded categories → apply recommendation cap → final recommendations순으로 처리하는지 확인하고 최종 결과에 크루즈가 없는지 확인합니다.실패 위치 격리. 크루즈가 원시 후보에는 나타나지만 최종 추천에는 없다면 정책이 올바르게 작동하는 것입니다. 오래된 클라이언트 응답, 잘못된 회원과 연결된 응답, 예상 워크플로를 우회하는 다른 소비자 또는 엔드포인트, 보고된 시간과 현재 구성의 차이를 조사합니다. 크루즈가
RecommendationPolicy를 통과한다면 카테고리 비교 또는 정규화, 권위 있는 구성 내용 및 식별자, 최근 정책 변경 또는 회귀를 검사합니다.차단. 올바른 파트너 정책을 설정하거나 안전하게 재현할 수 없으면 잠재적으로 비준수 추천을 반환하는 대신 실패 시 차단합니다. 이 애플리케이션에서 읽기 전용 Partner Configuration Service를 수정하려고 시도하지 마십시오.
수정 및 검증. 책임 계층의 결함을 수정하고 정확한 실패를 재현하는 회귀 테스트를 추가합니다. 실행:
npm run typecheck:all npm test npm run build해당 파트너, 영향을 받지 않은 테넌트 하나 이상, REST 동작, 관련된 경우 MCP 동작을 확인합니다.
후속 조치. 근본 원인, 영향받은 파트너 및 회원 범위, 영향 기간, 시정 조치, 회귀 테스트 범위, 예방 조치를 기록합니다.
Part B2 — 필수 추론 질문
AI 코딩 어시스턴트가 업스트림 회원 및 파트너 레코드를 Zod로 검증하지만 반환된 식별자를 요청된 식별자와 상호 연관시키지 않는 구현을 그럴듯하게 생성할 수 있습니다. 코드는 타입 안전성을 갖추고, 스키마 검증 및 정상 경로 테스트는 통과하며, 피상적인 검토는 합리적인 방어적 검증으로 볼 것입니다. 그러나 누락된 교차 테넌트 불변식은 여전히 심각한 정책 위험을 만듭니다.
예를 들어, MEMBER-001은 BANK_A에 속합니다. RecommendationService가 BANK_A의 구성을 요청하지만, 버그가 있거나 잘못 라우팅된 업스트림 서비스가 무제한 상한과 카테고리 제외가 없는 완전히 스키마에 유효한 BANK_B 구성을 반환합니다. Zod는 그 형태를 올바르게 수락하지만, 해당 정책을 MEMBER-001에 적용하면 BANK_A의 제한을 우회할 수 있습니다.
나는 적대적 회귀 테스트로 이를 잡을 것입니다. 의도적으로 결함이 있는 구성 서비스 테스트 대역이 유효한 BANK_B 구성을 반환하는 동안 BANK_A를 요청하는 것입니다. InvalidUpstreamDataError를 기대하고, 추천 결과가 생성되지 않았음을 단언하며, CandidateGenerator.generate가 호출되지 않았음을 명시적으로 검증할 것입니다. 또한 요청된 memberId가 반환된 member.memberId와 일치해야 함을 증명하는 해당 회원 데이터 테스트를 추가할 것입니다.
AI 생성 코드를 적용하기 전에 나는 타입만에 의존하지 않고 권한과 실행 순서를 추적할 것입니다. member.partnerId가 호출자 입력이 아니라 테넌트를 선택하는지, 반환된 두 식별자가 각자의 권위 있는 요청과 일치하는지, 누락되었거나 사용 불가능하거나 일치하지 않는 구성이 허용적 폴백 없이 실패 시 차단되는지 검증할 것입니다. 또한 정책 식별자가 안전하게 설정되기 전에는 생성이 시작될 수 없고, 부정적이고 적대적인 테스트가 정상적인 해피 패스와 함께 이러한 사례를 다루는지도 확인할 것입니다.
Section C — AI 사용 기록
인터랙션 1 — 아키텍처 검토
내가 요청한 것
AI 코딩 어시스턴트에게 과제를 검토하고 한 명의 엔지니어가 현실적으로 구현할 수 있는 최소 아키텍처를 설계하도록 요청했습니다. 요청한 범위에는 도메인 모델, 모의 업스트림 서비스, 추천 로직, REST, MCP, CLI, 자동화된 테스트, 컨테이너화가 포함되었으며, 개념 증명에 필요하지 않은 인프라는 피했습니다.
AI가 제공한 것
AI는 도메인 모델, 서비스 계약, 모의 업스트림 서비스, 후보 생성, 파트너 정책, 오케스트레이션, 전송 어댑터를 분리할 것을 제안했습니다. 처음에는 가장 단순한 MCP 전송으로 stdio를 제안했습니다.
내가 유지, 변경, 또는 거부한 것
계층적 분리를 유지했습니다. REST, MCP, CLI가 규칙을 독립적으로 구현하는 대신 하나의 비즈니스 계층을 호출할 수 있기 때문입니다. 기본 MCP 전송으로 stdio를 거부하고 POST /mcp의 공식 MCP SDK Streamable HTTP 전송으로 설계를 전환했습니다. 과제는 에이전트가 발견하고 호출해야 하는 내부 API를 설명하며, HTTP는 컨테이너화된 서비스 아키텍처에 적합합니다. 가장 단순한 옵션을 자동으로 수락하는 대신 제안을 과제의 통합 요구 사항과 비교한 후 해당 선택을 했습니다.
인터랙션 2 — 점진적 구현
내가 요청한 것
한 번의 프롬프트로 전체 애플리케이션을 요청하지 않았습니다. 구현을 도메인 모델, 스키마 및 오류, 업스트림 계약 및 모의, 후보 생성, 추천 정책, 오케스트레이션, REST, MCP, CLI, 관찰 가능성, Docker와 같은 경계 있는 단계로 나누었습니다. 각 단계 후에 보고된 동작을 검토하고 진행하기 전에 타입 검사와 테스트를 요구했습니다.
AI가 제공한 것
어시스턴트는 각 경계 있는 구성 요소를 집중된 테스트와 함께 구현하고 변경된 파일과 검증 결과를 보고했습니다. 이로 인해 개별 설계 선택이 대규모 생성 패치 안에 숨는 대신 눈에 보이고 검토 가능해졌습니다.
내가 유지, 변경, 또는 거부한 것
저는 공유 RecommendationService, 결정론적 CandidateGenerator, 분리된 RecommendationPolicy, 멤버 파생 테넌트 해석, 읽기 전용 구성 계약, 그리고 공유 REST/MCP/CLI 비즈니스 로직을 유지했습니다. 이 구조는 테넌트 정책을 독립적으로 테스트 가능하게 만들고 전송 수단별 규칙 구현을 방지합니다. 또한 외부 LLM 의존성을 추가하는 대신 결정론적 생성을 의도적으로 유지했습니다. 평가는 서비스 설계와 정책 시행에 초점을 맞추며, 재현 가능한 출력은 테스트, 디버깅, 시연이 더 쉽습니다. 각 증분은 동작이 아키텍처 불변식과 일치하고 검사를 통과한 후에만 수용되었습니다.
상호작용 3 — 프로덕션 및 보안 감사
내가 요청한 것
애플리케이션이 작동한 후, 나는 AI에게 기능 추가를 중단하고 시니어 엔지니어, 다중 테넌트 보안 검토자, 온콜 프로덕션 담당자, REST/MCP API 검토자의 관점에서 리포지토리를 감사하도록 요청했습니다.
AI가 제공한 것
감사 결과, 스키마를 통과한 업스트림 응답이 원래 요청된 멤버 또는 파트너 ID와 연관되지 않았음을 발견했습니다. 또한 잘못된 형식의 JSON은 요청 ID 미들웨어가 요청 컨텍스트를 설정하기 전에 실패할 수 있음을 발견했습니다. 추가로 우선순위가 낮은 개선 사항들이 제안되었습니다.
내가 유지, 변경, 또는 거부한 것
나는 두 가지 고가치 발견 사항을 모두 수용했습니다. 테넌트 정확성과 안전한 운영에 영향을 미치기 때문입니다. ID 연관을 위해 구현은 이제 반환된 memberId가 요청된 멤버와 일치하는지, configuration.partnerId가 권위 있는 member.partnerId와 일치하는지, 그리고 RecommendationService가 방어적으로 구성 ID 검사를 반복하는지 확인합니다. 불일치 시에는 실패 시 폐쇄(fail closed)되며, 적대적 회귀 테스트는 권위 있는 구성을 확립할 수 없을 때 후보 생성이 시작되지 않음을 검증합니다.
잘못된 형식의 JSON의 경우, 요청 컨텍스트와 요청 ID가 이제 파싱 전에 설정됩니다. 잘못된 본문에는 파서 세부 정보, 스택 추적, 파일 시스템 경로, 또는 원시 요청 콘텐츠 없이 안전한 구조화된 400 응답이 반환됩니다.
나는 영구 MCP 세션, 추가 분산 인프라, 더 고급 관측 가능성 같은 우선순위가 낮은 아이디어는 연기했습니다. 4주 개념 증명에 불필요하고 운영 범위를 늘릴 것이기 때문입니다. 나는 각 권장 사항을 과제 요구 사항, 테넌트 정확성, 테스트 가능성, 운영 위험, 전달 범위에 대해 평가했습니다. 어시스턴트는 옵션과 구현 지원을 제공했지만, 나는 근거를 검토하고 변경 사항을 선택했으며 집중 테스트와 엔드투엔드 검증을 통해 확인했습니다.
4주 첫 단계
먼저 출시되는 것
1주차 — 서비스 기반
TypeScript 및 Node.js 서비스 기반을 구축합니다.
도메인 모델, 엄격한 Zod 경계 검증, 타입화된 오류를 정의합니다.
MemberDataService계약과 목 구현을 추가합니다.읽기 전용
PartnerConfigurationService계약과 목 구현을 추가합니다.권위 있는 멤버 파생 테넌트 해석과 초기 단위 테스트 기반을 구축합니다.
목표: 추천 로직을 구현하기 전에 안전한 서비스 경계와 테넌트 권한을 확립합니다.
2주차 — 추천 워크플로우
파트너 규칙과 독립적으로 결정론적
CandidateGenerator를 구현합니다.카테고리 제외 및 추천 상한을 포함하는
RecommendationPolicy를 구현합니다.필수 순서를 적용합니다: 제외 먼저, 그 다음 상한.
RecommendationService오케스트레이션 및 실패 시 폐쇄(fail-closed) 구성 동작을 추가합니다.정책과 오케스트레이션을 집중 단위 테스트로 다룹니다.
목표: 계약상 파트너 규칙이 결정론적이며 후보 생성과 독립적임을 입증합니다.
3주차 — 인터페이스 및 엔드투엔드 흐름
REST 엔드포인트와 Streamable HTTP MCP 엔드포인트를 노출합니다.
MCP 도구
get_member_profile및get_recommendations를 제공합니다.CLI 데모를 추가합니다.
REST, MCP, CLI를 공유 비즈니스 계층을 통해 라우팅합니다.
REST/MCP 통합 테스트 및 테넌트 재정의 테스트를 추가합니다.
목표: 과제에서 요구하는 인터페이스를 통해 완전한 추천 워크플로우를 시연합니다.
4주차 — 프로덕션 준비 및 전달
요청 ID, 상관 필드, 구조화된 JSON 로깅, 안전한 오류 처리를 추가합니다.
잘못된 형식의 JSON을 안전하게 처리하고 정상 종료(graceful shutdown)를 구현합니다.
Docker 다단계 빌드 및 비루트 런타임을 추가합니다.
프로덕션 소스와 테스트를 분리하여 타입검사합니다.
프로덕션/보안 감사를 수행하고 적대적 ID 연관 테스트를 추가합니다.
최종 엔드투엔드 및 컨테이너 검증을 완료합니다.
README, 장애 대응 런북, 시연 비디오를 준비합니다.
목표: 개념 증명을 담당 팀이 온콜로 지원할 수 있게 만듭니다.
나중에 진행할 작업
다음 작업은 첫 4주 릴리스 이후로 의도적으로 연기됩니다:
실제 업스트림 통합. 기존 서비스 계약과 ID 연관 불변식을 유지하면서 목(mock)
MemberDataService및PartnerConfigurationService구현을 실제 arrivia REST 클라이언트로 교체합니다.기존 인증 및 인가 통합. 새로운 ID 플랫폼을 도입하는 대신 arrivia의 기존 ID 및 게이트웨이 메커니즘과 통합합니다. 인가는 멤버 파생 테넌트 권한을 보존해야 합니다.
네트워크 탄력성. 실제 업스트림 HTTP 의존성에 대해 요청 및 연결 시간 초과, 재시도해도 안전한 작업에 대한 제한된 재시도, 명시적 실패 동작을 검증하고 구성합니다. 구성 불확실성은 계속해서 실패 시 폐쇄(fail closed)되어야 합니다.
성능 검증. 최적화 전에 실제적인 부하 및 성능 테스트를 실행합니다. 측정 결과가 정당화할 때만 수명이 짧은 파트너 구성 캐싱을 고려합니다. 오래된 정책은 정확성 위험이므로 모든 캐시에는 명확한 신선도 및 무효화 전략이 필요합니다.
추천 지능. 결정론적
CandidateGenerator를 LLM, 랭킹 모델, 또는 더 풍부한 개인화로 대체하거나 보강할 수 있습니다.RecommendationPolicy는 결정론적이고 모델 외부에 유지되어 생성된 출력이 파트너 규칙을 재정의할 수 없어야 합니다.프로덕션 관측 가능성. 기존 구조화 이벤트 및 상관 ID를 arrivia의 승인된 메트릭, 추적, 알림, 운영 도구에 연결합니다.
MCP 진화. 구체적인 제품 요구 사항이 요청 간 상태를 필요로 할 때만 상태 저장 또는 재개 가능한 MCP 동작을 고려합니다. 현재의 무상태 Streamable HTTP 구현은 이 서비스에 의도적인 것입니다.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Hotel booking MCP server. Search, book, and manage reservations across 250K+ properties worldwide.
AI marketplace — flights, tours, activities, transport & more via MCP. No auth required.
MCP server exposing the Backtest360 engine API as tools for AI agents.
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/Varma904/agentic-travel-recommendations'
If you have feedback or need assistance with the MCP directory API, please join our Discord server