Back to Browse

Coda MCP Server

ProductivityLow Risk9.8MCP RegistryLocal
Free

Server data from the Official MCP Registry

Coda MCP server (MCP 2026-07-28): docs, pages, tables, rows, automations; writes or read-only

About

Coda MCP server (MCP 2026-07-28): docs, pages, tables, rows, automations; writes or read-only

Security Report

9.8
Low Risk9.8Low Risk

Valid MCP server (2 strong, 3 medium validity signals). 1 known CVE in dependencies Package registry verified. Imported from the Official MCP Registry. Trust signals: trusted author (4/4 approved).

4 files analyzed · 2 issues found

Security scores are indicators to help you make informed decisions, not guarantees. Always review permissions before connecting any MCP server.

Permissions Required

This plugin requests these system permissions. Most are normal for its category.

file_system

Check that this permission is expected for this type of plugin.

What You'll Need

Set these up before or after installing:

Coda API token (also accepts CODA_TOKEN or CODA_PAT)Required

Environment variable: CODA_API_TOKEN

Alias for MCP_READ_ONLY. Any value other than false/0/no/off/empty locks the server read-only; --read-only can only raise the lockOptional

Environment variable: CODA_READ_ONLY

Locks the server read-only: write tools and write-workflow prompts are not listed and nothing lifts the lock at runtime. Shared name across the mcp-* servers; set it in the deployer's envOptional

Environment variable: MCP_READ_ONLY

Bearer token (min 16 chars) required to bind an HTTP transport to a non-loopback host; clients send it as 'Authorization: Bearer <token>'Required

Environment variable: CODA_HTTP_BEARER_TOKEN

How to Install

Add this to your MCP configuration file:

{
  "mcpServers": {
    "io-github-vish288-mcp-coda": {
      "env": {
        "MCP_READ_ONLY": "your-mcp-read-only-here",
        "CODA_API_TOKEN": "your-coda-api-token-here",
        "CODA_READ_ONLY": "your-coda-read-only-here",
        "CODA_HTTP_BEARER_TOKEN": "your-coda-http-bearer-token-here"
      },
      "args": [
        "mcp-coda"
      ],
      "command": "uvx"
    }
  }
}

Documentation

View on GitHub

From the project's GitHub README.

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.

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

VariableRequiredDefaultDescription
CODA_API_TOKENYes-Coda API token (get one here)
MCP_READ_ONLYNofalseShared 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_ONLYNofalsePer-server alias for MCP_READ_ONLY; either one locks the server read-only. --read-only can only raise the lock
CODA_BASE_URLNohttps://coda.io/apis/v1API base URL
CODA_TIMEOUTNo30Request timeout in seconds
CODA_HTTP_BEARER_TOKENNo-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

ClientSupportedInstall Method
Claude DesktopYesclaude_desktop_config.json
Claude CodeYesclaude mcp add
CursorYesOne-click deeplink or .cursor/mcp.json
VS Code CopilotYesOne-click deeplink or .vscode/mcp.json
WindsurfYes~/.codeium/windsurf/mcp_config.json
Any MCP clientYesstdio 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)

CategoryCountTools
Account3whoami, resolve browser link, mutation status
Docs5list, get, create, update, delete
Pages9list, get, create, update, delete, get content, delete content, export, export status
Tables4list tables, get table, list columns, get column
Rows7list, get, insert/upsert, update, delete, bulk delete, push button
Permissions6sharing metadata, list, add, delete, search principals, ACL settings
Folders5list, get, create, update, delete
Misc8formulas (list, get), controls (list, get), publishing (list categories, publish, unpublish), trigger automation
Analytics7doc analytics, doc summary, page analytics, pack analytics, pack summary, formula analytics, analytics updated

Account

ToolDescription
coda_whoamiGet current user info
coda_resolve_browser_linkConvert browser URL to API IDs
coda_get_mutation_statusCheck async write status

Docs

ToolDescription
coda_list_docsList accessible docs
coda_get_docGet doc metadata
coda_create_docCreate a new doc
coda_update_docUpdate doc title/icon
coda_delete_docDelete a doc

Pages

ToolDescription
coda_list_pagesList pages in a doc
coda_get_pageGet page metadata
coda_create_pageCreate a page
coda_update_pageUpdate page name/content
coda_delete_pageDelete a page
coda_get_page_contentRead page content
coda_delete_page_contentClear page content
coda_export_pageExport page as HTML or markdown
coda_get_export_statusPoll an export started by coda_export_page

