Skip to main content
Glama
INTEGRATION.md16.6 kB
# Integration Guide This guide provides comprehensive instructions for integrating the Aerospace MCP project with various clients and applications. ## Table of Contents - [MCP Client Configuration](#mcp-client-configuration) - [FastAPI Direct Integration](#fastapi-direct-integration) - [Authentication & Security](#authentication--security) - [Rate Limiting](#rate-limiting) - [Common Integration Patterns](#common-integration-patterns) - [Troubleshooting](#troubleshooting) ## MCP Client Configuration The Aerospace MCP project provides flight planning capabilities through both MCP (Model Context Protocol) and direct FastAPI access. Here are configuration examples for popular MCP clients. ### Claude Desktop Add the following configuration to your Claude Desktop settings: #### Basic Configuration ```json { "mcpServers": { "aerospace-mcp": { "command": "python", "args": ["-m", "uvicorn", "main:app", "--host", "localhost", "--port", "8000"], "cwd": "/path/to/aerospace-mcp" } } } ``` #### Advanced Configuration with Environment Variables ```json { "mcpServers": { "aerospace-mcp": { "command": "python", "args": ["-m", "uvicorn", "main:app", "--host", "localhost", "--port", "8000", "--reload"], "cwd": "/path/to/aerospace-mcp", "env": { "DEBUG": "true", "LOG_LEVEL": "info", "OPENAP_AVAILABLE": "true" } } } } ``` ### VS Code with MCP Extension Add to your VS Code settings.json: ```json { "mcp.servers": [ { "name": "aerospace-mcp", "command": "python", "args": ["-m", "uvicorn", "main:app", "--host", "localhost", "--port", "8000"], "cwd": "/path/to/aerospace-mcp", "autoStart": true } ] } ``` ### Continue.dev Add to your `config.json`: ```json { "models": [...], "mcpServers": [ { "name": "aerospace-mcp", "serverPath": "python", "args": ["-m", "uvicorn", "main:app", "--host", "localhost", "--port", "8000"], "workingDirectory": "/path/to/aerospace-mcp" } ] } ``` ### Generic MCP Client For any MCP client that supports server configuration: ```bash # Start the server python -m uvicorn main:app --host localhost --port 8000 # The server will be available at: # HTTP: http://localhost:8000 # MCP: mcp://localhost:8000 ``` ## FastAPI Direct Integration ### Using cURL #### Health Check ```bash # Basic health check curl http://localhost:8000/health # Expected response: # { # "status": "ok", # "openap": true, # "airports_count": 28000 # } ``` #### Find Airports by City ```bash # Find airports in a specific city curl "http://localhost:8000/airports/by_city?city=San%20Francisco" # Find airports with country filter curl "http://localhost:8000/airports/by_city?city=London&country=GB" # Expected response: # [ # { # "iata": "SFO", # "icao": "KSFO", # "name": "San Francisco International Airport", # "city": "San Francisco", # "country": "US", # "lat": 37.621311, # "lon": -122.378958, # "tz": "America/Los_Angeles" # } # ] ``` #### Flight Planning ```bash # Basic flight plan curl -X POST "http://localhost:8000/plan" \ -H "Content-Type: application/json" \ -d '{ "depart_city": "San Francisco", "arrive_city": "New York", "ac_type": "A320", "cruise_alt_ft": 35000, "route_step_km": 50.0, "backend": "openap" }' # Flight plan with specific airports curl -X POST "http://localhost:8000/plan" \ -H "Content-Type: application/json" \ -d '{ "depart_city": "San Francisco", "arrive_city": "New York", "prefer_depart_iata": "SFO", "prefer_arrive_iata": "JFK", "ac_type": "B738", "cruise_alt_ft": 37000, "mass_kg": 65000, "route_step_km": 25.0, "backend": "openap" }' ``` ### Using HTTPie HTTPie provides a more user-friendly interface for API testing: #### Installation ```bash pip install httpie ``` #### Examples ```bash # Health check http GET localhost:8000/health # Airport search http GET localhost:8000/airports/by_city city=="San Francisco" country=="US" # Flight planning http POST localhost:8000/plan \ depart_city="Los Angeles" \ arrive_city="Chicago" \ ac_type="A321" \ cruise_alt_ft:=36000 \ route_step_km:=30.0 \ backend="openap" ``` ### Using Python Requests ```python import requests import json # Base URL for the API BASE_URL = "http://localhost:8000" # Health check response = requests.get(f"{BASE_URL}/health") print(f"Health: {response.json()}") # Find airports airports = requests.get( f"{BASE_URL}/airports/by_city", params={"city": "Tokyo", "country": "JP"} ) print(f"Tokyo airports: {airports.json()}") # Plan a flight plan_request = { "depart_city": "Tokyo", "arrive_city": "Sydney", "ac_type": "B777", "cruise_alt_ft": 39000, "route_step_km": 100.0, "backend": "openap" } response = requests.post( f"{BASE_URL}/plan", headers={"Content-Type": "application/json"}, json=plan_request ) if response.status_code == 200: plan = response.json() print(f"Flight distance: {plan['distance_nm']:.1f} NM") print(f"Estimated block time: {plan['estimates']['block']['time_min']:.1f} minutes") print(f"Estimated fuel: {plan['estimates']['block']['fuel_kg']:.1f} kg") else: print(f"Error: {response.status_code} - {response.text}") ``` ### JavaScript/TypeScript Integration ```typescript interface PlanRequest { depart_city: string; arrive_city: string; depart_country?: string; arrive_country?: string; prefer_depart_iata?: string; prefer_arrive_iata?: string; ac_type: string; cruise_alt_ft?: number; mass_kg?: number; route_step_km?: number; backend: "openap"; } interface Airport { iata: string; icao: string; name: string; city: string; country: string; lat: number; lon: number; tz?: string; } class AerospaceMCP { constructor(private baseUrl: string = "http://localhost:8000") {} async health(): Promise<{status: string, openap: boolean, airports_count: number}> { const response = await fetch(`${this.baseUrl}/health`); return response.json(); } async findAirports(city: string, country?: string): Promise<Airport[]> { const params = new URLSearchParams({ city }); if (country) params.append("country", country); const response = await fetch(`${this.baseUrl}/airports/by_city?${params}`); return response.json(); } async planFlight(request: PlanRequest): Promise<any> { const response = await fetch(`${this.baseUrl}/plan`, { method: "POST", headers: {"Content-Type": "application/json"}, body: JSON.stringify(request), }); if (!response.ok) { throw new Error(`Planning failed: ${response.statusText}`); } return response.json(); } } // Usage example const client = new AerospaceMCP(); async function example() { try { // Check service health const health = await client.health(); console.log("Service status:", health.status); // Find airports const airports = await client.findAirports("Paris", "FR"); console.log("Paris airports:", airports.map(a => a.iata)); // Plan a flight const plan = await client.planFlight({ depart_city: "Paris", arrive_city: "London", ac_type: "A319", cruise_alt_ft: 35000, backend: "openap" }); console.log(`Flight planned: ${plan.distance_nm.toFixed(1)} NM`); } catch (error) { console.error("Error:", error); } } ``` ## Authentication & Security ### Current Status The current version of Aerospace MCP does not implement authentication. This is suitable for: - Local development - Internal corporate networks - Proof-of-concept deployments ### Future Authentication Options For production deployments, consider implementing: #### API Key Authentication ```python # Example implementation (not currently in main.py) from fastapi import Header, HTTPException async def verify_api_key(x_api_key: str = Header()): if x_api_key != "your-secret-api-key": raise HTTPException(status_code=401, detail="Invalid API key") return x_api_key @app.post("/plan", dependencies=[Depends(verify_api_key)]) def plan(req: PlanRequest): # Implementation pass ``` Usage with authentication: ```bash curl -X POST "http://localhost:8000/plan" \ -H "X-API-Key: your-secret-api-key" \ -H "Content-Type: application/json" \ -d '{"depart_city": "NYC", "arrive_city": "LAX", "ac_type": "A320"}' ``` #### OAuth 2.0 / JWT For more sophisticated authentication: ```bash # Get token TOKEN=$(curl -X POST "http://localhost:8000/token" \ -d "username=user&password=pass" | jq -r '.access_token') # Use token curl -X POST "http://localhost:8000/plan" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"depart_city": "NYC", "arrive_city": "LAX", "ac_type": "A320"}' ``` ### HTTPS/TLS For production deployment: ```bash # Run with HTTPS (requires SSL certificates) uvicorn main:app --host 0.0.0.0 --port 443 \ --ssl-keyfile=key.pem --ssl-certfile=cert.pem ``` ## Rate Limiting ### Basic Rate Limiting Consider implementing rate limiting for production use: ```python # Example with slowapi (not currently implemented) from slowapi import Limiter, _rate_limit_exceeded_handler from slowapi.util import get_remote_address from slowapi.errors import RateLimitExceeded limiter = Limiter(key_func=get_remote_address) app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler) @app.post("/plan") @limiter.limit("10/minute") def plan(request: Request, req: PlanRequest): # Implementation pass ``` ### Client-Side Rate Limiting ```python import time import asyncio from typing import AsyncGenerator class RateLimitedClient: def __init__(self, requests_per_minute: int = 60): self.min_interval = 60.0 / requests_per_minute self.last_request = 0.0 async def request(self, method, url, **kwargs): # Rate limiting logic current_time = time.time() time_since_last = current_time - self.last_request if time_since_last < self.min_interval: await asyncio.sleep(self.min_interval - time_since_last) self.last_request = time.time() # Make the actual request # Implementation depends on your HTTP client pass ``` ## Common Integration Patterns ### Batch Flight Planning ```python import asyncio import aiohttp async def plan_multiple_flights(flight_requests: list) -> list: """Plan multiple flights concurrently with rate limiting.""" async with aiohttp.ClientSession() as session: tasks = [] for req in flight_requests: task = plan_single_flight(session, req) tasks.append(task) # Add small delay to avoid overwhelming the server await asyncio.sleep(0.1) return await asyncio.gather(*tasks, return_exceptions=True) async def plan_single_flight(session, request): async with session.post( "http://localhost:8000/plan", json=request ) as response: return await response.json() # Usage requests = [ {"depart_city": "NYC", "arrive_city": "LAX", "ac_type": "A320"}, {"depart_city": "LAX", "arrive_city": "CHI", "ac_type": "B737"}, {"depart_city": "CHI", "arrive_city": "MIA", "ac_type": "A321"}, ] results = asyncio.run(plan_multiple_flights(requests)) ``` ### Caching Integration ```python import redis import json import hashlib class CachedFlightPlanner: def __init__(self, redis_url="redis://localhost:6379"): self.redis = redis.from_url(redis_url) self.base_url = "http://localhost:8000" def _cache_key(self, request_data: dict) -> str: """Generate cache key from request parameters.""" request_str = json.dumps(request_data, sort_keys=True) return f"flight_plan:{hashlib.md5(request_str.encode()).hexdigest()}" def plan_flight(self, request_data: dict, cache_ttl: int = 3600): """Plan flight with Redis caching.""" cache_key = self._cache_key(request_data) # Check cache first cached_result = self.redis.get(cache_key) if cached_result: return json.loads(cached_result) # Make API request response = requests.post( f"{self.base_url}/plan", json=request_data ) if response.status_code == 200: result = response.json() # Cache the result self.redis.setex( cache_key, cache_ttl, json.dumps(result) ) return result else: response.raise_for_status() ``` ### WebSocket Integration (Future Enhancement) ```python # Example WebSocket endpoint for real-time flight tracking from fastapi import WebSocket @app.websocket("/ws/track/{flight_id}") async def websocket_flight_tracking(websocket: WebSocket, flight_id: str): await websocket.accept() try: while True: # Send flight updates update = await get_flight_update(flight_id) await websocket.send_json(update) await asyncio.sleep(30) # Update every 30 seconds except WebSocketDisconnect: pass ``` ## Troubleshooting ### Common Issues #### 1. OpenAP Import Errors **Problem**: `ModuleNotFoundError: No module named 'openap'` **Solution**: ```bash pip install openap # or uv add openap ``` **Graceful Handling**: The application will still work without OpenAP, but performance estimates will be unavailable. #### 2. Airport Not Found **Problem**: City name not recognized **Solutions**: - Use more specific city names - Include country code parameter - Use IATA code directly with `prefer_depart_iata` or `prefer_arrive_iata` ```bash # Instead of: curl "http://localhost:8000/airports/by_city?city=Paris" # Try: curl "http://localhost:8000/airports/by_city?city=Paris&country=FR" ``` #### 3. Connection Refused **Problem**: `Connection refused` when accessing the API **Solutions**: - Ensure the server is running: `uvicorn main:app --reload` - Check the correct port (default: 8000) - Verify firewall settings - For Docker: ensure port mapping is correct #### 4. Performance Estimation Errors **Problem**: Aircraft type not recognized by OpenAP **Solutions**: - Use standard ICAO aircraft codes (e.g., "A320", "B738", "B777") - Check OpenAP documentation for supported aircraft - Verify aircraft type spelling #### 5. Large Response Times **Problem**: Slow API responses **Solutions**: - Increase `route_step_km` to reduce polyline resolution - Use caching for repeated requests - Consider pagination for large result sets - Monitor server resources ### Debug Mode Enable debug logging: ```bash # Set environment variable export DEBUG=true export LOG_LEVEL=debug # Or run with debug flags uvicorn main:app --reload --log-level debug ``` ### Health Checks Implement health checks in your integration: ```python def check_service_health(): try: response = requests.get("http://localhost:8000/health", timeout=5) health_data = response.json() if health_data["status"] != "ok": raise Exception("Service unhealthy") if not health_data["openap"]: print("Warning: OpenAP not available") return True except Exception as e: print(f"Health check failed: {e}") return False ``` ### Performance Monitoring ```python import time from functools import wraps def monitor_api_calls(func): @wraps(func) def wrapper(*args, **kwargs): start_time = time.time() try: result = func(*args, **kwargs) success = True except Exception as e: result = None success = False raise finally: duration = time.time() - start_time print(f"API call {func.__name__}: {duration:.2f}s, success: {success}") return result return wrapper @monitor_api_calls def plan_flight(request_data): return requests.post("http://localhost:8000/plan", json=request_data) ``` ### Contact & Support For integration issues: - Check the [API documentation](API.md) - Review the [architecture guide](ARCHITECTURE.md) - Create an issue on GitHub - Check existing discussions and issues Remember to include: - Your integration environment (Python version, OS, etc.) - Complete error messages - Minimal reproduction example - Expected vs actual behavior

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/cheesejaguar/aerospace-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server