Flight Control MCP

A read-only API for querying and retrieving contextual information about devices and fleets using the Flight Control MCP server.

mcp-server

Model Context Protocol (MCP) server for Flight Control


Overview

The MCP server provides a read-only API layer for querying and retrieving contextual information about devices and fleets managed by Flight Control. It is designed for safe external integration, reporting, and automation, exposing a REST API that supports filtering and selector-based queries. The MCP server leverages the flightctl-python-client for backend communication and enforces authentication compatible with Flight Control's authorization model.


Building locally

To build the container image locally using Podman, run:

podman build -t mcp-server:latest .

This will create a local image named mcp-server:latest that you can use to run the server.


Pre-built Container Images

โœ… Ready-to-use images are automatically published to quay.io!

# Pull the latest stable image
docker pull quay.io/flightctl/flightctl-mcp:latest

# Run immediately with streamable-http transport
docker run -p 8000:8000 quay.io/flightctl/flightctl-mcp:latest

Automated Publishing

  • ๐Ÿ”„ Automatic builds: Every commit merged to main triggers a new build
  • โœ… Quality assured: Only builds after passing all tests (linting, type checking, unit tests)
  • ๐Ÿ”’ Security scanned: All images are scanned for vulnerabilities with Trivy
  • ๐Ÿ—๏ธ Multi-platform: Available for both linux/amd64 and linux/arm64
  • ๐Ÿท๏ธ Smart tagging: Images tagged with latest, branch name, and commit SHA

For maintainers: See CONTAINER-PUBLISHING.md for setup instructions and workflow details.


Running with Podman or Docker

Example: Using Automatic Configuration (Recommended)

If you've run flightctl login, you can mount the config directory. Note: The server now defaults to streamable-http transport for better web-based integration.

{
  "mcpServers": {
    "mcp-server": {
      "command": "podman",
      "args": [
        "run",
        "-i",
        "--rm",
        "-p", "8000:8000",
        "-v", "~/.config/flightctl:/root/.config/flightctl:ro",
        "-e", "MCP_TRANSPORT",
        "-e", "MCP_HOST",
        "-e", "MCP_PORT",
        "quay.io/flightctl/flightctl-mcp:latest"
      ],
      "env": {
        "MCP_TRANSPORT": "streamable-http",
        "MCP_HOST": "0.0.0.0",
        "MCP_PORT": "8000"
      }
    }
  }
}

Example: Using Environment Variables

For environments where mounting the config file isn't possible:

{
  "mcpServers": {
    "mcp-server": {
      "command": "podman",
      "args": [
        "run",
        "-i",
        "--rm",
        "-p", "8000:8000",
        "-e", "API_BASE_URL",
        "-e", "OIDC_TOKEN_URL",
        "-e", "OIDC_CLIENT_ID",
        "-e", "REFRESH_TOKEN",
        "-e", "INSECURE_SKIP_VERIFY",
        "-e", "LOG_LEVEL",
        "-e", "MCP_TRANSPORT",
        "-e", "MCP_HOST",
        "-e", "MCP_PORT",
        "quay.io/flightctl/flightctl-mcp:latest"
      ],
      "env": {
        "API_BASE_URL": "https://api.flightctl.example.com",
        "OIDC_TOKEN_URL": "https://auth.flightctl.example.com/realms/flightctl/protocol/openid-connect/token",
        "OIDC_CLIENT_ID": "flightctl",
        "REFRESH_TOKEN": "REDACTED",
        "INSECURE_SKIP_VERIFY": "false",
        "LOG_LEVEL": "INFO",
        "MCP_TRANSPORT": "streamable-http",
        "MCP_HOST": "0.0.0.0",
        "MCP_PORT": "8000"
      }
    }
  }
}

Transport Configuration

The MCP server supports three transport methods with stdio as the default for maximum compatibility:

STDIO (Default - Most Compatible)

  • Best for: Local tools, command-line scripts, integrations with clients like Claude Desktop
  • Configuration: Set MCP_TRANSPORT=stdio (default)
  • Why default: Maximum compatibility with existing MCP clients

