Skip to content
Esc
↑↓navigate↵open⌘Jpreview
On this page

Create App

Use this to create a new Charming app and render it inline.

MCP name: create_app

Tool contract

{
  "_meta": {
    "ui": {
      "resourceUri": "ui://charming/app-v2"
    },
    "ui/resourceUri": "ui://charming/app-v2"
  },
  "annotations": {
    "destructiveHint": true,
    "openWorldHint": true,
    "readOnlyHint": false,
    "title": "Create App"
  },
  "description": "Use this to create a new Charming app and render it inline. An app is a package: pass `files` holding package.json, server.js, and optionally ui.js, styles.css, and the files they import, with an `idempotency_key`. Charming apps run in a sandbox with their own storage and network rules, so code written for an ordinary web page or server often fails here. Before writing any source, read the build guide with read_docs({ path: \"build-mcp.md\" }), following `next_offset` until it is null. The result is an accepted build: poll get_app_build with its buildId until `published`; the app has no URL before that. A package.json `name` the caller already owns is refused with precondition_required unless `expected_revision` names that app's current revision (plus `migrate_contract: true` for an app saved before packages); to change an existing app, call update_app with its ID. Give the user `shareUrl` from the published app, never `url`, which carries a write-capable access token. A save needs a signed-in user and an idempotency_key. The package contract is dated 2026-10-25 and frozen.",
  "execution": {
    "taskSupport": "forbidden"
  },
  "inputSchema": {
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "properties": {
      "description": {
        "description": "Required unless files is given; a package describes itself in package.json. Search-friendly summary of what this app does, surfaced by list_apps so a future session can match user intent (e.g. \"open my protein tracker\", \"log food\") to this app even when display_name is ambiguous. Write 1-2 sentences covering: (a) what the app tracks/does, (b) the key actions it supports, and (c) synonyms or alternative phrasings the user might say. Example: \"Tracks daily protein intake. Log meals, view weekly totals, set a daily goal. Synonyms: meals, food log, nutrition tracker, calorie counter.\" Limit 500 characters.",
        "maxLength": 500,
        "type": "string"
      },
      "display_name": {
        "description": "Optional display name override",
        "type": "string"
      },
      "expected_revision": {
        "description": "Required when a package reuses an existing package name. Pass the desired revision from get_app_source.",
        "maximum": 9007199254740991,
        "minimum": -9007199254740991,
        "type": "integer"
      },
      "files": {
        "additionalProperties": {
          "type": "string"
        },
        "description": "The App as a package: a map from path to text holding `package.json` and `server.js`, plus optional `ui.js`, `styles.css`, and any other .js, .mjs, or .json files they import with relative paths. package.json follows npm: `name` is the App's id, `dependencies` holds public npm packages for both targets, and Charming facts sit under `charming` (`name`, `icon`, `permissions`); it may declare `\"$schema\": \"https://charm.ing/schema/app-package/2026-10-25.json\"`. server.js exports `routes` and imports what it uses, such as `import { kv } from 'charming:storage/[email protected]'`; capabilities come from those imports, never from a declaration. ui.js imports `{ api, onStateChange }` from 'charming:ui/[email protected]'. Mutually exclusive with module, ui, styles, and display_name. To call a person's connected service, such as Gmail, declare its Composio tool slugs in package.json under `charming.permissions.server.connectors` (for example `{ gmail: ['GMAIL_FETCH_EMAILS', 'GMAIL_FETCH_MESSAGE_BY_MESSAGE_ID'] }`), `import { connectors } from 'charming:[email protected]'`, and call `connectors.call(service, tool, args)` inside a route handler; on a `connector_not_granted` refusal the UI calls `charming.connect(service)` from a click. Never write a person's service data into the App's shared storage, where everyone using the App can read it. See read_docs({ path: \"capabilities/connectors.md\" }). The package contract is dated 2026-10-25 and frozen.",
        "propertyNames": {
          "type": "string"
        },
        "type": "object"
      },
      "idempotency_key": {
        "description": "Required for package builds: 8–128 visible ASCII characters. Retry the exact request with the same key to recover its build; use a new key for changed source.",
        "type": "string"
      },
      "migrate_contract": {
        "description": "Set true to move an existing App onto the package contract, together with expected_revision. Source submissions do not roll back contracts. History can explicitly restore a retained validated canonical revision.",
        "type": "boolean"
      },
      "module": {
        "description": "Omit this when passing `files`. Only for an app saved before packages, as a single ES module string with an exported manifest. New apps pass `files` instead; see read_docs({ path: \"guides/migrate-to-packages.md\" }) to move an older app onto the package contract.",
        "maxLength": 262144,
        "type": "string"
      },
      "styles": {
        "description": "Optional CSS for the rendered app",
        "maxLength": 262144,
        "type": "string"
      },
      "team_id": {
        "description": "Optional destination team id. Only a team owner or admin can create an App there. Omit it to create a personal App.",
        "type": "string"
      },
      "ui": {
        "description": "Omit this when passing `files`. Only for an app saved before packages: its inline frontend script. New apps carry ui.js inside `files`.",
        "maxLength": 262144,
        "type": "string"
      }
    },
    "type": "object"
  },
  "name": "create_app",
  "outputSchema": {
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "additionalProperties": false,
    "anyOf": [
      {
        "$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"
            ]
          },
          "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"
          },
          "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"
          },
          "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"
        ],
        "type": "object"
      },
      {
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "additionalProperties": false,
        "properties": {
          "acceptedAt": {
            "type": "string"
          },
          "activeRevision": {
            "maximum": 9007199254740991,
            "minimum": 0,
            "type": "integer"
          },
          "appId": {
            "description": "Existing target app ID, or the created app ID after publication.",
            "type": "string"
          },
          "attempts": {
            "maximum": 9007199254740991,
            "minimum": 0,
            "type": "integer"
          },
          "buildId": {
            "description": "Durable build ID. Use get_app_build to inspect progress or source.",
            "type": "string"
          },
          "deadline": {
            "type": "string"
          },
          "desiredRevision": {
            "maximum": 9007199254740991,
            "minimum": 0,
            "type": "integer"
          },
          "elapsedMs": {
            "minimum": 0,
            "type": "number"
          },
          "error": {
            "additionalProperties": false,
            "properties": {
              "column": {
                "maximum": 9007199254740991,
                "minimum": -9007199254740991,
                "type": "integer"
              },
              "details": {
                "anyOf": [
                  {
                    "additionalProperties": false,
                    "properties": {
                      "execution": {
                        "enum": [
                          "not_started",
                          "may_have_run"
                        ],
                        "type": "string"
                      },
                      "operationId": {
                        "minLength": 1,
                        "type": "string"
                      },
                      "reservationId": {
                        "minLength": 1,
                        "type": "string"
                      }
                    },
                    "required": [
                      "execution",
                      "operationId"
                    ],
                    "type": "object"
                  },
                  {
                    "additionalProperties": false,
                    "properties": {
                      "execution": {
                        "const": "may_have_run",
                        "type": "string"
                      }
                    },
                    "required": [
                      "execution"
                    ],
                    "type": "object"
                  }
                ]
              },
              "kind": {
                "type": "string"
              },
              "line": {
                "maximum": 9007199254740991,
                "minimum": -9007199254740991,
                "type": "integer"
              },
              "message": {
                "type": "string"
              },
              "retryable": {
                "type": "boolean"
              },
              "specifier": {
                "type": "string"
              },
              "target": {
                "type": "string"
              }
            },
            "required": [
              "kind",
              "message",
              "retryable"
            ],
            "type": "object"
          },
          "finishedAt": {
            "type": [
              "string",
              "null"
            ]
          },
          "idempotencyExpiresAt": {
            "type": [
              "string",
              "null"
            ]
          },
          "inputDigest": {
            "type": "string"
          },
          "inspectionExpiresAt": {
            "type": [
              "string",
              "null"
            ]
          },
          "intent": {
            "description": "The accepted operation: create, update, migrate, restore, or copy.",
            "type": "string"
          },
          "lockDigest": {
            "type": "string"
          },
          "lockState": {
            "enum": [
              "locked",
              "unresolved"
            ],
            "type": "string"
          },
          "ok": {
            "const": true,
            "type": "boolean"
          },
          "queueDeadline": {
            "type": "string"
          },
          "resolvedDependencies": {
            "additionalProperties": {
              "type": "string"
            },
            "description": "Exact package versions the build resolved for the declared dependencies.",
            "propertyNames": {
              "type": "string"
            },
            "type": "object"
          },
          "retryAfterSeconds": {
            "description": "Wait at least this many seconds before polling again.",
            "exclusiveMinimum": 0,
            "maximum": 9007199254740991,
            "type": "integer"
          },
          "revision": {
            "description": "Published app source revision.",
            "exclusiveMinimum": 0,
            "maximum": 9007199254740991,
            "type": "integer"
          },
          "source": {
            "additionalProperties": false,
            "description": "Exact accepted source, returned only when include_source is true.",
            "properties": {
              "files": {
                "additionalProperties": {
                  "type": "string"
                },
                "description": "The accepted file tree: package.json, server.js, and any other files.",
                "propertyNames": {
                  "type": "string"
                },
                "type": "object"
              }
            },
            "required": [
              "files"
            ],
            "type": "object"
          },
          "sourceEtag": {
            "description": "The quoted ETag of the revision this build saved once an App exists; an HTTP save passes it as If-Match. It doesn't change after a later save; get_app_source returns the current revision. Before a creation publishes, the digest of the accepted input.",
            "type": "string"
          },
          "state": {
            "enum": [
              "queued",
              "resolving",
              "building",
              "validating",
              "published",
              "failed",
              "superseded",
              "canceled",
              "expired"
            ],
            "type": "string"
          },
          "statusUrl": {
            "description": "Authenticated HTTP status URL for this build.",
            "type": "string"
          },
          "updatedAt": {
            "type": "string"
          },
          "url": {
            "description": "App URL. Present only after successful publication.",
            "type": "string"
          }
        },
        "required": [
          "ok",
          "buildId",
          "intent",
          "state",
          "sourceEtag",
          "statusUrl",
          "attempts",
          "acceptedAt",
          "updatedAt",
          "finishedAt",
          "queueDeadline",
          "deadline",
          "inspectionExpiresAt",
          "idempotencyExpiresAt",
          "elapsedMs",
          "lockState",
          "inputDigest"
        ],
        "type": "object"
      }
    ],
    "properties": {
      "acceptedAt": {
        "type": "string"
      },
      "activeRevision": {
        "maximum": 9007199254740991,
        "minimum": 0,
        "type": "integer"
      },
      "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"
      },
      "appId": {
        "description": "Existing target app ID, or the created app ID after publication.",
        "type": "string"
      },
      "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"
        ]
      },
      "attempts": {
        "maximum": 9007199254740991,
        "minimum": 0,
        "type": "integer"
      },
      "buildId": {
        "description": "Durable build ID. Use get_app_build to inspect progress or source.",
        "type": "string"
      },
      "deadline": {
        "type": "string"
      },
      "desiredRevision": {
        "maximum": 9007199254740991,
        "minimum": 0,
        "type": "integer"
      },
      "elapsedMs": {
        "minimum": 0,
        "type": "number"
      },
      "error": {
        "additionalProperties": false,
        "properties": {
          "column": {
            "maximum": 9007199254740991,
            "minimum": -9007199254740991,
            "type": "integer"
          },
          "details": {
            "anyOf": [
              {
                "additionalProperties": false,
                "properties": {
                  "execution": {
                    "enum": [
                      "not_started",
                      "may_have_run"
                    ],
                    "type": "string"
                  },
                  "operationId": {
                    "minLength": 1,
                    "type": "string"
                  },
                  "reservationId": {
                    "minLength": 1,
                    "type": "string"
                  }
                },
                "required": [
                  "execution",
                  "operationId"
                ],
                "type": "object"
              },
              {
                "additionalProperties": false,
                "properties": {
                  "execution": {
                    "const": "may_have_run",
                    "type": "string"
                  }
                },
                "required": [
                  "execution"
                ],
                "type": "object"
              }
            ]
          },
          "kind": {
            "type": "string"
          },
          "line": {
            "maximum": 9007199254740991,
            "minimum": -9007199254740991,
            "type": "integer"
          },
          "message": {
            "type": "string"
          },
          "retryable": {
            "type": "boolean"
          },
          "specifier": {
            "type": "string"
          },
          "target": {
            "type": "string"
          }
        },
        "required": [
          "kind",
          "message",
          "retryable"
        ],
        "type": "object"
      },
      "finishedAt": {
        "type": [
          "string",
          "null"
        ]
      },
      "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"
      },
      "idempotencyExpiresAt": {
        "type": [
          "string",
          "null"
        ]
      },
      "inputDigest": {
        "type": "string"
      },
      "inspectionExpiresAt": {
        "type": [
          "string",
          "null"
        ]
      },
      "intent": {
        "description": "The accepted operation: create, update, migrate, restore, or copy.",
        "type": "string"
      },
      "lockDigest": {
        "type": "string"
      },
      "lockState": {
        "enum": [
          "locked",
          "unresolved"
        ],
        "type": "string"
      },
      "ok": {
        "const": true,
        "type": "boolean"
      },
      "queueDeadline": {
        "type": "string"
      },
      "resolvedDependencies": {
        "additionalProperties": {
          "type": "string"
        },
        "description": "Exact package versions the build resolved for the declared dependencies.",
        "propertyNames": {
          "type": "string"
        },
        "type": "object"
      },
      "retryAfterSeconds": {
        "description": "Wait at least this many seconds before polling again.",
        "exclusiveMinimum": 0,
        "maximum": 9007199254740991,
        "type": "integer"
      },
      "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"
      },
      "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"
      },
      "source": {
        "additionalProperties": false,
        "description": "Exact accepted source, returned only when include_source is true.",
        "properties": {
          "files": {
            "additionalProperties": {
              "type": "string"
            },
            "description": "The accepted file tree: package.json, server.js, and any other files.",
            "propertyNames": {
              "type": "string"
            },
            "type": "object"
          }
        },
        "required": [
          "files"
        ],
        "type": "object"
      },
      "sourceEtag": {
        "description": "The quoted ETag of the revision this build saved once an App exists; an HTTP save passes it as If-Match. It doesn't change after a later save; get_app_source returns the current revision. Before a creation publishes, the digest of the accepted input.",
        "type": "string"
      },
      "state": {
        "enum": [
          "queued",
          "resolving",
          "building",
          "validating",
          "published",
          "failed",
          "superseded",
          "canceled",
          "expired"
        ],
        "type": "string"
      },
      "statusUrl": {
        "description": "Authenticated HTTP status URL for this build.",
        "type": "string"
      },
      "updatedAt": {
        "type": "string"
      },
      "url": {
        "description": "App URL. Present only after successful publication.",
        "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"
    ],
    "type": "object"
  }
}

ChatGPT metadata

ChatGPT adds or replaces these fields for progress messages and inline app rendering.

{
  "_meta": {
    "openai/outputTemplate": "ui://charming/chatgpt/app-v2",
    "openai/toolInvocation/invoked": "App created",
    "openai/toolInvocation/invoking": "Creating app…",
    "ui": {
      "resourceUri": "ui://charming/chatgpt/app-v2"
    },
    "ui/resourceUri": "ui://charming/chatgpt/app-v2"
  }
}

Was this page helpful?