Skip to main content
Glama
lichen911

Aviation MCP Server

by lichen911
README.md
# Aviation MCP Server

A FastMCP server that provides real-time aircraft data from ADS-B Exchange (adsb.lol API) via **Streamable HTTP transport**.

## Features

- šŸš€ **Streamable HTTP Transport** - Modern HTTP with JSON-RPC protocol
- šŸ” **API Key Authentication** - Secure access control
- ⚔ **FastMCP Framework** - High-performance MCP server
- šŸ›« **Real-time Aircraft Data** - Live ADS-B data from adsb.lol
- šŸ“” **Multiple Query Types** - 8 different ways to query aircraft data
- 🐳 **Production Ready** - Can run standalone or in containers

## Quick Start

### Installation

```bash
cd aviation-mcp-server
uv sync
```

### Running the Server

**Development:**
```bash
uv run aviation-mcp-server-http
```

**With Custom Configuration:**
```bash
export MCP_HOST="0.0.0.0"
export MCP_PORT="8000"
export MCP_API_KEY="your-secret-key"
uv run aviation-mcp-server-http
```

The server will start on `http://0.0.0.0:8000/mcp`

## Configuration

Environment variables:

```env
MCP_HOST=0.0.0.0                          # Server bind address (default: 0.0.0.0)
MCP_PORT=8000                             # Server port (default: 8000)
MCP_API_KEY=your-secret-key               # API key for authentication (default: dev key)
```

## API Documentation

### Endpoint

- **URL**: `http://localhost:8000/mcp`
- **Method**: POST
- **Content-Type**: `application/json`
- **Accept**: `application/json, text/event-stream`

### Authentication

Include API key in one of these headers:
- `X-API-Key: your-secret-key`
- `Authorization: Bearer your-secret-key`

### Available Tool: `query_aircraft`

Query real-time aircraft data from ADS-B Exchange.

#### Parameters

- **query_type** (required): Type of query
  - `"callsign"`: Search by flight callsign (e.g., "UAL123")
  - `"registration"`: Search by aircraft registration (e.g., "N12345")
  - `"aircraft_type"`: Search by aircraft type (e.g., "B738", "A320")
  - `"icao_hex"`: Search by ICAO hex code
  - `"squawk"`: Search by transponder squawk code (e.g., "7700")
  - `"location"`: Search within radius of coordinates
  - `"military"`: Get all military aircraft
  - `"privacy"`: Get aircraft with privacy ICAO addresses

- **value** (optional): Search value for most query types
- **latitude** (optional): Latitude for location queries (-90 to 90)
- **longitude** (optional): Longitude for location queries (-180 to 180)
- **radius** (optional): Search radius in nautical miles for location queries

#### Example Requests

**List Available Tools:**
```bash
curl -X POST http://localhost:8000/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "X-API-Key: adsb-mcp-secret-key-change-in-production" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/list",
    "params": {}
  }'
```

**Query Military Aircraft:**
```bash
curl -X POST http://localhost:8000/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "X-API-Key: adsb-mcp-secret-key-change-in-production" \
  -d '{
    "jsonrpc": "2.0",
    "id": 2,
    "method": "tools/call",
    "params": {
      "name": "query_aircraft",
      "arguments": {
        "query_type": "military"
      }
    }
  }'
```

**Query by Callsign:**
```bash
curl -X POST http://localhost:8000/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "X-API-Key: adsb-mcp-secret-key-change-in-production" \
  -d '{
    "jsonrpc": "2.0",
    "id": 3,
    "method": "tools/call",
    "params": {
      "name": "query_aircraft",
      "arguments": {
        "query_type": "callsign",
        "value": "UAL123"
      }
    }
  }'
```

**Query by Location:**
```bash
curl -X POST http://localhost:8000/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "X-API-Key: adsb-mcp-secret-key-change-in-production" \
  -d '{
    "jsonrpc": "2.0",
    "id": 4,
    "method": "tools/call",
    "params": {
      "name": "query_aircraft",
      "arguments": {
        "query_type": "location",
        "latitude": 40.7128,
        "longitude": -74.0060,
        "radius": 50
      }
    }
  }'
```

