Skip to content

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.

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.

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.

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_..." }
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.

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.

  • Reads never create anything; a read on a project without the relevant service answers qube_not_installed instead 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.
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": "..."}.

  • Protected-resource metadata: https://cloudqube.eu/.well-known/oauth-protected-resource
  • Authorization server: https://cloudqube.eu/oauth (dynamic client registration, PKCE)