Skip to main content
Glama
README.md
# asana-mcp

A minimal, zero-destructive MCP server for Asana — built because the official Anthropic/Asana connector is broken.

## Why this exists

The official Asana connector surfaced in Claude Code as `mcp__claude_ai_Asana__*` tools. As of mid-2026 it stopped working — claude.ai's registry returns "Server not found" and Asana's `/sse` endpoint has been deprecated. There's no ETA on a fix.

Rather than wait, this is a clean TypeScript MCP server using the official `asana` npm SDK (v3.x) and a Personal Access Token. It gives Claude Code full Asana access with no third-party middleman, no destructive operations, and a minimal dependency footprint.

## Features

- **26 tools** — 13 read, 13 write, 0 destructive (no delete operations)
- **Custom field support** — set enum, multi-enum, number, text, and date custom fields on create and update
- **Read-only mode** — set `READ_ONLY_MODE=true` to hide all write tools
- **Minimal deps** — `asana` SDK, `zod`, `@modelcontextprotocol/sdk`, `dotenv`

## Tools

| Category | Tools |
|----------|-------|
| Tasks | `search_tasks`, `get_task`, `get_task_stories`, `create_task`, `update_task`, `create_subtask`, `create_task_story`, `get_multiple_tasks_by_gid`, `set_parent_for_task`, `add_task_dependencies`, `add_task_dependents` |
| Projects | `search_projects`, `get_project`, `get_project_sections`, `get_project_task_counts`, `get_project_status`, `create_project`, `create_project_status` |
| Tags | `get_tags_for_workspace`, `get_tags_for_task`, `create_tag`, `add_tag_to_task`, `remove_tag_from_task` |
| Misc | `list_workspaces`, `add_project_to_task`, `remove_project_from_task` |

## Requirements

- Node.js ≥ 18
- An Asana account with a Personal Access Token

## Setup

### 1. Get an Asana PAT

Go to **Asana → Settings → Developer apps → Personal access tokens** and create a token.

### 2. Configure environment

```bash
cp .env.example .env
# Edit .env and fill in your values
```

`.env`:
```
ASANA_ACCESS_TOKEN=your_token_here
ASANA_WORKSPACE_ID=your_workspace_gid
ASANA_DEFAULT_PROJECT_ID=your_default_project_gid   # optional fallback
READ_ONLY_MODE=false
```

**Finding your Workspace GID:** Open Asana in a browser and navigate to any project. The URL looks like `https://app.asana.com/0/<workspace_gid>/<project_gid>`. The first long number after `/0/` is your workspace GID. Alternatively, after setup you can call `asana_list_workspaces` and it will return it.

> **Note:** Always pass `project` explicitly when creating tasks. If omitted, the server falls back to `ASANA_DEFAULT_PROJECT_ID`.

### 3. Build

```bash
npm install
npm run build
```

### 4. Register with Claude Code

```bash
claude mcp add asana -s user -- node /absolute/path/to/asana-mcp/dist/index.js
```

Or with env vars inline (if you prefer not to use a `.env` file):

```bash
claude mcp add asana -s user \
  -e ASANA_ACCESS_TOKEN=your_token \
  -e ASANA_WORKSPACE_ID=your_workspace_gid \
  -- node /absolute/path/to/asana-mcp/dist/index.js
```

Restart Claude Code, then enable via `/mcp`.

## Custom fields

`asana_create_task` and `asana_update_task` accept a `custom_fields` object. Keys are custom-field GIDs; value shape depends on field type:

```json
{
  "custom_fields": {
    "1234567890000001": "9876543210000001",
    "1234567890000002": ["9876543210000002", "9876543210000003"],
    "1234567890000003": 42,
    "1234567890000004": "plain text",
    "1234567890000005": { "date": "2026-12-31" }
  }
}
```

| Field type | Value |
|-----------|-------|
| Single-select enum | Option GID string |
| Multi-select enum | Array of option GID strings |
| Number | Number |
| Text | String |
| Date | `{"date":"YYYY-MM-DD"}` |

The field must be enabled on the task's project/portfolio for the API to accept it.

## Development

```bash
npm run build      # tsc → dist/
```

After rebuilding, restart your Claude Code session — stdio MCP servers are spawned at session start and don't hot-reload.

## License

UNLICENSED