Files
gds-mock-mcp/specs/001-mock-gds-server/research.md
Peter.Morton 35a98c6d4b feat: complete implementation plan for Mock GDS MCP server
Phase 0 (Research):
- Selected MCP SDK (@modelcontextprotocol/sdk) for protocol compliance
- Chose ioredis for Valkey client (Redis-compatible)
- Minimal dependencies: Pino logging, native test runner
- Docker buildx bake for multi-platform builds
- Embedded mock data with deterministic generation
- PNR format: TEST-{BASE32} for safety

Phase 1 (Design):
- Data model: 8 core entities (Session, PNR, FlightSegment, etc.)
- MCP contracts: 8 tools with JSON schemas
- Quickstart guide with complete workflow examples
- Constitution compliance verified

Technical stack:
- Node.js 20 LTS
- Valkey 8.0+ for persistence
- Docker containers (amd64/arm64)
- Performance: <2s search, 50+ concurrent sessions

Ready for task generation with /speckit.tasks

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-07 11:27:53 -05:00

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 Server class for initialization
  • Tool handlers registered via server.setRequestHandler
  • Automatic capability negotiation during handshake
  • Built-in error handling with standard MCP error codes

Decision 2: Valkey Client Library

Decision: Use ioredis v5.x as Valkey client

Rationale:

  • Valkey is Redis protocol-compatible, ioredis is the most mature Node.js Redis client
  • Full support for Redis/Valkey commands (GET, SET, HSET, EXPIRE, etc.)
  • Connection pooling and automatic reconnection
  • Cluster and sentinel support (for future scaling)
  • Pipeline and transaction support
  • Active maintenance and TypeScript support

Alternatives Considered:

  • node-redis: Rejected - ioredis has better TypeScript support and more features
  • Custom Valkey protocol: Rejected - unnecessarily complex
  • No persistence (memory-only): Rejected - requirement specifies Valkey for persistence

Implementation Notes:

  • Use Redis-compatible commands only (avoid Redis-specific extensions)
  • Session data stored with TTL (e.g., 1 hour default)
  • Key naming: gds:session:{sessionId}:bookings:{pnr}
  • Use hash structures for complex objects (bookings, searches)
  • Enable Valkey RDB/AOF persistence via docker-compose configuration

Decision 3: Minimal Dependencies Strategy

Decision: Limit external dependencies to essentials only

Core Dependencies (production):

  1. @modelcontextprotocol/sdk - MCP protocol (required)
  2. ioredis - Valkey client (required for persistence)
  3. pino - Structured logging (minimal, fast, constitution requires observability)

Development Dependencies:

  • Node.js native test runner (node:test) - no jest/mocha overhead
  • c8 - code coverage (lightweight)

Rationale:

  • Aligns with "minimal libraries" requirement
  • Reduces attack surface and dependency maintenance burden
  • Faster container builds and smaller images
  • Native Node.js features (test runner, assert) are mature and sufficient

Explicitly Avoided:

  • Express/Fastify/Koa - MCP uses stdio/SSE, no HTTP server needed
  • TypeORM/Prisma - direct Valkey commands sufficient for key-value storage
  • Jest/Mocha - native test runner adequate
  • Lodash/Ramda - native JS methods sufficient
  • Moment.js/date-fns - native Date and Temporal API (when available)

Decision 4: Docker Build Strategy

Decision: Use Docker Buildx with docker-bake.hcl for multi-platform builds

Rationale:

  • docker buildx bake supports complex build configurations
  • Multi-platform builds (linux/amd64, linux/arm64) in single command
  • Build matrix for multiple tags (latest, version, dev)
  • Better caching and parallelization than traditional Dockerfile
  • Aligns with requirement specification

Build Configuration:

# docker-bake.hcl
target "default" {
  dockerfile = "docker/Dockerfile"
  tags = ["gds-mock-mcp:latest"]
  platforms = ["linux/amd64", "linux/arm64"]
  cache-from = ["type=registry,ref=gds-mock-mcp:buildcache"]
  cache-to = ["type=registry,ref=gds-mock-mcp:buildcache,mode=max"]
}

Dockerfile Strategy:

  • Multi-stage build: builder → production
  • Builder stage: install dependencies, run tests
  • Production stage: copy only production deps and source
  • Use Node.js 20 Alpine for minimal image size
  • Non-root user for security
  • Health check via MCP ping or valkey connection test

Alternatives Considered:

  • Traditional Dockerfile only: Rejected - buildx bake provides better DX and multi-platform support
  • Docker Compose build: Rejected - less flexible than buildx, no multi-platform
  • Podman: Rejected - Docker specified in requirements

Decision 5: Mock Data Architecture

Decision: Embed realistic GDS data in JavaScript modules with deterministic generation

