MCP and programmatic access
Three programmatic surfaces, and which one you want.
Beetl has three programmatic surfaces. They are not interchangeable, and picking the wrong one costs you a day.
| Surface | Reach for it when | Auth | Direction |
|---|---|---|---|
| MCP | An LLM client should query your data, read the catalog, and edit pipelines on your behalf. | X-API-Key | Read and write |
| Arrow Flight SQL | A BI tool or SQL client should read tenant data as Arrow. | Per-tenant SQL credential | Read only |
| REST API | Your own code pushes data in or manages entities. | Ingest token, connector token, or session cookie | Read and write |
MCP
The one most people want. POST /mcp speaks Streamable-HTTP JSON-RPC 2.0 and negotiates protocol version 2025-11-25 or 2025-06-18. It implements initialize, ping, tools/list and tools/call, single and batched.
Thirteen tools are exposed, generated from the same 17-entry runtime registry the in-product assistant uses. Ten of them are read-scoped. Three (build_pipeline, update_pipeline, deploy_pipeline) need a write key.
What it does not do:
- HTTP POST only.
GETandDELETEreturn 405. - No SSE streaming and no server notifications.
listChangedisfalse. - No MCP resources and no MCP prompts. Tools are the whole surface.
- Origin and Host headers are validated as DNS-rebind protection.
Start at MCP setup, then Tool reference.
Arrow Flight SQL
A read-only Flight SQL profile runs inside the server on a dedicated internal gRPC listener. Tenant scope comes from the credential, never from caller input: each tenant sees one catalog, its own slug as the only schema, and only its own active datasets as tables.
Two things to know before you plan around it. Results are transient, so there is no durable result id to hand to a colleague, and the port carries a Kubernetes network policy restricting it to Superset pods with no public ingress. Embedded Superset is the only client wired up today. Details on Arrow Flight SQL.
REST API
The JSON API under /api/* covers ingestion and connector traffic. The browser API under /web/-/* is same-origin, authenticated with a session cookie plus X-CSRF-Token, and is what the web app itself calls.
The REST reference is generated from the server's OpenAPI spec rather than written by hand, so it tracks the code. API keys do not authenticate it. They authenticate /mcp and nothing else.