v1.0.0-alpha.3
Some checks failed
Build and Push Docker Image / build (push) Failing after 7s
- Add .gitea/workflows/release.yml for Gitea builds - Uses plain docker commands (no action dependencies) - Pushes to git.prettyhefty.com registry - Simplify .github/workflows/build.yaml for GitHub only - Remove Gitea detection logic - Only push latest tag for non-prerelease versions
grist-mcp
MCP server for AI agents to interact with Grist documents.
Overview
grist-mcp is a Model Context Protocol (MCP) server that enables AI agents to read, write, and modify Grist spreadsheets. It provides secure, token-based access control with granular permissions per document.
Features
- Discovery: List accessible documents with permissions
- Read Operations: List tables, describe columns, fetch records, run SQL queries
- Write Operations: Add, update, and delete records
- Schema Operations: Create tables, add/modify/delete columns
- Security: Token-based authentication with per-document permission scopes (read, write, schema)
- Multi-tenant: Support multiple Grist instances and documents
Requirements
- Python 3.14+
- Access to one or more Grist documents with API keys
Installation
# Clone the repository
git clone https://github.com/your-org/grist-mcp.git
cd grist-mcp
# Install with uv
uv sync --dev
Configuration
Create a config.yaml file based on the example:
cp config.yaml.example config.yaml
Configuration Structure
# Document definitions
documents:
my-document:
url: https://docs.getgrist.com # Grist instance URL
doc_id: abcd1234 # Document ID from URL
api_key: ${GRIST_API_KEY} # API key (supports env vars)
# Agent tokens with access scopes
tokens:
- token: your-secret-token # Unique token for this agent
name: my-agent # Human-readable name
scope:
- document: my-document
permissions: [read, write] # Allowed: read, write, schema
Generating Tokens
python -c "import secrets; print(secrets.token_urlsafe(32))"
# or
openssl rand -base64 32
Environment Variables
CONFIG_PATH: Path to config file (default:/app/config.yaml)GRIST_MCP_TOKEN: Agent token for authentication- Config file supports
${VAR}syntax for API keys
Usage
Running the Server
The server uses SSE (Server-Sent Events) transport over HTTP:
# Set your agent token
export GRIST_MCP_TOKEN="your-agent-token"
# Run with custom config path (defaults to port 3000)
CONFIG_PATH=./config.yaml uv run python -m grist_mcp.main
# Or specify a custom port
PORT=8080 CONFIG_PATH=./config.yaml uv run python -m grist_mcp.main
The server exposes two endpoints:
http://localhost:3000/sse- SSE connection endpointhttp://localhost:3000/messages- Message posting endpoint
MCP Client Configuration
Add to your MCP client configuration (e.g., Claude Desktop):
{
"mcpServers": {
"grist": {
"url": "http://localhost:3000/sse"
}
}
}
For remote deployments, use the server's public URL:
{
"mcpServers": {
"grist": {
"url": "https://your-server.example.com/sse"
}
}
}
Available Tools
Discovery
| Tool | Description |
|---|---|
list_documents |
List documents accessible to this agent with their permissions |
Read Operations (requires read permission)
| Tool | Description |
|---|---|
list_tables |
List all tables in a document |
describe_table |
Get column information (id, type, formula) for a table |
get_records |
Fetch records with optional filter, sort, and limit |
sql_query |
Run a read-only SELECT query against a document |
Write Operations (requires write permission)
| Tool | Description |
|---|---|
add_records |
Add new records to a table |
update_records |
Update existing records by ID |
delete_records |
Delete records by ID |
Schema Operations (requires schema permission)
| Tool | Description |
|---|---|
create_table |
Create a new table with specified columns |
add_column |
Add a column to an existing table |
modify_column |
Change a column's type or formula |
delete_column |
Remove a column from a table |
Security
- Token-based auth: Each agent has a unique token with specific document access
- Permission scopes: Granular control with
read,write, andschemapermissions - SQL validation: Only SELECT queries allowed, no multi-statement queries
- API key isolation: Each document can use a different Grist API key
- No token exposure: Tokens are validated at startup, not stored in responses
Development
Running Tests
uv run pytest -v
Project Structure
grist-mcp/
├── src/grist_mcp/
│ ├── __init__.py
│ ├── main.py # Entry point
│ ├── server.py # MCP server setup and tool registration
│ ├── config.py # Configuration loading
│ ├── auth.py # Authentication and authorization
│ ├── grist_client.py # Grist API client
│ └── tools/
│ ├── discovery.py # list_documents
│ ├── read.py # Read operations
│ ├── write.py # Write operations
│ └── schema.py # Schema operations
├── tests/
├── config.yaml.example
└── pyproject.toml
Docker Deployment
Prerequisites
- Docker and Docker Compose
Quick Start
# 1. Copy example files
cp .env.example .env
cp config.yaml.example config.yaml
# 2. Edit .env with your tokens and API keys
# - Set GRIST_MCP_TOKEN to a secure agent token
# - Set your Grist API keys
# 3. Edit config.yaml with your document settings
# - Configure your Grist documents
# - Set up token scopes and permissions
# 4. Start the server
docker compose up -d
Environment Variables
| Variable | Description | Default |
|---|---|---|
PORT |
Server port | 3000 |
GRIST_MCP_TOKEN |
Agent authentication token (required) | - |
CONFIG_PATH |
Path to config file inside container | /app/config.yaml |
GRIST_*_API_KEY |
Grist API keys referenced in config.yaml | - |
Using Prebuilt Images
To use a prebuilt image from a container registry:
# docker-compose.yaml
services:
grist-mcp:
image: your-registry/grist-mcp:latest
ports:
- "${PORT:-3000}:3000"
volumes:
- ./config.yaml:/app/config.yaml:ro
env_file:
- .env
restart: unless-stopped
Building Locally
# Build the image
docker build -t grist-mcp .
# Run directly
docker run -p 3000:3000 \
-v $(pwd)/config.yaml:/app/config.yaml:ro \
--env-file .env \
grist-mcp
License
MIT
Description
Languages
Python
97.3%
Makefile
0.9%
Shell
0.9%
Dockerfile
0.9%