Browse the docs

Start

MCP server

Connect Claude, ChatGPT, Cursor, VS Code, or Claude Code to fuast over MCP. Build, check, deploy, inspect, and share apps from an agent that has no terminal. Setup per client, sign-in, every tool, limits, and OAuth details.

fuast has a remote Model Context Protocol server at:

https://fuast.com/mcp

An agent that connects to it can read the docs, start from a template, check an app, deploy it, test it, read its logs and data, and share it. The agent needs no terminal and no file system: it sends and receives file contents. Agents that do have a terminal can keep using the CLI. See the agent start guide.

On a self-hosted platform the URL is <FUAST_BASE_URL>/mcp.

Connect your agent

The server URL is the same for every client. The first time a tool needs your account, the client opens a fuast sign-in page in your browser. fuast.com/agents has a page per client, with one-click links for Claude, Cursor, and VS Code.

One command for coding agents

curl -fsSL fuast.com/install | sh

The script connects this server to Claude Code, Codex, and Gemini CLI, whichever are installed, and saves the fuast skill where each one reads skills. It creates no account and deploys nothing, and you can read it first. Run it again to update the skill.

Claude (web, desktop, mobile)

  1. Open Customize > Connectors and choose Add custom connector, or use the link on fuast.com/agents/claude, which fills in the dialog.
  2. Enter https://fuast.com/mcp.
  3. Ask Claude to build something. When it reaches a tool that needs your account, choose Connect and approve.

Claude Code

claude mcp add --transport http --scope user fuast https://fuast.com/mcp

--scope user makes the server available in every folder. Without it, Claude Code adds the server for the current folder only. Run /mcp inside Claude Code to sign in. To use a token instead of the browser sign-in:

claude mcp add --transport http --scope user fuast https://fuast.com/mcp \
  --header "Authorization: Bearer $FUAST_TOKEN"

Codex

codex mcp add fuast --url https://fuast.com/mcp

To sign in, run codex mcp login fuast. It opens your browser.

Gemini CLI

gemini mcp add --transport http --scope user fuast https://fuast.com/mcp

To sign in, run /mcp auth fuast inside Gemini CLI.

Cursor

Use the Add to Cursor link on fuast.com/agents/cursor, or add this to .cursor/mcp.json in a project, or ~/.cursor/mcp.json for every project:

{
  "mcpServers": {
    "fuast": { "url": "https://fuast.com/mcp" }
  }
}

With a token instead of the browser sign-in:

{
  "mcpServers": {
    "fuast": {
      "url": "https://fuast.com/mcp",
      "headers": { "Authorization": "Bearer ${env:FUAST_TOKEN}" }
    }
  }
}

VS Code

Use the Add to VS Code link on fuast.com/agents/vscode, or add this to .vscode/mcp.json:

{
  "servers": {
    "fuast": { "type": "http", "url": "https://fuast.com/mcp" }
  }
}

ChatGPT

  1. Open Plugins, choose +, then Add custom MCP server.
  2. Enter https://fuast.com/mcp and pick OAuth as the authentication.
  3. Create it, then sign in to fuast when ChatGPT asks.

Any other client

Use Streamable HTTP with the URL above. The client needs to support OAuth for remote MCP servers, or let you set an Authorization header.

The server is described for the MCP registry at fuast.com/server.json.

The fuast skill

A skill is a short instruction file a coding agent loads when a request matches it. The fuast skill tells the agent when fuast fits ("make a little app for my team"), how to build and deploy with the CLI or with this server, and the rules agents most often get wrong. Read it at fuast.com/skill.md.

The install script saves it for Claude Code, Codex, and Gemini CLI. For Cursor, GitHub Copilot, and other agents that read skills:

npx skills add https://fuast.com

To add it by hand, save the file as fuast-build-and-host-small-apps/SKILL.md in the agent's skills folder, for example ~/.claude/skills/fuast-build-and-host-small-apps/SKILL.md for Claude Code. The long name is on purpose: an agent with many skills installed often sees only their names, so the name has to say what the skill is for.

A capsule made with fuast new or fuast init also carries an AGENTS.md with the rules for that version of fuast. The skill gets the agent to fuast; AGENTS.md is what it follows once it is in the project.

Three ways to authenticate

The server reads who is calling from the Authorization: Bearer header only. It never reads cookies.

