fixing jsonSchema validation by using zod

This commit is contained in:
2026-04-11 22:23:25 -05:00
parent 0bae26ae0b
commit eb0a4e8308
56 changed files with 12275 additions and 287 deletions

View File

@@ -393,3 +393,354 @@ All tools return standard MCP errors:
- Timestamps use ISO 8601 format
- Prices in USD cents (integer)
- All PNRs prefixed with "TEST-" for safety
---
## Remote Access Endpoints (Added 2026-04-07)
The following endpoints are available when running in HTTP/2 remote transport mode.
### Health Check Endpoint
**Endpoint**: `GET /health`
**Description**: Returns server operational status for monitoring and health checks. This endpoint is unauthenticated and exempt from rate limiting.
**Use Cases**:
- Load balancer health checks
- Monitoring system integration (Prometheus, Datadog, etc.)
- Deployment validation
- Debugging connection and memory issues
**HTTP Method**: GET
**Authentication**: None (publicly accessible)
**Rate Limiting**: Exempt (not subject to rate limits)
**Request**: No body required
**Response Schema**:
```json
{
"type": "object",
"properties": {
"status": {
"type": "string",
"enum": ["healthy", "degraded", "unhealthy"],
"description": "Overall server health status"
},
"uptime": {
"type": "integer",
"description": "Server uptime in seconds since start"
},
"version": {
"type": "string",
"description": "Server version (from package.json)"
},
"connections": {
"type": "object",
"properties": {
"stdio": {
"type": "integer",
"description": "Active stdio connections (0 or 1)"
},
"http": {
"type": "integer",
"description": "Active HTTP/2 connections"
},
"total": {
"type": "integer",
"description": "Total active connections"
}
},
"required": ["stdio", "http", "total"]
},
"sessions": {
"type": "object",
"properties": {
"active": {
"type": "integer",
"description": "Sessions with recent activity (within 5 minutes)"
},
"total": {
"type": "integer",
"description": "Total sessions in storage"
}
},
"required": ["active", "total"]
},
"storage": {
"type": "object",
"properties": {
"connected": {
"type": "boolean",
"description": "Valkey connection status"
},
"responseTime": {
"type": "number",
"description": "Valkey ping response time in milliseconds"
}
},
"required": ["connected", "responseTime"]
},
"memory": {
"type": "object",
"properties": {
"used": {
"type": "number",
"description": "Process memory used in MB"
},
"total": {
"type": "number",
"description": "Total system memory in MB"
},
"percentage": {
"type": "number",
"description": "Memory usage percentage (0-1)"
}
},
"required": ["used", "total", "percentage"]
},
"timestamp": {
"type": "integer",
"description": "Health check timestamp (Unix milliseconds)"
}
},
"required": ["status", "uptime", "version", "connections", "sessions", "storage", "memory", "timestamp"]
}
```
**Status Determination**:
- **healthy** (200 OK): All systems operational
- Storage connected
- Memory usage < 80%
- Valkey response time < 100ms
- **degraded** (200 OK): Some issues but still serving requests
- Storage slow (ping 100-500ms)
- Memory usage 80-90%
- **unhealthy** (503 Service Unavailable): Critical issues
- Storage disconnected
- Memory usage > 90%
- Unable to serve requests
**Example Response (Healthy)**:
```json
{
"status": "healthy",
"uptime": 3600,
"version": "0.1.0",
"connections": {
"stdio": 0,
"http": 12,
"total": 12
},
"sessions": {
"active": 8,
"total": 15
},
"storage": {
"connected": true,
"responseTime": 2.5
},
"memory": {
"used": 45.2,
"total": 8192,
"percentage": 0.0055
},
"timestamp": 1712486460000
}
```
**Example Response (Degraded)**:
```json
{
"status": "degraded",
"uptime": 7200,
"version": "0.1.0",
"connections": {
"stdio": 0,
"http": 45,
"total": 45
},
"sessions": {
"active": 42,
"total": 50
},
"storage": {
"connected": true,
"responseTime": 150
},
"memory": {
"used": 6553.6,
"total": 8192,
"percentage": 0.8
},
"timestamp": 1712490060000
}
```
**Example Response (Unhealthy)**:
```json
{
"status": "unhealthy",
"uptime": 10800,
"version": "0.1.0",
"connections": {
"stdio": 0,
"http": 0,
"total": 0
},
"sessions": {
"active": 0,
"total": 0
},
"storage": {
"connected": false,
"responseTime": null
},
"memory": {
"used": 120,
"total": 8192,
"percentage": 0.015
},
"timestamp": 1712493660000
}
```
**cURL Example**:
```bash
curl -i http://localhost:8080/health
```
**Load Balancer Integration** (Nginx):
```nginx
upstream mcp_backend {
server mcp-server:3000;
health_check interval=10s uri=/health;
}
```
**Prometheus Monitoring**:
```yaml
scrape_configs:
- job_name: 'mcp-server'
static_configs:
- targets: ['localhost:8080']
metrics_path: '/health'
scrape_interval: 30s
```
---
## Rate Limiting (HTTP Mode Only)
When running in HTTP/2 remote mode, all MCP tool endpoints are subject to rate limiting.
**Algorithm**: Sliding Window Counter (Hybrid)
**Default Limits**:
- 100 requests per minute per client IP address
- Window size: 60 seconds
- Burst tolerance: ~150 requests in worst-case window overlap
**Rate Limit Headers** (included in all HTTP responses):
```
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1712486520
```
**Rate Limit Exceeded Response** (429 Too Many Requests):
```json
{
"error": "Rate limit exceeded",
"code": "RATE_LIMIT_EXCEEDED",
"limit": 100,
"current": 105,
"resetAt": "2026-04-07T10:02:00.000Z",
"retryAfter": 15
}
```
**HTTP Headers on 429**:
```
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1712486520
Retry-After: 15
Content-Type: application/json
```
**Exemptions**:
- Health check endpoint (`/health`) is exempt from rate limiting
- CORS preflight requests (OPTIONS) are exempt
**Configuration**:
```bash
RATE_LIMIT_ENABLED=true
RATE_LIMIT_PER_MINUTE=100
RATE_LIMIT_WINDOW_SECONDS=60
```
---
## CORS Headers (HTTP Mode Only)
When running in HTTP/2 remote mode, all endpoints support cross-origin requests.
**CORS Policy**: Permissive wildcard (`Access-Control-Allow-Origin: *`)
**Preflight Request** (OPTIONS):
```
OPTIONS /mcp HTTP/1.1
Origin: https://web-client.example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Content-Type, MCP-Session-ID
```
**Preflight Response**:
```
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: Content-Type, MCP-Session-ID, X-Requested-With
Access-Control-Max-Age: 86400
```
**Actual Request Headers** (added to all responses):
```
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: false
Access-Control-Expose-Headers: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset
```
**Security Note**: Wildcard CORS is appropriate for development/testing with mock data only. Deploy within private networks (VPN, firewalls) for security.
---
## Transport Mode Configuration
**Environment Variables**:
```bash
# Transport selection
TRANSPORT_MODE=stdio|http|both # Default: stdio
# HTTP/2 configuration (when http or both)
HTTP_PORT=3000 # Internal port (default: 3000)
HTTP_HOST=127.0.0.1 # Bind address (default: 127.0.0.1 for proxy)
# External access via reverse proxy
# Nginx listens on :8080 (HTTP/2 + TLS)
# Proxies to mcp-server:3000 (HTTP/1.1)
```
**Protocol Notes (Updated)**:
- stdio mode: JSON-RPC 2.0 over stdin/stdout (local only)
- http mode: JSON-RPC 2.0 over SSE via StreamableHTTPServerTransport
- HTTP/2: Provided by nginx reverse proxy (terminates HTTP/2, proxies HTTP/1.1)
- CORS: Enabled in http mode, wildcard policy
- Rate limiting: Enabled in http mode, IP-based tracking
- Health checks: Available in http mode at `/health`

View File

@@ -392,3 +392,317 @@ No secondary indexes required - all queries use primary keys (sessionId, pnr)
Proceed to contract definition (Phase 1 continued):
- Define MCP tool schemas in `/contracts/mcp-tools.md`
- Create quickstart guide with example usage
---
## Remote Access Entities (Added 2026-04-07)
The following entities support remote MCP access over HTTP/2 with rate limiting, health monitoring, and global PNR retrieval.
### 8. Remote Connection
Represents an active remote client connection over HTTP/2.
**Fields**:
```typescript
{
connectionId: string; // Unique connection identifier (UUID)
sessionId: string; // Associated MCP session ID
remoteIP: string; // Client IP address (for rate limiting)
connectedAt: number; // Unix timestamp (ms)
lastActivityAt: number; // Unix timestamp (ms)
transportType: string; // 'http' | 'stdio'
userAgent: string; // Client user agent
requestCount: number; // Total requests made in this connection
}
```
**Storage**: Valkey hash at key `connection:{connectionId}`
**Validation**:
- `remoteIP` must be valid IPv4 or IPv6 format
- `transportType` must be 'http' or 'stdio'
- `connectedAt` must be <= `lastActivityAt`
**State Transitions**:
```
[Connected] → [Active] → [Idle] → [Disconnected]
[Expired]
```
**Lifecycle**:
- Created on initial HTTP request with new session
- Updated on every request (lastActivityAt, requestCount)
- Auto-expires after SESSION_TTL_HOURS of inactivity
- Explicitly deleted on graceful disconnect
---
### 9. Rate Limit Record
Tracks request rates per client IP address for abuse prevention.
**Fields**:
```typescript
{
clientIP: string; // Client IP address (key component)
currentWindow: number; // Current time window (Unix timestamp / window_seconds)
currentCount: number; // Request count in current window
previousCount: number; // Request count in previous window
limit: number; // Max requests allowed per window
resetAt: number; // Next window reset timestamp
}
```
**Storage**:
- Current window: Valkey integer at key `ratelimit:{ip}:{currentWindow}`
- Previous window: Valkey integer at key `ratelimit:{ip}:{previousWindow}`
**Validation**:
- `clientIP` must be valid IP address
- `currentCount`, `previousCount` must be non-negative integers
- `limit` must be positive integer (default: 100)
- `resetAt` must be in the future
**Algorithm**: Sliding Window Counter (Hybrid)
```javascript
estimatedCount = (previousCount * previousWeight) + currentCount
where previousWeight = 1 - (elapsedInWindow / windowSeconds)
```
**Lifecycle**:
- Counter incremented on each request: `INCR ratelimit:{ip}:{window}`
- TTL set to 2× window duration (keeps previous window accessible)
- Auto-expires after TTL (no manual cleanup needed)
- Resets at window boundary (new window key)
**Error Response** (when limit exceeded):
```typescript
{
error: "Rate limit exceeded",
code: "RATE_LIMIT_EXCEEDED",
limit: 100,
current: 105,
resetAt: "2026-04-07T10:01:00.000Z",
retryAfter: 15 // seconds
}
```
---
### 10. Health Status
Represents server operational status for monitoring and health checks.
**Fields**:
```typescript
{
status: string; // 'healthy' | 'degraded' | 'unhealthy'
uptime: number; // Seconds since server start
version: string; // Server version
connections: {
stdio: number; // Active stdio connections (0 or 1 typically)
http: number; // Active HTTP connections
total: number; // Total active connections
},
sessions: {
active: number; // Active sessions (sessions with recent activity)
total: number; // Total sessions in Valkey
},
storage: {
connected: boolean; // Valkey connection status
responseTime: number; // Valkey ping response time (ms)
},
memory: {
used: number; // Process memory used (MB)
total: number; // Total system memory (MB)
percentage: number; // Memory usage percentage
},
timestamp: number; // Health check timestamp (Unix ms)
}
```
**Endpoint**: `GET /health` (unauthenticated, exempt from rate limiting)
**Status Determination**:
- **healthy**: All systems operational, storage connected, memory < 80%
- **degraded**: Storage slow (ping > 100ms) or memory 80-90%
- **unhealthy**: Storage disconnected or memory > 90%
**Response Codes**:
- 200 OK: status = 'healthy'
- 200 OK: status = 'degraded' (still serving requests)
- 503 Service Unavailable: status = 'unhealthy'
**Example Response**:
```json
{
"status": "healthy",
"uptime": 3600,
"version": "0.1.0",
"connections": {
"stdio": 0,
"http": 12,
"total": 12
},
"sessions": {
"active": 8,
"total": 15
},
"storage": {
"connected": true,
"responseTime": 2
},
"memory": {
"used": 45,
"total": 8192,
"percentage": 0.55
},
"timestamp": 1712486460000
}
```
**Use Cases**:
- Load balancer health checks
- Monitoring system integration (Prometheus, Datadog)
- Deployment validation (verify server started successfully)
- Debugging (check connection counts, memory usage)
---
## Updated Storage Schema (Remote Mode)
### Global PNR Storage (Session-Independent)
**Key Change**: PNRs now stored globally with TTL, not scoped to sessions.
```
pnr:{pnr} # Global PNR storage
→ {
pnr: string,
status: 'confirmed' | 'cancelled',
createdAt: ISO8601,
expiresAt: ISO8601,
creatingSessionId: string, # For logging only, not access control
segments: [...],
passengers: [...],
totalPrice: number
}
```
**TTL**: Configurable via `PNR_TTL_HOURS` (default 1 hour)
**Access**: Any session can retrieve any PNR (global retrieval)
**Expiration**: PNR auto-deleted by Valkey after TTL expires
---
### Session PNR Reference
Sessions track which PNRs they created (for `listBookings` tool):
```
session:{sessionId}:pnrs # Set of PNR codes created in this session
→ Set<string> # e.g., ["TEST-ABC123", "TEST-DEF456"]
```
**Purpose**: Enable `listBookings` to return session-created PNRs
**Lifecycle**: Deleted when session expires (PNRs persist independently)
---
### Rate Limit Keys
```
ratelimit:{ip}:{window} # Request count for IP in time window
→ integer # e.g., 45 (requests made)
TTL: windowSeconds * 2 # Keep previous window accessible
```
**Example**:
```
ratelimit:192.168.1.1:287456 # Current window (e.g., minute 287456)
→ 45
ratelimit:192.168.1.1:287455 # Previous window
→ 92
```
---
### Connection Tracking
```
connection:{connectionId} # Remote connection metadata
→ { connectionId, sessionId, remoteIP, connectedAt, ... }
TTL: SESSION_TTL_HOURS
```
**Purpose**: Track active HTTP connections for health monitoring
**Cleanup**: Auto-expires with session TTL
---
## Updated Validation Rules (Remote Mode)
### Additional Validations
1. **IP Address Validation**:
- Must be valid IPv4 (e.g., `192.168.1.1`) or IPv6 format
- Used for rate limiting and logging
- Extracted from `X-Forwarded-For` or `X-Real-IP` headers (trusted proxy)
2. **Session ID Format** (HTTP mode):
- Must be valid UUID v4
- Sent via `MCP-Session-ID` header
- Generated by transport if not provided
3. **Rate Limit Headers** (HTTP mode):
- `X-RateLimit-Limit`: Integer > 0
- `X-RateLimit-Remaining`: Integer >= 0
- `X-RateLimit-Reset`: Unix timestamp
- `Retry-After`: Seconds (when limit exceeded)
4. **CORS Headers** (HTTP mode):
- `Origin`: Any (wildcard policy)
- `Access-Control-Allow-Origin`: Must be `*`
- Preflight requests must use OPTIONS method
---
## Performance Considerations (Remote Mode)
### Additional Overhead
- **Rate Limiting**: +3 Valkey ops per request (~1-2ms overhead)
- **Connection Tracking**: +1 Valkey write per request (~0.5ms overhead)
- **CORS Preflight**: OPTIONS requests handled immediately (no tool execution)
- **Health Checks**: Separate fast path (no session/rate limit checks)
### Expected Performance (Remote)
- **Search Operations**: <2s (requirement: SC-003)
- **Booking Operations**: <500ms (includes rate limit check)
- **Retrieval Operations**: <200ms (global PNR lookup)
- **Health Check**: <100ms (Valkey ping only)
- **Concurrent Remote Sessions**: 50+ (requirement: SC-012)
### Optimization Strategies
1. **Rate Limit Caching**: Cache IP counters in-memory for 1 second (reduce Valkey ops)
2. **Connection Pooling**: Reuse HTTP/2 connections (handled by Nginx)
3. **Health Check Caching**: Cache health status for 5 seconds
4. **CORS Preflight Caching**: 24-hour `Access-Control-Max-Age`
---
## Next Steps
Data model complete with remote access entities. Proceed to:
1. ✅ Update contracts/ with health endpoint schema
2. ✅ Update quickstart.md with remote access setup
3. ✅ Run agent context update script

View File

