feat: complete implementation plan for Mock GDS MCP server
Phase 0 (Research):
- Selected MCP SDK (@modelcontextprotocol/sdk) for protocol compliance
- Chose ioredis for Valkey client (Redis-compatible)
- Minimal dependencies: Pino logging, native test runner
- Docker buildx bake for multi-platform builds
- Embedded mock data with deterministic generation
- PNR format: TEST-{BASE32} for safety
Phase 1 (Design):
- Data model: 8 core entities (Session, PNR, FlightSegment, etc.)
- MCP contracts: 8 tools with JSON schemas
- Quickstart guide with complete workflow examples
- Constitution compliance verified
Technical stack:
- Node.js 20 LTS
- Valkey 8.0+ for persistence
- Docker containers (amd64/arm64)
- Performance: <2s search, 50+ concurrent sessions
Ready for task generation with /speckit.tasks
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
62
specs/001-mock-gds-server/checklists/requirements.md
Normal file
62
specs/001-mock-gds-server/checklists/requirements.md
Normal file
@@ -0,0 +1,62 @@
|
||||
# Specification Quality Checklist: Mock GDS MCP Server
|
||||
|
||||
**Purpose**: Validate specification completeness and quality before proceeding to planning
|
||||
**Created**: 2025-01-22
|
||||
**Feature**: [spec.md](../spec.md)
|
||||
|
||||
## Content Quality
|
||||
|
||||
- [x] No implementation details (languages, frameworks, APIs)
|
||||
- [x] Focused on user value and business needs
|
||||
- [x] Written for non-technical stakeholders
|
||||
- [x] All mandatory sections completed
|
||||
|
||||
## Requirement Completeness
|
||||
|
||||
- [x] No [NEEDS CLARIFICATION] markers remain
|
||||
- [x] Requirements are testable and unambiguous
|
||||
- [x] Success criteria are measurable
|
||||
- [x] Success criteria are technology-agnostic (no implementation details)
|
||||
- [x] All acceptance scenarios are defined
|
||||
- [x] Edge cases are identified
|
||||
- [x] Scope is clearly bounded
|
||||
- [x] Dependencies and assumptions identified
|
||||
|
||||
## Feature Readiness
|
||||
|
||||
- [x] All functional requirements have clear acceptance criteria
|
||||
- [x] User scenarios cover primary flows
|
||||
- [x] Feature meets measurable outcomes defined in Success Criteria
|
||||
- [x] No implementation details leak into specification
|
||||
|
||||
## Validation Summary
|
||||
|
||||
**Status**: ✅ PASSED
|
||||
|
||||
All checklist items have been validated:
|
||||
|
||||
### Content Quality
|
||||
- ✅ Specification is technology-agnostic - no mention of specific programming languages, frameworks, databases, or implementation technologies
|
||||
- ✅ All content focuses on WHAT users need (testing/demos) and WHY (development efficiency, reliable workflows)
|
||||
- ✅ Written in plain language suitable for stakeholders - uses business terms (developers, QA teams, sales demos) rather than technical jargon
|
||||
- ✅ All mandatory sections (User Scenarios, Requirements, Success Criteria, Assumptions) are complete and detailed
|
||||
|
||||
### Requirement Completeness
|
||||
- ✅ Zero [NEEDS CLARIFICATION] markers - all requirements are fully specified with concrete details
|
||||
- ✅ Each functional requirement is testable - FR-002 can be tested by executing searches with specified parameters and verifying outputs; FR-009 can be tested by running concurrent sessions and checking for data leakage
|
||||
- ✅ All success criteria include specific metrics (SC-001: 30 seconds, SC-002: 50 concurrent sessions, SC-003: under 2 seconds, SC-004: 100% valid codes)
|
||||
- ✅ Success criteria are technology-agnostic - no implementation details (e.g., SC-001 measures workflow completion time, not "API response time")
|
||||
- ✅ 5 user stories with 15 total acceptance scenarios covering all major workflows (flight booking, multi-service, car rental, session isolation, demo data)
|
||||
- ✅ 8 edge cases identified covering error scenarios (invalid codes, cancelled bookings, session expiry, validation failures)
|
||||
- ✅ Scope clearly bounded in Assumptions section - defines what's included (major airports, common workflows) and excluded (comprehensive airport coverage, complex fare rules, production use)
|
||||
- ✅ 12 assumptions documented covering data scope, pricing, payment handling, session management, and target users
|
||||
|
||||
### Feature Readiness
|
||||
- ✅ Each FR has corresponding acceptance scenarios - FR-002 (flight search) maps to User Story 1 acceptance scenario 1; FR-009 (session isolation) maps to User Story 4 scenarios
|
||||
- ✅ User scenarios cover all primary flows: basic flight booking (P1), multi-service bundling (P2), complete packages (P3), concurrent testing (P2), demo scenarios (P3)
|
||||
- ✅ Success criteria align with feature goals: rapid workflow completion (SC-001), concurrent session support (SC-002), realistic data quality (SC-004, SC-006), testing effectiveness (SC-005, SC-008)
|
||||
- ✅ No implementation leakage detected - specification never mentions MCP implementation details, data storage mechanisms, or specific tool implementations
|
||||
|
||||
## Notes
|
||||
|
||||
Specification is ready for next phase. Can proceed directly to `/speckit.plan` for implementation planning, or optionally run `/speckit.clarify` if additional stakeholder input is desired (though no clarifications are currently needed).
|
||||
395
specs/001-mock-gds-server/contracts/mcp-tools.md
Normal file
395
specs/001-mock-gds-server/contracts/mcp-tools.md
Normal file
@@ -0,0 +1,395 @@
|
||||
# MCP Tool Contracts: Mock GDS MCP Server
|
||||
|
||||
**Branch**: `001-mock-gds-server` | **Date**: 2026-04-07
|
||||
|
||||
## Overview
|
||||
|
||||
This document defines the MCP tool schemas exposed by the Mock GDS MCP server. All tools follow the MCP JSON-RPC 2.0 protocol and include comprehensive JSON Schema validation.
|
||||
|
||||
## Tool Categories
|
||||
|
||||
1. **Flight Operations**: searchFlights, bookFlight
|
||||
2. **Hotel Operations**: searchHotels, bookHotel
|
||||
3. **Car Rental Operations**: searchCars, bookCar
|
||||
4. **Booking Management**: retrieveBooking, cancelBooking, listBookings
|
||||
|
||||
---
|
||||
|
||||
## Flight Operations
|
||||
|
||||
### searchFlights
|
||||
|
||||
Search for available flight options.
|
||||
|
||||
**Tool Name**: `searchFlights`
|
||||
|
||||
**Description**: Search for flights between two airports on a specific date. Returns mock flight options with realistic pricing, schedules, and availability.
|
||||
|
||||
**Input Schema**:
|
||||
```json
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"origin": {
|
||||
"type": "string",
|
||||
"pattern": "^[A-Z]{3}$",
|
||||
"description": "Origin airport IATA code (3 letters, e.g., 'JFK')"
|
||||
},
|
||||
"destination": {
|
||||
"type": "string",
|
||||
"pattern": "^[A-Z]{3}$",
|
||||
"description": "Destination airport IATA code (3 letters, e.g., 'LAX')"
|
||||
},
|
||||
"departureDate": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Departure date in ISO 8601 format (YYYY-MM-DD)"
|
||||
},
|
||||
"passengers": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"adults": {
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 9,
|
||||
"default": 1
|
||||
},
|
||||
"children": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9,
|
||||
"default": 0
|
||||
},
|
||||
"infants": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9,
|
||||
"default": 0
|
||||
}
|
||||
},
|
||||
"required": ["adults"]
|
||||
},
|
||||
"cabin": {
|
||||
"type": "string",
|
||||
"enum": ["economy", "premium_economy", "business", "first"],
|
||||
"default": "economy"
|
||||
}
|
||||
},
|
||||
"required": ["origin", "destination", "departureDate"]
|
||||
}
|
||||
```
|
||||
|
||||
**Example Request**:
|
||||
```json
|
||||
{
|
||||
"origin": "JFK",
|
||||
"destination": "LAX",
|
||||
"departureDate": "2026-06-15",
|
||||
"passengers": { "adults": 2 },
|
||||
"cabin": "economy"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### bookFlight
|
||||
|
||||
Create a flight booking.
|
||||
|
||||
**Tool Name**: `bookFlight`
|
||||
|
||||
**Description**: Book one or more flight segments with passenger details. Creates a PNR (Passenger Name Record) with TEST- prefix.
|
||||
|
||||
**Input Schema**:
|
||||
```json
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"flightIds": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" },
|
||||
"minItems": 1,
|
||||
"description": "Array of flight IDs from search results"
|
||||
},
|
||||
"passengers": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["adult", "child", "infant"]
|
||||
},
|
||||
"firstName": { "type": "string", "minLength": 1, "maxLength": 50 },
|
||||
"lastName": { "type": "string", "minLength": 1, "maxLength": 50 },
|
||||
"dateOfBirth": { "type": "string", "format": "date" },
|
||||
"email": { "type": "string", "format": "email" },
|
||||
"phone": { "type": "string" },
|
||||
"frequentFlyerNumber": { "type": "string" }
|
||||
},
|
||||
"required": ["type", "firstName", "lastName"]
|
||||
}
|
||||
},
|
||||
"contactEmail": {
|
||||
"type": "string",
|
||||
"format": "email",
|
||||
"description": "Primary contact email"
|
||||
},
|
||||
"contactPhone": {
|
||||
"type": "string",
|
||||
"description": "Primary contact phone"
|
||||
}
|
||||
},
|
||||
"required": ["flightIds", "passengers"],
|
||||
"anyOf": [
|
||||
{ "required": ["contactEmail"] },
|
||||
{ "required": ["contactPhone"] }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Hotel Operations
|
||||
|
||||
### searchHotels
|
||||
|
||||
**Tool Name**: `searchHotels`
|
||||
|
||||
**Description**: Search for hotel properties in a city with check-in/check-out dates.
|
||||
|
||||
**Input Schema**:
|
||||
```json
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"cityCode": {
|
||||
"type": "string",
|
||||
"pattern": "^[A-Z]{3}$",
|
||||
"description": "City IATA code (3 letters, e.g., 'LAX')"
|
||||
},
|
||||
"checkInDate": {
|
||||
"type": "string",
|
||||
"format": "date"
|
||||
},
|
||||
"checkOutDate": {
|
||||
"type": "string",
|
||||
"format": "date"
|
||||
},
|
||||
"guests": {
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 10,
|
||||
"default": 1
|
||||
},
|
||||
"starRating": {
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 5,
|
||||
"description": "Minimum star rating filter (optional)"
|
||||
}
|
||||
},
|
||||
"required": ["cityCode", "checkInDate", "checkOutDate"]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### bookHotel
|
||||
|
||||
**Tool Name**: `bookHotel`
|
||||
|
||||
**Description**: Book a hotel reservation. Can create a new PNR or add to an existing flight booking.
|
||||
|
||||
**Input Schema**:
|
||||
```json
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"hotelId": { "type": "string" },
|
||||
"existingPnr": {
|
||||
"type": "string",
|
||||
"pattern": "^TEST-[A-Z0-9]{6}$",
|
||||
"description": "Optional: Add hotel to existing booking"
|
||||
},
|
||||
"guests": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"firstName": { "type": "string" },
|
||||
"lastName": { "type": "string" },
|
||||
"email": { "type": "string", "format": "email" }
|
||||
},
|
||||
"required": ["firstName", "lastName"]
|
||||
}
|
||||
},
|
||||
"specialRequests": { "type": "string" }
|
||||
},
|
||||
"required": ["hotelId", "guests"]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Car Rental Operations
|
||||
|
||||
### searchCars
|
||||
|
||||
**Tool Name**: `searchCars`
|
||||
|
||||
**Description**: Search for car rental options at an airport or city location.
|
||||
|
||||
**Input Schema**:
|
||||
```json
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"pickupLocationCode": {
|
||||
"type": "string",
|
||||
"pattern": "^[A-Z]{3}$"
|
||||
},
|
||||
"dropoffLocationCode": {
|
||||
"type": "string",
|
||||
"pattern": "^[A-Z]{3}$",
|
||||
"description": "Defaults to pickup location if not specified"
|
||||
},
|
||||
"pickupDate": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"dropoffDate": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"driverAge": {
|
||||
"type": "integer",
|
||||
"minimum": 21,
|
||||
"maximum": 99,
|
||||
"default": 30
|
||||
}
|
||||
},
|
||||
"required": ["pickupLocationCode", "pickupDate", "dropoffDate"]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### bookCar
|
||||
|
||||
**Tool Name**: `bookCar`
|
||||
|
||||
**Description**: Book a car rental. Can create a new PNR or add to an existing booking.
|
||||
|
||||
---
|
||||
|
||||
## Booking Management Operations
|
||||
|
||||
### retrieveBooking
|
||||
|
||||
**Tool Name**: `retrieveBooking`
|
||||
|
||||
**Description**: Fetch complete booking details including all segments.
|
||||
|
||||
**Input Schema**:
|
||||
```json
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"pnr": {
|
||||
"type": "string",
|
||||
"pattern": "^TEST-[A-Z0-9]{6}$"
|
||||
}
|
||||
},
|
||||
"required": ["pnr"]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### cancelBooking
|
||||
|
||||
**Tool Name**: `cancelBooking`
|
||||
|
||||
**Description**: Cancel a confirmed booking.
|
||||
|
||||
**Input Schema**:
|
||||
```json
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"pnr": {
|
||||
"type": "string",
|
||||
"pattern": "^TEST-[A-Z0-9]{6}$"
|
||||
},
|
||||
"reason": { "type": "string" }
|
||||
},
|
||||
"required": ["pnr"]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### listBookings
|
||||
|
||||
**Tool Name**: `listBookings`
|
||||
|
||||
**Description**: Retrieve a list of all PNRs created in the current MCP session.
|
||||
|
||||
**Input Schema**:
|
||||
```json
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": ["all", "confirmed", "cancelled"],
|
||||
"default": "all"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Error Responses
|
||||
|
||||
All tools return standard MCP errors:
|
||||
|
||||
- **-32602**: Invalid params (validation failure)
|
||||
- **-32603**: Internal error (server error)
|
||||
- **-32001**: Resource not found (invalid PNR, airport code, etc.)
|
||||
- **-32002**: Business logic error (cancelled booking, date in past, etc.)
|
||||
|
||||
**Error Format**:
|
||||
```json
|
||||
{
|
||||
"code": -32602,
|
||||
"message": "Invalid airport code 'XYZ': must be a valid 3-letter IATA code",
|
||||
"data": {
|
||||
"field": "origin",
|
||||
"value": "XYZ"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## MCP Resource Endpoints
|
||||
|
||||
- `gds://session/current` - Current session metadata
|
||||
- `gds://session/bookings` - List of all bookings
|
||||
- `gds://mock-data/airports` - Mock airport data
|
||||
- `gds://mock-data/airlines` - Mock airline data
|
||||
|
||||
---
|
||||
|
||||
## Protocol Notes
|
||||
|
||||
- All tools use JSON-RPC 2.0 over stdio (default) or SSE
|
||||
- Tool schemas validated before execution
|
||||
- Timestamps use ISO 8601 format
|
||||
- Prices in USD cents (integer)
|
||||
- All PNRs prefixed with "TEST-" for safety
|
||||
394
specs/001-mock-gds-server/data-model.md
Normal file
394
specs/001-mock-gds-server/data-model.md
Normal file
@@ -0,0 +1,394 @@
|
||||
# Data Model: Mock GDS MCP Server
|
||||
|
||||
**Branch**: `001-mock-gds-server` | **Date**: 2026-04-07
|
||||
|
||||
## Overview
|
||||
|
||||
This document defines the core data entities, their relationships, validation rules, and state transitions for the Mock GDS MCP server.
|
||||
|
||||
## Core Entities
|
||||
|
||||
### 1. Session
|
||||
|
||||
Represents an MCP client connection with isolated booking context.
|
||||
|
||||
**Fields**:
|
||||
```typescript
|
||||
{
|
||||
id: string; // Unique session identifier (UUID)
|
||||
createdAt: number; // Unix timestamp (ms)
|
||||
expiresAt: number; // Unix timestamp (ms), TTL-based
|
||||
lastActivity: number; // Unix timestamp (ms)
|
||||
bookingCount: number; // Number of bookings created in session
|
||||
searchCount: number; // Number of searches performed
|
||||
}
|
||||
```
|
||||
|
||||
**Storage**: Valkey hash at key `gds:session:{sessionId}`
|
||||
|
||||
**Validation**:
|
||||
- `id` must be valid UUID v4
|
||||
- `expiresAt` must be > `createdAt`
|
||||
- Automatic expiry via Valkey TTL (default 1 hour)
|
||||
|
||||
**State Transitions**:
|
||||
```
|
||||
[Created] → [Active] → [Expired]
|
||||
↓
|
||||
[Ended]
|
||||
```
|
||||
|
||||
### 2. Passenger
|
||||
|
||||
Represents a traveler in a booking.
|
||||
|
||||
**Fields**:
|
||||
```typescript
|
||||
{
|
||||
id: string; // Unique within booking
|
||||
type: enum; // 'adult' | 'child' | 'infant'
|
||||
firstName: string; // Required
|
||||
lastName: string; // Required
|
||||
dateOfBirth: string; // ISO 8601 date (YYYY-MM-DD), optional
|
||||
email: string; // Email address, optional
|
||||
phone: string; // Phone number, optional
|
||||
frequentFlyerNumber: string; // Airline loyalty number, optional
|
||||
}
|
||||
```
|
||||
|
||||
**Validation**:
|
||||
- `firstName`, `lastName` must be 1-50 characters, alphabetic + spaces/hyphens
|
||||
- `email` must match RFC 5322 pattern if provided
|
||||
- `phone` must match E.164 pattern if provided
|
||||
- `type` must be valid enum value
|
||||
|
||||
### 3. FlightSegment
|
||||
|
||||
Represents a single flight leg in an itinerary.
|
||||
|
||||
**Fields**:
|
||||
```typescript
|
||||
{
|
||||
id: string; // Unique segment identifier
|
||||
flightNumber: string; // e.g., "AA123"
|
||||
airlineCode: string; // IATA 2-letter code (e.g., "AA")
|
||||
airlineName: string; // Full airline name
|
||||
originCode: string; // IATA 3-letter airport code (e.g., "JFK")
|
||||
originName: string; // Airport name
|
||||
destinationCode: string; // IATA 3-letter airport code
|
||||
destinationName: string; // Airport name
|
||||
departureTime: string; // ISO 8601 datetime
|
||||
arrivalTime: string; // ISO 8601 datetime
|
||||
duration: number; // Minutes
|
||||
aircraftType: string; // e.g., "Boeing 737-800"
|
||||
cabin: enum; // 'economy' | 'premium_economy' | 'business' | 'first'
|
||||
price: number; // USD cents (e.g., 29900 = $299.00)
|
||||
seatsAvailable: number; // Available seats count
|
||||
bookingClass: string; // Fare class code (e.g., "Y", "J", "F")
|
||||
status: enum; // 'available' | 'sold_out' | 'cancelled'
|
||||
}
|
||||
```
|
||||
|
||||
**Validation**:
|
||||
- `airlineCode` must be valid IATA 2-letter code
|
||||
- `originCode`, `destinationCode` must be valid IATA 3-letter codes
|
||||
- `originCode` ≠ `destinationCode`
|
||||
- `departureTime` < `arrivalTime`
|
||||
- `duration` must match calculated time difference
|
||||
- `seatsAvailable` must be >= 0
|
||||
- `price` must be > 0
|
||||
|
||||
**Business Rules**:
|
||||
- Flight times must be realistic for route (e.g., JFK→LAX ~6 hours)
|
||||
- Prices scale with distance and cabin class
|
||||
- sold_out status when seatsAvailable = 0
|
||||
|
||||
### 4. HotelReservation
|
||||
|
||||
Represents a hotel booking segment.
|
||||
|
||||
**Fields**:
|
||||
```typescript
|
||||
{
|
||||
id: string; // Unique reservation identifier
|
||||
hotelCode: string; // Internal hotel identifier
|
||||
hotelName: string; // Hotel property name
|
||||
chainCode: string; // Hotel chain code (e.g., "MAR" for Marriott)
|
||||
chainName: string; // Hotel chain name
|
||||
address: string; // Full address
|
||||
cityCode: string; // IATA city code (e.g., "LAX")
|
||||
cityName: string; // City name
|
||||
checkInDate: string; // ISO 8601 date (YYYY-MM-DD)
|
||||
checkOutDate: string; // ISO 8601 date (YYYY-MM-DD)
|
||||
nights: number; // Calculated night count
|
||||
roomType: string; // e.g., "Standard King", "Deluxe Suite"
|
||||
rateCode: string; // Rate plan code
|
||||
starRating: number; // 1-5 stars
|
||||
price: number; // USD cents, total for stay
|
||||
pricePerNight: number; // USD cents
|
||||
guestCount: number; // Number of guests
|
||||
amenities: string[]; // List of amenities
|
||||
status: enum; // 'available' | 'sold_out' | 'confirmed' | 'cancelled'
|
||||
}
|
||||
```
|
||||
|
||||
**Validation**:
|
||||
- `checkInDate` < `checkOutDate`
|
||||
- `nights` must equal date difference
|
||||
- `starRating` must be 1-5
|
||||
- `guestCount` must be >= 1
|
||||
- `price` must equal `pricePerNight` * `nights`
|
||||
|
||||
**Business Rules**:
|
||||
- Check-in date must not be in the past
|
||||
- Minimum 1 night stay
|
||||
- Prices vary by star rating and city
|
||||
|
||||
### 5. CarRental
|
||||
|
||||
Represents a car rental segment.
|
||||
|
||||
**Fields**:
|
||||
```typescript
|
||||
{
|
||||
id: string; // Unique rental identifier
|
||||
companyCode: string; // Rental company code (e.g., "ZE" for Hertz)
|
||||
companyName: string; // Company name
|
||||
pickupLocationCode: string; // Airport code or location ID
|
||||
pickupLocationName: string; // Location name
|
||||
dropoffLocationCode: string; // Airport code or location ID
|
||||
dropoffLocationName: string; // Location name
|
||||
pickupDate: string; // ISO 8601 datetime
|
||||
dropoffDate: string; // ISO 8601 datetime
|
||||
vehicleClass: enum; // 'economy' | 'compact' | 'midsize' | 'fullsize' | 'suv' | 'luxury'
|
||||
vehicleModel: string; // e.g., "Toyota Camry or similar"
|
||||
dailyRate: number; // USD cents per day
|
||||
totalPrice: number; // USD cents
|
||||
rentalDays: number; // Number of days
|
||||
mileagePolicy: enum; // 'unlimited' | 'limited'
|
||||
insuranceIncluded: boolean;
|
||||
status: enum; // 'available' | 'confirmed' | 'cancelled'
|
||||
}
|
||||
```
|
||||
|
||||
**Validation**:
|
||||
- `pickupDate` < `dropoffDate`
|
||||
- `rentalDays` must match date calculation
|
||||
- `totalPrice` must equal `dailyRate` * `rentalDays`
|
||||
- `pickupLocationCode` should match airport/city code for traveler's destination
|
||||
|
||||
**Business Rules**:
|
||||
- Same-location dropoff preferred (one-way rentals add surcharge)
|
||||
- Pickup date should align with flight arrival
|
||||
- Dropoff date should align with departure flight
|
||||
|
||||
### 6. PNR (Passenger Name Record)
|
||||
|
||||
Represents a complete booking with multiple service segments.
|
||||
|
||||
**Fields**:
|
||||
```typescript
|
||||
{
|
||||
pnr: string; // Unique booking reference (format: TEST-{BASE32})
|
||||
sessionId: string; // Session that created the booking
|
||||
createdAt: number; // Unix timestamp (ms)
|
||||
lastModified: number; // Unix timestamp (ms)
|
||||
status: enum; // 'pending' | 'confirmed' | 'cancelled'
|
||||
passengers: Passenger[]; // Array of passengers
|
||||
flights: FlightSegment[]; // Array of flight segments
|
||||
hotels: HotelReservation[]; // Array of hotel bookings
|
||||
cars: CarRental[]; // Array of car rentals
|
||||
totalPrice: number; // USD cents, sum of all segments
|
||||
currency: string; // Always "USD" for mock data
|
||||
contactEmail: string; // Primary contact email
|
||||
contactPhone: string; // Primary contact phone
|
||||
}
|
||||
```
|
||||
|
||||
**Storage**: Valkey hash at key `gds:session:{sessionId}:booking:{pnr}`
|
||||
|
||||
**Validation**:
|
||||
- `pnr` must match format `TEST-[A-Z0-9]{6}`
|
||||
- Must have at least one passenger
|
||||
- Must have at least one service (flight, hotel, or car)
|
||||
- `totalPrice` must equal sum of all segment prices
|
||||
- `contactEmail` or `contactPhone` required (at least one)
|
||||
|
||||
**State Transitions**:
|
||||
```
|
||||
[Pending] → [Confirmed] → [Cancelled]
|
||||
↓
|
||||
[Modified] → [Confirmed]
|
||||
```
|
||||
|
||||
**Business Rules**:
|
||||
- Cannot modify after cancellation
|
||||
- Hotel dates must overlap with flight dates
|
||||
- Car pickup should align with flight arrival
|
||||
- Multi-city bookings require connecting flights
|
||||
|
||||
### 7. SearchQuery
|
||||
|
||||
Represents a search request (flights, hotels, or cars).
|
||||
|
||||
**Fields**:
|
||||
```typescript
|
||||
{
|
||||
id: string; // Unique search identifier
|
||||
sessionId: string; // Session performing search
|
||||
type: enum; // 'flight' | 'hotel' | 'car'
|
||||
timestamp: number; // Unix timestamp (ms)
|
||||
parameters: object; // Type-specific search params
|
||||
resultCount: number; // Number of results returned
|
||||
responseTime: number; // Milliseconds to generate results
|
||||
}
|
||||
```
|
||||
|
||||
**Storage**: Ephemeral (not persisted), tracked for statistics only
|
||||
|
||||
### 8. MockDataRecord
|
||||
|
||||
Represents a static mock data entry (airports, airlines, hotels, etc.).
|
||||
|
||||
**Fields**:
|
||||
```typescript
|
||||
{
|
||||
type: enum; // 'airport' | 'airline' | 'hotel' | 'car_company'
|
||||
code: string; // IATA/ICAO code or internal ID
|
||||
name: string; // Full name
|
||||
metadata: object; // Type-specific data (coordinates, address, etc.)
|
||||
}
|
||||
```
|
||||
|
||||
**Storage**: In-memory JavaScript modules, not in Valkey
|
||||
|
||||
## Relationships
|
||||
|
||||
### Session ↔ PNR
|
||||
- **Type**: One-to-Many
|
||||
- **Description**: A session can create multiple bookings
|
||||
- **Key**: `sessionId` in PNR references Session
|
||||
- **Cascade**: PNRs remain accessible after session expires (for retrieval)
|
||||
|
||||
### PNR ↔ Passengers
|
||||
- **Type**: One-to-Many
|
||||
- **Description**: A booking contains multiple passengers
|
||||
- **Embedded**: Passengers stored within PNR document
|
||||
- **Constraint**: Minimum 1 passenger per PNR
|
||||
|
||||
### PNR ↔ FlightSegments
|
||||
- **Type**: One-to-Many
|
||||
- **Description**: A booking can include multiple flight legs
|
||||
- **Embedded**: Flights stored within PNR document
|
||||
- **Ordering**: Flights ordered chronologically
|
||||
|
||||
### PNR ↔ HotelReservations
|
||||
- **Type**: One-to-Many
|
||||
- **Description**: A booking can include multiple hotel stays
|
||||
- **Embedded**: Hotels stored within PNR document
|
||||
|
||||
### PNR ↔ CarRentals
|
||||
- **Type**: One-to-Many
|
||||
- **Description**: A booking can include multiple car rentals
|
||||
- **Embedded**: Cars stored within PNR document
|
||||
|
||||
## Data Validation Rules
|
||||
|
||||
### Cross-Entity Validation
|
||||
|
||||
1. **Date Consistency**:
|
||||
- Hotel check-in must be >= flight arrival date
|
||||
- Hotel check-out must be <= return flight departure date
|
||||
- Car pickup must be >= flight arrival date
|
||||
- Car dropoff must be <= return flight departure date
|
||||
|
||||
2. **Location Consistency**:
|
||||
- Hotel city should match flight destination
|
||||
- Car pickup location should match airport or destination city
|
||||
|
||||
3. **Passenger Consistency**:
|
||||
- All segments in a PNR share the same passenger list
|
||||
- Passenger count must match across segments
|
||||
|
||||
4. **Pricing Integrity**:
|
||||
- PNR total must equal sum of all segment prices
|
||||
- Segment prices must be positive integers
|
||||
|
||||
### Validation Timing
|
||||
|
||||
- **Search-time**: Parameter validation (dates, codes, counts)
|
||||
- **Booking-time**: Business rule validation (date logic, location consistency)
|
||||
- **Retrieval-time**: PNR format validation
|
||||
- **Modification-time**: State transition validation (no modification of cancelled bookings)
|
||||
|
||||
## Mock Data Generation Rules
|
||||
|
||||
### Deterministic Generation
|
||||
|
||||
- Same search inputs → same results (when MOCK_DATA_SEED=fixed)
|
||||
- PNR generation uses session-scoped sequence + timestamp hash
|
||||
- Flight schedules fixed based on route (JFK→LAX always ~6 hours)
|
||||
|
||||
### Realistic Constraints
|
||||
|
||||
- Flight prices: $200-$800 domestic economy, $800-$2000 business, $2500+ first
|
||||
- Hotel prices: $80-$150 budget, $150-$300 midrange, $300-$800 luxury
|
||||
- Car rental: $35-$50 economy, $50-$80 midsize, $100-$150 luxury
|
||||
- Flight duration: Calculated from route distance
|
||||
- Availability: 90% flights available, 10% sold out
|
||||
|
||||
### Data Coverage
|
||||
|
||||
- **Airports**: ~100 major airports (top 50 US + top 50 international)
|
||||
- **Airlines**: ~30 major carriers
|
||||
- **Hotels**: ~50 chains/properties across major cities
|
||||
- **Car Companies**: ~6 major rental companies
|
||||
|
||||
## State Management (Valkey)
|
||||
|
||||
### Key Naming Convention
|
||||
|
||||
```
|
||||
gds:session:{sessionId} # Session metadata
|
||||
gds:session:{sessionId}:booking:{pnr} # Individual booking
|
||||
gds:session:{sessionId}:bookings # Set of all PNRs in session
|
||||
gds:session:{sessionId}:searches # List of search IDs
|
||||
gds:stats:bookings:total # Global booking counter
|
||||
gds:stats:sessions:active # Set of active session IDs
|
||||
```
|
||||
|
||||
### TTL Strategy
|
||||
|
||||
- **Sessions**: 1 hour (configurable via MCP_SESSION_TIMEOUT)
|
||||
- **Bookings**: No expiry (persist beyond session for retrieval)
|
||||
- **Search history**: 10 minutes (ephemeral)
|
||||
|
||||
### Data Serialization
|
||||
|
||||
- **Format**: JSON strings for complex objects
|
||||
- **Encoding**: UTF-8
|
||||
- **Compression**: None (mock data is small)
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
### Memory Footprint
|
||||
|
||||
- **Per Session**: ~5KB (metadata only)
|
||||
- **Per Booking**: ~10-30KB (depends on segment count)
|
||||
- **Mock Data**: ~2MB (embedded in code, not in Valkey)
|
||||
|
||||
### Query Patterns
|
||||
|
||||
- **Hot Path**: `GET gds:session:{sessionId}:booking:{pnr}` (booking retrieval)
|
||||
- **Write Path**: `HSET gds:session:{sessionId}:booking:{pnr}` (booking creation)
|
||||
- **Cleanup**: `SCAN` + `DEL` for expired sessions (background job)
|
||||
|
||||
### Indexing
|
||||
|
||||
No secondary indexes required - all queries use primary keys (sessionId, pnr)
|
||||
|
||||
## Next Steps
|
||||
|
||||
Proceed to contract definition (Phase 1 continued):
|
||||
- Define MCP tool schemas in `/contracts/mcp-tools.md`
|
||||
- Create quickstart guide with example usage
|
||||
194
specs/001-mock-gds-server/plan.md
Normal file
194
specs/001-mock-gds-server/plan.md
Normal file
@@ -0,0 +1,194 @@
|
||||
# Implementation Plan: Mock GDS MCP Server
|
||||
|
||||
**Branch**: `001-mock-gds-server` | **Date**: 2026-04-07 | **Spec**: [spec.md](./spec.md)
|
||||
**Input**: Feature specification from `/specs/001-mock-gds-server/spec.md`
|
||||
|
||||
## Summary
|
||||
|
||||
Build a Mock MCP server that simulates Global Distribution System (GDS) functionality for testing and demonstration. The server exposes GDS operations (search, book, retrieve, cancel) as MCP tools, maintains stateful session management for multi-step workflows, uses Valkey for persistence, and packages as a Docker container for easy deployment.
|
||||
|
||||
## Technical Context
|
||||
|
||||
**Language/Version**: Node.js 20 LTS (current stable)
|
||||
**Primary Dependencies**: Minimal libraries - MCP SDK (@modelcontextprotocol/sdk), Valkey client (ioredis), Docker buildx for multi-platform builds
|
||||
**Storage**: Valkey 8.0+ (Redis-compatible in-memory store with persistence)
|
||||
**Testing**: Node.js native test runner (node:test) with minimal external dependencies
|
||||
**Target Platform**: Docker containers (Linux amd64/arm64), deployable via docker-compose
|
||||
**Project Type**: MCP server (daemon/service)
|
||||
**Performance Goals**: <2s search response time, 50+ concurrent sessions, <500ms booking operations
|
||||
**Constraints**: Minimal dependencies (avoid framework bloat), stateless server design (state in Valkey), zero external API calls
|
||||
**Scale/Scope**: Single-server deployment, 1000+ bookings/session, 100+ concurrent MCP connections
|
||||
|
||||
## Constitution Check
|
||||
|
||||
*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
|
||||
|
||||
### Principle I: MCP Protocol Compliance (NON-NEGOTIABLE)
|
||||
- ✅ **Conformance**: Using official @modelcontextprotocol/sdk ensures protocol compliance
|
||||
- ✅ **JSON-RPC 2.0**: SDK handles message format automatically
|
||||
- ✅ **Capability Declaration**: Server will declare tools during initialization handshake
|
||||
- ✅ **Error Codes**: SDK provides standard MCP error structures
|
||||
|
||||
**Status**: PASS - Using official SDK guarantees protocol compliance
|
||||
|
||||
### Principle II: Mock Data Realism
|
||||
- ✅ **GDS Structures**: Will implement SABRE/Amadeus/Galileo-style response formats
|
||||
- ✅ **Valid IATA/ICAO Codes**: Mock data will use real airport (JFK, LAX) and airline (AA, DL, UA) codes
|
||||
- ✅ **Realistic Pricing**: Price ranges match market expectations ($200-$800 domestic flights)
|
||||
- ✅ **Real-World Constraints**: Flight times, connection logic, geography respected
|
||||
- ✅ **Edge Cases**: Will include sold-out flights, price variations, booking errors
|
||||
|
||||
**Status**: PASS - Spec requirements align with realism principle
|
||||
|
||||
### Principle III: No Real Transactions (Safety Guarantee)
|
||||
- ✅ **Zero External Connections**: No real GDS APIs called (all data from Valkey/memory)
|
||||
- ✅ **Simulated Operations**: All bookings are mock data only
|
||||
- ✅ **TEST Markers**: PNRs will have "TEST-" prefix (e.g., TEST-ABC123)
|
||||
- ✅ **Documentation**: README will include prominent "FOR TESTING AND DEMO PURPOSES ONLY" disclaimer
|
||||
- ✅ **Configuration Safety**: No production API key acceptance (configuration validates against production patterns)
|
||||
|
||||
**Status**: PASS - Safety guarantees built into design
|
||||
|
||||
### Principle IV: Tool-Based Architecture
|
||||
- ✅ **MCP Tools**: Each operation exposed as tool (searchFlights, bookFlight, retrieveBooking, cancelBooking, searchHotels, bookHotel, searchCars, bookCar)
|
||||
- ✅ **Self-Documenting**: JSON schemas with descriptions and validation
|
||||
- ✅ **Independent Tools**: Each tool callable without dependencies
|
||||
- ✅ **Deterministic**: Same inputs produce same outputs (controlled randomness for demo variety)
|
||||
- ✅ **Resources**: Will expose resources for session state inspection
|
||||
|
||||
**Status**: PASS - Tool-based design matches MCP patterns
|
||||
|
||||
### Principle V: Stateful Session Management
|
||||
- ✅ **Session State**: Valkey stores session data (searches, bookings, PNRs)
|
||||
- ✅ **Isolation**: Session ID scopes all data (no cross-session leakage)
|
||||
- ✅ **Explicit Transitions**: search → price → book → confirm flow tracked
|
||||
- ✅ **Cleanup**: TTL on session keys for automatic expiry
|
||||
- ✅ **Optional Persistence**: Valkey persistence configurable (RDB/AOF)
|
||||
|
||||
**Status**: PASS - Valkey provides robust session management
|
||||
|
||||
### Principle VI: Observable and Debuggable
|
||||
- ✅ **Structured Logging**: Pino logger with operation type, parameters, results
|
||||
- ✅ **Error Classification**: Client errors (4xx), server errors (5xx), success (2xx)
|
||||
- ✅ **Configurable Verbosity**: LOG_LEVEL env var (silent, error, warn, info, debug, trace)
|
||||
- ✅ **Actionable Errors**: Clear messages ("Invalid airport code 'XYZ': must be 3-letter IATA")
|
||||
- ✅ **Inspection**: MCP resource endpoints for session list, booking history
|
||||
|
||||
**Status**: PASS - Logging and observability built in
|
||||
|
||||
### Overall Gate Status: ✅ PASS
|
||||
All constitution principles satisfied. Proceed with Phase 0 research.
|
||||
|
||||
## Project Structure
|
||||
|
||||
### Documentation (this feature)
|
||||
|
||||
```text
|
||||
specs/[###-feature]/
|
||||
├── plan.md # This file (/speckit.plan command output)
|
||||
├── research.md # Phase 0 output (/speckit.plan command)
|
||||
├── data-model.md # Phase 1 output (/speckit.plan command)
|
||||
├── quickstart.md # Phase 1 output (/speckit.plan command)
|
||||
├── contracts/ # Phase 1 output (/speckit.plan command)
|
||||
└── tasks.md # Phase 2 output (/speckit.tasks command - NOT created by /speckit.plan)
|
||||
```
|
||||
|
||||
### Source Code (repository root)
|
||||
|
||||
```text
|
||||
src/
|
||||
├── index.js # MCP server entry point
|
||||
├── server.js # MCP server initialization
|
||||
├── tools/ # MCP tool handlers
|
||||
│ ├── flights.js # searchFlights, bookFlight
|
||||
│ ├── hotels.js # searchHotels, bookHotel
|
||||
│ ├── cars.js # searchCars, bookCar
|
||||
│ └── bookings.js # retrieveBooking, cancelBooking
|
||||
├── data/ # Mock data generators
|
||||
│ ├── airports.js # IATA airport codes and data
|
||||
│ ├── airlines.js # Airline codes and metadata
|
||||
│ ├── hotels.js # Hotel chains and properties
|
||||
│ ├── cars.js # Car rental companies and types
|
||||
│ └── pnr.js # PNR generation utilities
|
||||
├── session/ # Session management
|
||||
│ ├── manager.js # Session lifecycle
|
||||
│ └── storage.js # Valkey client wrapper
|
||||
├── validation/ # Input validation
|
||||
│ ├── schemas.js # JSON schemas for tools
|
||||
│ └── validators.js # Validation logic
|
||||
└── utils/ # Shared utilities
|
||||
├── logger.js # Pino logger setup
|
||||
└── errors.js # Error handling
|
||||
|
||||
tests/
|
||||
├── integration/ # End-to-end MCP workflows
|
||||
│ ├── flight-booking.test.js
|
||||
│ ├── multi-service.test.js
|
||||
│ └── concurrent-sessions.test.js
|
||||
├── unit/ # Tool and data tests
|
||||
│ ├── tools/
|
||||
│ ├── data/
|
||||
│ └── session/
|
||||
└── fixtures/ # Test data
|
||||
|
||||
docker/
|
||||
├── Dockerfile # Multi-stage build
|
||||
└── docker-bake.hcl # Buildx bake configuration
|
||||
|
||||
docker-compose.yaml # Local dev/test environment
|
||||
package.json # Dependencies and scripts
|
||||
.dockerignore # Build exclusions
|
||||
README.md # Setup and usage
|
||||
```
|
||||
|
||||
**Structure Decision**: Single project layout selected. The Mock GDS MCP server is a standalone daemon with embedded mock data. All source code in `src/`, organized by functional concerns (tools, data, session, validation, utils). Docker configuration in `docker/` directory with multi-stage Dockerfile and buildx bake configuration. Tests organized by type (unit, integration) with shared fixtures.
|
||||
|
||||
## Phase 0: Research & Technology Decisions (COMPLETED)
|
||||
|
||||
**Status**: ✅ Complete
|
||||
**Output**: `research.md`
|
||||
**Completion Date**: 2026-04-07
|
||||
|
||||
All technical unknowns resolved:
|
||||
- MCP SDK selection (@modelcontextprotocol/sdk)
|
||||
- Valkey client library (ioredis)
|
||||
- Minimal dependencies strategy (Pino for logging, native test runner)
|
||||
- Docker buildx bake configuration
|
||||
- Mock data architecture (embedded, deterministic generation)
|
||||
- PNR generation strategy (TEST- prefix with base32)
|
||||
- Configuration management (environment variables)
|
||||
- Testing strategy (3-tier: unit, integration, contract)
|
||||
|
||||
## Phase 1: Design & Contracts (COMPLETED)
|
||||
|
||||
**Status**: ✅ Complete
|
||||
**Output**: `data-model.md`, `contracts/mcp-tools.md`, `quickstart.md`
|
||||
**Completion Date**: 2026-04-07
|
||||
|
||||
Design artifacts created:
|
||||
- **Data Model**: 8 core entities (Session, Passenger, FlightSegment, HotelReservation, CarRental, PNR, SearchQuery, MockDataRecord)
|
||||
- **MCP Tool Contracts**: 8 tools defined with JSON schemas (searchFlights, bookFlight, searchHotels, bookHotel, searchCars, bookCar, retrieveBooking, cancelBooking, listBookings)
|
||||
- **Quick Start Guide**: Complete usage examples for all workflows
|
||||
- **Agent Context**: Updated Copilot context with Node.js, MCP SDK, Valkey stack
|
||||
|
||||
### Post-Design Constitution Re-Check
|
||||
|
||||
All principles remain satisfied after detailed design:
|
||||
|
||||
- ✅ **Principle I (MCP Protocol)**: Tool schemas follow JSON-RPC 2.0 specification
|
||||
- ✅ **Principle II (Mock Data Realism)**: Data model includes valid IATA codes, realistic pricing tiers
|
||||
- ✅ **Principle III (No Real Transactions)**: PNR format enforces TEST- prefix, no external APIs
|
||||
- ✅ **Principle IV (Tool Architecture)**: 8 independent tools with clear schemas
|
||||
- ✅ **Principle V (Session Management)**: Valkey key naming and TTL strategy defined
|
||||
- ✅ **Principle VI (Observability)**: Error codes, logging strategy, inspection resources specified
|
||||
|
||||
**Final Gate Status**: ✅ PASS - Ready for task generation
|
||||
|
||||
## Complexity Tracking
|
||||
|
||||
> **Fill ONLY if Constitution Check has violations that must be justified**
|
||||
|
||||
| Violation | Why Needed | Simpler Alternative Rejected Because |
|
||||
|-----------|------------|-------------------------------------|
|
||||
| [e.g., 4th project] | [current need] | [why 3 projects insufficient] |
|
||||
| [e.g., Repository pattern] | [specific problem] | [why direct DB access insufficient] |
|
||||
508
specs/001-mock-gds-server/quickstart.md
Normal file
508
specs/001-mock-gds-server/quickstart.md
Normal file
@@ -0,0 +1,508 @@
|
||||
# Quick Start Guide: Mock GDS MCP Server
|
||||
|
||||
**Branch**: `001-mock-gds-server` | **Date**: 2026-04-07
|
||||
|
||||
## Overview
|
||||
|
||||
This guide demonstrates how to use the Mock GDS MCP Server for testing travel applications. All examples use mock data with the TEST- prefix for safety.
|
||||
|
||||
---
|
||||
|
||||
## Installation & Setup
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Node.js 20 LTS or later
|
||||
- Docker & Docker Compose (for Valkey)
|
||||
- MCP-compatible client
|
||||
|
||||
### Running with Docker Compose
|
||||
|
||||
```bash
|
||||
# Start the mock GDS server and Valkey
|
||||
docker-compose up -d
|
||||
|
||||
# View logs
|
||||
docker-compose logs -f gds-mock-mcp
|
||||
|
||||
# Stop services
|
||||
docker-compose down
|
||||
```
|
||||
|
||||
### Configuration
|
||||
|
||||
Create a `.env` file (optional, defaults shown):
|
||||
|
||||
```bash
|
||||
# MCP Server
|
||||
MCP_TRANSPORT=stdio
|
||||
MCP_SESSION_TIMEOUT=3600
|
||||
|
||||
# Valkey
|
||||
VALKEY_HOST=valkey
|
||||
VALKEY_PORT=6379
|
||||
VALKEY_PASSWORD=
|
||||
VALKEY_DB=0
|
||||
|
||||
# Logging
|
||||
LOG_LEVEL=info
|
||||
LOG_PRETTY=false
|
||||
|
||||
# Mock Data
|
||||
MOCK_DATA_SEED=fixed
|
||||
MOCK_RESPONSE_DELAY=0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Basic Workflows
|
||||
|
||||
### 1. Search and Book a Flight
|
||||
|
||||
**Step 1: Search for flights**
|
||||
|
||||
```javascript
|
||||
// MCP tool call
|
||||
{
|
||||
"tool": "searchFlights",
|
||||
"arguments": {
|
||||
"origin": "JFK",
|
||||
"destination": "LAX",
|
||||
"departureDate": "2026-06-15",
|
||||
"passengers": { "adults": 1 },
|
||||
"cabin": "economy"
|
||||
}
|
||||
}
|
||||
|
||||
// Response
|
||||
{
|
||||
"searchId": "search_abc123",
|
||||
"flights": [
|
||||
{
|
||||
"id": "flight_1",
|
||||
"flightNumber": "AA123",
|
||||
"airline": { "code": "AA", "name": "American Airlines" },
|
||||
"departure": { "time": "2026-06-15T08:00:00Z", "airport": "JFK" },
|
||||
"arrival": { "time": "2026-06-15T11:30:00Z", "airport": "LAX" },
|
||||
"price": 29900, // $299.00
|
||||
"seatsAvailable": 45,
|
||||
"status": "available"
|
||||
},
|
||||
// ... more flights
|
||||
],
|
||||
"resultCount": 5
|
||||
}
|
||||
```
|
||||
|
||||
**Step 2: Book the selected flight**
|
||||
|
||||
```javascript
|
||||
// MCP tool call
|
||||
{
|
||||
"tool": "bookFlight",
|
||||
"arguments": {
|
||||
"flightIds": ["flight_1"],
|
||||
"passengers": [
|
||||
{
|
||||
"type": "adult",
|
||||
"firstName": "John",
|
||||
"lastName": "Doe",
|
||||
"email": "john.doe@example.com"
|
||||
}
|
||||
],
|
||||
"contactEmail": "john.doe@example.com"
|
||||
}
|
||||
}
|
||||
|
||||
// Response
|
||||
{
|
||||
"pnr": "TEST-A1B2C3", // Note: TEST- prefix for safety
|
||||
"status": "confirmed",
|
||||
"bookingDate": "2026-04-07T16:30:00Z",
|
||||
"passengers": [{ "firstName": "John", "lastName": "Doe" }],
|
||||
"flights": [{ /* flight details */ }],
|
||||
"totalPrice": 29900,
|
||||
"currency": "USD"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. Multi-Service Booking (Flight + Hotel)
|
||||
|
||||
**Step 1: Book a flight (as above)**
|
||||
|
||||
Result: `pnr = "TEST-A1B2C3"`
|
||||
|
||||
**Step 2: Search for hotels**
|
||||
|
||||
```javascript
|
||||
{
|
||||
"tool": "searchHotels",
|
||||
"arguments": {
|
||||
"cityCode": "LAX",
|
||||
"checkInDate": "2026-06-15",
|
||||
"checkOutDate": "2026-06-17",
|
||||
"guests": 1
|
||||
}
|
||||
}
|
||||
|
||||
// Response
|
||||
{
|
||||
"hotels": [
|
||||
{
|
||||
"id": "hotel_1",
|
||||
"name": "Marriott Los Angeles Downtown",
|
||||
"starRating": 4,
|
||||
"pricePerNight": 18000, // $180.00
|
||||
"totalPrice": 36000, // 2 nights
|
||||
"amenities": ["WiFi", "Pool", "Gym", "Parking"]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Step 3: Add hotel to existing booking**
|
||||
|
||||
```javascript
|
||||
{
|
||||
"tool": "bookHotel",
|
||||
"arguments": {
|
||||
"hotelId": "hotel_1",
|
||||
"existingPnr": "TEST-A1B2C3", // Add to flight booking
|
||||
"guests": [
|
||||
{
|
||||
"firstName": "John",
|
||||
"lastName": "Doe",
|
||||
"email": "john.doe@example.com"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
// Response
|
||||
{
|
||||
"pnr": "TEST-A1B2C3", // Same PNR, now includes hotel
|
||||
"flights": [{ /* flight */ }],
|
||||
"hotels": [{ /* hotel */ }],
|
||||
"totalPrice": 65900 // $299 flight + $360 hotel
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. Complete Travel Package (Flight + Hotel + Car)
|
||||
|
||||
**Step 1-2: Book flight and hotel** (as above)
|
||||
|
||||
Result: `pnr = "TEST-A1B2C3"`
|
||||
|
||||
**Step 3: Search for rental cars**
|
||||
|
||||
```javascript
|
||||
{
|
||||
"tool": "searchCars",
|
||||
"arguments": {
|
||||
"pickupLocationCode": "LAX",
|
||||
"pickupDate": "2026-06-15T12:00:00Z",
|
||||
"dropoffDate": "2026-06-17T10:00:00Z"
|
||||
}
|
||||
}
|
||||
|
||||
// Response
|
||||
{
|
||||
"cars": [
|
||||
{
|
||||
"id": "car_1",
|
||||
"companyName": "Hertz",
|
||||
"vehicleClass": "economy",
|
||||
"vehicleModel": "Toyota Corolla or similar",
|
||||
"dailyRate": 4500, // $45/day
|
||||
"totalPrice": 9000, // 2 days
|
||||
"mileagePolicy": "unlimited"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Step 4: Add car to booking**
|
||||
|
||||
```javascript
|
||||
{
|
||||
"tool": "bookCar",
|
||||
"arguments": {
|
||||
"carId": "car_1",
|
||||
"existingPnr": "TEST-A1B2C3",
|
||||
"driver": {
|
||||
"firstName": "John",
|
||||
"lastName": "Doe",
|
||||
"age": 35
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Response
|
||||
{
|
||||
"pnr": "TEST-A1B2C3",
|
||||
"flights": [{ /* flight */ }],
|
||||
"hotels": [{ /* hotel */ }],
|
||||
"cars": [{ /* car */ }],
|
||||
"totalPrice": 74900 // $299 + $360 + $90
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4. Retrieve and Manage Bookings
|
||||
|
||||
**Retrieve a booking by PNR**
|
||||
|
||||
```javascript
|
||||
{
|
||||
"tool": "retrieveBooking",
|
||||
"arguments": {
|
||||
"pnr": "TEST-A1B2C3"
|
||||
}
|
||||
}
|
||||
|
||||
// Response: Full booking details
|
||||
```
|
||||
|
||||
**List all bookings in session**
|
||||
|
||||
```javascript
|
||||
{
|
||||
"tool": "listBookings",
|
||||
"arguments": {
|
||||
"status": "all"
|
||||
}
|
||||
}
|
||||
|
||||
// Response
|
||||
{
|
||||
"bookings": [
|
||||
{
|
||||
"pnr": "TEST-A1B2C3",
|
||||
"status": "confirmed",
|
||||
"createdAt": "2026-04-07T16:30:00Z",
|
||||
"passengerCount": 1,
|
||||
"segmentCounts": { "flights": 1, "hotels": 1, "cars": 1 },
|
||||
"totalPrice": 74900
|
||||
}
|
||||
],
|
||||
"totalCount": 1
|
||||
}
|
||||
```
|
||||
|
||||
**Cancel a booking**
|
||||
|
||||
```javascript
|
||||
{
|
||||
"tool": "cancelBooking",
|
||||
"arguments": {
|
||||
"pnr": "TEST-A1B2C3",
|
||||
"reason": "Travel plans changed"
|
||||
}
|
||||
}
|
||||
|
||||
// Response
|
||||
{
|
||||
"pnr": "TEST-A1B2C3",
|
||||
"status": "cancelled",
|
||||
"cancelledAt": "2026-04-07T17:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Testing Scenarios
|
||||
|
||||
### Concurrent Sessions
|
||||
|
||||
```javascript
|
||||
// Session 1
|
||||
const session1 = createMCPConnection();
|
||||
const booking1 = await session1.call("bookFlight", { /* ... */ });
|
||||
// booking1.pnr = "TEST-A1B2C3"
|
||||
|
||||
// Session 2 (different MCP connection)
|
||||
const session2 = createMCPConnection();
|
||||
const booking2 = await session2.call("bookFlight", { /* ... */ });
|
||||
// booking2.pnr = "TEST-X7Y8Z9" // Different PNR
|
||||
|
||||
// Sessions are isolated - cannot retrieve booking1 from session2
|
||||
await session2.call("retrieveBooking", { pnr: "TEST-A1B2C3" });
|
||||
// Error: PNR not found in current session
|
||||
```
|
||||
|
||||
### Error Handling
|
||||
|
||||
**Invalid airport code**
|
||||
|
||||
```javascript
|
||||
{
|
||||
"tool": "searchFlights",
|
||||
"arguments": {
|
||||
"origin": "ZZZ", // Invalid code
|
||||
"destination": "LAX",
|
||||
"departureDate": "2026-06-15"
|
||||
}
|
||||
}
|
||||
|
||||
// Error response
|
||||
{
|
||||
"code": -32602,
|
||||
"message": "Invalid airport code 'ZZZ': must be a valid 3-letter IATA code",
|
||||
"data": { "field": "origin", "value": "ZZZ" }
|
||||
}
|
||||
```
|
||||
|
||||
**Date in the past**
|
||||
|
||||
```javascript
|
||||
{
|
||||
"tool": "searchFlights",
|
||||
"arguments": {
|
||||
"origin": "JFK",
|
||||
"destination": "LAX",
|
||||
"departureDate": "2020-01-01" // Past date
|
||||
}
|
||||
}
|
||||
|
||||
// Error response
|
||||
{
|
||||
"code": -32002,
|
||||
"message": "Departure date cannot be in the past",
|
||||
"data": { "field": "departureDate", "value": "2020-01-01" }
|
||||
}
|
||||
```
|
||||
|
||||
**Cancelled booking modification**
|
||||
|
||||
```javascript
|
||||
// First cancel
|
||||
await call("cancelBooking", { pnr: "TEST-A1B2C3" });
|
||||
|
||||
// Try to add hotel to cancelled booking
|
||||
await call("bookHotel", {
|
||||
hotelId: "hotel_1",
|
||||
existingPnr: "TEST-A1B2C3"
|
||||
});
|
||||
|
||||
// Error response
|
||||
{
|
||||
"code": -32002,
|
||||
"message": "Cannot modify cancelled booking TEST-A1B2C3",
|
||||
"data": { "pnr": "TEST-A1B2C3", "status": "cancelled" }
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Integration Testing Example
|
||||
|
||||
```javascript
|
||||
// Example integration test (using Node.js test runner)
|
||||
import { test } from 'node:test';
|
||||
import { strict as assert } from 'node:assert';
|
||||
import { MCPClient } from './mcp-client.js';
|
||||
|
||||
test('complete booking workflow', async (t) => {
|
||||
const client = new MCPClient();
|
||||
|
||||
// Search flights
|
||||
const searchResults = await client.call('searchFlights', {
|
||||
origin: 'JFK',
|
||||
destination: 'LAX',
|
||||
departureDate: '2026-06-15',
|
||||
passengers: { adults: 1 }
|
||||
});
|
||||
|
||||
assert.ok(searchResults.flights.length > 0);
|
||||
const flight = searchResults.flights[0];
|
||||
|
||||
// Book flight
|
||||
const booking = await client.call('bookFlight', {
|
||||
flightIds: [flight.id],
|
||||
passengers: [{
|
||||
type: 'adult',
|
||||
firstName: 'Test',
|
||||
lastName: 'User',
|
||||
email: 'test@example.com'
|
||||
}],
|
||||
contactEmail: 'test@example.com'
|
||||
});
|
||||
|
||||
assert.match(booking.pnr, /^TEST-[A-Z0-9]{6}$/);
|
||||
assert.equal(booking.status, 'confirmed');
|
||||
|
||||
// Retrieve booking
|
||||
const retrieved = await client.call('retrieveBooking', {
|
||||
pnr: booking.pnr
|
||||
});
|
||||
|
||||
assert.equal(retrieved.pnr, booking.pnr);
|
||||
assert.equal(retrieved.flights.length, 1);
|
||||
|
||||
// Cancel booking
|
||||
const cancelled = await client.call('cancelBooking', {
|
||||
pnr: booking.pnr
|
||||
});
|
||||
|
||||
assert.equal(cancelled.status, 'cancelled');
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Mock Data Reference
|
||||
|
||||
### Supported Airports
|
||||
|
||||
Major US: JFK, LAX, ORD, DFW, ATL, MIA, SFO, SEA, BOS, LAS
|
||||
International: LHR, CDG, FRA, NRT, HKG, SYD, DXB
|
||||
|
||||
### Supported Airlines
|
||||
|
||||
- American Airlines (AA)
|
||||
- Delta Air Lines (DL)
|
||||
- United Airlines (UA)
|
||||
- Southwest Airlines (WN)
|
||||
- British Airways (BA)
|
||||
- Virgin Atlantic (VS)
|
||||
- Lufthansa (LH)
|
||||
- Air France (AF)
|
||||
|
||||
### Price Ranges
|
||||
|
||||
- **Flights**: $200-$800 (economy domestic), $800-$2000 (business), $2500+ (first)
|
||||
- **Hotels**: $80-$150 (budget), $150-$300 (mid-range), $300-$800 (luxury)
|
||||
- **Cars**: $35-$50 (economy), $50-$80 (midsize), $100-$150 (luxury)
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Server won't start
|
||||
|
||||
Check Valkey connection:
|
||||
```bash
|
||||
docker-compose logs valkey
|
||||
```
|
||||
|
||||
### Session expires
|
||||
|
||||
Default timeout: 1 hour. Adjust with `MCP_SESSION_TIMEOUT` env var.
|
||||
|
||||
### PNR not found
|
||||
|
||||
Verify you're retrieving from the same session that created the booking.
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
- Explore all available tools in `/contracts/mcp-tools.md`
|
||||
- Review data model in `/data-model.md`
|
||||
- Check technical research in `/research.md`
|
||||
- See implementation tasks in `/tasks.md` (after running `/speckit.tasks`)
|
||||
299
specs/001-mock-gds-server/research.md
Normal file
299
specs/001-mock-gds-server/research.md
Normal file
@@ -0,0 +1,299 @@
|
||||
# Technical Research: Mock GDS MCP Server
|
||||
|
||||
**Branch**: `001-mock-gds-server` | **Date**: 2026-04-07
|
||||
|
||||
## Phase 0: Technology Decisions
|
||||
|
||||
### Decision 1: MCP SDK and Protocol Implementation
|
||||
|
||||
**Decision**: Use `@modelcontextprotocol/sdk` official Node.js SDK
|
||||
|
||||
**Rationale**:
|
||||
- Official SDK ensures MCP protocol compliance (Constitution Principle I)
|
||||
- Handles JSON-RPC 2.0 message format automatically
|
||||
- Provides TypeScript types for type safety
|
||||
- Active maintenance by Anthropic
|
||||
- Simplified tool registration and schema management
|
||||
|
||||
**Alternatives Considered**:
|
||||
- **Custom MCP implementation**: Rejected - high risk of protocol non-compliance, significant development effort
|
||||
- **Python MCP SDK**: Rejected - requirement specifies Node.js with minimal dependencies
|
||||
|
||||
**Implementation Notes**:
|
||||
- SDK provides `Server` class for initialization
|
||||
- Tool handlers registered via `server.setRequestHandler`
|
||||
- Automatic capability negotiation during handshake
|
||||
- Built-in error handling with standard MCP error codes
|
||||
|
||||
### Decision 2: Valkey Client Library
|
||||
|
||||
**Decision**: Use `ioredis` v5.x as Valkey client
|
||||
|
||||
**Rationale**:
|
||||
- Valkey is Redis protocol-compatible, ioredis is the most mature Node.js Redis client
|
||||
- Full support for Redis/Valkey commands (GET, SET, HSET, EXPIRE, etc.)
|
||||
- Connection pooling and automatic reconnection
|
||||
- Cluster and sentinel support (for future scaling)
|
||||
- Pipeline and transaction support
|
||||
- Active maintenance and TypeScript support
|
||||
|
||||
**Alternatives Considered**:
|
||||
- **node-redis**: Rejected - ioredis has better TypeScript support and more features
|
||||
- **Custom Valkey protocol**: Rejected - unnecessarily complex
|
||||
- **No persistence (memory-only)**: Rejected - requirement specifies Valkey for persistence
|
||||
|
||||
**Implementation Notes**:
|
||||
- Use Redis-compatible commands only (avoid Redis-specific extensions)
|
||||
- Session data stored with TTL (e.g., 1 hour default)
|
||||
- Key naming: `gds:session:{sessionId}:bookings:{pnr}`
|
||||
- Use hash structures for complex objects (bookings, searches)
|
||||
- Enable Valkey RDB/AOF persistence via docker-compose configuration
|
||||
|
||||
### Decision 3: Minimal Dependencies Strategy
|
||||
|
||||
**Decision**: Limit external dependencies to essentials only
|
||||
|
||||
**Core Dependencies** (production):
|
||||
1. `@modelcontextprotocol/sdk` - MCP protocol (required)
|
||||
2. `ioredis` - Valkey client (required for persistence)
|
||||
3. `pino` - Structured logging (minimal, fast, constitution requires observability)
|
||||
|
||||
**Development Dependencies**:
|
||||
- Node.js native test runner (`node:test`) - no jest/mocha overhead
|
||||
- `c8` - code coverage (lightweight)
|
||||
|
||||
**Rationale**:
|
||||
- Aligns with "minimal libraries" requirement
|
||||
- Reduces attack surface and dependency maintenance burden
|
||||
- Faster container builds and smaller images
|
||||
- Native Node.js features (test runner, assert) are mature and sufficient
|
||||
|
||||
**Explicitly Avoided**:
|
||||
- ❌ Express/Fastify/Koa - MCP uses stdio/SSE, no HTTP server needed
|
||||
- ❌ TypeORM/Prisma - direct Valkey commands sufficient for key-value storage
|
||||
- ❌ Jest/Mocha - native test runner adequate
|
||||
- ❌ Lodash/Ramda - native JS methods sufficient
|
||||
- ❌ Moment.js/date-fns - native Date and Temporal API (when available)
|
||||
|
||||
### Decision 4: Docker Build Strategy
|
||||
|
||||
**Decision**: Use Docker Buildx with `docker-bake.hcl` for multi-platform builds
|
||||
|
||||
**Rationale**:
|
||||
- `docker buildx bake` supports complex build configurations
|
||||
- Multi-platform builds (linux/amd64, linux/arm64) in single command
|
||||
- Build matrix for multiple tags (latest, version, dev)
|
||||
- Better caching and parallelization than traditional Dockerfile
|
||||
- Aligns with requirement specification
|
||||
|
||||
**Build Configuration**:
|
||||
```hcl
|
||||
# docker-bake.hcl
|
||||
target "default" {
|
||||
dockerfile = "docker/Dockerfile"
|
||||
tags = ["gds-mock-mcp:latest"]
|
||||
platforms = ["linux/amd64", "linux/arm64"]
|
||||
cache-from = ["type=registry,ref=gds-mock-mcp:buildcache"]
|
||||
cache-to = ["type=registry,ref=gds-mock-mcp:buildcache,mode=max"]
|
||||
}
|
||||
```
|
||||
|
||||
**Dockerfile Strategy**:
|
||||
- Multi-stage build: builder → production
|
||||
- Builder stage: install dependencies, run tests
|
||||
- Production stage: copy only production deps and source
|
||||
- Use Node.js 20 Alpine for minimal image size
|
||||
- Non-root user for security
|
||||
- Health check via MCP ping or valkey connection test
|
||||
|
||||
**Alternatives Considered**:
|
||||
- **Traditional Dockerfile only**: Rejected - buildx bake provides better DX and multi-platform support
|
||||
- **Docker Compose build**: Rejected - less flexible than buildx, no multi-platform
|
||||
- **Podman**: Rejected - Docker specified in requirements
|
||||
|
||||
### Decision 5: Mock Data Architecture
|
||||
|
||||
**Decision**: Embed realistic GDS data in JavaScript modules with deterministic generation
|
||||
|
||||
**Data Structure**:
|
||||
- **Airports**: ~100 major airports with IATA codes (JFK, LAX, ORD, etc.)
|
||||
- **Airlines**: Major carriers with IATA codes (AA, DL, UA, BA, etc.)
|
||||
- **Hotels**: 50+ chains/properties across major cities
|
||||
- **Car Rentals**: Major companies (Hertz, Avis, Enterprise) with vehicle types
|
||||
- **Flight Routes**: Pre-defined routes with realistic times and prices
|
||||
- **Pricing Tiers**: Economy ($200-$600 domestic), Business ($800-$2000), First Class ($2500+)
|
||||
|
||||
**Generation Strategy**:
|
||||
- Deterministic: Same search inputs produce same results (for testing reproducibility)
|
||||
- Controlled Randomness: Optional seed parameter for demo variety
|
||||
- Rule-Based Pricing: Distance-based pricing with time-of-day adjustments
|
||||
- Availability Simulation: Random sold-out scenarios (10% of flights)
|
||||
|
||||
**Rationale**:
|
||||
- Embedded data = no external dependencies (fast startup)
|
||||
- Deterministic = reliable integration tests
|
||||
- Realistic codes = constitution compliance (Principle II)
|
||||
- Pre-computed routes = sub-2s response times
|
||||
|
||||
**Alternatives Considered**:
|
||||
- **External API (Skyscanner, etc.)**: Rejected - violates "no external connections" (Constitution Principle III)
|
||||
- **Database seeding**: Rejected - overhead, embedded data sufficient for mock scope
|
||||
- **Fully random data**: Rejected - testing requires deterministic outputs
|
||||
|
||||
### Decision 6: Testing Strategy
|
||||
|
||||
**Decision**: Use Node.js native test runner with three-tier test structure
|
||||
|
||||
**Test Tiers**:
|
||||
1. **Unit Tests**: Individual tool handlers, data generators, validators
|
||||
- Fast (<100ms total), isolated, no external dependencies
|
||||
- Mock Valkey client for session tests
|
||||
|
||||
2. **Integration Tests**: Full MCP workflows with real Valkey (test container)
|
||||
- End-to-end booking flows (search → book → retrieve → cancel)
|
||||
- Multi-service workflows (flight + hotel + car)
|
||||
- Concurrent session isolation tests
|
||||
- Use docker-compose test profile for Valkey
|
||||
|
||||
3. **Contract Tests**: MCP protocol compliance validation
|
||||
- Verify JSON-RPC 2.0 format
|
||||
- Tool schema validation
|
||||
- Error response structure
|
||||
|
||||
**Test Execution**:
|
||||
```bash
|
||||
npm test # All tests
|
||||
npm run test:unit # Fast unit tests only
|
||||
npm run test:integration # Requires Valkey
|
||||
npm run test:coverage # Coverage report with c8
|
||||
```
|
||||
|
||||
**Rationale**:
|
||||
- Native test runner = minimal dependencies
|
||||
- Three tiers = appropriate test coverage
|
||||
- Docker test containers = realistic integration tests
|
||||
- Fast unit tests = quick feedback loop
|
||||
|
||||
### Decision 7: Configuration Management
|
||||
|
||||
**Decision**: Environment variables with secure defaults
|
||||
|
||||
**Configuration Variables**:
|
||||
```bash
|
||||
# MCP Server
|
||||
MCP_TRANSPORT=stdio # stdio or sse
|
||||
MCP_SESSION_TIMEOUT=3600 # 1 hour session TTL
|
||||
|
||||
# Valkey
|
||||
VALKEY_HOST=localhost
|
||||
VALKEY_PORT=6379
|
||||
VALKEY_PASSWORD= # Empty for dev, required for prod
|
||||
VALKEY_DB=0
|
||||
VALKEY_KEY_PREFIX=gds:
|
||||
|
||||
# Logging
|
||||
LOG_LEVEL=info # silent, error, warn, info, debug, trace
|
||||
LOG_PRETTY=false # Pretty print for dev
|
||||
|
||||
# Mock Data
|
||||
MOCK_DATA_SEED=fixed # fixed or random
|
||||
MOCK_RESPONSE_DELAY=0 # Artificial delay (ms) for demo purposes
|
||||
```
|
||||
|
||||
**Security Defaults**:
|
||||
- No production credentials in code or .env.example
|
||||
- Configuration validation on startup
|
||||
- Reject production-like patterns (Constitution Principle III)
|
||||
|
||||
**Rationale**:
|
||||
- Standard practice for containerized apps
|
||||
- Easy to override in docker-compose
|
||||
- Secure defaults prevent accidents
|
||||
|
||||
### Decision 8: PNR Generation Strategy
|
||||
|
||||
**Decision**: Deterministic PNR generation with TEST prefix
|
||||
|
||||
**Format**: `TEST-{BASE32}` where BASE32 is 6 characters
|
||||
|
||||
**Example**: `TEST-A1B2C3`
|
||||
|
||||
**Generation Algorithm**:
|
||||
1. Generate session-scoped sequence number
|
||||
2. Combine with booking timestamp
|
||||
3. Hash with SHA-256
|
||||
4. Take first 6 characters of base32 encoding
|
||||
5. Prefix with "TEST-"
|
||||
|
||||
**Rationale**:
|
||||
- "TEST-" prefix = clear mock indicator (Constitution Principle III)
|
||||
- Base32 = human-readable, unambiguous (no 0/O, 1/I confusion)
|
||||
- 6 characters = 1 billion unique combinations (sufficient for testing)
|
||||
- Deterministic = reproducible test scenarios
|
||||
- Session-scoped = prevents conflicts
|
||||
|
||||
**Alternatives Considered**:
|
||||
- **Random UUID**: Rejected - too long, not human-friendly
|
||||
- **Sequential numbers**: Rejected - predictable, not realistic
|
||||
- **No prefix**: Rejected - violates safety requirement
|
||||
|
||||
## Technology Stack Summary
|
||||
|
||||
| Component | Technology | Version | Rationale |
|
||||
|-----------|-----------|---------|-----------|
|
||||
| Runtime | Node.js | 20 LTS | Current stable, long-term support |
|
||||
| MCP SDK | @modelcontextprotocol/sdk | Latest | Official SDK, protocol compliance |
|
||||
| Persistence | Valkey | 8.0+ | Redis-compatible, requirement specified |
|
||||
| Valkey Client | ioredis | 5.x | Mature, feature-rich, TypeScript support |
|
||||
| Logging | Pino | Latest | Fast, structured, minimal overhead |
|
||||
| Testing | node:test | Built-in | Native, zero dependencies |
|
||||
| Coverage | c8 | Latest | V8 coverage, lightweight |
|
||||
| Container | Docker | 24+ | Buildx support, multi-platform |
|
||||
| Orchestration | docker-compose | 2.x | Development environment |
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
### Expected Performance Profile
|
||||
|
||||
- **Search Operations**: <500ms (data generation + Valkey lookup)
|
||||
- **Booking Operations**: <200ms (validation + Valkey write)
|
||||
- **Retrieval Operations**: <100ms (Valkey read)
|
||||
- **Concurrent Sessions**: 50+ (limited by Valkey and Node.js event loop)
|
||||
- **Memory Footprint**: <100MB per server instance
|
||||
- **Container Image Size**: <50MB (Alpine-based)
|
||||
|
||||
### Optimization Strategies
|
||||
|
||||
1. **Caching**: Pre-compute common search results in Valkey
|
||||
2. **Connection Pooling**: ioredis maintains persistent Valkey connections
|
||||
3. **Lazy Loading**: Load mock data modules on-demand
|
||||
4. **Batch Operations**: Use Valkey pipelines for multi-key operations
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### Mock Data Safety
|
||||
|
||||
- ✅ No real API keys or credentials stored
|
||||
- ✅ Configuration validation rejects production patterns
|
||||
- ✅ All PNRs prefixed with "TEST-"
|
||||
- ✅ No external network calls (except to local Valkey)
|
||||
- ✅ Non-root container user
|
||||
|
||||
### Docker Security
|
||||
|
||||
- Use official Node.js Alpine base images
|
||||
- Run as non-root user (node:node)
|
||||
- Minimal attack surface (no shell, no dev tools in prod image)
|
||||
- Regular security updates via base image updates
|
||||
|
||||
## Open Questions (Resolved)
|
||||
|
||||
All technical unknowns from initial planning have been resolved through research above. No blocking issues identified.
|
||||
|
||||
## Next Steps
|
||||
|
||||
Proceed to Phase 1: Design & Contracts
|
||||
- Create data-model.md (data structures)
|
||||
- Define MCP tool contracts in contracts/
|
||||
- Generate quickstart.md with usage examples
|
||||
- Update agent context with technology decisions
|
||||
219
specs/001-mock-gds-server/spec.md
Normal file
219
specs/001-mock-gds-server/spec.md
Normal file
@@ -0,0 +1,219 @@
|
||||
# Feature Specification: Mock GDS MCP Server
|
||||
|
||||
**Feature Branch**: `001-mock-gds-server`
|
||||
**Created**: 2025-01-22
|
||||
**Status**: Draft
|
||||
**Input**: User description: "Build a Mock GDS MCP Server"
|
||||
|
||||
## User Scenarios & Testing *(mandatory)*
|
||||
|
||||
### User Story 1 - Flight Search and Booking (Priority: P1)
|
||||
|
||||
A developer building a travel application needs to test flight search and booking functionality. They initiate a flight search for a specific route and date, receive mock availability results with realistic pricing, select a flight, and complete a booking that returns a PNR (Passenger Name Record). The mock server provides immediate responses with consistent data, allowing the developer to verify their application's search UI, results display, booking form, and confirmation workflow.
|
||||
|
||||
**Why this priority**: Flight booking is the core GDS capability and most commonly used. Without this, the mock server delivers no meaningful value. This represents the essential MVP - a working flight search and book operation demonstrates the server is functional.
|
||||
|
||||
**Independent Test**: Can be fully tested by executing a flight search request through MCP, receiving mock flight results, submitting a booking request with passenger details, and receiving a valid PNR. Delivers immediate value for testing basic travel app workflows without requiring any other travel service types.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** a developer requests flights from JFK to LAX on a future date, **When** the search executes, **Then** the system returns 3-5 mock flight options with different times, airlines (using valid IATA codes like AA, DL, UA), realistic prices ($200-$800), and available seats
|
||||
2. **Given** search results are displayed, **When** the developer selects a specific flight and provides passenger details (name, contact info), **Then** the system creates a booking and returns a 6-character alphanumeric PNR (e.g., ABC123)
|
||||
3. **Given** a valid PNR exists, **When** the developer retrieves the booking, **Then** the system returns complete booking details including passenger information, flight details, booking status, and total price
|
||||
4. **Given** a confirmed booking with PNR, **When** the developer requests cancellation, **Then** the system marks the booking as cancelled and confirms the cancellation
|
||||
|
||||
---
|
||||
|
||||
### User Story 2 - Hotel Search and Multi-Service Bundling (Priority: P2)
|
||||
|
||||
A developer needs to test a travel package feature that combines flights and hotels. They search for hotels in the destination city for specific dates, view available properties with realistic amenities and pricing, add a hotel to an existing flight booking to create a multi-service itinerary, and retrieve the combined booking showing both flight and hotel details under one PNR.
|
||||
|
||||
**Why this priority**: Multi-service bookings are a common real-world scenario and differentiate GDS from simple flight APIs. This adds significant testing value but flight-only booking (P1) must work first. Can be developed after P1 is stable.
|
||||
|
||||
**Independent Test**: Can be tested by performing hotel searches independently, creating hotel-only bookings, and then testing the bundling workflow by adding hotels to existing flight bookings. Demonstrates the server can handle multiple service types and maintain complex booking state.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** a destination city code (e.g., LAX) and date range, **When** the developer searches for hotels, **Then** the system returns 5-10 mock properties with names, star ratings (2-5 stars), nightly rates ($80-$400), amenities lists, and availability
|
||||
2. **Given** an existing flight booking PNR, **When** the developer adds a hotel to the itinerary with check-in/check-out dates matching travel dates, **Then** the system updates the PNR to include both flight and hotel segments
|
||||
3. **Given** a multi-service booking, **When** the developer retrieves the PNR, **Then** the system returns a complete itinerary showing flight departure/arrival times, hotel check-in/check-out dates, total price breakdown by service type, and overall booking status
|
||||
|
||||
---
|
||||
|
||||
### User Story 3 - Car Rental and Complete Travel Package (Priority: P3)
|
||||
|
||||
A developer testing a comprehensive travel platform needs to create complete travel packages including flights, hotels, and car rentals. They search for rental cars at the destination airport, view available vehicle classes with daily rates, add a car rental to an existing multi-service booking, and manage a complete end-to-end travel itinerary under one PNR.
|
||||
|
||||
**Why this priority**: Car rentals complete the full travel package offering but are less commonly used than flights and hotels. This is valuable for comprehensive testing but not essential for initial MVP. Requires P1 and P2 to be working first.
|
||||
|
||||
**Independent Test**: Can be tested by performing car rental searches independently, creating car-only bookings, and integrating with flight+hotel bookings. Demonstrates full GDS capability coverage and complex multi-segment itinerary management.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** an airport code (e.g., LAX) and rental dates, **When** the developer searches for cars, **Then** the system returns 4-6 vehicle options (economy, compact, SUV, luxury) with daily rates ($35-$150), rental companies (using valid codes like Hertz, Avis, Enterprise), and availability
|
||||
2. **Given** an existing flight+hotel booking, **When** the developer adds a car rental with pickup/dropoff dates matching the travel period, **Then** the system updates the PNR to include flight, hotel, and car segments in chronological order
|
||||
3. **Given** a complete travel package, **When** the developer requests the itinerary, **Then** the system returns a structured view showing the full trip timeline: flight arrival, car pickup, hotel check-in, hotel check-out, car dropoff, and return flight
|
||||
|
||||
---
|
||||
|
||||
### User Story 4 - Session Management for Concurrent Testing (Priority: P2)
|
||||
|
||||
A QA team runs automated integration tests that execute multiple booking scenarios simultaneously. Each test session needs isolated booking state so concurrent tests don't interfere with each other. The mock server assigns unique session identifiers, maintains separate booking contexts per session, and ensures that searches, bookings, and retrievals in one session are completely isolated from other sessions.
|
||||
|
||||
**Why this priority**: Essential for realistic testing environments where multiple developers or automated tests run in parallel. Without session isolation, the mock server can only handle one user at a time, severely limiting its usefulness. This is critical for CI/CD integration.
|
||||
|
||||
**Independent Test**: Can be tested by initiating 5-10 concurrent MCP sessions, performing different booking operations in each (different routes, dates, passenger names), and verifying that retrieving a PNR in one session never returns data from another session. Confirms multi-user readiness.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** two developers start separate MCP sessions, **When** each performs a flight search with different criteria (different cities and dates), **Then** each receives results matching their search only, with no data leakage between sessions
|
||||
2. **Given** concurrent test automation runs 10 booking flows simultaneously, **When** each creates a booking with unique passenger names, **Then** the system generates 10 distinct PNRs and each can be retrieved with correct passenger information in its originating session
|
||||
3. **Given** a session with multiple active bookings, **When** the developer ends the session, **Then** the system maintains booking data for retrieval operations but prevents new modifications, allowing tests to verify final state
|
||||
|
||||
---
|
||||
|
||||
### User Story 5 - Realistic Test Data for Demonstrations (Priority: P3)
|
||||
|
||||
A sales team demonstrates travel booking software to potential customers. They need realistic, professional-looking mock data that appears authentic during presentations - valid airline names and codes, recognizable hotel chains, realistic pricing that matches market expectations, and diverse route options covering major travel markets (domestic US, transatlantic, Asia-Pacific). The mock server provides curated demonstration scenarios with high-quality data suitable for live demos.
|
||||
|
||||
**Why this priority**: Important for sales and training but not for development testing. Demo quality data enhances presentations but basic valid mock data (covered in P1) suffices for testing. This is a polish feature that improves adoption but isn't technically essential.
|
||||
|
||||
**Independent Test**: Can be tested by reviewing the mock data catalog, executing searches for major routes (NYC-LAX, NYC-LON, LAX-TYO), verifying that returned data includes recognizable brands (United, Marriott, Hertz), realistic prices (not $1 or $999999), and appropriate travel times/durations. Success means demo-ready output requiring no explanation or apology.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** a demo scenario for domestic US travel, **When** the sales person searches JFK to LAX, **Then** the system returns flights on American, Delta, and United with prices between $250-$600, realistic departure times (6am, 9am, 2pm, 5pm), and 5.5-6 hour flight durations
|
||||
2. **Given** a demo scenario for international travel, **When** the sales person searches NYC to London, **Then** the system returns overnight flights on major carriers (BA, AA, Virgin Atlantic) with prices $800-$1500, premium cabin options (economy, business, first class), and realistic 7-8 hour flight times
|
||||
3. **Given** a demo for hotel bookings, **When** searching major cities (New York, London, Tokyo), **Then** the system returns recognizable hotel brands (Marriott, Hilton, Hyatt) with appropriate pricing tiers ($150-$300 mid-range, $400-$800 luxury) and realistic amenities (WiFi, breakfast, gym, pool)
|
||||
|
||||
---
|
||||
|
||||
### Edge Cases
|
||||
|
||||
- **Empty Search Results**: What happens when a search request uses invalid codes (non-existent airport ZZZZ, impossible date like Feb 30)? System should return user-friendly error messages with specific reasons ("Airport code ZZZZ not recognized in mock database", "Invalid date format") rather than crashing.
|
||||
|
||||
- **Booking Modifications**: How does the system handle attempts to modify an already-cancelled booking? System must reject modification requests and return clear error indicating booking is in cancelled state and cannot be changed.
|
||||
|
||||
- **Session Expiry**: What happens when a developer retrieves a PNR after the session expires or in a different session? System should handle this gracefully - either maintain PNRs across sessions (making them globally retrievable) or return clear error "PNR not found in current session" if session-scoped.
|
||||
|
||||
- **Incomplete Booking Data**: How does system respond when booking request is missing required fields (no passenger name, no contact info)? System must validate required fields and return specific validation errors ("Missing required field: passenger.lastName", "Missing required field: contact.email").
|
||||
|
||||
- **Concurrent Booking Same Flight**: What happens when two sessions simultaneously book the last seat on a mock flight? System should handle this realistically - either both succeed (infinite mock inventory), or implement basic availability tracking and one booking succeeds while other receives "No availability" response.
|
||||
|
||||
- **Invalid PNR Format**: How does retrieval handle malformed PNRs (wrong length, invalid characters like "A@B!C1")? System should validate PNR format and return "Invalid PNR format" error rather than attempting database lookup.
|
||||
|
||||
- **Date Logic**: What happens when hotel check-out date is before check-in date, or car dropoff is before pickup? System must validate date sequences and return errors like "Check-out date must be after check-in date".
|
||||
|
||||
- **Multi-Service Timing Conflicts**: What happens when developer tries to add a hotel with dates that don't overlap with the flight dates in the same booking (flight on June 10, hotel June 20-22)? System should either warn about date mismatch or enforce logical consistency (hotel dates must overlap with travel period).
|
||||
|
||||
## Requirements *(mandatory)*
|
||||
|
||||
### Functional Requirements
|
||||
|
||||
- **FR-001**: System MUST expose all travel search and booking capabilities as MCP tools with clearly defined input parameters and output schemas
|
||||
|
||||
- **FR-002**: System MUST support flight search with parameters: origin airport code (3-letter IATA), destination airport code, departure date, optional return date, and passenger count, returning a list of available flights with times, airlines, prices, and seat availability
|
||||
|
||||
- **FR-003**: System MUST support hotel search with parameters: city or airport code, check-in date, check-out date, and guest count, returning a list of available properties with names, ratings, nightly rates, total prices, and amenities
|
||||
|
||||
- **FR-004**: System MUST support car rental search with parameters: pickup location (airport code), pickup date/time, dropoff location, dropoff date/time, returning available vehicle classes with daily rates, rental companies, and vehicle specifications
|
||||
|
||||
- **FR-005**: System MUST support booking creation for any travel service (flight, hotel, car) with passenger/guest details, payment method placeholder (no actual processing), and return a unique 6-character alphanumeric PNR
|
||||
|
||||
- **FR-006**: System MUST allow multiple service types (flight + hotel + car) to be combined under a single PNR, maintaining all segment details in one unified booking record
|
||||
|
||||
- **FR-007**: System MUST support PNR retrieval by PNR code, returning complete booking details including all service segments, passenger information, prices, booking status, and creation timestamp
|
||||
|
||||
- **FR-008**: System MUST support booking cancellation by PNR, updating booking status to "cancelled" and returning cancellation confirmation with timestamp
|
||||
|
||||
- **FR-009**: System MUST maintain session isolation - each MCP session receives a unique session identifier and all bookings, searches, and state are isolated per session with no data leakage between concurrent sessions
|
||||
|
||||
- **FR-010**: System MUST include realistic mock data covering at minimum: 20+ major airports (US domestic and international hubs), 15+ airlines with valid IATA codes, 30+ hotels across major cities, and 5+ car rental companies
|
||||
|
||||
- **FR-011**: System MUST use only valid IATA/ICAO codes for airports and airlines - no fictional codes that would confuse users testing against real GDS documentation
|
||||
|
||||
- **FR-012**: System MUST clearly mark all data as mock/test data in responses (via metadata field like "data_source": "mock") to prevent any confusion with production systems
|
||||
|
||||
- **FR-013**: System MUST log all operations (search, book, retrieve, cancel) with timestamps, session IDs, and operation parameters to support debugging and test verification
|
||||
|
||||
- **FR-014**: System MUST return structured error responses with error codes and human-readable messages for all error conditions (invalid input, not found, validation failures)
|
||||
|
||||
- **FR-015**: System MUST support common GDS workflows including: price verification (confirm price before booking), seat/room availability checks, and multi-step booking processes (search → select → confirm)
|
||||
|
||||
- **FR-016**: System MUST generate realistic pricing based on route distance, service class, and time factors - no arbitrary prices like $1 or $999999
|
||||
|
||||
- **FR-017**: System MUST maintain booking state persistence within a session - bookings created during a session remain retrievable for the session duration
|
||||
|
||||
- **FR-018**: System MUST validate all input parameters (date formats YYYY-MM-DD, valid airport codes, positive passenger counts, logical date sequences) and reject invalid requests with specific error messages
|
||||
|
||||
- **FR-019**: System MUST support date/time handling for different time zones - flight times in local airport time, with UTC timestamps in responses for unambiguous time tracking
|
||||
|
||||
- **FR-020**: System MUST prevent any connection attempts to real booking systems, payment processors, or external GDS providers - all operations are fully self-contained mock operations
|
||||
|
||||
### Key Entities
|
||||
|
||||
- **Flight Segment**: Represents one flight leg with departure/arrival airports (IATA codes), departure/arrival times (local time + UTC), airline code, flight number, aircraft type, duration, available fare classes (economy/business/first), pricing per class, and seat availability counts
|
||||
|
||||
- **Hotel Reservation**: Represents accommodation booking with property name, location (city/address), star rating (1-5), check-in/check-out dates, room type (single/double/suite), nightly rate, total price, amenities list (WiFi, parking, breakfast, gym, pool), and cancellation policy
|
||||
|
||||
- **Car Rental**: Represents vehicle rental with pickup/dropoff locations (airport codes or city), pickup/dropoff date-times, rental company name and code, vehicle class (economy/compact/SUV/luxury), daily rate, total price, vehicle specifications (make/model/seats), and mileage policy (unlimited/limited)
|
||||
|
||||
- **Passenger/Guest**: Represents traveler information with full name (first/middle/last), date of birth, contact details (email, phone), loyalty program numbers (frequent flyer, hotel rewards), and special requests/needs (meal preferences, accessibility requirements, seat preferences)
|
||||
|
||||
- **PNR (Passenger Name Record)**: Core booking entity containing unique 6-character alphanumeric identifier, booking status (confirmed/cancelled/pending), creation timestamp, list of all service segments (flights, hotels, cars), passenger/guest details, total price summary, payment method placeholder, and session identifier
|
||||
|
||||
- **Session**: Represents an MCP connection session with unique session ID, creation timestamp, list of active PNRs created in this session, session expiry time, and isolation boundary ensuring no cross-session data access
|
||||
|
||||
- **Search Query**: Represents search parameters for any service type with service type (flight/hotel/car), origin/destination or location, dates, passenger/guest counts, optional filters (price range, star rating, airline preference), and returns matching results list
|
||||
|
||||
- **Mock Data Record**: Represents static test data entries for airports (code, city, country, timezone), airlines (code, name, country), hotels (name, location, rating, base rates), and rental companies (name, code, vehicle inventory), all marked with "mock: true" flag
|
||||
|
||||
## Success Criteria *(mandatory)*
|
||||
|
||||
### Measurable Outcomes
|
||||
|
||||
- **SC-001**: Developers can complete a full flight search and booking workflow (search → select → book → retrieve) in under 30 seconds with clear, understandable responses at each step
|
||||
|
||||
- **SC-002**: System handles 50 concurrent MCP sessions executing independent booking workflows simultaneously without response degradation, data corruption, or cross-session data leakage
|
||||
|
||||
- **SC-003**: All search operations (flight, hotel, car) return results in under 2 seconds with realistic data, enabling developers to build responsive user interfaces without waiting for slow mock responses
|
||||
|
||||
- **SC-004**: 100% of mock data uses valid IATA/ICAO codes and realistic pricing within market ranges (flights $100-$2000, hotels $50-$800/night, cars $25-$200/day) so developers don't need to question data authenticity
|
||||
|
||||
- **SC-005**: Integration tests using the mock server can verify end-to-end booking workflows without manual intervention, achieving 95% test automation coverage for travel app booking features
|
||||
|
||||
- **SC-006**: Sales demonstrations using the mock server require zero data explanation or disclaimer - all returned data appears professional and realistic enough to represent production-quality responses
|
||||
|
||||
- **SC-007**: New developers unfamiliar with GDS concepts can understand booking workflows by examining mock server responses within 15 minutes, using the clear response structure and realistic data as learning material
|
||||
|
||||
- **SC-008**: System logs provide sufficient detail that 90% of failed test cases can be debugged by examining logs alone, without needing to instrument additional debugging code
|
||||
|
||||
- **SC-009**: Zero production system connections or external API calls are made during any operation - 100% self-contained mock operation with no risk of accidental real bookings
|
||||
|
||||
- **SC-010**: Error messages enable developers to fix invalid requests on first attempt - each validation error specifies the exact field, expected format, and current invalid value
|
||||
|
||||
## Assumptions
|
||||
|
||||
- **Mock Data Scope**: The mock database will include major US airports, international hubs (London, Paris, Tokyo, Dubai), and popular tourist destinations, but will not attempt to be comprehensive (all 40,000+ airports worldwide). Coverage focuses on common testing scenarios.
|
||||
|
||||
- **Pricing Realism**: Mock prices will be realistic based on current market ranges but will not update for inflation, seasonal changes, or market conditions. Fixed pricing tiers will be maintained for consistency across tests and demos.
|
||||
|
||||
- **No Payment Processing**: All payment operations are placeholders - the system accepts payment method information (credit card type, last 4 digits) for workflow testing but performs no validation, tokenization, or processing of any kind.
|
||||
|
||||
- **Session Duration**: Sessions remain active for the duration of the MCP connection. When the connection closes, session data may be cleaned up. For persistent testing scenarios, developers should maintain their MCP connection or implement session rehydration in their test framework.
|
||||
|
||||
- **Infinite Inventory**: Mock availability is effectively unlimited - any search returns available results, and any booking succeeds (unless specifically testing error scenarios). No real inventory tracking or "sold out" conditions unless explicitly requested in test scenario.
|
||||
|
||||
- **Simplified Fare Rules**: Complex GDS fare rules (change fees, blackout dates, minimum stay requirements) are simplified or omitted. The focus is on basic booking workflows, not exhaustive fare rule validation.
|
||||
|
||||
- **English Language Only**: All mock data (airport names, hotel names, city names) will be in English with standard Latin character encoding (UTF-8). International character support is out of scope for v1.
|
||||
|
||||
- **No Real-Time Updates**: Prices and availability are static mock data. There are no real-time updates, dynamic pricing, or availability changes based on time or demand. Each search returns consistent results for the same parameters.
|
||||
|
||||
- **MCP Protocol Version**: System assumes MCP version 1.0 protocol standards for tool definition, parameter passing, and response formatting. Compatibility with future MCP versions may require updates.
|
||||
|
||||
- **Target Users**: Primary users are software developers and QA engineers familiar with travel industry concepts (IATA codes, PNR terminology). The system is not designed for end-user consumer access.
|
||||
|
||||
- **No Authentication**: Session isolation is based on MCP connection identity, not user authentication. There is no login system, user accounts, or permission management. All sessions have equal access to all mock operations.
|
||||
|
||||
- **Development Environment**: The mock server is designed for development, testing, and demonstration environments. It is not intended for production use, load testing beyond moderate concurrency (50-100 sessions), or as a production GDS proxy.
|
||||
Reference in New Issue
Block a user