Skip to main content
Glama

Upload document

well_upload_document

Upload a document (invoice, receipt, statement) into the workspace by sending its bytes as base64.

⚠️ THIS IS A WIDGET'S WRITE, NOT YOURS. The card's drop zone reads the file the person dropped or chose, encodes it, and calls this tool itself. Do NOT call it: a model holds no file, so a call made from a conversation can only carry bytes nobody supplied. When a person says they have the invoice, point them at the drop zone on the gap card.

Send content_base64 WITHOUT a data-URI prefix — the raw base64 only, no data:application/pdf;base64, header.

Accepted content: PDF, JPEG, PNG, GIF, HEIC, HEIF, AVIF, WEBP, TIFF, plain text, CSV, XML. The bytes are checked against the declared mime_type (file signature, not just the claim), so a PNG announced as a PDF is refused.

Size ceiling: 5 MB of file (before base64). A larger file is refused with its actual size — upload it through the web app instead, which accepts up to 15 MB.

Pass source_transaction_id to anchor the document to the bank transaction it pays. That is what makes a dropped invoice land on the right line instead of in a general inbox.

Well extracts the document after upload; the extraction is asynchronous and this call returns as soon as the file is stored. A file already in the workspace is deduplicated by content and returns the existing document rather than a copy.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
filenameYesThe file's name WITH its extension, e.g. `invoice-2026-03.pdf`. The extension resolves the content type when `mime_type` is generic.
mime_typeYesThe file's content type, e.g. `application/pdf`. Send `application/octet-stream` when unknown and the extension decides.
workspace_idNoTarget workspace. Omit when the token authorizes one workspace. Required when it authorizes several — a write lands in exactly one workspace and this call would not say which.
content_base64YesThe file's bytes, base64, with no data-URI prefix.
source_task_idNoThe task this document answers.
conversation_idNoThe conversation id returned by the previous Well result, in its meta under well/conversation_id, in its structuredContent, or in its JSON text block. Pass it back on every call in the same conversation, including a call a card makes, so the chosen workspace and the earlier answers still apply. It decides the conversation on its own: nothing the host states about the session replaces it. Omit it only on the first call of a conversation.
idempotency_keyNoOptional client-supplied key. A retried write with the same key returns the original result instead of re-applying the operation.
source_transaction_idNoThe bank transaction this document is the proof for.

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
errorNo
outcomeNo
successYes
filenameNo
max_bytesNo
mime_typeNo
error_codeNo
size_bytesNo
document_idNo
actual_bytesNo
deduplicatedNo
source_task_idNo
conversation_idNoThe conversation this result belongs to. Pass it back as the conversation_id argument on every later Well call in the same conversation.
conversation_id_noteNoPresent only when the server opened a fresh lane, stating that no choice recorded earlier was read.
source_transaction_idNo
conversation_id_sourceNoWhere the conversation id came from: the host's own request meta, the caller's argument, or a fresh lane the server opened.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed4 schema fields changed
    • addedInput schema / properties / conversation_id
      Added value: +{
      +  "description": "The conversation id returned by the previous Well result, in its meta under well/conversation_id, in its structuredContent, or in its JSON text block. Pass it back on every call in the same conversation, including a call a card makes, so the chosen workspace and the earlier answers still apply. It decides the conversation on its own: nothing the host states about the session replaces it. Omit it only on the first call of a conversation.",
      +  "type": "string"
      +}
    • addedOutput schema / properties / conversation_id
      Added value: +{
      +  "description": "The conversation this result belongs to. Pass it back as the conversation_id argument on every later Well call in the same conversation.",
      +  "type": "string"
      +}
    • addedOutput schema / properties / conversation_id_note
      Added value: +{
      +  "description": "Present only when the server opened a fresh lane, stating that no choice recorded earlier was read.",
      +  "type": "string"
      +}
    • addedOutput schema / properties / conversation_id_source
      Added value: +{
      +  "description": "Where the conversation id came from: the host's own request meta, the caller's argument, or a fresh lane the server opened.",
      +  "enum": [
      +    "host_meta",
      +    "argument",
      +    "minted"
      +  ],
      +  "type": "string"
      +}
  2. Changed1 schema field changed
    • removedInput schema / properties / filename / maxLength
      Removed value: -255
  3. Added

TDQS

A5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond annotations (readOnly=false, destructive=false), the description discloses numerous behavioral traits: the tool is intended for widget-only calls, the bytes are checked against the declared mime_type via file signature, the file is deduplicated by content, extraction is asynchronous and the call returns immediately after storage, and oversized files are refused with actual size. These details give the agent a complete mental model of the operation's side effects and constraints.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense but every sentence adds value. The critical warning is front-loaded right after the purpose statement tree. Content is organized into logical paragraphs: widget-only usage, encoding rules, accepted types, size limit, anchoring, and async behavior. There is no fluff or repetition; it is an efficient, well-structured explanation.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (8 parameters, write operation, async behavior, deduplication, size constraints), the description covers all necessary operational details. It complements the output schema (which explains return values) and the rich parameter descriptions. Nothing an agent needs to decide whether to call this tool, or to avoid calling it, is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Even though schema coverage is 100%, the description adds crucial semantics not present in the schema: content_base64 must be sent without a data-URI prefix, mime_type is validated against file signature (not just the claim), filename extension resolves content type when mime_type is generic, and source_transaction_id anchors the document to a bank transaction so it lands on the right line. This goes well beyond the schema's property descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and object: 'Upload a document (invoice, receipt, statement) into the workspace by sending its bytes as base64.' It clearly identifies the resource (document), the destination (workspace), and the mechanism (base64 bytes). It also distinguishes itself from sibling tools like well_upload_statement_bytes and well_create_invoice_document by listing document types and emphasizing the widget-driven flow.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly tells the agent when NOT to use the tool: 'THIS IS A WIDGET'S WRITE, NOT YOURS. Do NOT call it' and explains why ('a model holds no file'). It provides an alternative action for the agent ('point them at the drop zone on the gap card'). It also gives a size-based alternative ('upload it through the web app instead, which accepts up to 15 MB'), making the routing decision fully unambiguous.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.

Resources