PagePilot

Documentation

One hosted MCP endpoint. No dashboard, no local process, nothing to clone.

How this works

PagePilot is an MCP server that happens to have a landing page. Everything — publishing, listing, deleting — happens through MCP tools your agent calls. There is no dashboard and no login, on purpose: a UI would be one more authenticated surface guarding the same bucket.

The server runs inside this deployment at /api/mcp. Your agent talks to it over HTTP with your API key. Your R2 credentials never leave the server.

Your API key

Nobody issues this key — you choose it. It is the only credential your agents ever see, and the same value guards every tool.

generate one
openssl rand -hex 32

Set it as PAGEPILOT_API_KEY in your deployment's environment variables, then use the same value when adding the MCP server below. Your R2_* credentials come from Cloudflare and stay server-side.

Connect your agent

A remote MCP server, so there is no path to get wrong and no runtime to install.

Claude Code

one command

claude mcp add --transport http pagepilot \
  https://pagepilot.rafay99.com/api/mcp \
  --header "Authorization: Bearer YOUR_API_KEY"

Then just ask: “Write up the plan as an HTML page and publish it.”

Anything that reads mcp.json

Cursor, OpenCode, Command Code, Claude Desktop

{
  "mcpServers": {
    "pagepilot": {
      "type": "http",
      "url": "https://pagepilot.rafay99.com/api/mcp",
      "headers": { "Authorization": "Bearer YOUR_API_KEY" }
    }
  }
}

Raw HTTP

any client that speaks MCP over Streamable HTTP

curl -X POST https://pagepilot.rafay99.com/api/mcp \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

Tools

deploy_page

  • html (string)Full HTML content (required)
  • title (string)Label shown in the list

Returns: id, title, url, createdAt

list_pages

Returns: The 200 newest pages

delete_page

  • id (string)Page to remove

Returns: Confirmation

Who can read a page

Anyone holding the link. There is no login and no cookie — the 48-bit id in the URL is the credential, so a page is exactly as private as its link.

That means nobody can find your pages by guessing or crawling, but whoever you send a link to can forward it, and Slack, Discord and Notion all fetch a URL server-side to build previews. Pages send X-Robots-Tag: noindex and robots.txt disallows /p/, so a leaked link still can't become a search result. When you want a page gone, call delete_page — the URL dies immediately.

Your PAGEPILOT_API_KEY guards publishing, listing and deleting. Without it nobody can enumerate your vault or write to it, even though individual links are readable.

Run your own

1. Create an R2 bucket

  1. Cloudflare Dashboard → R2 → Create Bucket. Use a bucket dedicated to PagePilot.
  2. Leave public access disabled — no public development URL, no public custom domain on the bucket. Otherwise every page is fetchable straight from R2 and everything above is decoration.
  3. Create an API token with Object Read & Write on that bucket
  4. Copy the Access Key ID, Secret Access Key and your Account ID

2. Deploy to Vercel

Import the repo with Root Directory set to apps/web, then set:

environment variables
R2_BUCKET=your-bucket-name
R2_ACCOUNT_ID=your-32-char-hex-account-id
R2_ACCESS_KEY_ID=your-access-key
R2_SECRET_ACCESS_KEY=your-secret-key
PAGEPILOT_API_KEY=the-key-you-generated-above

# Only for a custom domain; otherwise defaults to your Vercel URL
PUBLIC_URL=https://pages.example.com

3. Local development

Put the same values in .env.local, run bun run dev, and point an agent at http://localhost:3000/api/mcp. bun run test round-trips real pages through your bucket.