112 lines
3.6 KiB
Markdown
112 lines
3.6 KiB
Markdown
# CLAUDE.md
|
|
|
|
Project-specific instructions for Claude Code.
|
|
|
|
## Project Overview
|
|
|
|
grist-mcp is an MCP (Model Context Protocol) server that enables AI agents to interact with Grist spreadsheet documents. It provides secure, token-based access with granular permissions.
|
|
|
|
## Tech Stack
|
|
|
|
- Python 3.14+
|
|
- MCP SDK (`mcp` package)
|
|
- httpx for async HTTP requests
|
|
- PyYAML for configuration
|
|
- pytest + pytest-asyncio + pytest-httpx for testing
|
|
|
|
## Commands
|
|
|
|
```bash
|
|
# Run unit tests
|
|
make test-unit
|
|
# or: uv run pytest tests/unit/ -v
|
|
|
|
# Run integration tests (manages containers automatically)
|
|
make test-integration
|
|
# or: ./scripts/run-integration-tests.sh
|
|
|
|
# Full pre-deploy pipeline
|
|
make pre-deploy
|
|
|
|
# Development environment
|
|
make dev-up # Start
|
|
make dev-down # Stop
|
|
|
|
# Build Docker image
|
|
make build
|
|
|
|
# Run the server (requires config and token)
|
|
CONFIG_PATH=./config.yaml GRIST_MCP_TOKEN=your-token uv run python -m grist_mcp.main
|
|
```
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
src/grist_mcp/ # Source code
|
|
├── main.py # Entry point, runs stdio server
|
|
├── server.py # MCP server setup, tool registration, call_tool dispatch
|
|
├── config.py # YAML config loading with env var substitution
|
|
├── auth.py # Token auth and permission checking
|
|
├── grist_client.py # Async Grist API client
|
|
└── tools/
|
|
├── discovery.py # list_documents tool
|
|
├── read.py # list_tables, describe_table, get_records, sql_query
|
|
├── write.py # add_records, update_records, delete_records
|
|
└── schema.py # create_table, add_column, modify_column, delete_column
|
|
tests/
|
|
├── unit/ # Unit tests (no containers)
|
|
└── integration/ # Integration tests (with Docker)
|
|
deploy/
|
|
├── dev/ # Development docker-compose
|
|
├── test/ # Test docker-compose (ephemeral)
|
|
└── prod/ # Production docker-compose
|
|
scripts/ # Test automation scripts
|
|
```
|
|
|
|
## Key Patterns
|
|
|
|
### Authentication Flow
|
|
1. Token provided via `GRIST_MCP_TOKEN` env var or passed to `create_server()`
|
|
2. `Authenticator.authenticate()` validates token and returns `Agent` object
|
|
3. Each tool call uses `Authenticator.authorize()` to check document + permission
|
|
|
|
### Permission Levels
|
|
- `read`: Query tables and records
|
|
- `write`: Add, update, delete records
|
|
- `schema`: Create tables, modify columns
|
|
|
|
### Tool Implementation Pattern
|
|
All tools follow this pattern:
|
|
```python
|
|
async def tool_name(agent, auth, document, ..., client=None):
|
|
auth.authorize(agent, document, Permission.X)
|
|
if client is None:
|
|
doc = auth.get_document(document)
|
|
client = GristClient(doc)
|
|
result = await client.some_method(...)
|
|
return {"key": result}
|
|
```
|
|
|
|
The optional `client` parameter enables dependency injection for testing.
|
|
|
|
## Testing
|
|
|
|
### Unit Tests (`tests/unit/`)
|
|
Fast tests using pytest-httpx to mock Grist API responses. Run with `make test-unit`.
|
|
- `test_auth.py`: Uses in-memory Config objects
|
|
- `test_grist_client.py`: Uses HTTPXMock for API mocking
|
|
- `test_tools_*.py`: Combine auth fixtures with mocked clients
|
|
|
|
### Integration Tests (`tests/integration/`)
|
|
Tests against real Grist containers. Run with `make test-integration`.
|
|
- Automatically manages Docker containers via `scripts/run-integration-tests.sh`
|
|
- Uses environment variables for configuration (no hardcoded URLs)
|
|
- Containers are ephemeral and cleaned up after tests
|
|
|
|
## Configuration
|
|
|
|
See `config.yaml.example` for the configuration format. Key points:
|
|
- Documents define Grist instance URL, doc ID, and API key
|
|
- Tokens define agent access with document/permission scopes
|
|
- Environment variables can be used with `${VAR}` syntax
|