Coda MCP server for AI agents

Live

BEARER TOKEN

COLLABORATIVE DOCS

Productivity

Coda gives your agent access to your collaborative docs: list docs and folders, read pages and tables, add and update rows, create and update pages, push row buttons, and trigger doc automations.

  • Per-user credentials: each call uses the actual user's access token, never a shared bot.
  • Encrypted per-tenant vault: AES-256, resolved at request time, never in LLM context.
  • Scoped before every call: pre-call scope check, 90-day SIEM-exportable audit chain.
Coda
agent · Acme Q3
Run
Which tasks in the Q4 Launch tracker are still open?
S
coda_rows_list
118ms
Docs agent
9 tasks in the Q4 Launch tracker are open. 3 are assigned to Dana and due this week.
Sources: 1 table, 42 rows
coda
42 rows
18:29
Message Claude...

Tools your docs agent reaches for on Coda, scoped per user.

CALL ANY TOOL
37 tools for collaborative docs in Coda: list docs and folders, read pages, tables, and formulas, upsert and update rows, create pages, and run automations.
coda_automation_trigger
Trigger automation
Run a Coda doc automation whose trigger is set to "Webhook invoked", optionally passing a JSON payload the automation can read. Returns a requestId; the automation runs asynchronously, so check coda_mutation_status_get with the requestId if you need to confirm. Use coda_automation_trigger to run a webhook-invoked automation. Use coda_row_button_push to press a button in a table row instead. The automation must already exist with a Webhook invoked trigger; its rule ID is shown in the automation's settings.
Parameters
Name
Type
Required
Description
doc_id
string
Required
ID of the Coda doc. Get it from coda_docs_list, or from the doc's URL: it is the part after `_d` in a link like https://coda.io/d/Project-Tracker_dAbCDeFGH (here AbCDeFGH).
rule_id
string
Required
ID of the automation rule to run, e.g. grid-auto-b3Jmey6jBS. It appears in the doc's automation settings when the rule's trigger is "Webhook invoked".
payload
object
Optional
JSON object to send to the automation. The automation can read it through Step 1 Result. Leave empty to send an empty object. Example: {"customer": "Acme", "amount": 120}.
coda_browser_link_resolve
Resolve browser link
coda_column_get
Get column
coda_columns_list
List columns
coda_control_get
Get control
coda_controls_list
List controls
coda_current_user_get
Get current user
coda_doc_acl_settings_get
Get doc acl settings
coda_doc_create
Create doc
coda_doc_get
Get doc
coda_doc_permissions_list
List doc permissions
coda_doc_principals_search
Search doc principals
coda_doc_sharing_metadata_get
Get doc sharing metadata
coda_doc_update
Update doc
coda_docs_list
List docs
coda_folder_children_list
List folder children
coda_folder_create
Create folder
coda_folder_update
Update folder
coda_formula_get
Get formula
coda_formulas_list
List formulas
coda_mutation_status_get
Get mutation status
coda_page_content_list
List page content
coda_page_export_begin
Page export begin
coda_page_export_status_get
Get page export status
coda_page_get
Get page
coda_page_update
Update page
coda_pages_list
List pages
coda_row_get
Get row
coda_rows_list
List rows
coda_rows_upsert
Upsert rows

For more tools, view docs.

Build your Agent
Same auth pattern across LangChain, OpenAI, Anthropic, and Google ADK.
Python · LlamaIndex
import { ScalekitClient } from "@scalekit-sdk/node";
import { createReactAgent } from "@langchain/langgraph/prebuilt";

const sk = new ScalekitClient(env.SCALEKIT_ENV_URL, env.SCALEKIT_CLIENT_ID, env.SCALEKIT_CLIENT_SECRET);

// Coda tools scoped to this user
const { tools } = await sk.tools.listScopedTools("user_123", {
  filter: { connectionNames: ["coda"], toolNames: [
    "coda_docs_list",
    "coda_rows_list",
    "coda_rows_upsert"] },
  pageSize: 100,
});