@@ -1,192 +1,256 @@
# Implementation Plan: Mock GDS MCP Server
**Branch**: `001-mock-gds-server` | **Date**: 2026-04-07 | **Spec**: [spec.md](./spec.md)
**Branch**: `001-mock-gds-server` | **Date**: 2026-04-11 | **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.
Build a Mock Global Distribution System (GDS) server exposing flight, hotel, and car rental booking operations as Model Context Protocol (MCP) tools via HTTP transport. The server provides realistic mock data for testing travel applications without connecting to real GDS systems, with session-based state management and multi-service booking capabilities.
## 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
**Language/Version**: Node.js 20 LTS with TypeScript 6.0.2
**Primary Dependencies**: @modelcontextprotocol/sdk ^1.0.4 (MCP protocol), @modelcontextprotocol/server ^2.0.0-alpha.2 (McpServer), @modelcontextprotocol/express ^2.0.0-alpha.2 (HTTP transport), ioredis ^5.4.1 (Valkey client), Express ^5.2.1, pino ^9.5.0 (structured logging)
**Storage**: Valkey 8.0+ (Redis-compatible in-memory store with persistence for PNRs and sessions)
**Testing**: Node.js built-in test runner or Vitest (TBD in Phase 0)
**Target Platform**: Linux/macOS servers, Docker containers (multi-platform: linux/amd64, linux/arm64)
**Project Type**: MCP server (HTTP-based tool provider for AI agents and MCP clients)
**Performance Goals**: Support 100+ concurrent sessions, <200ms p95 response time for search operations, <500ms for booking operations
**Constraints**: Stateless HTTP transport design (no server-side session affinity required), connection pooling for Valkey, structured logging for observability, all operations deterministic for given inputs
**Scale/Scope**: 11 MCP tools (search/book/cancel for flights/hotels/cars, plus session management), ~5000 lines of TypeScript, realistic mock data (100+ airports, 20+ airlines, 50+ hotels, 15+ car companies)
## 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
### I. MCP Protocol Compliance
- **Status**: COMPLIANT
- **Evidence**: Using official @modelcontextprotocol/server package with McpServer class, all tools registered via standard API, StreamableHTTPServerTransport for MCP HTTP specification compliance
- **Validation**: McpServer handles JSON-RPC 2.0 message format automatically, capabilities declared in server initialization, error responses use MCP error structures
**Status**: PASS - Using official SDK guarantees protocol compliance
### II. Mock Data Realism ✅
- **Status**: COMPLIANT
- **Evidence**: Mock data uses real IATA airport codes (JFK, LAX, etc.), valid airline codes (AA, DL, UA), realistic pricing ($200-$800 flights, $80-$400 hotels), flight times respect geography and time zones
- **Implementation**: data/ directory contains realistic airlines, airports, flights, hotels, cars with internally consistent relationships
### 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
### III. No Real Transactions (Safety Guarantee) ✅
- **Status**: COMPLIANT
- **Evidence**: Server is pure mock implementation with no external GDS connections, PNRs generated locally with clear test format, no production API keys accepted
- **Safety Markers**: Documentation includes "MOCK" and "FOR TESTING ONLY" disclaimers, no real booking system integration
**Status**: PASS - Spec requirements align with realism principle
### IV. Tool-Based Architecture ✅
- **Status**: COMPLIANT
- **Evidence**: 11 MCP tools exposed (searchFlights, bookFlight, searchHotels, bookHotel, searchCars, bookCar, retrieveBooking, cancelBooking, listBookings, getSessionInfo, clearSession)
- **Implementation**: Each tool registered with description and inputSchema, tools are independently callable, responses deterministic for same inputs
### 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)
### V. Stateful Session Management ✅
- **Status**: COMPLIANT
- **Evidence**: Session manager tracks state per session ID, Valkey storage isolates bookings by session, PNRs stored with configurable TTL (default 1 hour)
- **Implementation**: SessionManager class provides create/get/update/delete operations, state transitions explicit (search → book → confirm)
**Status**: PASS - Safety guarantees built into design
### VI. Observable and Debuggable ✅
- **Status**: COMPLIANT
- **Evidence**: Structured logging via pino with configurable levels (INFO, DEBUG, ERROR), all tool calls logged with parameters and results, error messages include actionable guidance
- **Implementation**: Logger middleware logs all MCP requests, tool execution tracked with duration metrics, health endpoint for server status
### 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.
**Gate Result**: ✅ PASS - All constitutional requirements met
## 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)
specs/001-mock-gds-server/
├── plan.md # This file (updated with TypeScript details)
├── research.md # Technology decisions and best practices
├── data-model.md # Entity definitions and state models
├── quickstart.md # Getting started guide
├── contracts/ # MCP tool schemas and API contracts
│ └── mcp-tools.md # Tool definitions with input/output schemas
├── spec.md # Feature specification
└── tasks.md # Implementation task breakdown
```
### 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
src/ # TypeScript source files
├── index.ts # Main entry point, tool registration
├── server.ts # GDSMockServer class (McpServer wrapper)
├── data/ # Mock data generators
│ ├── airlines.ts # Airline database and lookups
│ ├── airports.ts # Airport codes and geography
│ ├── flights.ts # Flight generation logic
── hotels.ts # Hotel data and pricing
│ ├── cars.ts # Car rental options
── pnr.ts # PNR generation utilities
├── session/ # Session and storage management
│ ├── manager.ts # SessionManager class
│ ├── storage.ts # ValkeyStorage (Redis client wrapper)
│ └── valkey-event-store.ts # Event store for MCP resumability
├── tools/ # MCP tool implementations
│ ├── flights.ts # searchFlights, bookFlight
── hotels.ts # searchHotels, bookHotel
│ ├── cars.ts # searchCars, bookCar
│ ├── bookings.ts # retrieveBooking, cancelBooking, listBookings
│ └── session.ts # getSessionInfo, clearSession
── transports/ # HTTP transport layer
├── http-server.ts # StreamableHTTPServerTransport setup
└── factory.ts # Transport factory
├── middleware/ # Express middleware
│ ├── cors.ts # CORS policy (allow all origins)
│ ├── rate-limit.ts # IP-based rate limiting
│ ├── logger.ts # Request logging
│ ├── protocol-version.ts # MCP-Protocol-Version validation
│ └── message-normalization.ts # Request normalization
├── utils/ # Shared utilities
│ ├── errors.ts # Error classes (MCPError, ValidationError, etc.)
│ └── logger.ts # Pino logger configuration
└── validation/ # Input validation
└── validators.ts # Validation helpers
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
dist/ # Compiled JavaScript output (build artifacts)
├── index.js
├── server.js
└── [mirrors src/ structure]
docker/
├── Dockerfile # Multi-stage build
── docker-bake.hcl # Buildx bake configuration
tests/ # Test files (TBD)
├── unit/
── integration/
└── contract/
docker-compose.yaml # Local dev/test environment
package.json # Dependencies and scripts
.dockerignore # Build exclusions
README.md # Setup and usage
docker/ # Docker configuration
├── Dockerfile # Multi-platform build
└── entrypoint.sh # Container startup script
tsconfig.json # TypeScript compiler configuration
package.json # Dependencies and scripts
```
**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
**Structure Decision**: Single Node.js/TypeScript project with clear separation of concerns. Source in `src/` compiled to `dist/` via TypeScript compiler. MCP tools in `tools/`, data generators in `data/`, session management in `session/`, HTTP transport in `transports/`. Middleware chain handles CORS, rate limiting, protocol validation. Valkey for persistent storage. Docker support for containerized deployment.
## Complexity Tracking
> **Fill ONLY if Constitution Check has violations that must be justified**
**No constitution violations** - All core principles satisfied without requiring exceptions or workarounds.
## Phase 0: Research & Technology Decisions
### Technology Stack Rationale
#### Node.js 20 LTS + TypeScript
**Decision**: Use Node.js 20 LTS with TypeScript 6.0.2 for type safety and modern JavaScript features
**Rationale**:
- MCP SDK officially supports Node.js with comprehensive TypeScript typings
- Strong ecosystem for HTTP servers and real-time streaming (SSE)
- TypeScript provides compile-time type checking reducing runtime errors
- ES2022 features (top-level await, private fields) improve code quality
- Active LTS support ensures stability and security updates
**Alternatives Considered**:
- Python with FastAPI: Good MCP support but weaker typing story, slower cold starts
- Go: Excellent performance but less mature MCP ecosystem
- Deno: Modern runtime but MCP SDK compatibility uncertain
#### MCP SDK Architecture
**Decision**: Use high-level `McpServer` from `@modelcontextprotocol/server` package
**Rationale**:
- Simplified tool registration API: `registerTool(name, config, callback)`
- Automatic JSON-RPC 2.0 message handling
- Built-in error handling and protocol validation
- Recommended approach per MCP SDK examples
- Reduces boilerplate compared to low-level `Server` class
**Implementation**:
```typescript
const server = new McpServer(
{ name: 'gds-mock-mcp', version: '0.1.0' },
{ capabilities: { tools: {}, logging: {} } }
);
server.registerTool('searchFlights', { description, inputSchema }, handler);
```
#### Valkey for State Storage
**Decision**: Valkey 8.0+ (Redis-compatible) for session and booking storage
**Rationale**:
- In-memory performance (<1ms read/write) meets latency requirements
- TTL support for automatic PNR expiration (1 hour default)
- Connection pooling via ioredis client
- Redis protocol compatibility enables ecosystem tooling
- Optional persistence (RDB/AOF) for development convenience
**Alternatives Considered**:
- In-memory only: Fast but state lost on restart, not suitable for demos
- PostgreSQL: Overkill for mock data, adds deployment complexity
- SQLite: File-based but lacks TTL and concurrent access patterns
#### HTTP Transport Strategy
**Decision**: StreamableHTTPServerTransport in stateless mode with Express 5
**Rationale**:
- MCP HTTP specification (2025-11-25) mandates HTTP/1.1 + SSE
- Stateless mode allows horizontal scaling (no session affinity)
- Express 5 provides modern middleware architecture
- @modelcontextprotocol/express package simplifies integration
- Health endpoint (`/health`) for monitoring without MCP overhead
**Key Pattern**:
```typescript
const transport = new StreamableHTTPServerTransport({
sessionIdGenerator: undefined // Stateless - clients manage sessions
});
await transport.handleRequest(req, res); // Processes MCP messages
```
#### Logging Strategy
**Decision**: Structured JSON logging via pino with configurable levels
**Rationale**:
- Structured logs enable automated analysis and monitoring
- Pino is fastest Node.js logger (benchmarks show 10x faster than Winston)
- Log levels (DEBUG, INFO, ERROR) support development and production
- Tool execution tracking with duration metrics
- Correlation IDs via session tracking
**Output Example**:
```json
{
"level": "INFO",
"time": "2026-04-11T18:37:43.129Z",
"service": "gds-mock-mcp",
"tool": "searchFlights",
"sessionId": "abc123",
"duration": 45,
"msg": "Tool execution completed"
}
```
### Testing Approach
**Decision**: Node.js built-in test runner with contract tests for MCP compliance
**Rationale**:
- Node.js 20 includes native test runner (no external dependencies)
- Contract tests validate MCP tool schemas and responses
- Integration tests cover multi-step workflows (search → book → cancel)
- Unit tests for data generators and validation logic
**Test Categories**:
1. **Contract Tests**: Verify MCP tool schemas match declared types
2. **Integration Tests**: End-to-end workflows with Valkey
3. **Unit Tests**: Data generation, validation, PNR logic
### Development Tooling
**Decision**:
- `tsx` for development mode with hot reload
- `tsc` for production builds
- ESLint + Prettier for code quality
- Docker multi-platform builds (linux/amd64, linux/arm64)
**Scripts**:
```json
{
"dev": "tsx watch src/index.ts --verbose",
"build": "tsc",
"start": "node dist/index.js",
"test": "node --test tests/**/*.test.js"
}
```
| Violation | Why Needed | Simpler Alternative Rejected Because |
|-----------|------------|-------------------------------------|

View File

@@ -506,3 +506,571 @@ Verify you're retrieving from the same session that created the booking.
- Review data model in `/data-model.md`
- Check technical research in `/research.md`
- See implementation tasks in `/tasks.md` (after running `/speckit.tasks`)
---
## Remote Access Setup (HTTP/2 Mode)
The mock GDS server can be accessed remotely over HTTP/2, enabling distributed teams and web-based MCP clients.
### Remote Mode Configuration
**Update `.env` for remote access**:
```bash
# Transport Mode
TRANSPORT_MODE=http # Enable HTTP transport (or 'both' for stdio + http)
# HTTP Server
HTTP_PORT=3000 # Internal HTTP port (proxied by nginx)
HTTP_HOST=127.0.0.1 # Bind to localhost (nginx only)
# Rate Limiting
RATE_LIMIT_ENABLED=true
RATE_LIMIT_PER_MINUTE=100 # 100 requests per minute per IP
RATE_LIMIT_WINDOW_SECONDS=60
# PNR/Session Timeouts
PNR_TTL_HOURS=1 # Global PNR retrieval window
SESSION_TTL_HOURS=24 # Session expiration
# CORS
CORS_ENABLED=true
CORS_ORIGINS=* # Wildcard for development
CORS_MAX_AGE=86400
```
### Docker Compose Setup (Remote Mode)
**docker-compose.yml** (with nginx reverse proxy):
```yaml
version: '3.8'
services:
valkey:
image: valkey/valkey:8.0-alpine
ports:
- "6379:6379"
volumes:
- valkey-data:/data
command: valkey-server --appendonly yes
mcp-server:
build: .
environment:
TRANSPORT_MODE: http
HTTP_PORT: 3000
HTTP_HOST: 0.0.0.0
VALKEY_HOST: valkey
VALKEY_PORT: 6379
RATE_LIMIT_ENABLED: "true"
RATE_LIMIT_PER_MINUTE: 100
PNR_TTL_HOURS: 1
LOG_LEVEL: info
depends_on:
- valkey
ports:
- "3000:3000" # For development without nginx
nginx:
image: nginx:alpine
ports:
- "8080:8080" # External HTTP/2 port
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx/certs:/etc/nginx/certs:ro
depends_on:
- mcp-server
volumes:
valkey-data:
```
### Nginx Configuration
**nginx/nginx.conf**:
```nginx
events {
worker_connections 1024;
}
http {
upstream mcp_backend {
server mcp-server:3000;
}
server {
listen 8080 ssl http2;
server_name localhost;
# TLS Configuration
ssl_certificate /etc/nginx/certs/cert.pem;
ssl_certificate_key /etc/nginx/certs/key.pem;
ssl_protocols TLSv1.2 TLSv1.3;
# MCP Endpoints
location /mcp {
proxy_pass http://mcp_backend;
proxy_http_version 1.1;
# Headers for rate limiting and logging
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
# SSE Support (for MCP streaming)
proxy_buffering off;
proxy_cache off;
chunked_transfer_encoding on;
proxy_read_timeout 3600s;
# CORS (optional - can be handled by app)
add_header Access-Control-Allow-Origin * always;
add_header Access-Control-Expose-Headers 'X-RateLimit-Limit, X-RateLimit-Remaining' always;
}
# Health Check
location /health {
proxy_pass http://mcp_backend/health;
proxy_http_version 1.1;
access_log off; # Don't log health checks
}
}
}
```
### Generate Self-Signed Certificate (Development)
```bash
# Create certs directory
mkdir -p nginx/certs
# Generate self-signed certificate (valid 365 days)
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout nginx/certs/key.pem \
-out nginx/certs/cert.pem \
-subj "/C=US/ST=Dev/L=Local/O=MockGDS/CN=localhost"
# Set permissions
chmod 644 nginx/certs/cert.pem
chmod 600 nginx/certs/key.pem
```
### Start Remote Server
```bash
# Start all services
docker-compose up -d
# Check status
docker-compose ps
# View logs
docker-compose logs -f mcp-server nginx
# Test health endpoint
curl -k https://localhost:8080/health
# Test CORS
curl -i -H "Origin: https://example.com" -X OPTIONS https://localhost:8080/mcp
```
---
## Connecting Remote MCP Clients
### Web-Based Client (Browser)
```javascript
// Example: Connect from browser-based MCP client
const mcpClient = new MCPClient({
url: 'https://localhost:8080/mcp',
transport: 'sse', // Server-sent events
sessionId: generateSessionId() // Or let server generate
});
await mcpClient.connect();
// Call tools
const flights = await mcpClient.callTool('searchFlights', {
origin: 'JFK',
destination: 'LAX',
departureDate: '2026-06-15',
passengers: { adults: 1 },
cabin: 'economy'
});
console.log(`Found ${flights.resultCount} flights`);
```
### cURL Examples
**Search flights**:
```bash
curl -k -X POST https://localhost:8080/mcp \
-H "Content-Type: application/json" \
-H "MCP-Session-ID: $(uuidgen)" \
-d '{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "searchFlights",
"arguments": {
"origin": "JFK",
"destination": "LAX",
"departureDate": "2026-06-15",
"passengers": { "adults": 1 },
"cabin": "economy"
}
},
"id": 1
}'
```
**Check health**:
```bash
curl -k https://localhost:8080/health | jq
```
**Check rate limits**:
```bash
# Make multiple requests and check headers
for i in {1..5}; do
curl -k -i https://localhost:8080/health 2>&1 | grep -i ratelimit
done
```
---
## Rate Limiting Examples
### Normal Usage
```bash
# First request
curl -i https://localhost:8080/health
# Returns:
# X-RateLimit-Limit: 100
# X-RateLimit-Remaining: 99
# X-RateLimit-Reset: 1712486520
```
### Rate Limit Exceeded
```bash
# Make 101 requests in under 60 seconds
for i in {1..101}; do
curl -s https://localhost:8080/health > /dev/null
done
# 101st request returns:
# HTTP/1.1 429 Too Many Requests
# X-RateLimit-Limit: 100
# X-RateLimit-Remaining: 0
# X-RateLimit-Reset: 1712486520
# Retry-After: 15
#
# {
# "error": "Rate limit exceeded",
# "code": "RATE_LIMIT_EXCEEDED",
# "limit": 100,
# "current": 101,
# "resetAt": "2026-04-07T10:02:00.000Z",
# "retryAfter": 15
# }
```
### Waiting for Reset
```bash
# Wait until reset time
sleep 15
# Try again (should work)
curl https://localhost:8080/health
# Returns 200 OK with fresh rate limit
```
---
## Global PNR Retrieval Demo
Remote mode enables cross-session PNR retrieval for testing flexibility.
### Session 1: Create Booking
```bash
SESSION1=$(uuidgen)
curl -k -X POST https://localhost:8080/mcp \
-H "MCP-Session-ID: $SESSION1" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "bookFlight",
"arguments": {
"flightId": "flight_1",
"passengers": [{
"type": "adult",
"firstName": "John",
"lastName": "Doe",
"email": "john@example.com"
}]
}
},
"id": 1
}'
# Returns: { "pnr": "TEST-ABC123", ... }
```
### Session 2: Retrieve Same PNR
```bash
SESSION2=$(uuidgen)
curl -k -X POST https://localhost:8080/mcp \
-H "MCP-Session-ID: $SESSION2" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "retrieveBooking",
"arguments": {
"pnr": "TEST-ABC123"
}
},
"id": 1
}'
# Returns: Full PNR details (cross-session retrieval works!)
```
### After 1 Hour: PNR Expired
```bash
# Wait 1 hour (or set PNR_TTL_HOURS=0.01 for 36 seconds)
sleep 3660
curl -k -X POST https://localhost:8080/mcp \
-H "MCP-Session-ID: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "retrieveBooking",
"arguments": { "pnr": "TEST-ABC123" }
},
"id": 1
}'
# Returns:
# {
# "error": {
# "code": -32001,
# "message": "PNR TEST-ABC123 not found or expired"
# }
# }
```
---
## Security Recommendations
### Development Environment
**Safe for local development**:
- Use on localhost or private networks
- Self-signed certificates acceptable
- Wildcard CORS appropriate for testing
### Shared Development Server
⚠️ **Use network-level security**:
```bash
# Option 1: VPN Access
# Deploy server within VPN, require VPN connection
# Option 2: Firewall Rules
# Allow only specific IP ranges
iptables -A INPUT -p tcp --dport 8080 -s 10.0.0.0/8 -j ACCEPT
iptables -A INPUT -p tcp --dport 8080 -j DROP
# Option 3: Private Network (AWS/GCP)
# Deploy in private subnet, access via bastion host or VPN
```
### Production-Like Environment
**DO NOT deploy to public internet without authentication**:
- Mock server has no authentication (by design for v1)
- Wildcard CORS allows any origin
- Contains test data but still inappropriate for public exposure
**Future Enhancement**: Authentication layer for production deployments
---
## Monitoring & Observability
### Health Check Integration
**Kubernetes Liveness Probe**:
```yaml
livenessProbe:
httpGet:
path: /health
port: 8080
scheme: HTTPS
initialDelaySeconds: 30
periodSeconds: 10
```
**Prometheus Scraping**:
```yaml
scrape_configs:
- job_name: 'mcp-server'
scheme: https
tls_config:
insecure_skip_verify: true
static_configs:
- targets: ['localhost:8080']
metrics_path: '/health'
```
### Log Aggregation
**View structured logs**:
```bash
docker-compose logs -f mcp-server | jq
```
**Filter by session**:
```bash
docker-compose logs mcp-server | grep "sessionId:abc-123"
```
**Monitor rate limits**:
```bash
docker-compose logs mcp-server | grep "RATE_LIMIT_EXCEEDED"
```
---
## Troubleshooting (Remote Mode)
### Connection Refused
```bash
# Check if server is running
docker-compose ps
# Check if port is exposed
netstat -an | grep 8080
# Check nginx logs
docker-compose logs nginx
```
### CORS Errors in Browser
```javascript
// Console error: "Access-Control-Allow-Origin"
// Check CORS headers:
curl -i -H "Origin: https://example.com" https://localhost:8080/mcp
# Should include: Access-Control-Allow-Origin: *
```
### Rate Limit Too Restrictive
```bash
# Increase limit in .env
RATE_LIMIT_PER_MINUTE=1000
# Restart server
docker-compose restart mcp-server
```
### SSL Certificate Warnings
```bash
# Browser: "Your connection is not private"
# Expected with self-signed cert
# Production: Use Let's Encrypt
certbot certonly --standalone -d your-domain.com
# Update nginx.conf with real certificate paths
```
### PNR Not Found (Cross-Session)
```bash
# Verify PNR is within TTL window
curl https://localhost:8080/health | jq .uptime
# If uptime > 3600 and PNR_TTL_HOURS=1, PNR may have expired
# Check Valkey directly
docker-compose exec valkey valkey-cli
> KEYS pnr:*
> TTL pnr:TEST-ABC123
```
---
## Performance Testing (Remote Mode)
### Load Testing with `ab` (Apache Bench)
```bash
# Test health endpoint (10000 requests, 100 concurrent)
ab -n 10000 -c 100 -k https://localhost:8080/health
# Expected: <2s for 10k requests
```
### Rate Limit Testing
```bash
# Verify rate limiting kicks in
ab -n 200 -c 1 https://localhost:8080/health
# Should see ~100 successful, ~100 rate limited (429)
```
### Concurrent Sessions
```bash
# Simulate 50 concurrent sessions
for i in {1..50}; do
(
SESSION=$(uuidgen)
curl -k -X POST https://localhost:8080/mcp \
-H "MCP-Session-ID: $SESSION" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"tools/list","id":1}' &
)
done
wait
# Check health to see connection count
curl -k https://localhost:8080/health | jq .connections
```
---
## Next Steps (Remote Mode)
1. ✅ Set up Docker Compose with nginx reverse proxy
2. ✅ Generate TLS certificates for development
3. ✅ Configure environment variables for remote access
4. ✅ Test health endpoint and CORS
5. ✅ Verify rate limiting behavior
6. ✅ Test cross-session PNR retrieval
7. ✅ Monitor logs and health metrics
8. 🔄 Integrate with your web-based MCP client
9. 🔄 Deploy to shared development environment (with VPN/firewall)
10. 📋 Plan authentication layer for future production use

