MCP Use Cases
These workflows show how an AI agent chains Copera MCP tools to get real work done. Because the server is stateless, every board/table/row tool needs explicit hex ObjectIds — so most flows start with discovery (list_boards → list_tables → get_table_schema) before reading or writing.
Each example shows the tool calls in order, with the key arguments. Tool results are JSON; the agent reads ids and values out of one result to feed the next call.
Find a board and read its rows
The most common pattern: locate a board by name, find a table, then read rows.
list_boards({ query: "Roadmap" })
// → [{ id: "66ab…b01", name: "Q3 Roadmap", … }]
list_tables({ boardId: "66ab…b01", query: "Features" })
// → [{ id: "66ab…t02", name: "Features", columns: [...] }]
get_table_schema({ boardId: "66ab…b01", tableId: "66ab…t02" })
// → column ids + STATUS/DROPDOWN option ids
list_rows({ boardId: "66ab…b01", tableId: "66ab…t02", sort: "66ab…date:desc" })
// → rows with cell values keyed by columnId
list_rows is not paginated and can be large. Narrow it with query, a structured filter ({ match, conditions: [{ column_id, operator, value }] }), and sort rather than reading every row.
Update a row's status
Reading the schema first is required so you use the real columnId and a valid option id.
get_table_schema({ boardId, tableId })
// find the STATUS column id and the "Done" option id
update_row({
boardId,
tableId,
rowId: "66ab…r07",
columns: [{ columnId: "66ab…status", value: "66ab…doneOption" }],
})
To edit a row's long-text description or a RICH TEXT column cell, use set_row_markdown instead — update_row does not touch long text. Writes to markdown are queued (HTTP 202), so re-read with get_row_markdown to confirm.
Search docs and summarize
Pull the most relevant document for a keyword, fetch its body, and let the model summarize it.
search_docs({ query: "onboarding checklist", limit: 5 })
// → ranked hits with highlights showing what matched
get_doc_content({ docId: "66ab…d11" })
// → full markdown body (can be large — only fetch when you need it)
The agent summarizes the returned markdown in its own response. To browse rather than search, use get_docs_tree to walk the hierarchy.
Capture a summary back into a new doc
Combine reading with writing — research across the workspace, then persist the result.
search({ query: "Q3 launch", types: ["document", "channelMessage"], limit: 20 })
// gather context across docs and chat
create_doc({ title: "Q3 Launch Summary", content: "# Summary\n\n…" })
// → { id: "66ab…d99" }
// append more later (async — re-read to confirm)
set_doc_content({ docId: "66ab…d99", content: "\n\n## Risks\n…", operation: "append" })
Post a channel message
Notify a channel, or direct-message a specific person. Provide exactly one of channelId or userId.
list_channels({ query: "engineering", type: "text" })
// → [{ id: "66ab…c01", name: "engineering" }]
// or resolve a DM target:
list_workspace_members({ query: "alex@" })
// → [{ id: "66ab…u22", name: "Alex", email: "alex@…" }]
// post to a channel (synchronous)
send_message({ channelId: "66ab…c01", message: "Deploy is green ✅" })
// or direct-message a user (queued, may not appear immediately)
send_message({ userId: "66ab…u22", message: "Can you review the PR?" })
The optional name (display-name override) is channel-only — it is rejected when sending a direct message.
Triage notifications
Read the inbox, mark items handled, and clear noise.
list_notifications()
// → { notifications: [...], unreadCount, count }
update_notification({ notificationId: "66ab…n05", status: "read" })
delete_notification({ notificationId: "66ab…n06" }) // no undo
Pagination uses notification ObjectIds as cursors: pass the oldest returned id as after to page back through history.
Comment on a row for a customer
Add an externally-visible comment to a board row — use external deliberately, only when people outside the workspace should see it.
list_row_comments({ boardId, tableId, rowId, visibility: "all" })
// review the thread (cursor-paginated via pageInfo.endCursor)
add_row_comment({
boardId,
tableId,
rowId,
content: "We shipped the fix in today's release.",
visibility: "external",
})
Export a view and save it to the drive
Render a table view to a file. For PDF/ZIP or large exports, prefer saveToDrive: true so the file lands in the drive instead of an inline payload.
// viewId comes from list_tables / get_table_schema
export_table({
boardId,
tableId,
viewId: "66ab…v01",
format: "PDF",
saveToDrive: true,
})
// → async job snapshot + a drive reference
// later, fetch the file
get_drive_download_url({ fileId: "66ab…f44" })
// → presigned CloudFront url (fetch directly, no auth)
Tips for reliable agent runs
- Discover before you write. Call
get_table_schemato get realcolumnIds and option ids beforecreate_row/update_row/set_row_markdown— unsupported column types increate_roware silently ignored. - Re-read after async writes.
set_row_markdown,set_doc_content, and direct messages are eventually consistent. - Keep request volume reasonable. The API rate-limits;
429s are retried automatically with backoff, but agents that fan out can still hit limits. Narrow searches and lists withquery/filter/limit. - Mind the scopes. A
403almost always means the token is missing a scope for that tool — see Authentication.
See also
- Tool reference — every tool, its arguments, and the Public API capability it maps to.
- Connect an MCP client — wire up Claude, Cursor, or the MCP Inspector.
- API Reference — request/response schemas for the underlying endpoints.