MCP is the one and only interface layer between FLYsafe.live data and AI agents. No agent β regardless of which MCP server it calls β ever reads or writes a table directly. Every MCP tool is a thin wrapper over an existing API or view, the same contract the frontend already uses. This keeps AI enablement additive: it can only do what the platform's own APIs already allow, scoped further by an agent-specific permission grant.
Read freely, write narrowly. This principle was established for the Aircraft Custodian API's MCP exposure (Aircraft_Custodian_dTwin_Strategy.html Β§β€) and this document extends it as the platform-wide standard for all five MCP servers: agents can read almost anything they're scoped to see, but can only write to a short, explicit, operationally-safe allowlist β never to identity, retirement, mission binding, partnership approval, or anything that changes who a drone is or who it's flying for.
This document sets the strategy layer above the individual repos. For the concrete API and schema details it references, see the companion docs already in this repo: Aircraft Custodian & dTwin Strategy, MQTT Topic Reference, and Cross-Tenant Partnership Architecture.
Two operational needs justify exposing FLYsafe.live data to AI agents, and both bound the scope of what "AI enablement" is allowed to mean here:
An Aircraft AI agent should be able to answer "is my drone's OI still conforming," "what's my battery and link health right now," "why did I get a TISB alert," and act on a short list of safe, reversible toggles (OI automation on/off, ADS-B surrogate) β without ever being able to change who owns the aircraft, retire it, or rebind its mission.
An OCC / Mission Manager AI agent needs fleet-wide visibility across own-tenant drones and the shared surveillance picture (MLAT, ADS-B, vision sensors, partner-tenant drones) to reason about conflicts and DAA proximity. This is read-heavy by nature β the value is situational awareness, not remote control.
Both use cases are served by read access to a wide surface. Neither use case requires broad write access β which is exactly why Β§6 draws the write boundary as narrowly as it does.
All five live in the AM - FLYsafe project in Bitbucket (workspace/projects/AMFS). Two are designated core β platform infrastructure every other AirMarket service builds on going forward β and three are domain adapters that the core layer will increasingly front.
The platform-wide MCP gateway for FLYsafe.live. Long-term home for the full data-stream surface β RTM state, surveillance feeds, partnerships, infrastructure health β everything in Β§3 that isn't already owned by mcp-api-custodian's per-drone API. Also owns the fleet-wide (make/model) side of the Blender/DSS query layer in Β§3.5 β oi.check_approval_by_description and oi.get_dss_subscribers β since both cross drone boundaries in a way the per-drone Custodian API doesn't.
Wraps the Aircraft Custodian API (Β§β€ of the dTwin strategy doc) β the per-drone dTwin, OI automation, ADS-B provisioning, ownership flag, health. Already has a drafted MCP tool table (drone.list, drone.get_state, drone.set_oi_automation, etc.) with the read/write split this document generalizes. Owns the by-serial side of the Blender/DSS query layer in Β§3.5 β oi.check_approval_by_serial β as a natural extension of its existing GET /drones/{serial}/oi/current.
Read-only fleet and flight history from FLYsafe.software / DroneLogBook β drone roster, flight logs, fleet summary. Fills in the historical/logbook context that live dTwin state doesn't carry (past flights, maintenance notes, inventory numbers).
list_drones, get_drone, list_flights, get_drone_flights, get_fleet_summary, cache_status, rebuild_cacheRead-only DJI FlightHub2 device, dock, and project data β org info, device list, dock status. Explicitly documented in its own source as read-only with respect to FH2; nothing in FH2 is ever modified through this server.
get_connection_info, get_organization_info, list_projects, list_devices, and dock/device detail callsmcp-fh2 currently contains two separate server implementations side by side β a FlightHub2 server at server.py and a FLYsafe/DroneLogBook server at deploy/server.py β plus two installers (install-fh2-mcp.ps1, install-flysafe-mcp.ps1) and two K8s manifests. Left as-is, this makes mcp-fh2 and mcp-flysafe ambiguous as separate Bitbucket repos. Before Phase 1 sign-off, split these cleanly along the repo boundary the team already named (FH2 code β am-mcp-dji-fh2, DroneLogBook code β mcp-flysafe) so each Bitbucket repo builds and deploys exactly one server.
The two core MCP servers (am-mcp-fsl, mcp-api-custodian) are where every FLYsafe.live data stream should eventually become AI-callable. The table below consolidates every stream this repo's existing architecture docs already describe. It is a floor, not a ceiling β Β§10 flags where it's still incomplete.
GCS Plugins β RTTP (encompassing Flink normalization/fusion jobs) β Custodian APIs β tenant.drones, with a second branch RTTP β Evidence & Storage for history/compliance. No raw telemetry ever hits a database directly β RTTP validates and normalizes first. Every row in the tables below is either a piece of RTTP's live output (MQTT), a piece of what it writes to state (Postgres), or a piece of what it writes to history (Evidence & Storage, below). "MQTT" and "RTTP" are not two different systems to account for β MQTT is RTTP's transport.
| Table / View | DB | What it holds | Exposing MCP |
|---|---|---|---|
drones.dlb_drones | tenant rtm_app_db | Raw DroneLogBook import β identity, hardware/firmware, ownership, financial fields. Written only by the Import process. | mcp-api-custodian (read via view) |
drones.drones | tenant rtm_app_db | Custodian dTwin table β adapter config, OI automation + geometry, ADS-B provisioning, ownership flag, live telemetry state, lifecycle timestamps. | mcp-api-custodian |
drones.v_dtwin | tenant rtm_app_db | Canonical joined dTwin record β the view every consumer (frontend, Custodian, MCP) should read the full drone record from. | mcp-api-custodian (primary read path) |
drones.v_dlb_drones | tenant rtm_app_db | Renamed display view over raw DLB import, for operator-facing reporting. | mcp-flysafe / am-mcp-fsl |
| Table / View | DB | What it holds | Exposing MCP |
|---|---|---|---|
aadms.drones | central AADMS | Materialized view over every tenant's drones.drones β dlb_drones via postgres_fdw β callsign β (tenant_id, serial_number) routing for inbound ADS-B. | am-mcp-fsl (routing/lookup tools only β never the raw FDW proxies) |
approved_partners | partnership service DB | Cross-tenant partnership allowlist. | am-mcp-fsl (read-only; status changes stay human-driven per Β§6) |
approval_requests | partnership service DB | Partnership request lifecycle log (pending β approved β suspended β revoked). | am-mcp-fsl (read-only) |
Full topic catalog: FLYsafe_MQTT_Topic.html. Categories relevant to agent read access:
| Category | Example topic | Contents | Agent access |
|---|---|---|---|
v1/output/aircraft/{sn}/β¦ | telemetry, networkid, c2links, events, alerts/{severity}, oi/declaration, proximate_aircraft | Post-Flink-normalized per-aircraft state β the same data the map renders. | Read, via API/MCP tool β never a raw broker subscription from an agent |
v1/shared/β¦ | surveillance_traffic/live_mlat, live_community, live_vision, live_regional_{region}, surveillance_fused, surveillance_sensors/* (station/sensor health), weather/*, infrastructure/sites, inventory/assets, rtm-services/platform, alerts/broadcast | Platform-wide surveillance targets and sensor-health, weather, tenant asset inventory, and infra/pipeline health β identical across tenants. | Read β core to OCC AI's integrated-airspace picture |
v1/input/# | aircraft/{sn}/gcs_telemetry, DJI thing/product/{sn}/osd (root-level, no namespace prefix) | Pre-normalization producer feed from GCS Plugins / adapters. | No agent access β this is the producer-only ingestion path |
v1/internal/# | dock-status/{sn}, asset-tracking/ops/{id}, asset-tracking/c2/{id} | Microservice coordination signals β dockβdrone serial pairing, ops asset positions (incl. dock-mounted ground weather sensors), C2 monitoring stations. | No direct agent access β surface derived fields (e.g. dock status, ground weather) through an API/view if a persona needs them |
GET /drones/{serial}/state, GET /drones/{serial}/telemetry) β consistent with this repo's existing ACL model, where only Flink publishes to v1/output/#/v1/internal/# and only producers/adapters publish to v1/input/#. An MCP server is neither.
v1/output|shared|input|internal, tenant implicit in the broker connection, no separate partner/ root) matches FLYsafe_MQTT_Topic.html's current in-progress revision β that file's own header marks it "v0 (legacy) β v1 (category-first) β in progress" and it is not yet committed to this repo. Beyond the overall structure, that doc's own Open Items table (Β§11) flags specific fields MCP tool design should treat as provisional: weather/* subtopic structure (OI-02, owned by the weather team β not yet designed, don't build a weather tool against it until it lands), the partner Kafka connector source topic (OI-08), and the networkid F3411 field names (OI-12, owned partly by Compliance). Re-check this table against the source doc before relying on it for tool design.
Kafka is the platform's general internal transform bus, not only a partnership mechanism β Flink adapter jobs land normalized output there (e.g. DJI OSD β {tenant}.telemetry.raw.dji) on the way to becoming v1/output/β¦ MQTT topics. The one Kafka-carried stream relevant to agent access is cross-tenant partnership data (partner drone telemetry/OI re-publication into this tenant's own output topics, tagged with sourceTenant), per cross-tenant-partnership-architecture.html. Agent read access to partner-drone data should go through the Partnerships API, not a Kafka consumer β the API is what resolves partner status and display-name mapping that the raw topic doesn't carry. No MCP tool, on any server, should ever consume Kafka directly β it is transform-internal, one layer further from a stable contract than even the MQTT topics.
RTTP has a second output besides tenant.drones: a distinct Evidence & Storage component (Postgres history + InfluxDB telemetry retention, holding CAR 922.08/09/10 evidence logs) that Compliance AI depends on and that isn't the same thing as live dTwin state. It's called out repeatedly as a consumer/destination in the Custodian strategy doc but wasn't broken out as its own inventory line in v1.0 of this document β corrected here.
| Component | Contents | Exposing MCP |
|---|---|---|
| Postgres history | OI generation history (GET /drones/{serial}/oi/history) β audit trail for FLYplan post-flight review and compliance. | mcp-api-custodian (read-only) |
| InfluxDB telemetry | Same store as the live-telemetry row above, retained for evidence rather than just trails β position/mode/battery history over a compliance-relevant window. | mcp-api-custodian (via GET /telemetry, via API, not direct Influx query) |
| CAR 922.08/09/10 evidence logs | Regulatory compliance records (Canadian Aviation Regulation 922 series). Referenced throughout the architecture docs as a destination, but no dedicated read API is documented yet. | Gap β no MCP tool exists or should be built until a scoped read API exists; flagged in Β§10 |
| Source | Contents | Exposing MCP |
|---|---|---|
| InfluxDB | Telemetry timeseries backing GET /drones/{serial}/telemetry (position/mode/battery history for trails). See also Evidence & Storage above β same store, compliance angle. | mcp-api-custodian (via API, not direct Influx query) |
DroneLogBook API (api.dronelogbook.com) | Fleet roster, flight logs β the source of drones.dlb_drones. | mcp-flysafe |
DJI FlightHub2 API (fh.dji.com) | Org, project, device, dock data. | am-mcp-dji-fh2 |
FLYrtm's RTM services run on a Blender deployment β this is the foundation underneath the OI conformance behavior described throughout this doc and the Custodian strategy (Β§β€A FLYplan & OI Automation, Β§β§ Surveillance & Ownership Tagging). It hasn't been broken out as its own layer in this document until now; it belongs here because it's the missing hop between "does this drone have an OI" and "who else needs to know about it" β which is exactly the query chain the integrated-airspace use case in Β§1 depends on.
GET /drones/{serial}/oi/current but scoped to the OI approval question specifically, not the full geometry.networkid in FLYsafe_MQTT_Topic.html Β§5) β a DSS entry doesn't carry the operational data itself, just where to go get it and who else is watching.The FLYsafe.live MCP must let an agent ask "does this drone have an approved OI" and get an answer two ways:
drones.v_dtwin β active mission binding β current OI reference) into the Blender/RTM query in step 1 above.drones.dlb_drones.brand/model aren't unique keys, so this resolves to a candidate list of drones matching that description (scoped to the caller's tenant), each annotated with its own OI approval state β not a single yes/no.| MCP tool name | Query chain | R/W | Notes |
|---|---|---|---|
oi.check_approval_by_serial | dTwin β Blender OI query | R | Exact match. The primary path β use this whenever the caller already has a serial. |
oi.check_approval_by_description | fleet lookup (brand/model) β Blender OI query per match | R | Returns a list, not a single result β the tool response must make the one-to-many nature explicit so an agent doesn't misreport a single drone's status when several matched. |
oi.get_dss_subscribers | OI reference β DSS subscriber query | R | Returns the subscriber/USS list for an OI's airspace volume. Core to OCC AI's integrated-airspace picture (Β§1, Β§7) β this is how an agent answers "who else is watching this flight." |
airmarket.postman.co/workspace/FLYsafe.live/β¦) sits behind Postman login this document's author doesn't have β an unauthenticated fetch redirects straight to identity.getpostman.com. The query chain and tool table above are built from the stated requirement (Blender OI query β DSS subscriber query) plus this repo's existing OI/F3411 conventions, not from the collection's actual request list. Action: Maykon should confirm the concrete Blender and DSS endpoints this covers (paths, auth scheme, whether it's a direct DSS participant connection or brokered) and reconcile them against the tool table above before am-mcp-fsl implementation starts.
mcp-api-custodian's drafted tool table deliberately excludes retire/restore, identity registration, mission binding writes, and adapter-config changes β start narrow, expand deliberately.domain.action naming. Follow the existing convention (drone.list, drone.get_state, drone.set_oi_automation) across all servers so an agent orchestrating across multiple MCP servers sees one consistent vocabulary.cache_last_updated / staleness warnings in the payload, per the existing mcp-flysafe pattern, so an agent (and the pilot it's advising) knows when it's looking at stale data.All five servers should converge on the two-transport pattern already proven in mcp-fh2: stdio for local development against Claude Desktop / Claude Code, sse for cloud/cluster deployment.
| Mode | When | How |
|---|---|---|
stdio | Local dev, Claude Desktop / Claude Code | Server runs as a subprocess; client talks over stdin/stdout. No network exposure, no auth server needed for local iteration. |
sse | Cloud / Kubernetes | Persistent HTTP service; client connects over HTTP + Server-Sent Events. This is the mode every production agent (Aircraft AI, OCC AI) uses. |
Docker image β AWS ECR β Kubernetes Deployment ββ Service :8000 (MCP/SSE) :8080 (health) ββ Pod: single replica per server* β ββ FastMCP SSE server β ββ Health HTTP endpoint β ββ Background cache-refresh thread (adapter-specific) ββ Secrets via K8s Secret β never a committed .env
mcp-api-custodian and am-mcp-fsl, which read live from Postgres rather than an in-process cache, don't have this constraint.
SSE is a long-lived streaming connection β the ingress must not buffer it:
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" nginx.ingress.kubernetes.io/proxy-buffering: "off"
Without proxy-buffering: off, the SSE stream buffers at the ingress and the client never receives messages β this has already bitten the mcp-fh2 deployment once; carry the fix forward to every server's manifest.
| Variable | Description |
|---|---|
MCP_TRANSPORT | stdio (default) or sse |
PORT / HEALTH_PORT | SSE port (default 8000) and health-check port (default 8080) |
<ADAPTER>_API_KEY / _URL | Per-adapter credentials β FLYSAFE_API_KEY, FH2_AUTH_TOKEN, etc. Supplied via K8s Secret in cloud, local .env (gitignored) in dev. |
*_REFRESH_INTERVAL / *_STALE_AFTER_S | Cache refresh cadence and staleness thresholds, surfaced in every tool response per the freshness principle in Β§4. |
This is the section that matters most for safety and compliance: where, exactly, is an agentic workflow allowed to write back into a FLYsafe.live RTM service? The answer is a four-tier model, generalized from the split mcp-api-custodian already drafted. Every MCP tool across all five servers must be classified into exactly one tier before it ships.
Operations that change a drone's identity, ownership registration, or cross-tenant routing, or that alter partnership trust state. These remain human-initiated through the frontend, full stop β no agent persona, no permission grant, changes this.
Operationally meaningful but reversible changes. Exposed only to agent service accounts with an explicit per-tenant permission grant in Keycloak, and every write must carry an audit reason field.
drone.set_ownership β surveillance ownership flag (audit reason required)Bounded, reversible, server-range-enforced. Safe to expose by default to the persona the tool serves (typically Aircraft AI), without a separate permission grant beyond normal tool access.
drone.set_oi_automation β enable/disable OI automationdrone.set_oi_distance β OI defaults, numeric clamp enforced server-sidedrone.set_adsb_surrogate β ADS-B surrogate toggledrone.regenerate_oi β force OI regenerationEverything else: dTwin state, telemetry, OI status/history, health, fleet/flight history, surveillance feeds, partnership visibility, ADS-B status, and the Blender/DSS OI-approval and subscriber lookups in Β§3.5. This is the overwhelming majority of the surface in Β§3 β read access should be generous, because both driving use cases in Β§1 are read-heavy.
Assists the pilot flying a specific drone. Primary consumer of mcp-api-custodian.
Assists mission managers running integrated airspace across the fleet and shared surveillance picture. Primary consumer of am-mcp-fsl.
Evidence and audit-focused. Reads OI history, ADS-B status, health/lifecycle events, and the Evidence & Storage domain (Β§3) once its CAR 922 read API exists.
FLYsafe_MQTT_Topic.html's Open Items table (OI-07) notes that dead-letter-queue monitoring is developer-watched today, with "AI agent monitoring under consideration for production." That's a genuine Ops/Platform AI use case distinct from the three above β read-only against pipeline health (rtm-services/platform, DLQ depth/age) rather than drone state. Don't design tools for it yet; note it here so Phase 3+ scoping doesn't miss it once the team confirms direction.
MCP inherits the platform's existing Keycloak/JWT model rather than inventing a parallel one:
Finalize mcp-api-custodian against the tier model in Β§6; this is the closest to done and becomes the reference implementation the other four match.
Split the mcp-fh2 working copy along its real repo boundary (Β§2 finding) so am-mcp-dji-fh2 and mcp-flysafe are each a single, cleanly deployable server.
Close the ClickUp whiteboard gap (Β§10) and extend am-mcp-fsl to the full data-stream inventory in Β§3 β surveillance, infrastructure health, partnerships β plus the Blender/DSS OI-approval and subscriber query tools in Β§3.5 once Maykon confirms the concrete endpoint scope.
Cross-tenant-aware read tools in am-mcp-fsl β partner-drone visibility through the Partnerships API, matching the read-only partner UX already specified in the partnership architecture doc.
Formalize the Tier 1 permission model as first-class Keycloak roles per agent persona, so granting/revoking agent write access is an admin action, not a code change.
app.clickup.com/8562670/whiteboards/859ze-31497 requires authenticated access this session doesn't have (an unauthenticated fetch returns ClickUp's mobile-app landing page, not the board). Β§3's inventory is built entirely from schemas and architecture docs already in this repo. Action: whoever owns that board should export it (image or ClickUp doc) into this repo, or walk through it live, so Β§3 can be reconciled against the authoritative data-structure map and any DB/table it names that isn't yet in Β§3 gets added.
bitbucket.org/AirMarket_Inc/workspace/projects/AMFS 404s on an unauthenticated fetch. This strategy is grounded in the two local working copies available (mcp-fh2/am-mcp) plus the architecture already documented in this repo β it has not been checked against the actual current state of mcp-api-custodian, mcp-flysafe, or am-mcp-dji-fh2 as they exist in Bitbucket today. Action: a repo-by-repo capability audit (tool list, transport mode, deployment status) before Phase 1 sign-off.
mcp-api-custodian β don't build agent access to the underlying store ahead of that API.
weather/* stays out of scope until OI-02 resolves. The topic exists and is named in Β§3, but its subtopic structure is still TBD (owned by the weather service team). Treat any weather MCP tool as blocked on that item landing, not as something to build against the current placeholder shape.
identity.getpostman.com for this session β same access limitation as the ClickUp whiteboard and Bitbucket project in the earlier entries above. Β§3.5's tool table is built from the stated query chain (Blender OI query β DSS subscriber query) and this repo's existing OI/F3411 conventions, not from the collection's actual requests. Action: Maykon to confirm the concrete Blender and DSS endpoints, auth scheme, and whether DSS access is a direct participant connection or brokered, before Β§3.5 tools are implemented.
oi.check_approval_by_serial (mcp-api-custodian), oi.check_approval_by_description and oi.get_dss_subscribers (am-mcp-fsl).weather/*, surveillance_sensors/*, and inventory/assets added to the shared-broker row; broadened the Kafka description beyond partnerships to its general adapter-transform role.weather/* MCP exposure blocked on OI-02.FLYsafe_MQTT_Topic.html β added surveillance_fused and alerts/broadcast to the v1/shared/β¦ row.mcp-fh2 working copy as a pre-Phase-1 cleanup item (Β§2).