DeployLane / MCP v0.8.0
Model Context Protocol · live

Let AI drive your DeployLane account.

A hosted MCP endpoint that gives Claude Code, Claude Desktop, Cursor and any other MCP‑capable client read or read/write access to the apps, servers and deploys attached to your DeployLane workspace. No SDKs to install, no glue to maintain.

Endpoint https://mcp.deploylane-c4ca.apps.deploylane.dev

01Quick start

Three steps from zero to chatting with your infra.

1

Generate a token

Open Settings → API access and click Generate token. Copy the value once — it’s shown only at creation.

2

Wire up your client

Add the endpoint and Bearer header to Claude Code, Claude Desktop or Cursor. One‑line CLI command or a small JSON snippet.

3

Ask in plain English

The model decides which tools to call. You describe what you want, not which API to hit.

02Install

Drop the endpoint into any MCP‑capable client. HTTP transport, Bearer auth, no SDK.

Add the server with one CLI call. Positional args come before the flags, otherwise the URL gets swallowed by --header.

terminal
claude mcp add deploylane https://mcp.deploylane-c4ca.apps.deploylane.dev \
  --transport http \
  --header "Authorization: Bearer mcp_..."

Verify it’s registered with claude mcp list — you should see deploylane alongside any other servers.

03Authentication & scopes

Every request other than GET /health must carry a Bearer token. Each token has a scope you can change later from the dashboard — the plaintext stays the same so connected clients keep working.

read

Read‑only

List + inspect apps, servers, deploys, logs, metrics. Safe default — hand to any AI client you want to give visibility without trusting it to act on your account.

  • list_*
  • get_app, get_recent_deploys, get_deploy_log
  • tail_logs, get_server_metrics, get_diagnose
write

Full access

Adds create / update / delete tools — provisioning new apps, setting env vars, managing cron jobs, triggering deploys. Only give to clients you trust to make changes.

  • create_app, add_web_route, set_env_vars
  • create_cron, update_cron, delete_cron
  • trigger_deploy
Tokens are per‑user and scoped

Every tool query is scoped to the owning user’s data and cannot see other accounts. Revoke a leaked token from the dashboard — it’s effective immediately.

04Tools · 30

Everything the AI can call. Tool names are namespaced deploylane.<name> in clients (the prefix is muted below for readability).

