Developer docs  /  MCP
Reference

MCP server, tool surface, build loop.

The technical reference for connecting AI clients, the 31-tool API surface with safety annotations, the five-step build loop, prompting patterns, anti-patterns, and troubleshooting.

The Hatchable MCP server lives at https://hatchable.com/mcp. It speaks the Streamable HTTP transport (protocol version 2025-03-26) and authenticates via OAuth 2.1 with dynamic client registration, or a static bearer token you paste. Add it once and every prompt that ends in "…on hatchable" ships through the same build loop.

Hatchable runs without a build step. Source files = production. No webpack, vite, esbuild, tsc, or Babel; no JSX or .jsx/.tsx; no ORMs (Drizzle, Prisma, etc.); no framework imports (Next, Remix, SvelteKit, Express). Each of these is a deploy-time anti-pattern reject with a remediation message. CSS/JS deps load from CDNs at runtime — Tailwind, Alpine, React via esm.sh + htm. Read this before your first deploy so the validator's "rejected" messages aren't a surprise.

Connecting your AI

Popular clients, one URL. Two have one-click deep links that install Hatchable directly:

# Claude & Claude Code — claude.ai/customize/connectors → Add custom connector
# (or use the one-click link above)
https://hatchable.com/mcp

# ChatGPT — chatgpt.com/apps#settings/Connectors/Advanced → Create app
https://hatchable.com/mcp

# Codex — Settings → MCP servers → Add server (Streamable HTTP)
https://hatchable.com/mcp

# Antigravity — ask the agent in chat
Add the https://hatchable.com/mcp MCP connector with OAuth.

# Cursor 1.0+ — use the one-click link above (OAuth on first connect, no token)
# Older Cursor versions — paste into ~/.cursor/mcp.json with a Bearer token
{ "mcpServers": { "hatchable": {
  "url": "https://hatchable.com/mcp",
  "headers": { "Authorization": "Bearer $HATCHABLE_TOKEN" }
}}}

OAuth-capable clients (Claude Code, Claude.ai, Antigravity, Codex) skip the token step — sign in on the browser tab that pops up and come back. For static-token clients like Cursor, grab $HATCHABLE_TOKEN from your API keys page.

The build loop

Every successful session follows the same five steps. Get your agent into this rhythm and most of what follows becomes automatic.

  1. create_project — once. Returns a project_id and the live URL. Use the URL as the final deliverable you hand to your user.
  2. write_files (plural) — bulk over per-file. One call with an array of {path, content} entries is faster than ten write_files and is atomic: an invalid path in the batch rejects the whole batch.
  3. deploy — runs new migrations, copies public/ to the CDN, registers API endpoints, bumps the version. Always populate intent and summary on each deploy: intent is the user's request in their own words ("Add split-the-bill"), summary is your 1–3 sentence plain-language description of what changed. They become the user-facing changelog in the console's History view, the git commit message, and (when the site is public) the prompt the user reads before clicking "Promote to live."
  4. run_function — execute the endpoints you just wrote through your authenticated session. Works on personal projects before you've made them public, so you can verify response shapes before a real user hits them.
  5. patch_file or another write_files — iterate. patch_file is a find-and-replace; cheaper than rewriting the whole file for small edits.

Then deploy again and loop.

Drafts vs live

Public sites have auto_promote_drafts off by default. Your deploy calls land at {slug}-draft.hatchable.site (collaborators only) until the user clicks Promote to live in the console's History tab. The deploy response sets is_draft: true with the preview URL — tell the user where to look. Don't try to auto-promote; promoting is the human's call.

Private sites auto-promote (sketch mode) — every deploy goes live instantly. The toggle flips automatically on the public/private edge, so most users never need to touch it manually.

Prompting

What we've seen work:

  • "…on hatchable" at the end of a prompt. A short, consistent signal that your agent should reach for the Hatchable tools rather than writing local files.
  • State the project once. "Working on proj_a8Kq7fR2xZ" early in the conversation — the agent remembers and stops asking which project.
  • Ask for a test after each endpoint. "Write the endpoint, then run_function it with a realistic body and show me the response." This catches half of all bugs before the frontend is written.
  • Keep iterations tight. "Tweak the copy and redeploy" beats "redo the whole landing page."

Database

