Это руководство пока доступно только на английском.

MCP tool reference

What it's for

The complete list of what an AI agent connected to DADA Cloud can actually do: every tool the MCP server exposes, what each one takes, whether it changes anything, and what it returns. Use it when you want to know if a task is possible before you ask an agent to try, or when you are writing your own client against the server.

Setup lives in Control DADA Cloud from an AI agent (MCP). Worked end-to-end flows live in MCP recipes.

The surface: 41 tools

The server is generated by reflection over the platform's own REST API and then cut down by an allowlist, so a tool exists here only if it was deliberately chosen. That is why the number is 41 and not the 216 operations the API has. Anything not on this page is not reachable from an agent — the last section explains what was left out and why.

Two flags come from the protocol itself and your client may show them:

  • read-only — the tool cannot change anything. All 20 list* / get* tools are read-only.
  • destructive — the tool removes something. Exactly two are: deleteBox and deleteEnvVar. Well-behaved clients ask you before running these.

Every other tool is a create or an update: additive, and (except extendBox) asynchronous.

How arguments work

All tools take one flat object. There are no nested paths, no request bodies to assemble — you pass projectId, name, image and so on at the top level and the server routes each one into the URL, the query string or the body.

Three argument names carry almost every call:

ArgumentWhat it isWhere you get it
projectIdProject UUID, not the slug you see in the console URLlistProjects
envIdEnvironment UUIDgetProject (or default_environment_id from createProject)
appNameApp name as a stringlistApps

projectId and envId are UUIDs even though the console shows you names. An agent that guesses "my-project" gets a 404. Start every session with listProjectsgetProject.

Async: what "Committed" means

Most mutations return HTTP 202 and an operation id rather than a finished result. The tool result says so explicitly, and the flow is always the same:

  1. Call the mutation. It returns an operation id.
  2. Poll getOperation until the status is terminal — Committed or Failed.
  3. Committed does not mean running. It means the desired state was written. Poll listApps until the app's phase is Healthy to know it actually came up.

If the phase never reaches Healthy, searchLogs is the next call.

extendBox is the only synchronous mutation (it moves a timestamp). boxUp is also synchronous but for the opposite reason: it holds the request open until a command has actually run inside the box.

Projects and environments

ToolRequiredOptionalNotes
listProjectsread-only. Start here. Returns every project you are a member of with your role in each.
getProjectprojectIdread-only. Returns the project plus its environments, each with an id — the only way to obtain an envId for a project that already exists.
createProjectslugdisplay_name, org_id, default_environmentCreates the project and its first environment, and returns default_environment_id. slug must be DNS-label-safe and is unique platform-wide. Without org_id the project lands in your personal org.

Apps

An app is a container workload: an image plus a port. Everything else the platform assembles.

ToolRequiredOptionalNotes
listAppsprojectId, envIdread-only. Every app in the environment with its live phase. This is the tool that answers "did it come up".
createAppprojectId, envIdname, image, port, replicas, profile, framework, worker, volume, workload_typeAsync. For a cloud (container) environment image is required in practice and port/replicas/profile apply. For a VM environment the app deploys as a Compose stack onto the environment's app server, which must already be Ready.
updateAppImageprojectId, envId, appNameimageAsync. Rolls an existing app to a new image tag. This is how you deploy a new version of something already running.
updateAppStorageprojectId, envId, appNamepath, size, storage_classAsync. Attaches a shared persistent directory, or grows an existing one. Grow-only, and the storage class is fixed once created.

There is no deleteApp and no restartApp. Both omissions are deliberate: delete is destructive enough to belong in the console with a human in front of it, and restart is unnecessary because env and image changes reconcile on their own.

Environment variables

ToolRequiredOptionalNotes
listEnvVarsprojectId, envId, appNameread-only. Non-secret values come back in plaintext; secret values are masked, so an agent can see that a key exists without seeing what it holds.
setEnvVarprojectId, envId, appName, keyvalue, is_secret, scope, preview_overrideCreates or updates one key. The value is stored AES-GCM encrypted either way; is_secret controls whether it is ever readable back.
deleteEnvVarprojectId, envId, appName, keypreview_overridedestructive. Removes one key. With preview_override=true it removes only the preview-environment override and leaves the base variable alone.

Changes reconcile without a restart. There is no bulk-set tool on the agent surface — one key per call, which keeps a partial failure legible.

Databases