deploylane.list_servers
read cheap
List all Hetzner servers in this DeployLane account. Returns id, alias, ipv4, status, location, server_type.
deploylane.list_apps
read cheap
List all apps in this DeployLane account with their server alias, primary domain (custom or auto-assigned), and derived status. Use deploylane.get_app for a single-app deep dive.
deploylane.get_app
read cheap
Full snapshot of one app: server, routes, env var keys (no values), recent deploys. The go-to call for "tell me everything about this app".
deploylane.get_recent_deploys
read cheap
Deployment history for one app. Use to answer "which deploys failed today" / "how long did the last deploy take". Logs come from deploylane.get_deploy_log.
deploylane.get_deploy_log
read cheap
Full log text of a single deployment. Use after deploylane.get_recent_deploys to investigate a failure. Logs are capped at 256 KiB — truncation is flagged in the response.
deploylane.tail_logs
read expensive
Recent container stdout/stderr for an app — `docker compose logs --tail` over SSH. Useful for 'what is my app saying right now'.
deploylane.get_server_metrics
read expensive
Snapshot of a server: CPU %, memory %, disk %, uptime. Use for operational health checks.
deploylane.get_diagnose
read expensive
Quick health check for one app: DNS resolution, container state, recent Traefik error lines. Lightweight alternative to the dashboard's Diagnose tab — for the AI to triage 'something's wrong' questions.
deploylane.get_migration_guide
read cheap
Returns the full DeployLane migration guide as text — same content as the `make_deploylane_ready` MCP prompt. Use when your MCP client doesn't expose prompts, or when you want the AI to ingest the guide as a regular tool response.
deploylane.create_app
write expensive
Create a new app on one of your servers. Probes the GitHub repo for compose vs Dockerfile and validates an optional per-app PAT. Every app automatically gets a unique HTTPS auto-domain (<service>.<app>-<id>.apps.deploylane.dev) that goes live on the first deploy — no DNS setup needed. An optional `domain` adds a custom hostname alongside it. Use after deploylane.list_servers to pick a server.
deploylane.add_web_route
write expensive
Attach a custom domain to an existing app, in addition to its auto-domain. For multi-service apps, set `service_name` to the matching compose service. Aliases (redirect / additional) are optional. Traefik labels are picked up on the next deploy.
deploylane.set_env_vars
write expensive
Bulk-upsert env vars on an app. Default mode is additive (existing keys not in the call are left alone). To replace the full set, pass both `replace_all: true` AND `confirm_wipe: true` AND at least one entry — a safety guard against the AI accidentally wiping secrets. Values are encrypted at rest. Per-service vars supported via `service_name`. Returns only the key list; secret values are never echoed back.
deploylane.create_cron
write expensive
Schedule a recurring HTTP call from an app. The job runs in a one-shot curl container on the server's docker network, so URLs like http://<app-name>-app:3000/... reach the app directly. Header values are encrypted at rest. The host crontab is re-synced as part of this call.
deploylane.trigger_deploy
write expensive
Kick off a deploy for an app. Returns immediately with a `deployment_id` — the build runs in the background. Poll deploylane.get_deploy_log and deploylane.get_recent_deploys to track progress. Pass `commit_sha` for an exact pin, or `ref` for a branch/tag (defaults to the app's configured branch).
deploylane.list_crons
read cheap
List cron jobs configured for an app. Header VALUES are NOT returned (they may contain bearer tokens) — only `header_keys` is echoed. Pairs with create_cron / update_cron / delete_cron.
deploylane.get_cron_history
read expensive
Per-run history of an HTTP cron job, newest first, read from the host's JSONL run log. Each run includes ok, http_status, duration, curl_exit, response_excerpt, error and any webhook_error — enough to see why a scheduled call failed. Get the cron_id from deploylane.list_crons.
deploylane.list_backup_jobs
read cheap
List the pg_dump backup jobs configured for an app: schedule, enabled state, target Postgres service, and a snapshot of the last run (time/status/size). Discovery entrypoint — feed the returned `id` to get_backup_history or list_stored_backups. This is the scheduled snapshot backup, distinct from PITR (see get_pitr_status).
deploylane.get_backup_history
read expensive
Per-run history of a backup job, newest first, read from the host's JSONL run log. Each run includes status (success/failure/skipped), exit_code, duration, dump size, the S3 key, and `output_excerpt` — the tail of pg_dump/aws-cli stderr that explains a failure. Get the backup_job_id from deploylane.list_backup_jobs.
deploylane.list_stored_backups
read expensive
List the dump files actually stored in object storage for a backup job (key, size, last-modified), newest first. Reflects what is RETAINED right now — older dumps may have been expired by the bucket lifecycle rule. Complements get_backup_history (which reports run outcomes). Get the backup_job_id from deploylane.list_backup_jobs.
deploylane.get_pitr_status
read expensive
Point-in-time-recovery status for an app: enabled flag, stanza, mirrored last-base-backup outcome, and the LIVE recovery window (earliest/latest target time, WAL lag, healthy) from `pgbackrest info`. This is the continuous WAL-archiving backup system, distinct from the scheduled pg_dump jobs (see list_backup_jobs). Returns enabled:false when PITR was never turned on.
deploylane.delete_env_var
write expensive
Remove a single env var from an app. Idempotent — a missing row returns success. service_name follows the same scoping as set_env_vars: omit/null for the shared var, a string for that compose service's per-service var. Managed BLOB_* vars cannot be deleted here.
deploylane.remove_web_route
write expensive
Detach a custom domain from an app by deleting its web route row. Get the route_id from deploylane.get_app (under `routes`). Auto-domains are managed separately by DeployLane (not routes), so they are unaffected. Traefik labels refresh on the next deploy.
deploylane.delete_cron
write expensive
Delete a cron job and re-sync the host crontab so its wrapper script + crontab line are removed. Get the cron_id from deploylane.list_crons.
deploylane.update_cron
write expensive
Update fields of a cron job (any subset of: name, schedule, method, url, headers, webhook_url, webhook_method, webhook_headers, enabled, timeout_seconds). Header maps are FULL-REPLACE — pass `{}` to clear all headers. Pass `webhook_url: null` to clear the completion callback entirely. The host crontab is re-synced as part of this call.
deploylane.restart_app
write expensive
Bounce an app's container(s) without rebuilding — `docker compose restart` for compose apps, `docker restart` for the single-container fallback. Use when a process needs a kick. Does NOT pick up env var changes — for those, set_env_vars then trigger_deploy.
deploylane.prune_docker
write expensive
Reclaim docker disk space on a server: image / build-cache / stopped-container / unused-network prune for items older than 72h. VOLUMES ARE NEVER TOUCHED (they hold Postgres data and app uploads). Returns the freed MB. Pair with deploylane.get_disk_usage_report for the inspect → reclaim → inspect cycle.
deploylane.get_disk_usage_report
read expensive
Detailed disk-usage breakdown for a server: filesystem, docker disk usage by type, per-resource breakdown, top /var/lib/docker subdirs, and how much an aggressive prune would free. Read-only — nothing is removed. Useful for 'my server is filling up, where's it going?' triage.
deploylane.restart_traefik
write expensive
Restart the Traefik reverse-proxy container on a server. Useful when Traefik wedges on a failed Let's Encrypt attempt — restarting clears the ACME backoff. Brief ingress outage (~5s) for ALL apps on the server.
deploylane.reboot_server
write expensive
Reboot a Hetzner server (shutdown → wait → power-on). Takes EVERY app on this server offline for ~30-60s. REQUIRES confirm: true — the AI must opt in deliberately. Returns once power-on is accepted by Hetzner; poll deploylane.list_servers to see the status converge back to 'running'.
deploylane.rollback_app
write expensive
Roll an app back to a previous successful deployment. Returns a NEW deployment_id; the actual rollback runs in the background. Compose-mode apps get a full redeploy at the old SHA; dockerfile-mode apps get a fast image swap. Get the deployment_id from deploylane.get_recent_deploys — must be status='success'.

05Prompts & resources

Server‑hosted prompt templates the AI invokes directly. In Claude Code: /mcp__deploylane__<name>. Clients that don’t surface prompts can invoke the equivalent tool instead.

Prompts

make_deploylane_ready Make this repo DeployLane-ready

Walk the current repo through the DeployLane migration checklist: strip Vercel-specific bits, swap Neon/Vercel Blob for sibling Postgres + Hetzner S3, generate Dockerfile + docker-compose, finish with the env-vars + cron config the user needs to paste into the DeployLane UI.

Resources

deploylane://spec/v1 text/markdown

DeployLane app spec (v1) — Conventions a repo must follow to be deployable via DeployLane. Placeholder until the full spec lands.

06Example prompts

Real questions you can paste into your AI client. The model decides which tools to call and chains them together as needed — you stay in plain English.

“Give me a status of all my apps.”
“Which Hetzner servers do I have, and where are they?”
“Are any of my apps in a failed state?”
“Show me apps that haven’t been deployed in the last 30 days.”
“How many apps do I have per server?”

07Rate limits

Per‑token, sliding 60‑second windows. Hitting a limit returns a clean tool error with a retry_after_seconds hint — not an HTTP 429 — so your AI client can back off without breaking the conversation.

cheap
120 / min

Pure DB reads — list_*, get_app, get_recent_deploys, get_deploy_log, list_crons, get_migration_guide.

expensive
20 / min

Anything that SSHes into a server (tail_logs, get_server_metrics, get_diagnose) or mutates state. The cheap limit applies in addition.

cooldown
60 sec

Per‑app on trigger_deploy. Prevents parallel‑deploy storms from a runaway AI loop. Independent of deploy status.

Backoff hints, not HTTP 429

The MCP SDK has no concept of transport‑level retry semantics. AI clients DO read the error text — the rejected response includes a precise retry_after_seconds.

08FAQ

Open Settings → API access in the dashboard and click revoke on the token row. Effective immediately — the next request from that token fails auth.
Yes. Edit the token from the dashboard and change its scope. The plaintext stays the same so connected clients keep working without re-pasting.
MCP traffic uses POST to this same root path. The SDK’s StreamableHTTP transport in stateless mode never uses GET, so serving an HTML help page here is conflict-free.
It doesn’t. Read tools return only key names. Write tools accept new values but never echo them back. Values are encrypted at rest.
A backup job is a scheduled pg_dump snapshot uploaded to object storage — inspect its runs with get_backup_history and the stored files with list_stored_backups. PITR (point-in-time recovery) is continuous WAL archiving via pgbackrest that lets you restore to any moment in the retention window; check it with get_pitr_status. They are independent and an app can use either or both.