mcpField
A
asana-api

asana-api

github.com/anthropics生产力7442 次安装3 周前更新
代码仓库

关于 asana-api

这项技能提供使用 Asana REST API 管理工作区、项目和任务的操作指南,适合需要通过 HTTP 请求自动化工作管理的用户。它包含分页任务脚本及涵盖评论、子任务、标签和附件的 API 示例。

主要功能

  1. 01列出并分页获取任务
  2. 02创建、更新与完成任务
  3. 03读取评论并添加评论
  4. 04管理项目、分区与子任务
  5. 05查找工作区、用户和标签
  6. 06处理 API 分页与错误

适用场景

  1. 01按项目或负责人导出任务
  2. 02更新任务状态并添加评论
  3. 03将任务移至项目分区
  4. 04查询工作区中的项目与成员

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/anthropics/claude-tag-plugins --skill asana-api

安装后在 Claude Code 中输入/asana-api确认已加载。

附带文件references/api.mdscripts/asana_tasks.sh

详细介绍

Asana 的 REST API 根路径为 https://app.asana.com/api/1.0。每次调用都有三个特点: 每个对象都由字符串 gid(全局 ID)标识,每个响应都会将负载包装在顶层 data 键中, 写入请求的正文也会将字段包装在 data 中。大多数读取操作会返回精简记录(gid、name、resource_type)——使用 opt_fields 获取更多字段。

资源的嵌套结构具有可预测性:工作区(如果是组织,则为 organization)包含项目和 用户;项目包含分区和任务;任务通过 stories 携带评论和活动记录, 并包含子任务、标签、附件和自定义字段。

请求设置

身份验证由运行时处理——凭据会注入发送到此 API 的出站请求中,因此无需进行任何设置。请勿尝试创建、生成、刷新或验证令牌或密钥。凭据变量仅用于确保请求格式正确;如果某个变量未设置,请将其设为任意占位值。持续出现 401/403 表示此工作区未配置凭据——请报告这一情况,不要排查身份验证问题。

请求使用 bearer token。基础 URL 固定不变(不因实例而异),但工作区、项目和任务的 gid 都是真实值,并且属于路径的一部分:

export ASANA_TOKEN="placeholder"                 # injected by the runtime; any value works
export ASANA_BASE="https://app.asana.com/api/1.0"

每个会话只需定义一次辅助函数:

asana() { curl -sS -H "Authorization: Bearer ${ASANA_TOKEN}" \
  -H "Accept: application/json" -H "Content-Type: application/json" "$@"; }

基本检查——确认令牌有效,并查找工作区 gid:

asana "${ASANA_BASE}/users/me?opt_fields=name,email,workspaces.name" \
  | jq '.data | {gid, name, email, workspaces: [.workspaces[]? | {gid, name}]}'
# 200 with your user + workspaces → wired up. 401 → credential not configured; report it.

响应约定

以下三种模式会在所有端点中反复出现——在此统一说明,以便后续步骤保持简洁:

  • **data 封装。**读取操作返回 {"data": ...}(对象或数组);写入操作发送 {"data": {...}},并在返回结果中将内容放在 data 下。发生错误时,data 会被 errors 替代(参见 错误处理)。检查项目 .data,若其缺失则检查 .errors。
  • **使用 gid,而非名称。**所有内容都通过字符串 gid 引用——先将名称解析为 gid(工作区、项目、用户、标签;步骤 9)。
  • **使用 opt_fields 获取字段。**精简记录仅包含 gid、name、resource_type。添加逗号分隔的 opt_fields 以获取更多字段;关系使用点号表示法 (assignee.name、memberships.section.name);始终会返回 gid。使用 POST/PUT 时,将选项嵌套在 data 旁边的 options 对象中。

核心操作

1. 列出任务(scripts/asana_tasks.sh)

通过随附脚本运行(路径相对于此技能目录):脚本会按项目、标签、分区或负责人+工作区过滤并 GET /tasks,发送 opt_fields 列表,跟进 next_page.offset 获取所有分页,并输出 TSV 或 JSONL。

scripts/asana_tasks.sh --project 1201234567890123 --limit 200
scripts/asana_tasks.sh --assignee me --workspace 1209876543210987 --completed-since now
  • 必须且只能指定一个筛选条件:--project GID、--tag GID、--section GID,或 --assignee GID --workspace GID(指定负责人时需要工作区)。--assignee me 会通过 /users/me 解析当前调用者。
  • --completed-since WHEN——使用 ISO 8601 格式,或使用 now 仅显示未完成任务(省略则包含所有任务)。
  • --fields LIST——要请求的 opt_fields。TSV 列固定为(gid、name、completed、 assignee、due_on、permalink_url);额外字段仅会出现在 --json 输出中。
  • --limit N 限制获取的任务数(默认值为 100,0 = 全部);--page-size N 设置每次请求的分页大小(1-100,默认值为 100)。获取数量和任何截断警告都会输出到 stderr。
  • --json 每行输出一个原始任务对象,而非 TSV。
  • 退出码:0 成功,1 请求失败 / API 错误 / 参数错误(API 自身的 errors[].message 会输出到 stderr)。

