Documentation
ReferenceArchitecture

The Node API (REST + MCP)

The node is the single binary that turns your private mesh into a public surface. It joins the mesh, discovers the apps your supervisors are hosting, and proxies traffic straight to each app's address — so external clients and AI agents never touch mesh setup. It speaks two protocols at once: a REST API (OpenAPI 3 + Swagger UI) and a full MCP server over Streamable-HTTP.

The node listens on :8090not :8080, which is reserved for the auth service on the same host.

REST surface

Every protected endpoint expects Authorization: Bearer <key>, checked in constant time. GET /health, GET /openapi.json, and GET /swagger-ui are open.

# Discover what's running across all supervisors
curl -H 'Authorization: Bearer tabbify-dev-node-key' \
  http://localhost:8090/v1/apps

# Start, stop, and deploy app instances
curl -X POST -H 'Authorization: Bearer tabbify-dev-node-key' \
  http://localhost:8090/v1/apps/<uuid>/start

Core endpoints: /v1/supervisors, /v1/apps, /v1/topology, /v1/apps/{uuid}/start|stop|reset|deploy, plus per-supervisor controls /v1/supervisors/{name}/runtimes and /v1/supervisors/{name}/version. The full schema lives at /openapi.json and is browsable at /swagger-ui.

/app/{uuid} routing

This is the data path. The node derives an app's mesh address directly from its UUID — blake3(uuid)[0:6] mapped into fd5a:1f02:...::1 — and dials it on port 8730. No supervisor query, no cache lookup; the node and the supervisor compute the same address independently. See Routing for the address scheme.

curl http://localhost:8090/app/0191e7c2-1111-7222-8333-444455556666 \
  -H 'Authorization: Bearer tabbify-dev-node-key'

GET /app/{uuid} proxies /; ANY /app/{uuid}/{*rest} forwards method, headers, query, and body to the subpath. Bodies stream both directions with no buffering — large uploads and downloads pass straight through, but a slow upstream holds the connection (no per-hop timeout). An unreachable app returns 502; a malformed UUID returns 400.

MCP tools

The same business logic backs an MCP endpoint at POST/GET /mcp (official rmcp SDK, Streamable-HTTP transport, Mcp-Session-Id header for sessions). Tools mirror the REST verbs — list_supervisors, list_apps, get_app, start_app, stop_app — and carry the same Bearer auth. So an agent discovers, starts, and routes to apps through one session.

Config and caveats

TABBIFY_NODE_BIND=0.0.0.0:8090
TABBIFY_NODE_KEY=<long-random-secret>
TABBIFY_MESH_COORDINATOR=http://3.124.69.92:8888

Honest about the current state: the Bearer key defaults to tabbify-dev-node-key (RnD only — set a real secret for shared deployments), and activation-policy and desired-version stores are in-memory only, lost on restart unless seeded via env. The mesh join needs NET_ADMIN + /dev/net/tun at runtime, so local dev needs sudo and Docker needs cap_add: [NET_ADMIN] with the TUN device. The GITHUB_WEBHOOK_SECRET-gated deploy webhook is wired but returns 503 when unset. For setting up your own edge, see Self-hosting a node.