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

A local MCP server exposing the **full Asana REST API** — usable directly
from [Claude Code](https://claude.com/claude-code) as a stdio server, or
packaged as an [MCPB bundle](https://github.com/anthropics/mcpb) for
one-click install into Claude Desktop.

## Why

Hosted Asana connectors expose a curated subset of the API, and some
operations just aren't reachable through them (attaching custom fields to
projects, setting library field values, portfolio/goal plumbing, batch
endpoints, …). Working around that meant one-off scripts with a PAT every
time the curated tools fell short.

This server takes the opposite approach: one generic pass-through tool
covering the entire
[Asana API surface](https://developers.asana.com/reference), plus a few
curated convenience tools for the common operations — with the safety
guardrails enforced **in code**, not in prompts, so an over-eager model
can't talk its way past them.

## Tools

| Tool | What it does |
|---|---|
| `asana_request` | Call any Asana REST endpoint (`GET`/`POST`/`PUT`/`DELETE`) with arbitrary query/body — full API coverage |
| `asana_list_workspaces` | List workspaces/organizations visible to the token |
| `asana_search_tasks` | Task search with common filters plus an `extraQuery` escape hatch for any Asana search param |
| `asana_create_task` | Create a task (name, notes, due date, assignee, projects, custom fields, subtask parent) |
| `asana_update_task` | Update fields on an existing task |

## Guardrails

These are enforced in server code, so a confused or over-eager model cannot
talk its way past them:

- **DELETE is blocked by default.** Any `DELETE` via `asana_request` is
  refused unless the bundle was installed with *Allow DELETE requests*
  turned on. The curated tools cannot delete at all.
- **Optional workspace allowlist.** If configured, every non-GET request is
  checked against a list of allowed workspace GIDs. The server resolves the
  affected workspace from the request body or target resource; if it cannot
  be determined, the request is refused (**fail closed**). Reads are never
  restricted.

## Use with Claude Code (stdio)

Build the self-contained server bundle, then register it:

```sh
git clone https://github.com/AlexDay3000/asana-full-mcp && cd asana-full-mcp
npm install
npm run build   # bundles src/ into server/index.js (no runtime deps needed)

claude mcp add asana-full \
  --env ASANA_PAT=your-asana-pat \
  --env ASANA_WORKSPACE_ALLOWLIST= \
  --env ASANA_ALLOW_DELETE=false \
  -- node "$PWD/server/index.js"
```

Configuration is via environment variables:

| Variable | Required | Notes |
|---|---|---|
| `ASANA_PAT` | yes | Personal Access Token — create at <https://app.asana.com/0/my-apps> |
| `ASANA_WORKSPACE_ALLOWLIST` | no | Comma-separated workspace GIDs writes are restricted to; blank = no restriction |
| `ASANA_ALLOW_DELETE` | no | `true` to permit DELETE via `asana_request`; anything else blocks it |

## Use with Claude Desktop (MCPB)

Build the `.mcpb` bundle (see below) and open it with Claude Desktop.
You'll be prompted for:

| Setting | Required | Notes |
|---|---|---|
| Asana Personal Access Token | yes | Create at <https://app.asana.com/0/my-apps> |
| Workspace GID allowlist | no | Comma-separated GIDs; blank = writes allowed anywhere the token can reach |
| Allow DELETE requests | no | Default off |

The token is stored by the host's user-config mechanism — it is never baked
into the bundle.

## Build from source

```sh
npm install
npm run pack   # esbuild-bundles src/ into server/index.js, then packs the .mcpb
```

Requires Node 18+ (uses global `fetch`).

## License

[MIT](LICENSE)

This project is not affiliated with or endorsed by Asana, Inc. "Asana" is a
trademark of Asana, Inc. Your use of the Asana API through this server is
subject to [Asana's API terms](https://asana.com/terms).