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

Upload Asset

UPLOAD A STATIC ASSET TO AN APP so app code stays small and the app reads it back same-origin.

MCP name: upload_asset

Tool contract

{
  "annotations": {
    "destructiveHint": true,
    "openWorldHint": true,
    "readOnlyHint": false,
    "title": "Upload Asset"
  },
  "description": "UPLOAD A STATIC ASSET TO AN APP so app code stays small and the app reads it back same-origin. Use this when an app needs a large or static file — an image, PDF, audio clip, or a dataset bigger than a few KB — that would otherwise be inlined into `module`/`ui` and blow the 256 KiB source cap. Provide EXACTLY ONE of: `sourceUrl` (PREFERRED for any binary — the SERVER fetches the remote file, follows redirects, and the bytes never transit this tool call), `text` (UTF-8 dataset/JSON/CSV — no encoding needed), or `dataBase64` (LAST RESORT, tiny binaries only: large base64 arguments can stall inside some MCP clients before ever reaching the server, so keep it under ~16 KB and use `sourceUrl` for anything bigger). The app reads the asset via `window.charming.assets.getUrl(key)` (for <img>/<a>) or `env.assets.get(key)` in its backend (the app must declare `charming:storage/[email protected]` in manifest.capabilities.imports to use env.assets). Caps: 10 MiB/asset, 50 assets/app, 100 MiB/app.",
  "execution": {
    "taskSupport": "forbidden"
  },
  "inputSchema": {
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "properties": {
      "appId": {
        "description": "The app id (app_modules.id) to attach the asset to. Must be an app you own.",
        "type": "string"
      },
      "contentType": {
        "description": "MIME type. Defaults: text/plain for text, sniffed for sourceUrl, application/octet-stream otherwise.",
        "type": "string"
      },
      "dataBase64": {
        "description": "Base64 of a SMALL binary. Last resort — prefer sourceUrl: large base64 tool arguments can stall in some MCP clients before reaching the server. Keep the encoded string under ~16 KB; the server-side hard cap is 64 KiB decoded.",
        "type": "string"
      },
      "key": {
        "description": "Asset name, e.g. \"dataset_v1.json\". URL-safe [a-zA-Z0-9._-], <=128 chars, no leading dot.",
        "type": "string"
      },
      "sourceUrl": {
        "description": "https URL the server fetches and stores. Bytes never pass through this tool call.",
        "format": "uri",
        "type": "string"
      },
      "text": {
        "description": "UTF-8 text payload (datasets, JSON, CSV). No base64.",
        "type": "string"
      }
    },
    "required": [
      "appId",
      "key"
    ],
    "type": "object"
  },
  "name": "upload_asset",
  "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"
      },
      "appId": {
        "description": "UUID of the asset-owning app.",
        "type": "string"
      },
      "bytes": {
        "description": "Stored byte length of the asset payload after decode/fetch.",
        "maximum": 9007199254740991,
        "minimum": -9007199254740991,
        "type": "integer"
      },
      "contentType": {
        "description": "Effective MIME type stored with the asset (supplied, sniffed from sourceUrl, or defaulted).",
        "type": "string"
      },
      "key": {
        "description": "The asset key it was stored under. Same value passed in.",
        "type": "string"
      },
      "ok": {
        "const": true,
        "description": "Indicates success. Errors arrive as content with isError:true.",
        "type": "boolean"
      },
      "url": {
        "description": "Same-origin URL serving the asset. Use in <img src>/<a href>/fetch, or read in the backend via env.assets.get(key). Equivalent to window.charming.assets.getUrl(key).",
        "type": "string"
      }
    },
    "required": [
      "ok",
      "appId",
      "key",
      "bytes",
      "contentType",
      "url"
    ],
    "type": "object"
  }
}

Was this page helpful?