const agent = createReactAgent({ llm, tools });
await agent.invoke({ messages: [{ role: "user", content: "Find open tasks in the Q4 Launch tracker and add a row for the pricing page task" }] });
import OpenAI from "openai";
import { ScalekitClient } from "@scalekit-sdk/node";

const sk = new ScalekitClient(env.SCALEKIT_ENV_URL, env.SCALEKIT_CLIENT_ID, env.SCALEKIT_CLIENT_SECRET);
const openai = new OpenAI();

const { tools } = await sk.tools.listScopedTools("user_123", {
  filter: { connectionNames: ["coda"] }, pageSize: 100,
});

const res = await openai.chat.completions.create({
  model: "gpt-5",
  messages: [{ role: "user", content: "Find open tasks in the Q4 Launch tracker and add a row for the pricing page task" }],
  tools,
});

// Execute the tool call with the user's vaulted Coda access token
await sk.tools.executeTool(res.choices[0].message.tool_calls[0], "user_123");
import Anthropic from "@anthropic-ai/sdk";
import { ScalekitClient } from "@scalekit-sdk/node";

const sk = new ScalekitClient(env.SCALEKIT_ENV_URL, env.SCALEKIT_CLIENT_ID, env.SCALEKIT_CLIENT_SECRET);
const anthropic = new Anthropic();

const { tools } = await sk.tools.listScopedTools("user_123", {
  filter: { connectionNames: ["coda"] }, pageSize: 100,
});

const msg = await anthropic.messages.create({
  model: "claude-sonnet-5",
  max_tokens: 1024,
  messages: [{ role: "user", content: "Find open tasks in the Q4 Launch tracker and add a row for the pricing page task" }],
  tools,
});

// Tool call runs with the user's vaulted Coda access token
await sk.tools.executeTool(msg.content, "user_123");
import { Agent } from "@google/adk/agents";
import { ScalekitClient } from "@scalekit-sdk/node";

const sk = new ScalekitClient(env.SCALEKIT_ENV_URL, env.SCALEKIT_CLIENT_ID, env.SCALEKIT_CLIENT_SECRET);

const { tools } = await sk.tools.listScopedTools("user_123", {
  filter: { connectionNames: ["coda"] }, pageSize: 100,
});

const agent = new Agent({
  name: "docs_agent",
  model: "gemini-2.5-pro",
  instruction: "Coda tools scoped to this user",
  tools,
});

await agent.run("Find open tasks in the Q4 Launch tracker and add a row for the pricing page task");
Try these prompts
Copy any prompt into your agent. Each maps directly to a Coda tool. Click to copy, paste into your agent, done.
Docs and pages
Copy the prompt
Copied
List the Coda docs I can access.
Copy the prompt
Copied
Create a page called Retro notes in the Q4 Launch doc.
Copy the prompt
Copied
Export the Launch plan page as Markdown.
Tables
Copy the prompt
Copied
List open tasks in the Q4 Launch tracker.
Copy the prompt
Copied
Add a row for the pricing page task, owned by Dana.
Copy the prompt
Copied
Mark the onboarding email task as done.
Automation and sharing
Copy the prompt
Copied
Press the Notify owner button on the pricing task row.
Copy the prompt
Copied
Trigger the weekly digest automation in the Q4 Launch doc.
Copy the prompt
Copied
Who is the Q4 Launch doc shared with?
SEE HOW AUTH WORKS
Each user connects their own Coda access token once, and Scalekit sends it with every call. Tokens stay vaulted, every call is scope checked, and every action is logged.
1
Authorize
Your user connects
Coda
once. We tie it to their identity and the meetings they approved — no shared bot account, no org-wide access
Who:
user ‘A’
when:
Once per user
access:
Limited to user
2
Store
Their
Coda
token lives in a vault scoped to them. User A's meetings are never reachable by an agent acting for user B, even on the same connection
vault:
encrypted
scope:
per-user
tokens:
auto-refreshed
3
Resolve
When your agent calls a
Coda
tool, we fetch the right token server-side. It never touches your agent, never appears in the LLM context, never shows up in your logs
speed:
~40ms
check:
before every call
seen by:
nobody
4
Audit
Every
Coda
tool call is logged — who triggered it, which meeting was fetched, what came back. 90 days of history, tied to the user who authorized it
history:
90 days
export:
SIEM-ready
logged:
every call
Test other agents
See the same per-user auth pattern across other docs and productivity connectors.
Support and Ops Teams
Meeting prep
Pulls agenda, participant context, and open action items before every meeting.
Engineering Teams
Engineering standup agent
Pulls commits from GitHub and GitLab, tracks issue movement in Jira, and posts a per-engineer standup brief to Slack. Each engineer's activity is read on their own delegated OAuth.
Test other agents
See the same per-user auth pattern across other docs and productivity connectors.
OPS
Meeting prep agent
Assemble the agenda, HubSpot attendee history, and open action items from Gmail before every meeting on the calendar.
ENGINEERING
Engineering standup agent
Pull commits from GitHub and GitLab, track Jira issue movement, and post a per-engineer standup brief to Slack.
Why Scalekit
Secure your agent's access. Connectors ship in minutes
01.
Shared tokens break per-user analytics
A shared Coda access token looks fine in a demo. In production every row update and page edit looks like one service account, and you cannot tell which user triggered it. Scalekit resolves the credential of the actual user who triggered the agent, never a shared bot.
// shared token
audit → bot_service_account

