mcp-coda 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mcp_coda-0.1.0/.env.example +14 -0
- mcp_coda-0.1.0/.github/workflows/lint.yml +28 -0
- mcp_coda-0.1.0/.github/workflows/publish.yml +30 -0
- mcp_coda-0.1.0/.github/workflows/release.yml +42 -0
- mcp_coda-0.1.0/.github/workflows/tests.yml +35 -0
- mcp_coda-0.1.0/.gitignore +18 -0
- mcp_coda-0.1.0/AGENTS.md +54 -0
- mcp_coda-0.1.0/CHANGELOG.md +28 -0
- mcp_coda-0.1.0/PKG-INFO +208 -0
- mcp_coda-0.1.0/README.md +181 -0
- mcp_coda-0.1.0/pyproject.toml +81 -0
- mcp_coda-0.1.0/src/mcp_coda/__init__.py +49 -0
- mcp_coda-0.1.0/src/mcp_coda/__main__.py +5 -0
- mcp_coda-0.1.0/src/mcp_coda/client.py +115 -0
- mcp_coda-0.1.0/src/mcp_coda/config.py +44 -0
- mcp_coda-0.1.0/src/mcp_coda/exceptions.py +47 -0
- mcp_coda-0.1.0/src/mcp_coda/models/__init__.py +0 -0
- mcp_coda-0.1.0/src/mcp_coda/py.typed +0 -0
- mcp_coda-0.1.0/src/mcp_coda/servers/__init__.py +59 -0
- mcp_coda-0.1.0/src/mcp_coda/servers/_helpers.py +96 -0
- mcp_coda-0.1.0/src/mcp_coda/servers/account.py +82 -0
- mcp_coda-0.1.0/src/mcp_coda/servers/analytics.py +351 -0
- mcp_coda-0.1.0/src/mcp_coda/servers/automations.py +51 -0
- mcp_coda-0.1.0/src/mcp_coda/servers/controls.py +84 -0
- mcp_coda-0.1.0/src/mcp_coda/servers/docs.py +219 -0
- mcp_coda-0.1.0/src/mcp_coda/servers/folders.py +141 -0
- mcp_coda-0.1.0/src/mcp_coda/servers/formulas.py +83 -0
- mcp_coda-0.1.0/src/mcp_coda/servers/pages.py +333 -0
- mcp_coda-0.1.0/src/mcp_coda/servers/permissions.py +216 -0
- mcp_coda-0.1.0/src/mcp_coda/servers/publishing.py +102 -0
- mcp_coda-0.1.0/src/mcp_coda/servers/rows.py +364 -0
- mcp_coda-0.1.0/src/mcp_coda/servers/tables.py +175 -0
- mcp_coda-0.1.0/tests/__init__.py +0 -0
- mcp_coda-0.1.0/tests/conftest.py +33 -0
- mcp_coda-0.1.0/tests/unit/__init__.py +0 -0
- mcp_coda-0.1.0/tests/unit/test_client.py +199 -0
- mcp_coda-0.1.0/tests/unit/test_config.py +75 -0
- mcp_coda-0.1.0/tests/unit/test_exceptions.py +61 -0
- mcp_coda-0.1.0/tests/unit/test_helpers.py +122 -0
- mcp_coda-0.1.0/tests/unit/test_tools_account.py +61 -0
- mcp_coda-0.1.0/tests/unit/test_tools_docs.py +122 -0
- mcp_coda-0.1.0/tests/unit/test_tools_pages.py +113 -0
- mcp_coda-0.1.0/tests/unit/test_tools_rows.py +140 -0
- mcp_coda-0.1.0/uv.lock +1883 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Required: Coda API token (https://coda.io/account#apiSettings)
|
|
2
|
+
CODA_API_TOKEN=
|
|
3
|
+
|
|
4
|
+
# Optional: Disable all write operations
|
|
5
|
+
# CODA_READ_ONLY=false
|
|
6
|
+
|
|
7
|
+
# Optional: Custom API base URL
|
|
8
|
+
# CODA_BASE_URL=https://coda.io/apis/v1
|
|
9
|
+
|
|
10
|
+
# Optional: HTTP timeout in seconds
|
|
11
|
+
# CODA_TIMEOUT=30
|
|
12
|
+
|
|
13
|
+
# Optional: SSL certificate verification
|
|
14
|
+
# CODA_SSL_VERIFY=true
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
name: Lint
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
lint:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
|
|
15
|
+
- name: Install uv
|
|
16
|
+
uses: astral-sh/setup-uv@v4
|
|
17
|
+
|
|
18
|
+
- name: Set up Python
|
|
19
|
+
run: uv python install 3.13
|
|
20
|
+
|
|
21
|
+
- name: Install dependencies
|
|
22
|
+
run: uv sync
|
|
23
|
+
|
|
24
|
+
- name: Ruff check
|
|
25
|
+
run: uv run ruff check src/ tests/
|
|
26
|
+
|
|
27
|
+
- name: Ruff format check
|
|
28
|
+
run: uv run ruff format --check src/ tests/
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
id-token: write
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
publish:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
environment:
|
|
15
|
+
name: pypi
|
|
16
|
+
url: https://pypi.org/p/mcp-coda
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
|
|
20
|
+
- name: Install uv
|
|
21
|
+
uses: astral-sh/setup-uv@v4
|
|
22
|
+
|
|
23
|
+
- name: Set up Python
|
|
24
|
+
run: uv python install 3.13
|
|
25
|
+
|
|
26
|
+
- name: Build
|
|
27
|
+
run: uv build
|
|
28
|
+
|
|
29
|
+
- name: Publish to PyPI
|
|
30
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
inputs:
|
|
6
|
+
version:
|
|
7
|
+
description: "Version to release (e.g. 0.2.0)"
|
|
8
|
+
required: true
|
|
9
|
+
type: string
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: write
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
release:
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
with:
|
|
20
|
+
fetch-depth: 0
|
|
21
|
+
|
|
22
|
+
- name: Configure git
|
|
23
|
+
run: |
|
|
24
|
+
git config user.name "github-actions[bot]"
|
|
25
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
26
|
+
|
|
27
|
+
- name: Install uv
|
|
28
|
+
uses: astral-sh/setup-uv@v4
|
|
29
|
+
|
|
30
|
+
- name: Set up Python
|
|
31
|
+
run: uv python install 3.13
|
|
32
|
+
|
|
33
|
+
- name: Update version
|
|
34
|
+
run: |
|
|
35
|
+
sed -i "s/^version = .*/version = \"${{ inputs.version }}\"/" pyproject.toml
|
|
36
|
+
|
|
37
|
+
- name: Commit and tag
|
|
38
|
+
run: |
|
|
39
|
+
git add pyproject.toml
|
|
40
|
+
git commit -m "chore: release v${{ inputs.version }}"
|
|
41
|
+
git tag "v${{ inputs.version }}"
|
|
42
|
+
git push origin main --tags
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
name: Tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
strategy:
|
|
13
|
+
matrix:
|
|
14
|
+
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
15
|
+
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
|
|
19
|
+
- name: Install uv
|
|
20
|
+
uses: astral-sh/setup-uv@v4
|
|
21
|
+
|
|
22
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
23
|
+
run: uv python install ${{ matrix.python-version }}
|
|
24
|
+
|
|
25
|
+
- name: Install dependencies
|
|
26
|
+
run: uv sync --python ${{ matrix.python-version }}
|
|
27
|
+
|
|
28
|
+
- name: Run tests
|
|
29
|
+
run: uv run pytest tests/ -v --cov=mcp_coda --cov-report=xml
|
|
30
|
+
|
|
31
|
+
- name: Upload coverage
|
|
32
|
+
if: matrix.python-version == '3.13'
|
|
33
|
+
uses: codecov/codecov-action@v4
|
|
34
|
+
with:
|
|
35
|
+
file: coverage.xml
|
mcp_coda-0.1.0/AGENTS.md
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# mcp-coda — Agent Context
|
|
2
|
+
|
|
3
|
+
## What This Is
|
|
4
|
+
|
|
5
|
+
MCP server for the Coda v1 API. 55 tools covering docs, pages, tables, rows, formulas, controls, permissions, folders, publishing, automations, and analytics.
|
|
6
|
+
|
|
7
|
+
## Architecture
|
|
8
|
+
|
|
9
|
+
- **Framework**: FastMCP >= 2.13.0
|
|
10
|
+
- **HTTP client**: httpx AsyncClient
|
|
11
|
+
- **Auth**: Bearer token via `CODA_API_TOKEN` env var
|
|
12
|
+
- **Build**: hatchling with `src/` layout
|
|
13
|
+
- **Structure**: Modular tool files in `src/mcp_coda/servers/` (one per domain)
|
|
14
|
+
|
|
15
|
+
### RBAC Model
|
|
16
|
+
|
|
17
|
+
1. **Server-level**: `CODA_READ_ONLY=true` blocks all write tools
|
|
18
|
+
2. **MCP annotations**: `readOnlyHint`, `destructiveHint`, `idempotentHint` per tool
|
|
19
|
+
3. **Coda token scope**: API token permissions enforce doc-level access
|
|
20
|
+
|
|
21
|
+
### Key Patterns
|
|
22
|
+
|
|
23
|
+
- Tools never raise — all errors return `_err(e)` as JSON string
|
|
24
|
+
- Every tool returns `str` (JSON via `_ok`/`_err`)
|
|
25
|
+
- Write tools call `_check_write(ctx)` first
|
|
26
|
+
- List responses include `{items, has_more, next_cursor, total_count}`
|
|
27
|
+
- Rate limit errors include `retry_after` seconds
|
|
28
|
+
- Async mutations return `requestId` for polling via `coda_get_mutation_status`
|
|
29
|
+
|
|
30
|
+
## Development
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
uv sync # install deps
|
|
34
|
+
uv run pytest tests/ -v --cov=mcp_coda # run tests
|
|
35
|
+
uv run ruff check src/ tests/ # lint
|
|
36
|
+
uv run ruff format --check src/ tests/ # format check
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Tool Inventory (55 tools)
|
|
40
|
+
|
|
41
|
+
| Module | Tools | Type |
|
|
42
|
+
|--------|-------|------|
|
|
43
|
+
| account | 3 | read |
|
|
44
|
+
| docs | 5 | read/write |
|
|
45
|
+
| pages | 8 | read/write |
|
|
46
|
+
| tables | 4 | read |
|
|
47
|
+
| rows | 7 | read/write |
|
|
48
|
+
| formulas | 2 | read |
|
|
49
|
+
| controls | 2 | read |
|
|
50
|
+
| permissions | 6 | read/write |
|
|
51
|
+
| publishing | 3 | read/write |
|
|
52
|
+
| folders | 5 | read/write |
|
|
53
|
+
| automations | 1 | write |
|
|
54
|
+
| analytics | 7 | read |
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0 (unreleased)
|
|
4
|
+
|
|
5
|
+
Initial release.
|
|
6
|
+
|
|
7
|
+
### Tools (55)
|
|
8
|
+
|
|
9
|
+
- **Account** (3): whoami, resolve_browser_link, get_mutation_status
|
|
10
|
+
- **Docs** (5): list, get, create, update, delete
|
|
11
|
+
- **Pages** (8): list, get, create, update, delete, get_content, delete_content, export
|
|
12
|
+
- **Tables** (4): list_tables, get_table, list_columns, get_column
|
|
13
|
+
- **Rows** (7): list, get, insert (with upsert), update, delete, bulk_delete, push_button
|
|
14
|
+
- **Formulas** (2): list, get
|
|
15
|
+
- **Controls** (2): list, get
|
|
16
|
+
- **Permissions** (6): get_sharing_metadata, list, add, delete, search_principals, get_acl_settings
|
|
17
|
+
- **Publishing** (3): list_categories, publish, unpublish
|
|
18
|
+
- **Folders** (5): list, get, create, update, delete
|
|
19
|
+
- **Automations** (1): trigger
|
|
20
|
+
- **Analytics** (7): doc_analytics, doc_summary, page_analytics, pack_analytics, pack_summary, pack_formula_analytics, analytics_updated
|
|
21
|
+
|
|
22
|
+
### Features
|
|
23
|
+
|
|
24
|
+
- 3-layer RBAC: server read-only toggle, MCP annotations, Coda token scope
|
|
25
|
+
- Rate limit error surfacing with `retry_after` seconds
|
|
26
|
+
- Async mutation tracking via `coda_get_mutation_status`
|
|
27
|
+
- Curated JSON responses with pagination envelope
|
|
28
|
+
- stdio, SSE, and streamable-http transports
|
mcp_coda-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mcp-coda
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: MCP server for Coda API — docs, pages, tables, rows, formulas, permissions, and more
|
|
5
|
+
Project-URL: Homepage, https://github.com/vish288/mcp-coda
|
|
6
|
+
Project-URL: Repository, https://github.com/vish288/mcp-coda
|
|
7
|
+
Project-URL: Issues, https://github.com/vish288/mcp-coda/issues
|
|
8
|
+
Author: vish288
|
|
9
|
+
License: MIT
|
|
10
|
+
Keywords: ai,automation,coda,coda-api,llm,mcp,mcp-server,model-context-protocol
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Typing :: Typed
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Requires-Dist: click>=8.1.7
|
|
22
|
+
Requires-Dist: fastmcp>=2.13.0
|
|
23
|
+
Requires-Dist: httpx>=0.28.0
|
|
24
|
+
Requires-Dist: pydantic<3.0,>=2.10.0
|
|
25
|
+
Requires-Dist: python-dotenv>=1.0.1
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
|
|
28
|
+
# mcp-coda
|
|
29
|
+
|
|
30
|
+
MCP server for the [Coda API](https://coda.io/developers/apis/v1) — docs, pages, tables, rows, formulas, controls, permissions, folders, publishing, automations, and analytics.
|
|
31
|
+
|
|
32
|
+
## Features
|
|
33
|
+
|
|
34
|
+
- 55 tools covering the full Coda v1 API
|
|
35
|
+
- Read-only mode via `CODA_READ_ONLY=true`
|
|
36
|
+
- MCP tool annotations (readOnlyHint, destructiveHint, idempotentHint)
|
|
37
|
+
- Rate limit error surfacing with `retry_after` seconds
|
|
38
|
+
- Async mutation tracking via `coda_get_mutation_status`
|
|
39
|
+
- stdio, SSE, and streamable-http transports
|
|
40
|
+
|
|
41
|
+
## Installation
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
# Via uvx (recommended)
|
|
45
|
+
uvx mcp-coda
|
|
46
|
+
|
|
47
|
+
# Via pip
|
|
48
|
+
pip install mcp-coda
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Configuration
|
|
52
|
+
|
|
53
|
+
Set the `CODA_API_TOKEN` environment variable with your [Coda API token](https://coda.io/account#apiSettings).
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
export CODA_API_TOKEN=your-token-here
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Environment Variables
|
|
60
|
+
|
|
61
|
+
| Variable | Required | Default | Description |
|
|
62
|
+
|----------|----------|---------|-------------|
|
|
63
|
+
| `CODA_API_TOKEN` | Yes | — | Coda API token |
|
|
64
|
+
| `CODA_READ_ONLY` | No | `false` | Disable all write operations |
|
|
65
|
+
| `CODA_BASE_URL` | No | `https://coda.io/apis/v1` | API base URL |
|
|
66
|
+
| `CODA_TIMEOUT` | No | `30` | HTTP timeout in seconds |
|
|
67
|
+
| `CODA_SSL_VERIFY` | No | `true` | Verify SSL certificates |
|
|
68
|
+
|
|
69
|
+
## Usage
|
|
70
|
+
|
|
71
|
+
### Claude Code / Cursor
|
|
72
|
+
|
|
73
|
+
Add to your MCP config (`.mcp.json` or `.cursor/mcp.json`):
|
|
74
|
+
|
|
75
|
+
```json
|
|
76
|
+
{
|
|
77
|
+
"mcpServers": {
|
|
78
|
+
"coda": {
|
|
79
|
+
"command": "uvx",
|
|
80
|
+
"args": ["mcp-coda"],
|
|
81
|
+
"env": {
|
|
82
|
+
"CODA_API_TOKEN": "your-token-here"
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### CLI
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
# stdio (default)
|
|
93
|
+
mcp-coda
|
|
94
|
+
|
|
95
|
+
# SSE transport
|
|
96
|
+
mcp-coda --transport sse --port 8000
|
|
97
|
+
|
|
98
|
+
# Read-only mode
|
|
99
|
+
mcp-coda --read-only
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Tools
|
|
103
|
+
|
|
104
|
+
### Account (3)
|
|
105
|
+
- `coda_whoami` — Get current user info
|
|
106
|
+
- `coda_resolve_browser_link` — Convert browser URL to API IDs
|
|
107
|
+
- `coda_get_mutation_status` — Check async write status
|
|
108
|
+
|
|
109
|
+
### Docs (5)
|
|
110
|
+
- `coda_list_docs` — List accessible docs
|
|
111
|
+
- `coda_get_doc` — Get doc metadata
|
|
112
|
+
- `coda_create_doc` — Create a new doc
|
|
113
|
+
- `coda_update_doc` — Update doc title/icon
|
|
114
|
+
- `coda_delete_doc` — Delete a doc
|
|
115
|
+
|
|
116
|
+
### Pages (8)
|
|
117
|
+
- `coda_list_pages` — List pages in a doc
|
|
118
|
+
- `coda_get_page` — Get page metadata
|
|
119
|
+
- `coda_create_page` — Create a page
|
|
120
|
+
- `coda_update_page` — Update page name/content
|
|
121
|
+
- `coda_delete_page` — Delete a page
|
|
122
|
+
- `coda_get_page_content` — Read page content
|
|
123
|
+
- `coda_delete_page_content` — Clear page content
|
|
124
|
+
- `coda_export_page` — Export page content
|
|
125
|
+
|
|
126
|
+
### Tables (4)
|
|
127
|
+
- `coda_list_tables` — List tables/views
|
|
128
|
+
- `coda_get_table` — Get table metadata
|
|
129
|
+
- `coda_list_columns` — List columns
|
|
130
|
+
- `coda_get_column` — Get column metadata
|
|
131
|
+
|
|
132
|
+
### Rows (7)
|
|
133
|
+
- `coda_list_rows` — List/filter rows
|
|
134
|
+
- `coda_get_row` — Get a single row
|
|
135
|
+
- `coda_insert_rows` — Insert/upsert rows
|
|
136
|
+
- `coda_update_row` — Update a row
|
|
137
|
+
- `coda_delete_row` — Delete a row
|
|
138
|
+
- `coda_delete_rows` — Bulk delete rows
|
|
139
|
+
- `coda_push_button` — Push a button
|
|
140
|
+
|
|
141
|
+
### Formulas (2)
|
|
142
|
+
- `coda_list_formulas` — List named formulas
|
|
143
|
+
- `coda_get_formula` — Get formula value
|
|
144
|
+
|
|
145
|
+
### Controls (2)
|
|
146
|
+
- `coda_list_controls` — List controls
|
|
147
|
+
- `coda_get_control` — Get control value
|
|
148
|
+
|
|
149
|
+
### Permissions (6)
|
|
150
|
+
- `coda_get_sharing_metadata` — Get sharing config
|
|
151
|
+
- `coda_list_permissions` — List ACL entries
|
|
152
|
+
- `coda_add_permission` — Grant access
|
|
153
|
+
- `coda_delete_permission` — Revoke access
|
|
154
|
+
- `coda_search_principals` — Search users/groups
|
|
155
|
+
- `coda_get_acl_settings` — Get ACL settings
|
|
156
|
+
|
|
157
|
+
### Publishing (3)
|
|
158
|
+
- `coda_list_categories` — List publishing categories
|
|
159
|
+
- `coda_publish_doc` — Publish a doc
|
|
160
|
+
- `coda_unpublish_doc` — Unpublish a doc
|
|
161
|
+
|
|
162
|
+
### Folders (5)
|
|
163
|
+
- `coda_list_folders` — List folders
|
|
164
|
+
- `coda_get_folder` — Get folder details
|
|
165
|
+
- `coda_create_folder` — Create a folder
|
|
166
|
+
- `coda_update_folder` — Rename a folder
|
|
167
|
+
- `coda_delete_folder` — Delete a folder
|
|
168
|
+
|
|
169
|
+
### Automations (1)
|
|
170
|
+
- `coda_trigger_automation` — Trigger an automation rule
|
|
171
|
+
|
|
172
|
+
### Analytics (7)
|
|
173
|
+
- `coda_list_doc_analytics` — Doc usage metrics
|
|
174
|
+
- `coda_get_doc_analytics_summary` — Aggregated doc metrics
|
|
175
|
+
- `coda_list_page_analytics` — Page usage metrics
|
|
176
|
+
- `coda_list_pack_analytics` — Pack usage metrics
|
|
177
|
+
- `coda_get_pack_analytics_summary` — Aggregated pack metrics
|
|
178
|
+
- `coda_list_pack_formula_analytics` — Formula-level metrics
|
|
179
|
+
- `coda_get_analytics_updated` — Analytics freshness timestamp
|
|
180
|
+
|
|
181
|
+
## RBAC Model
|
|
182
|
+
|
|
183
|
+
Three layers of access control:
|
|
184
|
+
|
|
185
|
+
1. **Server-level**: `CODA_READ_ONLY=true` blocks all write tools
|
|
186
|
+
2. **MCP annotations**: Each tool declares `readOnlyHint`, `destructiveHint`, `idempotentHint` for client-side permission prompts
|
|
187
|
+
3. **Coda token scope**: The API token's permissions enforce doc-level access
|
|
188
|
+
|
|
189
|
+
## Development
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
# Install dev dependencies
|
|
193
|
+
uv sync
|
|
194
|
+
|
|
195
|
+
# Run tests
|
|
196
|
+
pytest tests/ -v --cov=mcp_coda
|
|
197
|
+
|
|
198
|
+
# Lint
|
|
199
|
+
ruff check src/ tests/
|
|
200
|
+
ruff format --check src/ tests/
|
|
201
|
+
|
|
202
|
+
# Type check
|
|
203
|
+
mypy src/
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## License
|
|
207
|
+
|
|
208
|
+
MIT
|
mcp_coda-0.1.0/README.md
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
# mcp-coda
|
|
2
|
+
|
|
3
|
+
MCP server for the [Coda API](https://coda.io/developers/apis/v1) — docs, pages, tables, rows, formulas, controls, permissions, folders, publishing, automations, and analytics.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 55 tools covering the full Coda v1 API
|
|
8
|
+
- Read-only mode via `CODA_READ_ONLY=true`
|
|
9
|
+
- MCP tool annotations (readOnlyHint, destructiveHint, idempotentHint)
|
|
10
|
+
- Rate limit error surfacing with `retry_after` seconds
|
|
11
|
+
- Async mutation tracking via `coda_get_mutation_status`
|
|
12
|
+
- stdio, SSE, and streamable-http transports
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
# Via uvx (recommended)
|
|
18
|
+
uvx mcp-coda
|
|
19
|
+
|
|
20
|
+
# Via pip
|
|
21
|
+
pip install mcp-coda
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Configuration
|
|
25
|
+
|
|
26
|
+
Set the `CODA_API_TOKEN` environment variable with your [Coda API token](https://coda.io/account#apiSettings).
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
export CODA_API_TOKEN=your-token-here
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Environment Variables
|
|
33
|
+
|
|
34
|
+
| Variable | Required | Default | Description |
|
|
35
|
+
|----------|----------|---------|-------------|
|
|
36
|
+
| `CODA_API_TOKEN` | Yes | — | Coda API token |
|
|
37
|
+
| `CODA_READ_ONLY` | No | `false` | Disable all write operations |
|
|
38
|
+
| `CODA_BASE_URL` | No | `https://coda.io/apis/v1` | API base URL |
|
|
39
|
+
| `CODA_TIMEOUT` | No | `30` | HTTP timeout in seconds |
|
|
40
|
+
| `CODA_SSL_VERIFY` | No | `true` | Verify SSL certificates |
|
|
41
|
+
|
|
42
|
+
## Usage
|
|
43
|
+
|
|
44
|
+
### Claude Code / Cursor
|
|
45
|
+
|
|
46
|
+
Add to your MCP config (`.mcp.json` or `.cursor/mcp.json`):
|
|
47
|
+
|
|
48
|
+
```json
|
|
49
|
+
{
|
|
50
|
+
"mcpServers": {
|
|
51
|
+
"coda": {
|
|
52
|
+
"command": "uvx",
|
|
53
|
+
"args": ["mcp-coda"],
|
|
54
|
+
"env": {
|
|
55
|
+
"CODA_API_TOKEN": "your-token-here"
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### CLI
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
# stdio (default)
|
|
66
|
+
mcp-coda
|
|
67
|
+
|
|
68
|
+
# SSE transport
|
|
69
|
+
mcp-coda --transport sse --port 8000
|
|
70
|
+
|
|
71
|
+
# Read-only mode
|
|
72
|
+
mcp-coda --read-only
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Tools
|
|
76
|
+
|
|
77
|
+
### Account (3)
|
|
78
|
+
- `coda_whoami` — Get current user info
|
|
79
|
+
- `coda_resolve_browser_link` — Convert browser URL to API IDs
|
|
80
|
+
- `coda_get_mutation_status` — Check async write status
|
|
81
|
+
|
|
82
|
+
### Docs (5)
|
|
83
|
+
- `coda_list_docs` — List accessible docs
|
|
84
|
+
- `coda_get_doc` — Get doc metadata
|
|
85
|
+
- `coda_create_doc` — Create a new doc
|
|
86
|
+
- `coda_update_doc` — Update doc title/icon
|
|
87
|
+
- `coda_delete_doc` — Delete a doc
|
|
88
|
+
|
|
89
|
+
### Pages (8)
|
|
90
|
+
- `coda_list_pages` — List pages in a doc
|
|
91
|
+
- `coda_get_page` — Get page metadata
|
|
92
|
+
- `coda_create_page` — Create a page
|
|
93
|
+
- `coda_update_page` — Update page name/content
|
|
94
|
+
- `coda_delete_page` — Delete a page
|
|
95
|
+
- `coda_get_page_content` — Read page content
|
|
96
|
+
- `coda_delete_page_content` — Clear page content
|
|
97
|
+
- `coda_export_page` — Export page content
|
|
98
|
+
|
|
99
|
+
### Tables (4)
|
|
100
|
+
- `coda_list_tables` — List tables/views
|
|
101
|
+
- `coda_get_table` — Get table metadata
|
|
102
|
+
- `coda_list_columns` — List columns
|
|
103
|
+
- `coda_get_column` — Get column metadata
|
|
104
|
+
|
|
105
|
+
### Rows (7)
|
|
106
|
+
- `coda_list_rows` — List/filter rows
|
|
107
|
+
- `coda_get_row` — Get a single row
|
|
108
|
+
- `coda_insert_rows` — Insert/upsert rows
|
|
109
|
+
- `coda_update_row` — Update a row
|
|
110
|
+
- `coda_delete_row` — Delete a row
|
|
111
|
+
- `coda_delete_rows` — Bulk delete rows
|
|
112
|
+
- `coda_push_button` — Push a button
|
|
113
|
+
|
|
114
|
+
### Formulas (2)
|
|
115
|
+
- `coda_list_formulas` — List named formulas
|
|
116
|
+
- `coda_get_formula` — Get formula value
|
|
117
|
+
|
|
118
|
+
### Controls (2)
|
|
119
|
+
- `coda_list_controls` — List controls
|
|
120
|
+
- `coda_get_control` — Get control value
|
|
121
|
+
|
|
122
|
+
### Permissions (6)
|
|
123
|
+
- `coda_get_sharing_metadata` — Get sharing config
|
|
124
|
+
- `coda_list_permissions` — List ACL entries
|
|
125
|
+
- `coda_add_permission` — Grant access
|
|
126
|
+
- `coda_delete_permission` — Revoke access
|
|
127
|
+
- `coda_search_principals` — Search users/groups
|
|
128
|
+
- `coda_get_acl_settings` — Get ACL settings
|
|
129
|
+
|
|
130
|
+
### Publishing (3)
|
|
131
|
+
- `coda_list_categories` — List publishing categories
|
|
132
|
+
- `coda_publish_doc` — Publish a doc
|
|
133
|
+
- `coda_unpublish_doc` — Unpublish a doc
|
|
134
|
+
|
|
135
|
+
### Folders (5)
|
|
136
|
+
- `coda_list_folders` — List folders
|
|
137
|
+
- `coda_get_folder` — Get folder details
|
|
138
|
+
- `coda_create_folder` — Create a folder
|
|
139
|
+
- `coda_update_folder` — Rename a folder
|
|
140
|
+
- `coda_delete_folder` — Delete a folder
|
|
141
|
+
|
|
142
|
+
### Automations (1)
|
|
143
|
+
- `coda_trigger_automation` — Trigger an automation rule
|
|
144
|
+
|
|
145
|
+
### Analytics (7)
|
|
146
|
+
- `coda_list_doc_analytics` — Doc usage metrics
|
|
147
|
+
- `coda_get_doc_analytics_summary` — Aggregated doc metrics
|
|
148
|
+
- `coda_list_page_analytics` — Page usage metrics
|
|
149
|
+
- `coda_list_pack_analytics` — Pack usage metrics
|
|
150
|
+
- `coda_get_pack_analytics_summary` — Aggregated pack metrics
|
|
151
|
+
- `coda_list_pack_formula_analytics` — Formula-level metrics
|
|
152
|
+
- `coda_get_analytics_updated` — Analytics freshness timestamp
|
|
153
|
+
|
|
154
|
+
## RBAC Model
|
|
155
|
+
|
|
156
|
+
Three layers of access control:
|
|
157
|
+
|
|
158
|
+
1. **Server-level**: `CODA_READ_ONLY=true` blocks all write tools
|
|
159
|
+
2. **MCP annotations**: Each tool declares `readOnlyHint`, `destructiveHint`, `idempotentHint` for client-side permission prompts
|
|
160
|
+
3. **Coda token scope**: The API token's permissions enforce doc-level access
|
|
161
|
+
|
|
162
|
+
## Development
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
# Install dev dependencies
|
|
166
|
+
uv sync
|
|
167
|
+
|
|
168
|
+
# Run tests
|
|
169
|
+
pytest tests/ -v --cov=mcp_coda
|
|
170
|
+
|
|
171
|
+
# Lint
|
|
172
|
+
ruff check src/ tests/
|
|
173
|
+
ruff format --check src/ tests/
|
|
174
|
+
|
|
175
|
+
# Type check
|
|
176
|
+
mypy src/
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## License
|
|
180
|
+
|
|
181
|
+
MIT
|