RunApps via MCP
RunApps (https://www.runapps.ai) publishes AI web apps: a creator uploads a static frontend bundle (zip), it is served on its own https://<slug>.runapps.dev, users sign in with one RunApps account and pay for their own model usage, and the creator earns a fee on every call. Everything below is done through the runapps MCP server and the SDK. Not connected yet? See "Connecting".
This file is the entry point: connecting, the platform model, the tool catalogue, the workflow and the rules. The SDK (how the app code talks to models and files) is references/sdk.md; exact tool parameters are references/tools.md. Read only what the task needs.
Connecting (authorization)
The authoritative, always-current version is https://www.runapps.ai/agent/setup.md; this is the short form. The user never types a password for you and you never see one: you ask for a key, the user clicks Approve once in a browser.
- Request a key:
POST https://www.runapps.ai/api/agent/device/codewith JSON{"name": "<your name> @ <machine>", "scopes": "read,develop,publish,gateway"}. The response hasdevice_code,user_code,verification_uri_complete(https://www.runapps.ai/agent/authorize?code=XXXX-XXXX),expires_in(600 s) andinterval(5 s). Showverification_uri_completeto the user verbatim and ask them to open it and approve.nameis the key's identity: approving a request with the same name revokes the previous key of that name, so re-running setup does not pile keys up. - Poll:
POST https://www.runapps.ai/api/agent/device/tokenwith{"device_code": "…"}everyintervalseconds.statusispending(wait),slow_down(back off),denied/expired(stop and tell the user) orapproved, which returnsapi_key(rk_…),key_prefix,scopesandmcp_url— once. Write it into your MCP configuration immediately; never into the conversation, logs or a repository. - Connect: MCP Streamable HTTP at
https://www.runapps.ai/api/mcpwith headerAuthorization: Bearer <api_key>. Claude Code:claude mcp add --transport http runapps "https://www.runapps.ai/api/mcp" --header "Authorization: Bearer <api_key>". Codex:[mcp_servers.runapps] url = "https://www.runapps.ai/api/mcp",http_headers = { Authorization = "Bearer <api_key>" }. Other clients: the same URL and header. Thentools/list; theinstructionsfrominitializegive the recommended workflow.
Scopes: read, develop, publish, gateway are granted by default; danger (delete / unpublish) is never included unless you ask for it explicitly and tell the user why. The user can untick scopes on the approval page, and later rename the key, change its scopes or revoke it at https://www.runapps.ai/dashboard/api (a scope change applies to your next call, no new key needed). A tool called without its scope answers with an error naming the scope: ask the user to authorize again, do not work around it.
The same key works at the gateway (https://www.runapps.ai/v1, OpenAI-compatible, Authorization: Bearer rk_…) when it has the gateway scope — for testing the app you build; each call is billed to the user. To disconnect for good, call revoke_my_key with confirm: true.
The platform model
| Object | What it is | How you reach it |
|---|---|---|
| App (project) | A published bundle with a platform-assigned slug, name, one-line description, Markdown long description, category, icon, visibility and creator fee (rebate_rate). Created as a draft with no bundle, so the slug exists before any code does. | list_apps, get_app, create_app, update_app |
| Bundle | The zip of the app's build. Stored whole; files are served out of it on https://<slug>.runapps.dev. Dot files (.private/…) are never served; index.html at the zip root is the default entry. | upload_bundle (+ PUT), upload_bundle_base64, check_bundle |
| Visibility | draft (only the creator) → private (unlisted: anyone with the link, no review) or public (in the library; the first move to public is reviewed and shows as pending, later updates are live at once; a rejection carries a review_note). | update_app with visibility, get_review |
| User & sign-in | Users sign in with their RunApps account inside the app (the SDK does it; new RunApps() with no key). Each user pays their own model usage plus the creator fee. The app never holds a key. | SDK (references/sdk.md) |
| Private prompts | Prompt files the app ships but browsers never see: .private/prompts/<id>.md in the zip; the app sends prompt: { id, vars } and the gateway fills and prepends it. | get_app / check_bundle list the ids found |
| Per-user files & sync | Each user has a file space per app (client.files), and an IndexedDB sync (client.sync) mirrors a local database into it. | SDK |
| Models | A catalogue of chat, vision, image, speech, transcription, video, embedding and realtime models; the request names the model by its catalogue name. | list_models |
| Agent key | The rk_ key you hold: kind = agent, scoped; listed under the user's API Keys. | revoke_my_key |
Categories: Creative, Content, Productivity, Marketing, Engineering, Design, Research, Data Analysis, Business, Finance.
Workflow
- Create:
create_appwithname(anddescription,category). The result hasslug(proj-xxxxxxxx, assigned by the platform and never chosen by you or the user; an admin may later give a listed app a readable one) andurl. Tell the user the slug. - Develop locally against the slug (
references/sdk.md, "Build an app"):Sign-in from<script src="https://www.runapps.ai/sdk/latest.js"></script> <script> const client = new RunApps({ project: "<slug>" }); const r = await client.chat.create({ model: "Claude Sonnet 4.6", messages: [{ role: "user", content: "hi" }] }); </script>http://localhost:<port>works and calls go through the real gateway. Pick models fromlist_models(exact names). Never put anrk_key in app code. - Build and zip the contents of the build folder:
cd dist && zip -r ../app.zip .soindex.htmlis at the zip root (zipping the folder itself is the most common mistake). Absolute asset paths work; dot folders are hidden. - Upload:
upload_bundle→PUTthe zip toupload_url(curl -sS -X PUT -H 'Content-Type: application/zip' --data-binary @app.zip '<upload_url>'). The PUT response is the bundle report: fix every warning (SDK not loaded, entry not at root, a key in the page).check_bundlere-reads it any time. - Describe:
update_appwithdescription(one line, what it does),long_description(Markdown: what the user gets, how to use it, what it costs in practice),category,icon_url(square PNG/SVG, https or data URL). - Ship:
update_appvisibility: "private"for a link to share, or"public"for the library. After"public",get_reviewshowspendinguntil a reviewer decides;rejectedcomes with areview_noteto act on, then setpublicagain. Openurlyourself (or ask the user to) before publishing: a bundle that 404s or shows a blank page will be rejected.
Updates: upload a new bundle or change metadata any time; a public app stays public.
Rules
[danger]tools (unpublish_app,delete_app) remove something other people may be using. Ask the user first and passconfirm: trueonly after they agree; without thedangerscope they are refused anyway.- Every model call made with the
gatewayscope, and every call the user's app makes, costs real money. Test with short prompts and cheap models;list_modelsgives prices. - The key is the user's: one per machine (the
namedistinguishes them), never shared, never written anywhere but the MCP config. Revoke withrevoke_my_keywhen asked to disconnect. - Do not invent model names; use
list_models. An unknown name is a 400, never a silent swap. - A private prompt's text must stay private: the gateway withholds replies that echo it.
Where to read next
| Task | Read |
|---|---|
| Writing the app: sign-in, chat, streaming, images, audio, video, files, sync, private prompts, errors | references/sdk.md |
| Exact tool parameters and result shapes | references/tools.md |
| Connecting (full text, always current) | https://www.runapps.ai/agent/setup.md |
| Building a bundle, publishing, earnings | references/sdk.md → "Build an app", "Publish it" |