Skip to main content

mcp-coda

PyPI version PyPI downloads Python License: MIT CI MCP Registry

Install: uvx mcp-coda | PyPI | MCP Registry | Changelog

uvx mcp-coda                          # with writes
MCP_READ_ONLY=true uvx mcp-coda       # locked read-only: write tools are not listed

mcp-coda is a Model Context Protocol (MCP) server for Coda. It lets an AI assistant read and write Coda docs, pages, tables, and rows through the Coda API. It also runs formulas, manages permissions and folders, publishes docs, and triggers automations. The server exposes 54 tools, 12 resources, and 5 prompts. It supports the MCP 2026-07-28 specification (often called MCP 2.0) and stays compatible with 2025-11-25 clients. It works with Claude Desktop, Claude Code, Cursor, Windsurf, VS Code Copilot, and any MCP-compatible client. Runs in one of two modes: with writes, or locked read-only (MCP_READ_ONLY=true) so the 20 write tools are never offered to the model.

mcp-coda uses FastMCP, httpx, and Pydantic.

1-Click Installation

Install in Cursor

Install in VS Code Install in VS Code Insiders

Tip: For other AI assistants (Claude Code, Windsurf, IntelliJ, Gemini CLI), visit the Coda MCP Installation Gateway.

Manual Setup Guides (Click to expand)

Prerequisite: Install uv first (required for all uvx install flows). Install uv.

Claude Code

# with writes
claude mcp add coda -e CODA_API_TOKEN=your-token-here -- uvx mcp-coda
# locked read-only
claude mcp add coda -e MCP_READ_ONLY=true -e CODA_API_TOKEN=your-token-here -- uvx mcp-coda

Windsurf & IntelliJ

Windsurf: Add to ~/.codeium/windsurf/mcp_config.json IntelliJ: Add to Settings | Tools | MCP Servers

Note: The actual server config starts at coda inside the mcpServers object. Remove MCP_READ_ONLY to allow writes.

{
  "mcpServers": {
    "coda": {
      "command": "uvx",
      "args": ["mcp-coda"],
      "env": {
        "CODA_API_TOKEN": "your-token-here",
        "MCP_READ_ONLY": "true"
      }
    }
  }
}

Gemini CLI

# with writes
gemini mcp add -s user -e CODA_API_TOKEN=your-token-here coda uvx mcp-coda
# locked read-only
gemini mcp add -s user -e MCP_READ_ONLY=true -e CODA_API_TOKEN=your-token-here coda uvx mcp-coda

VS Code

Add to .vscode/mcp.json:

{
  "servers": {
    "coda": {
      "type": "stdio",
      "command": "uvx",
      "args": ["mcp-coda"],
      "env": { "CODA_API_TOKEN": "your-token-here", "MCP_READ_ONLY": "true" }
    }
  }
}

Codex

# with writes
codex mcp add coda --env CODA_API_TOKEN=your-token-here -- uvx mcp-coda
# locked read-only
codex mcp add coda --env MCP_READ_ONLY=true --env CODA_API_TOKEN=your-token-here -- uvx mcp-coda

pip / uv

uv pip install mcp-coda

Drop MCP_READ_ONLY to allow writes. On a shared or hosted server put it in the deployer's env, not the client config.

Configuration

Variable Required Default Description
CODA_API_TOKEN Yes - Coda API token (get one here)
MCP_READ_ONLY No false Shared name across the mcp-* servers. Any value other than false/0/no/off/empty locks the server read-only: the 20 write tools and write-workflow prompts are not listed, and nothing can turn it back off at runtime
CODA_READ_ONLY No false Per-server alias for MCP_READ_ONLY; either one locks the server read-only. --read-only can only raise the lock
CODA_BASE_URL No https://coda.io/apis/v1 API base URL
CODA_TIMEOUT No 30 Request timeout in seconds
CODA_HTTP_BEARER_TOKEN No - Required to bind an HTTP transport to a non-loopback host. Clients send Authorization: Bearer <token>. Minimum 16 characters

Supported Token Types

The server checks these environment variables in order — first match wins:

  1. CODA_API_TOKEN
  2. CODA_TOKEN
  3. CODA_PAT

Generate tokens at coda.io/account#apiSettings. Tokens grant access to all docs accessible by the token owner. Tokens have no scope restrictions. Coda's sharing settings control doc-level access.

Compatibility

