Skip to content

feat(attachments): add work package attachment tools#24

Open
i-matveev wants to merge 1 commit into
AndyEverything:mainfrom
i-matveev:feat/attachments
Open

feat(attachments): add work package attachment tools#24
i-matveev wants to merge 1 commit into
AndyEverything:mainfrom
i-matveev:feat/attachments

Conversation

@i-matveev

Copy link
Copy Markdown

Summary

Adds support for work package attachments, which were not covered by any existing tool. This makes it possible to list, read, download, upload and delete files attached to OpenProject work packages.

New tools (5)

Tool Description
list_attachments List all attachments of a work package
get_attachment Get metadata for a single attachment
download_attachment Download content (inline text, or save to disk via save_path)
upload_attachment Upload a local file (multipart/form-data)
delete_attachment Delete an attachment

Tool count: 49 → 54.

Implementation notes

  • src/client.py — new client methods list_work_package_attachments, get_attachment, delete_attachment, download_attachment, upload_attachment.
    • download_attachment follows the /attachments/{id}/content redirect manually so the API key is not forwarded to external object storage (which would otherwise reject the request). Local-storage instances (direct content) are handled too.
    • upload_attachment sends multipart/form-data without the JSON Content-Type header so aiohttp sets the multipart boundary itself; metadata + file parts follow the OpenProject API v3 contract.
  • src/tools/attachments.py — FastMCP tools following the existing module pattern (pydantic input model for upload, format_success/format_error helpers). download_attachment returns text content inline and asks for a save_path for binary content.
  • src/server.py — registers the new module.
  • README.md — documents tools #41–#45.
  • test_attachments.py — offline validation of the input model and formatting helpers (same dry-run style as test_tools.py).

Testing

Verified end-to-end against a live OpenProject instance:

  • list_attachments / get_attachment on a work package with attachments ✅
  • download_attachment inline text + redirect handling ✅
  • upload_attachmentdelete_attachment round-trip (cleans up after itself) ✅
  • test_attachments.py passes ✅
  • All 54 tool modules load successfully ✅

Add support for OpenProject work package attachments, which were not
covered by any existing tool.

Client (src/client.py):
- list_work_package_attachments, get_attachment, delete_attachment
- download_attachment: follows the content redirect manually so the API
  key is not forwarded to external object storage
- upload_attachment: multipart/form-data without the JSON Content-Type
  header so aiohttp sets the multipart boundary

Tools (src/tools/attachments.py): list_attachments, get_attachment,
download_attachment (inline text or save_path), upload_attachment,
delete_attachment. Registered in src/server.py (49 -> 54 tools).

Docs + tests: README tool list (#41-#45) and offline test_attachments.py.
@AndreaV-Lsi

AndreaV-Lsi commented Jul 16, 2026

Copy link
Copy Markdown

Thanks for this, @i-matveev — the attachment tools fill a real gap (list / get / download / upload / delete were all missing), and the details are well handled: not forwarding the API key through the storage redirect, and letting aiohttp own the multipart boundary.

For transparency on where it has landed: LS Instruments maintains an actively developed downstream fork of this project (https://github.com/LS-Instruments/openproject-mcp-server) that we're advancing for day-to-day agentic project management on OpenProject. Given the current upstream review cadence we're maintaining that fork independently for now.

As part of that we've integrated your change, adapted to our fork's modular layout and covered by an offline unit test plus a live end-to-end integration test (upload → list → get → download round-trip → delete against OpenProject 17.5.1). Your authorship is preserved: the commit carries you as co-author and you're credited in our NOTICE. Everything stays under the project's MIT license.

Integrated into our main branch: LS-Instruments@a0d46cb.

We'd gladly contribute this back upstream if review capacity returns, and you're welcome to draw from our fork in the meantime. Thanks again.

AndreaV-Lsi added a commit to LS-Instruments/openproject-mcp-server that referenced this pull request Jul 16, 2026
Adds 5 tools for work package attachments (previously unsupported):
list_attachments, get_attachment, download_attachment, upload_attachment,
delete_attachment, plus the backing client methods.

- download_attachment follows the /attachments/{id}/content storage redirect
  manually so the API key is not forwarded to external object storage; text
  content is returned inline, binary content is saved via save_path.
- upload_attachment sends multipart/form-data without the JSON Content-Type
  header so aiohttp sets the multipart boundary.

Ported from upstream PR AndyEverything#24 by @i-matveev,
adapted to this fork's conventions. Verified end to end against an ephemeral
OpenProject 17 (upload -> list -> get -> download round-trip -> delete) and with
an offline unit test for the input model and formatting helpers.

Closes #13

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: i-matveev <i-matveev@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants