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

300 lines
11 KiB
Markdown

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