View File

@@ -297,3 +297,462 @@ Proceed to Phase 1: Design & Contracts
- Define MCP tool contracts in contracts/
- Generate quickstart.md with usage examples
- Update agent context with technology decisions
---
## Remote Access Research (Added 2026-04-07)
This section documents research findings for remote MCP access requirements based on clarifications received after initial planning.
### Decision 8: Streamable HTTP Transport Implementation (MCP Specification Compliant)
**Decision**: Use MCP SDK's `StreamableHTTPServerTransport` over HTTP/1.1 with Server-Sent Events (SSE)
**Question**: How to implement remote transport for MCP SDK per official specification?
**Investigation Findings**:
The MCP specification (2025-11-25) defines **Streamable HTTP** as the standard remote transport. The MCP SDK (@modelcontextprotocol/sdk v1.0.4) provides official transport implementations:
1. **StdioServerTransport** - stdio for local process communication
2. **StreamableHTTPServerTransport** - Remote HTTP/1.1 using SSE (spec-compliant)
3. **WebStandardStreamableHTTPServerTransport** - Platform-agnostic HTTP
4. **SSEServerTransport** - Deprecated legacy transport
**Key Finding**: MCP's **Streamable HTTP** transport uses HTTP/1.1 with Server-Sent Events (SSE), NOT HTTP/2. The specification requires:
- Single endpoint supporting POST, GET, and DELETE methods
- POST for client→server messages (returns SSE stream or 202)
- GET for server→client message stream (optional)
- DELETE for explicit session termination
- SSE for server→client streaming
- Session management via `Mcp-Session-Id` header
- Protocol version via `MCP-Protocol-Version` header (REQUIRED per clarification 2026-04-08)
- Origin header validation for security
- SSE polling pattern: Server sends initial event with ID and empty data, MAY close connection after response, clients reconnect using Last-Event-ID, server sends `retry` field before closing
**Integration Approaches Evaluated**:
**Option A: Native HTTP/1.1 + SSE (MCP Spec Compliant)** ⭐ SELECTED
```
Client → Node.js MCP Server (HTTP/1.1 + SSE via StreamableHTTPServerTransport)
```
- ✅ Direct implementation per MCP specification
- ✅ Zero code complexity - use SDK's `StreamableHTTPServerTransport` directly
- ✅ Single process deployment (no reverse proxy required for spec compliance)
- ✅ Simplified debugging and local development
- ✅ Meets all MCP security requirements (Origin validation, localhost binding)
- ⚠️ Optional: Can add Nginx/Caddy for TLS termination and HTTP/2 upgrade (production enhancement)
**Option B: Reverse Proxy with HTTP/2 Upgrade**
```
Client (HTTP/2) → Nginx/Caddy (HTTP/2 → HTTP/1.1) → Node.js MCP Server (HTTP/1.1+SSE)
```
- ✅ Adds HTTP/2 multiplexing for client connections
- ✅ TLS termination in reverse proxy
- ⚠️ Adds deployment complexity
- ⚠️ Not required for MCP specification compliance
**Rationale for Selection**:
- MCP specification explicitly defines Streamable HTTP as HTTP/1.1 + SSE
- HTTP/2 is an optional enhancement, not a requirement
- Simpler deployment path (single Node.js process)
**Implementation Strategy**:
```javascript
// src/transports/streamable-http.js
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
import http from 'node:http';
import { randomUUID } from 'node:crypto';
export class HTTPTransport {
constructor(options = {}) {
this.port = options.port || 3000;
this.host = options.host || '127.0.0.1'; // Localhost for proxy
this.mcpTransport = new StreamableHTTPServerTransport({
sessionIdGenerator: () => randomUUID(),
enableJsonResponse: false // Use SSE streaming
});
this.server = http.createServer(async (req, res) => {
// CORS, rate limiting, health check middleware
// Then delegate to mcpTransport.handleRequest()
});
}
}
```
**Docker Configuration**:
```yaml
# docker-compose.yaml
services:
mcp-server:
environment:
TRANSPORT_MODE: http
HTTP_PORT: 3000
HTTP_HOST: 127.0.0.1 # Only accessible via nginx
nginx:
image: nginx:alpine
ports:
- "8080:8080" # External HTTP/2 port
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
depends_on:
- mcp-server
```
**Nginx Configuration** (nginx/nginx.conf):
```nginx
server {
listen 8080 ssl http2;
server_name localhost;
ssl_certificate /etc/nginx/certs/cert.pem;
ssl_certificate_key /etc/nginx/certs/key.pem;
location /mcp {
proxy_pass http://mcp-server:3000;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
# SSE support
proxy_buffering off;
proxy_cache off;
chunked_transfer_encoding on;
}
location /health {
proxy_pass http://mcp-server:3000/health;
}
}
```
**Alternatives**: Future enhancement can add native HTTP/2 option for single-binary deployment.
---
### Decision 9: MCP Session Management for Remote Access
**Decision**: Stateful sessions with Valkey backing, MCP Session ID mapped to Valkey session
**Question**: How should connection lifecycle and session management work for remote MCP?
**Key Distinction**: HTTP/2 Stream ≠ MCP Session
- **HTTP/2 Stream**: Single request/response cycle, multiplexed over one TCP connection
- **MCP Session**: Persistent identifier (`sessionId`) spanning multiple HTTP requests
- **Valkey Session**: Business logic session tracking PNRs, searches, user context
**Session Lifecycle**:
1. **Initialize**: Client connects → Transport generates sessionId (UUID) → Create Valkey session
2. **Active**: Client makes requests with `MCP-Session-ID` header → Refresh session TTL
3. **Idle**: No requests for N minutes → Session remains in Valkey (TTL not expired)
4. **Expired**: TTL reaches zero → Valkey auto-deletes session data
5. **Reconnect**: Client can resume with same `MCP-Session-ID` header
**Storage Pattern**:
```
session:{sessionId}:metadata → { createdAt, lastActivityAt, transportType, remoteIP }
session:{sessionId}:searches → Recent search results (optional caching)
session:{sessionId}:pnrs → Set of PNR codes created in this session
pnr:{pnr} → Global PNR storage (not session-namespaced)
```
**Implementation**:
```javascript
// src/session/manager.js
async function handleToolCall(request, sessionId) {
if (!sessionId) throw new Error('Session ID required');
let valkeySession = await sessionManager.getSession(sessionId);
if (!valkeySession) {
valkeySession = await sessionManager.createSession(sessionId);
}
await sessionManager.updateActivity(sessionId);
return await toolHandler(request.params, sessionId);
}
```
**Session Isolation**: Each session has isolated Valkey namespace. PNRs stored globally (separate from sessions).
---
### Decision 10: IP-Based Rate Limiting Algorithm
**Decision**: Sliding Window Counter (Hybrid Approach)
**Question**: What rate limiting algorithm works for IP-based tracking without authentication?
**Algorithms Evaluated**:
1. **Fixed Window**: Simple but has burst problem (200 req in 1 second across window boundary)
2. **Sliding Window Log**: Accurate but high memory (stores timestamp per request)
3. **Sliding Window Counter**: Approximation balancing accuracy and performance ⭐ SELECTED
4. **Token Bucket**: Good for burst allowance but complex state management
**Selected Algorithm**: Sliding Window Counter
- ✅ Prevents large bursts (unlike fixed window)
- ✅ Low memory (2 counters per IP)
- ✅ Simple implementation (no Lua scripts required)
- ✅ Accuracy within 1-2% of perfect sliding window
**Implementation**:
```javascript
// src/remote/ratelimit.js
async function checkRateLimit(clientIP, limit = 100, windowSeconds = 60) {
const now = Math.floor(Date.now() / 1000);
const currentWindow = Math.floor(now / windowSeconds);
const previousWindow = currentWindow - 1;
const currentKey = `ratelimit:${clientIP}:${currentWindow}`;
const previousKey = `ratelimit:${clientIP}:${previousWindow}`;
const [currentCount, previousCount] = await Promise.all([
storage.incr(currentKey),
storage.get(previousKey) || 0
]);
if (currentCount === 1) {
await storage.expire(currentKey, windowSeconds * 2);
}
const elapsedInWindow = now % windowSeconds;
const previousWeight = 1 - (elapsedInWindow / windowSeconds);
const estimatedCount = (previousCount * previousWeight) + currentCount;
if (estimatedCount > limit) {
throw new RateLimitError({ limit, current: Math.floor(estimatedCount) });
}
return { allowed: true, remaining: limit - Math.floor(estimatedCount) };
}
```
**Performance**: ~3 Valkey ops per request, ~100 bytes per IP, within 1-2% of perfect sliding window.
**HTTP Headers**:
```
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1712486460
Retry-After: 15
```
**Client IP Extraction**:
```javascript
function getClientIP(request) {
const forwarded = request.headers['x-forwarded-for'];
if (forwarded) return forwarded.split(',')[0].trim();
const realIP = request.headers['x-real-ip'];
if (realIP) return realIP;
return request.socket.remoteAddress;
}
```
**Configuration**:
```bash
RATE_LIMIT_ENABLED=true
RATE_LIMIT_PER_MINUTE=100
RATE_LIMIT_WINDOW_SECONDS=60
```
---
### Decision 11: Global PNR Storage with TTL
**Decision**: Global namespace with SETEX, independent PNR lifecycle from sessions
**Question**: How to implement global PNR retrieval across sessions with configurable expiration?
**Requirements**:
1. PNRs globally retrievable (any session can retrieve any PNR)
2. PNRs expire after TTL (default 1 hour)
3. PNR creation session logged but doesn't restrict retrieval
4. Session expiration doesn't delete PNRs
**Storage Pattern**:
**Global PNR** (not session-scoped):
```
pnr:TEST-ABC123 → { pnr, status, segments, passengers, createdAt, expiresAt, creatingSessionId }
```
**Session Reference** (for listBookings tool):
```
session:{sessionId}:pnrs → Set<pnr> // PNRs created in this session
```
**Implementation**:
```javascript
// Create PNR
async function createPNR(pnrData, ttlHours = 1) {
const pnr = generatePNR(); // TEST-XXXXXX
const ttlSeconds = ttlHours * 3600;
const pnrRecord = {
pnr,
status: 'confirmed',
createdAt: new Date().toISOString(),
expiresAt: new Date(Date.now() + ttlSeconds * 1000).toISOString(),
creatingSessionId: pnrData.sessionId, // For logging only
...pnrData
};
// Store globally with TTL
await storage.setex(`pnr:${pnr}`, ttlSeconds, JSON.stringify(pnrRecord));
// Add to session's created PNRs list
await storage.sadd(`session:${pnrData.sessionId}:pnrs`, pnr);
return pnrRecord;
}
// Retrieve PNR (global, any session)
async function retrieveBooking({ pnr }, sessionId) {
const pnrData = await storage.get(`pnr:${pnr}`);
if (!pnrData) {
throw new NotFoundError(`PNR ${pnr} not found or expired`);
}
return JSON.parse(pnrData);
}
// List PNRs created in session
async function listBookings({ limit = 10 }, sessionId) {
const pnrCodes = await storage.smembers(`session:${sessionId}:pnrs`);
const pnrs = await Promise.all(
pnrCodes.map(async (code) => {
const data = await storage.get(`pnr:${code}`);
return data ? JSON.parse(data) : null;
})
);
return pnrs.filter(Boolean).slice(0, limit);
}
```
**Edge Cases**:
1. **PNR Expired**: `retrieveBooking` returns "PNR not found or expired"
2. **Session Expires Before PNR**: PNR remains globally retrievable
3. **List After Session Expiry**: Returns empty (session reference deleted)
**Configuration**:
```bash
PNR_TTL_HOURS=1
SESSION_TTL_HOURS=24
```
**Storage Efficiency**: ~2KB per PNR, 1000 PNRs = 2MB, auto-cleanup via Valkey TTL.
---
### Decision 12: CORS Configuration
**Decision**: Permissive Wildcard CORS with Network-Level Access Control
**Question**: How to configure CORS for web-based MCP clients?
**CORS Policy**: `Access-Control-Allow-Origin: *` (wildcard)
**Rationale**:
- ✅ Maximum compatibility - any web client can connect from any domain
- ✅ Simplifies development - no origin whitelist configuration
- ✅ Enables browser tools, Chrome extensions, web IDEs
- ⚠️ Requires network-level security (firewall, VPN, private network)
- ⚠️ Only acceptable for trusted development/testing environments
**Security Implications**:
1. **No Credentials**: Wildcard incompatible with `Access-Control-Allow-Credentials: true` (acceptable - we have no auth)
2. **Public Data**: Any website can make requests (acceptable - test data only)
3. **CSRF Potential**: Limited risk (no authentication, state changes require valid PNR)
4. **Network Security**: Deploy within private networks, use firewall rules
**Implementation**:
```javascript
// src/remote/cors.js
export function applyCORS(req, res) {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Credentials', 'false');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, MCP-Session-ID');
res.setHeader('Access-Control-Expose-Headers', 'X-RateLimit-Limit, X-RateLimit-Remaining');
res.setHeader('Access-Control-Max-Age', '86400');
if (req.method === 'OPTIONS') {
res.writeHead(204);
res.end();
return true; // Handled
}
return false; // Continue
}
```
**Nginx Alternative**:
```nginx
location /mcp {
if ($request_method = OPTIONS) {
add_header Access-Control-Allow-Origin * always;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
return 204;
}
add_header Access-Control-Allow-Origin * always;
proxy_pass http://mcp-server:3000;
}
```
**Security Posture**: Wildcard CORS acceptable for mock server because:
1. Contains only test data (no sensitive information)
2. No authentication (no credentials to steal)
3. Network-level access controls provide security boundary
4. Maximizes developer flexibility for ad-hoc tooling
**Configuration**:
```bash
CORS_ENABLED=true
CORS_ORIGINS=*
CORS_MAX_AGE=86400
```
---
## Remote Access Technology Summary
| Component | Technology | Decision |
|-----------|-----------|----------|
| **HTTP/2 Server** | Nginx reverse proxy | Terminate HTTP/2, proxy to HTTP/1.1 |
| **MCP Transport** | StreamableHTTPServerTransport | Over HTTP/1.1 (proxied) |
| **Rate Limiting** | Sliding window counter | Valkey-backed, IP-based |
| **PNR Storage** | Global with TTL | Valkey SETEX, independent lifecycle |
| **CORS** | Wildcard policy | `Access-Control-Allow-Origin: *` |
| **Health Check** | Unauthenticated endpoint | `/health` returning JSON status |
## Environment Variables (Remote Mode)
```bash
# Transport
TRANSPORT_MODE=stdio|http|both
HTTP_PORT=3000
HTTP_HOST=127.0.0.1
# Rate Limiting
RATE_LIMIT_ENABLED=true
RATE_LIMIT_PER_MINUTE=100
RATE_LIMIT_WINDOW_SECONDS=60
# PNR/Session
PNR_TTL_HOURS=1
SESSION_TTL_HOURS=24
# CORS
CORS_ENABLED=true
CORS_ORIGINS=*
CORS_MAX_AGE=86400
```
## Next Steps
All remote access research complete. Proceed to update:
1. ✅ data-model.md - Add RemoteConnection, RateLimitRecord, HealthStatus entities
2. ✅ contracts/ - Add health endpoint contract
3. ✅ quickstart.md - Add remote access setup instructions