Tables

ToolDescription
coda_list_tablesList tables and views
coda_get_tableGet table metadata
coda_list_columnsList columns in a table
coda_get_columnGet column metadata

Rows

ToolDescription
coda_list_rowsList and filter rows
coda_get_rowGet a single row
coda_insert_rowsInsert or upsert rows
coda_update_rowUpdate a row
coda_delete_rowDelete a row
coda_delete_rowsBulk delete rows by filter
coda_push_buttonPush a button column value

Formulas

ToolDescription
coda_list_formulasList named formulas
coda_get_formulaGet formula value

Controls

ToolDescription
coda_list_controlsList controls
coda_get_controlGet control value

Permissions

ToolDescription
coda_get_sharing_metadataGet sharing config
coda_list_permissionsList ACL entries
coda_add_permissionGrant access
coda_delete_permissionRevoke access
coda_search_principalsSearch users/groups
coda_get_acl_settingsGet ACL settings

Publishing

ToolDescription
coda_list_categoriesList publishing categories
coda_publish_docPublish a doc
coda_unpublish_docUnpublish a doc

Folders

ToolDescription
coda_list_foldersList folders
coda_get_folderGet folder details
coda_create_folderCreate a folder
coda_update_folderRename a folder
coda_delete_folderDelete a folder

Automations

ToolDescription
coda_trigger_automationTrigger an automation rule

Analytics

ToolDescription
coda_list_doc_analyticsDoc usage metrics
coda_get_doc_analytics_summaryAggregated doc metrics
coda_list_page_analyticsPage usage metrics
coda_list_pack_analyticsPack usage metrics
coda_get_pack_analytics_summaryAggregated pack metrics
coda_list_pack_formula_analyticsFormula-level metrics
coda_get_analytics_updatedAnalytics freshness timestamp

Resources (12)

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

Data Resources (live API)

URINameDescription
coda://docsCoda DocsList of docs accessible to the current API token
coda://docs/{doc_id}/schemaCoda Doc SchemaTable and column definitions for a doc

Rules (static knowledge)

URINameDescription
resource://rules/coda-doc-structureCoda Doc StructureDoc/page hierarchy, page types, naming, when to split docs vs folders
resource://rules/coda-table-designCoda Table DesignColumn types, relations, display columns, row limits, table vs view
resource://rules/coda-permissionsCoda Permission ModelDoc-level vs page-level locking, ACL, domain sharing, principal types
resource://rules/coda-automationsCoda Automation PatternsWebhooks, button triggers, rate limits, payload design, idempotency
resource://rules/coda-api-patternsCoda API Best PracticesRate limits, pagination, async mutations, error handling, retry

Guides (how-to)

URINameDescription
resource://guides/row-operationsRow Operations GuideInsert vs upsert, bulk ops, key columns, cell formats, delete strategies
resource://guides/page-contentPage Content GuideHTML vs markdown, insert modes, export workflows
resource://guides/formula-controlsFormulas & Controls GuideNamed formulas, control types, reading values
resource://guides/publishing-analyticsPublishing & Analytics GuidePublishing categories, gallery settings, analytics date filtering
resource://guides/folder-organizationFolder Organization GuideFolder CRUD, doc-folder relationships, hierarchy, bulk organization

Prompts (5)

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

PromptParametersDescription
analyze_doc_structuredoc_idAnalyze a doc's page hierarchy, table layout, and organization
design_table_schemadescriptionDesign a table schema from a natural language description
migrate_spreadsheetdoc_id, source_formatGuide for migrating CSV/Excel/Sheets data into Coda
setup_automationdoc_id, trigger_typeSet up a webhook/button/time automation with error handling
audit_permissionsdoc_idAudit 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

OperationMinimum Coda Doc Role
List docs, read pages, tables, rows, formulas, controlsViewer
Read permissions, analyticsViewer (doc owner for analytics)
Create/update pages, insert/update/delete rowsEditor
Create/delete docs, manage foldersEditor (or doc owner)
Add/remove permissions, publish/unpublishDoc Owner
Trigger automationsEditor

Access Control

LayerMechanism
Server-levelCODA_READ_ONLY=true / MCP_READ_ONLY=true hides every write tool (deployer-owned launch required)
MCP annotationsreadOnlyHint, destructiveHint, idempotentHint for client-side prompts
Coda tokenDoc-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.

Related MCP Servers

  • 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

Reviews

No reviews yet

Be the first to review this server!