Client Supported Install Method
Claude Desktop Yes claude_desktop_config.json
Claude Code Yes claude mcp add
Cursor Yes One-click deeplink or .cursor/mcp.json
VS Code Copilot Yes One-click deeplink or .vscode/mcp.json
Windsurf Yes ~/.codeium/windsurf/mcp_config.json
Any MCP client Yes stdio or HTTP transport

Protocol support

mcp-coda implements the Model Context Protocol 2026-07-28 specification, often called MCP 2.0. It also stays compatible with 2025-11-25 clients. A FastMCP client pinned to 2026-07-28 and a legacy client both list all tools and reach the Coda API over stdio. The companion code PR adds a regression test that checks tools/list with an in-memory client pinned to 2026-07-28.

  • Spec version: MCP 2026-07-28 (MCP 2.0), backward compatible with 2025-11-25.
  • Built on: FastMCP 4.x and the MCP Python SDK 2.x.
  • Transports: stdio (default) and streamable-http (recommended for remote). sse (HTTP+SSE) still works, but the 2026-07-28 specification deprecates it, so the server prints a warning.
  • Capabilities: tools, resources, and prompts. The server uses no Roots, Sampling, Logging, elicitation, or resource subscriptions, so the 2026-07-28 deprecations do not affect it.

Error results