No account

A connection without credentials can still ship something:

  • fuast_guide, fuast_docs, list_templates, get_template: read the docs and the starter apps.
  • check_app: build and type check files without deploying.
  • deploy_app: deploy a temporary preview. It returns preview_url, claim_url, edit_token, and expires_at.

Give the claim link to the person the app is for. They open it, sign in to fuast, and the app becomes theirs. The agent keeps the edit token and passes it as edit_token to update_app_files, get_app_source, get_app, get_logs, inspect_app, call_app, and get_claim_link to keep working on that preview.

A preview is not a full app. It is deleted at expires_at (72 hours after it was created, by default) unless someone claims it. It has no accounts, so every visitor is a guest. Its schedules and jobs wait until it is claimed. Its upload and data limits are smaller: the deploy result lists them under limits, and limits explains them. The edit token is a secret: keep it in the conversation, never in the app's files. After a claim it stops working, and the app is reached through the owner's account.

Previews exist only on platforms that serve each app on its own subdomain, which fuast.com does.

Sign in with your fuast account (OAuth)

Tools that work on your apps need your account. The first call to one of them answers HTTP 401 with a WWW-Authenticate header, and the client starts sign-in: you sign in to fuast, read a consent screen that names the app, where it sends you back to, your workspace, and what it may do, and approve. The client then repeats the call. To sign in before deploying, ask the agent to call whoami.

A connection gets only the scopes you approved:

Scope Lets the agent
apps:read List your apps and read their source, logs, data, and usage. Run queries with call_app.
apps:write Deploy, roll back, and delete apps, set their env vars, and run mutations and actions with call_app.
apps:share Change who can open an app and invite people by email.

The challenge names the scopes the call needs, so a client that follows it asks for the least. A request without any scope gets apps:read. When a later call needs a scope the connection lacks, the server answers 403 with error="insufficient_scope" and the full list to ask for, and the client asks you to approve the larger set.

A signed-in connection acts as you, with your permissions, and only through these tools. Its token is not accepted by the fuast API or by any app.

API token

Clients that take a static header can send a fuast API token:

fuast token create --name my-agent          # personal: everything you can do
fuast token create --name ci --app my-app   # app deploy token: one app only

Send it as Authorization: Bearer <token>. A personal token can use every tool. An app deploy token can deploy, roll back, and read the status of its own app, and nothing else: it sees a shorter tool list, deploy_app and update_app_files must name its app, and inspect_app gives it manifest, usage, and schedules only. The session that fuast login saves is not accepted here. See account and tokens.

Deploying into an account needs a verified email address. Until then deploys answer Verify your email address first. Check your inbox for the link.

Tools

Every tool returns text and the same data as structuredContent, with an outputSchema. Arguments are checked against the tool's inputSchema, and unknown arguments are refused. A failure the agent can fix comes back as a tool result with isError: true and a message that says what to do.

"Account" is what the tool needs when it is called with app. Tools that also take edit_token work on a preview without an account.

Tool What it does Account Kind
fuast_guide The guide for connected agents and the capsule rules. Call it first. No Read-only
fuast_docs Read one docs page (page), search every page (search), or list the pages. No Read-only
list_templates The starter apps and what each one shows. No Read-only
get_template One template's files as {path: content}, named with name. No Read-only
check_app Build, type check, and load files in a sandbox without deploying. Returns the handlers and tables the app declares, or diagnostics with file, line, and message. No Read-only
deploy_app Deploy files. Creates a private app in your workspace, updates app, or (without an account) deploys a preview. Updates a preview with edit_token. apps:write, or none for a preview Destructive
get_app_source The live deploy's source as {path: content} and its deploy_id. Apps over 400 KiB return the file list: ask again with paths. Takes app or edit_token. apps:read Read-only
update_app_files Redeploy with some files changed: files maps a path to new content, or to null to delete it. expected_deploy_id must be the live deploy. Takes app or edit_token. apps:write Destructive
list_apps The apps you can use: yours, your workspace's, and apps shared with you. apps:read Read-only
get_app One app: URL, status, sharing, handlers, the last 10 deploys, today's usage, env var names. Takes app or edit_token. apps:read Read-only
get_logs Recent log entries, oldest first, with a cursor for the next call. level, since, limit (at most 200). Takes app or edit_token. apps:read Read-only
inspect_app what: manifest, tables, rows (one table, at most 100 rows per call), usage, schedules, or jobs. Takes app or edit_token. apps:read Read-only
call_app Run one query, mutation, or action and return its result and the log lines it wrote. Takes app or edit_token. apps:read for a query, apps:write for a mutation or action Destructive
share_app Set visibility (private, workspace, public), invite people by email, remove people. apps:share Destructive
set_env set and unset env vars of an app. Values are write-only. apps:write Destructive
rollback_app Make an earlier deploy live again (deploy_id, or the previous ready deploy). apps:write Destructive
delete_app Delete an app and everything in it. Owner only, and confirm must repeat the slug. apps:write Destructive
get_claim_link The claim link, preview link, and expiry of a preview, from its edit_token. No Read-only
whoami The connected account, workspace, role, and scopes. Starts sign-in when nothing is connected. apps:read Read-only

