midplane local runs the gateway with no Midplane Cloud: each database’s
policy is in midplane.yaml, and tokens are signed with a key you make. Use it
offline, to try Midplane (quickstart), or
when you don’t want a hosted control plane.
What it doesn’t have: approvals (a held write is refused, with a pointer to
linking the gateway), a dashboard, and taint shared between instances (each
gateway keeps taint in its audit file).
Keys and tokens
midplane-signing-key.json (private: keep it secret, it mints tokens)
and midplane-verify-key.json (public: auth.public_key_file names it). It
won’t overwrite either.
--sub), for one database or all of them,
read by default, valid for an hour by default. Each token is its own grant:
taint recorded for it doesn’t follow its person to another token. A token
whose id is in auth.revoked_token_ids is refused.
Serving
Authorization: Bearer <token>:
MIDPLANE_TOKEN; it is verified at start and again on every call, so an
expired token stops working without a restart. Logs go to stderr, since
stdout carries MCP. Each session starts a gateway of its own; with one
config they share its audit file, as one chain, and the taint it keeps.
Stdio keeps an agent out only if it has no shell or file access: the
gateway’s secrets (the DSN, the salt, the token) sit in the agent’s MCP
config, and the gateway runs as the agent’s own user. Beyond a demo, serve
over HTTP, with the gateway running as another user or on another host.
What an agent can call
Four tools:query (one statement, with an optional intent, the agent’s
reason), list_tables, describe_table, and check_approval (which, in
local mode, says approvals need a linked gateway).
Tested by apps/gateway/test/cli.e2e.test.ts (keygen, token, stdio) and
apps/gateway/test/gateway.e2e.test.ts (local mode end to end).