Agents first

MCP for aft.page

Thin remote MCP — any capable agent can publish small software to a live URL — no account, no repository setup.

Remote MCP: https://mcp.aft.page/mcp. Agents: prefer https://aft.page/mcp.md or llms.txt — same content, machine-friendly. HTML below is for humans configuring a host.

What it is

aft.page hosts small software — one-pagers, prototypes, agent-built HTML, static SPAs — at a shareable HTTPS URL in seconds. The name comes from the aft of a ship: the back of the vessel — take what you built and put it out into the world.

Prefer the MCP tools below. If MCP is unavailable, call the API directly.

Quick start

Thin remote MCP — one deploy tool (html or files), plus aft_deploys, aft_rollback, aft_health. No account. Point your host at:

https://mcp.aft.page/mcp

MCP host config (preferred)

Add a server named aft-page with the remote URL (Cursor, Claude Desktop, and other Streamable HTTP clients):

{
  "mcpServers": {
    "aft-page": {
      "url": "https://mcp.aft.page/mcp"
    }
  }
}

Reload the host, then ask:

Deploy this HTML to aft.page

The agent should call deploy and return a live URL.

Local / advanced (stdio)

Optional. Clone the repo and run apps/mcp over stdio when you need an offline or patched server. Most users should use the remote URL above.

cd apps/mcp
npm install
npm start
{
  "mcpServers": {
    "aft-page": {
      "command": "npx",
      "args": [
        "tsx",
        "/ABSOLUTE/PATH/TO/aft.page/apps/mcp/src/index.ts"
      ]
    }
  }
}

Tools

aft.page does not build your app. Detect first: plain HTML → upload those files; Vite/React → npm run build then dist/ only; Next static export → out/. Never upload src/ or node_modules.

deploy

One tool. Pass html or files — not both. Goes live immediately. One-file pages use html; multi-file / SPA build output uses files (always include index.html).

Input Type Required Notes
html string one of Full document; prefer <!DOCTYPE html>…</html>
files array one of Built static files. Paths relative; UTF-8 or base64.
preferred_slug string no Hint like about-me. First hit never overwrites — collision gets a suffix. Required with edit_token.
edit_token string no From first deploy / .aft/state.json. When set, MCP PATCHes this slug — same URL, new rollback row.

Returns text + structured content:

Live: https://{slug}.aft.page
Claim: https://aft.page/claim?slug=…&token=…
slug: …
deploy: dep_…
files: 1
Unclaimed sites are deleted after 30 days idle. Visit, update, or claim to keep.

Limits: 500 files · 25 MB each · 100 MB total. Paths: no .., no leading /, no \.

aft_deploys

List rollback-able deploys for a slug. Needs edit_token from .aft/state.json. Same D1 history as the project UI after claim.

aft_rollback

Point the live slug at a prior deploy_id. Same URL. Unclaimed: edit_token. After claim, token is dead — session owner/editor only. MCP has no session yet.

aft_health

Ping the deploy API. No inputs. Returns ok and the API base.

Prompt: deploy_to_aft

Optional prompt that steers the agent:

  • Detect first: plain HTML vs JS app (Vite/React/Next).
  • Call deploy with html or files.
  • Vite/React: npm run build, then dist/ only. Next static export: out/.
  • Pass preferred_slug when sensible. Persist .aft/state.json; later deploys send edit_token.
  • Return the live HTTPS URL as the deliverable.
  • Do not invent account or repository setup steps.

Arg: html_or_files (optional context string).

API (no MCP)

Base: https://api.aft.page. CORS: * on deploy + site GET.

GET /health

{ "ok": true }

POST /v1/deploy

Query: optional ?slug=preferred-name. Optional header X-Aft-Client: mcp|web|extension|curl|cli|mac (metrics). Three body shapes:

A) Raw HTML

POST /v1/deploy?slug=hello
Content-Type: text/html; charset=utf-8

<!DOCTYPE html><html><body><h1>Hi</h1></body></html>

B) JSON files (agents)

POST /v1/deploy
Content-Type: application/json

{
  "files": [
    { "path": "index.html", "content": "<h1>App</h1>" },
    { "path": "style.css", "content": "body{margin:0}" }
  ]
}

C) Multipart — fields file0 + file0_path, …

Success (200)

{
  "ok": true,
  "slug": "hello",
  "deployId": "dep_…",
  "url": "https://hello.aft.page",
  "files": 1,
  "bytes": 42,
  "editToken": "aft_edit_…",
  "claimUrl": "https://aft.page/claim?slug=hello&token=…",
  "owned": false,
  "notice": "Unclaimed sites are deleted after 30 days idle. Visit, update, or claim to keep."
}

Errors include no_files, too_many_files, file_too_large, payload_too_large, bad_path, reserved_slug, slug_exhausted, internal. Invalid ?slug= patterns are ignored (random unique slug); only reserved names return reserved_slug.

Serving

URL Behavior
https://{slug}.aft.page/ Primary — index.html
https://{slug}.aft.page/{path} Static asset
https://api.aft.page/s/{slug}/ Path fallback

If the requested object is missing, the Worker soft-falls back to that deploy’s index.html (SPA-style). Content-Type follows the file extension when the upload type is missing or application/octet-stream (so CSS is text/css).

Slugs

  1. Prefer valid ?slug= / preferred_slug when provided.
  2. Else allocate a random unique slug.
  3. Clients (paste UI, extension, agents) may derive a hint from <title> / <h1> and pass it as ?slug= — the Worker does not parse HTML for a name.
  4. First POST never overwrites — append a short word suffix on collision. PATCH with edit_token updates that slug in place.
  5. Reserved: www, api, app, admin, docs, status, …

Claim / manage

https://aft.page/claim?slug=…&token=…

The live URL is the product. After deploy, open claimUrl to add email or Google. Unclaimed sites also show Claim on the live slug. After claim, Manage opens the project page (invite, rollback, secrets, custom domains — request access). Keep editToken to prove you deployed.

Limits (today)

Limit Value
Files per deploy 500
Per-file size 25 MB
Total payload 100 MB
Auth None (anonymous)
Unclaimed retention Deleted after 30d idle. Visit, PATCH, or claim to keep.
Overwrite Never
Custom domains / private invite After claim · request access (Domains tab)

Examples

Minimal HTML via curl

curl -sS -X POST "https://api.aft.page/v1/deploy?slug=curl-smoke" \
  -H "content-type: text/html; charset=utf-8" \
  --data-binary @index.html

Agent rule of thumb

  1. Prefer MCP deploy (html or files).
  2. Return the live URL.
  3. Optionally link the preview shell.
  4. Do not invent auth steps that do not exist yet.

Troubleshoot

Symptom Fix
MCP tools missing Reload host; check absolute path; Node 20+
reserved_slug Change title / slug
Size errors Stay under 25 MB / file, 100 MB total
Unstyled CSS Ensure path ends in .css; re-deploy
Site 404 Wait for DNS; try /s/{slug}/ on API host