## Testing

### Test Server Connectivity
```bash
uv run python test_server.py
```

This will:
1. Test military aircraft query
2. Test callsign query
3. Verify API connectivity

### Manual Health Check
```bash
curl -I http://localhost:8000/mcp
```

Expected: `405 Method Not Allowed` (GET not supported, use POST)

## Integration

### Discord Bot

The `aviation-discord-bot` project can connect to this server:

```env
MCP_TRANSPORT=http
MCP_SERVER_URL=http://localhost:8000/mcp
MCP_API_KEY=your-secret-key
```

### Claude Desktop

Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "adsb-aircraft-data": {
      "command": "bash",
      "args": ["-c", "cd /path/to/aviation-mcp-server && uv run aviation-mcp-server-http"],
      "env": {
        "MCP_API_KEY": "your-secret-key"
      }
    }
  }
}
```

### Other MCP Clients

Any MCP client supporting HTTP transport can connect using:
- **Transport**: HTTP
- **URL**: `http://localhost:8000/mcp`
- **Protocol**: JSON-RPC 2.0
- **Authentication**: API key via `X-API-Key` header

## Architecture

```
ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│  MCP Client    │
│  (Bot/Claude)  │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜
         │
         │ HTTP POST + JSON-RPC
         │ + X-API-Key header
         │
         ā–¼
ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│  FastMCP       │
│  + uvicorn     │
│  + Auth        │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜
         │
         │ HTTPS
         │
         ā–¼
ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│  adsb.lol API  │
│  (ADS-B Data)  │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜
```

## Deployment

### Docker

```dockerfile
FROM python:3.12-slim
WORKDIR /app
COPY . .
RUN pip install uv && uv sync
ENV MCP_API_KEY=${MCP_API_KEY}
ENV MCP_HOST=0.0.0.0
ENV MCP_PORT=8000
EXPOSE 8000
CMD ["uv", "run", "aviation-mcp-server-http"]
```

Build and run:
```bash
docker build -t aviation-mcp-server .
docker run -p 8000:8000 -e MCP_API_KEY=your-secret-key aviation-mcp-server
```

### Kubernetes

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: aviation-mcp-server
spec:
  replicas: 2
  selector:
    matchLabels:
      app: aviation-mcp-server
  template:
    metadata:
      labels:
        app: aviation-mcp-server
    spec:
      containers:
      - name: server
        image: aviation-mcp-server:latest
        ports:
        - containerPort: 8000
        env:
        - name: MCP_API_KEY
          valueFrom:
            secretKeyRef:
              name: mcp-secrets
              key: api-key
---
apiVersion: v1
kind: Service
metadata:
  name: aviation-mcp-server
spec:
  selector:
    app: aviation-mcp-server
  ports:
  - port: 80
    targetPort: 8000
  type: LoadBalancer
```

### systemd Service

Create `/etc/systemd/system/aviation-mcp-server.service`:

```ini
[Unit]
Description=Aviation MCP Server
After=network.target

[Service]
Type=simple
User=adsb
WorkingDirectory=/opt/aviation-mcp-server
Environment="MCP_API_KEY=your-secret-key"
Environment="MCP_HOST=0.0.0.0"
Environment="MCP_PORT=8000"
ExecStart=/usr/local/bin/uv run aviation-mcp-server-http
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target
```

Enable and start:
```bash
sudo systemctl enable aviation-mcp-server
sudo systemctl start aviation-mcp-server
sudo systemctl status aviation-mcp-server
```

## Security

### Production Recommendations

1. **Use HTTPS**: Deploy behind reverse proxy (nginx, Caddy) with TLS
2. **Secure API Keys**: Use secrets management (AWS Secrets Manager, HashiCorp Vault)
3. **Rate Limiting**: Implement rate limiting to prevent abuse
4. **Monitoring**: Add logging and metrics (Prometheus, Grafana)
5. **IP Filtering**: Restrict access to known client IPs
6. **Regular Updates**: Keep dependencies updated

### Example nginx Configuration

```nginx
upstream adsb_mcp {
    server 127.0.0.1:8000;
}

