MCP server and email-code sign-up
An AI agent or a script can do everything a person does on aipps.dev: make an account, add an app, start a build, read the log and hand back the install page with its QR code. No browser and no password. Builds use the account and the store keys of the person who owns the app.
Sign up with an email code
Send an email address and aipps.dev emails a 6-digit code. Send the email and the code back and you get a session key. A new email gets a free account right there; an email that already has one signs in to it, and the same account opens in the console later.
curl -s https://aipps.dev/api/auth -H 'content-type: application/json' \
-d '{"email":"you@example.com"}'
# {"otp_sent": true, "expires_in_seconds": 600, ...}
curl -s https://aipps.dev/api/auth -H 'content-type: application/json' \
-d '{"email":"you@example.com","otp":"123456"}'
# {"session_key": "ais_...", "token_type": "Bearer", "expires_at": "...", "email": "you@example.com"}- Send the key as
Authorization: Bearer ais_…on every later call, REST or MCP. It lasts 30 days. - Codes last 10 minutes and allow 5 tries; at most 3 codes per email in 15 minutes.
- Already have an API key (
ak_…, from the console under Keys)? Send it asX-Api-Keyor as the Bearer token, or trade it:{"api_key":"ak_..."}. - Sign out:
POST /api/auth/logoutwith the session key inAuthorization. - The address needs a real mailbox: throwaway email domains are refused.
MCP server
https://aipps.dev/api/mcp speaks the Model Context Protocol over Streamable HTTP (JSON-RPC 2.0 on POST; protocol versions 2024-11-05, 2025-03-26 and 2025-06-18). initialize and tools/list need no sign-in, so an agent can find the tools first and call auth to sign up. Agents that use plain function calling can read the same tools as JSON schemas at /api/mcp/schema.
Client setup
Most MCP clients take a block like this in their settings (the file name depends on the client):
{
"mcpServers": {
"aipps": {
"url": "https://aipps.dev/api/mcp",
"headers": { "Authorization": "Bearer ak_your_api_key" }
}
}
}Leave out headers to start signed out: the agent calls auth with your email, asks you for the code, and sends the session key it gets back. Clients that can't set headers can use that path too.
curl
curl -s https://aipps.dev/api/mcp -H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
curl -s https://aipps.dev/api/mcp -H 'content-type: application/json' \
-H 'Authorization: Bearer ais_...' \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call",
"params":{"name":"start_build","arguments":{"app":"checklists","platform":"android"}}}'A tool result comes back as text holding JSON in result.content[0].text. When a call fails the result has isError: true and the text is {"error", "status", "message"}, for example wrong_code or 401 when you aren't signed in.
Tools
| Tool | Arguments (* required) | What it does |
|---|---|---|
auth | email, otp, api_key | Sign up or sign in. {email} emails a 6-digit code; {email, otp} returns a session key. Or trade an API key for one. |
get_pricing | – | Free builds a day, what a build pack adds, build size classes. No sign-in needed. |
get_account | – | Email, build packs and today's usage (allowance, counted, pending, left). |
list_apps | – | Your apps: slug, name, framework, iOS bundle id, Android package. |
create_app | name*, slug, framework, ios_bundle_id, android_package | Adds an app. Do it once per project; start_build takes its slug. |
start_build | app*, platform*, profile, message, submit | Starts a build and returns upload_url: PUT the project .tar.gz there and it joins the queue. |
list_builds | app, limit | Recent builds, newest first. |
get_build | build_id* | Status (waiting_source, queued, running, succeeded, failed, canceled); install_url and qr_url once it has succeeded. |
get_build_logs | build_id*, offset | Log text from offset; call again with next_offset until done is true. |
cancel_build | build_id* | Stops a build. Nothing is counted if it hadn't started. |
list_updates | app*, channel | An Expo app's over-the-air updates, newest first, and url for app.json updates.url. Publishing is npx aipps update. |
rollback_update | app*, channel, to, runtime_version, platform, message | to=embedded (needs runtime_version): back to the bundle inside the build. to=<update or group id>: publish it again, or promote it to another channel. |
A build, step by step
authwith the person's email, then again with the code they read out (or use their API key).create_apponce with the app's name, framework and bundle id / package.start_buildwith the slug andandroidorios.- Pack the project as one
.tar.gz(git-tracked files, nonode_modules, no.envor keys) andPUTit toupload_urlwith the sameAuthorizationheader. Or runnpx aipps buildin the project instead of steps 3 and 4. get_buildevery 20 to 30 seconds (or followget_build_logs) until the status issucceeded, then give the personinstall_url. A failed build'serrorsays why.
Signed iPhone builds and store uploads use the owner's own App Store Connect key and Play service account, kept encrypted on the app (see iPhone builds). aipps.dev never asks for an Apple or Google password.
Errors and limits
MCP builds count like any other build: 3 a day are free across all your apps, and a build pack adds more (see get_pricing or the pricing page). A build that would go over today's allowance is refused with a message saying so; nothing is counted for builds that never start.