MCP SERVERAvailable

Let an agent read the aircraft. Carefully.

A Model Context Protocol server in front of the drone agent and the fleet backend. It turns 'what is my fleet doing' and 'explain this parameter' into tool calls a coding agent can make, and it puts a gate in front of every one of them. Flight tools are hidden and refused unless you explicitly switch them on.
Available

The server, its gate and its catalog are in tree with tests. It is early: there is no published npm package yet, so you run it from a checkout, and a quarter of the route table is declared seams with no handler behind them.

45
Tools
6
Scopes
3
Transports

THE SURFACE

45 tools, and a published catalog

The tool list is not documentation that drifts. It is a committed catalog file, and a test fails the build if a fresh build of the catalog does not byte-match it.

Registered surface
Read tools
18
Admin and write tools
21
Flight tools
6
Prompts
5
MCP spec revision
2025-06-18

READ

Consolidated and full status, host resources, version, health, a liveness ping, a telemetry snapshot, the service list, perception status, the reachable node list, the agent config with secrets redacted, the full flight-controller parameter set with firmware metadata, one parameter explained, the diff from firmware defaults, a read-only tuning advisory, and the server's own audit log.

ADMIN

Restart a service or the supervisor, set a parameter, set a config key, install, enable, disable, remove, configure, list and inspect plugins, query the node's logs, rename a node, run the pairing flow, change the radio channel or transmit power, and join or leave a WiFi network. Every one of these takes an explicit confirmation argument.

FLIGHT

Arm, disarm, land, return to launch, take off to an altitude capped at 500 m, and set a flight mode. These six are not listed and not callable unless the server was started with flight enforcement on, and each one needs a confirmation id the caller has to echo back.

The route table carries 70 rows and 45 of them have handlers. The other 25 are declared seams: guided goto, emergency stop, mission read and upload, video snapshot and live URL, file access, fleet search and targeting, log tailing, vision writes, and system reboot or factory reset. They are in the table so the scope and safety class of each is decided before anyone writes the handler. None of them is callable today.

INSTALL

Run it from a checkout

There is no package to install yet. Clone, build, and point your MCP client at the built entry point.

shell
$git clone https://github.com/altnautica/ADOS-MCP
cd ADOS-MCP && pnpm install && pnpm build

# Check it can reach a node before wiring a client to it:
node dist/index.js --target agent 192.168.1.50 --verify
# ✓ Connected — agent mode → http://192.168.1.50:8080
claude mcp add
claude mcp add ados -e ADOS_MCP_AGENT_KEY=<pairing-key> -- \
  node "$(pwd)/dist/index.js" --target agent 192.168.1.50

Three transports. A client that spawns the process gets stdio. A long-lived deployment can serve streamable HTTP with an SSE upgrade. On the node itself it binds a Unix socket, and in either non-stdio mode it advertises itself over mDNS so a client on the same network can find it.

SCOPES

Six scopes, and a token that only ever exists once

A credential is minted with an explicit scope set and an optional node allowlist. The plaintext is returned exactly once and only its SHA-256 is stored, so a database read cannot recover a working credential.

readstatus, telemetry, parameters
safe_writereversible configuration
adminservices, plugins, pairing, radio
flightarm, mode, takeoff, land, RTL
destructiveunpair and equivalents
secret_readunredacted config values

New credentials get read, safe write and admin. Flight, destructive and secret read are elevated and have to be asked for. Revoking a credential sets a flag and takes effect on the next call; a fleet-mode server also re-verifies its own credential against the backend every 60 seconds and deauthorizes itself when it is pulled. A malformed or unrecognised principal fails closed.

THE GATE

What happens before a call reaches the drone

The safety gate has no exemptions

A process running on the drone itself is trusted for scope: presence on the Unix socket is the credential, so the scope check is waived. The safety gate is not. Every principal passes it, including the on-box one, and the waiver requires both the on-box flag and the on-box plane so a credential minted elsewhere cannot inherit it.

Simulation is verified, not declared

Starting with a simulation flag does not make the server believe you. It asks each bound node whether it reports itself as simulated, and refuses to serve at all if any node says no or cannot be reached. Until that resolves, the gate treats the target as real hardware.

The audit log is a precondition

A write is refused when the audit log is unhealthy, so there is no path where the aircraft changes and the record does not. Audit events are queryable through the server's own read tools, mirrored to the fleet backend in fleet mode, and pruned after 30 days.

The agent gates again on its own side

The agent does not trust the server. It keeps its own token file at 0600, strips and re-stamps the scope header so a client cannot spoof it, and maps every route to a required scope fail-closed: unclassified writes are denied, sending a command needs flight scope, unpairing needs destructive.

IN PRACTICE

What a session looks like

Redaction is part of the contract, not a formatting choice. The same tool returns a redacted value to a read-only credential and the cleartext to one that also holds secret read.

session
> status.get { node: "drone-01" }
  { ok: true, mode: "LOITER", armed: false, battery: { voltage: 16.4 } }

> config.get { node: "drone-01" }          # read-only credential
  { api_key: "[REDACTED]", ... }

> params.read_all { node: "drone-01", search: "FENCE" }
  { firmware: "ardupilot", total: <n>, params: [{ name: "FENCE_ENABLE", ... }] }

> status.get { node: "drone-01" }          # safe_write-only credential
  refused: scope_missing
Get Early Access