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 :8090 — not :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.