Data Structure:

  • Airports: ~100 major airports with IATA codes (JFK, LAX, ORD, etc.)
  • Airlines: Major carriers with IATA codes (AA, DL, UA, BA, etc.)
  • Hotels: 50+ chains/properties across major cities
  • Car Rentals: Major companies (Hertz, Avis, Enterprise) with vehicle types
  • Flight Routes: Pre-defined routes with realistic times and prices
  • Pricing Tiers: Economy ($200-$600 domestic), Business ($800-$2000), First Class ($2500+)

Generation Strategy:

  • Deterministic: Same search inputs produce same results (for testing reproducibility)
  • Controlled Randomness: Optional seed parameter for demo variety
  • Rule-Based Pricing: Distance-based pricing with time-of-day adjustments
  • Availability Simulation: Random sold-out scenarios (10% of flights)

Rationale:

  • Embedded data = no external dependencies (fast startup)
  • Deterministic = reliable integration tests
  • Realistic codes = constitution compliance (Principle II)
  • Pre-computed routes = sub-2s response times

Alternatives Considered:

  • External API (Skyscanner, etc.): Rejected - violates "no external connections" (Constitution Principle III)
  • Database seeding: Rejected - overhead, embedded data sufficient for mock scope
  • Fully random data: Rejected - testing requires deterministic outputs

Decision 6: Testing Strategy

Decision: Use Node.js native test runner with three-tier test structure

Test Tiers:

  1. Unit Tests: Individual tool handlers, data generators, validators

    • Fast (<100ms total), isolated, no external dependencies
    • Mock Valkey client for session tests
  2. Integration Tests: Full MCP workflows with real Valkey (test container)

    • End-to-end booking flows (search → book → retrieve → cancel)
    • Multi-service workflows (flight + hotel + car)
    • Concurrent session isolation tests
    • Use docker-compose test profile for Valkey
  3. Contract Tests: MCP protocol compliance validation

    • Verify JSON-RPC 2.0 format
    • Tool schema validation
    • Error response structure

Test Execution:

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:

  1. Generate session-scoped sequence number
  2. Combine with booking timestamp
  3. Hash with SHA-256
  4. Take first 6 characters of base32 encoding
  5. Prefix with "TEST-"

Rationale:

  • "TEST-" prefix = clear mock indicator (Constitution Principle III)
  • Base32 = human-readable, unambiguous (no 0/O, 1/I confusion)
  • 6 characters = 1 billion unique combinations (sufficient for testing)
  • Deterministic = reproducible test scenarios
  • Session-scoped = prevents conflicts

Alternatives Considered:

  • Random UUID: Rejected - too long, not human-friendly
  • Sequential numbers: Rejected - predictable, not realistic
  • No prefix: Rejected - violates safety requirement

Technology Stack Summary

Component Technology Version Rationale
Runtime Node.js 20 LTS Current stable, long-term support
MCP SDK @modelcontextprotocol/sdk Latest Official SDK, protocol compliance
Persistence Valkey 8.0+ Redis-compatible, requirement specified
Valkey Client ioredis 5.x Mature, feature-rich, TypeScript support
Logging Pino Latest Fast, structured, minimal overhead
Testing node:test Built-in Native, zero dependencies
Coverage c8 Latest V8 coverage, lightweight
Container Docker 24+ Buildx support, multi-platform
Orchestration docker-compose 2.x Development environment

Performance Considerations

Expected Performance Profile

  • Search Operations: <500ms (data generation + Valkey lookup)
  • Booking Operations: <200ms (validation + Valkey write)
  • Retrieval Operations: <100ms (Valkey read)
  • Concurrent Sessions: 50+ (limited by Valkey and Node.js event loop)
  • Memory Footprint: <100MB per server instance
  • Container Image Size: <50MB (Alpine-based)

Optimization Strategies

  1. Caching: Pre-compute common search results in Valkey
  2. Connection Pooling: ioredis maintains persistent Valkey connections
  3. Lazy Loading: Load mock data modules on-demand
  4. Batch Operations: Use Valkey pipelines for multi-key operations

Security Considerations

Mock Data Safety

  • No real API keys or credentials stored
  • Configuration validation rejects production patterns
  • All PNRs prefixed with "TEST-"
  • No external network calls (except to local Valkey)
  • Non-root container user

Docker Security

  • Use official Node.js Alpine base images
  • Run as non-root user (node:node)
  • Minimal attack surface (no shell, no dev tools in prod image)
  • Regular security updates via base image updates

Open Questions (Resolved)

All technical unknowns from initial planning have been resolved through research above. No blocking issues identified.

Next Steps

Proceed to Phase 1: Design & Contracts

  • Create data-model.md (data structures)
  • Define MCP tool contracts in contracts/
  • Generate quickstart.md with usage examples
  • Update agent context with technology decisions