asana-gate は何をしますか?
asana-gateは、Asana REST APIの前に配置されたポリシーゲートウェイです。
YAMLポリシーは、スコープ(ワークスペース、チーム、ポートフォリオ、プロジェクト、セクション、タスク)ごとに、エージェントが実行できるアクションとリクエストの形式を定義します。ゲートウェイは、MCPツール呼び出しとしてもasana-gateコマンドとしても、すべてのリクエストに対してこれを強制します。
あなたが見たり実行したりできるすべてのものは、Asanaではなくそのポリシーによって決定されます。ポリシーが隠すオブジェクトはあなたにとって存在せず、拒否はメッセージがasana-gate:で始まるHTTP形式のエラーとして返されます。
まずゲートの応答を読む
ゲートが返すすべてのオブジェクトにはallowed_actionsが含まれています。これは、ポリシーがそのオブジェクトに対して現在許可している<リソース>:<動詞>形式のアクション(例:task:update、story:create)です。
書き込みを行う前にこれを確認してください。なぜなら、そこにないアクションは拒否されるからです。試行錯誤するのではなく、リストされているものに基づいて計画を立ててください。
| 応答 | 意味 | 対処方法 |
|---|---|---|
404 <タイプ>: Not a recognized ID: <gid> | オブジェクトが存在しないか、ポリシーが隠しています。ゲートは意図的にこの2つを区別不可能にしています(Asanaが送信するのと同じ404)。 | 再試行したり他のgidを試したりしないでください。オブジェクトはポリシーで表示されないと伝えてください。オーナーはasana-gate explain <gid>を実行して、どのルールが隠しているかを確認できます。 |
403 asana-gate: <アクション> is not permitted on <タイプ> <gid> | オブジェクトは表示されていますが、ポリシーがそのオブジェクトに対するこのアクションを許可していません。 | それを報告し、allowed_actionsからのアクションを提案してください。ポリシーの拡張はオーナーの判断です。 |
403 asana-gate: updating <リソース>.<メンバー> is not permitted here (allowed fields: …) | 更新がルールのfields許可リスト外のメンバーに触れました。 | 許可されたメンバーのみを使用して再送信してください。 |
400 asana-gate: the <リソース> does not satisfy the policy: … | ポリシーの制約:必須メンバーが不足またはクリアされている、プレフィックスまたは形式が間違っている、値が許可されていない、メンバーが禁止されている。 | メッセージの指示に従って正確にリクエストを修正し、再送信してください。 |
428 asana-gate: <アクション> needs a person's confirmation | ポリシーがこのアクションに人間の承認を必要としています。 | MCPの場合は、クライアントが表示する確認プロンプトに答えてください。シェルからは、--yesを付けて再実行してください。 |
429 asana-gate: <アクション> is limited to N per <期間> | ポリシーがこのスコープのこのアクションに設定したレート制限です。 | 期間が経過するのを待ってください。ループしないでください。 |
リスト(プロジェクト、タスク、検索、タイプアヘッド、イベント)はサイレントにフィルタリングされます。隠されたオブジェクトは単に存在しないものとされ、いくつ削除されたかは示されません。また、ページにはnext_page.offsetが含まれ、offsetを指定して続行できます。
Asana自身のエラーは、asana-gate:プレフィックスなしでそのまま通過します。402はワークスペースのプランに機能(検索、カスタムフィールド、ポートフォリオ、ゴールは有料プランが必要)がないことを意味し、プレーンな400はAsanaがボディを拒否したこと、プレーンな403はトークン自体の権限(監査ログイベント、ワークスペースイベント、組織エクスポートはEnterprise層のサービスアカウントが必要。早期アクセスのAgentsエンドポイントは設定のasana.enable内のai_teammate_actorsフラグが必要)を示します。
プレフィックスを探してください。プレフィックスがあればポリシーが決定し、なければAsanaが決定したものです。
MCPを通じた作業
サーバーは、ポリシーが許可する可能性のある厳選されたツールに加え、3つの汎用ツールを公開します。
asana_create_tasksとasana_update_tasksは一度に最大50のタスクを受け付け、タスクごとに1つのstatus_codeとbodyを順に返します。一部のタスクが成功し、他が失敗する場合があります。asana_requestは、同じポリシーを介して任意のAsana REST操作(method、/api/1.0以下のpath、query、bodyをdataオブジェクトとして)を呼び出します。これによるPOST /batchは最大50のアクションを受け付けます。asana_operationsは、各操作に必要なポリシーアクションをリストします。asana_allowed_actionsは、1つのオブジェクトに対して実行できることを示します。
| ツール | コマンドライン | 説明 |
|---|---|---|
asana_search_tasks | asana-gate task search | ワークスペース内のタスクを全文検索およびフィルター検索します(Asana Search API、有料プランのみ)。結果はポリシーが表示可能にしたタスクに限定されます。 |
asana_list_tasks | asana-gate task list | プロジェクト、セクション、タグ、またはユーザーに割り当てられたタスクをリストします(project、section、tag、assigneeのいずれか1つが必要)。各タスクにはallowed_actionsが含まれます。 |
asana_get_task | asana-gate task get <task_gid> | 1つのタスクを、そのすべてのフィールドとallowed_actionsとともに読み取ります。 |
asana_create_task | asana-gate task create | 1つ以上のプロジェクト(オプションでセクション内)、親タスクの下、またはワークスペース内のホーム無しでタスクを作成します。 |
asana_update_task | asana-gate task update <task_gid> | タスクのフィールドを更新します。完了にはtask:complete、割り当てにはtask:assignが必要です。その他のフィールドにはtask:updateが必要です(許可リストに制限される場合があります)。 |
asana_create_tasks | asana-gate task create-many | 1回の呼び出しで最大50のタスクを作成します。各タスクはasana_create_taskと同様に作成されます。結果はタスクごとに1つのstatus_codeとbodyを順に保持します。Asanaは一部のタスクで失敗し、他は成功する場合があります。いずれかのタスクに対するポリシー拒否は、実行前に呼び出し全体を拒否し、そのメッセージはタスク(actions[i])を指定します。 |
asana_update_tasks | asana-gate task update-many | 1回の呼び出しで最大50のタスクを更新します。各タスクはasana_update_taskと同様に更新されます。結果はタスクごとに1つのstatus_codeとbodyを順に保持します。Asanaは一部のタスクで失敗し、他は成功する場合があります。いずれかのタスクに対するポリシー拒否は、実行前に呼び出し全体を拒否し、そのメッセージはタスク(actions[i])を指定します。 |
asana_delete_task | asana-gate task delete <task_gid> | タスクを削除します(Asana内ではゴミ箱に移動します)。 |
asana_list_subtasks | asana-gate task subtasks <task_gid> | タスクの直接のサブタスクをリストします。 |
asana_create_subtask | — | タスクの下にサブタスクを作成します。プロジェクトが指定されない限り、親のスコープを継承します。 |
asana_set_task_parent | asana-gate task set-parent <task_gid> | タスクを別のタスクのサブタスクにします(親をnullにするとトップレベルのタスクになります)。 |
asana_add_task_to_project | asana-gate task add-project <task_gid> | タスクをプロジェクトにマルチホームし、オプションでセクションにも追加します。 |
asana_remove_task_from_project | asana-gate task remove-project <task_gid> | タスクをそのプロジェクトの1つから削除します。 |
asana_move_task_to_section | asana-gate task move <task_gid> | タスクを、それが属するプロジェクトのセクションに移動します(両端でtask:moveが必要)。 |
asana_add_tag_to_task | asana-gate task tag <task_gid> | タスクにタグを適用します(タスクのスコープでtag:applyが必要)。 |
asana_remove_tag_from_task | asana-gate task untag <task_gid> | タスクからタグを削除します(タスクのスコープでtag:applyが必要)。 |
asana_add_task_dependencies | asana-gate task add-dependencies <task_gid> | このタスクが依存するタスクをマークします。参照されるすべてのタスクは表示可能である必要があります。 |
asana_remove_task_dependencies | asana-gate task remove-dependencies <task_gid> | タスクの依存関係を削除します。 |
asana_list_task_stories | asana-gate task comments <task_gid> | タスクのコメントとアクティビティ(ストーリー)をリストします。 |
asana_create_comment | asana-gate task comment <task_gid> | タスクにコメント(ストーリー)を追加します。 |
asana_update_story | — | ストーリーを更新します(例:コメントの編集)。 |
asana_get_story | — | 1つのストーリーをそのフィールドとともに読み取ります。 |
asana_delete_story | — | ストーリーを削除します。 |
asana_list_projects | asana-gate project list | ワークスペースまたはチーム内のプロジェクトをリストします。結果はポリシーで表示可能なものに限定されます。各プロジェクトにはallowed_actionsが含まれます。 |
asana_get_project | asana-gate project get <project_gid> | 1つのプロジェクトをそのすべてのフィールドとともに読み取ります。 |
asana_create_project | asana-gate project create | プロジェクトを作成します。 |
asana_update_project | asana-gate project update <project_gid> | プロジェクトのフィールドを更新します。 |
asana_delete_project | — | プロジェクトを削除します。 |
asana_list_project_tasks | asana-gate project tasks <project_gid> | プロジェクト内のタスクをリストします。 |
asana_list_project_sections | asana-gate project sections <project_gid> | プロジェクト内のセクションをリストします。 |
asana_get_section | asana-gate section get <section_gid> | 1つのセクションをそのフィールドとともに読み取ります。 |
asana_list_section_tasks | asana-gate section tasks <section_gid> | セクション内のタスクをリストします。 |
asana_list_tags | asana-gate tag list | ワークスペース内のタグをリストします。 |
asana_create_tag | asana-gate tag create | タグを作成します。 |
asana_get_tag | — | 1つのタグをそのフィールドとともに読み取ります。 |
asana_list_users | asana-gate user list | ワークスペースまたはチーム内のユーザーをリストします。 |
asana_get_user | asana-gate user get <user_gid> | 1人のユーザーをそのフィールドとともに読み取ります。 |
asana_get_me | asana-gate whoami | 現在のユーザーに関する情報を読み取ります。 |
asana_list_teams | asana-gate team list | ワークスペース内のチームをリストします。 |
asana_get_team | asana-gate team get <team_gid> | 1つのチームをそのフィールドとともに読み取ります。 |
asana_get_workspace | asana-gate workspace get <workspace_gid> | 1つのワークスペースをそのフィールドとともに読み取ります。 |
asana_get_portfolio | asana-gate portfolio get <portfolio_gid> | 1つのポートフォリオをそのフィールドとともに読み取ります。 |
asana_get_goal | asana-gate goal get <goal_gid> | 1つのゴールをそのフィールドとともに読み取ります。 |
asana_get_custom_field | — | 1つのカスタムフィールドをそのフィールドとともに読み取ります。 |
ポリシーの理解とデバッグ
応答が期待と異なる場合(隠されたオブジェクト、予期しない拒否)、所有者はasana-gate explain <gid>を使用して、そのgidに一致するルールを確認できます。ポリシールールはpolicy.ymlにあり、構造は次のとおりです。
# ルールはスコープ(workspace、team、portfolio、project、section、task)に一致します。
# 各ルールには、actionにマッチするパターンと、制約を定義するwhereブロックがあります。
# whereブロックは、完了を必須にする、プレフィックスを強制する、rate limitを設定するなどの制約を追加できます。
# ルールの順序は重要です。最初に一致したルールが適用されます。
ポリシールールの一般的な構造:
- スコープの選択:ルールは特定のgidまたはパターンに適用されます。
- アクションの定義:
allowアクション(例:task:create)とdenyアクション(例:task:delete)を定義できます。 - 制約の追加(オプション):
whereブロックで、許可されるフィールド、必須のフィールド、プレフィックス、rate limitなどを指定できます。 - 確認の要求(オプション):特定のアクションに人間の確認を要求できます。
環境設定
asana-gateサーバーは以下の環境変数を必要とします。
ASANA_ACCESS_TOKEN:Asana個人用アクセストークン。ASANA_GATE_POLICY:ポリシーYAMLファイルへのパス。指定しない場合、デフォルトでpolicy.ymlが使用されます。ASANA_GATE_PORT(オプション):サーバーがリッスンするポート(デフォルト:8765)。
使用例
タスクを読む
asana-gate task get 123456
タスクを更新する(確認が必要な場合)
asana-gate task update 123456 --field name --value "新しい名前"
応答が428 asana-gate: task:update needs a person's confirmationの場合:
asana-gate task update 123456 --field name --value "新しい名前" --yes
ポリシーを説明する
asana-gate explain 123456
MCPツールとして使用する
{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "asana_get_task",
"arguments": {
"task_gid": "123456"
}
}
}
タスクを一括作成する
{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "asana_create_tasks",
"arguments": {
"tasks": [
{
"name": "タスク1",
"projects": ["111"]
},
{
"name": "タスク2",
"projects": ["111", "222"]
}
]
}
}
}
生のAPIリクエスト
{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "asana_request",
"arguments": {
"method": "GET",
"path": "/projects/111"
}
}
}