Who may do what is the same as in the dashboard and the CLI:

  • Opening an app follows its sharing. list_apps, get_app, and get_app_source work on any app you can open.
  • Deploying, logs, inspection, call_app, share_app, set_env, and rollback_app need the app's owner or a workspace admin.
  • delete_app needs the owner.
  • An app you cannot see answers exactly like an app that does not exist.

Notes on single tools:

  • deploy_app and update_app_files run the normal deploy pipeline: the same checks, the same sandboxed build, and a type check that cannot be skipped. A failed build deploys nothing. If a schema change would delete a table that holds rows, the error names the tables and the delete_tables argument that confirms it. A redeploy of an app in your account keeps the env values the previous deploy carried. A redeploy of a preview by its edit token starts with no env.
  • call_app runs as the connected person (as: "me", the default): the handler sees your identity in ctx.auth, exactly as if you had opened the app. It never runs as another user. as: "guest" runs it as a guest visitor, and works only on public apps that do not require sign-in. On a preview every call runs as one guest. Calls count against the app's daily quota, and mutations and actions change real data.
  • Restricted apps. An app that was claimed from a preview is restricted until its owner trusts it: email, team tables, the member list, schedules, and jobs are off. get_app and list_apps report it as restricted: true. deploy_app and update_app_files work on it like on any app you may manage, and they never lift the restriction: their result has restricted: true, a restricted_hint that says workspace features are off, and trust_command and trust_url for the person. No tool trusts an app. The owner or a workspace admin does that outside MCP, with fuast trust <slug> or "Trust this app with my workspace" on the app's page in the dashboard. A preview's edit token stops working at the claim.
  • get_app_source never returns .env files, and no tool returns env values.
  • inspect_app returns the same manifest and usage documents as fuast inspect. Rows are capped per call and open to the owner and workspace admins only, like the dashboard's Data tab.

Guide for connected agents

You are connected to fuast through MCP. You have no terminal and no file system here: you build an app by sending its files to these tools. A fuast app (a capsule) is a small full-stack TypeScript app with server/index.ts, client/index.tsx, and optional shared/ files. It uses no npm packages.

Work in this order:

  1. Start from a template. list_templates, then get_template({id, name}), returns a complete working app as {path: content}. Keep that file map and edit it. You do not need tsconfig.json or type declaration files.
  2. Read what you need. The rules below cover the essentials. fuast_docs({page: "capsule-api"}) has every API, and fuast_docs({search: "..."}) finds a topic.
  3. Call check_app({files}). It builds and type checks without deploying. Fix every diagnostic (each has a file, a line, and a message) and check again until ok is true.
  4. Call deploy_app({files, name}). It returns the URL and a deploy_id. Send every file.
  5. Verify the deployed app. call_app runs a query, mutation, or action and returns its result and logs. get_logs shows handler errors. inspect_app with what: "tables" or "rows" shows the data. Read a write back instead of assuming it happened.
  6. For a later change, call update_app_files({app, files, expected_deploy_id}) with only the files that change. A null value deletes a file. If it answers that the app changed, call get_app_source and apply your change to what it returns.
  7. Tell the person the URL, who can open the app, and what you checked.

