Skip to main content
Glama

Download attachment

download_attachment
Read-only

Save an OpenProject attachment to disk using its attachment ID, streaming bytes in chunks and returning path, size, content type, and SHA-256 for verification.

Instructions

Download an attachment's bytes to a file on the machine running this server.

Use it once list_attachments (or get_work_package(include=['attachments'])) has given you an attachment_id. Metadata is read first, then the bytes are streamed to disk in chunks with progress notifications, so a large file neither stalls the call nor buffers in memory.

Returns path, file_name, size_bytes, content_type and the SHA-256 of the bytes (use it to verify or de-duplicate). With return_image=true an image of at most 1 MB comes back as an inline image block as well.

Pitfalls: the file is written on the server's machine, which is the user's machine only in a local (stdio) deployment — tell the user the returned path rather than assuming they can see it. Quarantined attachments fail with attachment_quarantined and are never fetched. An attachment whose virus scan is unfinished answers 401 for everyone except its uploader. Transfers above OPENPROJECT_MCP_MAX_DOWNLOAD_MB (default 100) are refused up front and aborted mid-stream, leaving no partial file. A name collision in the target directory saves as 'name (2).ext' and says so in notes.

Related: list_attachments produces attachment_id; upload_attachment is the reverse direction.

Input Schema

NameRequiredDescriptionDefault
save_dirNoAbsolute directory to save into; it is created when missing. Defaults to OPENPROJECT_MCP_DOWNLOAD_DIR, and otherwise to an 'openproject-downloads' folder beside the server's working directory. Relative paths are rejected because the server's working directory is not the user's.
return_imageNoAlso return the file as an inline image so the model can look at it. Honored only for image/* content of at most 1 MB; otherwise the file is still saved and a note explains why nothing was shown.
attachment_idYesNumeric attachment id from list_attachments or get_work_package(include=['attachments']). Not a work package id.

Output Schema

NameRequiredDescriptionDefault
pathYes
notesNo
sha256Yes
file_nameYes
size_bytesYes
content_typeNo

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed11 schema fields changedv0.4.0
    • removedOutput schema / description
      Removed value: -"Where the bytes landed and what they were."
    • removedOutput schema / properties / content_type / anyOf
      Removed value: -[
      -  {
      -    "type": "string"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • removedOutput schema / properties / content_type / default
      Removed value: -null
    • removedOutput schema / properties / content_type / description
      Removed value: -"MIME type reported by OpenProject."
    • addedOutput schema / properties / content_type / type
      Added value: +[
      +  "string",
      +  "null"
      +]
    • removedOutput schema / properties / file_name / description
      Removed value: -"Name the file was saved under; may differ from the attachment's own name when it collided with an existing file."
    • removedOutput schema / properties / notes / default
      Removed value: -null
    • removedOutput schema / properties / notes / description
      Removed value: -"Degradation markers: renamed target, image not shown inline, …"
    • removedOutput schema / properties / path / description
      Removed value: -"Absolute path of the saved file on the MCP server's machine."
    • removedOutput schema / properties / sha256 / description
      Removed value: -"SHA-256 of the downloaded bytes, hex encoded."
    • removedOutput schema / properties / size_bytes / description
      Removed value: -"Bytes actually written to disk."
  2. First observedv0.1.0

TDQS

A4.1/5.0
Behavior1/5

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

The description explicitly says the bytes are streamed to disk and that a file is written on the server's machine, which is a filesystem side effect. This directly contradicts the annotation readOnlyHint=true, so despite otherwise rich behavioral detail, the contradiction requires a score of 1.

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 definition is front-loaded with the core action and then organized into scoped paragraphs for return values, pitfalls, and related tools. Despite its length, every sentence adds operational value for a download tool with several failure modes.

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?

An output schema exists, and the description still adds important context: returned fields, SHA-256 verification, progress notifications, size limits, partial-file behavior, and path visibility caveats. It gives an agent everything needed to call the tool correctly, apart from the annotation mismatch noted above.

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

Parameters4/5

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

Schema coverage is 100%, so the schema already documents all three parameters. The description still adds useful semantics beyond the schema, especially return_image's 1 MB inline-image limit, attachment_id provenance, and target-directory collision behavior.

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 uses a specific verb and resource: downloading an attachment's bytes to a file. It names how to obtain attachment_id via list_attachments or get_work_package(include=['attachments']), and explicitly distinguishes the operation from upload_attachment.

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?

It states the prerequisite clearly and places the tool relative to siblings: use list_attachments first, upload_attachment is the reverse direction. It also gives detailed when-not and failure conditions, including quarantined attachments, unfinished virus scans, size limits, and path collisions.

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