# Jigsaw: the complete guide for agents > Jigsaw is a cloud for small software. An AI agent, or a person with a zip file, publishes a small web app. Jigsaw hosts it at its own address, signs every visitor in, and lets the owner share it by email with viewer and editor roles, the way you share a doc. ## Key facts - Site: https://jigsawapps.com. Each published app gets its own address: https://.onjigsaw.app. - Every app is private. Only the owner and the people they add by email can open it. There are no public links. - Roles: owner, editor, viewer. Jigsaw signs each visitor in and tells the app who they are, so apps contain no login code. - Two kinds of app. A page: static files that use Jigsaw's built-in data API and key proxy. An app with its own server: a Node app in its own machine, asleep when idle, with its own disk. - Agents publish through a remote MCP server at https://jigsawapps.com/mcp, or the HTTP API at https://jigsawapps.com/api/publish. People can upload a zip. - Secret API keys are pasted by the owner, stored encrypted, and added by Jigsaw on the server side. They never reach the browser. - Teams: a team owns its apps, so they stay when a person leaves. Admins and builders manage them; one bill for the team. - Pricing: Free: 3 page apps, each shared with up to 5 people. Individual: $9 a month or $90 a year, for 10 apps (up to 3 with their own server), each shared with up to 25 people. Team: $19 a month for each builder, for apps the team owns together. Prices include tax. The people an app is shared with never pay. ## Connecting Remote MCP server: https://jigsawapps.com/mcp (Streamable HTTP). Tools: publish_app, get_upload_link, list_apps. Authorisation: sign in when the agent's app asks, or send "Authorization: Bearer ". The person creates a publish token at https://jigsawapps.com/publish. Adding it to an agent's app. Each one opens a sign-in page; sign in with your Jigsaw email. Claude: Settings, Connectors, Add custom connector, then paste the address. Claude Code: claude mcp add --transport http jigsaw https://jigsawapps.com/mcp then /mcp to sign in. ChatGPT: turn on developer mode in Settings, under Apps, then add a custom app with the address. Cursor: in ~/.cursor/mcp.json put { "mcpServers": { "jigsaw": { "url": "https://jigsawapps.com/mcp" } } } VS Code: code --add-mcp '{"name":"jigsaw","type":"http","url":"https://jigsawapps.com/mcp"}' HTTP API, for agents without MCP: POST https://jigsawapps.com/api/publish Authorization: Bearer Content-Type: application/json { "slug": "shift-rota", "files": [{ "path": "index.html", "content": "..." }] } Binary files use "contentBase64" in place of "content". A zip can be sent instead: Content-Type: application/zip, with ?slug=shift-rota. Add "team": "" to publish a new app into a team the person builds for. The answer gives the app's address. Publishing again under the same name makes a new version. ## Building an app for Jigsaw Jigsaw hosts small apps and shares them by email, like a doc. To publish: - If you can run shell commands, call get_upload_link and run the command it gives you. It uploads the app's folder from disk, so you do not retype the files. Always prefer this. - If you cannot run commands, use publish_app and pass every file. Build for the LIGHT LANE unless the app truly needs its own server: - A light-lane app is static files with an index.html at the top level. No build step, no server code, no login code. - Jigsaw signs every visitor in before the page loads. Call GET /_jigsaw/me for { email, role }. Role is "owner", "editor" or "viewer". The visitor can change data when the role is "owner" or "editor". - The page may use inline or external scripts and styles; Jigsaw adds no content policy to an app's own files. Refer to Jigsaw's API with paths that start with a slash, as written here. - Store data with Jigsaw's data API, on the app's own address, using fetch with no extra headers: GET /_jigsaw/data/ -> { records: [{ id, data, createdBy, createdAt, updatedAt }] } POST /_jigsaw/data/ body: any JSON object -> the new record GET /_jigsaw/data// PUT /_jigsaw/data// body: the replacement JSON object DELETE /_jigsaw/data// is a lowercase name you choose, like "tasks". Send JSON with Content-Type: application/json. A record is { id, data, createdBy, createdAt, updatedAt }: data is exactly the object you sent, createdBy is an email, the dates are ISO strings. POST answers 201 with the new record. PUT answers 200 with the updated record; it replaces the whole object, so to change one field send the old data with that field changed. DELETE answers 204 with no body. A list returns records oldest first, up to 1000 at a time (or ?limit=N), with "next": when it is not null, ask again with ?after= for the following page. A record can be up to 100 KB. The data belongs to the app: everyone with access sees the same lists. Errors answer with a status of 400 or above and { "error": "what went wrong" }. Jigsaw enforces roles: viewers can read, editors and the owner can write. A viewer's write gets 403, so hide edit controls for viewers. - To call an outside API that needs a secret key, never put the key in the page. Call: POST /_jigsaw/fetch body: { "url": "https://api.example.com/v1/...", "method": "POST", "headers": { "Content-Type": "application/json" }, "body": "..." } Do not send the key or any placeholder for it. The owner pastes the key into Jigsaw (app settings, Keys) and says which host it is for and how that service expects it (usually the Authorization: Bearer header). Jigsaw adds it and returns the outside response. Calls to a host with no key saved are refused with 403, so tell the owner the exact host to save the key for. FULL LANE (only when a server is needed): include a package.json with a "start" script. - The server must listen on process.env.PORT and process.env.HOST. - Jigsaw installs the packages (install hooks do not run), runs "npm run build" if there is a "build" script, then "npm start". Do not upload node_modules. - Keep files and databases in process.env.JIGSAW_DATA_DIR. It outlives restarts and new versions; the app's own folder does not. - Every request has already passed sign-in. Who the visitor is arrives in headers: X-Jigsaw-Email, X-Jigsaw-Role ("owner", "editor" or "viewer") and X-Jigsaw-User-Id (stable per person). The same facts are in X-Jigsaw-Pass, a signed JWT you can verify with the keys at process.env.JIGSAW_JWKS_URL (issuer process.env.JIGSAW_ISSUER, audience process.env.JIGSAW_APP_ID). - The app's code must respect the role itself. The app sees the address visitors use (Host), available as process.env.JIGSAW_APP_URL too. - WebSockets work. Cookies the app sets are its own. - Keys the owner pasted arrive as environment variables. - The first start after publishing can take a minute or two while packages install. To publish a new app into a team the person builds for, pass the team's handle as "team". list_apps shows which team an app belongs to. After publishing, tell the person the app's address and the sharing address, which is https://jigsawapps.com/apps//share.