From a7bb11d7651501919c4217a5e7328cd810c2d81c Mon Sep 17 00:00:00 2001 From: Bill Date: Fri, 2 Jan 2026 13:39:02 -0500 Subject: [PATCH] feat(tools): add get_proxy_documentation tool Add a new MCP tool that returns complete documentation for the HTTP proxy API. This enables agents to get all the information they need to construct valid proxy requests when writing scripts. The tool is stateless and returns a static documentation dict describing endpoints, methods, authentication, and example usage. --- src/grist_mcp/tools/session.py | 106 +++++++++++++++++++++++++++++++ tests/unit/test_tools_session.py | 16 +++++ 2 files changed, 122 insertions(+) create mode 100644 src/grist_mcp/tools/session.py create mode 100644 tests/unit/test_tools_session.py diff --git a/src/grist_mcp/tools/session.py b/src/grist_mcp/tools/session.py new file mode 100644 index 0000000..f1b957e --- /dev/null +++ b/src/grist_mcp/tools/session.py @@ -0,0 +1,106 @@ +"""Session token tools for HTTP proxy access.""" + +PROXY_DOCUMENTATION = { + "description": "HTTP proxy API for bulk data operations. Use request_session_token to get a short-lived token, then call the proxy endpoint directly from scripts.", + "endpoint": "POST /api/v1/proxy", + "authentication": "Bearer token in Authorization header", + "request_format": { + "method": "Operation name (required)", + "table": "Table name (required for most operations)", + }, + "methods": { + "get_records": { + "description": "Fetch records from a table", + "fields": { + "table": "string", + "filter": "object (optional)", + "sort": "string (optional)", + "limit": "integer (optional)", + }, + }, + "sql_query": { + "description": "Run a read-only SQL query", + "fields": {"query": "string"}, + }, + "list_tables": { + "description": "List all tables in the document", + "fields": {}, + }, + "describe_table": { + "description": "Get column information for a table", + "fields": {"table": "string"}, + }, + "add_records": { + "description": "Add records to a table", + "fields": {"table": "string", "records": "array of objects"}, + }, + "update_records": { + "description": "Update existing records", + "fields": {"table": "string", "records": "array of {id, fields}"}, + }, + "delete_records": { + "description": "Delete records by ID", + "fields": {"table": "string", "record_ids": "array of integers"}, + }, + "create_table": { + "description": "Create a new table", + "fields": {"table_id": "string", "columns": "array of {id, type}"}, + }, + "add_column": { + "description": "Add a column to a table", + "fields": { + "table": "string", + "column_id": "string", + "column_type": "string", + "formula": "string (optional)", + }, + }, + "modify_column": { + "description": "Modify a column's type or formula", + "fields": { + "table": "string", + "column_id": "string", + "type": "string (optional)", + "formula": "string (optional)", + }, + }, + "delete_column": { + "description": "Delete a column", + "fields": {"table": "string", "column_id": "string"}, + }, + }, + "response_format": { + "success": {"success": True, "data": "..."}, + "error": {"success": False, "error": "message", "code": "ERROR_CODE"}, + }, + "error_codes": [ + "UNAUTHORIZED", + "INVALID_TOKEN", + "TOKEN_EXPIRED", + "INVALID_REQUEST", + "GRIST_ERROR", + ], + "example_script": """#!/usr/bin/env python3 +import requests +import sys + +token = sys.argv[1] +host = sys.argv[2] + +response = requests.post( + f'{host}/api/v1/proxy', + headers={'Authorization': f'Bearer {token}'}, + json={ + 'method': 'add_records', + 'table': 'Orders', + 'records': [{'item': 'Widget', 'qty': 100}] + } +) +print(response.json()) +""", +} + + +async def get_proxy_documentation() -> dict: + """Return complete documentation for the HTTP proxy API.""" + return PROXY_DOCUMENTATION diff --git a/tests/unit/test_tools_session.py b/tests/unit/test_tools_session.py new file mode 100644 index 0000000..d1d3078 --- /dev/null +++ b/tests/unit/test_tools_session.py @@ -0,0 +1,16 @@ +import pytest +from grist_mcp.tools.session import get_proxy_documentation + + +@pytest.mark.asyncio +async def test_get_proxy_documentation_returns_complete_spec(): + result = await get_proxy_documentation() + + assert "description" in result + assert "endpoint" in result + assert result["endpoint"] == "POST /api/v1/proxy" + assert "authentication" in result + assert "methods" in result + assert "add_records" in result["methods"] + assert "get_records" in result["methods"] + assert "example_script" in result