MCP server
The Deploys.app MCP server exposes the whole API to AI assistants like Claude. Ask in plain language — “list my projects”, “deploy this image”, “what’s my bill this month” — and the assistant finds the right action and runs it as you.
What it is#
MCP (Model Context Protocol) is the standard way to give an AI assistant tools. The Deploys.app MCP server is a bridge between an assistant — Claude Desktop, Claude Code, or any MCP client — and the Deploys.app API.
It exposes every user-facing action through a search + execute pair, so the ~90 API actions never flood the model’s context: the assistant searches for the action it needs, reads its input schema, then runs it on your behalf. It is the same backend the console and CLI use, so it can only do what your identity is allowed to do.
There are two ways to connect. Most people want the first.
Connect with OAuth (recommended)#
No download, no secret to manage — you log in through the browser and the assistant acts as your account.
Claude Code:
# add it to the current project (default scope)
claude mcp add --transport http deploys https://mcp.deploys.app/
# …or make it available in every project on your machine
claude mcp add --transport http --scope user deploys https://mcp.deploys.app/
The first time the assistant uses it, a browser window opens for you to sign in
to Deploys.app. After that the connection is remembered. Use claude mcp list
to check which servers are configured in the current scope.
Claude Desktop: Settings → Connectors → Add custom connector → set the
URL to https://mcp.deploys.app/ and complete the sign-in.
Confirm it’s connected:
claude mcp list # deploys ✓ connected
Connect with a service account (local)#
For CI, headless, or offline use — or when you want the assistant to act as a service account rather than as you — run the server locally and authenticate with a key.
Download a prebuilt binary (no Go toolchain needed):
| Platform | File |
|---|---|
| macOS (Apple silicon) | deploys-mcp-darwin-arm64 |
| macOS (Intel) | deploys-mcp-darwin-amd64 |
| Linux | deploys-mcp-linux-amd64 / deploys-mcp-linux-arm64 |
| Windows | deploys-mcp-windows-amd64.exe |
curl -fsSL https://dl.deploys.app/mcp/latest/deploys-mcp-darwin-arm64 -o deploys-mcp
chmod +x deploys-mcp
Register it with Claude Code, passing the service-account credentials as env:
claude mcp add deploys \
-e DEPLOYS_SA_EMAIL='ci@acme.serviceaccount.deploys.app' \
-e DEPLOYS_SA_SECRET='…the key…' \
-- /absolute/path/to/deploys-mcp
Add --scope user here too to make it available in every project rather than
just the current one.
Or in the Claude Desktop config (claude_desktop_config.json):
{
"mcpServers": {
"deploys": {
"command": "/absolute/path/to/deploys-mcp",
"env": {
"DEPLOYS_SA_EMAIL": "ci@acme.serviceaccount.deploys.app",
"DEPLOYS_SA_SECRET": "…the key…"
}
}
}
}
DEPLOYS_API_KEY="<email>:<secret>" works as a single-variable alternative, and
DEPLOYS_ENDPOINT overrides the API base URL (mainly for staging).
How it works#
The server exposes exactly two tools:
| Tool | Purpose |
|---|---|
deploys_search_actions | Find actions by intent. Returns matching action ids, descriptions, whether each is read-only or destructive, and the JSON input schema for each. |
deploys_execute_action | Run an action by id with a parameters object. Returns the API’s JSON result. |
You don’t call these yourself — you just talk to the assistant. It searches for the action, reads the schema, fills in the parameters, and executes. Actions that change or delete things are flagged destructive so the assistant treats them with care and confirms before running.
Examples#
Ask in natural language; the assistant maps it to an action:
| You say | Action it runs |
|---|---|
| “list my projects” | project.list |
“show deployments in acme” | deployment.list |
“deploy ghcr.io/acme/web:v2 to acme as service web” | deployment.deploy |
“roll web back to the previous revision” | deployment.rollback |
“what’s the usage report for acme this month?” | billing.report |
“add the domain app.acme.com to acme” | domain.create |
“pause the worker deployment in acme” | deployment.pause |
“restart web in acme” | deployment.restart |
A typical exchange:
You: show deployments in acme
Claude: (searches → deployment.list → executes)
6 deployments, all healthy — web services, a couple of cron
jobs, and a background worker. Want details on any one?
Recipes#
Diagnose a failing deploy#
When a deployment.deploy comes back with a status that isn’t Success, the
assistant can close the loop itself — observe, then read the cause:
You: I deployed web to acme but it's not coming up. What's wrong?
Claude: (deployment.status → sees ready:0, waitingReason CrashLoopBackOff)
All 3 pods are crash-looping (CrashLoopBackOff, 7 restarts).
(deployment.logs with previous:true → reads the crashed container)
The previous container panicked on startup:
panic: missing env DATABASE_URL
Add DATABASE_URL to the deployment's env and redeploy.
The two actions behind this:
deployment.statusreturns pod counts plus each non-ready pod’s raw failure reason (CrashLoopBackOff,ImagePullBackOff,OOMKilled, exit code) in one call.deployment.logsreturns a bounded snapshot of recent live container output; withprevious: trueit reads the last crashed container, which is where aCrashLoopBackOff’s panic or stack trace lives.deployment.logsHistoryreturns the durable 30-day captured history over asince/untilwindow — oldest-first, or newest-first withreverse: true, paged with the opaquecursor. Reach for it when the pod is already gone and live logs have nothing left to read (available only where the location has a log bucket configured). It reuses the samedeployment.logspermission.
All three are read-only and return once (no streaming). See
Monitoring & debugging
for the contract and the deployment.logs permission split.
For triaging recurring crashes, error.list and error.get pull up the
deployment’s grouped, deduplicated error issues — each with an occurrence count
and a representative stack — so the assistant can read what’s been throwing without
scrolling raw logs, and error.create lets it report an error directly. See
application error detection.
Ship a throwaway preview#
To iterate on a static site or a container without touching production, spin an
ephemeral preview that cleans itself up. deployment.deploy with a ttl
(seconds) creates a deployment that auto-deletes when the window expires:
You: Build a preview of the new landing page.
Claude: (deploys_publish_site, environment "preview" → site://…@<sha>)
(deployment.deploy type:Static, site:…, ttl:7200 → landing-preview)
(deployment.get → url + releaseUrl)
Preview is live: https://landing-preview-….deploys.app (rolling — always the latest build)
This exact build: https://landing-preview-<sha8>-….deploys.app (immutable; expires in 2h)
You: Looks good — keep it up while I show the team.
Claude: (deployment.extendTTL ttl:7200 → re-stamps the window to now + 2h)
The pieces:
deployment.deploywithttlturns any deploy into a self-deleting preview; omitttlfor a normal deployment. Publish with a non-production environment so the release is servedX-Robots-Tag: noindex.deployment.getreturnsurl(rolling, always the current build) and — for static deployments —releaseUrl(immutable, pinned to that exact build), plusexpiresAtso the assistant can see (and reap) what’s near expiry.deployment.extendTTLre-stamps the window (expires_at = now + ttl) without redeploying — the keep-alive for a long session.deployment.deletedrops it early.
Container previews get a rolling url only; the immutable releaseUrl is
static-only (containers have no content-addressed release). Preview URLs are
public and unlisted. See
static sites → preview deployments.
Permissions & safety#
- It acts as an identity you control. Over OAuth it’s your account; locally it’s the service account whose key you provided. Either way it’s the same authentication and IAM roles as the console and CLI — the assistant can never exceed what that identity is permitted to do.
- Scope the service account. For the local mode, grant the service account only the roles it needs, the same as you would for CI.
- Destructive actions are labelled. Each action advertises a read-only or destructive hint, so deletes, pauses, and rollbacks are gated rather than run blindly.
See also#
- The deploys CLI — the same API from the terminal
- Service accounts — credentials for the local mode
- API overview — the underlying actions