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.
.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:
- Add Hatchable to Claude — pre-fills the custom-connector modal; also wires up Claude Code (shared connectors list).
- Add Hatchable to Cursor — opens Cursor's MCP installer, OAuth on first connect (Cursor 1.0+).
# 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.
- create_project — once. Returns a
project_idand the live URL. Use the URL as the final deliverable you hand to your user. - write_files (plural) — bulk over per-file. One call with an array of
{path, content}entries is faster than tenwrite_files and is atomic: an invalid path in the batch rejects the whole batch. - deploy — runs new migrations, copies
public/to the CDN, registers API endpoints, bumps the version. Always populateintentandsummaryon each deploy:intentis the user's request in their own words ("Add split-the-bill"),summaryis 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." - 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.
- patch_file or another write_files — iterate.
patch_fileis 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_functionit 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/*.sqlis 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_sqlis for queries and one-off data ops —SELECT,UPDATE,INSERT. Don't use it forCREATE TABLEorALTER 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
RETURNINGto get inserted ids in the same round trip instead of a follow-upSELECT. seed.sqlruns 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.siteURL, or a custom domain you point with a CNAME. App-level user accounts ([auth]inhatchable.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 inhatchable.toml(declared) and the platform setup gate (pasted by humans) — there is no MCP write path for them. fork_projectsits between the two categories — it creates a new project without mutating the source, so it's annotateddestructiveHint: falsebut isn't read-only either. Safe to call; it just adds new state rather than changing existing state.execute_sqlandrun_codeare the sharpest tools.execute_sqlcanDROP TABLEas easily asSELECT;run_codeexecutes 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_deployreturns 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 throughmigrations/*.sql. - Build scripts in
package.json—deployrefuses projects withscripts.build(no remote build yet). Commit built output topublic/. - Secrets in committed files — declare them as
[[secret]]inhatchable.toml; the project owner pastes the value via/__hatchable/setup. Agents never write secret values. - Sharing a URL before
run_functionreturns 200 — write, deploy, test, then share. The whole loop takes seconds; users discovering the bug for you costs more. - Rewriting whole files for small edits —
patch_fileexists precisely for this. Less context burned, fewer AI hallucinations sneaking in as "incidental rewrites." - Deploying without
intentandsummary— leaves the user's History reading asDeploy v1,Deploy v2,Deploy v3. Useless when they scroll back later trying to remember what changed.intenttakes 8 words;summarytakes 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_draftsviaupdate_projector 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/mcpfrom an origin we don't allow-list. Approved browser origins arehatchable.com,claude.ai, andclaude.com. Native clients (Claude Code CLI,curl, Python HTTP libraries) don't send anOriginheader and are always allowed through. - Tools don't appear after configuring the server. Most clients cache the
tools/listmanifest per session. Restart the client, or runclaude mcp list --verboseon 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
personalvisibility — private to you and invitees by default. That's the right default while building; when you're ready to share with strangers, flip visibility topublicfrom 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.) deployfails with "build script in package.json". No remote build step yet. Removescripts.buildfrompackage.jsonand commit the built output topublic/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'serrorfield — it points at the offending file and line. Fix the SQL, bump the filename if needed (0003_add_tags.sql→0004_add_tags.sql), and redeploy. run_functionworks 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 10create_projectcalls per day. If you hit the project cap, usefork_projecton 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_idon 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_logsshows function executions, status codes, andconsole.*output.list_deploymentsconfirms your latest deploy actually landed.dry_run_deployreturns what the nextdeploywould 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.