ToolRequiredOptionalNotes
listDatabasesprojectId, envIdread-only. Managed PostgreSQL instances in the environment with their live phase.
createDatabaseprojectId, envIdname, database, app_ref, backup_enabled, backup_schedule, backup_retentionAsync. Omit app_ref for a standalone environment-level database; set it to bind the database to an app.
getDatabaseCredentialsprojectId, envId, name, revealread-only, but reveal must be true and every reveal is written to the audit log. Returns host, port, database, username and password. Returns 404 while the database is still provisioning — that is "not ready yet", not "does not exist".

Git repositories and builds

The path from a repository to a running app.

ToolRequiredOptionalNotes
getGitInstallUrlprojectId, providerread-only. Returns the URL a human must open to grant repository access. An agent cannot install the app for you; it can only hand you the link.
listGitInstallationsprojectIdread-only. Which GitHub/GitLab installations the project's org already has.
listInstallationReposprojectId, installationIdread-only. Repositories a given installation can see.
connectGitRepoprojectId, envIdrepo_full_name, clone_url, installation_id, provider, production_branch, auto_deploy, app_name, root_dir, framework_override, port, replicas, profile, tokenLinks a repo to an app so pushes build and deploy. port/replicas/profile describe the app the first successful build will create (defaults 8080 / 2 / small). token is GitLab-only and is stored encrypted.
triggerBuildprojectId, envId, appNameQueues a build of the linked repo at its production branch HEAD. Builds are imperative: this returns the queued build, not an operation, so track it with getBuild rather than getOperation.
getBuildprojectId, buildIdread-only. One build by id.

Domains

ToolRequiredOptionalNotes
addDomainAuthorizationprojectIdapex_domainRegisters an apex you own (acme.com) and returns a TXT challenge to publish. Authorizing the apex covers its subdomains too.
verifyDomainAuthorizationprojectId, idForces the DNS check immediately instead of waiting for the next scheduled one.

Attaching a verified hostname to a specific app is not on the agent surface — finish that step in the console. See Custom domains and HTTPS.

Logs

ToolRequiredOptionalNotes
searchLogsprojectIdapp, vm, q, since, sizeread-only. One tool, both runtimes: pass app for a cloud app or vm for a VM/Compose app. At least one of the two is required and must belong to the project — that check is what stops one tenant reading another's logs. since accepts 15m, 1h, 6h, 24h, 7d (default 1h); size is 1-1000 (default 200); q is free text.

Operations

ToolRequiredOptionalNotes
getOperationprojectId, operationIdread-only. The state of one async operation. Poll after any 202 until Committed or Failed; on Failed, read the message.

App servers (VMs)

ToolRequiredOptionalNotes
listAppServersprojectIdread-only. Provisioned and connected VMs, newest first, excluding deleted ones.
createAppServerprojectIdname, mode, flavor, region, os_image, ssh_key_name, vm_ip, ssh_private_key, ssh_user, ssh_portAsync. mode=terraform (the default) provisions a new VM; mode=manual connects a VM you already have and needs vm_ip and ssh_private_key.

Boxes

A box is an ephemeral sandbox with root inside it — the shape an agent actually wants to work in. It owns exactly one environment, which is what every later attachment and hostname hangs off, and which crystallization promotes in place.

Getting a box

ToolRequiredOptionalNotes
getBoxCatalogread-only. The frozen catalog of warm images and size profiles. A size is only real if the pool controller has pre-warmed bodies of that shape, so read this rather than guessing a profile name.
boxUpprojectIdname, image, profile, region, ttl_seconds, session_ttl_hours, spend_cap_rub, ssh_public_key, wait_secondsSynchronous and the one to reach for. Returns only once a command has actually executed inside the box and succeeded — not when the API answered, not when a port accepted. The response carries the connection coordinates, a one-time dadabox_ session token (shown once, never retrievable), a ready-to-paste mcpServers snippet pointing at the box's own endpoint, and the measured time to ready by phase. wait_seconds is a bound in [0,120], not a hint: exceeding it returns a classified failure.
createBoxprojectIdname, image, profile, region, ttl_seconds, spend_cap_rub, ssh_public_keyAsync form of the same thing, for a caller that does not want to hold a request open. Poll the operation, then getBoxState for coordinates.
listBoxesprojectIdread-only. Every non-deleted box in the project, newest first.

ssh_public_key is the public half. The platform never holds your private key, which is why there is nothing to leak on our side.

ttl_seconds is when the box goes to sleep, not when it is destroyed. spend_cap_rub, when reached, suspends the box — deliberately: a runaway should cost the customer money, never their data.

