Files
grist-mcp-server/tests/unit/test_tools_write.py
Bill a7c87128ef
All checks were successful
Build and Push Docker Image / build (push) Successful in 8s
feat: replace MCP attachment tool with proxy endpoint
The MCP tool approach was impractical because it required the LLM to
generate large base64 strings token-by-token, causing timeouts.

Changes:
- Remove upload_attachment MCP tool
- Add POST /api/v1/attachments endpoint for multipart/form-data uploads
- Update proxy documentation to show both endpoints
- Uses existing GristClient.upload_attachment() method
- Requires write permission in session token
2026-01-03 20:26:36 -05:00

97 lines
2.4 KiB
Python

import pytest
from unittest.mock import AsyncMock
from grist_mcp.tools.write import add_records, update_records, delete_records
from grist_mcp.auth import Authenticator, AuthError
from grist_mcp.config import Config, Document, Token, TokenScope
@pytest.fixture
def config():
return Config(
documents={
"budget": Document(
url="https://grist.example.com",
doc_id="abc123",
api_key="key",
),
},
tokens=[
Token(
token="write-token",
name="write-agent",
scope=[TokenScope(document="budget", permissions=["read", "write"])],
),
Token(
token="read-token",
name="read-agent",
scope=[TokenScope(document="budget", permissions=["read"])],
),
],
)
@pytest.fixture
def auth(config):
return Authenticator(config)
@pytest.fixture
def mock_client():
client = AsyncMock()
client.add_records.return_value = [1, 2]
client.update_records.return_value = None
client.delete_records.return_value = None
return client
@pytest.mark.asyncio
async def test_add_records(auth, mock_client):
agent = auth.authenticate("write-token")
result = await add_records(
agent, auth, "budget", "Table1",
records=[{"Name": "Alice"}, {"Name": "Bob"}],
client=mock_client,
)
assert result == {"inserted_ids": [1, 2]}
@pytest.mark.asyncio
async def test_add_records_denied_without_write(auth, mock_client):
agent = auth.authenticate("read-token")
with pytest.raises(AuthError, match="Permission denied"):
await add_records(
agent, auth, "budget", "Table1",
records=[{"Name": "Alice"}],
client=mock_client,
)
@pytest.mark.asyncio
async def test_update_records(auth, mock_client):
agent = auth.authenticate("write-token")
result = await update_records(
agent, auth, "budget", "Table1",
records=[{"id": 1, "fields": {"Name": "Updated"}}],
client=mock_client,
)
assert result == {"updated": True}
@pytest.mark.asyncio
async def test_delete_records(auth, mock_client):
agent = auth.authenticate("write-token")
result = await delete_records(
agent, auth, "budget", "Table1",
record_ids=[1, 2],
client=mock_client,
)
assert result == {"deleted": True}