Copy App
Use this to make the signed-in user a private copy of an existing app in one call, without reading or re-sending its source.
MCP name: copy_app
Tool contract
{
"annotations": {
"destructiveHint": false,
"openWorldHint": false,
"readOnlyHint": false,
"title": "Copy App"
},
"description": "Use this to make the signed-in user a private copy of an existing app in one call, without reading or re-sending its source. Works on an app the user can edit (owner, collaborator, team member) and on a Template they may copy (a `search_templates` result, or a Template shared with them); a Template copy records its source. The copy is owned by the user and private: it keeps the source code, styles, icon, and network settings, never sharing, Public or Template state, secrets, Routines, Webhooks, domains, or version history. It never replaces an app: without `manifest_id` the copy takes the next free manifest id (`<id>-2`, `<id>-3`), and a `manifest_id` you already hold fails with manifest_id_conflict. The UI keeps working unchanged. Pass `include_data: true` to copy the stored data and assets too; only the app’s owner can, and a team app’s data stays in the team, and the data must fit the 24 MiB a copy carries and the account storage allowance. Pass an `idempotency_key` to make a retry safe: the same key returns the first copy instead of making another. `secretsNotCopied` names any secrets to set on the copy. Give the user `shareUrl` to open the copy; `url` is machine-only.",
"execution": {
"taskSupport": "forbidden"
},
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"app_id": {
"description": "The app ID (UUID) to copy.",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
"type": "string"
},
"display_name": {
"description": "Display name for the copy. Defaults to the source’s.",
"type": "string"
},
"idempotency_key": {
"description": "Optional key of 8-100 visible ASCII characters naming this copy. A retry with the same key returns the copy the first call made instead of making another; the same key with a different app, include_data, or manifest_id fails with idempotency_conflict. Omit it and every call makes a new copy.",
"type": "string"
},
"include_data": {
"description": "Also copy the stored data and assets. Defaults to false. Only the owner of a personally owned source can; a team app’s data is not copied.",
"type": "boolean"
},
"manifest_id": {
"description": "Manifest id for the copy. Must be one you do not already hold. Omit it to take the next free id after the source’s.",
"type": "string"
}
},
"required": [
"app_id"
],
"type": "object"
},
"name": "copy_app",
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"additionalProperties": false,
"properties": {
"advisories": {
"description": "Structured non-fatal advisories, including authoring issues and unread staff feedback responses. Each advisory.summary is also appended to the text content for the LLM path.",
"items": {
"additionalProperties": false,
"properties": {
"data": {
"additionalProperties": {},
"description": "Kind-specific structured payload. Shape varies per advisory kind.",
"propertyNames": {
"type": "string"
},
"type": "object"
},
"doc_url": {
"description": "Optional docs pointer for this advisory kind.",
"type": "string"
},
"kind": {
"description": "Stable advisory identifier (e.g. \"legacy-bridge\").",
"type": "string"
},
"severity": {
"description": "Severity; omitted advisories are treated as 'info'.",
"enum": [
"info",
"warn"
],
"type": "string"
},
"summary": {
"description": "Agent-facing summary. Self-sufficient; no extra context required.",
"type": "string"
},
"userSummary": {
"description": "End-user-facing summary. Set when the advisory should render in-app.",
"type": "string"
}
},
"required": [
"kind",
"summary"
],
"type": "object"
},
"type": "array"
},
"appName": {
"description": "URL-safe slug for the app, unique per owner. Distinct from manifestId and displayName, and stable across edits — use rename_app to change it (the title changing does NOT change the slug).",
"type": [
"string",
"null"
]
},
"copiedData": {
"additionalProperties": false,
"description": "Present when include_data copied the data on this call. Absent on an idempotency replay, which returns the earlier copy without recounting.",
"properties": {
"assets": {
"description": "Assets copied.",
"maximum": 9007199254740991,
"minimum": 0,
"type": "integer"
},
"keys": {
"description": "Stored keys copied.",
"maximum": 9007199254740991,
"minimum": 0,
"type": "integer"
}
},
"required": [
"keys",
"assets"
],
"type": "object"
},
"copyKind": {
"description": "`app` for a copy of an app you can edit; `template` for a Template copy, which records the source as its origin.",
"enum": [
"app",
"template"
],
"type": "string"
},
"icon": {
"additionalProperties": false,
"description": "The effective home-screen icon stored for the app. Canonical source declares it at `manifest.meta.icon`.",
"properties": {
"bg": {
"description": "The icon background as a hex color (e.g. \"#1d8a4e\").",
"type": "string"
},
"emoji": {
"description": "The single emoji rendered on the icon.",
"type": "string"
}
},
"required": [
"emoji",
"bg"
],
"type": "object"
},
"id": {
"description": "UUID of the created or updated app.",
"type": "string"
},
"ok": {
"const": true,
"description": "Indicates success. Errors arrive as content with isError:true.",
"type": "boolean"
},
"revision": {
"description": "Server-owned app source revision. Historical null counters read as 0; new apps start at 1; each successful source write advances it once. Pass this value through `expected_revision` when guarding update_app.",
"maximum": 9007199254740991,
"minimum": 0,
"type": "integer"
},
"secretsNotCopied": {
"description": "Names of the source secrets the copy does not have. Set them on the copy before it needs them.",
"items": {
"type": "string"
},
"type": "array"
},
"shareUrl": {
"description": "The link to give humans whenever the user wants to open or share the app. Friendly /<handle>/<app-name> form when the OWNER has a live handle and the app a slug, /app/<uuid> otherwise. Always token-free — safe to show, paste, and send. Not an API base: appending /api/<op> to the friendly form 404s; use `url` for machine calls.",
"type": "string"
},
"sourceAppId": {
"description": "The app that was copied.",
"type": "string"
},
"url": {
"description": "Machine/API URL for the app (stable /app/<uuid> form). Embeds a write-capable ?t= access token — NEVER show, paste, or send it to the user. Append /api/<op> to its path for out-of-band operation calls. For anything user-facing, use shareUrl instead.",
"type": "string"
},
"warnings": {
"description": "Non-blocking publish feedback (#1126): present when static validation found UI/backend contract mismatches or legacy icon input needed a fallback. The write succeeded; fix the named source field.",
"items": {
"type": "string"
},
"type": "array"
}
},
"required": [
"ok",
"id",
"url",
"shareUrl",
"revision",
"icon",
"sourceAppId",
"copyKind"
],
"type": "object"
}
}