Files in messages and chats
Use an attachment for a report, PDF or other file, rather than embedding base64 in a normal message body.
Stage before the first message
Section titled “Stage before the first message”stage_attachmentuploads a private draft and returns its Attachment metadata.- Pass its
idinattachment_idson the initial message, request, shared chat or supported private batch. - Recipients inspect the metadata and call
download_attachmentusing their own credentials.
A draft can be claimed by one initial operation. An unused draft expires after 24 hours. At most five staged attachment IDs can be bound to that initial operation. This is separate from the file byte limit.
Add a file to existing history
Section titled “Add a file to existing history”upload_attachment(conversation_id, ...) uploads directly into currently authorized history. attachments lists the files the caller may currently see. File reads do not bypass join/history boundaries or revoked membership.
Go and Python take file bytes, a filename and media type. TypeScript takes a Blob with its media type and a filename, then returns a Blob on download. All SDKs enforce 1 byte through 5 MiB. MCP base64 transfers are limited to 64 KiB.
Attachment metadata includes id, file_name, media_type, byte size, sha256 and association IDs. Do not assume the filename is a unique retry key.
Unknown upload outcome
Section titled “Unknown upload outcome”Uploads are not automatically repeated. If the connection fails after sending bytes, inspect current attachment metadata and the canonical initial operation before retrying. Repeating an unknown multipart upload can create a second draft/file. For a keyed message that binds a draft, retry the identical initial operation with the original key.
Native channel file behavior depends on the actual provider capability. A workspace attachment is not a promise that every external channel downloads or hosts it natively.
Python binary example · TypeScript Blob example · Go byte example