Living with a box

ToolRequiredOptionalNotes
getBoxStateprojectId, boxNameread-only. Phase, the coordinates the runtime reported, the age of the newest sample, and whether the TTL has passed. Coordinates are empty until the box reports Ready.
getBoxConnectionprojectId, boxNamenew_sessionread-only. SSH and MCP coordinates plus the paste-ready mcpServers snippet. new_session=true mints a fresh one-time token; the old one is not revealed because only its hash is stored. Minting does not revoke — suspend or delete for that.
extendBoxprojectId, boxNamettl_secondsSynchronous. Pushes out the sleep time, measured from now, capped at 24 hours.
suspendBoxprojectId, boxNameAsync. Freezes the box: compute billing stops, the disk survives, resume brings the same box back. Not a delete.
resumeBoxprojectId, boxNamessh_public_keyAsync. Wakes it and waits for the exec channel to accept again — same disk, same injected credentials. Optionally rebinds a fresh key so you need not keep one alive across the sleep.
deleteBoxprojectId, boxNamedestructive, async. Destroys the sandbox and its disk. Resources attached to the box (databases, buckets) live outside it and survive. The name becomes reusable once deletion completes.
getBoxUsageprojectId, boxNamefrom, toread-only. Billed minutes and money for one box, straight from the per-minute ledger. Kinds are active and suspended_disk. Idle minutes are absent entirely — an idle minute writes no row, which is why an idle box reports zero rather than a small charge. Window defaults to the current calendar month and may not span more than 92 days.

Making a box useful

ToolRequiredOptionalNotes
attachBoxDatabaseprojectId, boxNamename, env_prefixProvisions a managed Postgres outside the box and injects the credential into the box's env file (mode 0600, root). The next command inside the box already sees DATABASE_URL. The database is not inside the box on purpose: deleting or crystallizing the box never destroys it. The response lists which env keys were injected, never their values. env_prefix lets one box hold two databases without collisions.
listBoxAttachmentsprojectId, boxNameread-only. What is attached and which env key names each one injected. Never values.
exposeBoxprojectId, boxNameportPublishes a port serving inside the box on a hostname the platform assigns under its wildcard. You cannot choose the hostname — custom domains are a crystallization feature, and a throwaway body with an arbitrary name is a phishing surface. Returns the hostname, the URL, and the measured time to the first real 200. Responses carry X-Robots-Tag: noindex.
crystallizeBoxprojectId, boxNameack_monthly_charge, app_server_name, domain, probe_pathPromotes the box's userland onto a real VM booted from a standard OS image: the VM keeps its own kernel and init, and the result runs under systemd — no Docker, no Compose, no agent, because a crystallized VM is not a container host. Then it is verified: file-manifest equality on (path, size, mode, sha256), the listening-socket set before and after, an sha256-per-key env comparison, and an end-to-end HTTP probe. Requires ack_monthly_charge — promotion turns a per-minute body into a monthly bill, so consent is a gate and the answer is 409 without it.
listBoxCrystallizationsprojectId, boxNameread-only. Every attempt with its stored verification report. verified is separate from status on purpose: an attempt can finish while verification failed.

What is deliberately not exposed

Knowing what an agent cannot do is as useful as knowing what it can.

  • No command execution inside a box, ever. There is no boxExec and there will not be one. Our MCP surface is control plane only. The box hands out its own local MCP endpoint, which you add to your client as a second server — so your code and your model credentials never traverse our API. A command tool here would route every keystroke of your work through us, which is the opposite of the promise.
  • No deleteApp, deleteDatabase, deleteProject, deleteAppServer. Deleting a customer's deployment is not an agent's job. deleteBox is the exception because ending a disposable body is the normal end of its life, and an agent that cannot release a box it created leaks paid capacity you pay for.
  • No account or billing tools beyond getBoxUsage. An agent needs to see what it has spent, not your whole account.
  • No admin, monitoring-config, model-serving, DNS-record or file-manager tools. They exist in the REST API; they are noise in a tool list an agent carries in its context on every turn.
  • No bulk env-var set and no revealEnvVar. One key per call, and secret values stay unreadable.

Everything omitted here is still available over the REST API with the same token, so nothing is locked away — it is just not in the agent's hands by default.

Self-hosting the full surface

The allowlist is a file. Mounting your own at MCP_OVERRIDES_PATH with an empty keep list exposes every operation the API has. That is supported for private deployments and not something we do on the hosted platform, for the reasons above.