Skip to content

Connecting AI tools over MCP

Flatstack runs a remote MCP server at https://api.flatstack.dev/mcp. Claude, Claude Code, Cursor, Codex and any other client that speaks MCP over Streamable HTTP can connect to it, sign in with your Flatstack account, and then create projects, deploy, set variables and secrets, manage domains and email, import from Supabase or Clerk, read logs and usage, and look things up in these docs for you.

Connecting

You sign in once in the browser: the client opens Flatstack’s consent screen, you choose what it may do, and it receives its own token. You need a Flatstack account first; the MCP server can’t create one.

Claude Code

claude mcp add --transport http flatstack https://api.flatstack.dev/mcp

Then run /mcp in Claude Code, choose flatstack and Authenticate.

Claude (claude.ai and the desktop app): Settings, Connectors, Add custom connector, with the URL https://api.flatstack.dev/mcp. Then choose Connect.

Cursor: add to ~/.cursor/mcp.json (or the project’s .cursor/mcp.json):

{ "mcpServers": { "flatstack": { "url": "https://api.flatstack.dev/mcp" } } }

Cursor shows Needs login next to the server; choose it to sign in.

Other clients: give them the URL. A client that supports MCP authorisation finds the sign-in on its own. One that doesn’t can send a personal access token instead, as Authorization: Bearer fs_pat_…, for example claude mcp add --transport http flatstack https://api.flatstack.dev/mcp --header "Authorization: Bearer $FLATSTACK_TOKEN".

The consent screen names the app, shows the address it will return you to, and lists what it asked to do. Untick anything you don’t want it to have. It never gets more than your role allows (see Teams and roles): a developer can’t give an app projects:write, for example, and if your role changes later, the app’s access changes with it.

Permission Lets the app
projects:read See projects, deploys, domains, email and usage
projects:write Create projects and change domains and email settings
deploy Deploy code, apply migrations, roll back, run the security scan
env:read See environment variables and the names of secrets
env:write Set environment variables and secrets
logs:read Read logs
data:read See your apps’ data, files and users
data:write Change your apps’ data, files and users, and import
addons:buy Buy add-ons on your account’s card, each one only after you confirm it (owners only)
projects:lifecycle Export, archive, delete and restore projects, archiving and deleting each only after you confirm it (owners only)

Like other tokens, an MCP app can’t manage members or tokens, change plan or cards, remove add-ons, or transfer a project to another account. Those need you signed in to the dashboard; an owner sends a project from its Settings in the dashboard and the receiving owner accepts it on Projects, then Transfers (see moving a project). With projects:lifecycle, an owner’s app can delete and restore projects (delete_project needs confirm: true).

Connected apps are listed on Security in the dashboard, with what each can do and when it was last used. Disconnect cuts one off at once. An app nobody uses for 90 days is disconnected on its own. Owners and admins see and can disconnect every member’s apps.

Tools

Every tool calls the same API the dashboard and CLI use, so it behaves the same way and its changes are in the audit log, under the app’s token. Most tools take projectId (from list_projects) and an optional environment: production, the default, or preview/<name>.