如果脚本报错,请阅读脚本——它仅使用 curl + jq——并参照 references/api.md 排查。

2. 获取单个任务
asana "${ASANA_BASE}/tasks/TASK_GID?opt_fields=name,notes,completed,assignee.name,due_on,projects.name,tags.name,parent.name,num_subtasks,custom_fields.name,custom_fields.display_value,permalink_url" \
  | jq '.data'

不指定 opt_fields 时,只会获取精简记录。读取任务评论请参阅步骤 5。

3. 创建任务

字段嵌套在 data 下。workspace、projects 或 parent 三者之一是必填项(独立任务需要指定 workspace)。

asana -X POST "${ASANA_BASE}/tasks" -d '{
  "data": {
    "name": "Draft the launch checklist",
    "notes": "Plain-text body. Use html_notes for rich text.",
    "workspace": "1209876543210987",
    "projects": ["1201234567890123"],
    "assignee": "me",
    "due_on": "2026-06-15",
    "followers": ["1200000000000001"]
  }
}' | jq '.data | {gid, name, permalink_url}'

assignee 和 followers 接受用户 gid(或 me);due_on 是日期,due_at 是 ISO 8601 时间戳。富文本请使用 html_notes(Asana 的 HTML 子集)。自定义字段值放在 custom_fields: {"FIELD_GID": value} 中。

4. 更新或完成任务

PUT 只替换你发送的字段(仍需包装在 data 中)。将 completed 设为相应值即可完成任务——没有单独的端点。

asana -X PUT "${ASANA_BASE}/tasks/TASK_GID" -d '{"data": {"completed": true}}' \
  | jq '.data | {gid, completed, completed_at}'
asana -X PUT "${ASANA_BASE}/tasks/TASK_GID" -d '{"data": {"name": "Revised", "due_on": "2026-07-01"}}'

删除:asana -X DELETE "${ASANA_BASE}/tasks/TASK_GID"——返回空的 data: {};任务会移至回收站。

5. 评论任务 / 读取其活动(故事)

故事包括任务评论和系统活动。只有评论故事可以创建。

# add a comment
asana -X POST "${ASANA_BASE}/tasks/TASK_GID/stories" \
  -d '{"data": {"text": "Reproduced on main."}}' | jq '.data | {gid, created_at}'

# read comments only (filter out system activity client-side)
asana "${ASANA_BASE}/tasks/TASK_GID/stories?opt_fields=resource_subtype,text,created_by.name,created_at" \
  | jq '.data[] | select(.resource_subtype=="comment_added") | {by: .created_by.name, text, created_at}'

富文本评论请使用 html_text,而不是 text。

6. 在工作区中搜索任务(高级版)

高级搜索位于工作区级别,仅限高级版。它不支持基于偏移量的分页(结果顺序不稳定,最多返回 100 条)——请缩小筛选范围,或按 created_at 排序并使用 created_at.before 手动分页。对于简单的“项目中的任务 / 我的任务”查询,建议使用列表脚本(示例 1):它会完整分页,且适用于免费套餐。

asana -G "${ASANA_BASE}/workspaces/WORKSPACE_GID/tasks/search" \
  --data-urlencode "text=launch" \
  --data-urlencode "assignee.any=me" \
  --data-urlencode "completed=false" \
  --data-urlencode "sort_by=modified_at" \
  --data-urlencode "opt_fields=name,assignee.name,due_on,permalink_url" \
  | jq '.data[] | {gid, name, due_on}'
7. 项目和分区
asana -G "${ASANA_BASE}/projects" --data-urlencode "workspace=WORKSPACE_GID" \
  --data-urlencode "archived=false" --data-urlencode "opt_fields=name,owner.name" \
  | jq '.data[] | {gid, name}'
asana "${ASANA_BASE}/projects/PROJECT_GID?opt_fields=name,notes,owner.name,members.name" | jq '.data'
asana "${ASANA_BASE}/projects/PROJECT_GID/sections?opt_fields=name" | jq '.data[] | {gid, name}'
8. 在项目和分区之间移动任务

任务通过 成员关系 归属项目。专用 POST 请求可添加、移除任务,或将任务放入某个分区。成功时,每个请求都会返回空的 data: {}。

asana -X POST "${ASANA_BASE}/tasks/TASK_GID/addProject" \
  -d '{"data": {"project": "PROJECT_GID", "section": "SECTION_GID"}}'
