feat: add upload_attachment MCP tool
All checks were successful
Build and Push Docker Image / build (push) Successful in 24s
All checks were successful
Build and Push Docker Image / build (push) Successful in 24s
Add support for uploading file attachments to Grist documents: - GristClient.upload_attachment() method using multipart/form-data - upload_attachment tool function with base64 decoding and MIME detection - Tool registration in server.py - Comprehensive unit tests (7 new tests) Returns attachment ID for linking to records via update_records. Bumps version to 1.3.0.
This commit is contained in:
@@ -1,4 +1,7 @@
|
||||
"""Write tools - create, update, delete records."""
|
||||
"""Write tools - create, update, delete records, upload attachments."""
|
||||
|
||||
import base64
|
||||
import mimetypes
|
||||
|
||||
from grist_mcp.auth import Agent, Authenticator, Permission
|
||||
from grist_mcp.grist_client import GristClient
|
||||
@@ -59,3 +62,50 @@ async def delete_records(
|
||||
|
||||
await client.delete_records(table, record_ids)
|
||||
return {"deleted": True}
|
||||
|
||||
|
||||
async def upload_attachment(
|
||||
agent: Agent,
|
||||
auth: Authenticator,
|
||||
document: str,
|
||||
filename: str,
|
||||
content_base64: str,
|
||||
content_type: str | None = None,
|
||||
client: GristClient | None = None,
|
||||
) -> dict:
|
||||
"""Upload a file attachment to a document.
|
||||
|
||||
Args:
|
||||
agent: The authenticated agent.
|
||||
auth: Authenticator for permission checks.
|
||||
document: Document name.
|
||||
filename: Filename with extension.
|
||||
content_base64: File content as base64-encoded string.
|
||||
content_type: MIME type (auto-detected from filename if omitted).
|
||||
client: Optional GristClient instance.
|
||||
|
||||
Returns:
|
||||
Dict with attachment_id, filename, and size_bytes.
|
||||
|
||||
Raises:
|
||||
ValueError: If content_base64 is not valid base64.
|
||||
"""
|
||||
auth.authorize(agent, document, Permission.WRITE)
|
||||
|
||||
# Decode base64 content
|
||||
try:
|
||||
content = base64.b64decode(content_base64)
|
||||
except Exception:
|
||||
raise ValueError("Invalid base64 encoding")
|
||||
|
||||
# Auto-detect MIME type if not provided
|
||||
if content_type is None:
|
||||
content_type, _ = mimetypes.guess_type(filename)
|
||||
if content_type is None:
|
||||
content_type = "application/octet-stream"
|
||||
|
||||
if client is None:
|
||||
doc = auth.get_document(document)
|
||||
client = GristClient(doc)
|
||||
|
||||
return await client.upload_attachment(filename, content, content_type)
|
||||
|
||||
Reference in New Issue
Block a user