MCP Tool Reference
Every tool Picora exposes over MCP, with its exact input schema. AI clients read this automatically via tools/list; this page is the human-readable copy.
The machine-readable source is https://api.picora.me/mcp/tools.json — it carries the same inputSchema objects documented below.
How to read this page
- Scope — the OAuth scope the token must carry. With an API Key, scopes are derived from the key tier:
read→ all*.read;read_write→ addsmedia.write+kb.write;read_write_delete→ addsmedia.delete. See Concepts. - Billing tier —
readorwrite, used for per-call metering. Metering is not enabled today; all calls are free. - Rate tier — which HTTP rate-limit bucket the call consumes:
read,mutationorupload. See Rate Limits. - Plan — minimum plan. Only one tool has a plan gate.
- Required columns mark fields the server rejects the call without.
All 19 tools
| Tool | Purpose | Scope | Billing tier | Rate tier | Plan |
|---|---|---|---|---|---|
picora.help | List available tools and usage patterns | (none) | read | read | any |
picora.about | Service metadata, docs URL, version | (none) | read | read | any |
picora.upload_image | Upload an image, get a permanent CDN URL | media.write | write | upload | any |
picora.upload_video | Upload a video (async transcoding) | media.write | write | upload | pro |
picora.upload_audio | Upload an audio file (synchronous) | media.write | write | upload | any |
picora.list_media | List images / videos / audio | media.read | read | read | any |
picora.get_media | Detail for one media item | media.read | read | read | any |
picora.update_media | Rename or change visibility | media.write | write | mutation | any |
picora.delete_media | Permanently delete media | media.delete | write | mutation | any |
picora.get_usage | Plan, storage, bandwidth counters | usage.read | read | read | any |
picora.upload_doc | Upload a Markdown document | kb.write | write | upload | any |
picora.list_docs | List Markdown documents | kb.read | read | read | any |
picora.get_doc | Document metadata, optionally content | kb.read | read | read | any |
picora.delete_doc | Delete Markdown documents | kb.write | write | mutation | any |
picora.list_kbs | List knowledge bases | kb.read | read | read | any |
picora.create_kb | Create a knowledge base | kb.write | write | mutation | any |
picora.get_kb_manifest | File manifest of a knowledge base | kb.read | read | read | any |
picora.read_kb_doc | Read one file inside a knowledge base | kb.read | read | read | any |
picora.sync_kb | Batch upsert / delete / move in a KB | kb.write | write | upload | any |
File sources (shared by all upload tools)
upload_image, upload_video, upload_audio and upload_doc all take the file the same way. Provide exactly one of:
| Field | Type | Notes |
|---|---|---|
filePath | string | Absolute local path, e.g. /Users/x/Desktop/cat.jpg. stdio only — the remote server has no filesystem access. Relative paths are rejected. |
url | string (uri) | Publicly reachable http/https URL; the server downloads it (max 100 MB). Private/internal addresses are rejected. |
base64 | string | Base64 file content, recommended under 2 MB. A data:*;base64, prefix is accepted and stripped. Requires filename. |
filename | string | Filename with extension, e.g. "cat.jpg". Required with base64, ignored otherwise. |
Passing two sources at once is a validation error.
Integration tools
These two require no scope and no authentication decision — an agent can call them before the user has granted anything, to find out what is available.
picora.help
Overview of every Picora MCP tool, grouped by capability (media / docs / kb / usage), plus authentication options and documentation links.
Scope (none) · Billing tier read · Rate tier read · Plan any
Input — no parameters.
Use it when you are unsure which Picora tool fits, or the user asks “what can Picora do?”. Call it first in an unfamiliar session.
Don’t use it for service metadata like version or region — that’s picora.about.
Typical errors — none; read-only with no side effects.
picora.about
Basic information about the Picora service: what it is, documentation URL, API base endpoints, and tool package version.
Scope (none) · Billing tier read · Rate tier read · Plan any
Input — no parameters.
Use it when the user asks “what is Picora?” or you need service metadata (which region/endpoint am I talking to, which tool version is loaded).
Don’t use it for discovering tools — that’s picora.help.
Typical errors — none; read-only with no side effects.
Media tools
picora.upload_image
Upload an image to Picora cloud hosting and get back a permanent CDN URL that never expires. Supports JPEG / PNG / WebP / GIF / AVIF up to 20 MB.
Scope media.write · Billing tier write · Rate tier upload · Plan any
Input
| Field | Type | Required | Notes |
|---|---|---|---|
filePath | string | one-of | Absolute local path (stdio only) |
url | string (uri) | one-of | Public file URL, fetched server-side, max 100 MB |
base64 | string | one-of | Base64 content, recommended < 2 MB; needs filename |
filename | string | with base64 | Filename with extension |
isPublic | boolean | no | Publicly accessible. Default true |
tags | string[] | no | Max 10 tags, each ≤ 50 chars |
Use it when the user asks to upload, host or share an image, or wants a permanent URL for a picture.
Don’t use it for videos (upload_video), audio (upload_audio) or Markdown (upload_doc).
Typical errors — QUOTA_EXCEEDED (image storage full), INVALID_MIME (unsupported format), VALIDATION_ERROR (no file source, or two at once), MCP_SCOPE_INSUFFICIENT (key is read-only).
picora.upload_video
Upload a video (mp4 / mov / avi). Transcoding is asynchronous: the call returns immediately with status: "processing".
Scope media.write · Billing tier write · Rate tier upload · Plan pro (Pro ≤ 500 MB, Pro+ ≤ 2 GB)
Input
| Field | Type | Required | Notes |
|---|---|---|---|
title | string | yes | Display title, 1–255 chars |
filePath | string | one-of | Absolute local path (stdio only) |
url | string (uri) | one-of | Public file URL, fetched server-side, max 100 MB |
base64 | string | one-of | Base64 content, recommended < 2 MB; needs filename |
filename | string | with base64 | Filename with extension |
isPublic | boolean | no | Publicly accessible. Default true |
Use it when the user asks to upload or share a video. Afterwards, poll picora.get_media (or list_media filtered by type: "video") until status becomes "ready" — only then does a playbackUrl exist. Short clips typically take 1–3 minutes; HD/4K takes longer.
Don’t use it for images or audio, and don’t report success to the user while status is still processing.
Typical errors — PLAN_REQUIRED / MCP_PLAN_INSUFFICIENT (free or trial account), QUOTA_EXCEEDED (video storage), VALIDATION_ERROR (file too large for the plan, missing title).
picora.upload_audio
Upload an audio file (mp3 / m4a / wav / flac / ogg). Unlike video this is synchronous — when the call returns, the audio is immediately playable.
Scope media.write · Billing tier write · Rate tier upload · Plan any (per-file caps: Trial 50 MB / Pro 100 MB / Pro+ 500 MB)
Input
| Field | Type | Required | Notes |
|---|---|---|---|
title | string | yes | Display title, 1–255 chars |
filePath | string | one-of | Absolute local path (stdio only) |
url | string (uri) | one-of | Public file URL, fetched server-side, max 100 MB |
base64 | string | one-of | Base64 content, recommended < 2 MB; needs filename |
filename | string | with base64 | Filename with extension |
isPublic | boolean | no | Publicly accessible. Default true |
Use it when the user wants to host a podcast episode, music track or voice recording. For MP3 (ID3v2) and FLAC, embedded cover art plus bitrate and duration are extracted automatically; other formats get a per-format default thumbnail and null bitrate / durationSeconds.
Don’t use it for images or videos.
Typical errors — QUOTA_EXCEEDED (audio storage), INVALID_MIME, VALIDATION_ERROR (file exceeds the per-plan cap, missing title).
picora.list_media
List uploaded media newest-first, with cursor pagination. Omit type for a unified mixed list.
Scope media.read · Billing tier read · Rate tier read · Plan any
Input
| Field | Type | Required | Notes |
|---|---|---|---|
type | "image" | "video" | "audio" | no | Filter by media type; omit for all |
limit | integer | no | 1–50, default 20 |
cursor | string | no | nextCursor from the previous response |
query | string | no | Fuzzy match on filename / title, ≤ 255 chars |
Use it when the user asks to list, show or find their media, or you need to poll several videos’ transcode status at once.
Don’t use it for fetching one known item — get_media is cheaper and returns the same detail.
Typical errors — VALIDATION_ERROR (limit out of range, malformed cursor), MCP_SCOPE_INSUFFICIENT.
picora.get_media
Metadata for a single media item, addressed by id and type.
Scope media.read · Billing tier read · Rate tier read · Plan any
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | string | yes | 11-char nanoid for images, 21-char for video / audio |
type | "image" | "video" | "audio" | yes | Required to route to the right endpoint |
Use it when the user asks for details on a specific item — and specifically to check whether a video finished transcoding: read the status field (processing / ready / failed).
Don’t use it for browsing; use list_media when you don’t already have the id.
Typical errors — NOT_FOUND (wrong id, or right id with the wrong type), VALIDATION_ERROR.
picora.update_media
Change the title or visibility of an existing media item. The server invalidates its cache, so subsequent reads see the new values immediately.
Scope media.write · Billing tier write · Rate tier mutation · Plan any
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | string | yes | Media id (11- or 21-char nanoid) |
type | "image" | "video" | "audio" | yes | Media type |
title | string | no | New title, ≤ 255 chars. Omit to leave unchanged |
isPublic | boolean | no | New visibility. Omit to leave unchanged |
Use it when the user says “rename this video”, “make this image private”, “publish this audio”. Pass at least one of title / isPublic.
Don’t use it for editing filename or image tags — those are not editable here.
Typical errors — NOT_FOUND, VALIDATION_ERROR (neither title nor isPublic supplied), MCP_SCOPE_INSUFFICIENT.
picora.delete_media
Permanently remove media from object storage, database and cache. Irreversible — no trash, no undo, and the CDN URLs start returning 404.
Scope media.delete · Billing tier write · Rate tier mutation · Plan any
Input
| Field | Type | Required | Notes |
|---|---|---|---|
items | array | yes | 1–100 objects, each { id: string, type: "image" | "video" | "audio" }. Mixed types allowed |
dryRun | boolean | no | Default true — preview only. false actually deletes |
Use it only via the two-step protocol:
- Call with
dryRun: true(the default) to preview exactly what would be removed. - Show the user that list and get explicit confirmation.
- Only after the user says yes, call again with
dryRun: false.
Don’t use it for hiding content from the public — update_media with isPublic: false is reversible, deletion is not.
Typical errors — MCP_SCOPE_INSUFFICIENT (needs a read_write_delete key; read_write cannot delete), NOT_FOUND (an id in the batch does not exist), VALIDATION_ERROR (more than 100 items).
Usage tools
picora.get_usage
The account’s current plan plus storage, bandwidth and upload counters.
Scope usage.read · Billing tier read · Rate tier read · Plan any
Input — no parameters.
Use it when the user asks “how much storage have I used?”, “what plan am I on?”, “how much bandwidth this month?” — or before a large batch upload, to check there is room.
Don’t report raw byte counts back to the user: all byte values are integers, so format them (2147483648 → 2 GB). Bandwidth figures are estimates — CDN cache hits are not counted, so a small gap versus billing is expected.
Typical errors — MCP_SCOPE_INSUFFICIENT (token lacks usage.read).
Document tools
These operate on standalone documents — flat Markdown files that are not inside a knowledge base. For files organised under paths in a workspace, use the KB tools.
picora.upload_doc
Upload a Markdown document (.md / .markdown, max 5 MB) and get a permanent URL.
Scope kb.write · Billing tier write · Rate tier upload · Plan any
Input
| Field | Type | Required | Notes |
|---|---|---|---|
filePath | string | one-of | Absolute local path (stdio only) |
url | string (uri) | one-of | Public file URL, fetched server-side, max 100 MB |
base64 | string | one-of | Base64 content; needs filename |
filename | string | with base64 | Filename with extension |
title | string | no | ≤ 200 chars. Takes priority over frontmatter / H1 / filename |
tags | string[] | no | Max 10 tags, each ≤ 32 chars. Takes priority over frontmatter tags |
isPublic | boolean | no | Default false. Public docs are readable at /v1/docs/:id/raw without auth |
rewriteImages | boolean | no | Decode and re-host inline base64 images. Default true |
Behaviours worth knowing
- Content is read as UTF-8, 5 MB maximum.
- Inline
data:image embeds are re-uploaded to Picora CDN URLs — this consumes the image quota too. - Links already pointing at Picora (e.g.
media.picora.me) are left alone. file://and relative paths inside the Markdown are kept as-is, with a warning.- YAML frontmatter (
--- … ---) is parsed for title / tags / public hints; the original content is preserved. - Idempotent: identical content returns the existing document id with
duplicate: true, and does not consume quota again.
Use it when the user wants to publish, host or share a Markdown note, or wants a permanent URL for one.
Don’t use it for images, generic binary files, or files that belong inside a KB directory tree (use sync_kb).
Typical errors — QUOTA_EXCEEDED (document count limit), VALIDATION_ERROR (over 5 MB, no file source).
picora.list_docs
List standalone Markdown documents. Returns metadata only — never content.
Scope kb.read · Billing tier read · Rate tier read · Plan any
Input
| Field | Type | Required | Notes |
|---|---|---|---|
limit | number | no | 1–50, default 20 |
cursor | string | no | nextCursor from the previous response |
query | string | no | Title fuzzy match, ≤ 100 chars (no full-text search yet) |
tag | string | no | Single tag, or comma-separated for OR semantics. ≤ 200 chars |
isPublic | boolean | no | Filter by visibility; omit for all |
sort | created_desc | created_asc | updated_desc | updated_asc | no | Default created_desc |
Use it when the user asks “what docs do I have?”, “find my notes about X”, “list documents tagged Y”.
Don’t use it for reading the Markdown itself — follow up with get_doc and includeContent: true.
Typical errors — VALIDATION_ERROR (limit out of range, malformed cursor).
picora.get_doc
Metadata for one standalone document, optionally with its full Markdown text.
Scope kb.read · Billing tier read · Rate tier read · Plan any
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | string | yes | Exactly 21 characters (nanoid) |
includeContent | boolean | no | Also fetch the raw Markdown. Default false |
Use it when you have a document id and need its metadata, or its body to summarise or edit. Content above 5 MB is truncated to 4.99 MB with truncated: true; for very large documents fetch /v1/docs/:id/raw over HTTP instead.
Don’t use it for documents inside a knowledge base addressed by path — that’s read_kb_doc.
Typical errors — NOT_FOUND, VALIDATION_ERROR (id is not 21 characters).
picora.delete_doc
Delete one or more standalone Markdown documents. Irreversible.
Scope kb.write · Billing tier write · Rate tier mutation · Plan any
Input
| Field | Type | Required | Notes |
|---|---|---|---|
ids | string[] | yes | 1–50 document ids, each exactly 21 characters |
dryRun | boolean | no | Default true — returns a willDelete preview. Set false only after user confirmation |
Use it with the same two-step protocol as delete_media: preview → confirm with the user → delete.
Note: embedded images that were uploaded into the user’s image quota are not cascaded — an image may be referenced by several documents, so orphan cleanup is handled separately.
Typical errors — MCP_SCOPE_INSUFFICIENT (needs a delete-capable key), NOT_FOUND, VALIDATION_ERROR (more than 50 ids).
Knowledge base tools
A knowledge base (KB) is a named workspace holding documents under relative paths — a cloud folder tree. The usual flow is list_kbs → get_kb_manifest → read_kb_doc → sync_kb.
picora.list_kbs
List the account’s knowledge bases, with cursor pagination.
Scope kb.read · Billing tier read · Rate tier read · Plan any
Input
| Field | Type | Required | Notes |
|---|---|---|---|
limit | number | no | 1–50, default 20 |
cursor | string | no | nextCursor from the previous response |
sort | updated_at | name | no | Default updated_at (descending) |
type | all | creator | output | no | creator = personal workspaces, output = publishable output KBs. Omit for all |
Use it first in any KB workflow — you need a kbId before you can call get_kb_manifest, read_kb_doc or sync_kb.
Don’t use it for listing flat standalone documents; that’s list_docs.
Typical errors — VALIDATION_ERROR (limit out of range).
picora.create_kb
Create a new knowledge base.
Scope kb.write · Billing tier write · Rate tier mutation · Plan any (KB count limit: Trial 5 / Pro 50 / Pro+ 500)
Input
| Field | Type | Required | Notes |
|---|---|---|---|
name | string | yes | Display name, 1–120 chars |
slug | string | no | Path-friendly id ^[a-z0-9][a-z0-9-]{0,62}[a-z0-9]$. Derived from name when omitted. Immutable after creation |
description | string | no | ≤ 500 chars |
kbType | creator | output | no | Default creator. Immutable after creation |
Use it when the user asks for a new KB / workspace / notebook for synced documents.
Don’t use it for uploading a single standalone document (upload_doc) or writing files into an existing KB (sync_kb).
Typical errors — KB_LIMIT_REACHED (plan KB limit), CONFLICT (slug taken), VALIDATION_ERROR (name empty or slug malformed).
picora.get_kb_manifest
The file manifest of a KB: every document’s relativePath, sourceHash, sizeBytes and updatedAt. Metadata only, no content.
Scope kb.read · Billing tier read · Rate tier read · Plan any
Input
| Field | Type | Required | Notes |
|---|---|---|---|
kbId | string | yes | 21-char nanoid from list_kbs |
since | string (date-time) | no | Incremental watermark, ISO 8601. Omit for a full listing |
cursor | string | no | nextCursor from the previous response |
limit | number | no | 1–1000, default 500 |
Use it as the entry point for browsing a KB’s directory structure and discovering file paths — before read_kb_doc (to find the exact path) and before sync_kb (to get baseUpdatedAt for optimistic locking).
- Full mode (no
since): all active documents; soft-deleted ones excluded. - Incremental mode (
sinceset): entries changed after that time, including soft-deleted ones (deletedAtnon-null). Store the response’sserverTimeand use it as the nextsince. - Sync protocol v2 (header
Picora-Sync-Version: 2) also returnstombstones— hard-deleted documents retained for 30 days (90 for Pro+) so other clients can drop their local copies. - One page per call, sorted by
updatedAtdescending. Keep calling withcursor: <nextCursor>while it is non-null.
Don’t use it for reading file content (read_kb_doc) or listing KBs themselves (list_kbs).
Typical errors — NOT_FOUND (unknown kbId), VALIDATION_ERROR (since not ISO 8601, limit out of range).
picora.read_kb_doc
Read the raw text of a single document inside a KB, addressed by its relative path.
Scope kb.read · Billing tier read · Rate tier read · Plan any
Input
| Field | Type | Required | Notes |
|---|---|---|---|
kbId | string | yes | 21-char nanoid from list_kbs |
path | string | yes | POSIX relative path, 1–1024 chars, e.g. notes/idea.md or .claude/memory.md. No leading /, no .. |
Use it after get_kb_manifest has revealed the paths. Returns the full text plus sourceHash (SHA-256 of content) and updatedAt — keep that updatedAt and pass it as baseUpdatedAt in a later sync_kb upsert to avoid conflicts. Content over 5 MB is truncated with truncated: true.
Don’t guess paths — discover them via get_kb_manifest first. And don’t use this with a document id; standalone documents use get_doc.
Typical errors — NOT_FOUND (no such path in that KB), VALIDATION_ERROR (leading /, .. traversal, path too long).
picora.sync_kb
Batch-write into a KB: up to 100 operations per call, each one an upsert, delete or move.
Scope kb.write · Billing tier write · Rate tier upload · Plan any
Input
| Field | Type | Required | Notes |
|---|---|---|---|
kbId | string | yes | 21-char nanoid from list_kbs |
ops | array | yes | 1–100 operations, each of the three shapes below |
upsert — create or overwrite content at a path:
| Field | Type | Required | Notes |
|---|---|---|---|
op | "upsert" | yes | |
relativePath | string | yes | POSIX relative path, ≤ 1024 chars. No leading /, no .. |
content | string | yes | Full document text (UTF-8) |
sourceHash | string | no | SHA-256 hex (64 lowercase chars) of content; computed for you when omitted |
baseUpdatedAt | string (date-time) | no | Optimistic lock — the updatedAt you last saw. Omit only when creating a new path |
title | string | no | ≤ 200 chars |
tags | string[] | no | Max 10, each ≤ 32 chars |
isPublic | boolean | no | Default private |
delete — soft-delete a path:
| Field | Type | Required | Notes |
|---|---|---|---|
op | "delete" | yes | |
relativePath | string | yes | Path of the document to delete |
baseUpdatedAt | string (date-time) | no | Optimistic lock; omitting it on an existing doc yields a BASE_MISSING conflict |
move — rename or relocate; content and document id are unchanged:
| Field | Type | Required | Notes |
|---|---|---|---|
op | "move" | yes | |
fromPath | string | yes | Current path |
toPath | string | yes | New path; must not be occupied by an active document |
baseUpdatedAt | string (date-time) | no | Optimistic lock on the source document |
Use it to save, update, reorganise or remove files inside a KB.
Don’t use it for standalone documents outside a KB (upload_doc / delete_doc), or to create the KB itself (create_kb).
Conflict semantics — read this before you write any sync loop
Operations apply independently. The call returns HTTP 200 with three arrays — applied, conflicts, skipped. Partial success is normal, so always inspect conflicts.
baseUpdatedAt is the optimistic lock: pass the updatedAt you last saw from get_kb_manifest or read_kb_doc. Omitting it means “create new”.
| Conflict code | Meaning | Resolution |
|---|---|---|
BASE_MISSING | No baseUpdatedAt given but the path already exists — rejected instead of silently overwriting | Read the current version, then resend with its updatedAt |
REMOTE_NEWER | Your baseUpdatedAt is stale; the server kept its newer version | Re-read with read_kb_doc, merge yourself, resend |
REMOTE_DELETED | The server deleted the document in the meantime | Decide whether to recreate it |
MOVE_SOURCE_MISSING | fromPath does not exist | Re-check the manifest |
MOVE_TARGET_EXISTS | toPath is occupied by an active document | Pick another path, or delete the target first |
The server never merges content. Resolution is always: re-read, then resend with a fresh baseUpdatedAt.
Side effects — writes documents (new paths consume the document-count quota), soft-deletes, or moves them. move and delete leave tombstones so other synced clients drop stale local copies. Upserting identical content at the same path is de-duplicated server-side, and re-sending a delete for an already-deleted path lands in skipped — so retrying a whole batch is safe.
Typical errors — QUOTA_EXCEEDED (document count), NOT_FOUND (unknown kbId), VALIDATION_ERROR (over 100 ops, malformed path, bad sourceHash).
Gate errors common to every tool
Before a tool runs, the server checks the catalog, the token’s scopes, and the plan — in that order.
| Code | Meaning |
|---|---|
MCP_TOOL_NOT_FOUND | The slug is not in the catalog — check tools.json, or the tool may not be deployed yet |
MCP_SCOPE_INSUFFICIENT | Token is missing a scope; meta.required and meta.missing list which |
MCP_PLAN_INSUFFICIENT | The plan gate failed; meta.required and meta.current say which plan is needed |
RATE_LIMITED | The rate-limit bucket for this tier is exhausted — back off and retry |
See Concepts for the full authentication and rate-limit model.