feat(deck): add file/note attachment MCP tools
Adds four tools that expose Deck card attachments via the MCP surface: deck_attach_file, deck_attach_note, deck_list_attachments, and deck_delete_attachment. The attach* variants share an existing Files entry (or Notes-app note) with the card via OCS shareType=12 — same mechanism the Deck UI's "Share from Files" picker uses, no file copy. This replaces the prior workaround of appending bulky activity content as Deck card comments: per-PR/per-event narrative now lives in NC Notes and surfaces on the tracking card as a clickable attachment that opens the original note in place. Implementation reuses existing client methods (SharingClient.create_share, DeckClient.get/delete_attachment, NotesClient.get_settings/get_note); no new client code. _SHARE_TYPE_DECK is centralised with a CI-guard test to prevent silent drift, and SharingClient.create_share's wire format is pinned to what the Deck Vue source sends. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
bfbb294d86
commit
c0a974c498
@@ -144,6 +144,11 @@ class DeckAttachmentExtendedData(BaseModel):
|
||||
filesize: int
|
||||
mimetype: str
|
||||
info: Dict[str, str]
|
||||
# Populated for type="file" (Files share) attachments via FilesAppService.
|
||||
path: Optional[str] = None
|
||||
fileid: Optional[int] = None
|
||||
hasPreview: Optional[bool] = None
|
||||
permissions: Optional[int] = None
|
||||
|
||||
|
||||
class DeckAttachment(BaseModel):
|
||||
@@ -308,3 +313,37 @@ class CardCommentOperationResponse(StatusResponse):
|
||||
|
||||
card_id: int = Field(description="ID of the card the comment belongs to")
|
||||
comment_id: int = Field(description="ID of the affected comment")
|
||||
|
||||
|
||||
# Attachment Response Models
|
||||
|
||||
|
||||
class AttachFileResponse(BaseResponse):
|
||||
"""Response model for attaching an existing Nextcloud file to a Deck card.
|
||||
|
||||
The attachment is created by sharing the file with the card via the standard
|
||||
OCS Sharing API using ``shareType=12`` (``IShare::TYPE_DECK``). The returned
|
||||
``attachment_id`` is the share ID, which is also the Deck attachment ID.
|
||||
"""
|
||||
|
||||
attachment_id: int = Field(
|
||||
description="ID of the created attachment (share ID)",
|
||||
)
|
||||
card_id: int = Field(description="ID of the card the file is attached to")
|
||||
path: str = Field(description="Path of the shared file in the user's Files")
|
||||
|
||||
|
||||
class ListAttachmentsResponse(BaseResponse):
|
||||
"""Response model for listing card attachments."""
|
||||
|
||||
results: list["DeckAttachment"] = Field(
|
||||
description="Attachments on the card (both type='file' and type='deck_file')"
|
||||
)
|
||||
count: int = Field(description="Number of attachments returned")
|
||||
|
||||
|
||||
class AttachmentOperationResponse(StatusResponse):
|
||||
"""Response model for attachment operations that don't return data (e.g. delete)."""
|
||||
|
||||
card_id: int = Field(description="ID of the card the attachment belongs to")
|
||||
attachment_id: int = Field(description="ID of the affected attachment")
|
||||
|
||||
Reference in New Issue
Block a user