From a repository to production
Four steps, about ten minutes, and you end up with a web service, a Postgres database, managed auth, a storage bucket and a custom domain on a certificate.
The same four steps are shown twice below: once as CLI commands for a person at a terminal, once as MCP tool calls for an agent. They are the same operations. Nothing is available to one and not the other.
01
Create the Product
Point Helm7 at a repository. It inspects it and proposes a shape.
02
Add the state
Postgres, managed auth and a bucket, each one call.
03
Deploy
Build the current commit and swap traffic once health checks pass.
04
Attach the domain
Create one DNS record and the certificate issues itself.
Before you start
You need a git repository the platform can read, and somewhere to run it. A Product runs in one region, and there are two today: eu-central is Falkenstein and eu-north is Helsinki. There is no US region yet, so pick the one closer to your users and know that neither of them is close to North America.
You do not need an account to try this. An agent can call cloud_init and get a temporary workspace with a scoped key, no email and no card. See for agent operators.
The CLI path
The CLI is not published to a registry yet, so it runs from the repository. Nothing about the API needs it: every command below has an HTTP equivalent, and an agent should use that rather than shelling out.
Identify yourself
whoami is worth the one call. It returns the organisation, the member your key speaks as, its scopes, its capability flags and, for an agent key, its remaining budget and expiry. A key can never exceed what that member can do, so this is your real ceiling.
1. Create the Product
Plan it first. Every mutating command takes --dry-run, which changes nothing and costs nothing.
- create productAcme eu-central
- create environmentproduction
Inside the $12 Builder minimum, so that is the bill. Largest cost: nothing billable.
Read the plan, then apply it
2. Add the state
Postgres sets DATABASE_URL on the environment for you. Auth is GoTrue-compatible and storage is Supabase-Storage-compatible, so an application already written against supabase-js works with a changed URL and key.
Secret values are encrypted at rest and are never returned by any endpoint, including the one that sets them. secret_list gives you names and fingerprints and nothing else.
Storage buckets have no command yet. Create one over the API or MCP with storage_create_bucket; the CLI covers what people reach for at a terminal and is smaller than the full surface.
3. Deploy
Traffic swaps only once health checks pass, and the previous deployment is kept. If the new one is wrong, helm7 rollback dep_... is a traffic swap and takes seconds. It does not revert database migrations, so if the deployment changed the schema, undo that yourself first.
4. Attach the domain
The domain reads as pending until the DNS record resolves. That is not an error. The certificate issues on its own once it does, usually within a minute.
The MCP path
Same operations, same names, same plans. Point your client at the MCP server and give it a key. The tool list it sees is whatever that key is allowed to use, so a narrow key is also a shorter prompt.
To sign in with your browser instead, run claude mcp add --transport http helm7 https://www.helm7.com/mcp and choose Authenticate. Approving the connection gives the client a key with your own permissions, which you can revoke from the keys page. There are no refresh tokens: the key lasts until you revoke it.
{
"mcpServers": {
"helm7": {
"url": "https://www.helm7.com/mcp",
"headers": { "Authorization": "Bearer hlm_sk_..." }
}
}
}whoami {}
product_create {
"name": "Acme",
"repo": "https://github.com/acme/acme-app",
"region": "eu-central",
"dry_run": true
}
product_create {
"name": "Acme",
"repo": "https://github.com/acme/acme-app",
"region": "eu-central",
"idempotency_key": "acme-first-run"
}
database_create {
"productId": "prd_7k2m9x4qw1nv8bz3ct6d",
"environment": "production",
"extensions": ["pgvector"]
}
auth_enable {
"productId": "prd_7k2m9x4qw1nv8bz3ct6d",
"providers": ["email", "google"]
}
storage_create_bucket {
"productId": "prd_7k2m9x4qw1nv8bz3ct6d",
"name": "uploads"
}
deploy {
"productId": "prd_7k2m9x4qw1nv8bz3ct6d",
"environment": "production"
}
domain_attach {
"productId": "prd_7k2m9x4qw1nv8bz3ct6d",
"hostname": "acme.com"
}Plan first, always
dry_run returns the changes, the monthly cost and anything irreversible. It is free and has no side effects, so there is no reason to skip it on a change you have not made before.
Use an idempotency key
Replaying the same key returns the original result rather than acting twice. Worth it on anything that creates a resource or spends money.
Expect refusals to be useful
A destructive call without confirm returns the plan and refuses. Errors carry a stable code and a remedy. Branch on the code, never on the message.
When it goes wrong
The build failed
deployment_get extracts the specific reason rather than leaving you to find it in a log tail. If detection picked the wrong build, override it on the service instead of fighting the detector.
The app starts and then dies
service_logs gives you stdout and stderr. Secrets are redacted on a best-effort basis before logs leave the platform, which is a safety net and not a guarantee, so do not deliberately print them.
The domain says pending
The DNS record has not resolved yet. domain_list shows the record it expects. Nothing is broken until the record is right and it is still pending an hour later.
Something else
Email [email protected] with the request_id from the error. Every failure carries one.
Next
- Every CLI commandThe full reference, generated from the same definitions.
- The REST APIInputs, scopes and which calls cannot be undone.
