This project is a minimal end‑to‑end airspace copilot that connects:
- n8n workflows that periodically fetch flight data (e.g., from OpenSky) and expose it via HTTP webhooks.
- An MCP server (
server.py) that wraps those webhooks as strongly‑typed MCP tools. - Groq‑backed agents (
agents.py) that call those tools to reason about flight status and anomalies. - A Streamlit UI (
ui_app.py) that lets travelers and ops staff interact with the system in the browser.
It is designed as a simple but complete example of an agentic tools + workflows stack: data flows from n8n → MCP tools → agents → UI.
Modern airline operations and passengers both have access to raw flight‑tracking data, but:
- Passengers struggle to interpret altitudes, speeds, and positions into answers like “Is my flight OK?”
- Ops teams need a concise view of regional traffic and anomalies rather than raw state vectors.
- Many systems are tightly coupled to a single API and lack a clean separation between:
- Data collection (scheduled workflows),
- Tooling interfaces (MCP),
- Reasoning (LLM agents),
- User experience (UI).
This project addresses that gap by:
- Using n8n to periodically fetch and cache flight snapshots.
- Exposing those snapshots as MCP tools that any agent or client can call.
- Building Groq‑based agents that can call the tools and coordinate with each other.
- Providing a simple web UI where travelers and ops staff can ask natural‑language questions.
The result is a compact, extensible example of an agentic AI system over live(ish) aviation data.
High‑level flow:
- n8n periodically calls an aviation data API (e.g. OpenSky), normalizes the response, and stores the latest snapshot per region.
- n8n exposes HTTP webhooks (e.g.
REGION1_WEBHOOK) that always return the latest snapshot as JSON. - The MCP server (
server.py) defines tools that internally call those webhooks and return strongly typed results. - Groq agents (
agents.py) call those tools via tool‑calling. - The Streamlit UI (
ui_app.py) provides two personas:- Traveler: focuses on a single callsign.
- Ops: focuses on regional traffic and anomalies.
Architecture diagram (from the assignment, implemented here):
Additional inspector / debugging views:
The n8n workflows (not stored in this repo) are responsible for:
- Fetching data from an aviation API on a schedule (e.g. every N seconds).
- Transforming the raw state vectors into a normalized snapshot shape:
region: region identifier (e.g."region1").snapshot_time: Unix timestamp of the snapshot.fetched_at_iso: ISO8601 timestamp of when n8n fetched it.flight_count: number of flights.flights: list of flight dicts with keys likeicao24,callsign,origin_country,latitude,longitude,geo_altitude,velocity,vertical_rate,on_ground, etc.
- Caching the latest snapshot in memory or a simple store inside n8n.
- Exposing the latest snapshot via an HTTP webhook endpoint per region:
- Example:
http://localhost:5678/webhook/latest-region1
- Example:
In this project, the Python code never talks directly to OpenSky. Instead, it trusts that n8n owns data collection and caching, and simply pulls the most recent snapshot on demand via HTTP.
The MCP server uses FastMCP (mcp.server.fastmcp.FastMCP) and exposes an HTTP endpoint using the streamable-http transport.
-
Type definitions (via
typing_extensions.TypedDict):Flight: a single aircraft’s state, with fields likeicao24,callsign,origin_country,latitude,longitude,geo_altitude,velocity,vertical_rate,on_ground, etc.Snapshot: a region snapshot containing metadata and a list ofFlight.FlightLookupResult: metadata + an optionalflight+ a human‑readable message.AlertandAlertResult: anomaly descriptions and severity.
-
Webhook configuration:
REGION_WEBHOOKSis a dictionary mapping region IDs to webhook URLs.- URLs can be overridden via environment variables, e.g.:
REGION1_WEBHOOK(default:http://localhost:5678/webhook/latest-region1).
-
Internal helper:
_fetch_snapshot(region):- Validates that the region exists.
- Calls the configured n8n webhook using
requests. - Ensures
regionandflight_countfields are present.
Exposed MCP tools:
-
flights_list_region_snapshot(region: str = "region1") -> Snapshot
Returns the latest cached snapshot for the given region. -
flights_get_by_callsign(callsign: str, region: str = "region1") -> FlightLookupResult- Searches the latest snapshot for
callsign. - Returns a result with:
flight(orNone),messagedescribing the outcome,region,snapshot_time, andfetched_at_iso.
- Searches the latest snapshot for
-
alerts_list_active(region: str = "region1") -> AlertResult
Simple rule‑based anomaly detection:- Flags flights with low speed at high altitude (e.g.
alt > 8000andvelocity < 100 m/s). - Flags very high climb/descent rates (e.g.
vertical_rate > 20or< -20m/s).
- Flags flights with low speed at high altitude (e.g.
These tools are what agents and external MCP clients see; they hide the n8n details behind a clean tool interface.
Agents are implemented using Groq’s chat completions with tool‑calling.
- Tool registry (
TOOLS): describes the MCP tools in the standard function‑calling schema (names, descriptions, parameters). execute_tool(name, arguments): routes a tool call from the LLM to the actual Python implementations inserver.py.- Groq client:
- Configured via
GROQ_API_KEY(environment variable). - Created lazily so that importing
agents.pydoesn’t immediately fail if the key is missing.
- Configured via
- Send a
system_promptanduser_queryplus the allowed tools to the model. - If the model returns
tool_calls, parse each call, execute it viaexecute_tool, and append the results astoolmessages. - Call the model again with the conversation (including tool outputs) to produce a final answer.
-
traveler_agent(question: str)- Persona: traveler support.
- Prompt: explains that the agent should help passengers understand where their flight is, its altitude and speed, and whether anything looks unusual.
- Tools: restricted to
flights_get_by_callsign.
-
ops_agent(question: str)- Persona: airline operations / dispatcher.
- Prompt: focuses on regional safety, traffic levels, and anomalies.
- Tools:
flights_list_region_snapshotandalerts_list_active.
-
traveler_with_ops(callsign: str, passenger_question: str)- Multi‑agent orchestration pattern:
- Call
traveler_agentwith a question focused on the passenger’s flight. - Call
ops_agentfor a broader regional SITREP around that flight. - Make a final Groq call with both agents’ responses to synthesize one coordinated answer for the passenger.
- Call
- Multi‑agent orchestration pattern:
This structure cleanly demonstrates agent‑to‑agent (A2A) communication on top of shared MCP tools.
The UI uses Streamlit and exposes two main tabs at http://localhost:8501:
-
Traveler View – “Personal Flight Watchdog”
- Inputs:
- Flight callsign (e.g.
PIA293). - Free‑text passenger question (e.g. “Where is my flight and is everything normal?”).
- Flight callsign (e.g.
- Actions:
- Fetch current flight data (tools only):
- Calls
flights_get_by_callsignand shows the raw tool JSON.
- Calls
- Ask Traveler Agent:
- Sends a natural‑language question to
traveler_agent, which may use tools.
- Sends a natural‑language question to
- Ask Traveler + Ops (coordinated):
- Uses
traveler_with_opsto combine traveler and ops perspectives.
- Uses
- Fetch current flight data (tools only):
- Inputs:
-
Ops View – “Airspace Ops Copilot”
- Inputs:
- Region selector (currently only
region1).
- Region selector (currently only
- Actions:
- Fetch latest snapshot:
- Calls
flights_list_region_snapshotand displays:- Region metadata (
region,snapshot_time,flight_count). - A dataframe of flights (callsign, country, altitude, speed, on_ground).
- Region metadata (
- Calls
- Analyze anomalies:
- Calls
alerts_list_activeand shows a table of anomalous flights (altitude, speed, vertical rate, reason, severity).
- Calls
- Ask Ops agent for SITREP:
- Calls
ops_agentto summarize regional traffic and highlight critical flights.
- Calls
- Fetch latest snapshot:
- Inputs:
This UI gives both personas a transparent view: they can see both raw tool output and high‑level agent answers.
The directory contains:
- End‑to‑end demo:
demo.mp4– walkthrough of the MCP + n8n + agents + UI workflow. - Inspector demo:
testing_inspector.mp4– focuses on the MCP/agent inspector tooling.
On GitHub, the videos can be embedded via relative paths, for example:
Screenshots included in this README:
successful_workflow.png– overall architecture.agents_test.png– agent tool‑calling tests.mcp_inspector.png– MCP inspector / HTTP view.
- Single region: only
region1is wired by default, although the code supports additional regions viaREGION_WEBHOOKS. - Simple anomaly rules: detection is threshold‑based (speed vs altitude, vertical rate) and not learned.
- No historical analytics: only the latest snapshot is used; trends and time‑series analysis are out of scope.
- External workflows: the n8n workflows are assumed to exist but are not versioned inside this repository.
- Minimal error handling: network failures, malformed responses, and rate‑limit handling are simplified to keep the example focused.
Potential future improvements:
- Add multi‑region support and a configuration file for regions and webhooks.
- Plug in a database or time‑series store to analyze trends and recurring anomalies.
- Replace the hand‑written rules with a data‑driven anomaly detector (e.g. supervised or unsupervised ML).
- Add authentication/authorization to the MCP server and UI.
- Package the stack (n8n + MCP server + UI) using Docker Compose for single‑command deployment.