View File

@@ -5,6 +5,22 @@
**Status**: Draft
**Input**: User description: "Build a Mock GDS MCP Server"
## Clarifications
### Session 2026-04-07
- Q: Authentication implementation approach for remote connections → A: Don't implement authentication at this time (authentication deferred to future version, remote access will be open/unauthenticated for initial implementation)
- Q: Remote transport protocol selection → A: HTTP/2 with streaming (modern HTTP version with multiplexed streams for efficient concurrent request handling)
- Q: Session expiry and PNR lifecycle behavior → A: Global with TTL - PNRs are globally retrievable for a configurable time period (e.g., 1 hour) after creation, regardless of which session created them, allowing cross-session retrieval for testing flexibility
- Q: CORS policy configuration for web clients → A: Allow all origins (*) - Permissive wildcard CORS policy allowing any web client to connect, suitable for open development/testing environments
- Q: Rate limiting identifier without authentication → A: Client IP address - Track request rates per source IP address to prevent abuse while supporting unauthenticated access
### Session 2026-04-08
- Q: MCP transport protocol implementation - correct specification compliance → A: Implement MCP Streamable HTTP spec (HTTP/1.1 + SSE) - Follow the official MCP 2025-11-25 specification: HTTP/1.1 with Server-Sent Events, single /mcp endpoint with POST/GET/DELETE methods, event IDs for resumability, MCP-Protocol-Version header handling. Optional Nginx reverse proxy can upgrade to HTTP/2 for clients while proxying HTTP/1.1 to the application.
- Q: SSE connection management strategy for resource efficiency → A: Implement SSE polling pattern with connection closure - Server sends initial event with ID and empty data to prime reconnection, then MAY close the HTTP connection (not stream) after sending responses to reduce resource usage. Clients reconnect using Last-Event-ID header to resume. Server sends retry field before closing connections per MCP 2025-11-25 specification.
- Q: MCP-Protocol-Version header validation behavior → A: Require MCP-Protocol-Version header on all requests - Reject requests without the header with 400 Bad Request immediately, forcing all clients to send version explicitly with no backward compatibility fallback.
## User Scenarios & Testing *(mandatory)*
### User Story 1 - Flight Search and Booking (Priority: P1)
@@ -72,6 +88,23 @@ A QA team runs automated integration tests that execute multiple booking scenari
---
### User Story 6 - Remote Access for Distributed Teams (Priority: P2)
A distributed development team needs to access the mock GDS server from different locations without setting up local instances. Remote developers connect to a centrally hosted mock server over the internet and execute booking workflows from their local development environments or web-based tools. The remote server handles multiple concurrent connections while maintaining session isolation.
**Why this priority**: Enables distributed teams to share a single mock server instance, reducing setup overhead and ensuring consistency across team members. Remote access supports cloud-based development environments, CI/CD pipelines running in the cloud, and web-based MCP clients that cannot use local stdio connections.
**Independent Test**: Can be tested by deploying the server to a public endpoint, connecting from multiple external clients, executing parallel booking workflows, and verifying that each session maintains proper isolation and receives correct responses. Confirms remote multi-user capability.
**Acceptance Scenarios**:
1. **Given** a remote MCP client, **When** the client connects to the server's public endpoint, **Then** the system establishes a connection and responds to MCP tool calls with the same functionality as stdio mode
2. **Given** web-based MCP clients from different origins, **When** clients connect to the server, **Then** the system allows connections and handles cross-origin requests appropriately
3. **Given** multiple remote clients connected simultaneously, **When** each executes independent booking workflows, **Then** the system maintains separate session contexts and prevents data leakage between remote sessions
4. **Given** monitoring tools checking server availability, **When** health check endpoints are queried, **Then** the system returns status information indicating operational readiness
---
### 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.
@@ -94,7 +127,7 @@ A sales team demonstrates travel booking software to potential customers. They n
- **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.
- **Session Expiry**: PNRs remain globally retrievable for a configurable time period (default 1 hour) after creation, regardless of which session created them or whether that session is still active. After the TTL expires, PNR retrieval returns "PNR not found or expired" error. This allows testing scenarios where bookings need to be retrieved across different sessions or after reconnection.
- **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").
@@ -106,6 +139,22 @@ A sales team demonstrates travel booking software to potential customers. They n
- **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).
### Remote Access Edge Cases
- **Rapid Connection Attempts**: What happens when a client attempts to connect 20 times in quick succession (potential connection retry loop)? System should handle connection rate limiting separately from request rate limiting, allowing reasonable reconnection attempts but preventing connection floods.
- **CORS Preflight Failures**: What happens when a web-based client from an allowed origin sends preflight OPTIONS requests? System must respond correctly to preflight requests to enable web clients to complete connection establishment.
- **Concurrent Requests from Same Remote Session**: What happens when a remote client sends 10 simultaneous booking requests in parallel using the same session? System should handle concurrent requests within a session appropriately - either process them in parallel maintaining consistency, or serialize them with appropriate queuing.
- **Health Check During High Load**: What happens when health check endpoint is queried while server is processing maximum concurrent connections? Health check should remain responsive (sub-second response) even under load, possibly with degraded status if resource utilization is high.
- **Rate Limit Edge Conditions**: What happens when a client makes exactly the limit number of requests at the boundary of a time window? System should handle edge cases consistently (requests at exactly the limit boundary should either all succeed or clearly fail with limit message, not random behavior).
- **Connection Cleanup on Client Crash**: What happens when a remote client crashes or loses network connectivity without gracefully closing the connection? System should detect inactive connections (no requests for N minutes) and clean up associated resources, freeing session data for garbage collection.
- **Invalid Origin Headers**: What happens when a remote client sends requests with spoofed or missing Origin headers? System should validate CORS based on request characteristics and either allow (if origin validation passes) or deny with appropriate CORS error.
## Requirements *(mandatory)*
### Functional Requirements
@@ -142,7 +191,7 @@ A sales team demonstrates travel booking software to potential customers. They n
- **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-017**: System MUST maintain booking state persistence with configurable TTL (default 1 hour) - bookings remain globally retrievable from any session until TTL expiration, after which they return "not found" errors
- **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
@@ -150,6 +199,40 @@ A sales team demonstrates travel booking software to potential customers. They n
- **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
### Remote Access Functional Requirements
- **FR-021**: System MUST support both stdio transport (for local MCP clients) and remote transport (for internet-accessible MCP clients), with transport mode configurable via environment settings
- **FR-022**: System MUST implement MCP Streamable HTTP transport per specification 2025-11-25: HTTP/1.1 with Server-Sent Events (SSE), single /mcp endpoint supporting POST (client-to-server messages with SSE response), GET (server-to-client message stream), and DELETE (session termination) methods, event IDs for stream resumability, MCP-Protocol-Version header handling, and MCP-Session-Id header for session management. The application uses HTTP/1.1 + SSE; optional reverse proxy (Nginx/Caddy) may upgrade client connections to HTTP/2 while proxying HTTP/1.1 to the application.
- **FR-022a**: System MUST implement SSE polling pattern for resource efficiency: send initial event with ID and empty data field to prime client reconnection, MAY close HTTP connection (not stream) after sending responses to reduce resource usage, clients reconnect using Last-Event-ID header to resume stream, and server MUST send retry field (milliseconds) before closing connections to guide client reconnection timing per MCP specification.
- **FR-022b**: System MUST require MCP-Protocol-Version header on all remote HTTP requests and reject requests without this header with HTTP 400 Bad Request and error message indicating the missing required header. System MUST validate the header value and support protocol version 2025-11-25, rejecting unsupported versions with HTTP 400 Bad Request.
- **FR-023**: System MAY implement authentication for remote connections in future versions, but initial implementation allows unauthenticated access suitable for trusted development/testing environments
- **FR-024**: System MUST support cross-origin requests from web-based MCP clients using permissive CORS policy (Allow-Origin: *), enabling browser-based tools and applications from any domain to connect to the remote server
- **FR-025**: System MUST enforce rate limiting on remote connections based on client IP address to prevent abuse, with configurable limits for requests per IP per time period (e.g., 100 requests per minute per IP address)
- **FR-026**: System MUST validate all input data from remote connections with security checks protecting against malicious payloads or injection attacks
- **FR-027**: System MUST provide health check endpoints that return operational status without requiring authentication, enabling monitoring systems and load balancers to verify server availability
- **FR-028**: System MUST maintain session isolation for remote clients identical to stdio sessions - each remote connection receives a unique session identifier with complete data isolation from other remote and local sessions
- **FR-029**: System MUST handle multiple concurrent remote client connections (minimum 50 simultaneous remote sessions) while maintaining performance and isolation guarantees
- **FR-030**: System MUST support secure connections using standard encryption for remote transport, protecting data in transit from client to server
- **FR-031**: System MUST log connection events and rate limit violations for remote connections in addition to standard operation logging, supporting operational monitoring
- **FR-032**: System MUST allow transport mode to be selected at server startup (stdio-only, remote-only, or both) to support different deployment scenarios from local development to public cloud hosting
- **FR-033**: System MUST gracefully handle remote client disconnections, cleaning up session resources and maintaining data consistency even when clients disconnect unexpectedly
- **FR-034**: System MUST provide the same MCP tool functionality and response format for both stdio and remote connections, ensuring consistent behavior regardless of transport method
### 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
@@ -160,14 +243,20 @@ A sales team demonstrates travel booking software to potential customers. They n
- **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
- **PNR (Passenger Name Record)**: Core booking entity containing unique 6-character alphanumeric identifier, booking status (confirmed/cancelled/pending), creation timestamp, expiration timestamp (creation time + configurable TTL, default 1 hour), list of all service segments (flights, hotels, cars), passenger/guest details, total price summary, payment method placeholder, and originating session identifier for logging purposes. PNRs are globally retrievable from any session until TTL expiration.
- **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
- **Session**: Represents an MCP connection session with unique session ID, creation timestamp, session expiry time, and isolation boundary ensuring no cross-session data access during operation. Sessions track which PNRs were created during the session for logging but do not restrict retrieval - PNRs remain accessible globally based on their own TTL.
- **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
- **Remote Connection**: Represents an active remote client connection with connection identifier, remote client IP address (for logging and rate limiting), connection start timestamp, last activity timestamp, transport protocol details, and associated session identifier
- **Rate Limit Record**: Tracks request rates per client IP address with IP address identifier, time window start, request count in current window, limit threshold, and next reset timestamp, enabling enforcement of usage limits to prevent abuse from individual source addresses
- **Health Status**: Represents server operational status with overall health state (healthy/degraded/unhealthy), active connection counts (stdio and remote), resource utilization metrics, uptime duration, and any current issues or warnings
## Success Criteria *(mandatory)*
### Measurable Outcomes
@@ -192,6 +281,24 @@ A sales team demonstrates travel booking software to potential customers. They n
- **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
### Remote Access Success Criteria
- **SC-011**: Remote developers can connect to a deployed server instance from any location with internet access and complete booking workflows with the same sub-30-second performance as local stdio connections
- **SC-012**: System handles 50 concurrent remote clients executing independent booking workflows simultaneously while maintaining sub-2-second response times and complete session isolation
- **SC-013**: Web-based MCP clients from different domains can successfully connect and execute MCP tools without CORS-related failures, enabling browser-based development tools
- **SC-014**: Rate limiting prevents abuse while allowing legitimate usage - clients can execute at least 100 requests per minute under normal operation, with clear error messages when limits are exceeded
- **SC-015**: Health check endpoints respond within 500ms and accurately reflect server operational status, enabling effective monitoring and automated health checks by deployment platforms
- **SC-016**: Distributed teams can share a single remote server instance without coordination overhead - each developer receives isolated session data regardless of how many other team members are connected
- **SC-017**: Remote connections survive typical network interruptions - temporary disconnections of under 30 seconds result in automatic reconnection without data loss or session corruption
- **SC-018**: Transport mode configuration is clear and validated at startup - invalid configuration (missing required settings, contradictory options) results in immediate startup failure with specific error messages indicating the configuration problem
## 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.
@@ -200,7 +307,7 @@ A sales team demonstrates travel booking software to potential customers. They n
- **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.
- **Session Duration**: Sessions remain active for the duration of the MCP connection. When the connection closes, session metadata may be cleaned up, but PNRs created during that session remain retrievable globally based on their own TTL (default 1 hour from creation). This allows test scenarios to create bookings in one session and verify them in another.
- **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.
@@ -217,3 +324,29 @@ A sales team demonstrates travel booking software to potential customers. They n
- **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.
### Remote Access Assumptions
- **Network Environment**: Remote deployments assume standard cloud hosting environments with public internet access and no unusual firewall restrictions. Complex enterprise network configurations (corporate proxies, VPNs, non-standard ports) may require additional configuration.
- **MCP Transport Protocol**: System implements MCP Streamable HTTP transport per specification 2025-11-25 using HTTP/1.1 with Server-Sent Events (SSE). Optional reverse proxy (Nginx, Caddy) may be deployed to upgrade client connections to HTTP/2 while proxying HTTP/1.1 to the application, but this is an infrastructure enhancement not required for MCP specification compliance.
- **No Authentication (Initial Version)**: Initial implementation provides open/unauthenticated remote access suitable for trusted development/testing environments. Authentication may be added in future versions when deployment to less trusted environments is required.
- **Rate Limiting Scope**: Rate limits are designed to prevent abuse and accidental infinite loops, not to implement billing tiers or usage tracking. Limits are set at reasonable levels for development usage (hundreds of requests per minute) and may be adjusted based on deployment capacity. Rate limiting may be based on client IP address or connection identifier rather than authenticated credentials.
- **Security Posture**: Remote access is appropriate for development/testing environments with trusted team members on trusted networks. Initial version without authentication is NOT designed for public internet exposure to untrusted users. Deployment should use network-level access controls (firewalls, VPNs, private networks) to limit access to authorized development teams.
- **CORS Configuration**: CORS support uses permissive wildcard policy (Access-Control-Allow-Origin: *) allowing connections from any web origin. This maximizes development flexibility - web-based tools, browser extensions, and client applications from any domain can connect without CORS configuration. Suitable for trusted development/testing networks where access control is managed at the network layer (firewalls, VPNs) rather than application layer.
- **Connection Persistence**: Remote connections are expected to be relatively short-lived (minutes to hours, not days). Long-lived connections are supported but may be subject to cleanup on server restart or maintenance. No connection migration or state persistence across server restarts.
- **Health Check Usage**: Health checks are designed for basic operational monitoring and load balancer integration. They report simple up/down status and basic metrics, not comprehensive performance monitoring or detailed diagnostics.
- **Transport Coexistence**: When both stdio and remote transport are enabled simultaneously, they share the same mock data and session isolation boundaries but operate independently. No cross-transport session sharing or migration.
- **Deployment Model**: Remote deployments assume container-based hosting (Docker) or similar cloud deployment models. The system does not include installation packages, system service configurations, or traditional server deployment tooling.
- **SSL/TLS Termination**: Secure connections assume standard SSL/TLS termination at the server or load balancer level. The mock server itself focuses on application-level functionality and relies on deployment infrastructure for transport security.
- **Monitoring Integration**: Basic health endpoints are provided, but comprehensive monitoring (metrics collection, distributed tracing, log aggregation) relies on standard deployment infrastructure and observability tools, not custom mock server monitoring features.

View File