Accounts:

  • Without a connected account, deploy_app deploys a temporary preview and returns preview_url, claim_url, edit_token, and expires_at. Give the person the claim link: they open it, sign in, and the app becomes theirs. Say when the preview is deleted if nobody claims it.
  • Keep edit_token in this conversation and pass it instead of app to update_app_files, get_app_source, get_app, get_logs, inspect_app, call_app, and get_claim_link. Never write it into the app's files. Once the preview is claimed the token stops working: use app with the slug.
  • A preview has guests only, and its schedules and jobs wait until it is claimed.
  • A claimed preview is restricted (restricted: true in get_app and in every deploy result): email, team tables, the member list, schedules, and jobs stay off until the owner trusts the app. You can keep deploying to it with deploy_app and update_app_files; that does not turn them on, and no tool does. If the app needs them, tell the person to press "Trust this app with my workspace" on the app's page (trust_url) or to run fuast trust <slug>.
  • If the person has a fuast account, or wants the app in their own workspace, call whoami. The first call asks them to sign in. After that deploy_app creates private apps in their workspace.

Rules for these tools:

  • New apps are private. Call share_app only when the person asks, and pick the narrowest mode that works.
  • Set secrets with set_env({app, set: {NAME: "value"}}) and read them as ctx.env.NAME in handlers. It works on apps in an account, not on previews. Never put a secret in client/, shared/, a tool description, or a log message.
  • call_app runs as the connected person. Mutations and actions change real data.
  • Call delete_app, and pass delete_tables, only when the person explicitly asks for data to be deleted.
  • The sections below were written for the fuast CLI. Here the tools replace it: check_app is fuast check, deploy_app is fuast deploy, share_app is fuast share, call_app is fuast run, get_logs is fuast logs, and inspect_app is fuast inspect and fuast db dump. There is no local dev server, no fuast login, and no .env.fuast.server file: you check with check_app and test against the deployed app.

Limits

Limit Value
Requests without an account 60 per minute per client address
Requests with an account 600 per minute per account
check_app, deploy_app, update_app_files 30 per minute per client address
check_app without an account 12 per minute per client address, 4 running at once across the platform
Builds running at once (check_app, deploy_app, update_app_files) 3 per account, 2 per client address without an account
call_app 600 per minute per client address, plus the app's daily quotas
Requests with a wrong token 30 per 10 minutes per client address, then 429
Request body, calls without a file map 256 KiB
File map, signed in The deploy limits: 1000 files, 20 MiB in total, 1 MiB per file
File map, no account The smaller preview limits. The error states them.
get_app_source without paths 400 KiB of source. Larger apps return the file list only.
call_app result 200 KiB of JSON. Larger results are cut and marked truncated.

A client address is an IPv4 address, or a whole IPv6 /64. Over one of the first two limits the server answers 429 with Retry-After, and a platform operator can change them. Over a per-tool limit the tool returns an error that says to wait. See limits for what an app itself may use.