An expected failure — a 404, a 401, a rate limit, or a write that reaches the read-only guard — comes back as a tool result with isError: true rather than a value the caller must inspect for an error key. (In locked read-only mode the write tools are hidden, so calling one returns an Unknown tool error; the error envelope below is the guard's own response, returned only when a client reaches a write tool anyway.) The result body is the text content: a JSON object with error, an actionable hint, and, where relevant, status_code, body, and retry_after. The result carries no structuredContent — the TypeScript MCP SDK validates structuredContent against the tool's output schema even when isError is true, so an error payload there would make strict clients reject the whole result. Unexpected exceptions (a bug in a tool) are also isError: true, their text is TypeName: message, and the server logs them with a traceback.

A successful result carries the Coda JSON object as structuredContent beside the pretty-printed text, and tools advertise no outputSchema: payloads pass the upstream fields through untyped, so strict clients validate nothing and receive the object directly rather than a double-encoded {"result": "<json>"} wrapper. A typed schema is opt-in per tool via @mcp.tool(output_schema=…).

Tools (54)

Category Count Tools
Account 3 whoami, resolve browser link, mutation status
Docs 5 list, get, create, update, delete
Pages 9 list, get, create, update, delete, get content, delete content, export, export status
Tables 4 list tables, get table, list columns, get column
Rows 7 list, get, insert/upsert, update, delete, bulk delete, push button
Permissions 6 sharing metadata, list, add, delete, search principals, ACL settings
Folders 5 list, get, create, update, delete
Misc 8 formulas (list, get), controls (list, get), publishing (list categories, publish, unpublish), trigger automation
Analytics 7 doc analytics, doc summary, page analytics, pack analytics, pack summary, formula analytics, analytics updated
Full tool reference (click to expand)

Account

Tool Description
coda_whoami Get current user info
coda_resolve_browser_link Convert browser URL to API IDs
coda_get_mutation_status Check async write status

Docs

Tool Description
coda_list_docs List accessible docs
coda_get_doc Get doc metadata
coda_create_doc Create a new doc
coda_update_doc Update doc title/icon
coda_delete_doc Delete a doc

Pages

Tool Description
coda_list_pages List pages in a doc
coda_get_page Get page metadata
coda_create_page Create a page
coda_update_page Update page name/content
coda_delete_page Delete a page
coda_get_page_content Read page content
coda_delete_page_content Clear page content
coda_export_page Export page as HTML or markdown
coda_get_export_status Poll an export started by coda_export_page

Tables

Tool Description
coda_list_tables List tables and views
coda_get_table Get table metadata
coda_list_columns List columns in a table
coda_get_column Get column metadata

Rows

Tool Description
coda_list_rows List and filter rows
coda_get_row Get a single row
coda_insert_rows Insert or upsert rows
coda_update_row Update a row
coda_delete_row Delete a row
coda_delete_rows Bulk delete rows by filter
coda_push_button Push a button column value

Formulas

Tool Description
coda_list_formulas List named formulas
coda_get_formula Get formula value

Controls

Tool Description
coda_list_controls List controls
coda_get_control Get control value

Permissions

Tool Description
coda_get_sharing_metadata Get sharing config
coda_list_permissions List ACL entries
coda_add_permission Grant access
coda_delete_permission Revoke access
coda_search_principals Search users/groups
coda_get_acl_settings Get ACL settings

Publishing

Tool Description
coda_list_categories List publishing categories
coda_publish_doc Publish a doc
coda_unpublish_doc Unpublish a doc

Folders

Tool Description
coda_list_folders List folders
coda_get_folder Get folder details
coda_create_folder Create a folder
coda_update_folder Rename a folder
coda_delete_folder Delete a folder

Automations

Tool Description
coda_trigger_automation Trigger an automation rule

Analytics

Tool Description
coda_list_doc_analytics Doc usage metrics
coda_get_doc_analytics_summary Aggregated doc metrics
coda_list_page_analytics Page usage metrics
coda_list_pack_analytics Pack usage metrics
coda_get_pack_analytics_summary Aggregated pack metrics
coda_list_pack_formula_analytics Formula-level metrics
coda_get_analytics_updated Analytics freshness timestamp

Resources (12)

The server exposes MCP resources that provide ambient context and do not consume tool calls.

Data Resources (live API)

URI Name Description
coda://docs Coda Docs List of docs accessible to the current API token
coda://docs/{doc_id}/schema Coda Doc Schema Table and column definitions for a doc

Rules (static knowledge)

URI Name Description
resource://rules/coda-doc-structure Coda Doc Structure Doc/page hierarchy, page types, naming, when to split docs vs folders
resource://rules/coda-table-design Coda Table Design Column types, relations, display columns, row limits, table vs view
resource://rules/coda-permissions Coda Permission Model Doc-level vs page-level locking, ACL, domain sharing, principal types
resource://rules/coda-automations Coda Automation Patterns Webhooks, button triggers, rate limits, payload design, idempotency
resource://rules/coda-api-patterns Coda API Best Practices Rate limits, pagination, async mutations, error handling, retry

Guides (how-to)

URI Name Description
resource://guides/row-operations Row Operations Guide Insert vs upsert, bulk ops, key columns, cell formats, delete strategies
resource://guides/page-content Page Content Guide HTML vs markdown, insert modes, export workflows
resource://guides/formula-controls Formulas & Controls Guide Named formulas, control types, reading values
resource://guides/publishing-analytics Publishing & Analytics Guide Publishing categories, gallery settings, analytics date filtering
resource://guides/folder-organization Folder Organization Guide Folder CRUD, doc-folder relationships, hierarchy, bulk organization

Prompts (5)

The server provides MCP prompts — reusable task templates that clients can invoke.

Prompt Parameters Description
analyze_doc_structure doc_id Analyze a doc's page hierarchy, table layout, and organization
design_table_schema description Design a table schema from a natural language description
migrate_spreadsheet doc_id, source_format Guide for migrating CSV/Excel/Sheets data into Coda
setup_automation doc_id, trigger_type Set up a webhook/button/time automation with error handling
audit_permissions doc_id Audit sharing and permissions, suggest tightening

Usage Examples

Docs & Pages

"List all my Coda docs"
→ coda_list_docs(is_owner=True)

"Get the content of page 'Sprint Planning' in doc d1"
→ coda_list_pages(doc_id="d1") → find page ID
→ coda_get_page_content(doc_id="d1", page_id_or_name="canvas-abc")

"Create a new doc from a template"
→ coda_create_doc(title="Q1 Planning", source_doc="template-doc-id")

Tables & Rows

"List all tables in doc d1"
→ coda_list_tables(doc_id="d1")

"Find rows where Status is 'Done'"
→ coda_list_rows(doc_id="d1", table_id_or_name="Tasks", query="Done")

"Insert a new row into the Tasks table"
→ coda_insert_rows(doc_id="d1", table_id_or_name="Tasks", rows=[{"cells": [{"column": "Name", "value": "New task"}]}])

"Update a row's status"
→ coda_update_row(doc_id="d1", table_id_or_name="Tasks", row_id_or_name="i-abc", row={"cells": [{"column": "Status", "value": "In Progress"}]})

Formulas & Controls

"Get the value of the TotalBudget formula"
→ coda_get_formula(doc_id="d1", formula_id_or_name="TotalBudget")

"Check the current value of the DateFilter control"
→ coda_get_control(doc_id="d1", control_id_or_name="DateFilter")

Permissions & Sharing

"Share a doc with a teammate"
→ coda_add_permission(doc_id="d1", access="write", principal_email="alice@example.com")

"List who has access to a doc"
→ coda_list_permissions(doc_id="d1")

Security Considerations

  • Token scope: Coda API tokens grant access to all docs the token owner can access. Use a dedicated service account for production deployments to limit exposure.
  • Read-only mode: Set MCP_READ_ONLY=true (or CODA_READ_ONLY=true) in the launch you control and the server starts locked: the 20 write tools and the write-workflow prompts are not listed, a call to one returns "Unknown tool", and the guard refuses any write that still reaches it. Nothing lifts the lock at runtime — not a false from another source, not a .env file, not tool arguments; any value other than false/0/no/off/empty locks, and --read-only can only raise it. The lock is only as strong as the launch: set it where users cannot edit it (a managed MCP config such as Claude Code managed-mcp.json, a container, k8s or systemd env, or a hosted HTTP deployment). A user who starts the server themselves controls its environment. A Coda token has no scopes, so this lock is the only read-only control.
  • MCP tool annotations: Each tool declares readOnlyHint, destructiveHint, and idempotentHint for client-side permission prompts.
  • No credential storage: The server does not persist tokens. It reads credentials from environment variables at startup.
  • HTTP transport auth: Host/Origin protection is not authentication. Binding an HTTP transport to a non-loopback host requires CODA_HTTP_BEARER_TOKEN (min 16 chars); clients send Authorization: Bearer <token> and anything else gets a 401. Without it the server refuses to start on a non-loopback host.

Upgrading to 0.9.0

Two defaults changed. Both are breaking for callers that relied on the old behaviour:

  • coda_publish_doc no longer lists docs in the public gallery by default. discoverable now defaults to False — publishing alone makes a doc reachable by URL; pass discoverable=True to list it in the Coda gallery. mode is now restricted to view, play, or edit.
  • An HTTP transport on a non-loopback host now requires a bearer token. uvx mcp-coda --transport streamable-http --host 0.0.0.0 (or any non-loopback host) exits with an error unless CODA_HTTP_BEARER_TOKEN (min 16 chars) is set; clients then send Authorization: Bearer <token>. Binding to 127.0.0.1 is unchanged.

Rate Limits & Permissions

Rate Limits

Coda enforces per-token rate limits (varies by plan). When Coda rate-limits a request, the tool returns a 429 error with retry_after seconds. The server does not retry. Wait that many seconds, then retry. Most paginated endpoints default to 50 results per page (coda_list_docs 25, coda_list_columns 100). Use limit to adjust.

Async Mutations

Coda processes write operations (insert, update, delete rows) asynchronously. Tools return a requestId. Check it with coda_get_mutation_status to confirm completion.

Required Permissions

Operation Minimum Coda Doc Role
List docs, read pages, tables, rows, formulas, controls Viewer
Read permissions, analytics Viewer (doc owner for analytics)
Create/update pages, insert/update/delete rows Editor
Create/delete docs, manage folders Editor (or doc owner)
Add/remove permissions, publish/unpublish Doc Owner
Trigger automations Editor

Access Control

Layer Mechanism
Server-level CODA_READ_ONLY=true / MCP_READ_ONLY=true hides every write tool (deployer-owned launch required)
MCP annotations readOnlyHint, destructiveHint, idempotentHint for client-side prompts
Coda token Doc-level access enforced by Coda's sharing settings

CLI & Transport Options

# Default: stdio transport (for MCP clients)
uvx mcp-coda

# HTTP transport (SSE or streamable-http)
uvx mcp-coda --transport sse --host 127.0.0.1 --port 8000
uvx mcp-coda --transport streamable-http --port 9000

# Binding to a non-loopback host requires a bearer token
CODA_HTTP_BEARER_TOKEN=$(openssl rand -hex 32) \
  uvx mcp-coda --transport streamable-http --host 0.0.0.0 --port 9000
# Clients authenticate with the token:
#   curl -H "Authorization: Bearer $CODA_HTTP_BEARER_TOKEN" http://host:9000/mcp

# Config comes from env vars
CODA_API_TOKEN=your-token uvx mcp-coda --read-only

--coda-token still works but is deprecated and hidden from --help: it exposes the token to ps and shell history. Use CODA_API_TOKEN.

The server loads .env files from the working directory automatically via python-dotenv.

Docker

The image is a minimal, non-root python:3.13-slim build. The image defaults to locked read-only (MCP_READ_ONLY=true); pass -e MCP_READ_ONLY=false to allow writes.

docker build -t mcp-coda .

# stdio (default), locked read-only
docker run -i --rm -e CODA_API_TOKEN=your-token mcp-coda

# HTTP transport on a non-loopback host requires a bearer token (min 16 chars);
# clients then send Authorization: Bearer <token>
BEARER=$(openssl rand -hex 32)
docker run --rm -p 9000:9000 \
  -e CODA_API_TOKEN=your-token \
  -e CODA_HTTP_BEARER_TOKEN="$BEARER" \
  mcp-coda --transport streamable-http --host 0.0.0.0 --port 9000

FAQ

Does mcp-coda support MCP 2.0 (the 2026-07-28 spec)?

Yes. mcp-coda implements the MCP 2026-07-28 specification, commonly called MCP 2.0. It also works with 2025-11-25 clients.

Which transports does mcp-coda support?

The server supports stdio (the default) and streamable-http. It also supports sse, but the 2026-07-28 specification deprecates it. Prefer streamable-http for remote connections.

Can I run mcp-coda read-only so the assistant cannot change anything?

Yes. Start it with MCP_READ_ONLY=true (or CODA_READ_ONLY=true). The 20 write tools and the write-workflow prompts are then not listed at all, so the model never sees them; a call to one returns "Unknown tool", and nothing can turn writes back on while the process runs. Set it in a launch you control — a managed MCP config, a container or systemd env, or a hosted deployment — because a user who starts the server themselves can start it without the variable. A Coda token has no scopes, so this lock is the only read-only control.

What token scopes does mcp-coda need?

Coda tokens have no scopes. A token reaches every doc its owner can reach. Coda's sharing settings control doc-level access. Use a dedicated service account to limit exposure.

Does mcp-coda work with self-hosted Coda?

Coda is a hosted service, so there is no self-hosted deployment. Set CODA_BASE_URL only to target a proxy or a non-default API base.

Which clients work with mcp-coda?

mcp-coda works with Claude Desktop, Claude Code, Cursor, Windsurf, VS Code Copilot, and any MCP-compatible client over stdio or HTTP.

How many tools, resources, and prompts does it provide?

mcp-coda provides 54 tools, 12 resources, and 5 prompts. They cover docs, pages, tables, rows, formulas, controls, permissions, folders, publishing, automations, and analytics.

  • mcp-gitlab — GitLab integration (83 tools, 7 resources, 6 prompts)
  • mcp-atlassian-extended — Jira + Confluence integration (22 tools, 15 resources, 5 prompts)
  • mcp-argocd — Argo CD integration (37 tools, 7 resources, 7 prompts)

Development

git clone https://github.com/vish288/mcp-coda.git
cd mcp-coda
uv sync --all-extras

uv run pytest --cov
uv run ruff check .
uv run ruff format --check .

License

MIT

Metadata

Release files for mcp-coda 0.12.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for mcp-coda 0.12.1
File Size Uploaded
mcp_coda-0.12.1.tar.gz 251.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for mcp-coda 0.12.1
File Interpreter ABI Platform
mcp_coda-0.12.1-py3-none-any.whl Python 3 none any Details

Total release size: 319.6 kB

Release files / mcp_coda-0.12.1.tar.gz

Download URL mcp_coda-0.12.1.tar.gz
Size 251.0 kB
Tags Source
SHA-256 checksum
How to use checksums
5d3fe5c7d4666c9e69f070a13ccaaaac7f3c1494401f3d272e9ac74bd1a6d8d4
BLAKE2b-256 checksum
How to use checksums
82eb382c11ad92361e0e45631f42f12ed2949ec15fe10e6318c8b7af25882aa1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.

Transparency log

Release files / mcp_coda-0.12.1-py3-none-any.whl

Download URL mcp_coda-0.12.1-py3-none-any.whl
Size 68.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7ac85e688c7bb2bcd37c6efcbcd0e074065dd8596d024cf0ea7cdd4ac8824883
BLAKE2b-256 checksum
How to use checksums
382876028f700c453c71a8dca255417772ddec80984516ef4c6583863270222b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.12.1 This release

2 release files

0.12.0

2 release files

0.11.0

2 release files

0.10.0

2 release files

0.9.0

2 release files

0.8.0

2 release files

0.7.4

2 release files

0.7.3

2 release files

0.7.2

2 release files

0.7.1

2 release files

0.7.0

2 release files

0.6.1

2 release files

0.6.0

2 release files

0.5.9

2 release files

0.5.8

2 release files

0.5.7

2 release files

0.5.6

2 release files

0.5.5

2 release files

0.5.4

2 release files

0.5.3

2 release files

0.5.2

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4.12

2 release files

0.4.11

2 release files

0.4.10

2 release files

0.4.9

2 release files

0.4.8

2 release files

0.4.7

2 release files

0.4.6

2 release files

0.4.5

2 release files

0.4.4

2 release files

0.4.3

2 release files

0.4.2

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page