Every project gets a dedicated PostgreSQL database. Treat it like any other Postgres — you have the full language.

  • migrations/*.sql is the schema source of truth. Each migration runs exactly once, in filename order, tracked in __hatchable_migrations. Use numbered prefixes: 0001_init.sql, 0002_add_tags.sql.
  • execute_sql is for queries and one-off data opsSELECT, UPDATE, INSERT. Don't use it for CREATE TABLE or ALTER TABLE; changes made there aren't in your migration history and won't reproduce for forks.
  • Parameterize everything. $1, $2, etc. — never string-interpolate untrusted values.
  • Use RETURNING to get inserted ids in the same round trip instead of a follow-up SELECT.
  • seed.sql runs once per project (and on every fresh fork). Good for demo data; keep it idempotent-ish so re-running doesn't duplicate rows if you trigger it manually.

Going live

Two visibility levels:

  • personal (free, default) — login-gated with Hatchable accounts. Collaborators you invite can see it; strangers can't. Perfect for building in the open without exposing a half-done app.
  • public ($12/mo across your whole account, flat) — on the open web at your your-slug.hatchable.site URL, or a custom domain you point with a CNAME. App-level user accounts ([auth] in hatchable.toml) work in either visibility — they're a separate concept from who can load the site.

Build on personal. Promote when you're ready.

Visibility is set at create time and is changed only from the dashboard — never from MCP. Flipping a project public can expose user data and trigger plan upgrades, so it's a deliberate human action, not an agent step.

Tool safety

Every Hatchable tool carries MCP annotations so your AI (and the client surface it runs in) can reason about what a call will do before making it. 31 tools total:

  • 17 read-only (readOnlyHint: true) — get_project, list_projects, read_file, grep, list_files, get_schema, view_logs, list_deployments, list_functions, get_deployment, list_cron_jobs, search_documentation, list_skills, read_skill, dry_run_deploy, list_pending_uploads, search_projects. Safe to call freely.
  • 13 destructive (destructiveHint: true) — everything that writes, deletes, or mutates state: create_project, deploy, write_file, write_files, patch_file, delete_file, execute_sql, update_project, run_function, run_code, import_file_from_url, upload_file, setup_account. Clients that prompt before destructive calls will surface these. Visibility flips deliberately are NOT exposed via MCP — they're dashboard-only. Project secrets and config live in hatchable.toml (declared) and the platform setup gate (pasted by humans) — there is no MCP write path for them.
  • fork_project sits between the two categories — it creates a new project without mutating the source, so it's annotated destructiveHint: false but isn't read-only either. Safe to call; it just adds new state rather than changing existing state.
  • execute_sql and run_code are the sharpest tools. execute_sql can DROP TABLE as easily as SELECT; run_code executes arbitrary code in the project's sandbox. Agents should prefer the structured tools (get_schema, migrations, run_function) when possible.
  • Before a risky deploy, dry_run_deploy returns exactly what would happen — which migrations would run, which files would be copied, which functions would (re-)register — without applying anything. Useful on first-time-after-a-big-change deploys.

Anti-patterns

Things we regularly see that end in tears:

  • Schema changes via execute_sql — bypasses migration tracking, doesn't reproduce on fork. Always go through migrations/*.sql.
  • Build scripts in package.jsondeploy refuses projects with scripts.build (no remote build yet). Commit built output to public/.
  • Secrets in committed files — declare them as [[secret]] in hatchable.toml; the project owner pastes the value via /__hatchable/setup. Agents never write secret values.
  • Sharing a URL before run_function returns 200 — write, deploy, test, then share. The whole loop takes seconds; users discovering the bug for you costs more.
  • Rewriting whole files for small editspatch_file exists precisely for this. Less context burned, fewer AI hallucinations sneaking in as "incidental rewrites."
  • Deploying without intent and summary — leaves the user's History reading as Deploy v1, Deploy v2, Deploy v3. Useless when they scroll back later trying to remember what changed. intent takes 8 words; summary takes 1–2 sentences; the future-them with no context will thank you.
  • Auto-promoting drafts from the agent side — drafts exist precisely so a human reviews before users see changes. Don't try to flip auto_promote_drafts via update_project or otherwise force a draft live.

Troubleshooting

The failure modes we see most often, and what to do about each.

  • 401 Unauthorized on every call, even right after connecting. Your client isn't persisting the bearer token between calls. Check that the Authorization: Bearer … header is actually set in your MCP config. If you're using OAuth, start a fresh session — some clients silently drop tokens after idle timeouts.
  • 403 with "Origin not allowed". A browser request is hitting /mcp from an origin we don't allow-list. Approved browser origins are hatchable.com, claude.ai, and claude.com. Native clients (Claude Code CLI, curl, Python HTTP libraries) don't send an Origin header and are always allowed through.
  • Tools don't appear after configuring the server. Most clients cache the tools/list manifest per session. Restart the client, or run claude mcp list --verbose on Claude Code to force a refresh. If the server is listed but greyed out, the manifest fetch failed — re-check the Bearer token.
  • Live URL returns a login wall. Your project is personal visibility — private to you and invitees by default. That's the right default while building; when you're ready to share with strangers, flip visibility to public from the dashboard. (Visibility is dashboard-only; MCP can't promote a project for you because the consequences — data exposure, plan upgrade — should be a deliberate human decision.)
  • deploy fails with "build script in package.json". No remote build step yet. Remove scripts.build from package.json and commit the built output to public/ instead. (On the roadmap — not there yet.)
  • Migration rejected on deploy. The deploy tool won't retry a migration that already ran (they're tracked in __hatchable_migrations) and won't skip one that's new but malformed. Check the deploy response's error field — it points at the offending file and line. Fix the SQL, bump the filename if needed (0003_add_tags.sql0004_add_tags.sql), and redeploy.
  • run_function works locally but 500s on the deployed URL. Usually a missing environment variable. The local SDK stubs values that production requires the project owner to paste via /__hatchable/setup. Visit the deployed URL once as the owner; the platform redirects to the gate for any unsatisfied [[secret]] declarations, then back to the app.
  • Rate-limited (429 on /mcp, or an inline "daily limit" error). Per-account throttles: 60 MCP calls/minute and 10 create_project calls per day. If you hit the project cap, use fork_project on an existing public project (fork doesn't count against the cap) or resume tomorrow — counters reset at UTC midnight.
  • OAuth flow loops — "connect" button keeps re-prompting. Almost always a client-side issue: the client registered a fresh client_id on every reconnect instead of caching it. The server sees a normal OAuth dance complete successfully each time. If this persists, stop the client, start a new session, and try once — in our experience the loop self-heals on a clean start.
  • Nothing's wrong but nothing's happening. view_logs shows function executions, status codes, and console.* output. list_deployments confirms your latest deploy actually landed. dry_run_deploy returns what the next deploy would do without applying it — useful when the feedback loop feels broken.

Still stuck? Email support@hatchable.com with your project_id, the tool call you ran, and the response — we usually reply within one business day.


Want the canonical spec? Every MCP tool includes its full schema in the tool description when your AI lists them — so the agent always has an up-to-date copy, even if this page lags.