diff --git a/src/grist_mcp/proxy.py b/src/grist_mcp/proxy.py new file mode 100644 index 0000000..ee96bea --- /dev/null +++ b/src/grist_mcp/proxy.py @@ -0,0 +1,66 @@ +"""HTTP proxy handler for session token access.""" + +from dataclasses import dataclass +from typing import Any + + +class ProxyError(Exception): + """Error during proxy request processing.""" + + def __init__(self, message: str, code: str): + self.message = message + self.code = code + super().__init__(message) + + +@dataclass +class ProxyRequest: + """Parsed proxy request.""" + method: str + table: str | None = None + records: list[dict] | None = None + record_ids: list[int] | None = None + filter: dict | None = None + sort: str | None = None + limit: int | None = None + query: str | None = None + table_id: str | None = None + columns: list[dict] | None = None + column_id: str | None = None + column_type: str | None = None + formula: str | None = None + type: str | None = None + + +METHODS_REQUIRING_TABLE = { + "get_records", "describe_table", "add_records", "update_records", + "delete_records", "add_column", "modify_column", "delete_column", +} + + +def parse_proxy_request(body: dict[str, Any]) -> ProxyRequest: + """Parse and validate a proxy request body.""" + if "method" not in body: + raise ProxyError("Missing required field: method", "INVALID_REQUEST") + + method = body["method"] + + if method in METHODS_REQUIRING_TABLE and "table" not in body: + raise ProxyError(f"Missing required field 'table' for method '{method}'", "INVALID_REQUEST") + + return ProxyRequest( + method=method, + table=body.get("table"), + records=body.get("records"), + record_ids=body.get("record_ids"), + filter=body.get("filter"), + sort=body.get("sort"), + limit=body.get("limit"), + query=body.get("query"), + table_id=body.get("table_id"), + columns=body.get("columns"), + column_id=body.get("column_id"), + column_type=body.get("column_type"), + formula=body.get("formula"), + type=body.get("type"), + ) diff --git a/tests/unit/test_proxy.py b/tests/unit/test_proxy.py new file mode 100644 index 0000000..b59000d --- /dev/null +++ b/tests/unit/test_proxy.py @@ -0,0 +1,26 @@ +import pytest +from grist_mcp.proxy import parse_proxy_request, ProxyRequest, ProxyError + + +def test_parse_proxy_request_valid_add_records(): + body = { + "method": "add_records", + "table": "Orders", + "records": [{"item": "Widget", "qty": 10}], + } + + request = parse_proxy_request(body) + + assert request.method == "add_records" + assert request.table == "Orders" + assert request.records == [{"item": "Widget", "qty": 10}] + + +def test_parse_proxy_request_missing_method(): + body = {"table": "Orders"} + + with pytest.raises(ProxyError) as exc_info: + parse_proxy_request(body) + + assert exc_info.value.code == "INVALID_REQUEST" + assert "method" in str(exc_info.value)