// scalekit
audit → user_abc ✓
02.
Authentication is not authorization
03.
Multi-tenancy is architectural
04.
Coda today. Ten connectors tomorrow.
“Our agents act across Salesforce, Gong, Google Drive, and more, on behalf of every customer. Scalekit behind the scenes meant we can keep adding tools without ever rebuilding how credentials or tool calling work.”
Venu Madhav Kattagoni
Head of Engineering / Von
FAQs
Frequently Asked Questions
Does the agent access Coda as the user or through a shared token?
As the user. Each user connects their own Coda access token once, and Scalekit sends it with every call. Audit logs attribute every row change, page edit, and automation run to that user, not a shared service account.
Where is the Coda access token stored?
In Scalekit's managed AES-256 token vault, namespaced per tenant. To rotate it, the user reconnects with a new access token. Revocation is a single dashboard action. Credentials never appear in prompts, logs, or LLM context.
Can I limit what the agent does in Coda?
Yes. Filter by tool name in listScopedTools to expose only what you want, for example the read tools without coda_row_button_push or coda_automation_trigger, which run whatever action the button or automation defines. No Coda tool deletes data. Scalekit also enforces scope checks before every API call.
What happens when a user revokes Coda access?
The connection is invalidated on the next tool call. Subsequent requests for that user fail closed with a clear error. Other users in the tenant remain unaffected. The event is logged for audit.
Why does a Coda write not show up right away?
Coda applies some writes asynchronously, such as row inserts. coda_mutation_status_get checks whether a write has finished, so the agent can confirm the change before it reads the table again.
Start in your coding agent
Up and running in one command
Install the Scalekit skill in your editor of choice. Connector, auth, tools, prompt, all wired up
Claude Code REPL
/plugin marketplace add scalekit-inc/claude-code-authstack
/plugin install agentkit@scalekit-auth-stack
Cursor Code REPL
# ~/.cursor/mcp.json
{
""mcpServers"": {
""coda"": {
""url"": ""https://mcp.scalekit.com/coda"",
""headers"": { ""Authorization"": ""Bearer $SCALEKIT_TOKEN"" }
}
}
}
Codex Code REPL
# ~/.codex/config.toml
[mcp_servers.coda]
url = ""https://mcp.scalekit.com/coda""
auth_env = ""SCALEKIT_TOKEN""
Copilot Code REPL
# .vscode/mcp.json
{
""servers"": {
""coda"": {
""url"": ""https://mcp.scalekit.com/coda"",
""type"": ""http""
}
}
}