Skip to main content
Glama

Download attachment

download_attachment
Read-only

Download an attachment to a file on the server machine, streaming large files to disk in chunks. Returns file path, size, 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

TableJSON 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

TableJSON Schema
NameRequiredDescriptionDefault
pathYesAbsolute path of the saved file on the MCP server's machine.
notesNoDegradation markers: renamed target, image not shown inline, …
sha256YesSHA-256 of the downloaded bytes, hex encoded.
file_nameYesName the file was saved under; may differ from the attachment's own name when it collided with an existing file.
size_bytesYesBytes actually written to disk.
content_typeNoMIME type reported by OpenProject.
Behavior5/5

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

Annotations only hint at read-only and non-destructive intent, but the description explains actual behavior: streaming to disk with progress, return fields including SHA-256, local-vs-server path caveat, quarantine and virus-scan failures, size limits with mid-stream aborts, and name-collision handling. This far exceeds annotation coverage.

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 long but every sentence earns its place. It is structured with a clear lead, workflow, return-value summary, pitfalls, and related tools, making it scannable and information-dense without redundancy.

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?

Covers the full lifecycle: prerequisites, execution behavior, return values, error conditions, size limits, filename conflicts, and deployment context. For a tool with this complexity and an output schema, the description is complete and self-contained.

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 critical nuances: attachment_id is explicitly 'Not a work package id', save_dir defaults and relative-path rejection rationale, and return_image's 1 MB/type limitations. This adds real semantic value beyond the schema.

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 'Download an attachment's bytes to a file on the machine running this server,' which uses a specific verb and resource, clearly distinguishing it from sibling tools like upload_attachment, list_attachments, and delete_attachment. It also references related tools, reinforcing its unique role.

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?

Explicitly states when to use ('Use it once list_attachments (or get_work_package(include=["attachments"])) has given you an attachment_id') and provides prerequisites. It also covers when not to use (quarantined, unfinished virus scan, oversized files) and names the reverse operation (upload_attachment).

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

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/kar-thik/openproject-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server