Streamable HTTP (Recommended for Web Deployments)

  • Best for: Web-based deployments, microservices, exposing MCP over a network
  • Default endpoint: http://127.0.0.1:8000/mcp
  • Configuration: Set MCP_TRANSPORT=streamable-http
  • Note: Requires MCP clients that support the new streamable-http transport

SSE (Server-Sent Events)

  • Best for: Legacy deployments that specifically require SSE
  • Configuration: Set MCP_TRANSPORT=sse
  • Default endpoint: http://127.0.0.1:8000/sse

Authentication Setup

The MCP server uses OIDC/OAuth2 refresh tokens for authentication. To obtain the required credentials:

  1. OIDC_TOKEN_URL: This is typically in the format https://your-auth-server/realms/your-realm/protocol/openid-connect/token

    • If you only have the base realm URL (e.g., https://auth.example.com/realms/flightctl), the server will automatically append /protocol/openid-connect/token
  2. REFRESH_TOKEN: Obtain this from your Flight Control authentication system

    • This token should have appropriate permissions to read Flight Control resources
  3. OIDC_CLIENT_ID: Usually flightctl (this is the default if not specified)


Configuration

The MCP server supports two configuration methods:

1. Automatic Configuration (Recommended)

If you've run flightctl login, the server will automatically read configuration from ~/.config/flightctl/client.yaml. This includes:

  • API server URL
  • OIDC authentication settings
  • SSL certificate configuration
  • Refresh tokens

2. Environment Variable Configuration

The following environment variables can override or supplement the automatic configuration:

  • API_BASE_URL: Base URL for the Flight Control API (e.g., https://api.flightctl.example.com) - Optional (read from config file)
  • OIDC_TOKEN_URL: Full URL to the OIDC token endpoint (e.g., https://auth.flightctl.example.com/realms/flightctl/protocol/openid-connect/token) - Optional (read from config file)
  • OIDC_CLIENT_ID: OIDC client identifier (defaults to flightctl) - Optional
  • REFRESH_TOKEN: OAuth2 refresh token for authentication - Optional (read from config file)
  • INSECURE_SKIP_VERIFY: Skip SSL certificate verification (true/false) - Optional (read from config file)
  • CA_CERT_PATH: Path to custom CA certificate file for SSL verification - Optional
  • LOG_LEVEL: Logging level (DEBUG, INFO, WARNING, ERROR) - Optional (defaults to INFO)

3. MCP Transport Configuration

The following environment variables control the MCP server transport and network settings:

  • MCP_TRANSPORT: Transport mechanism (stdio, sse, streamable-http) - Optional (defaults to stdio)
  • MCP_HOST: Host to bind to for HTTP transports - Optional (defaults to 127.0.0.1)
  • MCP_PORT: Port to listen on for HTTP transports - Optional (defaults to 8000)
  • MCP_PATH: Path for the MCP endpoint - Optional (defaults to /mcp for streamable-http)
  • MCP_LOG_LEVEL: Server log level (debug, info, warning, error) - Optional (defaults to info)

SSL Certificate Handling

The server properly handles SSL certificates in the following priority:

  1. Custom CA Certificate: If CA_CERT_PATH is set, uses the specified certificate file
  2. Skip SSL Verification: If INSECURE_SKIP_VERIFY=true, disables certificate verification (useful for development)
  3. System CA Bundle: Uses the system's default certificate authority bundle (production default)

Logging

The server uses file-based logging to avoid conflicts with the MCP protocol on stdio:

  • Log Location: ~/.local/share/flightctl-mcp/flightctl-mcp.log
  • Log Rotation: Automatic rotation at 10MB with 5 backup files
  • Log Levels: Configurable via LOG_LEVEL environment variable
  • Structured Logging: Includes timestamps, component names, and detailed error context

Error Handling

The server provides robust error handling:

  • Specific Exceptions: Uses typed exceptions (AuthenticationError, APIError, FlightControlError)
  • Detailed Logging: All errors are logged with full context

Running the Server

Local Development

# Run with default stdio transport
python main.py

# Run with streamable-http transport (for web deployments)
MCP_TRANSPORT=streamable-http python main.py

# Run with custom HTTP configuration
MCP_TRANSPORT=streamable-http MCP_HOST=0.0.0.0 MCP_PORT=8080 python main.py

Accessing the HTTP Endpoint

When running with HTTP transport, the MCP endpoint will be available at:

  • Streamable HTTP: http://127.0.0.1:8000/mcp (default)
  • SSE: http://127.0.0.1:8000/sse

Client Connection Examples

For HTTP clients (streamable-http):

from fastmcp import Client

# Connect to streamable-http server
client = Client("http://127.0.0.1:8000/mcp")

For Claude Desktop (stdio):

{
  "mcpServers": {
    "flightctl": {
      "command": "python",
      "args": ["main.py"],
      "env": {
        "MCP_TRANSPORT": "stdio"
      }
    }
  }
}

API Endpoints

The MCP server exposes the following tool endpoints:

Device Management

  • query_devices: Query and filter devices using label and field selectors
  • run_command_on_device: Execute Linux commands on specific devices

Fleet Management

  • query_fleets: Query and filter fleet configurations

Events and Monitoring

  • query_events: Query system events and audit logs

Enrollment

  • query_enrollment_requests: Query device enrollment requests

Configuration Management

  • query_repositories: Query configuration repositories
  • query_resource_syncs: Query resource synchronization status

Testing

Live Instance Testing

To test against your actual Flight Control instance:

# Ensure you have logged in first
flightctl login

# Run the live integration test
python test_live_instance.py

Unit Testing

# Run unit tests
python -m pytest test_flightctl_mcp.py -v

# Run with coverage
python -m pytest test_flightctl_mcp.py --cov=resource_queries --cov=main --cov=cli --cov-report=html

MCP Client Testing

# Test the MCP server with a simple client
python -c "
from fastmcp import Client
import asyncio

async def test():
    client = Client('http://127.0.0.1:8000/mcp')
    async with client:
        tools = await client.list_tools()
        print(f'Available tools: {[t.name for t in tools]}')

asyncio.run(test())
"

Troubleshooting

Common Issues

  1. Server not starting: Check if the port is already in use

    lsof -i :8000
    
  2. Authentication failures: Verify your Flight Control credentials

    flightctl login
    
  3. Connection refused: Ensure the server is running and accessible

    curl -v http://127.0.0.1:8000/mcp
    
  4. Transport issues: Verify the transport configuration matches your client

    # Check server logs
    tail -f ~/.local/share/flightctl-mcp/flightctl-mcp.log
    

Debug Mode

Enable debug logging for more detailed information:

MCP_LOG_LEVEL=debug LOG_LEVEL=DEBUG python main.py

Migration from STDIO

If you're migrating from the previous stdio-only version:

  1. Update your client configuration to use HTTP endpoints instead of stdio
  2. Set environment variables for host/port configuration if needed
  3. Update firewall rules if running on a remote server
  4. Test the connection using the provided client examples

The server will still support stdio transport if you set MCP_TRANSPORT=stdio, maintaining backward compatibility.


Features

  • Read-only querying of devices, fleets, events, enrollment requests, repositories, and resource syncs from Flight Control
  • Support for filtering by labels and fields using Kubernetes-style selectors
  • Context-rich JSON responses including metadata and links to related resources
  • Secure OIDC/OAuth2 refresh tokenโ€“based authentication
  • Remote device console access for executing commands on managed devices
  • Automatic pagination handling for large result sets

Documentation

API endpoints, filtering options, and example requests will be described in the docs/ directory or in the OpenAPI specification.


License

This project is open source. See LICENSE for details.


Contributing

Issues and pull requests are welcome! Please see CONTRIBUTING.md for guidelines.


Related Servers