forgejo-mcp/demos/comment-attachments.md
Christoph Görn 03aaf58679
feat: ✨ add issue & comment attachment tools (closes #106)
Implements 12 new MCP tools for full CRUD on issue and comment
attachments via a new raw-HTTP helper, bypassing the SDK gap.

New packages:
- pkg/forgejo/rawhttp.go: DoJSON, DoJSONList, DoMultipart, DoRaw
  with 1 MiB inline cap (ErrPayloadTooLarge sentinel), auth-header
  propagation, and 401/403/404 error sentinels
- operation/attachment/attachment.go: 12 tools registered under the
  new "attachment" CLI domain

Key design decisions (see docs/plans/issue-attachments.md):
- Files < 1 MiB: inline as BlobResourceContents + metadata JSON
- Files >= 1 MiB: metadata + browser_download_url only; caller fetches
  with Authorization: token (verified live against Codeberg API)
- Always includes browser_download_url regardless of size
- 404 on list endpoints treated as empty array, not error

Also:
- operation/params/params.go: attachment param descriptions
- operation/operation.go + cmd/cli.go: registration wired
- README.md: tool table updated
- demos/issue-attachments.md + demos/comment-attachments.md added
2026-04-26 13:10:49 +02:00

3.5 KiB

Demo: comment attachments — full CRUD

2026-04-26T13:12:00Z

What these tools do

Six MCP tools mirror the issue-attachment tools but operate on issue/PR comment attachments — the same lifecycle (list, get, download, create, edit, delete), keyed by comment_id instead of index:

  • list_comment_attachments
  • get_comment_attachment
  • download_comment_attachment (inline if < 1 MiB; metadata + URL otherwise)
  • create_comment_attachment
  • edit_comment_attachment
  • delete_comment_attachment

Same wire format, same 1 MiB cap, same "always include browser_download_url" contract as the issue-attachment tools. See demos/issue-attachments.md for the design rationale.

Setup

export FORGEJO_URL=https://codeberg.org
export FORGEJO_ACCESS_TOKEN=...
make build

End-to-end lifecycle

1. Create a comment to attach to

./forgejo-mcp --cli create_issue_comment \
  --args '{"owner":"goern","repo":"forgejo-mcp","index":108,"body":"Comment for attachment demo"}'

The response includes the new comment's id — use that as comment_id below.

2. Upload an attachment to the comment

B64=$(base64 -w0 /tmp/snippet.txt)
./forgejo-mcp --cli create_comment_attachment \
  --args "{\"owner\":\"goern\",\"repo\":\"forgejo-mcp\",\"comment_id\":13781165,\"content\":\"$B64\",\"filename\":\"snippet.txt\",\"mime_type\":\"text/plain\"}"
[
  {
    "type": "text",
    "text": "{\"Result\":{\"id\":1174940,\"name\":\"snippet.txt\",\"size\":24,\"download_count\":0,\"created_at\":\"2026-04-26T12:59:29+02:00\",\"uuid\":\"251ef6f2-b2c4-4fc5-877e-cc4573bdd884\",\"browser_download_url\":\"https://codeberg.org/attachments/251ef6f2-b2c4-4fc5-877e-cc4573bdd884\"}}"
  }
]

3. List comment attachments

./forgejo-mcp --cli list_comment_attachments \
  --args '{"owner":"goern","repo":"forgejo-mcp","comment_id":13781165}'
[
  {
    "type": "text",
    "text": "{\"Result\":[{\"id\":1174940,\"name\":\"snippet.txt\",\"size\":24,...}]}"
  }
]

4. Get single-attachment metadata

./forgejo-mcp --cli get_comment_attachment \
  --args '{"owner":"goern","repo":"forgejo-mcp","comment_id":13781165,"attachment_id":1174940}'

5. Download

./forgejo-mcp --cli download_comment_attachment \
  --args '{"owner":"goern","repo":"forgejo-mcp","comment_id":13781165,"attachment_id":1174940}'

Same response shape as download_issue_attachment — a JSON text part and (if under cap) an EmbeddedResource with the base64 blob.

6. Rename

./forgejo-mcp --cli edit_comment_attachment \
  --args '{"owner":"goern","repo":"forgejo-mcp","comment_id":13781165,"attachment_id":1174940,"name":"renamed.txt"}'

7. Delete

./forgejo-mcp --cli delete_comment_attachment \
  --args '{"owner":"goern","repo":"forgejo-mcp","comment_id":13781165,"attachment_id":1174940}'
[
  {
    "type": "text",
    "text": "{\"Result\":{\"status\":\"deleted\"}}"
  }
]

Pattern: agent walks an issue with attachments scattered across comments

1. get_issue_by_index            → see issue body, comment count
2. list_issue_attachments        → see issue-level attachments
3. list_issue_comments           → enumerate comment IDs
4. for each comment_id:
     list_comment_attachments    → discover comment-level attachments
5. download_*_attachment         → pull bytes for any relevant file

This pattern lets an agent fully reconstruct an issue's attachment graph — the gap reported in #106.