lathe

API and MCP

Everything the portal does, from code or from an AI agent. Same rules, same checks, same jobs.

API keys

One credential for both the REST API and the MCP server.

Sign in, then create a key on the Account page. A key acts as the customer who created it and cannot create or revoke other keys. Send it on every request:

Authorization: Bearer lathe_…

MCP server

Streamable HTTP · https://mcp.lathe.live/mcp

Claude.ai and other clients that sign you in

Settings → Connectors → Add custom connector: name it Lathe, paste the URL above, keep Requires sign-in on and leave the client id and secret blank (the server registers the client itself). Claude sends you here to sign in with your email link and approve access; the app then appears under Connected apps, where you can disconnect it.

https://mcp.lathe.live/mcp

Clients that take a header

Give the agent the endpoint and an API key. Claude Code (which can also sign in: add it without the header, then run /mcp):

claude mcp add --transport http lathe https://mcp.lathe.live/mcp --header "Authorization: Bearer lathe_…"

Claude Desktop, Cursor and most other clients take a JSON entry of this shape:

{
  "mcpServers": {
    "lathe": {
      "type": "http",
      "url": "https://mcp.lathe.live/mcp",
      "headers": { "Authorization": "Bearer lathe_…" }
    }
  }
}

Tools

ToolWhat it does
list_plans readPlans with prices (USD per month), hardware, price per GB, and the locations an instance can be created in.
get_account readThe account behind this key: email, profile (name, company, tax id, address), card on file, and whether another instance can be created now (new accounts run one instance until their first renewal).
update_accountUpdate the profile that goes on receipts. Omitted fields keep their value; the name is required before the first purchase.
get_billing readSubscriptions (status, tier, next charge, trial_ends_at while a trial has not been charged yet) and the charge history.
list_instances readThe customer's instances with status, tier, location, tags, billing status and any job in progress. No secrets: use get_connection_urls for those.
get_instance readOne instance in full: status (awaiting_payment / pending / creating / running / …), billing, disk and connection usage, 24h monitoring (load, memory, disk, database size, TPS, cache hit, long queries), backups, recent activity, upgrade options and the pending job if any.
get_connection_urls readConnection strings for an instance, password included: direct (5432) and pooled (6432, transaction pooling). Handle as a secret.
create_instanceCreate an instance on a plan (mini | starter | plus | pro). This costs money: a paid plan returns checkout_url, which the person must open in a browser and pay - the instance is created when the payment page returns, and the returned instance_id is valid from the start (poll get_instance). A coupon that covers the whole first month creates it immediately. Where list_plans reports a trial, a customer's first Mini answers trial=true: with trial.card 'later' it is created at once with no checkout (a card added on the portal keeps it past the trial); with 'start' checkout_url verifies the card and nothing is charged until the trial ends. Optional: name (a label), tags (lowercase tokens), location (from list_plans), coupon, engines (names from list_plans; default Postgres alone).
update_instanceRename or retag an instance. Omitted fields keep their value; an empty name or an empty tag list clears it. Allowed while a job is running.
configure_enginesSet which engines run on the box and their memory budgets in MB: {name: {memory_mb}} for every engine wanted (omit memory_mb to split what is left). The plan's budget and each engine's floor are in list_plans. An engine restarts if its budget changes. An engine left out is stopped with its data kept on disk; at least one engine stays on.
set_allowlistReplace the IP allowlist for ports 5432 and 6432 with a list of CIDRs. An empty list opens the instance to the internet (TLS and password still required). Takes effect within a minute.
configure_engine_settingsSet one engine's settings (keys, bounds and defaults are in list_plans under engines[name].settings): e.g. Postgres statement_timeout_ms and timezone, Redis maxmemory_policy, NATS max_payload_mb. The engine restarts or reloads.
restart_engineRestart one engine on the box; the others are untouched. Connections to it drop for a few seconds.
reset_engine destructiveWipe one engine's data and start it empty (an undo snapshot is kept 7 days); the other engines keep running. confirm must be the instance id.
list_databases readThe databases on an engine: postgres (size, connections) or couchdb (documents, size).
create_databaseCreate a database on postgres or couchdb (lowercase letters, digits, underscores).
drop_database destructiveDrop a database on postgres or couchdb. confirm must be the database's name. Data is gone (the instance's daily backups remain).
list_extensions readPostgres extensions installed in a database and the ones this instance offers (pgvector, pg_trgm, pgcrypto, …).
set_extensionInstall (installed=true) or remove a Postgres extension in a database, from the offered list.
redis_consoleSwitch the Redis console off, ro or rw. redis_keys / redis_key / redis_command need it on; rw allows writes.
redis_keys readScan Redis keys matching a glob (type, TTL, size), 50 at a time; pass the returned cursor to continue.
redis_key readOne Redis key's value (up to 200 members of a collection).
redis_commandRun one Redis command line on the instance (read-only commands unless the console is rw; server management never).
list_streams readJetStream streams on the NATS engine: subjects, messages, bytes, consumers.
create_streamCreate a JetStream stream: name, subjects (e.g. ['orders.>']), retention limits|interest|workqueue, storage file|memory, max_bytes (-1 = none).
purge_stream destructivePurge every message from a stream. confirm must be the stream's name.
delete_stream destructiveDelete a stream and its messages. confirm must be the stream's name.
rotate_passwordIssue a new password for one engine (engine = postgres, redis, …) or for every engine on the box (omit engine). The old connection URLs stop working immediately; the new ones come from get_connection_urls once the job is done.
set_sql_consoleTurn the browser SQL console (reachable only through the portal) off, read-only (ro) or read-write (rw). The console is connected to one database: pass `database` to open it there (default: the owner database).
upgrade_instanceMove an instance to a higher plan. The prorated difference for the rest of the billing period is charged to the card on file now; expect 5-10 minutes of downtime. Plans move up only.
list_backups readDaily backups (newest first) and undo snapshots that can be restored in place.
restore_backup destructiveRestore a backup or undo snapshot in place: the current data is replaced (a snapshot of it is kept 7 days). Same address, so connection strings keep working. confirm must be the instance id.
reset_instance destructiveWipe every engine's data and start empty (a snapshot is kept 7 days). confirm must be the instance id.
delete_instance destructiveDelete an instance: billing stops, the VM and its backups are destroyed, a final snapshot is kept 7 days. confirm must be the instance id.
get_job readA queued, running or finished operation on one of the customer's instances: kind, status (queued / running / done / error) and the error's first line if it failed.

Creating an instance costs money: for a paid plan the tool returns a checkout URL that a person opens and pays (on a trial plan it verifies the card and the trial starts); the instance is provisioned when the payment page returns. Destructive tools take confirm, the instance id typed exactly, like the portal.

Webhooks

Every event about your instances, posted to an https URL of yours. Add endpoints on the Account page or with POST /webhooks.

Each delivery is a POST with a JSON body {"id", "type", "instance_id", "at", "data"} and three headers: X-Lathe-Event (the type), X-Lathe-Delivery (an id, the same on every retry) and X-Lathe-Signature - sha256= followed by the hex HMAC-SHA256 of the raw body with the endpoint's secret. Verify the signature before trusting the body. Answer any 2xx within 10 seconds; anything else is retried after 1 minute, 5, 30, 2 hours and 12 hours, then given up. An endpoint that fails 20 deliveries in a row is disabled until you enable it again.

Types you will see: created ready allowlist label resize reset restore rotate console engines engine_settings health_alert health_reset verify_ok verify_failed job_failed pg_database_created pg_database_dropped couch_database_created couch_database_deleted nats_stream_created nats_stream_purged nats_stream_deleted api_key_created api_key_revoked oauth_granted oauth_disconnected. New types appear as features do; ignore what you do not know.

REST API

Base URL https://app.lathe.live/api/v1 · interactive docs · OpenAPI

curl -H "Authorization: Bearer lathe_…" https://app.lathe.live/api/v1/instances
curl -H "Authorization: Bearer lathe_…" https://app.lathe.live/api/v1/instances/ID/connection
curl -X POST -H "Authorization: Bearer lathe_…" -H "Content-Type: application/json" \
  -d '{"tier": "starter", "name": "acme-prod", "tags": ["prod"]}' https://app.lathe.live/api/v1/instances
Method and pathPurpose
GET /me · PATCH /meThe account and its profile (what goes on receipts).
GET /plans · GET /locationsPlans, prices, hardware, locations.
GET /instances · POST /instancesList; create (returns checkout_url for a paid plan).
GET /instances/{id} · PATCH · DELETE ?confirm=Status, usage, monitoring, backups, activity; rename and retag; delete.
GET /instances/{id}/connectionConnection strings, password included.
GET /instances/{id}/backupsDaily backups and undo snapshots.
PUT /instances/{id}/allowlist · PUT …/sql-consoleIP allowlist; SQL console off / ro / rw.
PUT /instances/{id}/enginesThe engines on the box (any subset of Postgres, Redis, CouchDB and NATS) and their memory budgets; GET /plans lists each engine's floor, port, category and licence.
POST /instances/{id}/actions/rotate | resize | reset | restoreQueue an operation; answers 202 with a job id.
GET /jobs/{id} · GET /billingA job's progress; subscriptions and charges.

Errors are JSON: {"detail": "…", "code": "…"}. One job runs per instance at a time; a busy instance answers 409. Reset, restore and delete need confirm = the instance id.

Are you sure?

Type to confirm