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"
}
}