Tool What it does Needs
list_projects The account’s projects (deleted: true for deleted ones you can still restore). Idle projects come back as suggestions and warnings: park an active one with no requests for 30 days, archive a parked one with none for 90. Only suggestions: act on one only when you ask projects:read
create_project Create and provision a project: name, optional slug, region, engine projects:write
get_project One project projects:read
park_project, promote_project Move a project to a parked slot, or a parked one to an active slot; same ID, URL, data and deploys projects:write
archive_project Archive a project: export it, keep the export 12 months, remove what’s live, free its slot. Needs confirm: true. Owners only projects:lifecycle
restore_project Restore a deleted project (within 30 days), or an archived one into a free slot; optional state: active or parked projects:lifecycle
delete_project Delete a project; restorable for 30 days. Needs confirm: true. Owners only projects:lifecycle
export_project Export a project as one ZIP with SELF_HOST.md; returns a download link that lasts an hour. Works while the account is read-only. Owners only projects:lifecycle
create_sandbox Signed in, a parked project in the account with no expiry (template optional). Fails with parked_slots_full when none is free. Without an account, use the sandbox endpoint projects:write
claim_sandbox Move an unclaimed sandbox into the account, where it lands parked, or archived when no parked slot is free: claim, its claim URL or fs_clm_ token (keeping a sandbox) projects:write
get_usage This period’s usage against each limit, for the account or one project
get_activation The setup checklist: each step done or not, and next, the step to offer
list_addons Add-ons the account can buy (with price, what each adds and onSale), the ones it holds, and the AI credit balance addons:buy
buy_addon Buy an add-on: addOnId, optional quantity and projectId (always-on Postgres). Needs confirm: true. Packs return a Checkout url for you to pay addons:buy
deploy Deploy a bundled Worker with its migrations, scan sources and cron jobs, and a small site as staticFiles ([{ path, content }], base64) with its hosting config. Larger sites deploy with the CLI deploy
get_deploy_status One deploy, or the latest deploys without deployId projects:read
rollback Make an earlier deploy live again deploy
publish_site Put static files (a prototype’s index.html and the rest) live at a shareable URL in one call (quick publish) projects:write
apply_schema Apply migration files without deploying; dryRun: true shows what would run deploy
run_security_scan The deploy’s security scan, without deploying deploy
list_env Variables with values, and secrets by name env:read
set_env Set a variable env:write
set_secret Set a secret; its value is never shown again env:write
list_domains, add_domain, check_domain Custom domains and the DNS records to add projects:read, projects:write
add_email_domain, get_email_domain, check_email_domain Sender domains: the record to add, status and diagnostics projects:read, projects:write
remove_email_domain Remove a sender domain. Needs confirm: true projects:write
send_test_email Send a template to your own address projects:write
get_email_log Recent sends and their delivery status projects:read
import_project Import from Supabase, Lovable Cloud or Clerk; dryRun: true returns the migration report and writes nothing data:write
get_import_status An import’s progress; advance: true runs its next step, report: true adds the report and the files to write data:read
list_cron_runs Cron run history projects:read
list_end_users Your app’s users, with search data:read
get_auth_settings How your app’s users sign in: methods, email verification, OAuth providers, Turnstile, trusted origins, email templates and pages. Client secrets show only as clientSecretSet: true projects:read
set_auth_settings Change sign-in settings; only the fields sent change. A provider takes clientId and, the first time, clientSecret; leave clientSecret out to keep the stored one, and set a provider or turnstile to null to turn it off. Secrets are never returned by any tool. Reaches the app on its next deploy projects:write
get_logs An environment’s logs, newest first: console output, requests, exceptions and cron runs, with the deploy that served each. Filter with since (15m, 2h or an ISO time; default an hour), level (the lowest to include), search and limit. Secrets are redacted before logs are stored. See Logs logs:read
search_docs Search these docs and the error reference: query, optional limit (default 5, at most 20). Each result has a title, section, url on flatstack.dev and a short snippet

More tools arrive as their features ship: branches, errors, SQL, export and type generation.

Sandboxes without an account

https://api.flatstack.dev/mcp/sandbox needs no sign-in. It offers create_sandbox, which makes a 24-hour sandbox and returns its URL, a token and a claim link for the person you’re building for, and then apply_schema, deploy, get_deploy_status, get_logs, run_security_scan, set_env, set_secret and search_docs for that sandbox alone. Send the token as a Bearer token or as each tool’s token argument; projectId isn’t needed. Three sandboxes an hour and ten a day per address (sandbox_rate_limited). Account tokens are refused there, and sandbox tokens are refused here.

Results, warnings and errors

Every result is JSON with a warnings list. It holds cap warnings (a metric at 80% of its limit, or capped at 100%) and security scan findings. Clients should show them to you.

Results of create_project, deploy, publish_site and a completed get_import_status also carry next: the setup step to offer you next (id, label, the CLI command, the mcpTool that does it, and a docs link), or null once the setup checklist is complete. It is the earliest checklist step still undone that a tool can do; get_activation returns the whole checklist. Agents are asked to offer it once, in their own words.

A failed call comes back as a tool error whose body is the API’s error: { "error": { "code", "message", "docsUrl", "details"? }, "warnings": [] }. The codes are the API’s own; each has a page under errors. Arguments that don’t match a tool’s schema get validation_failed with details for each field. A missing permission is forbidden, with details.requiredPermission.

Changes that can’t be undone

Destructive tools refuse to run without confirm: true and answer confirmation_required. remove_email_domain, archive_project and delete_project are. apply_schema and deploy take confirm: true to apply migrations that drop or rewrite data; without it they answer destructive_migration and list the changes. A deploy with critical scan findings is refused with deploy_blocked_by_scanner unless the call passes forceInsecure: { confirm: "<project slug>" }. A client should ask you before setting any of these.

For client developers

The server follows the MCP authorisation spec.

  • POST /mcp takes one JSON-RPC message and answers application/json. There are no sessions and no server-sent stream: GET and DELETE answer 405.
  • Without a valid token, /mcp answers 401 with WWW-Authenticate: Bearer resource_metadata="https://api.flatstack.dev/.well-known/oauth-protected-resource/mcp".
  • OAuth 2.1 with PKCE (S256), dynamic client registration and rotating refresh tokens. The endpoints are in OAuth for MCP clients.
  • Access tokens last an hour and only work at /mcp; /v1 refuses them. Use a personal access token for the REST API.
  • Deploy tokens can’t use /mcp.

As Markdown: apps/mcp.md