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

@@ -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