# ShipDapp MCP — Full Reference > Complete documentation for AI agents connecting to the ShipDapp Model Context Protocol server. Version 0.2.0. ShipDapp deploys web applications to Akash Network (devnet). The MCP server handles cloud builds (Google Cloud Build), container registry, and Akash orchestration. Agents should follow a **local-first** workflow: write and test code on disk, then upload via MCP only when ready to ship. --- ## Endpoints | Resource | URL | |----------|-----| | MCP SSE (connect here) | `https://api.shipdapp.com/api/mcp/sse` | | MCP message POST | `https://api.shipdapp.com/api/mcp/message?sessionId=...` (returned by SSE handshake) | | Templates REST | `GET https://api.shipdapp.com/api/templates` | | Template + files REST | `GET https://api.shipdapp.com/api/templates/:id?includeFiles=true&appName=my-app` | | API keys (human UI) | `https://shipdapp.com/account/keys` | | This document | `https://api.shipdapp.com/llm-full.txt` | | Short index | `https://api.shipdapp.com/llm.txt` | --- ## Authentication API keys are **MCP-only**. They do not work on REST routes that require JWT wallet auth. ### Option A — API key (recommended for Cursor, Claude, IDE agents) 1. Human creates a key at https://shipdapp.com/account/keys 2. Add to MCP client config headers — **never** in tool arguments or chat: ```json { "mcpServers": { "shipdapp": { "url": "https://api.shipdapp.com/api/mcp/sse", "headers": { "Authorization": "Bearer shipdapp_sk_YOUR_KEY_HERE" } } } } ``` Keys are prefixed `shipdapp_sk_`. Max 5 active keys per account. Regenerate or revoke from the UI. ### Option B — Sign-In With Solana (SIWS) For agents with local wallet access (no API key): 1. `get_auth_challenge({ walletAddress })` → returns `challengeMessage` 2. Sign `challengeMessage` locally with ed25519 (off-chain, no gas) 3. `authenticate({ walletAddress, signature })` → signature is base58-encoded Challenge expires in 5 minutes. Session is per MCP SSE connection. --- ## Local-first workflow ``` list_templates(includeFiles=true, appName="my-app") → write scaffold files to disk → npm install && npm run dev → iterate until app works → npm run build (must succeed before deploy) → deploy_app({ appName, templateId, files }) → get_build_status(buildId, deploymentId) until SUCCESS → get_app_status(deploymentId) until ACTIVE → share proxyUri with user ``` **Devnet:** `deploy_app` registers a `BUILDING` deployment first. `get_build_status(buildId, deploymentId)` starts the Akash deploy automatically once Cloud Build reaches SUCCESS. No SOL funding step. `network: "devnet"` in response. **Prebuilt images:** Use `deploy_image(appName, dockerImage, port)` when you already have a public Docker/OCI image and do not want to upload source or run Cloud Build. **Updates:** Use `update_app(deploymentId, files, templateId)` — do **not** call `deploy_app` again for the same app. **Teardown:** `close_app(deploymentId)` is irreversible for that deployment ID. --- ## Templates Call `list_templates` or REST `GET /api/templates`. ### webapp-static | Field | Value | |-------|-------| | id | `webapp-static` | | Stack | Vite + React + TypeScript + Tailwind | | Type | Frontend-only SPA, no backend | | defaultPort | 3000 | | buildCommand | `npm run build` | | startCommand | `npm start` (vite preview on PORT) | | outputDirectory | `dist` | Download scaffold: `list_templates({ includeFiles: true, appName: "my-app" })` --- ## Tools reference ### get_auth_challenge **When:** First step if NOT using API key in MCP headers. **Input:** - `walletAddress` (string) — Solana public key, base58 **Output:** `challengeMessage` to sign locally, `walletAddress`, expiry info. --- ### authenticate **When:** Immediately after `get_auth_challenge`. **Input:** - `walletAddress` (string) — same as challenge - `signature` (string) — base58 ed25519 signature of `challengeMessage` **Output:** `{ success: true, authMethod: "siws" }` --- ### get_usage_limits **When:** After a guardrail block, or before planning multiple deploys/builds. **Input:** none (requires auth) **Output:** Current quotas, usage counts, active deployments, hourly build/deploy/update counts. --- ### list_templates **When:** Starting a new app, or need `templateId` for `deploy_app` / `build_image`. **Input:** - `includeFiles` (boolean, default false) — set `true` to download full scaffold - `appName` (string, optional) — substituted into template (e.g. index.html title) **Output:** Array of templates with metadata; includes `files` map when `includeFiles=true`. --- ### deploy_app **When:** App is built and tested locally; ready to ship to devnet. **Primary deploy tool.** **Input:** - `appName` (string, required) — unique app name for store listing and image tag - `templateId` (string, required) — e.g. `webapp-static` - `files` (object, required) — map of relative path → file content (complete project) - `description` (string, optional) - `port` (number, optional) — default 3000 for webapp-static - `imageUrl` (string, optional) — preview thumbnail for app store - `buildCommand` (string, optional) — override template default - `startCommand` (string, optional) — override template default - `dockerfileContent` (string, optional) — custom Dockerfile; omit for Cloud Buildpacks **Output:** `deploymentId`, `buildId`, `logUrl`, `network: "devnet"`, image info, `status: "BUILDING"`. **Next steps:** Poll `get_build_status({ buildId, deploymentId })` until SUCCESS. This starts the devnet deploy automatically. Then poll `get_app_status({ deploymentId })` until ACTIVE. **Guardrails:** max active deployments, daily limit, duplicate appName blocked, hourly rate limit, cooldown between deploys, upload size limits. --- ### build_image **When:** Build container image **without** creating a deployment. Prefer `deploy_app` for normal shipping. **Input:** - `appName` (string, required) - `templateId` (string, required) - `files` (object, required) - `buildCommand`, `startCommand`, `dockerfileContent` (optional overrides) **Output:** `buildId`, `image`, `logUrl`, `status` **Next steps:** Poll `get_build_status(buildId)` until SUCCESS. --- ### deploy_image **When:** You already have a public Docker/OCI image and want to deploy it to devnet without uploading source files or running Cloud Build. Use `deploy_app` instead when the agent has local source files and wants ShipDapp to build the image. **Input:** - `appName` (string, required) — unique app name for store listing - `dockerImage` (string, required) — public image URI, e.g. `ghcr.io/acme/my-app:latest` - `description` (string, optional) - `port` (number, optional) — container listen port; default 3000 - `imageUrl` (string, optional) — preview thumbnail for app store - `startCommand` (string, optional) — command override if the image needs one **Output:** `deploymentId`, `status`, `network: "devnet"`, `dockerImage`, `port` **Next steps:** Poll `get_app_status(deploymentId)` until ACTIVE. There is no `buildId` because no Cloud Build runs. **Guardrails:** Same deployment limits as `deploy_app` (active deployments, daily deploy limit, duplicate appName, hourly deploy rate, cooldown). File upload limits do not apply because no files are uploaded. --- ### get_build_status **When:** After `deploy_app`, `update_app` rebuild, or `build_image`. Poll every 10–30s. **Input:** - `buildId` (string, required) - `deploymentId` (string, optional) — pass this for `deploy_app` / file-based `update_app`; when build status is SUCCESS the server starts Akash deploy/update automatically **Output:** `status` (QUEUED | WORKING | SUCCESS | FAILURE | CANCELLED), `logUrl`, `images`, timestamps, optional `deploymentStarted`. **On FAILURE:** Call `get_logs({ type: "build", buildId, deploymentId })`. Do not redeploy while status is QUEUED or WORKING. --- ### update_app **When:** App already deployed; push new code or config. **Input:** - `deploymentId` (string, required) - `files` (object, optional) — triggers cloud rebuild; requires `templateId`; then poll `get_build_status(buildId, deploymentId)` - `templateId` (string, required when `files` provided) - `appName`, `description`, `port` (optional) - `dockerImage` (string, optional) — redeploy pre-built image instead of rebuilding from files **Output:** Updated deployment info, and `buildId`/`logUrl` when a rebuild runs. **Next steps:** Poll `get_app_status` until ACTIVE again. --- ### get_app_status **When:** After build succeeds, or anytime to check health / get live URL. **Input:** - `deploymentId` (string, required) **Output:** Deployment record with `status`, `proxyUri` (when ACTIVE), `lastError`, workflow state. **Poll:** Every 10–30s until ACTIVE or FAILED. No funding step on devnet. --- ### list_apps **When:** Find `deploymentId`, check which apps are ACTIVE vs DEPLOYING. **Input:** none **Output:** Array of deployments for authenticated wallet (excludes DELETED). --- ### get_logs **When:** Debugging build failures or runtime crashes. **Input:** - `deploymentId` (string, required) - `type` (`"build"` | `"runtime"`, default `"runtime"`) - `buildId` (string, required when `type=build`) - `tail` (number, optional) — max log lines for runtime (default 500) **Output:** Log text / entries. **Notes:** - `type=build`: use after `get_build_status` returns FAILURE - `type=runtime`: requires deployment ACTIVE; returns container stdout/stderr from Akash --- ### close_app **When:** Permanently shutting down an app. Irreversible for that `deploymentId`. **Input:** - `deploymentId` (string, required) **Output:** `{ success: true, closed: boolean, warnings?: string[] }` Stops Akash lease, frees resources, marks deployment DELETED. --- ## Guardrails (default limits) Call `get_usage_limits` to see current values for the authenticated wallet. | Limit | Default | |-------|---------| | Max active deployments | 5 | | Max deployments per day | 10 | | Max builds per hour | 5 | | Max deploys per hour | 3 | | Max updates per hour | 10 | | Max files per upload | 200 | | Max total upload size | 2 MB | | Max single file size | 512 KB | | Deploy cooldown | 60 seconds | **Blocked response format:** ``` GUARDRAIL BLOCKED [CODE] Call get_usage_limits to see current quotas. Do not retry the same action in a loop. ``` **Common codes:** `TOO_MANY_ACTIVE`, `DAILY_LIMIT`, `RATE_LIMIT`, `DUPLICATE_APP_NAME`, `COOLDOWN`, `TOO_MANY_FILES`, `UPLOAD_TOO_LARGE`, `FILE_TOO_LARGE`, `EMPTY_UPLOAD`, `INVALID_PATH`. --- ## File upload rules - `files` is a map: relative path → UTF-8 string content - Paths must be relative (no `..`, no leading `/`) - Include complete project (not just changed files) for reliable builds - Exclude `node_modules`, `.git`, build artifacts unless intentionally needed - Run `npm run build` locally before `deploy_app` --- ## MCP prompts (optional) The server registers MCP prompts agents can use: - **deploy_app_guide** — guided new-app deploy workflow - **monitor_app** — check status and logs for a deploymentId --- ## Example agent Reference implementation: https://github.com/yash1ts/shipdapp/tree/main/examples/x-agency-agent ```bash git clone https://github.com/yash1ts/shipdapp.git cd shipdapp/examples/x-agency-agent npm install export SHIPDAPP_BASE=https://api.shipdapp.com npm run agent -- "build me a neon snake game" ``` --- ## Agent rules (critical) 1. **Never** expose API keys in chat, commits, tool args, or logs 2. **Always** test locally before `deploy_app` 3. **Do not** retry guardrail-blocked actions in a loop — read `get_usage_limits` 4. **Use** `update_app` for existing deployments, not `deploy_app` 5. **Use** `close_app` only for permanent teardown 6. **Poll** build then status — do not assume instant ACTIVE 7. API keys authenticate MCP only — not REST JWT routes --- ## Status values Deployment statuses include: `BUILDING`, `PENDING_FUNDS`, `FUNDED`, `DEPLOYING`, `ACTIVE`, `FAILED`, `RECOVERING`, `RECOVERY_FAILED`, `LEASE_CLOSED`, `DELETED`. On devnet source MCP flow, expect: BUILDING → DEPLOYING → ACTIVE (no manual funding). Build statuses: `QUEUED`, `WORKING`, `SUCCESS`, `FAILURE`, `CANCELLED`. --- ## Support links - Website: https://shipdapp.com - API: https://api.shipdapp.com - GitHub: https://github.com/yash1ts/shipdapp