tabbify.io
Documentation
Product directionEDGE BOX
ReferenceArchitecture

The Node API (REST + MCP)

The node connects the public edge to tenant-private workloads. It exposes public application ingress, an OpenAPI-described REST surface, and an MCP endpoint over Streamable HTTP. REST, MCP, CLI, and console coverage are partial and do not expose every operation through every interface.

The control endpoint lives at https://api.tabbify.io behind HTTPS. Public applications use https://app.tabbify.io/app/<uuid>/ or a configured custom domain. Raw host ports are implementation details behind those edges.

REST surface

Every protected endpoint expects Authorization: Bearer <TABBIFY_TOKEN> — your Tabbify API token — 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_TOKEN>' \
  https://api.tabbify.io/v1/apps

# Start, stop, and reset app instances
curl -X POST -H 'Authorization: Bearer <TABBIFY_TOKEN>' \
  https://api.tabbify.io/v1/apps/<uuid>/start

Current operations include application and supervisor reads, selected lifecycle actions, topology, and asynchronous deployment status. Endpoint coverage changes as slices are published, so /openapi.json is the source of truth for paths, methods, request bodies, and response schemas in the deployed version. It is browsable at /swagger-ui.

/app/{uuid} routing

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

curl https://app.tabbify.io/app/0191e7c2-1111-7222-8333-444455556666/

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.

App ingress is public by default. A configured custom domain reaches the same workload through the TLS edge. Your application remains responsible for its own user authentication and authorization.

MCP tools

The same node serves MCP at /mcp. The server advertises the tools enabled in the deployed version and authorized for the session. Coverage is intentionally partial: do not assume that every console or REST operation has an MCP tool, or that a tool name remains available without discovery. Let the client call MCP tool discovery and use the returned names and schemas.

How apps get there

Deploy through the tabbify-io/deploy GitHub Action or run tcli deploy --remote manually. Both submit an asynchronous request; the node clones the selected revision, builds an OCI image, pushes it to the registry, selects one eligible workload target, and activates a CPU-only Firecracker microVM after the configured health gate passes. See the deploy pipeline and the CLI reference.

Config and caveats

The node joins the mesh automatically — the coordinator address is baked into the joiner, so there is nothing to point it at. Requests authenticate with a Bearer token (your network token), or — for MCP clients — via the node's OAuth flow.

Connect an MCP client

The same node serves the Model Context Protocol alongside the REST API, at https://api.tabbify.io/mcp. Interactive clients authorize via the node's full OAuth 2.1 surface (/.well-known/oauth-protected-resource, /.well-known/oauth-authorization-server, dynamic client /register, /authorize, /token) — nothing to paste; a static Bearer token works for headless/CI use. For step-by-step setup of Claude, OpenAI, and other clients, see Connect an MCP client.

Deploy status and lifecycle reads describe current state. They are not a durable release history, and application output is available only as a bounded local tail when the selected host retains it. Production workload traffic uses the managed relay. A self-hosted supervisor still needs NET_ADMIN, /dev/net/tun, and /dev/kvm for Firecracker workloads. See Self-hosting a node.