Tool Catalog
This is the complete reference for every MCP tool Picora exposes. AI clients automatically read this schema via tools/list; this page documents it for human readers.
Tools at a glance
| Tool | Purpose | Required scope |
|---|---|---|
upload_image | Upload an image | media:write |
upload_video | Upload a video | media:write |
upload_audio | Upload an audio file | media:write |
upload_doc | Upload a Markdown document | docs:write |
list_media | List images / videos / audio | media:read |
list_docs | List Markdown documents | docs:read |
get_image | Get image metadata | media:read |
get_media | Get video / audio metadata | media:read |
get_doc | Get document metadata + optional content | docs:read |
delete_media | Delete images / videos / audio | media:delete |
delete_doc | Delete documents | docs:delete |
get_usage | Read current quota / usage stats | usage:read |
All delete_* tools default to dryRun: true.
Upload tools
upload_image {#upload_image}
Upload an image file to Picora.
Input:
{ "filePath": "string (absolute path to local file)", "title": "string?", "tags": ["string"]?, "isPublic": "boolean? (default: true)"}Output:
{ "id": "string (11-char nanoid)", "url": "string (public CDN URL)", "filename": "string", "sizeBytes": "number", "isPublic": "boolean", "tags": ["string"], "createdAt": "ISO 8601"}Errors: QUOTA_EXCEEDED:img_storage, VALIDATION_ERROR, RATE_LIMIT
upload_video {#upload_video}
Upload a video. Returns immediately with status: "processing"; transcoding happens asynchronously.
Input:
{ "filePath": "string", "title": "string?", "tags": ["string"]?, "isPublic": "boolean? (default: true)"}Output:
{ "id": "string", "title": "string", "filename": "string", "sizeBytes": "number", "status": "processing | ready | failed", "createdAt": "ISO 8601"}After upload, poll get_media until status: "ready" to get playback_url.
Errors: QUOTA_EXCEEDED:video_storage, VALIDATION_ERROR (file too large / too long), FORBIDDEN (plan doesn’t include video).
upload_audio {#upload_audio}
Upload an audio file. ID3 metadata (cover art, title, duration, bitrate) is extracted automatically.
Input:
{ "filePath": "string", "title": "string?", "tags": ["string"]?, "isPublic": "boolean? (default: true)"}Output:
{ "id": "string", "url": "string", "thumbnail_url": "string (extracted ID3 cover or default)", "title": "string", "filename": "string", "sizeBytes": "number", "durationSeconds": "number", "bitrate": "number", "isPublic": "boolean", "createdAt": "ISO 8601"}Errors: same as video.
upload_doc {#upload_doc}
Upload a Markdown document. Inline base64 images are auto-extracted and rewritten to Picora CDN URLs.
Input:
{ "filePath": "string?", "content": "string?", "filename": "string (e.g. 'README.md')", "title": "string?", "tags": ["string"]?, "isPublic": "boolean? (default: false)", "rewriteImages": "boolean? (default: true)"}Either filePath or content is required (not both).
Output:
{ "id": "string", "title": "string", "filename": "string", "sizeBytes": "number", "wordCount": "number", "imageCount": "number (total embedded refs)", "rewrittenCount": "number (actually rewritten)", "failedCount": "number", "failures": [{ "index": "number", "reason": "string" }], "warnings": ["string"], "isPublic": "boolean", "tags": ["string"], "createdAt": "ISO 8601"}Errors: QUOTA_EXCEEDED:doc_count, QUOTA_EXCEEDED:img_storage (when rewriting), DOC_FILE_TOO_LARGE, DOC_IMAGE_LIMIT_EXCEEDED, DOC_HASH_DUPLICATE (returns existing doc, not actually an error).
List tools
list_media {#list_media}
List images, videos, and audio (unified resource endpoint).
Input:
{ "type": "image | video | audio | null (all)", "cursor": "string? (paginate)", "limit": "number? (default: 20, max: 50)", "tag": "string?"}Output:
{ "items": [{ "id": "string", "type": "image | video | audio", "title": "string", "filename": "string", "sizeBytes": "number", "thumbnail_url": "string?", "isPublic": "boolean", "tags": ["string"], "createdAt": "ISO 8601" }], "nextCursor": "string? (null if last page)"}list_docs {#list_docs}
List Markdown documents. Filters by title (q) and tags.
Input:
{ "cursor": "string?", "limit": "number? (default: 20, max: 50)", "q": "string? (matches title only)", "tag": "string? (multi via comma)", "isPublic": "boolean? (filter)", "sort": "created_desc | created_asc | updated_desc | updated_asc (default: created_desc)"}Output:
{ "items": [{ "id": "string", "title": "string", "filename": "string", "sizeBytes": "number", "wordCount": "number", "imageCount": "number", "isPublic": "boolean", "tags": ["string"], "createdAt": "ISO 8601", "updatedAt": "ISO 8601" }], "nextCursor": "string?"}Get tools
get_image {#get_image}
Get full metadata for one image.
Input: { "id": "string" }
Output: same as upload_image plus updatedAt.
get_media {#get_media}
Get metadata for video or audio. The playback_url field is populated when status: "ready".
Input: { "id": "string" }
Output:
{ "id": "string", "type": "video | audio", "title": "string", "filename": "string", "sizeBytes": "number", "durationSeconds": "number?", "playback_url": "string? (HLS playlist for video, direct URL for audio)", "thumbnail_url": "string?", "status": "processing | ready | failed", "isPublic": "boolean", "createdAt": "ISO 8601", "updatedAt": "ISO 8601"}get_doc {#get_doc}
Get document metadata. Optionally include the full markdown content.
Input:
{ "id": "string", "includeContent": "boolean? (default: false)"}Output: metadata fields (see list_docs) + optional content: string (utf-8 markdown).
When includeContent: true and content is huge (>5 MB), the response is truncated with truncated: true flag — fetch via the public raw endpoint instead for very large documents.
Delete tools
delete_media {#delete_media}
Delete one or many images / videos / audio. Defaults to dryRun: true.
Input:
{ "ids": ["string"], "dryRun": "boolean (default: true)"}Output (dry-run):
{ "dryRun": true, "wouldDelete": [{ "id": "string", "type": "image | video | audio", "title": "string", "sizeBytes": "number" }], "totalCount": "number", "totalBytes": "number"}Output (actual delete):
{ "dryRun": false, "deleted": ["string (list of ids)"], "failed": [{ "id": "string", "reason": "string" }]}Single batch limit: 50 ids.
delete_doc {#delete_doc}
Delete Markdown documents. Same dryRun pattern.
Input:
{ "ids": ["string"], "dryRun": "boolean (default: true)"}Output: same shape as delete_media.
Usage
get_usage {#get_usage}
Read your current quota and usage stats.
Input: {} (no parameters)
Output:
{ "plan": "trial | pro | pro_plus", "image": { "storage": { "used": "number", "limit": "number" }, "bandwidth": { "used": "number", "limit": "number", "monthYear": "YYYY-MM" } }, "video": { "storage": { "used": "number", "limit": "number" }, "bandwidth": { "used": "number", "limit": "number", "monthYear": "YYYY-MM" }, "status": "ok | degraded | suspended" }, "audio": { "storage": { "used": "number", "limit": "number (shared with video)" } }, "doc": { "count": { "used": "number", "limit": "number" } }, "uploadCount": { "today": "number", "todayLimit": "number", "thisMonth": "number", "thisMonthLimit": "number" }}Error codes summary
All tools may return these structured errors. The AI client sees error.code and error.meta and can react / re-prompt.
| Code | HTTP | Description |
|---|---|---|
UNAUTHORIZED | 401 | API Key / OAuth token invalid or expired |
FORBIDDEN | 403 | OAuth scope insufficient, or feature not in plan |
QUOTA_EXCEEDED | 403 | meta.type indicates which: img_storage, media_storage, doc_count etc. |
RATE_LIMIT | 429 | Tier-based rate limit exceeded; Retry-After header set |
NOT_FOUND | 404 | Resource doesn’t exist |
VALIDATION_ERROR | 422 | Input failed schema validation |
DOC_HASH_DUPLICATE | 409 | Document content hash already exists; meta.existingId returns the original |
DOC_FILE_TOO_LARGE | 422 | Markdown exceeds plan’s doc_max_file_bytes |
DOC_IMAGE_LIMIT_EXCEEDED | 422 | Embedded image count exceeds plan’s doc_max_images_per_doc |
STORAGE_ERROR | 502 | Object storage unavailable; retry |
INTERNAL | 500 | Unexpected error; report with requestId |
Related
- API Reference — direct HTTP API docs
- Authorized apps — manage OAuth grants per tool
- Plan comparison — what each plan includes
- Quota overview — quota dimensions & cache keys