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/blob@1.0` 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": {
"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"
}
}