Phase 0 (Research):
- Selected MCP SDK (@modelcontextprotocol/sdk) for protocol compliance
- Chose ioredis for Valkey client (Redis-compatible)
- Minimal dependencies: Pino logging, native test runner
- Docker buildx bake for multi-platform builds
- Embedded mock data with deterministic generation
- PNR format: TEST-{BASE32} for safety
Phase 1 (Design):
- Data model: 8 core entities (Session, PNR, FlightSegment, etc.)
- MCP contracts: 8 tools with JSON schemas
- Quickstart guide with complete workflow examples
- Constitution compliance verified
Technical stack:
- Node.js 20 LTS
- Valkey 8.0+ for persistence
- Docker containers (amd64/arm64)
- Performance: <2s search, 50+ concurrent sessions
Ready for task generation with /speckit.tasks
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
11 KiB
Technical Research: Mock GDS MCP Server
Branch: 001-mock-gds-server | Date: 2026-04-07
Phase 0: Technology Decisions
Decision 1: MCP SDK and Protocol Implementation
Decision: Use @modelcontextprotocol/sdk official Node.js SDK
Rationale:
- Official SDK ensures MCP protocol compliance (Constitution Principle I)
- Handles JSON-RPC 2.0 message format automatically
- Provides TypeScript types for type safety
- Active maintenance by Anthropic
- Simplified tool registration and schema management
Alternatives Considered:
- Custom MCP implementation: Rejected - high risk of protocol non-compliance, significant development effort
- Python MCP SDK: Rejected - requirement specifies Node.js with minimal dependencies
Implementation Notes:
- SDK provides
Serverclass for initialization - Tool handlers registered via
server.setRequestHandler - Automatic capability negotiation during handshake
- Built-in error handling with standard MCP error codes
Decision 2: Valkey Client Library
Decision: Use ioredis v5.x as Valkey client
Rationale:
- Valkey is Redis protocol-compatible, ioredis is the most mature Node.js Redis client
- Full support for Redis/Valkey commands (GET, SET, HSET, EXPIRE, etc.)
- Connection pooling and automatic reconnection
- Cluster and sentinel support (for future scaling)
- Pipeline and transaction support
- Active maintenance and TypeScript support
Alternatives Considered:
- node-redis: Rejected - ioredis has better TypeScript support and more features
- Custom Valkey protocol: Rejected - unnecessarily complex
- No persistence (memory-only): Rejected - requirement specifies Valkey for persistence
Implementation Notes:
- Use Redis-compatible commands only (avoid Redis-specific extensions)
- Session data stored with TTL (e.g., 1 hour default)
- Key naming:
gds:session:{sessionId}:bookings:{pnr} - Use hash structures for complex objects (bookings, searches)
- Enable Valkey RDB/AOF persistence via docker-compose configuration
Decision 3: Minimal Dependencies Strategy
Decision: Limit external dependencies to essentials only
Core Dependencies (production):
@modelcontextprotocol/sdk- MCP protocol (required)ioredis- Valkey client (required for persistence)pino- Structured logging (minimal, fast, constitution requires observability)
Development Dependencies:
- Node.js native test runner (
node:test) - no jest/mocha overhead c8- code coverage (lightweight)
Rationale:
- Aligns with "minimal libraries" requirement
- Reduces attack surface and dependency maintenance burden
- Faster container builds and smaller images
- Native Node.js features (test runner, assert) are mature and sufficient
Explicitly Avoided:
- ❌ Express/Fastify/Koa - MCP uses stdio/SSE, no HTTP server needed
- ❌ TypeORM/Prisma - direct Valkey commands sufficient for key-value storage
- ❌ Jest/Mocha - native test runner adequate
- ❌ Lodash/Ramda - native JS methods sufficient
- ❌ Moment.js/date-fns - native Date and Temporal API (when available)
Decision 4: Docker Build Strategy
Decision: Use Docker Buildx with docker-bake.hcl for multi-platform builds
Rationale:
docker buildx bakesupports complex build configurations- Multi-platform builds (linux/amd64, linux/arm64) in single command
- Build matrix for multiple tags (latest, version, dev)
- Better caching and parallelization than traditional Dockerfile
- Aligns with requirement specification
Build Configuration:
# docker-bake.hcl
target "default" {
dockerfile = "docker/Dockerfile"
tags = ["gds-mock-mcp:latest"]
platforms = ["linux/amd64", "linux/arm64"]
cache-from = ["type=registry,ref=gds-mock-mcp:buildcache"]
cache-to = ["type=registry,ref=gds-mock-mcp:buildcache,mode=max"]
}
Dockerfile Strategy:
- Multi-stage build: builder → production
- Builder stage: install dependencies, run tests
- Production stage: copy only production deps and source
- Use Node.js 20 Alpine for minimal image size
- Non-root user for security
- Health check via MCP ping or valkey connection test
Alternatives Considered:
- Traditional Dockerfile only: Rejected - buildx bake provides better DX and multi-platform support
- Docker Compose build: Rejected - less flexible than buildx, no multi-platform
- Podman: Rejected - Docker specified in requirements
Decision 5: Mock Data Architecture
Decision: Embed realistic GDS data in JavaScript modules with deterministic generation
Data Structure:
- Airports: ~100 major airports with IATA codes (JFK, LAX, ORD, etc.)
- Airlines: Major carriers with IATA codes (AA, DL, UA, BA, etc.)
- Hotels: 50+ chains/properties across major cities
- Car Rentals: Major companies (Hertz, Avis, Enterprise) with vehicle types
- Flight Routes: Pre-defined routes with realistic times and prices
- Pricing Tiers: Economy ($200-$600 domestic), Business ($800-$2000), First Class ($2500+)
Generation Strategy:
- Deterministic: Same search inputs produce same results (for testing reproducibility)
- Controlled Randomness: Optional seed parameter for demo variety
- Rule-Based Pricing: Distance-based pricing with time-of-day adjustments
- Availability Simulation: Random sold-out scenarios (10% of flights)
Rationale:
- Embedded data = no external dependencies (fast startup)
- Deterministic = reliable integration tests
- Realistic codes = constitution compliance (Principle II)
- Pre-computed routes = sub-2s response times
Alternatives Considered:
- External API (Skyscanner, etc.): Rejected - violates "no external connections" (Constitution Principle III)
- Database seeding: Rejected - overhead, embedded data sufficient for mock scope
- Fully random data: Rejected - testing requires deterministic outputs
Decision 6: Testing Strategy
Decision: Use Node.js native test runner with three-tier test structure
Test Tiers:
-
Unit Tests: Individual tool handlers, data generators, validators
- Fast (<100ms total), isolated, no external dependencies
- Mock Valkey client for session tests
-
Integration Tests: Full MCP workflows with real Valkey (test container)
- End-to-end booking flows (search → book → retrieve → cancel)
- Multi-service workflows (flight + hotel + car)
- Concurrent session isolation tests
- Use docker-compose test profile for Valkey
-
Contract Tests: MCP protocol compliance validation
- Verify JSON-RPC 2.0 format
- Tool schema validation
- Error response structure
Test Execution:
npm test # All tests
npm run test:unit # Fast unit tests only
npm run test:integration # Requires Valkey
npm run test:coverage # Coverage report with c8
Rationale:
- Native test runner = minimal dependencies
- Three tiers = appropriate test coverage
- Docker test containers = realistic integration tests
- Fast unit tests = quick feedback loop
Decision 7: Configuration Management
Decision: Environment variables with secure defaults
Configuration Variables:
# MCP Server
MCP_TRANSPORT=stdio # stdio or sse
MCP_SESSION_TIMEOUT=3600 # 1 hour session TTL
# Valkey
VALKEY_HOST=localhost
VALKEY_PORT=6379
VALKEY_PASSWORD= # Empty for dev, required for prod
VALKEY_DB=0
VALKEY_KEY_PREFIX=gds:
# Logging
LOG_LEVEL=info # silent, error, warn, info, debug, trace
LOG_PRETTY=false # Pretty print for dev
# Mock Data
MOCK_DATA_SEED=fixed # fixed or random
MOCK_RESPONSE_DELAY=0 # Artificial delay (ms) for demo purposes
Security Defaults:
- No production credentials in code or .env.example
- Configuration validation on startup
- Reject production-like patterns (Constitution Principle III)
Rationale:
- Standard practice for containerized apps
- Easy to override in docker-compose
- Secure defaults prevent accidents
Decision 8: PNR Generation Strategy
Decision: Deterministic PNR generation with TEST prefix
Format: TEST-{BASE32} where BASE32 is 6 characters
Example: TEST-A1B2C3
Generation Algorithm:
- Generate session-scoped sequence number
- Combine with booking timestamp
- Hash with SHA-256
- Take first 6 characters of base32 encoding
- Prefix with "TEST-"
Rationale:
- "TEST-" prefix = clear mock indicator (Constitution Principle III)
- Base32 = human-readable, unambiguous (no 0/O, 1/I confusion)
- 6 characters = 1 billion unique combinations (sufficient for testing)
- Deterministic = reproducible test scenarios
- Session-scoped = prevents conflicts
Alternatives Considered:
- Random UUID: Rejected - too long, not human-friendly
- Sequential numbers: Rejected - predictable, not realistic
- No prefix: Rejected - violates safety requirement
Technology Stack Summary
| Component | Technology | Version | Rationale |
|---|---|---|---|
| Runtime | Node.js | 20 LTS | Current stable, long-term support |
| MCP SDK | @modelcontextprotocol/sdk | Latest | Official SDK, protocol compliance |
| Persistence | Valkey | 8.0+ | Redis-compatible, requirement specified |
| Valkey Client | ioredis | 5.x | Mature, feature-rich, TypeScript support |
| Logging | Pino | Latest | Fast, structured, minimal overhead |
| Testing | node:test | Built-in | Native, zero dependencies |
| Coverage | c8 | Latest | V8 coverage, lightweight |
| Container | Docker | 24+ | Buildx support, multi-platform |
| Orchestration | docker-compose | 2.x | Development environment |
Performance Considerations
Expected Performance Profile
- Search Operations: <500ms (data generation + Valkey lookup)
- Booking Operations: <200ms (validation + Valkey write)
- Retrieval Operations: <100ms (Valkey read)
- Concurrent Sessions: 50+ (limited by Valkey and Node.js event loop)
- Memory Footprint: <100MB per server instance
- Container Image Size: <50MB (Alpine-based)
Optimization Strategies
- Caching: Pre-compute common search results in Valkey
- Connection Pooling: ioredis maintains persistent Valkey connections
- Lazy Loading: Load mock data modules on-demand
- Batch Operations: Use Valkey pipelines for multi-key operations
Security Considerations
Mock Data Safety
- ✅ No real API keys or credentials stored
- ✅ Configuration validation rejects production patterns
- ✅ All PNRs prefixed with "TEST-"
- ✅ No external network calls (except to local Valkey)
- ✅ Non-root container user
Docker Security
- Use official Node.js Alpine base images
- Run as non-root user (node:node)
- Minimal attack surface (no shell, no dev tools in prod image)
- Regular security updates via base image updates
Open Questions (Resolved)
All technical unknowns from initial planning have been resolved through research above. No blocking issues identified.
Next Steps
Proceed to Phase 1: Design & Contracts
- Create data-model.md (data structures)
- Define MCP tool contracts in contracts/
- Generate quickstart.md with usage examples
- Update agent context with technology decisions