server {
    listen 443 ssl http2;
    server_name mcp.example.com;

    ssl_certificate /etc/ssl/certs/mcp.crt;
    ssl_certificate_key /etc/ssl/private/mcp.key;

    location /mcp {
        proxy_pass http://adsb_mcp;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # Rate limiting
        limit_req zone=mcp_limit burst=10 nodelay;
    }
}
```

## Troubleshooting

### Server won't start
- Check if port 8000 is already in use: `lsof -i :8000`
- Verify dependencies: `uv sync`
- Check Python version: `python --version` (requires 3.10+)

### Authentication errors
- Verify API key in request headers
- Check server logs for authentication failures
- Ensure API key matches `MCP_API_KEY` environment variable

### API errors
- Verify internet connectivity to adsb.lol
- Check adsb.lol API status
- Review server logs for error details

### Performance issues
- Monitor server resources (CPU, memory)
- Check network latency to adsb.lol API
- Consider implementing caching

## Development

### Project Structure
```
aviation-mcp-server/
ā”œā”€ā”€ src/
│   └── aviation_mcp_server/
│       ā”œā”€ā”€ __init__.py
│       └── server.py          # Main server implementation
ā”œā”€ā”€ pyproject.toml             # Dependencies
ā”œā”€ā”€ .python-version            # Python version (3.12)
ā”œā”€ā”€ README.md                  # This file
└── test_server.py             # Connectivity tests
```

### Adding New Tools

To add a new MCP tool, edit `server.py`:

```python
@mcp.tool()
async def your_new_tool(param1: str, param2: int) -> str:
    """
    Description of your tool.

    Args:
        param1: Description
        param2: Description

    Returns:
        Result description
    """
    # Implementation
    return "result"
```

### Running Tests

```bash
# Test server connectivity
uv run python test_server.py

# Manual API test
curl -X POST http://localhost:8000/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "X-API-Key: adsb-mcp-secret-key-change-in-production" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
```

## API Data Source

This server uses the [adsb.lol](https://adsb.lol) API, which provides:
- Real-time aircraft positions
- Flight information (callsign, altitude, speed)
- Aircraft details (type, registration)
- Military aircraft tracking
- Worldwide coverage

## License

MIT

## Contributing

Contributions welcome! Please:
1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Add tests if applicable
5. Submit a pull request

## Support

For issues or questions:
- Check the troubleshooting section
- Review server logs
- Test with manual curl requests
- Verify environment variables

## Acknowledgments

- **ADS-B data**: Provided by [adsb.lol](https://adsb.lol)
- **MCP Framework**: [FastMCP](https://github.com/jlowin/fastmcp)
- **MCP Specification**: [Model Context Protocol](https://spec.modelcontextprotocol.io/)

---

**Version**: 0.1.0
**Status**: Production Ready
**Last Updated**: 2025-10-12

TDQS

A3.9/5.0

Scored across 2 tools

Disambiguation5/5

The two tools have clearly distinct purposes: one queries real-time aircraft data from ADS-B Exchange, the other queries the FAA registration database. There is no overlap in functionality.

Naming Consistency5/5

Both tools follow a consistent verb_noun pattern ('query_aircraft', 'query_registration'), making them predictable and easy to understand.

Tool Count4/5

With only two tools, the server is minimal but covers two primary aviation data sources. It feels slightly thin but is reasonable for a focused purpose.

Completeness4/5

The server covers real-time tracking and registration lookup, which are core aviation queries. Minor gaps exist (e.g., historical data, airport info), but the main workflows are supported.

Maintenance

ActivityInactive
ResponsivenessNo issues