Skip to content
Charming Docs
Esc
navigateopen⌘Jpreview
On this page

Publish App as Template

Enable a Charming Template for people who can already read the source App, and optionally publish it in Charming's public Template directory so anyone can discover and copy it.

MCP name: set_template

Tool contract

{
  "annotations": {
    "destructiveHint": false,
    "openWorldHint": true,
    "readOnlyHint": false,
    "title": "Publish App as Template"
  },
  "description": "Enable a Charming Template for people who can already read the source App, and optionally publish it in Charming's public Template directory so anyone can discover and copy it. Listed grants no access to the live source App or its data. Use this when the user wants independent copies or a public Template listing, not access to the live App. Each copy belongs to the signed-in visitor from creation. Optional listing fields are a patch: `title`, `summary`, `content_markdown`, `category`, cover fields, and `gallery` change only when supplied. Publishing with `listed: true` requires a nonblank resulting title and summary; every cover or gallery image needs nonblank alt text and must reference an image asset from this App. Pass `listed: true` to also mark it for discovery, or `listed: false` to unlist it. Omitting `listed` is a patch, not a reset: it leaves the current listed state exactly as it is (an already-listed app stays listed; a never-listed app stays unlisted), so re-affirming that an app is a template never surprises the owner by delisting it. Idempotent: calling with the same effective `listed` state as the current one returns the same URL without re-firing analytics. Anonymous apps cannot be made into templates; the app must be claimed first.",
  "execution": {
    "taskSupport": "forbidden"
  },
  "inputSchema": {
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "properties": {
      "app_id": {
        "description": "The app ID (UUID) to publish as a template",
        "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"
      },
      "category": {
        "anyOf": [
          {
            "enum": [
              "business",
              "developer-tools",
              "education",
              "entertainment",
              "lifestyle",
              "productivity",
              "utilities"
            ],
            "type": "string"
          },
          {
            "type": "null"
          }
        ],
        "description": "Template listing category; null clears it"
      },
      "content_markdown": {
        "description": "Long-form Template listing content; null clears it",
        "type": [
          "string",
          "null"
        ]
      },
      "cover_alt": {
        "description": "Nonblank cover alt text; supply with cover_asset_key",
        "type": "string"
      },
      "cover_asset_key": {
        "description": "App asset key for the cover image; null removes the cover",
        "type": [
          "string",
          "null"
        ]
      },
      "cover_caption": {
        "description": "Optional cover caption; supply with cover_asset_key",
        "type": [
          "string",
          "null"
        ]
      },
      "gallery": {
        "anyOf": [
          {
            "items": {
              "additionalProperties": false,
              "properties": {
                "alt": {
                  "description": "Nonblank alt text for this screenshot",
                  "type": "string"
                },
                "asset_key": {
                  "description": "App asset key for this screenshot",
                  "type": "string"
                },
                "caption": {
                  "description": "Optional screenshot caption",
                  "type": [
                    "string",
                    "null"
                  ]
                }
              },
              "required": [
                "asset_key",
                "alt"
              ],
              "type": "object"
            },
            "type": "array"
          },
          {
            "type": "null"
          }
        ],
        "description": "Ordered screenshot records; null or an empty array clears the gallery"
      },
      "listed": {
        "description": "Whether to also list the app in Charming's public template directory for discovery. `true` lists it, `false` unlists it. Omit this to leave the current listed state untouched — it is NOT a default-false reset, so omitting it never unlists an already-listed app.",
        "type": "boolean"
      },
      "summary": {
        "description": "Template listing summary; null clears it",
        "type": [
          "string",
          "null"
        ]
      },
      "title": {
        "description": "Template listing title; null clears it",
        "type": [
          "string",
          "null"
        ]
      }
    },
    "required": [
      "app_id"
    ],
    "type": "object"
  },
  "name": "set_template",
  "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"
      },
      "listed": {
        "description": "Whether the app is currently listed in the public template directory, reflecting the ACTUAL resulting state — not necessarily the call's `listed` input, since an omitted `listed` leaves the prior state unchanged. A template can be copyable without being listed.",
        "type": "boolean"
      },
      "message": {
        "description": "Consequence copy the agent should surface verbatim to the user when reporting the change. Spells out that other people will get their own copy — the user's data is untouched — and, when listed, that strangers can discover it.",
        "type": "string"
      },
      "ok": {
        "const": true,
        "description": "Indicates success. Errors arrive as content with isError:true.",
        "type": "boolean"
      },
      "public_url": {
        "description": "Canonical `/templates/<handle>/<app-name>` Template page. The URL stays the same while the Template is listed or unlisted. Existing App readers can copy an unlisted Template; anyone can copy it when Listed. The original is never mutated. Free of write-capable `?t=` tokens.",
        "type": "string"
      }
    },
    "required": [
      "ok",
      "public_url",
      "listed",
      "message"
    ],
    "type": "object"
  }
}

Was this page helpful?