Protocol

  • Transport. Streamable HTTP on one endpoint. Send each JSON-RPC message as its own POST with Content-Type: application/json. GET and DELETE answer 405: there is no server-to-client stream and no session to end. A JSON-RPC batch (an array) answers 400 and nothing in it runs. That includes revision 2025-03-26, the one revision that allowed batches.
  • Revisions. 2026-07-28 (stateless: the version, client info, and capabilities travel in every request's _meta and in the MCP-Protocol-Version, Mcp-Method, and Mcp-Name headers), and 2025-11-25, 2025-06-18, and 2025-03-26 through the initialize handshake. An unsupported version answers 400 with the list of supported ones.
  • No sessions. The server never sends Mcp-Session-Id and remembers nothing between requests.
  • Methods. initialize, ping, server/discover, tools/list, tools/call. subscriptions/listen is acknowledged and closed at once, because the tool list does not change while a client listens. There are no resources and no prompts.
  • Responses. A single JSON object. A build can take a while, so check_app, deploy_app, and update_app_files switch to a text/event-stream response after 5 seconds when the client's Accept header allows it. The stream carries keep-alive comments, then the one JSON-RPC response, and ends.
  • Sign-in signals. A call that needs an account answers 401 with WWW-Authenticate: Bearer error="invalid_token", resource_metadata="...", scope="...". A call that needs a scope the connection lacks answers 403 with error="insufficient_scope". Both bodies are also a tool result with the challenge under _meta["mcp/www_authenticate"]. Each entry of tools/list carries _meta.securitySchemes (noauth, oauth2 with scopes).
  • Browsers. A request with an Origin header from another website is refused with 403. See security.

OAuth for client builders

Protected resource metadata https://fuast.com/.well-known/oauth-protected-resource/mcp and https://fuast.com/.well-known/oauth-protected-resource
Authorization server metadata https://fuast.com/.well-known/oauth-authorization-server
Issuer https://fuast.com
Resource https://fuast.com/mcp
Endpoints /oauth/authorize, /oauth/token, /oauth/register, /oauth/revoke
  • Grants. Authorization code and refresh token.
  • Public clients only. There are no client secrets. token_endpoint_auth_methods_supported is ["none"].
  • PKCE is required, with code_challenge_method=S256.
  • Client identity. Either a Client ID Metadata Document (the client_id is an https URL with a path, and the document must name the same client_id and allow the none auth method), or dynamic client registration at POST /oauth/register (JSON, redirect_uris required, token_endpoint_auth_method none).
  • Redirect URIs. https, or http on localhost, 127.0.0.1, or [::1]. They are matched exactly. A loopback URI matches with any port, so a native client can bind a free one. No wildcards, fragments, or credentials. A redirect URI on fuast's own addresses (fuast.com, any *.fuast.com, a custom domain of a fuast app) is refused: use your own site.
  • Errors before consent are shown to the person, not redirected. A request with a missing code_challenge, a wrong response_type, or a foreign resource gets a fuast error page that names the OAuth error code. Your redirect URI is only ever called with a code, or with error=access_denied when the person chose Cancel.
  • resource. When sent, it must be the MCP URL above. Tokens are issued for that resource and for nothing else.
  • state is echoed. Every authorization response, errors included, carries iss (RFC 9207).
  • Authorization codes work once and for 60 seconds, and only with the same client, redirect URI, and PKCE verifier.
  • Access tokens last 1 hour. Refresh tokens last 30 days and rotate: each use returns a new one and ends the old one. Using an old one again ends the whole connection, and the token endpoint answers invalid_grant.
  • POST /oauth/token and /oauth/revoke take application/x-www-form-urlencoded. Revoking either token of a connection ends the connection.
  • Consent is asked on every authorization. There is no silent approval. The screen shows your redirect host as a checked fact and your client_name as a name you chose. A client whose metadata document is on a well-known host is shown as verified by that host.

Disconnect an agent

Open API tokens in the dashboard and find Connected agents, or open /dashboard/connect. Each connection shows the app's name, where it sends you back to, its scopes, and when it was last used. Disconnect ends it at once: its access and refresh tokens stop working. Removing the connector in the agent's own settings also works when the client tells fuast.

API tokens are revoked on the same page, or with fuast token revoke <id>.

Resetting your fuast password disconnects every agent and revokes every API token at once. Do that if you think a connection or a token leaked, then connect again.

What agents did through MCP is recorded: every deploy, share, env change, rollback, delete, and mutation or action run, plus each connect and disconnect. Deploys and other changes also show in the app's logs with the client's name.

Troubleshooting

  • The client cannot reach the server. Check the URL: https://fuast.com/mcp, on the dashboard's host. An app's address such as https://my-app.fuast.com/mcp is the app, not this server. A 404 on the right host means the platform has the MCP server turned off.
  • A tool answers "Sign in to fuast to use ..." and no sign-in page opens. The client does not act on the 401 challenge. Connect with an API token header instead.
  • 401 after it worked before. The connection was revoked, the account's password was reset, or the refresh token ran out after 30 days without use. Connect again.
  • "needs the apps:write permission". The connection was approved with fewer scopes. Approve the larger set when the client asks, or remove the connector and add it again.
  • "Verify your email address first." Open the link fuast mailed you, then deploy again.
  • "changed since you read it". Someone deployed between your read and your update. Call get_app_source and apply the change to those files.
  • "This edit token does not open a preview". The preview expired, was deleted, or was claimed. Deploy a new preview, or sign in as the owner and use app.
  • "Unsupported protocol version". The error's data.supported lists the revisions this server speaks.
  • 403 from a web page. Browser pages on other sites cannot call the server. Use an MCP client.
  • A fuast login token does not work as a header. Create an API token with fuast token create.