Change Asana without opening Asana.
A local-first Asana MCP over the REST API: controlled writes, schema operations, diagnostics, and one-call briefs over a Personal Access Token.
```bash npx -y @jtalk22/asana-mcp --setup ```Claude Code Claude Desktop Cursor Copilot Windsurf Gemini CLI Codex CLI any stdio MCP client
Why this exists · Install · 75 tools · Composites · Slack + Asana · Honest limits · API reference
--- ## Why this exists Asana's official V2 MCP server is the supported hosted choice: OAuth, workspace-scoped access, consolidated task writes, and interactive confirmations in supported clients. Its tool set changes over time, so use Asana's [current tools reference](https://developers.asana.com/docs/mcp-tools-reference) rather than a frozen comparison table. Choose this server when you want a transparent local stdio process and direct REST coverage: | Need | This server's approach | |---|---| | Local operation | PAT + stdio. No hosted intermediary and no product telemetry. | | Controlled agent surface | Mount `read`, `write`, `all`, or an explicit comma-list of tools. | | Board and field design | Create fields and enum options, attach fields to projects, create/reorder sections, and instantiate templates. | | Reliable REST edge cases | Typed custom-field values, section placement, rich task notes, start/due ordering, pagination, and bounded retry. | | Large or repetitive work | Bulk loops continue past individual failures and report per-item outcomes. | | Fewer agent round-trips | Morning briefs, user queues, portfolio rollups, board rollups, and inbox triage return decision-ready results. | | Local diagnostics | `--doctor`, explicit workspace detection, generated tool reference, and release preflight. | You can use both: the official service for managed OAuth and this package for local-first REST workflows or capabilities your operating model needs. To use this package, create a [Personal Access Token](https://app.asana.com/0/my-apps), run `--setup`, and keep the process on your machine. It talks only to `app.asana.com`. ## Slack + Asana continuity preview This package remains the full 75-tool, MIT-licensed local server. Nothing below is an unlock for missing tools. The same maintainer is also building [Keep the Thread](https://mcp.revasserlabs.com/workflows), a managed continuity layer for an independent operator or two-to-five-person team that already works in Slack and Asana but does not want another dashboard. Its first cross-tool contract asks a narrower question: > Which Slack commitment is missing, incomplete, or stale in one selected Asana project? ```mermaid flowchart LR Slack["1–5 selected Slack channels"] --> Report["continuity_asana_discrepancy_report"] Asana["1 selected Asana project\nincomplete tasks only"] --> Report Report --> Gaps["matched commitments · gaps · task drift · next reviews"] Gaps --> Receipt["source IDs preserved\nwrites_performed: 0"] ``` | Choose | When it fits | |---|---| | **This open-source package** | You want local stdio, your own PAT, all 75 Asana REST tools, controlled writes, board/schema design, and no hosted intermediary. | | **Keep the Thread preview** | You want a managed remote MCP endpoint, official connector consent, Slack-to-Asana discrepancy reporting, saved continuity contracts, or scheduled Slack delivery. | The hosted Asana connector code is live and read-only, but public OAuth activation is still staged. See the [representative input/output contract](https://mcp.revasserlabs.com/workflows), inspect the [live connector status](https://mcp.revasserlabs.com/api/v1/asana/oauth/status), or request a bounded [deployment review](https://mcp.revasserlabs.com/deployment). Creating, updating, completing, or deleting Asana tasks is not part of the hosted discrepancy report. ## Install **1. Get a token** — [app.asana.com/0/my-apps](https://app.asana.com/0/my-apps) → Personal access tokens → Create. Then either: ```bash npx -y @jtalk22/asana-mcp --setup # stores it in the macOS Keychain (or ~/.asana-mcp.json, mode 600) ``` or export `ASANA_PAT` yourself. **2. Add the server** to your MCP client: ```json { "mcpServers": { "asana": { "command": "npx", "args": ["-y", "@jtalk22/asana-mcp"] } } } ``` Claude Code one-liner: `claude mcp add asana -- npx -y @jtalk22/asana-mcp` **3. Verify:** ```bash npx -y @jtalk22/asana-mcp --doctor # token → identity → workspace → tool surface, as JSON ``` Workspace is auto-detected when your token sees exactly one. Tokens that see several: set `ASANA_WORKSPACE_GID` (the doctor lists your options) or pass `workspace` per call. ## 75 tools: read, act, design - **26 reads** — tasks, projects, sections, users, teams, tags, stories, subtasks, dependencies, attachments, statuses, portfolios, typeahead (name→GID), cross-board duplicate detection that knows a multi-homed task is *not* a duplicate. - **40 writes** — create/update/complete/assign, comments, followers, tags, dependencies, memberships, section moves, dates (`start_on` done right), custom fields (dates wrapped, `multi_enum` arrays), rich notes (sanitized), attachments (100MB uploads), bulk ops, project statuses, portfolios, templates with async-job polling, and `asana_set_notes_safe` for boards where automations rewrite what you just wrote. - **6 schema/design tools** — create custom fields, extend dropdowns, attach fields to projects, sections, reorder: the agent can *build* the board, not just fill it. - **3 destructive** — `delete_task` / `delete_project` / `delete_section` refuse to run without `confirm: true`. - **Local file boundary** — `attach_file` requires `confirm: true` and only reads from the current directory or `ASANA_MCP_FILE_ROOTS`. - **Read-only batch** — `batch_ops` rejects every non-GET action at both schema and runtime layers. Every tool declares [MCP annotations](https://modelcontextprotocol.io/docs/concepts/tools#tool-annotations) — `readOnlyHint`, `destructiveHint`, `idempotentHint`, `openWorldHint`, titles. Clients that honor them (Claude Code does) auto-allow reads in plan mode, parallelize them safely, and gate the destructive three. Trim the advertised surface with `ASANA_MCP_TOOLS=read` (30 tools), `write`, or a comma-list — a triage agent doesn't need delete tools in its context. Full inputs and semantics: [docs/API.md](docs/API.md). ## Composites: one call, one answer Five tools that replace ten-call round-trips, built from running real boards daily: - **`asana_morning_brief`** — incomplete tasks bucketed overdue / due-today / upcoming / blocked-by-dependency, one call. - **`asana_user_queue`** — one person's FULL queue, paginated past the API's 100-result search cap, bucketed by due date with per-project counts. The "what is X sitting on?" call. - **`asana_portfolio_rollup`** — per-project health (incomplete / overdue / completed-this-week + status) across a portfolio or project list. `include_archived: true` catches the open tasks hiding on archived boards — every default listing skips them. - **`asana_board_rollup`** — one board grouped by section, any number custom field summed per section ("Deal $", "Claim $"), deadline fields checked for overdue **by name** — fields resolve live from the board's own settings, nothing hard-coded. - **`asana_triage_inbox`** — bulk-create from a triaged list (the bulk CREATE the API doesn't have), per-item overrides, continues past failures. ## Honest limits - Asana's search API caps at 100 results with no pagination. Tools built on it say so (`truncated: true`) instead of pretending the tail doesn't exist; `asana_user_queue` and the list tools paginate past it where the REST API allows. - The `/batch` endpoint silently discards PUT bodies and GET options upstream — so this server doesn't route writes through it. `asana_batch_ops` exists for GET-with-default-fields only, and its description says exactly that. - Comment rich text (`html_text` on stories) is downgraded to escaped plaintext *by Asana* — comments here are plain text by design rather than silently ugly. - Date custom fields come back as full ISO timestamps; overdue math normalizes to `YYYY-MM-DD` before comparing (a silent all-clear bug we hit and fixed). - A PAT reads only its *own* My Tasks (others 403) — `asana_user_queue` uses the assignee route that works for anyone. More in [docs/TROUBLESHOOTING.md](docs/TROUBLESHOOTING.md). ## Security Your PAT has the same access as your Asana login. It's read from `ASANA_PAT`, the macOS Keychain (`asana-mcp`), or `~/.asana-mcp.json` (written mode 600) — never logged, never sent anywhere but `api.asana.com`'s host. No telemetry, no phone-home; read [SECURITY.md](SECURITY.md). ## Development ```bash npm ci && npm test # 16 unit tests, no token needed npm run doctor # live check against your workspace npm run api-docs # regenerate docs/API.md from lib/tools.js ``` PRs welcome — see [CONTRIBUTING.md](CONTRIBUTING.md). MIT. ---Also by the same author: @jtalk22/slack-mcp — catch up on Slack without reading it.