@@ -19,11 +19,11 @@
**Purpose**: Project initialization and basic structure from plan.md
- [ ] T001 Initialize Node.js 20 project with package.json including @modelcontextprotocol/sdk, ioredis, pino dependencies
- [ ] T002 Create project directory structure: src/{tools,data,session,validation,utils}/, tests/{integration,unit,fixtures}/, docker/
- [ ] T003 [P] Configure ESLint and Prettier for code quality in .eslintrc.json and .prettierrc
- [ ] T004 [P] Create .dockerignore and .gitignore files for build optimization
- [ ] T005 [P] Create docker-compose.yaml with Valkey service configuration (port 6379, persistence enabled)
- [X] T001 Initialize Node.js 20 project with package.json including @modelcontextprotocol/sdk, ioredis, pino dependencies
- [X] T002 Create project directory structure: src/{tools,data,session,validation,utils}/, tests/{integration,unit,fixtures}/, docker/
- [X] T003 [P] Configure ESLint and Prettier for code quality in .eslintrc.json and .prettierrc
- [X] T004 [P] Create .dockerignore and .gitignore files for build optimization
- [X] T005 [P] Create docker-compose.yaml with Valkey service configuration (port 6379, persistence enabled)
---
@@ -33,15 +33,15 @@
**⚠️ CRITICAL**: No user story work can begin until this phase is complete
- [ ] T006 Implement Pino structured logger setup in src/utils/logger.js with configurable log levels
- [ ] T007 [P] Implement error handling utilities in src/utils/errors.js with MCP error codes
- [ ] T008 [P] Create Valkey client wrapper in src/session/storage.js with connection pooling and error handling
- [ ] T009 [P] Implement JSON schema validators in src/validation/validators.js using native validation
- [ ] T010 [P] Create MCP tool schemas in src/validation/schemas.js based on contracts/mcp-tools.md
- [ ] T011 Create session lifecycle manager in src/session/manager.js with TTL management (1 hour default)
- [ ] T012 [P] Implement PNR generation utilities in src/data/pnr.js with TEST- prefix and base32 encoding
- [ ] T013 Initialize MCP server in src/server.js with @modelcontextprotocol/sdk Server class
- [ ] T014 Create MCP server entry point in src/index.js with stdio transport and error handling
- [X] T006 Implement Pino structured logger setup in src/utils/logger.js with configurable log levels
- [X] T007 [P] Implement error handling utilities in src/utils/errors.js with MCP error codes
- [X] T008 [P] Create Valkey client wrapper in src/session/storage.js with connection pooling and error handling
- [X] T009 [P] Implement JSON schema validators in src/validation/validators.js using native validation
- [X] T010 [P] Create MCP tool schemas in src/validation/schemas.js based on contracts/mcp-tools.md
- [X] T011 Create session lifecycle manager in src/session/manager.js with TTL management (1 hour default)
- [X] T012 [P] Implement PNR generation utilities in src/data/pnr.js with TEST- prefix and base32 encoding
- [X] T013 Initialize MCP server in src/server.js with @modelcontextprotocol/sdk Server class
- [X] T014 Create MCP server entry point in src/index.js with stdio transport and error handling
**Checkpoint**: Foundation ready - user story implementation can now begin in parallel
@@ -55,35 +55,35 @@
### Core Data for User Story 1
- [ ] T015 [P] [US1] Create airports mock data in src/data/airports.js with 100+ major airports (IATA codes, names, cities, timezones, coordinates)
- [ ] T016 [P] [US1] Create airlines mock data in src/data/airlines.js with 30+ carriers (IATA codes, names, countries)
- [ ] T017 [US1] Implement flight data generator in src/data/flights.js with deterministic pricing, duration calculation, and availability logic
- [X] T015 [P] [US1] Create airports mock data in src/data/airports.js with 100+ major airports (IATA codes, names, cities, timezones, coordinates)
- [X] T016 [P] [US1] Create airlines mock data in src/data/airlines.js with 30+ carriers (IATA codes, names, countries)
- [X] T017 [US1] Implement flight data generator in src/data/flights.js with deterministic pricing, duration calculation, and availability logic
### Flight Search Tool
- [ ] T018 [US1] Implement searchFlights tool handler in src/tools/flights.js with input validation (origin, destination, departureDate, passengers, cabin)
- [ ] T019 [US1] Add flight search result generation with 3-5 mock flights per search, realistic schedules (6am-10pm departures), and price ranges ($200-$800 economy, $800-$2000 business, $2500+ first)
- [ ] T020 [US1] Implement seat availability simulation (90% available, 10% sold out) and booking class assignment. **Note**: Implements infinite inventory model where concurrent bookings on same flight both succeed. This aligns with spec.md edge case discussion and is appropriate for mock server testing scope.
- [X] T018 [US1] Implement searchFlights tool handler in src/tools/flights.js with input validation (origin, destination, departureDate, passengers, cabin)
- [X] T019 [US1] Add flight search result generation with 3-5 mock flights per search, realistic schedules (6am-10pm departures), and price ranges ($200-$800 economy, $800-$2000 business, $2500+ first)
- [X] T020 [US1] Implement seat availability simulation (90% available, 10% sold out) and booking class assignment. **Note**: Implements infinite inventory model where concurrent bookings on same flight both succeed. This aligns with spec.md edge case discussion and is appropriate for mock server testing scope.
### Flight Booking Tool
- [ ] T021 [US1] Implement bookFlight tool handler in src/tools/flights.js with passenger validation (firstName, lastName, email, phone)
- [ ] T022 [US1] Add flight booking creation logic: validate flight selection, generate PNR via src/data/pnr.js, persist to Valkey with key gds:session:{sessionId}:booking:{pnr}
- [ ] T023 [US1] Implement PNR storage structure in Valkey with FlightSegment, Passenger, pricing, status fields per data-model.md
- [ ] T024 [US1] Add session booking tracking: update gds:session:{sessionId}:bookings set and increment bookingCount
- [X] T021 [US1] Implement bookFlight tool handler in src/tools/flights.js with passenger validation (firstName, lastName, email, phone)
- [X] T022 [US1] Add flight booking creation logic: validate flight selection, generate PNR via src/data/pnr.js, persist to Valkey with key gds:session:{sessionId}:booking:{pnr}
- [X] T023 [US1] Implement PNR storage structure in Valkey with FlightSegment, Passenger, pricing, status fields per data-model.md
- [X] T024 [US1] Add session booking tracking: update gds:session:{sessionId}:bookings set and increment bookingCount
### Booking Management Tools
- [ ] T025 [US1] Implement retrieveBooking tool handler in src/tools/bookings.js with PNR validation and Valkey lookup
- [ ] T026 [US1] Add booking retrieval logic: fetch from gds:session:{sessionId}:booking:{pnr}, return complete booking details with all segments
- [ ] T027 [US1] Implement cancelBooking tool handler in src/tools/bookings.js with status transition validation (confirmed→cancelled only)
- [ ] T028 [US1] Add cancellation logic: update booking status to 'cancelled', persist timestamp, return confirmation
- [X] T025 [US1] Implement retrieveBooking tool handler in src/tools/bookings.js with PNR validation and Valkey lookup
- [X] T026 [US1] Add booking retrieval logic: fetch from gds:session:{sessionId}:booking:{pnr}, return complete booking details with all segments
- [X] T027 [US1] Implement cancelBooking tool handler in src/tools/bookings.js with status transition validation (confirmed→cancelled only)
- [X] T028 [US1] Add cancellation logic: update booking status to 'cancelled', persist timestamp, return confirmation
### MCP Server Integration
- [ ] T029 [US1] Register searchFlights, bookFlight, retrieveBooking, cancelBooking tools in src/server.js with tool handlers
- [ ] T030 [US1] Add request/response logging for all flight operations with session ID, operation type, parameters, and response times
- [ ] T031 [US1] Implement error handling for invalid airport codes, invalid dates, validation failures with specific error messages per FR-014
- [X] T029 [US1] Register searchFlights, bookFlight, retrieveBooking, cancelBooking tools in src/server.js with tool handlers
- [X] T030 [US1] Add request/response logging for all flight operations with session ID, operation type, parameters, and response times
- [X] T031 [US1] Implement error handling for invalid airport codes, invalid dates, validation failures with specific error messages per FR-014
**FR-015 Coverage Note**: Multi-step booking workflows (search → price verification → select → confirm) are implemented through the task sequence T018-T028. The searchFlights tool (T018-T020) enables price verification, bookFlight (T021-T024) handles selection and confirmation, and retrieveBooking (T025-T026) supports workflow verification.
@@ -99,29 +99,102 @@
### Session Infrastructure
- [ ] T032 [US4] Implement session creation logic in src/session/manager.js: generate UUID v4 session ID on MCP connection initialization
- [ ] T033 [US4] Add session metadata storage in Valkey at gds:session:{sessionId} with createdAt, expiresAt, lastActivity, bookingCount, searchCount fields
- [ ] T034 [US4] Implement session TTL management: set EXPIRE on session keys (default 3600 seconds), refresh on activity
- [ ] T035 [US4] Add session validation middleware in src/session/manager.js: verify session exists and not expired before tool execution
- [X] T032 [US4] Implement session creation logic in src/session/manager.js: generate UUID v4 session ID on MCP connection initialization
- [X] T033 [US4] Add session metadata storage in Valkey at gds:session:{sessionId} with createdAt, expiresAt, lastActivity, bookingCount, searchCount fields
- [X] T034 [US4] Implement session TTL management: set EXPIRE on session keys (default 3600 seconds), refresh on activity
- [X] T035 [US4] Add session validation middleware in src/session/manager.js: verify session exists and not expired before tool execution
### Session Isolation
- [ ] T036 [US4] Implement session-scoped key prefixing in src/session/storage.js: all Valkey keys include session ID for isolation
- [ ] T037 [US4] Update booking storage to enforce session scope: gds:session:{sessionId}:booking:{pnr} pattern in all tools
- [ ] T038 [US4] Add session cleanup on expiry: implement background job or TTL-based cleanup for expired session data
- [ ] T039 [US4] Implement session statistics tracking: maintain gds:stats:sessions:active set, update gds:stats:bookings:total counter
- [X] T036 [US4] Implement session-scoped key prefixing in src/session/storage.js: all Valkey keys include session ID for isolation
- [X] T037 [US4] Update booking storage to enforce session scope: gds:session:{sessionId}:booking:{pnr} pattern in all tools
- [X] T038 [US4] Add session cleanup on expiry: implement background job or TTL-based cleanup for expired session data
- [X] T039 [US4] Implement session statistics tracking: maintain gds:stats:sessions:active set, update gds:stats:bookings:total counter
### Session Validation
- [ ] T040 [US4] Add cross-session isolation validation in retrieveBooking tool: verify PNR belongs to current session before returning
- [ ] T041 [US4] Implement session activity tracking in src/session/manager.js: update lastActivity timestamp on every tool call
- [ ] T042 [US4] Add session error responses for expired/invalid sessions with clear messages "Session expired" or "Session not found"
- [X] T040 [US4] Add cross-session isolation validation in retrieveBooking tool: verify PNR belongs to current session before returning
- [X] T041 [US4] Implement session activity tracking in src/session/manager.js: update lastActivity timestamp on every tool call
- [X] T042 [US4] Add session error responses for expired/invalid sessions with clear messages "Session expired" or "Session not found"
**Checkpoint**: Multiple MCP sessions can now run concurrently with complete isolation - bookings in one session never appear in another session.
---
## Phase 5: User Story 2 - Hotel Search and Multi-Service Bundling (Priority: P2)
## Phase 5: User Story 6 - Remote Access for Distributed Teams (Priority: P2)
**Goal**: Enable remote MCP access over Streamable HTTP (HTTP/1.1 + SSE per MCP 2025-11-25 specification) with rate limiting, CORS, health checks, and comprehensive security.
**Independent Test**: Start server with remote transport enabled, connect from remote MCP client over HTTP/1.1 using SSE for server-to-client messages and POST for client-to-server requests, execute flight search tool with MCP-Protocol-Version header, verify SSE polling pattern with connection closure and retry field, test Last-Event-ID resumption, verify rate limiting enforces 100 req/min default, test CORS preflight with wildcard origin, verify health endpoint returns service status, confirm MCP-Session-Id header management, confirm graceful shutdown preserves active sessions. All operations work independently of other user stories.
### Streamable HTTP Server Setup (MCP 2025-11-25 Compliant)
- [X] T043 [P] [US6] Update package.json with dependencies: @modelcontextprotocol/sdk for StreamableHTTPServerTransport, express for middleware
- [X] T044 [US6] Create Streamable HTTP server in src/transports/http-server.js using MCP SDK's StreamableHTTPServerTransport (HTTP/1.1 + SSE)
- [X] T045 [US6] Implement single /mcp endpoint supporting POST (client messages), GET (server message stream), DELETE (session termination) per MCP spec
- [X] T046 [US6] Add HTTP server lifecycle management: startup on configurable port, graceful shutdown (drain connections, 30s timeout), error handling
### SSE Polling Pattern Implementation (MCP 2025-11-25 Spec)
- [X] T047 [US6] Implement SSE event stream with unique event IDs for resumability in src/transports/sse-handler.js
- [X] T048 [US6] Add initial SSE event with ID and empty data field to prime client reconnection per MCP polling pattern
- [X] T049 [US6] Implement connection closure after response with `retry` field (default: 5000ms) to guide client reconnection timing
- [X] T050 [US6] Add Last-Event-ID header support for stream resumption when clients reconnect after disconnection
### MCP Protocol Version Validation
- [X] T051 [US6] Create protocol version middleware in src/middleware/protocol-version.js
- [X] T052 [US6] Implement MCP-Protocol-Version header validation: require header on all requests, reject missing/invalid versions with 400 Bad Request
- [X] T053 [US6] Add supported version check: accept 2025-11-25, reject unsupported versions with clear error message
### Session Management (MCP-Session-Id Header)
- [X] T054 [US6] Implement MCP-Session-Id header handling in src/session/session-manager.js
- [X] T055 [US6] Add session ID generation on InitializeResult response (cryptographically secure UUID)
- [X] T056 [US6] Validate MCP-Session-Id on subsequent requests: respond with 404 if session expired/not found
- [X] T057 [US6] Implement DELETE /mcp handler for explicit session termination
### Rate Limiting
- [X] T058 [P] [US6] Install express-rate-limit package in package.json for IP-based rate limiting
- [X] T059 [US6] Create rate limiter middleware in src/middleware/rate-limit.js with configurable limits (default: 100 req/min per IP)
- [X] T060 [US6] Implement rate limit enforcement: return 429 Too Many Requests with Retry-After header when limit exceeded
- [X] T061 [US6] Add rate limit headers to all responses: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset
- [X] T062 [US6] Implement rate limit storage in Valkey: use sliding window counter with key expiration (60s TTL)
### CORS Configuration (Wildcard Policy)
- [X] T063 [P] [US6] Install cors package in package.json for CORS middleware
- [X] T064 [US6] Create CORS handler in src/middleware/cors.js with permissive wildcard policy (Access-Control-Allow-Origin: *)
- [X] T065 [US6] Implement CORS preflight handling for OPTIONS requests: return allowed methods (GET, POST, DELETE, OPTIONS), headers (Content-Type, MCP-Session-Id, MCP-Protocol-Version)
- [X] T066 [US6] Add Origin header validation per MCP security requirement: respond with 403 Forbidden if Origin present and validation fails
### Health Checks
- [X] T067 [US6] Implement health check endpoint in src/remote/health.js returning GET /health with JSON status response
- [X] T068 [US6] Add service health indicators: Valkey connection status, active session count, uptime, memory usage
- [X] T069 [US6] Implement readiness check: return 503 Service Unavailable if Valkey is disconnected or critical services unavailable
- [X] T070 [US6] Add health check logging: log every 10th health check to avoid log spam, log all failed health checks immediately
### Security & Transport Selection
- [X] T071 [US6] Create transport factory in src/transports/factory.js to select stdio or Streamable HTTP based on TRANSPORT environment variable
- [X] T072 [US6] Implement environment-based configuration in src/config/remote.js: PORT (default: 3000), HOST (default: 127.0.0.1 per MCP security), RATE_LIMIT_MAX, CORS_ORIGINS
- [X] T073 [US6] Add request logging middleware in src/middleware/logger.js: log method, path, IP, User-Agent, MCP-Protocol-Version, duration, status code
- [X] T074 [US6] Implement localhost binding (127.0.0.1) by default per MCP security recommendation, document production deployment with reverse proxy
### Integration & Testing Infrastructure
- [X] T075 [US6] Update src/index.js to support dual transport modes: stdio (default) or Streamable HTTP (when TRANSPORT=http or --remote flag)
- [X] T076 [US6] Add CLI argument parsing in src/index.js: --remote (enable HTTP), --port <number>, --host <address>, --verbose, --log-level <level>
- [X] T077 [US6] Create remote access example client in tests/fixtures/remote-client.js demonstrating SSE connection, Last-Event-ID resumption, and tool invocation
- [X] T078 [US6] Add nginx.conf.example in docker/ for optional HTTP/2 upgrade reverse proxy (client-facing HTTP/2, backend HTTP/1.1)
**Checkpoint**: Remote access complete - developers can connect to MCP server over Streamable HTTP (HTTP/1.1 + SSE per MCP 2025-11-25 spec), enforced rate limits, wildcard CORS, MCP-Protocol-Version validation, SSE polling pattern with connection closure, Last-Event-ID resumption, and health monitoring. Transport selection via TRANSPORT env var or --remote flag.
---
## Phase 6: User Story 2 - Hotel Search and Multi-Service Bundling (Priority: P2)
**Goal**: Enable developers to test hotel search and multi-service booking workflows. Search hotels, create hotel bookings, and bundle hotels with flights under single PNR.
@@ -129,34 +202,34 @@
### Hotel Data
- [ ] T043 [P] [US2] Create hotels mock data in src/data/hotels.js with 50+ properties across major cities (names, chains, star ratings, addresses, amenities)
- [ ] T044 [US2] Implement hotel data generator with realistic pricing tiers: budget $80-$150, midrange $150-$300, luxury $300-$800 per night
- [X] T079 [P] [US2] Create hotels mock data in src/data/hotels.js with 50+ properties across major cities (names, chains, star ratings, addresses, amenities)
- [X] T080 [US2] Implement hotel data generator with realistic pricing tiers: budget $80-$150, midrange $150-$300, luxury $300-$800 per night
### Hotel Search Tool
- [ ] T045 [US2] Implement searchHotels tool handler in src/tools/hotels.js with input validation (cityCode, checkInDate, checkOutDate, guests)
- [ ] T046 [US2] Add hotel search result generation: 5-10 properties per search, calculate nights and total prices, include amenities (WiFi, parking, breakfast, gym, pool)
- [ ] T047 [US2] Implement date validation: checkInDate < checkOutDate, minimum 1 night stay, no past dates
- [X] T081 [US2] Implement searchHotels tool handler in src/tools/hotels.js with input validation (cityCode, checkInDate, checkOutDate, guests)
- [X] T082 [US2] Add hotel search result generation: 5-10 properties per search, calculate nights and total prices, include amenities (WiFi, parking, breakfast, gym, pool)
- [X] T083 [US2] Implement date validation: checkInDate < checkOutDate, minimum 1 night stay, no past dates
### Hotel Booking Tool
- [ ] T048 [US2] Implement bookHotel tool handler in src/tools/hotels.js with guest validation and room selection
- [ ] T049 [US2] Add hotel booking creation: generate or use existing PNR, persist HotelReservation to Valkey with check-in/check-out dates, room type, pricing
- [ ] T050 [US2] Implement multi-service bundling logic in src/tools/hotels.js: add hotel to existing PNR if provided, create new PNR if not
- [X] T084 [US2] Implement bookHotel tool handler in src/tools/hotels.js with guest validation and room selection
- [X] T085 [US2] Add hotel booking creation: generate or use existing PNR, persist HotelReservation to Valkey with check-in/check-out dates, room type, pricing
- [X] T086 [US2] Implement multi-service bundling logic in src/tools/hotels.js: add hotel to existing PNR if provided, create new PNR if not
### Multi-Service Integration
- [ ] T051 [US2] Update PNR structure in src/data/pnr.js to support multiple service segments: flights[], hotels[], cars[] arrays
- [ ] T052 [US2] Implement total price calculation across all segments: sum flight prices + hotel prices, update PNR totalPrice field
- [ ] T053 [US2] Add date consistency validation: hotel dates should overlap with flight dates, warn if hotel is outside travel period
- [ ] T054 [US2] Update retrieveBooking tool in src/tools/bookings.js to return complete multi-service itineraries with all segment types
- [ ] T055 [US2] Register searchHotels and bookHotel tools in src/server.js with tool handlers
- [X] T087 [US2] Update PNR structure in src/data/pnr.js to support multiple service segments: flights[], hotels[], cars[] arrays
- [X] T088 [US2] Implement total price calculation across all segments: sum flight prices + hotel prices, update PNR totalPrice field
- [X] T089 [US2] Add date consistency validation: hotel dates should overlap with flight dates, warn if hotel is outside travel period
- [X] T090 [US2] Update retrieveBooking tool in src/tools/bookings.js to return complete multi-service itineraries with all segment types
- [X] T091 [US2] Register searchHotels and bookHotel tools in src/server.js with tool handlers
**Checkpoint**: Developers can now search hotels, create hotel bookings, and bundle hotels with flights. Both flight-only and flight+hotel bookings work independently.
---
## Phase 6: User Story 3 - Car Rental and Complete Travel Package (Priority: P3)
## Phase 7: User Story 3 - Car Rental and Complete Travel Package (Priority: P3)
**Goal**: Complete the full travel package capability by adding car rentals. Search cars, create car bookings, and bundle with flights+hotels for complete end-to-end travel itineraries.
@@ -164,33 +237,33 @@
### Car Rental Data
- [ ] T056 [P] [US3] Create car rental mock data in src/data/cars.js with 6+ rental companies (Hertz, Avis, Enterprise codes and names)
- [ ] T057 [US3] Implement car rental data generator with vehicle classes: economy $35-$50, midsize $50-$80, SUV/luxury $100-$150 per day
- [X] T092 [P] [US3] Create car rental mock data in src/data/cars.js with 6+ rental companies (Hertz, Avis, Enterprise codes and names)
- [X] T093 [US3] Implement car rental data generator with vehicle classes: economy $35-$50, midsize $50-$80, SUV/luxury $100-$150 per day
### Car Rental Search Tool
- [ ] T058 [US3] Implement searchCars tool handler in src/tools/cars.js with input validation (pickupLocation, pickupDate, dropoffLocation, dropoffDate)
- [ ] T059 [US3] Add car search result generation: 4-6 vehicle classes per search, calculate rental days and total prices, include vehicle specs and mileage policies
- [ ] T060 [US3] Implement date validation: pickupDate < dropoffDate, minimum 1 day rental, location validation (airport/city codes)
- [X] T094 [US3] Implement searchCars tool handler in src/tools/cars.js with input validation (pickupLocation, pickupDate, dropoffLocation, dropoffDate)
- [X] T095 [US3] Add car search result generation: 4-6 vehicle classes per search, calculate rental days and total prices, include vehicle specs and mileage policies
- [X] T096 [US3] Implement date validation: pickupDate < dropoffDate, minimum 1 day rental, location validation (airport/city codes)
### Car Rental Booking Tool
- [ ] T061 [US3] Implement bookCar tool handler in src/tools/cars.js with driver validation and vehicle selection
- [ ] T062 [US3] Add car rental booking creation: generate or use existing PNR, persist CarRental to Valkey with pickup/dropoff details, vehicle class, pricing
- [ ] T063 [US3] Implement car bundling logic in src/tools/cars.js: add car to existing PNR, validate dates align with flight arrival/departure
- [X] T097 [US3] Implement bookCar tool handler in src/tools/cars.js with driver validation and vehicle selection
- [X] T098 [US3] Add car rental booking creation: generate or use existing PNR, persist CarRental to Valkey with pickup/dropoff details, vehicle class, pricing
- [X] T099 [US3] Implement car bundling logic in src/tools/cars.js: add car to existing PNR, validate dates align with flight arrival/departure
### Complete Package Integration
- [ ] T064 [US3] Update total price calculation in src/data/pnr.js to include car rental prices: sum flights + hotels + cars
- [ ] T065 [US3] Add chronological itinerary ordering in retrieveBooking: sort segments by date/time (flight arrival → car pickup → hotel check-in → hotel check-out → car dropoff → return flight)
- [ ] T066 [US3] Implement date consistency validation for cars: pickup should align with flight arrival, dropoff should align with departure
- [ ] T067 [US3] Register searchCars and bookCar tools in src/server.js with tool handlers
- [X] T100 [US3] Update total price calculation in src/data/pnr.js to include car rental prices: sum flights + hotels + cars
- [X] T101 [US3] Add chronological itinerary ordering in retrieveBooking: sort segments by date/time (flight arrival → car pickup → hotel check-in → hotel check-out → car dropoff → return flight)
- [X] T102 [US3] Implement date consistency validation for cars: pickup should align with flight arrival, dropoff should align with departure
- [X] T103 [US3] Register searchCars and bookCar tools in src/server.js with tool handlers
**Checkpoint**: Full GDS capability is now complete - developers can create comprehensive travel packages with flights, hotels, and cars all bundled under one PNR.
---
## Phase 7: User Story 5 - Realistic Test Data for Demonstrations (Priority: P3)
## Phase 8: User Story 5 - Realistic Test Data for Demonstrations (Priority: P3)
**Goal**: Polish mock data quality to enable professional sales demonstrations and training scenarios with recognizable brands, realistic pricing, and diverse route coverage.
@@ -198,76 +271,76 @@
### Enhanced Mock Data Quality
- [ ] T068 [P] [US5] Expand airports mock data in src/data/airports.js to include 50+ international hubs (London LHR, Paris CDG, Tokyo NRT, Dubai DXB, etc.)
- [ ] T069 [P] [US5] Add major hotel chains to src/data/hotels.js: Marriott, Hilton, Hyatt, IHG properties in 20+ major cities worldwide
- [ ] T070 [P] [US5] Enhance airline data in src/data/airlines.js with international carriers: British Airways, Virgin Atlantic, Lufthansa, Emirates, ANA, JAL
- [X] T104 [P] [US5] Expand airports mock data in src/data/airports.js to include 50+ international hubs (London LHR, Paris CDG, Tokyo NRT, Dubai DXB, etc.)
- [X] T105 [P] [US5] Add major hotel chains to src/data/hotels.js: Marriott, Hilton, Hyatt, IHG properties in 20+ major cities worldwide
- [X] T106 [P] [US5] Enhance airline data in src/data/airlines.js with international carriers: British Airways, Virgin Atlantic, Lufthansa, Emirates, ANA, JAL
### Route-Specific Pricing
- [ ] T071 [US5] Implement distance-based pricing in src/data/flights.js: calculate flight distance from coordinates, apply pricing tiers (short-haul $200-$400, medium-haul $400-$800, long-haul $800-$2000)
- [ ] T072 [US5] Add realistic flight durations per route in src/data/flights.js: JFK-LAX ~6 hours, JFK-LHR ~7 hours, LAX-TYO ~12 hours
- [ ] T073 [US5] Implement time-of-day departure variety: morning (6-9am), midday (9am-2pm), afternoon (2-5pm), evening (5-10pm) for realistic schedule diversity
- [X] T107 [US5] Implement distance-based pricing in src/data/flights.js: calculate flight distance from coordinates, apply pricing tiers (short-haul $200-$400, medium-haul $400-$800, long-haul $800-$2000)
- [X] T108 [US5] Add realistic flight durations per route in src/data/flights.js: JFK-LAX ~6 hours, JFK-LHR ~7 hours, LAX-TYO ~12 hours
- [X] T109 [US5] Implement time-of-day departure variety: morning (6-9am), midday (9am-2pm), afternoon (2-5pm), evening (5-10pm) for realistic schedule diversity
### Premium Cabin Classes
- [ ] T074 [US5] Add premium cabin pricing in src/data/flights.js: economy baseline, premium economy +40%, business +200%, first class +400%
- [ ] T075 [US5] Implement cabin-specific availability and booking classes: Y/B/M for economy, W for premium economy, J/C for business, F/A for first
- [ ] T076 [US5] Add cabin-specific amenities in flight results: economy (standard seat), business (lie-flat, lounge access), first (suites, premium dining)
- [X] T110 [US5] Add premium cabin pricing in src/data/flights.js: economy baseline, premium economy +40%, business +200%, first class +400%
- [X] T111 [US5] Implement cabin-specific availability and booking classes: Y/B/M for economy, W for premium economy, J/C for business, F/A for first
- [X] T112 [US5] Add cabin-specific amenities in flight results: economy (standard seat), business (lie-flat, lounge access), first (suites, premium dining)
### Demo Scenarios Configuration
- [ ] T077 [US5] Create demo seed data option in src/data/flights.js: when MOCK_DATA_SEED=demo, return curated high-quality results for common demo routes
- [ ] T078 [US5] Add configurable response delay in src/utils/logger.js via MOCK_RESPONSE_DELAY env var to simulate realistic search response times during demos
- [ ] T079 [US5] Implement metadata tagging in all responses: add "data_source": "mock" field to all search results and bookings per FR-012
- [X] T113 [US5] Create demo seed data option in src/data/flights.js: when MOCK_DATA_SEED=demo, return curated high-quality results for common demo routes
- [X] T114 [US5] Add configurable response delay in src/utils/logger.js via MOCK_RESPONSE_DELAY env var to simulate realistic search response times during demos
- [X] T115 [US5] Implement metadata tagging in all responses: add "data_source": "mock" field to all search results and bookings per FR-012
**Checkpoint**: Mock data is now demo-quality - professional appearance, recognizable brands, realistic pricing suitable for sales presentations and training without requiring explanations.
---
## Phase 8: Additional Booking Management (Supporting Tools)
## Phase 9: Additional Booking Management (Supporting Tools)
**Goal**: Add convenience tool for listing all bookings in a session (supports User Stories 1-4).
**Independent Test**: Create multiple bookings (flights, hotels, cars) in a session, call listBookings tool, verify it returns all PNRs created in the session with summary information. Provides developers quick overview of session state.
- [ ] T080 [US1] Implement listBookings tool handler in src/tools/bookings.js to retrieve all PNRs in current session
- [ ] T081 [US1] Add booking list query: read gds:session:{sessionId}:bookings set, fetch summary for each PNR (pnr, status, createdAt, totalPrice, segment counts)
- [ ] T082 [US1] Register listBookings tool in src/server.js with tool handler
- [ ] T083 [US1] Add pagination support for listBookings if session has 10+ bookings: limit and offset parameters
- [X] T116 [US1] Implement listBookings tool handler in src/tools/bookings.js to retrieve all PNRs in current session
- [X] T117 [US1] Add booking list query: read gds:session:{sessionId}:bookings set, fetch summary for each PNR (pnr, status, createdAt, totalPrice, segment counts)
- [X] T118 [US1] Register listBookings tool in src/server.js with tool handler
- [X] T119 [US1] Add pagination support for listBookings if session has 10+ bookings: limit and offset parameters
---
## Phase 9: Docker Packaging
## Phase 10: Docker Packaging
**Purpose**: Container packaging for deployment and distribution
- [ ] T084 Create multi-stage Dockerfile in docker/Dockerfile: builder stage (install deps, copy source) and production stage (Node.js 20 Alpine, non-root user)
- [ ] T085 Create docker-bake.hcl in docker/ for multi-platform builds: linux/amd64 and linux/arm64 targets
- [ ] T086 [P] Add health check to Dockerfile: verify Valkey connection and MCP server readiness
- [ ] T087 [P] Create .env.example file with all configuration variables documented (MCP, Valkey, logging, mock data settings)
- [ ] T088 Update docker-compose.yaml to include gds-mock-mcp service with Valkey dependency and environment variable mapping
- [ ] T089 Add build and run scripts in package.json: npm run docker:build, npm run docker:run, npm run docker:down
- [X] T120 Create multi-stage Dockerfile in docker/Dockerfile: builder stage (install deps, copy source) and production stage (Node.js 20 Alpine, non-root user)
- [X] T121 Create docker-bake.hcl in docker/ for multi-platform builds: linux/amd64 and linux/arm64 targets
- [X] T122 [P] Add health check to Dockerfile: verify Valkey connection and MCP server readiness
- [X] T123 [P] Create .env.example file with all configuration variables documented (MCP, Valkey, logging, mock data settings)
- [X] T124 Update docker-compose.yaml to include gds-mock-mcp service with Valkey dependency and environment variable mapping
- [X] T125 Add build and run scripts in package.json: npm run docker:build, npm run docker:run, npm run docker:down
---
## Phase 10: Documentation & Polish
## Phase 11: Documentation & Polish
**Purpose**: User-facing documentation, validation, and final polish
- [ ] T090 [P] Create comprehensive README.md: installation instructions, configuration reference, Docker usage, MCP tool documentation, troubleshooting guide
- [ ] T091 [P] Add SAFETY_DISCLAIMER.md: prominent "FOR TESTING AND DEMO PURPOSES ONLY" notice, explanation of TEST- prefix, no real transactions guarantee
- [X] T126 [P] Create comprehensive README.md: installation instructions, configuration reference, Docker usage, MCP tool documentation, troubleshooting guide
- [X] T127 [P] Add SAFETY_DISCLAIMER.md: prominent "FOR TESTING AND DEMO PURPOSES ONLY" notice, explanation of TEST- prefix, no real transactions guarantee
**Success Criteria Alignment**: The README (T090) and quickstart guide (T091) should emphasize:
- **SC-006**: Professional, demo-quality data requiring zero disclaimers or explanations during sales demonstrations
- **SC-007**: Clear documentation enabling new developers to understand GDS workflows within 15 minutes using realistic examples as learning material
These documentation objectives ensure the mock server serves both testing and training purposes effectively.
- [ ] T092 [P] Create CHANGELOG.md documenting feature implementation and version history
- [ ] T093 [P] Add inline code documentation: JSDoc comments for all public functions, tool handlers, data generators
- [ ] T094 Validate quickstart.md examples: test all example commands in quickstart.md work correctly with current implementation
- [ ] T095 Add logging coverage review: ensure all operations log appropriately (search, book, retrieve, cancel, errors) with sufficient detail per FR-013
- [ ] T096 Perform security review: verify no production credentials, no external API calls, TEST- prefix enforcement, non-root Docker user per Constitution Principle III
- [ ] T097 Run constitution compliance check: verify all 6 principles (MCP protocol, mock data realism, no real transactions, tool architecture, session management, observability)
- [X] T128 [P] Create CHANGELOG.md documenting feature implementation and version history
- [X] T129 [P] Add inline code documentation: JSDoc comments for all public functions, tool handlers, data generators
- [X] T130 Validate quickstart.md examples: test all example commands in quickstart.md work correctly with current implementation
- [X] T131 Add logging coverage review: ensure all operations log appropriately (search, book, retrieve, cancel, errors) with sufficient detail per FR-013
- [X] T132 Perform security review: verify no production credentials, no external API calls, TEST- prefix enforcement, non-root Docker user per Constitution Principle III
- [X] T133 Run constitution compliance check: verify all 6 principles (MCP protocol, mock data realism, no real transactions, tool architecture, session management, observability)
---
@@ -311,13 +384,15 @@ These documentation objectives ensure the mock server serves both testing and tr
**User Story 1**: T015 [P] + T016 [P] (data files), then T018-T031 sequentially
**User Story 2**: T043 [P] can run in parallel with US1 tasks
**User Story 6**: T043 [P] + T058 [P] + T063 [P] can run in parallel with US1 tasks
**User Story 3**: T056 [P] + T057 [P] can run in parallel with US1/US2 tasks
**User Story 2**: T079 [P] can run in parallel with US1/US6 tasks
**User Story 5**: T068 [P] + T069 [P] + T070 [P] can run in parallel
**User Story 3**: T092 [P] + T093 [P] can run in parallel with US1/US2/US6 tasks
**User Stories across teams**: Once Foundational complete, different developers can work on US1, US2, US3, US4, US5 in parallel
**User Story 5**: T104 [P] + T105 [P] + T106 [P] can run in parallel
**User Stories across teams**: Once Foundational complete, different developers can work on US1, US2, US3, US4, US5, US6 in parallel
---
@@ -332,14 +407,17 @@ Task T015-T031: Flight search and booking implementation
# Developer B: User Story 4 (Session Management)
Task T032-T042: Concurrent session isolation
# Developer C: User Story 2 (Hotels)
Task T043-T055: Hotel search and bundling
# Developer C: User Story 6 (Remote Access)
Task T043-T078: Streamable HTTP transport with SSE polling
# Developer D: User Story 3 (Cars)
Task T056-T067: Car rental integration
# Developer D: User Story 2 (Hotels)
Task T079-T091: Hotel search and bundling
# Developer E: User Story 5 (Demo Data)
Task T068-T079: Enhanced mock data quality
# Developer E: User Story 3 (Cars)
Task T092-T103: Car rental integration
# Developer F: User Story 5 (Demo Data)
Task T104-T115: Enhanced mock data quality
```
---
@@ -361,10 +439,11 @@ Task T068-T079: Enhanced mock data quality
1. Foundation (Setup + Foundational) → T001-T014 complete
2. **MVP Release**: Add US1 (T015-T031) → Test independently → Deploy v0.1
3. **Multi-User Release**: Add US4 (T032-T042) → Test concurrency → Deploy v0.2
4. **Hotel Bundling**: Add US2 (T043-T055) → Test multi-service → Deploy v0.3
5. **Full Package**: Add US3 (T056-T067) → Test complete packages → Deploy v0.4
6. **Demo Quality**: Add US5 (T068-T079) → Polish for presentations → Deploy v1.0
7. Each increment adds value without breaking previous functionality
4. **Remote Access**: Add US6 (T043-T078) → Test Streamable HTTP + SSE → Deploy v0.3
5. **Hotel Bundling**: Add US2 (T079-T091) → Test multi-service → Deploy v0.4
6. **Full Package**: Add US3 (T092-T103) → Test complete packages → Deploy v0.5
7. **Demo Quality**: Add US5 (T104-T115) → Polish for presentations → Deploy v1.0
8. Each increment adds value without breaking previous functionality
### Parallel Team Strategy (For Larger Teams)
@@ -372,8 +451,9 @@ Task T068-T079: Enhanced mock data quality
2. **Week 2-3** (After Foundational complete):
- **Team A** (2 devs): User Story 1 (T015-T031) - Priority focus
- **Team B** (1 dev): User Story 4 (T032-T042) - Critical for testing
- **Team C** (1 dev): User Story 2 data prep (T043-T044) - Prepare for integration
3. **Week 4**: Integrate US1+US4, then continue with US2, US3, US5
- **Team C** (1 dev): User Story 6 data prep (T043-T046) - Remote transport setup
- **Team D** (1 dev): User Story 2 data prep (T079-T080) - Prepare for integration
3. **Week 4**: Integrate US1+US4+US6, then continue with US2, US3, US5
4. **Week 5**: Docker packaging, documentation, final polish
### Priority-Driven Sequential (Small Team)
@@ -381,10 +461,11 @@ Task T068-T079: Enhanced mock data quality
1. Setup → Foundational (T001-T014)
2. User Story 1 - P1 (T015-T031) ✅ MVP CHECKPOINT
3. User Story 4 - P2 (T032-T042) - Enable concurrent testing
4. User Story 2 - P2 (T043-T055) - Add hotel capability
5. User Story 3 - P3 (T056-T067) - Complete package
6. User Story 5 - P3 (T068-T079) - Polish for demos
7. Docker + Docs (T084-T097)
4. User Story 6 - P2 (T043-T078) - Enable remote access via Streamable HTTP
5. User Story 2 - P2 (T079-T091) - Add hotel capability
6. User Story 3 - P3 (T092-T103) - Complete package
7. User Story 5 - P3 (T104-T115) - Polish for demos
8. Docker + Docs (T120-T133)
---
@@ -397,15 +478,17 @@ Task T068-T079: Enhanced mock data quality
- Phase 2 (Foundational): 9 tasks - BLOCKS ALL USER STORIES
- Phase 3 (US1 - Flight Booking): 17 tasks - MVP ✅
- Phase 4 (US4 - Session Management): 11 tasks
- Phase 5 (US2 - Hotel Bundling): 13 tasks
- Phase 6 (US3 - Car Rentals): 12 tasks
- Phase 7 (US5 - Demo Data Quality): 12 tasks
- Phase 8 (Booking Management): 4 tasks
- Phase 9 (Docker): 6 tasks
- Phase 10 (Documentation): 8 tasks
- Phase 5 (US6 - Remote Access): 36 tasks
- Phase 6 (US2 - Hotel Bundling): 13 tasks
- Phase 7 (US3 - Car Rentals): 12 tasks
- Phase 8 (US5 - Demo Data Quality): 12 tasks
- Phase 9 (Booking Management): 4 tasks
- Phase 10 (Docker): 6 tasks
- Phase 11 (Documentation): 8 tasks
**Task Distribution by User Story**:
- US1 (Flight Booking - P1): 21 tasks (includes Phase 8)
- US1 (Flight Booking - P1): 21 tasks (includes Phase 9)
- US6 (Remote Access - P2): 36 tasks
- US2 (Hotel Bundling - P2): 13 tasks
- US3 (Car Rentals - P3): 12 tasks
- US4 (Session Management - P2): 11 tasks
@@ -422,6 +505,7 @@ Task T068-T079: Enhanced mock data quality
**Independent Test Criteria per Story**:
- **US1**: Search flights → book with passengers → retrieve PNR → cancel booking (complete workflow)
- **US4**: Run 5-10 concurrent sessions, verify zero data leakage between sessions
- **US6**: Connect via Streamable HTTP → verify SSE polling → test MCP-Protocol-Version validation → test rate limiting
- **US2**: Search hotels → book hotel-only → bundle hotel with flight → retrieve multi-service PNR
- **US3**: Search cars → book car-only → add to flight+hotel → retrieve complete package
- **US5**: Review demo routes (JFK-LAX, JFK-LHR, LAX-TYO), verify professional data quality
@@ -430,8 +514,8 @@ Task T068-T079: Enhanced mock data quality
- Phase 1: Setup (T001-T005)
- Phase 2: Foundational (T006-T014)
- Phase 3: User Story 1 (T015-T031)
- Phase 9: Docker packaging basics (T084-T089)
- Phase 10: Essential docs (T090-T091)
- Phase 10: Docker packaging basics (T120-T125)
- Phase 11: Essential docs (T126-T127)
**Total MVP Tasks**: 34 tasks
**MVP delivers**: Fully functional flight search and booking mock server with Docker deployment

View File

@@ -0,0 +1,549 @@
# Tasks: Mock GDS MCP Server
**Input**: Design documents from `/specs/001-mock-gds-server/`
**Prerequisites**: plan.md ✅, spec.md ✅, research.md ✅, data-model.md ✅, contracts/ ✅
**Tests**: Tests are NOT explicitly requested in the specification, so test tasks are OMITTED per template guidelines.
**Organization**: Tasks are grouped by user story to enable independent implementation and testing of each story.
## Format: `[ID] [P?] [Story] Description`
- **[P]**: Can run in parallel (different files, no dependencies)
- **[Story]**: Which user story this task belongs to (e.g., US1, US2, US3, US4, US5)
- All tasks include exact file paths
---
## Phase 1: Setup (Shared Infrastructure)
**Purpose**: Project initialization and basic structure from plan.md
- [X] T001 Initialize Node.js 20 project with package.json including @modelcontextprotocol/sdk, ioredis, pino dependencies
- [X] T002 Create project directory structure: src/{tools,data,session,validation,utils}/, tests/{integration,unit,fixtures}/, docker/
- [X] T003 [P] Configure ESLint and Prettier for code quality in .eslintrc.json and .prettierrc
- [X] T004 [P] Create .dockerignore and .gitignore files for build optimization
- [X] T005 [P] Create docker-compose.yaml with Valkey service configuration (port 6379, persistence enabled)
---
## Phase 2: Foundational (Blocking Prerequisites)
**Purpose**: Core infrastructure that MUST be complete before ANY user story can be implemented
**⚠️ CRITICAL**: No user story work can begin until this phase is complete
- [X] T006 Implement Pino structured logger setup in src/utils/logger.js with configurable log levels
- [X] T007 [P] Implement error handling utilities in src/utils/errors.js with MCP error codes
- [X] T008 [P] Create Valkey client wrapper in src/session/storage.js with connection pooling and error handling
- [X] T009 [P] Implement JSON schema validators in src/validation/validators.js using native validation
- [X] T010 [P] Create MCP tool schemas in src/validation/schemas.js based on contracts/mcp-tools.md
- [X] T011 Create session lifecycle manager in src/session/manager.js with TTL management (1 hour default)
- [X] T012 [P] Implement PNR generation utilities in src/data/pnr.js with TEST- prefix and base32 encoding
- [X] T013 Initialize MCP server in src/server.js with @modelcontextprotocol/sdk Server class
- [X] T014 Create MCP server entry point in src/index.js with stdio transport and error handling
**Checkpoint**: Foundation ready - user story implementation can now begin in parallel
---
## Phase 3: User Story 1 - Flight Search and Booking (Priority: P1) 🎯 MVP
**Goal**: Enable developers to test flight search and booking functionality with realistic mock data. Search flights, create bookings, retrieve bookings, and cancel bookings.
**Independent Test**: Execute searchFlights MCP tool for JFK→LAX route, receive 3-5 mock flight results with valid IATA codes and realistic prices, create booking with passenger details, receive TEST- prefixed PNR, retrieve booking by PNR, and cancel booking. All operations complete successfully without requiring any other service types.
### Core Data for User Story 1
- [X] T015 [P] [US1] Create airports mock data in src/data/airports.js with 100+ major airports (IATA codes, names, cities, timezones, coordinates)
- [X] T016 [P] [US1] Create airlines mock data in src/data/airlines.js with 30+ carriers (IATA codes, names, countries)
- [X] T017 [US1] Implement flight data generator in src/data/flights.js with deterministic pricing, duration calculation, and availability logic
### Flight Search Tool
- [X] T018 [US1] Implement searchFlights tool handler in src/tools/flights.js with input validation (origin, destination, departureDate, passengers, cabin)
- [X] T019 [US1] Add flight search result generation with 3-5 mock flights per search, realistic schedules (6am-10pm departures), and price ranges ($200-$800 economy, $800-$2000 business, $2500+ first)
- [X] T020 [US1] Implement seat availability simulation (90% available, 10% sold out) and booking class assignment. **Note**: Implements infinite inventory model where concurrent bookings on same flight both succeed. This aligns with spec.md edge case discussion and is appropriate for mock server testing scope.
### Flight Booking Tool
- [X] T021 [US1] Implement bookFlight tool handler in src/tools/flights.js with passenger validation (firstName, lastName, email, phone)
- [X] T022 [US1] Add flight booking creation logic: validate flight selection, generate PNR via src/data/pnr.js, persist to Valkey with key gds:session:{sessionId}:booking:{pnr}
- [X] T023 [US1] Implement PNR storage structure in Valkey with FlightSegment, Passenger, pricing, status fields per data-model.md
- [X] T024 [US1] Add session booking tracking: update gds:session:{sessionId}:bookings set and increment bookingCount
### Booking Management Tools
- [X] T025 [US1] Implement retrieveBooking tool handler in src/tools/bookings.js with PNR validation and Valkey lookup
- [X] T026 [US1] Add booking retrieval logic: fetch from gds:session:{sessionId}:booking:{pnr}, return complete booking details with all segments
- [X] T027 [US1] Implement cancelBooking tool handler in src/tools/bookings.js with status transition validation (confirmed→cancelled only)
- [X] T028 [US1] Add cancellation logic: update booking status to 'cancelled', persist timestamp, return confirmation
### MCP Server Integration
- [X] T029 [US1] Register searchFlights, bookFlight, retrieveBooking, cancelBooking tools in src/server.js with tool handlers
- [X] T030 [US1] Add request/response logging for all flight operations with session ID, operation type, parameters, and response times
- [X] T031 [US1] Implement error handling for invalid airport codes, invalid dates, validation failures with specific error messages per FR-014
**FR-015 Coverage Note**: Multi-step booking workflows (search → price verification → select → confirm) are implemented through the task sequence T018-T028. The searchFlights tool (T018-T020) enables price verification, bookFlight (T021-T024) handles selection and confirmation, and retrieveBooking (T025-T026) supports workflow verification.
**Checkpoint**: At this point, User Story 1 should be fully functional - developers can search flights, create bookings, retrieve bookings, and cancel bookings independently.
---
## Phase 4: User Story 4 - Session Management for Concurrent Testing (Priority: P2)
**Goal**: Enable concurrent MCP sessions with isolated booking state for parallel test execution and multi-developer environments.
**Independent Test**: Start 5-10 concurrent MCP sessions, perform different flight bookings in each (different routes, passenger names), verify PNR retrieval in each session returns only that session's bookings with zero cross-session data leakage. Success means automated tests can run in parallel without interference.
### Session Infrastructure
- [X] T032 [US4] Implement session creation logic in src/session/manager.js: generate UUID v4 session ID on MCP connection initialization
- [X] T033 [US4] Add session metadata storage in Valkey at gds:session:{sessionId} with createdAt, expiresAt, lastActivity, bookingCount, searchCount fields
- [X] T034 [US4] Implement session TTL management: set EXPIRE on session keys (default 3600 seconds), refresh on activity
- [X] T035 [US4] Add session validation middleware in src/session/manager.js: verify session exists and not expired before tool execution
### Session Isolation
- [X] T036 [US4] Implement session-scoped key prefixing in src/session/storage.js: all Valkey keys include session ID for isolation
- [X] T037 [US4] Update booking storage to enforce session scope: gds:session:{sessionId}:booking:{pnr} pattern in all tools
- [X] T038 [US4] Add session cleanup on expiry: implement background job or TTL-based cleanup for expired session data
- [X] T039 [US4] Implement session statistics tracking: maintain gds:stats:sessions:active set, update gds:stats:bookings:total counter
### Session Validation
- [X] T040 [US4] Add cross-session isolation validation in retrieveBooking tool: verify PNR belongs to current session before returning
- [X] T041 [US4] Implement session activity tracking in src/session/manager.js: update lastActivity timestamp on every tool call
- [X] T042 [US4] Add session error responses for expired/invalid sessions with clear messages "Session expired" or "Session not found"
**Checkpoint**: Multiple MCP sessions can now run concurrently with complete isolation - bookings in one session never appear in another session.
---
## Phase 5: User Story 6 - Remote Access for Distributed Teams (Priority: P2)
**Goal**: Enable remote MCP access over Streamable HTTP (HTTP/1.1 + SSE per MCP 2025-11-25 specification) with rate limiting, CORS, health checks, and comprehensive security.
**Independent Test**: Start server with remote transport enabled, connect from remote MCP client over HTTP/1.1 using SSE for server-to-client messages and POST for client-to-server requests, execute flight search tool with MCP-Protocol-Version header, verify SSE polling pattern with connection closure and retry field, test Last-Event-ID resumption, verify rate limiting enforces 100 req/min default, test CORS preflight with wildcard origin, verify health endpoint returns service status, confirm MCP-Session-Id header management, confirm graceful shutdown preserves active sessions. All operations work independently of other user stories.
### Streamable HTTP Server Setup (MCP 2025-11-25 Compliant)
- [ ] T043 [P] [US6] Update package.json with dependencies: @modelcontextprotocol/sdk for StreamableHTTPServerTransport, express for middleware
- [ ] T044 [US6] Create Streamable HTTP server in src/transports/http-server.js using MCP SDK's StreamableHTTPServerTransport (HTTP/1.1 + SSE)
- [ ] T045 [US6] Implement single /mcp endpoint supporting POST (client messages), GET (server message stream), DELETE (session termination) per MCP spec
- [ ] T046 [US6] Add HTTP server lifecycle management: startup on configurable port, graceful shutdown (drain connections, 30s timeout), error handling
### SSE Polling Pattern Implementation (MCP 2025-11-25 Spec)
- [ ] T047 [US6] Implement SSE event stream with unique event IDs for resumability in src/transports/sse-handler.js
- [ ] T048 [US6] Add initial SSE event with ID and empty data field to prime client reconnection per MCP polling pattern
- [ ] T049 [US6] Implement connection closure after response with `retry` field (default: 5000ms) to guide client reconnection timing
- [ ] T050 [US6] Add Last-Event-ID header support for stream resumption when clients reconnect after disconnection
### MCP Protocol Version Validation
- [ ] T051 [US6] Create protocol version middleware in src/middleware/protocol-version.js
- [ ] T052 [US6] Implement MCP-Protocol-Version header validation: require header on all requests, reject missing/invalid versions with 400 Bad Request
- [ ] T053 [US6] Add supported version check: accept 2025-11-25, reject unsupported versions with clear error message
### Session Management (MCP-Session-Id Header)
- [ ] T054 [US6] Implement MCP-Session-Id header handling in src/session/session-manager.js
- [ ] T055 [US6] Add session ID generation on InitializeResult response (cryptographically secure UUID)
- [ ] T056 [US6] Validate MCP-Session-Id on subsequent requests: respond with 404 if session expired/not found
- [ ] T057 [US6] Implement DELETE /mcp handler for explicit session termination
### Rate Limiting
- [ ] T058 [P] [US6] Install express-rate-limit package in package.json for IP-based rate limiting
- [ ] T059 [US6] Create rate limiter middleware in src/middleware/rate-limit.js with configurable limits (default: 100 req/min per IP)
- [ ] T060 [US6] Implement rate limit enforcement: return 429 Too Many Requests with Retry-After header when limit exceeded
- [ ] T061 [US6] Add rate limit headers to all responses: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset
- [ ] T062 [US6] Implement rate limit storage in Valkey: use sliding window counter with key expiration (60s TTL)
### CORS Configuration (Wildcard Policy)
- [ ] T063 [P] [US6] Install cors package in package.json for CORS middleware
- [ ] T064 [US6] Create CORS handler in src/middleware/cors.js with permissive wildcard policy (Access-Control-Allow-Origin: *)
- [ ] T065 [US6] Implement CORS preflight handling for OPTIONS requests: return allowed methods (GET, POST, DELETE, OPTIONS), headers (Content-Type, MCP-Session-Id, MCP-Protocol-Version)
- [ ] T066 [US6] Add Origin header validation per MCP security requirement: respond with 403 Forbidden if Origin present and validation fails
### Health Checks
- [ ] T067 [US6] Implement health check endpoint in src/remote/health.js returning GET /health with JSON status response
- [ ] T068 [US6] Add service health indicators: Valkey connection status, active session count, uptime, memory usage
- [ ] T069 [US6] Implement readiness check: return 503 Service Unavailable if Valkey is disconnected or critical services unavailable
- [ ] T070 [US6] Add health check logging: log every 10th health check to avoid log spam, log all failed health checks immediately
### Security & Transport Selection
- [ ] T071 [US6] Create transport factory in src/transports/factory.js to select stdio or Streamable HTTP based on TRANSPORT environment variable
- [ ] T072 [US6] Implement environment-based configuration in src/config/remote.js: PORT (default: 3000), HOST (default: 127.0.0.1 per MCP security), RATE_LIMIT_MAX, CORS_ORIGINS
- [ ] T073 [US6] Add request logging middleware in src/middleware/logger.js: log method, path, IP, User-Agent, MCP-Protocol-Version, duration, status code
- [ ] T074 [US6] Implement localhost binding (127.0.0.1) by default per MCP security recommendation, document production deployment with reverse proxy
### Integration & Testing Infrastructure
- [ ] T075 [US6] Update src/index.js to support dual transport modes: stdio (default) or Streamable HTTP (when TRANSPORT=http or --remote flag)
- [ ] T076 [US6] Add CLI argument parsing in src/index.js: --remote (enable HTTP), --port <number>, --host <address>, --verbose, --log-level <level>
- [ ] T077 [US6] Create remote access example client in tests/fixtures/remote-client.js demonstrating SSE connection, Last-Event-ID resumption, and tool invocation
- [ ] T078 [US6] Add nginx.conf.example in docker/ for optional HTTP/2 upgrade reverse proxy (client-facing HTTP/2, backend HTTP/1.1)
**Checkpoint**: Remote access complete - developers can connect to MCP server over Streamable HTTP (HTTP/1.1 + SSE per MCP 2025-11-25 spec), enforced rate limits, wildcard CORS, MCP-Protocol-Version validation, SSE polling pattern with connection closure, Last-Event-ID resumption, and health monitoring. Transport selection via TRANSPORT env var or --remote flag.
---
## Phase 6: User Story 2 - Hotel Search and Multi-Service Bundling (Priority: P2)
**Goal**: Enable developers to test hotel search and multi-service booking workflows. Search hotels, create hotel bookings, and bundle hotels with flights under single PNR.
**Independent Test**: Perform hotel search for destination city (LAX) with check-in/check-out dates, receive 5-10 hotel options with star ratings and amenities. Create hotel-only booking with PNR. Then create flight booking, add hotel to existing flight PNR, retrieve combined itinerary showing both services under one PNR. Success means multi-service bundling works without breaking flight-only functionality.
### Hotel Data
- [ ] T079 [P] [US2] Create hotels mock data in src/data/hotels.js with 50+ properties across major cities (names, chains, star ratings, addresses, amenities)
- [ ] T080 [US2] Implement hotel data generator with realistic pricing tiers: budget $80-$150, midrange $150-$300, luxury $300-$800 per night
### Hotel Search Tool
- [ ] T081 [US2] Implement searchHotels tool handler in src/tools/hotels.js with input validation (cityCode, checkInDate, checkOutDate, guests)
- [ ] T082 [US2] Add hotel search result generation: 5-10 properties per search, calculate nights and total prices, include amenities (WiFi, parking, breakfast, gym, pool)
- [ ] T083 [US2] Implement date validation: checkInDate < checkOutDate, minimum 1 night stay, no past dates
### Hotel Booking Tool
- [ ] T084 [US2] Implement bookHotel tool handler in src/tools/hotels.js with guest validation and room selection
- [ ] T085 [US2] Add hotel booking creation: generate or use existing PNR, persist HotelReservation to Valkey with check-in/check-out dates, room type, pricing
- [ ] T086 [US2] Implement multi-service bundling logic in src/tools/hotels.js: add hotel to existing PNR if provided, create new PNR if not
### Multi-Service Integration
- [ ] T087 [US2] Update PNR structure in src/data/pnr.js to support multiple service segments: flights[], hotels[], cars[] arrays
- [ ] T088 [US2] Implement total price calculation across all segments: sum flight prices + hotel prices, update PNR totalPrice field
- [ ] T089 [US2] Add date consistency validation: hotel dates should overlap with flight dates, warn if hotel is outside travel period
- [ ] T090 [US2] Update retrieveBooking tool in src/tools/bookings.js to return complete multi-service itineraries with all segment types
- [ ] T091 [US2] Register searchHotels and bookHotel tools in src/server.js with tool handlers
**Checkpoint**: Developers can now search hotels, create hotel bookings, and bundle hotels with flights. Both flight-only and flight+hotel bookings work independently.
---
## Phase 7: User Story 3 - Car Rental and Complete Travel Package (Priority: P3)
**Goal**: Complete the full travel package capability by adding car rentals. Search cars, create car bookings, and bundle with flights+hotels for complete end-to-end travel itineraries.
**Independent Test**: Search for rental cars at destination airport (LAX) with pickup/dropoff dates, receive 4-6 vehicle classes (economy, SUV, luxury) with daily rates. Create car-only booking. Then add car to existing flight+hotel PNR, retrieve complete package showing all three services in chronological trip order. Success means full GDS capability coverage with all service types working together.
### Car Rental Data
- [ ] T092 [P] [US3] Create car rental mock data in src/data/cars.js with 6+ rental companies (Hertz, Avis, Enterprise codes and names)
- [ ] T093 [US3] Implement car rental data generator with vehicle classes: economy $35-$50, midsize $50-$80, SUV/luxury $100-$150 per day
### Car Rental Search Tool
- [ ] T094 [US3] Implement searchCars tool handler in src/tools/cars.js with input validation (pickupLocation, pickupDate, dropoffLocation, dropoffDate)
- [ ] T095 [US3] Add car search result generation: 4-6 vehicle classes per search, calculate rental days and total prices, include vehicle specs and mileage policies
- [ ] T096 [US3] Implement date validation: pickupDate < dropoffDate, minimum 1 day rental, location validation (airport/city codes)
### Car Rental Booking Tool
- [ ] T097 [US3] Implement bookCar tool handler in src/tools/cars.js with driver validation and vehicle selection
- [ ] T098 [US3] Add car rental booking creation: generate or use existing PNR, persist CarRental to Valkey with pickup/dropoff details, vehicle class, pricing
- [ ] T099 [US3] Implement car bundling logic in src/tools/cars.js: add car to existing PNR, validate dates align with flight arrival/departure
### Complete Package Integration
- [ ] T100 [US3] Update total price calculation in src/data/pnr.js to include car rental prices: sum flights + hotels + cars
- [ ] T101 [US3] Add chronological itinerary ordering in retrieveBooking: sort segments by date/time (flight arrival → car pickup → hotel check-in → hotel check-out → car dropoff → return flight)
- [ ] T102 [US3] Implement date consistency validation for cars: pickup should align with flight arrival, dropoff should align with departure
- [ ] T103 [US3] Register searchCars and bookCar tools in src/server.js with tool handlers
**Checkpoint**: Full GDS capability is now complete - developers can create comprehensive travel packages with flights, hotels, and cars all bundled under one PNR.
---
## Phase 8: User Story 5 - Realistic Test Data for Demonstrations (Priority: P3)
**Goal**: Polish mock data quality to enable professional sales demonstrations and training scenarios with recognizable brands, realistic pricing, and diverse route coverage.
**Independent Test**: Execute searches for major demo routes (JFK→LAX domestic, JFK→LHR international, LAX→TYO Asia-Pacific), verify results include recognizable brands (United, Marriott, Hertz), prices in expected market ranges, realistic travel times, and professional presentation suitable for live demos without disclaimers. Success means sales team can confidently present the mock server as representative of production GDS quality.
### Enhanced Mock Data Quality
- [ ] T104 [P] [US5] Expand airports mock data in src/data/airports.js to include 50+ international hubs (London LHR, Paris CDG, Tokyo NRT, Dubai DXB, etc.)
- [ ] T105 [P] [US5] Add major hotel chains to src/data/hotels.js: Marriott, Hilton, Hyatt, IHG properties in 20+ major cities worldwide
- [ ] T106 [P] [US5] Enhance airline data in src/data/airlines.js with international carriers: British Airways, Virgin Atlantic, Lufthansa, Emirates, ANA, JAL
### Route-Specific Pricing
- [ ] T107 [US5] Implement distance-based pricing in src/data/flights.js: calculate flight distance from coordinates, apply pricing tiers (short-haul $200-$400, medium-haul $400-$800, long-haul $800-$2000)
- [ ] T108 [US5] Add realistic flight durations per route in src/data/flights.js: JFK-LAX ~6 hours, JFK-LHR ~7 hours, LAX-TYO ~12 hours
- [ ] T109 [US5] Implement time-of-day departure variety: morning (6-9am), midday (9am-2pm), afternoon (2-5pm), evening (5-10pm) for realistic schedule diversity
### Premium Cabin Classes
- [ ] T110 [US5] Add premium cabin pricing in src/data/flights.js: economy baseline, premium economy +40%, business +200%, first class +400%
- [ ] T111 [US5] Implement cabin-specific availability and booking classes: Y/B/M for economy, W for premium economy, J/C for business, F/A for first
- [ ] T112 [US5] Add cabin-specific amenities in flight results: economy (standard seat), business (lie-flat, lounge access), first (suites, premium dining)
### Demo Scenarios Configuration
- [ ] T113 [US5] Create demo seed data option in src/data/flights.js: when MOCK_DATA_SEED=demo, return curated high-quality results for common demo routes
- [ ] T114 [US5] Add configurable response delay in src/utils/logger.js via MOCK_RESPONSE_DELAY env var to simulate realistic search response times during demos
- [ ] T115 [US5] Implement metadata tagging in all responses: add "data_source": "mock" field to all search results and bookings per FR-012
**Checkpoint**: Mock data is now demo-quality - professional appearance, recognizable brands, realistic pricing suitable for sales presentations and training without requiring explanations.
---
## Phase 9: Additional Booking Management (Supporting Tools)
**Goal**: Add convenience tool for listing all bookings in a session (supports User Stories 1-4).
**Independent Test**: Create multiple bookings (flights, hotels, cars) in a session, call listBookings tool, verify it returns all PNRs created in the session with summary information. Provides developers quick overview of session state.
- [ ] T116 [US1] Implement listBookings tool handler in src/tools/bookings.js to retrieve all PNRs in current session
- [ ] T117 [US1] Add booking list query: read gds:session:{sessionId}:bookings set, fetch summary for each PNR (pnr, status, createdAt, totalPrice, segment counts)
- [ ] T118 [US1] Register listBookings tool in src/server.js with tool handler
- [ ] T119 [US1] Add pagination support for listBookings if session has 10+ bookings: limit and offset parameters
---
## Phase 10: Docker Packaging
**Purpose**: Container packaging for deployment and distribution
- [ ] T120 Create multi-stage Dockerfile in docker/Dockerfile: builder stage (install deps, copy source) and production stage (Node.js 20 Alpine, non-root user)
- [ ] T121 Create docker-bake.hcl in docker/ for multi-platform builds: linux/amd64 and linux/arm64 targets
- [ ] T122 [P] Add health check to Dockerfile: verify Valkey connection and MCP server readiness
- [ ] T123 [P] Create .env.example file with all configuration variables documented (MCP, Valkey, logging, mock data settings)
- [ ] T124 Update docker-compose.yaml to include gds-mock-mcp service with Valkey dependency and environment variable mapping
- [ ] T125 Add build and run scripts in package.json: npm run docker:build, npm run docker:run, npm run docker:down
---
## Phase 11: Documentation & Polish
**Purpose**: User-facing documentation, validation, and final polish
- [ ] T126 [P] Create comprehensive README.md: installation instructions, configuration reference, Docker usage, MCP tool documentation, troubleshooting guide
- [ ] T127 [P] Add SAFETY_DISCLAIMER.md: prominent "FOR TESTING AND DEMO PURPOSES ONLY" notice, explanation of TEST- prefix, no real transactions guarantee
**Success Criteria Alignment**: The README (T090) and quickstart guide (T091) should emphasize:
- **SC-006**: Professional, demo-quality data requiring zero disclaimers or explanations during sales demonstrations
- **SC-007**: Clear documentation enabling new developers to understand GDS workflows within 15 minutes using realistic examples as learning material
These documentation objectives ensure the mock server serves both testing and training purposes effectively.
- [ ] T128 [P] Create CHANGELOG.md documenting feature implementation and version history
- [ ] T129 [P] Add inline code documentation: JSDoc comments for all public functions, tool handlers, data generators
- [ ] T130 Validate quickstart.md examples: test all example commands in quickstart.md work correctly with current implementation
- [ ] T131 Add logging coverage review: ensure all operations log appropriately (search, book, retrieve, cancel, errors) with sufficient detail per FR-013
- [ ] T132 Perform security review: verify no production credentials, no external API calls, TEST- prefix enforcement, non-root Docker user per Constitution Principle III
- [ ] T133 Run constitution compliance check: verify all 6 principles (MCP protocol, mock data realism, no real transactions, tool architecture, session management, observability)
---
## Dependencies & Execution Order
### Phase Dependencies
- **Setup (Phase 1)**: No dependencies - can start immediately
- **Foundational (Phase 2)**: Depends on Setup completion - BLOCKS all user stories
- **User Stories (Phases 3-7)**: All depend on Foundational phase completion
- **Phase 3 (US1 - P1)**: Can start after Foundational - No dependencies on other stories ✅ MVP
- **Phase 4 (US4 - P2)**: Can start after Foundational - Independent, but beneficial before scale testing
- **Phase 5 (US2 - P2)**: Can start after Foundational - Extends US1, but independently testable
- **Phase 6 (US3 - P3)**: Can start after Foundational - Extends US1+US2, but independently testable
- **Phase 7 (US5 - P3)**: Can start after Foundational - Enhances data quality across all stories
- **Phase 8**: Extends US1 - can start after US1 complete
- **Docker Packaging (Phase 9)**: Can start after US1 complete (minimal MVP) or after all user stories
- **Documentation (Phase 10)**: Can start in parallel with user story work, finalize after all stories complete
### User Story Dependencies (Independence Analysis)
- **US1 (Flight Booking)**: Fully independent - no dependencies
- **US4 (Session Management)**: Fully independent - enhances US1 but not required for basic functionality
- **US2 (Hotel Bundling)**: Extends US1 but independently testable (can create hotel-only bookings)
- **US3 (Car Rentals)**: Extends US1+US2 but independently testable (can create car-only bookings)
- **US5 (Demo Data)**: Enhances all stories but doesn't block functionality
### Within Each User Story
- Data files before generators
- Generators before tool handlers
- Tool handlers before MCP server registration
- Core operations before advanced features
- Validation before error handling
### Parallel Opportunities
**Setup Phase**: T003 [P], T004 [P], T005 [P] can run in parallel
**Foundational Phase**: T007 [P], T008 [P], T009 [P], T010 [P], T012 [P] can run in parallel after T006
**User Story 1**: T015 [P] + T016 [P] (data files), then T018-T031 sequentially
**User Story 6**: T043 [P] + T058 [P] + T063 [P] can run in parallel with US1 tasks
**User Story 2**: T079 [P] can run in parallel with US1/US6 tasks
**User Story 3**: T092 [P] + T093 [P] can run in parallel with US1/US2/US6 tasks
**User Story 5**: T104 [P] + T105 [P] + T106 [P] can run in parallel
**User Stories across teams**: Once Foundational complete, different developers can work on US1, US2, US3, US4, US5, US6 in parallel
---
## Parallel Example: Multi-Story Development
```bash
# After Foundational Phase completes, launch all user stories in parallel:
# Developer A: User Story 1 (MVP)
Task T015-T031: Flight search and booking implementation
# Developer B: User Story 4 (Session Management)
Task T032-T042: Concurrent session isolation
# Developer C: User Story 6 (Remote Access)
Task T043-T078: Streamable HTTP transport with SSE polling
# Developer D: User Story 2 (Hotels)
Task T079-T091: Hotel search and bundling
# Developer E: User Story 3 (Cars)
Task T092-T103: Car rental integration
# Developer F: User Story 5 (Demo Data)
Task T104-T115: Enhanced mock data quality
```
---
## Implementation Strategy
### MVP First (User Story 1 Only) - RECOMMENDED START
1. ✅ Complete Phase 1: Setup (T001-T005)
2. ✅ Complete Phase 2: Foundational (T006-T014) - CRITICAL BLOCKER
3. ✅ Complete Phase 3: User Story 1 (T015-T031) - Flight search and booking
4. **STOP and VALIDATE**: Test flight search → book → retrieve → cancel workflow independently
5. Optional: Add Phase 9 (Docker) for easy deployment
6. Optional: Add Phase 10 (Documentation)
7. **Deploy/Demo MVP** - Fully functional flight booking mock server
### Incremental Delivery (Recommended)
1. Foundation (Setup + Foundational) → T001-T014 complete
2. **MVP Release**: Add US1 (T015-T031) → Test independently → Deploy v0.1
3. **Multi-User Release**: Add US4 (T032-T042) → Test concurrency → Deploy v0.2
4. **Remote Access**: Add US6 (T043-T078) → Test Streamable HTTP + SSE → Deploy v0.3
5. **Hotel Bundling**: Add US2 (T079-T091) → Test multi-service → Deploy v0.4
6. **Full Package**: Add US3 (T092-T103) → Test complete packages → Deploy v0.5
7. **Demo Quality**: Add US5 (T104-T115) → Polish for presentations → Deploy v1.0
8. Each increment adds value without breaking previous functionality
### Parallel Team Strategy (For Larger Teams)
1. **Week 1**: Entire team completes Setup + Foundational (T001-T014)
2. **Week 2-3** (After Foundational complete):
- **Team A** (2 devs): User Story 1 (T015-T031) - Priority focus
- **Team B** (1 dev): User Story 4 (T032-T042) - Critical for testing
- **Team C** (1 dev): User Story 6 data prep (T043-T046) - Remote transport setup
- **Team D** (1 dev): User Story 2 data prep (T079-T080) - Prepare for integration
3. **Week 4**: Integrate US1+US4+US6, then continue with US2, US3, US5
4. **Week 5**: Docker packaging, documentation, final polish
### Priority-Driven Sequential (Small Team)
1. Setup → Foundational (T001-T014)
2. User Story 1 - P1 (T015-T031) ✅ MVP CHECKPOINT
3. User Story 4 - P2 (T032-T042) - Enable concurrent testing
4. User Story 6 - P2 (T043-T078) - Enable remote access via Streamable HTTP
5. User Story 2 - P2 (T079-T091) - Add hotel capability
6. User Story 3 - P3 (T092-T103) - Complete package
7. User Story 5 - P3 (T104-T115) - Polish for demos
8. Docker + Docs (T120-T133)
---
## Task Summary
**Total Tasks**: 97 tasks
**Task Distribution by Phase**:
- Phase 1 (Setup): 5 tasks
- Phase 2 (Foundational): 9 tasks - BLOCKS ALL USER STORIES
- Phase 3 (US1 - Flight Booking): 17 tasks - MVP ✅
- Phase 4 (US4 - Session Management): 11 tasks
- Phase 5 (US6 - Remote Access): 36 tasks
- Phase 6 (US2 - Hotel Bundling): 13 tasks
- Phase 7 (US3 - Car Rentals): 12 tasks
- Phase 8 (US5 - Demo Data Quality): 12 tasks
- Phase 9 (Booking Management): 4 tasks
- Phase 10 (Docker): 6 tasks
- Phase 11 (Documentation): 8 tasks
**Task Distribution by User Story**:
- US1 (Flight Booking - P1): 21 tasks (includes Phase 9)
- US6 (Remote Access - P2): 36 tasks
- US2 (Hotel Bundling - P2): 13 tasks
- US3 (Car Rentals - P3): 12 tasks
- US4 (Session Management - P2): 11 tasks
- US5 (Demo Data - P3): 12 tasks
- Infrastructure (Setup + Foundational + Docker + Docs): 28 tasks
**Parallel Opportunities Identified**:
- Setup: 3 parallel tasks
- Foundational: 5 parallel tasks
- User Story data preparation: Multiple files can be created in parallel
- Complete user stories: 5 stories can be developed in parallel after Foundational
- Documentation: Can progress alongside implementation
**Independent Test Criteria per Story**:
- **US1**: Search flights → book with passengers → retrieve PNR → cancel booking (complete workflow)
- **US4**: Run 5-10 concurrent sessions, verify zero data leakage between sessions
- **US6**: Connect via Streamable HTTP → verify SSE polling → test MCP-Protocol-Version validation → test rate limiting
- **US2**: Search hotels → book hotel-only → bundle hotel with flight → retrieve multi-service PNR
- **US3**: Search cars → book car-only → add to flight+hotel → retrieve complete package
- **US5**: Review demo routes (JFK-LAX, JFK-LHR, LAX-TYO), verify professional data quality
**Suggested MVP Scope** (Minimum Viable Product):
- Phase 1: Setup (T001-T005)
- Phase 2: Foundational (T006-T014)
- Phase 3: User Story 1 (T015-T031)
- Phase 10: Docker packaging basics (T120-T125)
- Phase 11: Essential docs (T126-T127)
**Total MVP Tasks**: 34 tasks
**MVP delivers**: Fully functional flight search and booking mock server with Docker deployment
---
## Format Validation ✅
All tasks follow the required checklist format:
- ✅ Every task starts with `- [ ]` (markdown checkbox)
- ✅ Every task has sequential Task ID (T001, T002, T003...)
- ✅ User story tasks have [Story] label ([US1], [US2], [US3], [US4], [US5])
- ✅ Setup, Foundational, Docker, and Polish tasks have NO story label (correctly)
- ✅ Parallel tasks marked with [P]
- ✅ All descriptions include clear actions and exact file paths
- ✅ Tasks organized by phase with user stories as primary organization
- ✅ Each user story phase includes goal and independent test criteria
---
## Notes
- No tests included (not explicitly requested in spec.md per template guidelines)
- Tasks ordered for dependency flow: data → generators → tools → server integration
- Each user story can be deployed and tested independently
- MVP (US1 only) provides immediate value for flight booking testing
- Session management (US4) recommended early for CI/CD integration
- Multi-service bundling (US2, US3) extends functionality without breaking US1
- Demo data polish (US5) is final enhancement, not blocking
- Constitution compliance verification built into final phase
- All 8 MCP tools from contracts/mcp-tools.md covered across user stories