Get App
Fetch an existing app by ID and render it inline.
MCP name: get_app
Tool contract
{
"_meta": {
"ui": {
"resourceUri": "ui://charming/app"
},
"ui/resourceUri": "ui://charming/app"
},
"annotations": {
"destructiveHint": false,
"openWorldHint": false,
"readOnlyHint": true,
"title": "Get App"
},
"description": "Fetch an existing app by ID and render it inline. Use this to open, re-render, or continue working with an app the caller already has. Returns the live embedded UI plus its callable API operations, which another agent can invoke with query_app (read-only) or mutate_app (writes) to query or update saved app data. Unlike list_apps, which returns metadata including IDs and URLs, get_app renders the app; call list_apps first to find the ID. When telling the user where to open or share the app, always give them `shareUrl` from the result — never the `url` field, which is machine-only and embeds a write-capable access token.",
"execution": {
"taskSupport": "forbidden"
},
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"app_id": {
"description": "The app ID (UUID)",
"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"
}
},
"required": [
"app_id"
],
"type": "object"
},
"name": "get_app",
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"additionalProperties": false,
"properties": {
"$schema": {
"const": "https://charm.ing/schema/app-manifest/2026-07-31.json",
"description": "Exact dated canonical manifest schema URL. Omitted for legacy apps.",
"type": "string"
},
"advisories": {
"description": "Structured advisories attached when the tool detected a non-fatal authoring issue (e.g. legacy bridge usage). 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"
},
"api": {
"additionalProperties": false,
"description": "Full API surface — same shape as `_meta.charming.api`, but model-facing.",
"properties": {
"baseUrl": {
"description": "Origin + app prefix the operations live under.",
"type": "string"
},
"operations": {
"description": "Discovered routes in author order.",
"items": {
"additionalProperties": false,
"properties": {
"description": {
"description": "Author-supplied prose description.",
"type": "string"
},
"destructive": {
"description": "True when the route destroys data. Default false unless derived as such.",
"type": "boolean"
},
"discoveredFrom": {
"description": "Sources that contributed this operation (precedence order).",
"items": {
"enum": [
"routes_export",
"manifest_export",
"module_route"
],
"type": "string"
},
"type": "array"
},
"examples": {
"description": "Author-supplied calling examples that flow into the query_app/mutate_app snippet.",
"items": {
"additionalProperties": false,
"properties": {
"description": {
"type": "string"
},
"input": {},
"output": {}
},
"type": "object"
},
"type": "array"
},
"input": {
"description": "JSON Schema for the field. Canonical source declares it as `route.inputSchema` or `route.outputSchema`."
},
"manifestExport": {
"description": "Original capability-export string when discovered via `manifest_export`.",
"type": "string"
},
"method": {
"description": "HTTP method the route accepts.",
"enum": [
"GET",
"POST",
"PUT",
"PATCH",
"DELETE"
],
"type": "string"
},
"op": {
"description": "Operation name. Matches the `op` field on the corresponding Route.",
"type": "string"
},
"output": {
"description": "JSON Schema for the field. Canonical source declares it as `route.inputSchema` or `route.outputSchema`."
},
"path": {
"description": "Path under the app, e.g. `/api/increment`.",
"type": "string"
},
"public": {
"description": "True when the route is visible to discovery. Default true.",
"type": "boolean"
},
"readOnly": {
"description": "True when the route is a safe read (resolved from author intent + derivation).",
"type": "boolean"
},
"title": {
"description": "Short author-supplied title for the operation.",
"type": "string"
},
"tool": {
"description": "MCP tool to invoke this op: `query_app` for read-only, `mutate_app` otherwise.",
"enum": [
"query_app",
"mutate_app"
],
"type": "string"
},
"url": {
"description": "Full URL (origin + app prefix + path).",
"type": "string"
}
},
"required": [
"op",
"method",
"path",
"url",
"readOnly",
"destructive",
"public",
"tool",
"discoveredFrom"
],
"type": "object"
},
"type": "array"
}
},
"required": [
"baseUrl",
"operations"
],
"type": "object"
},
"appName": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"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)."
},
"appVersion": {
"description": "Canonical apps return decimal String(revision). Legacy apps return their stored effective SemVer.",
"type": "string"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Search-friendly summary of what the app does. Null on apps created before descriptions existed; agents are nudged to backfill on the next update_app."
},
"displayName": {
"description": "Human-readable name shown in app listings and headers.",
"type": "string"
},
"id": {
"description": "UUID of the opened app.",
"type": "string"
},
"manifestId": {
"description": "Stable manifest identifier declared by the app module. Distinct from `id` (DB primary key) — surface this when discussing the app with the user.",
"type": "string"
},
"manifestVersion": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Deprecated public contract marker. Canonical apps return null; legacy apps return their stored contract date."
},
"ok": {
"const": true,
"description": "Indicates success. Errors arrive as content with isError:true.",
"type": "boolean"
},
"recentIssues": {
"additionalProperties": false,
"description": "Runtime failures recorded against the current app revision since it was published (#1133): contract misses, runtime JS errors, CSP violations, and failed API calls. Present only when the current revision has at least one such event — absence means a clean render. The same summary is appended to the text content. Fetch full detail with GET /app/:id/activity.",
"properties": {
"counts": {
"additionalProperties": false,
"description": "Issue counts per category.",
"properties": {
"apiFailures": {
"description": "Failed calls to the app API proxy.",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
"appLoadErrors": {
"description": "Caught manifest-resolve / app load failures the bridge swallowed before they became an unhandled rejection.",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
"contractMisses": {
"description": "Publish-time UI/backend contract validation failures.",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
"cspViolations": {
"description": "Content-Security-Policy violations (e.g. an external image blocked by img-src).",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
"runtimeErrors": {
"description": "Runtime JS errors and unhandled rejections reported by the rendered page.",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
}
},
"required": [
"contractMisses",
"runtimeErrors",
"cspViolations",
"apiFailures",
"appLoadErrors"
],
"type": "object"
},
"examples": {
"description": "Most recent example per non-empty category, newest first.",
"items": {
"additionalProperties": false,
"properties": {
"category": {
"description": "Which `counts` bucket this example illustrates.",
"enum": [
"contractMisses",
"runtimeErrors",
"cspViolations",
"apiFailures",
"appLoadErrors"
],
"type": "string"
},
"kind": {
"description": "Underlying durable event kind: `diag_report` (runtime errors and CSP violations, distinguished by category), `contract_validation` (contract misses), `api_proxy_result` (API failures), or `app_load_error` (caught load failures).",
"type": "string"
},
"summary": {
"description": "Compact one-line description.",
"type": "string"
},
"ts": {
"description": "ISO-8601 timestamp of the event.",
"type": "string"
}
},
"required": [
"ts",
"category",
"kind",
"summary"
],
"type": "object"
},
"type": "array"
},
"sinceRevision": {
"description": "The app revision the issues are attributed to (the current revision at call time). Legacy nulls normalize to 0.",
"maximum": 9007199254740991,
"minimum": 0,
"type": "integer"
},
"total": {
"description": "Issue events counted for the current revision, capped at 500 — a value of 500 means 500 or more. Use GET /app/:id/activity for the exact, paginated list.",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
}
},
"required": [
"sinceRevision",
"total",
"counts",
"examples"
],
"type": "object"
},
"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"
}
},
"required": [
"ok",
"id",
"url",
"shareUrl",
"displayName",
"description",
"manifestId",
"revision",
"appVersion",
"manifestVersion",
"api"
],
"type": "object"
}
}
ChatGPT metadata
ChatGPT adds or replaces these fields for progress messages and inline app rendering.
{
"_meta": {
"openai/outputTemplate": "ui://charming/chatgpt/app-v1",
"openai/toolInvocation/invoked": "App ready",
"openai/toolInvocation/invoking": "Opening app…",
"ui": {
"resourceUri": "ui://charming/chatgpt/app-v1"
},
"ui/resourceUri": "ui://charming/chatgpt/app-v1"
}
}