Connect an AI agent
CloudQube exposes the same primitives your dashboard uses to AI agents: an
MCP server at https://cloudqube.eu/mcp and a REST API at
https://cloudqube.eu/agent/v1. An agent acts under an agent key you
mint, and every key carries a policy: which projects it acts on, how many
projects it may create, and which actions must wait for your approval. You stay the accountable owner, and the agent works with
its own scoped credential instead of your login.
Which projects a key acts on
Section titled “Which projects a key acts on”A key is either pinned to one project or scoped to all your
projects. Pinning works in both directions. A pinned key can’t see or
touch your other projects, and it can’t create new ones either, because a project it created would fall outside its own scope and be
invisible to it the moment it existed. project.create on a pinned key
answers project_scope_pinned.
So “how many projects it may create” is a setting on all-projects keys only. Pin a key when the agent works on something that already exists; scope it to all your projects when you want it to bootstrap its own.
A new account is held to one key per project and one agent-created project
in total, whichever keys it mints. Those bounds lift on their own once the
account has a settled payment older than the card-dispute window and no
chargeback; policy.status shows the tier and the headroom.
Two ways to connect
Section titled “Two ways to connect”By URL (OAuth)
Section titled “By URL (OAuth)”Add the server and let the client sign you in: it discovers our authorization server, opens the CloudQube login, and shows a consent screen where you pick an existing key or create one with the safe defaults. Tokens last an hour and refresh on their own; revoking the key ends them at the next call.
With a key (bearer)
Section titled “With a key (bearer)”Mint a key under Account → Agents (it is shown once) and pass it as a header. Any streamable-HTTP client works this way, and the REST API takes the same bearer key.
Mistral is the European option: Le Chat and the Vibe CLI both speak MCP.
In Le Chat or Mistral Work you connect by URL. Open Connectors, click + Add
Connector, switch to Custom MCP Connector, set the server URL to
https://cloudqube.eu/mcp, and click Connect. Le Chat detects OAuth
2.1 and walks you through the CloudQube consent screen. Adding a
connector is an administrator action; on Free, Pro and Student plans the
account owner is the administrator.
The Vibe CLI connects with a key, because Vibe doesn’t do OAuth for MCP
servers yet. Add this to ~/.vibe/config.toml:
[[mcp_servers]]name = "cloudqube"transport = "streamable-http"url = "https://cloudqube.eu/mcp"headers = { "Authorization" = "Bearer cq_ak_..." }By URL:
claude mcp add --transport http cloudqube https://cloudqube.eu/mcpWith a key:
claude mcp add --transport http cloudqube https://cloudqube.eu/mcp \ --header "Authorization: Bearer cq_ak_..."Cursor reads ~/.cursor/mcp.json (or .cursor/mcp.json in the project):
{ "mcpServers": { "cloudqube": { "url": "https://cloudqube.eu/mcp", "headers": { "Authorization": "Bearer cq_ak_..." } } }}VS Code reads .vscode/mcp.json:
{ "servers": { "cloudqube": { "type": "http", "url": "https://cloudqube.eu/mcp", "headers": { "Authorization": "Bearer cq_ak_..." } } }}Leave out headers to sign in by URL instead.
Any MCP client that supports streamable HTTP: server URL
https://cloudqube.eu/mcp, and either its OAuth option or an
Authorization: Bearer cq_ak_... header. The MCP Inspector works the
same way for trying things out.
What an agent can do
Section titled “What an agent can do”| Tool | What it does | Default mode |
|---|---|---|
policy.status |
every cap that applies to the key, in one call | read |
project.list / project.get / project.create / project.delete |
your projects; delete asks you first | create allowed on an all-projects key, refused on a pinned one; delete asks |
domain.search |
availability and price for up to 10 names | read |
domain.register |
buy a domain into a project at the price domain.search showed; approving is where you pay, from your domain credit or at checkout |
asks you first |
domain.set_autorenew |
turn our renewal of the domain on or off; the same setting as the dashboard toggle | allowed |
dns.list_records / dns.set_record / dns.delete_record |
records on the project’s domain | allowed; on a new account MX, TXT, NS and CAA changes ask first |
mailbox.create / mailbox.status |
a receiving mailbox on the domain, records set automatically | allowed |
mail.send |
send from the project’s mailbox, inside the project’s monthly quota | allowed |
site.deploy / site.status |
deploy a static site from inline files (MCP) or a zip (REST); spa_routing switches single-page-app routing on or off; the bare domain forwards to the site |
first deploy per project asks |
qube.catalog / qube.install / qube.uninstall |
the services the account can add (analytics, monitoring, email, a static site, and so on), add one to a project, remove one | catalogue is read; install allowed; uninstall asks you first |
actions.list / actions.get |
what the key did, and the state of anything that parked | read |
Modes are per key and per tool: allow, confirm (parks for your
approval) or deny (absent from the tool list). No key can delete a DNS
zone. domain.register is always confirm: you cannot set it to
allow, because your approval is your consent as the registrant of record.
The only choice on that tool is confirm or deny, and the mint screen asks it
that way: whether the key may buy domains at all. A key that may buy still
asks you for every purchase. If a name looks like a well-known brand, the
approval screen warns you, and you should only approve it if you hold the
rights to that name.
Names under .it and .es need a declaration only you can make, so agents
cannot order them; register those from the dashboard.
Approvals and money
Section titled “Approvals and money”A call that needs you returns pending_approval with an action_id
straight away, so the agent isn’t left hanging on the call. You get an email and see it under Account →
Approvals with the exact arguments; approve or deny, and the agent picks up
the result through actions.get or the webhook you set on the key.
Approvals expire after 72 hours.
Money moves only when you approve. A domain purchase waits for you, and
approving it is the payment: from your domain credit when it covers the
price, otherwise on a checkout page the approval sends you to; the price
shown is before VAT, and the request says what will be charged. Keys don’t
carry a spending limit of their own, because the only things an agent can buy are domains,
which always wait for your approval, and projects, which count against the
key’s project allowance. New accounts also have a monthly ceiling across all
their keys, shown by policy.status. The account also has domain-order limits (how much
can be outstanding inside the card-dispute window, and how many orders per
day and per month); an order over them fails with order_limit and the
limits rise as the account builds a payment history. Before billing is set up
a key can still do everything that doesn’t cost money, like changing DNS
records and deploying a site. The registrar call runs once the payment
has settled, and actions.get reports order_status and the expiry date
once it has. A held request carries approval_url, the page where you
decide it.
Every mutating call takes an idempotency_key; repeating one returns the
original outcome, so a retry never charges or creates twice.
Safety rails
Section titled “Safety rails”- Reads never create anything; a read on a project without the relevant
service answers
qube_not_installedinstead of installing it. - A key freezes automatically after a burst of failed calls or a chargeback on the account; frozen keys still read, and you unfreeze from the dashboard.
- Every call is one row in your activity feed with its arguments, outcome and cost. We also watch agent spending on our side, so a runaway agent gets noticed within the hour.
- Every domain is registered to your business profile. An agent can’t supply registrant details of its own.
REST equivalents
Section titled “REST equivalents”| MCP | REST |
|---|---|
project.create |
POST /agent/v1/projects |
domain.search |
GET /agent/v1/domains/search?project_id=…&names=a.eu,b.nl |
domain.register |
POST /agent/v1/domains |
dns.set_record |
PUT /agent/v1/dns/records |
mailbox.create |
POST /agent/v1/mailboxes |
mail.send |
POST /agent/v1/mail/send |
site.deploy |
POST /agent/v1/sites/deploy (multipart zip) |
policy.status |
GET /agent/v1/policy |
actions.get |
GET /agent/v1/actions/{id} |
Writes take an Idempotency-Key header and answer 202 when parked.
Every error comes back in the same shape, for example
{"error": "over_cap", "message": "..."}.
Discovery
Section titled “Discovery”- Protected-resource metadata:
https://cloudqube.eu/.well-known/oauth-protected-resource - Authorization server:
https://cloudqube.eu/oauth(dynamic client registration, PKCE)