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/mcpAn 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 | shThe 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)
- Open Customize > Connectors and choose Add custom connector, or use the link on fuast.com/agents/claude, which fills in the dialog.
- Enter
https://fuast.com/mcp. - 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/mcpTo sign in, run codex mcp login fuast. It opens your browser.
Gemini CLI
gemini mcp add --transport http --scope user fuast https://fuast.com/mcpTo 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
- Open Plugins, choose +, then Add custom MCP server.
- Enter
https://fuast.com/mcpand pick OAuth as the authentication. - 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.comTo 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 returnspreview_url,claim_url,edit_token, andexpires_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 onlySend 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, andget_app_sourcework on any app you can open. - Deploying, logs, inspection,
call_app,share_app,set_env, androllback_appneed the app's owner or a workspace admin. delete_appneeds the owner.- An app you cannot see answers exactly like an app that does not exist.
Notes on single tools:
deploy_appandupdate_app_filesrun 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 thedelete_tablesargument 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_appruns as the connected person (as: "me", the default): the handler sees your identity inctx.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_appandlist_appsreport it asrestricted: true.deploy_appandupdate_app_fileswork on it like on any app you may manage, and they never lift the restriction: their result hasrestricted: true, arestricted_hintthat says workspace features are off, andtrust_commandandtrust_urlfor the person. No tool trusts an app. The owner or a workspace admin does that outside MCP, withfuast 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_sourcenever returns.envfiles, and no tool returns env values.inspect_appreturns the same manifest and usage documents asfuast 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:
- Start from a template.
list_templates, thenget_template({id, name}), returns a complete working app as{path: content}. Keep that file map and edit it. You do not needtsconfig.jsonor type declaration files. - Read what you need. The rules below cover the essentials.
fuast_docs({page: "capsule-api"})has every API, andfuast_docs({search: "..."})finds a topic. - 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 untilokis true. - Call
deploy_app({files, name}). It returns the URL and adeploy_id. Send every file. - Verify the deployed app.
call_appruns a query, mutation, or action and returns its result and logs.get_logsshows handler errors.inspect_appwithwhat: "tables"or"rows"shows the data. Read a write back instead of assuming it happened. - For a later change, call
update_app_files({app, files, expected_deploy_id})with only the files that change. Anullvalue deletes a file. If it answers that the app changed, callget_app_sourceand apply your change to what it returns. - Tell the person the URL, who can open the app, and what you checked.
Accounts:
- Without a connected account,
deploy_appdeploys a temporary preview and returnspreview_url,claim_url,edit_token, andexpires_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_tokenin this conversation and pass it instead ofapptoupdate_app_files,get_app_source,get_app,get_logs,inspect_app,call_app, andget_claim_link. Never write it into the app's files. Once the preview is claimed the token stops working: useappwith the slug. - A preview has guests only, and its schedules and jobs wait until it is claimed.
- A claimed preview is restricted (
restricted: trueinget_appand 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 withdeploy_appandupdate_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 runfuast 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 thatdeploy_appcreates private apps in their workspace.
Rules for these tools:
- New apps are private. Call
share_apponly when the person asks, and pick the narrowest mode that works. - Set secrets with
set_env({app, set: {NAME: "value"}})and read them asctx.env.NAMEin handlers. It works on apps in an account, not on previews. Never put a secret inclient/,shared/, a tool description, or a log message. call_appruns as the connected person. Mutations and actions change real data.- Call
delete_app, and passdelete_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_appisfuast check,deploy_appisfuast deploy,share_appisfuast share,call_appisfuast run,get_logsisfuast logs, andinspect_appisfuast inspectandfuast db dump. There is no local dev server, nofuast login, and no.env.fuast.serverfile: you check withcheck_appand 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
POSTwithContent-Type: application/json.GETandDELETEanswer405: there is no server-to-client stream and no session to end. A JSON-RPC batch (an array) answers400and nothing in it runs. That includes revision2025-03-26, the one revision that allowed batches. - Revisions.
2026-07-28(stateless: the version, client info, and capabilities travel in every request's_metaand in theMCP-Protocol-Version,Mcp-Method, andMcp-Nameheaders), and2025-11-25,2025-06-18, and2025-03-26through theinitializehandshake. An unsupported version answers400with the list of supported ones. - No sessions. The server never sends
Mcp-Session-Idand remembers nothing between requests. - Methods.
initialize,ping,server/discover,tools/list,tools/call.subscriptions/listenis 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, andupdate_app_filesswitch to atext/event-streamresponse after 5 seconds when the client'sAcceptheader 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
401withWWW-Authenticate: Bearer error="invalid_token", resource_metadata="...", scope="...". A call that needs a scope the connection lacks answers403witherror="insufficient_scope". Both bodies are also a tool result with the challenge under_meta["mcp/www_authenticate"]. Each entry oftools/listcarries_meta.securitySchemes(noauth,oauth2with scopes). - Browsers. A request with an
Originheader from another website is refused with403. 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_supportedis["none"]. - PKCE is required, with
code_challenge_method=S256. - Client identity. Either a Client ID Metadata Document (the
client_idis anhttpsURL with a path, and the document must name the sameclient_idand allow thenoneauth method), or dynamic client registration atPOST /oauth/register(JSON,redirect_urisrequired,token_endpoint_auth_methodnone). - Redirect URIs.
https, orhttponlocalhost,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 wrongresponse_type, or a foreignresourcegets a fuast error page that names the OAuth error code. Your redirect URI is only ever called with acode, or witherror=access_deniedwhen the person chose Cancel. resource. When sent, it must be the MCP URL above. Tokens are issued for that resource and for nothing else.stateis echoed. Every authorization response, errors included, carriesiss(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/tokenand/oauth/revoketakeapplication/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_nameas 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 ashttps://my-app.fuast.com/mcpis the app, not this server. A404on 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
401challenge. Connect with an API token header instead. 401after 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_sourceand 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.supportedlists the revisions this server speaks. 403from a web page. Browser pages on other sites cannot call the server. Use an MCP client.- A
fuast logintoken does not work as a header. Create an API token withfuast token create.