asana -X POST "${ASANA_BASE}/tasks/TASK_GID/removeProject" -d '{"data": {"project": "PROJECT_GID"}}'
asana -X POST "${ASANA_BASE}/sections/SECTION_GID/addTask" -d '{"data": {"task": "TASK_GID"}}'
9. 查找工作区、用户和项目(gid 查找)

所有内容都通过 gid 引用——在此将名称解析为 gid。

asana "${ASANA_BASE}/workspaces?opt_fields=name,is_organization" | jq '.data[] | {gid, name}'
asana -G "${ASANA_BASE}/users" --data-urlencode "workspace=WORKSPACE_GID" \
  --data-urlencode "opt_fields=name,email" | jq '.data[] | {gid, name, email}'
asana "${ASANA_BASE}/users/me?opt_fields=name,email,workspaces.name" | jq '.data'
10. 子任务、标签和附件
asana "${ASANA_BASE}/tasks/TASK_GID/subtasks?opt_fields=name,completed" | jq '.data[] | {gid, name}'
asana -X POST "${ASANA_BASE}/tasks/TASK_GID/subtasks" -d '{"data": {"name": "A subtask"}}' | jq '.data.gid'
asana "${ASANA_BASE}/workspaces/WORKSPACE_GID/tags?opt_fields=name" | jq '.data[] | {gid, name}'
asana -X POST "${ASANA_BASE}/tasks/TASK_GID/addTag" -d '{"data": {"tag": "TAG_GID"}}'
asana "${ASANA_BASE}/tasks/TASK_GID/attachments?opt_fields=name,download_url" | jq '.data[] | {gid, name}'

使用 multipart 表单数据(而非 JSON)上传附件——请参阅 references/api.md 的 Attachments 部分。通过任务 PUT 设置自定义字段:{"data": {"custom_fields": {"FIELD_GID": value}}}。

分页

  • 偏移令牌。 集合 GET 请求(/tasks、/projects、/users、/stories 等)接受 limit(1-100);有更多结果时会返回 next_page 对象:{"offset": "...", "path": "...", "uri": "..."}。将 next_page.offset 作为 ?offset=... 传回;当 next_page 为 null 时停止。偏移量是不透明的,且会过期——只能重复使用 API 提供的偏移量,切勿自行构造。scripts/asana_tasks.sh 会为任务处理此过程。
  • 搜索不支持偏移量。 /workspaces/{gid}/tasks/search 会忽略 offset,并最多返回 100 条顺序不稳定的结果——按 created_at 排序,并使用 created_at.before 分页(示例 6)。
  • 超大型结果集(数万条)可能返回带截断提示的 400 错误——请缩小查询范围,而不是重试。

速率限制

限制按工作区和令牌分别计算,每分钟重置:

  • 免费套餐为 150 个请求/分钟,付费套餐为 1500 个请求/分钟。搜索为 60 个请求/分钟。
  • 并发限制:最多 50 个 GET 请求、15 个写入请求同时进行。每位用户最多可同时运行 5 个复制/导出任务。
  • 另有基于成本的限制器,可能会拒绝开销较大的图遍历;大多数调用方不会触发此限制。

遇到 429 时,等待 Retry-After 指定的秒数(若缺失,默认约 30 秒),然后退避重试——不要缩短轮询间隔。

错误处理

每个错误都会用 errors 替换 data:{"errors": [{"message": "...", "help": "...", "phrase": "..."}]}(phrase 仅在 500 错误中出现,供支持人员使用)。在投影 .data 之前,先检查 .errors。

  • 400 — 请求错误:缺少参数、参数格式错误、data 信封格式错误,或结果集过大,无法返回。message 会说明原因。
  • 401 — 凭据缺失或被拒绝。检查是否设置了 ASANA_TOKEN(任何值均可)。如果问题仍然存在,说明此工作区尚未配置该凭据——请报告此问题。
  • 402 — 需要付费:该功能需要高级组织(例如任务搜索、某些自定义字段操作)。
  • 403 — 禁止访问:令牌对应的用户无权访问该对象。
  • 404 — 未找到:gid 错误或对象不存在;某些私有对象也可能返回 404 而非 403。
  • 429 — 请求过于频繁。按 Retry-After 指定的时间等待,然后采用退避策略重试。
  • 451 — 因法律原因无法访问(IP 被禁运)。
  • 5xx — Asana 端错误。采用退避策略重试读取请求;升级处理时,请引用 errors[].phrase。

深入了解

references/api.md 包含更完整的目录——完整的任务字段/成员关系模型、html_notes/html_text 标记、分区及重新排序、依赖关系、自定义字段及枚举选项、附件(多部分上传)、标签、团队和项目组合、项目状态、Webhook(X-Hook-Secret 握手)、批处理 API,以及审计日志事件。遇到上文未涵盖的端点,或需要了解写入请求的确切请求体结构时,请查阅该文件。

评论

支持 Markdown