Trello MCP
Provides tools for managing Trello boards, lists, cards, checklists, attachments, labels, members, comments, and more, enabling AI agents to read and update Trello boards.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Trello MCPshow my open cards on the GTD board"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Trello MCP — Personal remote connector for Claude
A small, opinionated MCP server that lets Claude read and update Trello boards. Runs on Cloudflare Workers, gated behind GitHub OAuth, allowlisted to a single GitHub user.
Designed primarily around Dann Bleeker Pedersen's GTD workflow, but the underlying tools are generic — friendly aliases for boards / lists / labels live in src/trello/constants.ts and are easy to extend for other workflows.
Since v1.19.0 the connector is multi-workspace: every board in every workspace on the account is reachable by name, with no configuration — see Workspaces.
Since v1.12.0 the same Worker also serves a private web To-Do dashboard at /dashboard — see Web dashboard.
Tools (102)
Reads
Tool | Purpose |
| All open boards the user belongs to, in every workspace, each tagged with its workspace; optional |
| Every workspace on the account with the boards it holds — the entry point on a multi-workspace account |
| Lists on a board (alias, name, ID, or board URL) |
| Cards on a list or board; includes |
| Read one list with |
| Filter by scope: |
| Closed (archived) cards on a board — same CardSummary shape as list_cards |
| Full details for one card |
| Fuzzy name search, scoped by |
|
|
| Checklists + items on a card |
| Attachments on a card (id, name, url, date, mimeType) |
| Fetch a single attachment with richer fields (previews[], edgeColor, pos) than list_attachments returns |
| All labels on a board (id, name, color) |
| Fetch one label directly by ID or by name (with board scope) |
| Everyone with access to a board (id, fullName, username, initials) |
| Members assigned to one card |
| Cross-board, cross-workspace "everything assigned to me"; optional |
| Chronological comment thread on a card |
| Recent actions on a card — moves, due-date edits, label/comment/attachment events |
| Cards hidden by the Snooze Power-Up, with wake times ( |
| Cards whose |
| One-call GTD snapshot: inbox, overdue, due-today, due-this-week, context-list counts, waiting stale, could-do horizons, snoozed, big-rocks |
| Authenticated user's bell-icon feed; filter by type + read state |
| Members who have voted on a card |
| All emoji reactions on a comment |
| Grouped emoji-reaction counts on a comment (lighter than list_comment_reactions) |
| Recent actions on a single list |
| The authenticated user's cross-board recent activity |
| Full detail for a single action (move, comment, update, etc.) |
| Trello's pre-rendered human-readable version of an action |
| Richer than |
| Look up any Trello member by ID or username |
| Custom-field DEFINITIONS on a board (errors actionably if the Power-Up is off) |
| A card's custom-field values, joined to their definitions (name + type, option labels resolved, unset fields as |
| Power-Ups currently enabled on a board (id + idPlugin + alias) |
| Plugin metadata (name, description, url) by alias or ID |
| Bundle up to 10 relative Trello paths into one request via |
Writes
Tool | Purpose |
| New card on a list (with guards + WIP warning) |
| Duplicate a card to a target list; |
| Move card between lists (guards source AND destination) |
| Edit name / description / due date |
| Soft archive ( |
| Mark due date as done (triggers Butler automations) |
| Set minutes-before-due reminder offset; null clears |
| Move a card to top / bottom / numeric position within its list |
| Set or clear a card's start date (ISO 8601 or null) |
| Tick / untick a single checklist item |
| Apply a label by ID or name |
| Remove a label by ID or name |
| Create a new label on a board (palette token or null for no color) |
| Delete a label board-wide (destructive — strips it from every card carrying it) |
| Assign a member (ID, username, or full name resolved on the card's board) |
| Unassign a member |
| Append a comment to a card |
| Edit an existing comment (by action ID from |
| Delete an existing comment |
| Append an item to the card's checklist |
| Remove an item from a checklist |
| Create a new named checklist (e.g. "Agenda", "Decisions") |
| Change a checklist's name |
| Delete a checklist and all its items |
| Promote a checklist item to a standalone card; optional |
| Attach a URL to a card |
| Upload a real file (base64 → multipart). 10 MB hard cap — for larger files, host the file and use |
| Remove an attachment from a card |
| Apply the same label to up to 50 cards (per-card skip reasons reported) |
| Move up to 50 cards to the same destination list (guards + WIP warning) |
| Unarchive a Power-Up-snoozed card NOW (refuses non-snoozed cards; creating snoozes via API is impossible) |
| Send the "Todays Actions" digest email immediately with live board data |
| Create a new list on a board (with position) |
| Rename a list |
| Archive (default) or reopen a list |
| Reposition a list and/or move it to another board |
| Bulk-move every card on a list to another list |
| Bulk-archive every open card on a list |
| Set cover (palette color or attachment); size + brightness optional |
| Strip the card's cover |
| Set or clear a due date on a checklist item |
| Assign or unassign a member on a checklist item |
| Move a checklist item within its checklist (top/bottom/number) |
| Rename and/or recolor an existing label |
| Watch / unwatch a card |
| Watch / unwatch a list |
| Flip one notification's read flag |
| Bulk mark every (optionally filtered) notification read |
| Vote on a card as the authenticated user |
| Withdraw your vote from a card |
| Add an emoji reaction to a comment |
| Remove a reaction by its ID |
| Duplicate an entire checklist (with items) onto another card |
| Bulk-clear every notification associated with one card |
| Create a new custom-field definition on a board (Power-Up-dependent) |
| Rename / reposition / toggle display-on-card-front for a custom field |
| Delete a custom-field definition — destructive, requires |
| Add an option to a list-type custom field |
| Remove an option from a list-type custom field |
| Set a custom-field value on a card (polymorphic: checkbox / date / number / text / list, or null to clear) — value is checked against the field's declared type |
| Set the same custom field to the same value across many cards (resolves + type-checks once per board) |
| Rename a list-type option without losing the cards using it (Trello has no update-option endpoint) |
| Enable a Power-Up on a board by alias (custom-fields, card-aging, voting, calendar) or ID |
| Disable a Power-Up (takes the boardPlugin id from list_board_plugins, NOT the idPlugin — Trello REST quirk) |
Related MCP server: Railway Guardrail MCP
Workspaces
The connector is workspace-agnostic. Trello scopes everything to the member behind the API token, so a workspace added to the account after the Worker was deployed is visible immediately — no redeploy, no code change.
Start with list_workspaces. It returns every workspace on the account with the boards it holds, plus a (no workspace) bucket for personal boards and any workspace a board was merely shared from:
{
"workspaces": [
{ "id": "…", "name": "techretail1", "displayName": "TECH Retail",
"boards": [ { "id": "…", "alias": null, "name": "TECH Retail Decision Board", "workspace": {…} } ] },
…
]
}Referring to a board
Anywhere a tool takes board, it accepts — in this order:
Form | Example | Notes |
Alias |
| From |
24-char ID |
| Passed straight through. No API call. |
Board URL |
| Paste from the browser; the short link is used as the ID. |
Board name |
| Matched live against every board the account can see, in any workspace. |
Name matching is case-insensitive and tiered: an exact match wins, then unique prefix, then unique substring — so tech retail finds the board above, while Done matching lists on three boards is refused, not guessed, with an error naming each candidate and its workspace. That refusal is the design: two workspaces will eventually both have a "Roadmap", and silently picking one is worse than asking.
Referring to a list
list accepts an alias, a 24-char ID, or a list name. A name is resolved on board when you pass one, otherwise across every board the account can see. Since generic list names (Backlog, Doing, Done) collide across boards by nature, pass board alongside list on any multi-workspace board:
create_card({ board: "TECH Retail Decision Board", list: "Backlog", name: "Ship it" })Narrowing by workspace
workspace takes a short name (techretail1), a display name (TECH Retail), or an ID. It appears on:
list_boards/list_my_cards_assigned— filters the result setsearch_cards(workspace) andsearch_cards_advanced(workspaces[]) — passed to Trello asidOrganizations, so the search runs workspace-scoped server-sideany board lookup — disambiguates a board name that exists in two workspaces
What stays single-board
Two surfaces are deliberately tied to the GTD board and are not workspace-generic: the daily digest and the weekly_review_pack tool. Both are shaped around dann-to-do's specific lists (Inbox, @Contexts, Could-do horizons), and weekly_review_pack refuses another board outright rather than returning all-zero buckets. The dashboard defaults to the same board but accepts ?board= with any of the reference forms above.
Caching
Board / workspace / list directory reads are cached per client for 60 seconds, so name resolution costs at most one round trip per minute rather than one per call. list_boards and list_workspaces always bypass the cache — a board created seconds ago must show up in the tool you'd use to look for it.
Safety guards
Enforced server-side before any Trello call — same rules for every tool, no per-tool drift:
Forbidden lists (Butler, Repeater Cards) — all writes refused. These lists hold automation rules and recurring templates; the connector observes but never modifies them.
Read-only lists (Rolling Big Rocks) —
move_cardsource OR destination refused.create_cardto this list refused.WIP-limit warnings — when a
move_cardorcreate_cardputs a list with a(WIP limit N)suffix over its limit, the response includes a warning, but the call still succeeds (treats WIP as guidance, not enforcement).No hard delete — the capability is not in the code.
archive_cardis the only destructive-feeling operation, and it's reversible from the Trello UI.delete_custom_fieldrequiresconfirm: true— deleting a field definition also erases its value on every card on the board, which is the one operation here that destroys data across many cards at once. Without the flag the call is refused, and the refusal names the field it would have deleted.Custom-field values are type-checked —
set_card_custom_fieldreads the field's declared type before writing and refuses a mismatched value (naming the key you should have used) rather than letting Trello 400 or silently no-op.
Custom fields
Custom fields are a Power-Up, so a board needs it enabled first — enable_board_plugin("custom-fields"). If it isn't on, the read tools say so and tell you which call fixes it, rather than returning an empty list you'd have to interpret.
Every custom-field tool takes a field by name or ID, the same way boards and lists already resolve, and list-type options resolve by their label as well as their ID:
// Both of these do the same thing.
set_card_custom_field({ cardId, customFieldId: "Priority", value: { listOptionId: "High" } })
set_card_custom_field({ cardId, customFieldId: "eeeeeeee…", value: { listOptionId: "1111aaaa…" } })Names are looked up on the board param (default board when omitted); set_card_custom_field infers the board from the card. An ambiguous name is refused with the candidate IDs rather than guessed.
Reads come back joined to their definitions — name, type, list values resolved to the option's label, and fields that have never been set included as value: null (Trello omits those entirely, which makes "unset" and "no such field" indistinguishable):
{ "id": "…", "idCustomField": "…", "name": "Priority", "type": "list",
"idValue": "2222bbbb…", "value": { "text": "Low" } }get_card, list_cards, list_cards_by_list, search_cards, search_cards_advanced and weekly_review_pack all take customFields: true to include the same block. It's opt-in everywhere: values ride along on the card fetch, but joining them to their names costs a definition lookup, and these are hot paths. Definitions are memoised per board for the life of a request, so a batch operation pays for that lookup once, not once per card.
The dashboard and the morning digest render custom-field values as badges automatically when the board has any — deliberately quieter than the label badges, since a custom field is data about a card rather than a flag on it.
Two operations exist because Trello's API can't do them directly:
batch_set_card_custom_field— same field, same value, many cards. Resolves and type-checks once per board instead of once per card.rename_custom_field_option— Trello has GET/POST/DELETE on options but no PUT, so an option's label is immutable and the obvious workaround (delete + re-add) silently clears the field on every card pointing at it. This adds the new option, re-points affected cards, then deletes the old one. If any card fails to move it stops and leaves both options in place rather than destroying values.
create_card accepts a customFields array. Trello can't set them on the create call, so they're applied as follow-ups and reported per field — the card is still returned if one fails, because reporting a hard failure would invite a retry that creates a duplicate.
Copying a card: name customFields explicitly in keepFromSource. Atlassian changed the semantics so that all is not a safe assumption for custom fields.
One real limitation: search_cards_advanced can't filter on custom-field values. Trello's search syntax doesn't support them. customFields: true annotates the results so you can filter the returned rows, but it can't narrow the search itself.
Access control
Only one GitHub login (dannbleeker) can call any tool or open the dashboard — hard-coded in src/allowlist.ts (single source of truth for both surfaces). Any other authenticated GitHub user reaches the OAuth flow but every tool call returns a refusal message, and the dashboard answers 403.
Session kill switch: dashboard sessions live ~30 days in a signed cookie with no server-side session store. If a device is lost, rotate the signing key — wrangler secret put COOKIE_ENCRYPTION_KEY (new openssl rand -hex 32) — which instantly invalidates every session everywhere. The MCP connector re-authenticates via GitHub on its own.
Web dashboard
A private, browser-accessible To-Do dashboard served by this same Worker — a hosted, always-on version of the desktop artifact. Open https://trello-mcp.<your-subdomain>.workers.dev/dashboard (or just /, which redirects) in any browser; you'll be sent through GitHub login the first time and get a ~30-day session cookie.
Zones: health bar (inbox / next actions / waiting / big rocks + WIP status), quick capture → Inbox, cards-per-list overview, next actions by context with label filters, needs-attention (Waiting / Inbox), and Rolling Big Rocks (read-only, each showing how long it has gone untouched, stalest first — a big rock has no due date and no actions, so age is the only signal that one is being buried).
Staleness, per zone: no card on the board carries a due date, so age is the live signal. A card shows
untouched Nonce it passes its zone's threshold — Inbox at 7 days, Waiting-for at 10, next actions at 14, big rocks always. Red at 21 / 21 / 30, and for big rocks amber at a full quarter (90 days) with the alarm a month past it, since they're quarterly goals that may legitimately roll over. Outside big rocks a healthy board shows none of them.Weekly review panel: the Could-do horizon counts and the stale waiting-for items — the two things the daily board deliberately hides. Backed by the same
weekly_review_packtool the digest and an MCP-driven review use, so all three read identical numbers. Opens itself on Fridays, a one-line strip otherwise, fetched only when open.Phone-ready: ~44px touch targets under
pointer: coarse(not a width breakpoint, so a narrow desktop window keeps the compact layout), and a 16px capture input so iOS doesn't auto-zoom. Captures made offline are queued inlocalStorageand flushed oldest-first when the connection returns; a capture that fails while online is not queued, since it may already have reached Trello and/api/capturehas no idempotency key.Layout comes from the board, not from constants:
/api/cardsreturns the board's lists, and the page treats any list named@…as a context (WIP parsed from the(WIP limit N)suffix) plus four roles matched by name — Inbox, Waiting for…, Done-do, Rolling Big Rocks. Everything else — Could-do (*), Someday maybe, Repeater Cards, Butler — stays off the dashboard. Add a context list or change a WIP limit in Trello and it lands here on the next refresh;/dashboard?board=<alias|name|id|url>points the whole view at another board.Labels: every label a card carries renders as a badge, coloured from its Trello palette colour — a label added on the board shows up here (and in the digest) without a code change.
BESTSELLER,DBP InvestandPlease Clarify and Organizekeep a hand-tuned look, the last one shortened toclarify.Filter chips above Next actions:
All/BESTSELLER/DBP Invest/SSF/Personal, each with a live count, persisted per browser.Personalis the residual — a card in none of the labelled spheres. The chips are defined in oneFILTER_LABELSlist inpage.htmlthat the counts, the chip row and the filter predicate all derive from, so adding a sphere is a one-line change that narrowsPersonalby the same stroke.Actions: ✓ Done sets
dueComplete=true(the board's Butler automation moves the card to Done-do — same semantics as theset_due_completetool); Move and Quick capture reuse the tools layer, so the safety guards above apply identically.Auth: GitHub OAuth (same OAuth app as the MCP flow) + the
ALLOWED_LOGINSallowlist, re-checked on every request. The JSON API under/api/*answers401/403and the page redirects itself to/app/login.Routes:
/dashboard,/app/login,/app/callback,/app/logout,/api/*(cards, move, done, undo-done, capture, snoozed, wake, digest/send), plus public PWA assets (/manifest.webmanifest,/icon.svg). The MCP surface (/mcp) and the reserved OAuth endpoints (/authorize,/callback,/token,/register) are untouched.Installable: the dashboard ships a web-app manifest — "Add to Home Screen" installs it as a standalone app. Dark mode follows the device preference.
Digest monitoring (optional): set a healthchecks.io ping URL as the
HEARTBEAT_URLsecret; the Worker pings it after every successful daily send, so a silent digest failure becomes an email alert.
Daily email digest
Since v1.14.0 the Worker also emails "Todays Actions" — a full HTML replica of the dashboard plus an Overdue & due today section — every day at 04:00 Europe/Copenhagen, DST-proof, with board data fetched at send time.
Scheduling: Cloudflare cron is UTC-only, so three triggers fire at 02:00/03:00/04:00 UTC and
src/digest/scheduler.tssends exactly once, at the first firing whose local hour is ≥ 4; the later firings retry automatically if the first attempt failed. A KV flag (written only on success) guarantees once per local day.Delivery: Resend, from
todo@bleeker-pedersen.dktodann@bleeker-pedersen.dk(both configurable viaDIGEST_FROM/DIGEST_TOvars inwrangler.jsonc).Testing it:
GET /digest/preview(session-gated) shows the exact email HTML in the browser;POST /api/digest/sendsends one immediately.Setup: verify the sending domain in Resend (three DNS records on their own subdomains — root SPF/mail is untouched) and
wrangler secret put RESEND_API_KEY. Until the key exists the scheduler logs and skips (fail-soft).
Setup
1. GitHub OAuth app
Create an OAuth app at https://github.com/settings/developers:
Homepage URL:
https://trello-mcp.<your-subdomain>.workers.devAuthorization callback URL:
https://trello-mcp.<your-subdomain>.workers.dev/(the origin root, with the trailing slash)Note the Client ID and generate a Client secret.
Why the origin root? The MCP flow redirects to
/callbackand the web dashboard to/app/callback. A GitHub OAuth app has a single callback URL, but GitHub accepts anyredirect_uriat or below the registered path — registering the root validates both. If you registered/callbackbefore v1.12.0, broaden it to the root or the dashboard login will fail withredirect_urimismatch (the MCP flow is unaffected either way).
For local development, register a second OAuth app with:
Homepage URL:
http://localhost:8788Authorization callback URL:
http://localhost:8788/
2. Trello credentials
You need an API key and a user token:
Value | Where |
API key | https://trello.com/power-ups/admin → create an app → API key |
Token |
|
3. KV namespace + secrets
# install deps
pnpm install
# create the KV namespace, then paste the returned id into wrangler.jsonc
pnpm exec wrangler kv namespace create OAUTH_KV
# production secrets
pnpm exec wrangler secret put GITHUB_CLIENT_ID
pnpm exec wrangler secret put GITHUB_CLIENT_SECRET
pnpm exec wrangler secret put COOKIE_ENCRYPTION_KEY # openssl rand -hex 32
pnpm exec wrangler secret put TRELLO_KEY
pnpm exec wrangler secret put TRELLO_TOKEN
# deploy
pnpm exec wrangler deployFor local dev, copy .dev.vars.example to .dev.vars and fill in the values; then pnpm dev.
4. Add to claude.ai
Settings → Connectors → Add custom connector. URL: https://trello-mcp.<your-subdomain>.workers.dev/mcp. Sign in with GitHub when prompted.
Adding a new board or workspace
Nothing is required. Since v1.19.0 a new board — in an existing workspace or a brand-new one — is reachable by name the moment Trello knows about it: list_workspaces shows it, and every board argument accepts its name, ID or URL. See Workspaces.
Adding an alias is still worth it for a board you touch constantly (it saves a name lookup and reads better in a prompt):
In Trello: copy the board's 24-char ID from the URL or from a
list_boardscall.In
src/trello/constants.ts: add an entry toBOARD_ALIASES.Optionally add list aliases under
LIST_ALIASES.Optionally mark any list as forbidden or read-only.
pnpm exec wrangler deploy.
No tool code changes are needed — the existing tools resolve aliases at call time.
Project layout
src/
index.ts — Worker entry, OAuth wiring, tool registrations
allowlist.ts — GitHub-login allowlist (shared: MCP + dashboard)
github-handler.ts — OAuth consent screen + GitHub callback; mounts the dashboard
utils.ts — auth helpers (unchanged from template)
workers-oauth-utils.ts — cookie/state utilities (HMAC helpers exported for the dashboard)
dashboard/
handler.ts — browser routes: /, /dashboard, /app/login|callback|logout, /digest/preview
api.ts — session-gated JSON API: /api/cards|move|done|capture|digest/send
session.ts — signed __Host-DASH_SESSION cookie (sign/verify/expiry)
page.html — the dashboard page (imported as a wrangler Text module)
digest/
render.ts — "Todays Actions" email HTML (pure function; full dashboard replica)
scheduler.ts — DST-proof 04:00-Copenhagen send window + KV dedupe + Resend call
trello/
client.ts — typed Trello REST client (retry on 429 + 5xx)
constants.ts — aliases, forbidden + read-only lists, WIP parser
resolve.ts — workspace / board / list reference resolution + directory cache
guards.ts — server-side safety guards
tools.ts — 102 tool implementations (testable in plain Node)
test/ — vitest unit tests (265; no real Trello calls)
wrangler.jsonc — Cloudflare Workers config
package.json
tsconfig.json
.dev.vars.exampleDevelopment
pnpm install
pnpm type-check # tsc --noEmit
pnpm dev # wrangler dev → http://localhost:8788Related
dannbleeker/trello-plugin— the local Python MCP for Claude Code on the same Trello account. The two coexist; this one is the remote connector for claude.ai.
License
MIT.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- Alicense-qualityDmaintenanceAn MCP server that connects Claude to Trello, enabling comprehensive management of boards, lists, and cards through natural language conversation. It supports a wide range of actions including searching cards, adding comments, managing checklists, and tracking board activity.Last updated148ISC
- Flicense-qualityBmaintenanceA team-wide, remote MCP server that lets Claude operate Railway projects through natural language, with safety guardrails to prevent irreversible actions without human approval.Last updated
- Alicense-qualityDmaintenanceA Model Context Protocol (MCP) server that connects Trello to Claude Code. Manage your boards, lists, cards, checklists, and more — all through natural language.Last updated631MIT
- Alicense-qualityFmaintenanceA secure MCP server that allows Claude to read and write local files on your machine with explicit approval gating for each access.Last updatedMIT
Related MCP Connectors
MCP server giving Claude AI access to 22+ NYC public-record databases for real estate due diligence
MCP server for AI agents to plan, verify, and deploy Cloudflare-native apps.
Cloud-hosted MCP server for durable AI memory
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/dannbleeker/trello-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server