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.
Files changed (44) hide show
  1. mcp_coda-0.1.0/.env.example +14 -0
  2. mcp_coda-0.1.0/.github/workflows/lint.yml +28 -0
  3. mcp_coda-0.1.0/.github/workflows/publish.yml +30 -0
  4. mcp_coda-0.1.0/.github/workflows/release.yml +42 -0
  5. mcp_coda-0.1.0/.github/workflows/tests.yml +35 -0
  6. mcp_coda-0.1.0/.gitignore +18 -0
  7. mcp_coda-0.1.0/AGENTS.md +54 -0
  8. mcp_coda-0.1.0/CHANGELOG.md +28 -0
  9. mcp_coda-0.1.0/PKG-INFO +208 -0
  10. mcp_coda-0.1.0/README.md +181 -0
  11. mcp_coda-0.1.0/pyproject.toml +81 -0
  12. mcp_coda-0.1.0/src/mcp_coda/__init__.py +49 -0
  13. mcp_coda-0.1.0/src/mcp_coda/__main__.py +5 -0
  14. mcp_coda-0.1.0/src/mcp_coda/client.py +115 -0
  15. mcp_coda-0.1.0/src/mcp_coda/config.py +44 -0
  16. mcp_coda-0.1.0/src/mcp_coda/exceptions.py +47 -0
  17. mcp_coda-0.1.0/src/mcp_coda/models/__init__.py +0 -0
  18. mcp_coda-0.1.0/src/mcp_coda/py.typed +0 -0
  19. mcp_coda-0.1.0/src/mcp_coda/servers/__init__.py +59 -0
  20. mcp_coda-0.1.0/src/mcp_coda/servers/_helpers.py +96 -0
  21. mcp_coda-0.1.0/src/mcp_coda/servers/account.py +82 -0
  22. mcp_coda-0.1.0/src/mcp_coda/servers/analytics.py +351 -0
  23. mcp_coda-0.1.0/src/mcp_coda/servers/automations.py +51 -0
  24. mcp_coda-0.1.0/src/mcp_coda/servers/controls.py +84 -0
  25. mcp_coda-0.1.0/src/mcp_coda/servers/docs.py +219 -0
  26. mcp_coda-0.1.0/src/mcp_coda/servers/folders.py +141 -0
  27. mcp_coda-0.1.0/src/mcp_coda/servers/formulas.py +83 -0
  28. mcp_coda-0.1.0/src/mcp_coda/servers/pages.py +333 -0
  29. mcp_coda-0.1.0/src/mcp_coda/servers/permissions.py +216 -0
  30. mcp_coda-0.1.0/src/mcp_coda/servers/publishing.py +102 -0
  31. mcp_coda-0.1.0/src/mcp_coda/servers/rows.py +364 -0
  32. mcp_coda-0.1.0/src/mcp_coda/servers/tables.py +175 -0
  33. mcp_coda-0.1.0/tests/__init__.py +0 -0
  34. mcp_coda-0.1.0/tests/conftest.py +33 -0
  35. mcp_coda-0.1.0/tests/unit/__init__.py +0 -0
  36. mcp_coda-0.1.0/tests/unit/test_client.py +199 -0
  37. mcp_coda-0.1.0/tests/unit/test_config.py +75 -0
  38. mcp_coda-0.1.0/tests/unit/test_exceptions.py +61 -0
  39. mcp_coda-0.1.0/tests/unit/test_helpers.py +122 -0
  40. mcp_coda-0.1.0/tests/unit/test_tools_account.py +61 -0
  41. mcp_coda-0.1.0/tests/unit/test_tools_docs.py +122 -0
  42. mcp_coda-0.1.0/tests/unit/test_tools_pages.py +113 -0
  43. mcp_coda-0.1.0/tests/unit/test_tools_rows.py +140 -0
  44. 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
@@ -0,0 +1,18 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ dist/
5
+ build/
6
+ .eggs/
7
+ *.egg
8
+ .venv/
9
+ .env
10
+ .env.local
11
+ .pytest_cache/
12
+ .mypy_cache/
13
+ .ruff_cache/
14
+ htmlcov/
15
+ coverage.xml
16
+ .coverage
17
+ *.so
18
+ .DS_Store
@@ -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
@@ -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
@@ -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