Managed AgentsをGitHubに接続しトークン権限とPR作成を実装する
Managed AgentsのセッションにGitHubリポジトリをマウントし、トークンの必要最小権限・複数リポジトリの運用・PR作成までを実装コード付きで解説します。
Managed AgentsのGitHub連携で何ができるか
Managed AgentsはセッションのサンドボックスにGitHubリポジトリをマウントし、同時にGitHub MCPサーバーへ接続してPR作成までできます。マウントはクローンしたコードをファイルシステム上で読み書きする経路、GitHub MCPはブランチ作成・コミット・プッシュ・PR作成をツール呼び出しとして実行する経路で、両方が揃って初めて「リポジトリを読んで直してPRまで出す」一連の作業が1セッションで完結します。マウントしたリポジトリはキャッシュされるため、同じリポジトリを使う後続セッションは起動が速くなります。スケジュールデプロイで同じリポジトリを毎回マウントする運用でも、このキャッシュの恩恵をそのまま受けられます。
GitHubのコードを触るエージェントを無人で走らせる場合、心配になるのは「トークンがどこまで見えるか」「どのリポジトリまで触れてしまうか」という権限の範囲です。Managed Agentsはこの不安に対して、トークンをエージェント定義から切り離してセッション単位のリソースにする設計と、スコープを絞ったfine-grainedトークンの利用を前提にした運用の2段構えで応えています。実装の流れとしては、①GitHub MCPを宣言したエージェントを作る、②セッション作成時にリポジトリとトークンをリソースとして渡す、③必要ならトークンだけを後から差し替える、という順序になります。
GitHub MCPを使うエージェントを作る
最初に、GitHub MCPサーバーを宣言したエージェントを作成します。エージェント定義に持たせるのはサーバーのURLだけで、認証トークンはエージェント定義には含めません。トークンはセッション作成時にリソースとして渡す設計になっており、この分離によって同じエージェント定義を複数の組織・複数のリポジトリで使い回せます。mcp_servers にGitHub MCPサーバーのURLを、tools に mcp_toolset を並べて宣言します。
agent_id=$(curl -fsS https://api.anthropic.com/v1/agents \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "anthropic-beta: managed-agents-2026-04-01" \
-H "content-type: application/json" \
--data @- <<JSON | jq -r '.id'
{
"name": "Code Reviewer",
"model": "claude-opus-5",
"system": "You are a code review assistant with access to GitHub.",
"mcp_servers": [
{
"type": "url",
"name": "github",
"url": "https://api.githubcopilot.com/mcp/"
}
],
"tools": [
{"type": "agent_toolset_20260401"},
{
"type": "mcp_toolset",
"mcp_server_name": "github"
}
]
}
JSON
)tools の agent_toolset_20260401 はエージェントの標準ツール一式、mcp_toolset が mcp_server_name で指定したMCPサーバー(ここでは github)のツールをまとめて有効化する指定です。この2つを両方入れて初めて、GitHub MCPのツール呼び出しが使えるエージェントになります。
リポジトリをセッションにマウントする
エージェントを作ったら、セッション作成時の resources 配列に github_repository タイプのリソースを追加します。url にリポジトリ、authorization_token にGitHubトークンを渡し、mount_path は省略可能で指定しなければ /workspace/<repo-name> にクローンされます。
session_id=$(curl -fsS https://api.anthropic.com/v1/sessions \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "anthropic-beta: managed-agents-2026-04-01" \
-H "content-type: application/json" \
--data @- <<JSON | jq -r '.id'
{
"agent": "$agent_id",
"environment_id": "$environment_id",
"resources": [
{
"type": "github_repository",
"url": "https://github.com/org/repo",
"mount_path": "/workspace/repo",
"authorization_token": "ghp_your_github_token"
}
]
}
JSON
)マウントしたリポジトリのルートに .claude/skills ディレクトリがあれば、そこに置かれたスキルもセッション起動時に自動で読み込まれます。リポジトリ固有の作業手順をスキルとして同梱しておけば、マウントするだけでエージェントに引き継がれます。
トークン権限は必要最小限にする
GitHubトークンはfine-grained personal access tokenを使い、必要最小限のスコープに絞ります。GitHubアカウント全体に及ぶ広い権限のトークンを使い回すのは避けます。以降のサンプルの ghp_your_github_token はプレースホルダで、実際にはfine-grainedトークン(github_pat_...)の値に置き換えます。
| 操作 | 必要スコープ |
|---|---|
| プライベートリポジトリのクローン | 必要スコープrepo |
| PRの作成 | 必要スコープrepo |
| Issueの読み取り | 必要スコープrepo(プライベート)または public_repo |
| Issueの作成 | 必要スコープrepo(プライベート)または public_repo |
トークン権限をどこまで削るべきか
「読むだけなら public_repo で足りるのでは」と考えたくなりますが、これはパブリックリポジトリに限った話です。前掲の表のとおり、プライベートリポジトリを対象にする場合はIssueの読み取りのような操作でも repo スコープが必要で、「読み取りだから緩いスコープで済む」という区分は成立しません。fine-grainedトークンを発行するときは対象リポジトリを個別に選び、公式が案内するとおり必要最小限の権限だけを付与する形が、GitHubアカウント全体に効く古典的なpersonal access tokenより安全です。
複数リポジトリをマウントする
resources 配列に複数のエントリを並べれば、1セッションから複数のリポジトリを同時に読み書きできます。マイクロサービス構成でフロントエンドとバックエンドを横断して直す作業のように、単一リポジトリでは完結しないタスクに向きます。
resources='[
{
"type": "github_repository",
"url": "https://github.com/org/frontend",
"mount_path": "/workspace/frontend",
"authorization_token": "ghp_your_github_token"
},
{
"type": "github_repository",
"url": "https://github.com/org/backend",
"mount_path": "/workspace/backend",
"authorization_token": "ghp_your_github_token"
}
]'複数リポジトリを扱う場合、各エントリの mount_path を必ず明示して衝突を避けます。省略時のデフォルト(/workspace/<repo-name>)はリポジトリ名が被らない前提のフォールバックなので、同名リポジトリを別組織から2つマウントするような構成では明示指定が必須になります。
走行中セッションでトークンをローテーションする
セッション作成後も、マウント済みリポジトリの一覧取得とトークンのローテーションができます。各リソースにはセッション作成時(または resources.list)に払い出される id があり、更新のたびにこの id を指定します。
repo_resource_id=$(curl -fsS "https://api.anthropic.com/v1/sessions/$session_id/resources" \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "anthropic-beta: managed-agents-2026-04-01" \
-H "content-type: application/json" | jq -r '.data[0].id')
curl -fsS "https://api.anthropic.com/v1/sessions/$session_id/resources/$repo_resource_id" \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "anthropic-beta: managed-agents-2026-04-01" \
-H "content-type: application/json" \
-o /dev/null \
--data @- <<JSON
{
"authorization_token": "ghp_your_new_github_token"
}
JSONトークンのローテーションはできますが、マウントするリポジトリ自体を走行中セッションで差し替えることはできません。リポジトリはセッションの生存期間中ずっと固定で、これはマウントがサンドボックスのファイルシステムに直結しているためです。有効期限が切れそうなトークンを更新する分にはこのAPIで対応できますが、「途中から別のリポジトリを足したい」場合は新しいセッションを作り直す必要があります。
GitHub MCPでブランチ作成からPRまでを1メッセージで任せる
リポジトリがマウントされ、GitHub MCPが接続されたセッションでは、修正・コミット・プッシュを1つの指示にまとめて投げられます。
curl -fsS "https://api.anthropic.com/v1/sessions/$session_id/events" \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "anthropic-beta: managed-agents-2026-04-01" \
-H "content-type: application/json" \
-o /dev/null \
--data @- <<JSON
{
"events": [
{
"type": "user.message",
"content": [
{
"type": "text",
"text": "Fix the type error in src/utils.ts, commit it to a new branch, and push it."
}
]
}
]
}
JSONここでのポイントは、ファイルの修正自体はマウント済みのファイルシステムに対する操作である一方、ブランチ作成・コミット・プッシュ・PR発行はGitHub MCPサーバー経由のツール呼び出しとして実行される点です。両方の経路が同じセッションで揃っているからこそ、「直す」と「PRにする」を分けて指示する必要がありません。
Managed AgentsのGitHub連携とClaude CodeのGitHub MCPの違い
GitHub MCPサーバー自体はClaude CodeでもMCP経由で同じように使えます。違いはリポジトリのマウント方法と実行環境です。Claude Codeはローカルのファイルシステムやローカルにクローン済みのリポジトリを直接操作するのに対し、Managed Agentsはクラウドのサンドボックス内にリポジトリをクローンし、そのサンドボックスごとAPIで起動・停止・スケジュール実行します。CLIを開いて対話する運用ならClaude Code、無人でスケジュール実行やAPI統合を組みたい運用ならManaged Agentsという住み分けです。Claude(チャット)のGitHub連携はさらに別物で、こちらはチャット画面からリポジトリを参照する用途に限られ、PR作成のような書き込み操作までは踏み込みません。
よくあるつまずき
- エージェント定義にトークンを書こうとすること。トークンはセッション作成時のリソースとして渡すもので、エージェント定義側にはサーバーURLしか持たせられません。エージェントを使い回す設計を前提にするなら、この分離を最初から意識しておきます。
repoスコープを安易に全リポジトリに広げること。fine-grainedトークンで対象リポジトリを絞らずに発行すると、想定していないリポジトリまでエージェントが触れる状態になります。- リポジトリの追加・変更をセッション更新で済まそうとすること。マウントはセッション作成時に確定するため、リポジトリ構成を変えたいときは新しいセッションを作ります。
- 同名リポジトリの
mount_path衝突に気づかないこと。複数リポジトリをマウントするときは、デフォルトのマウントパスに頼らず明示的に指定します。 - 複数リポジトリを1つのトークンで済まそうとすること。用途ごとにトークンを分けておけば、片方のリポジトリで問題が起きても他方への影響を切り離せます。resources配列は複数のトークンを個別に持てる設計なので、リポジトリ単位でトークンを分けること自体にコストはかかりません。
トークンはAPIレスポンスに出てこない
authorization_token はAPIレスポンスにエコーバックされません。セッションやリソースを取得しても、渡したトークンの値自体は返ってこない設計です。これは監査ログや障害調査でAPIレスポンスをそのまま出力・共有しても、トークンが一緒に漏れないための仕組みです。裏を返すと、一度渡したトークンをAPI経由で「確認」する手段はないので、どのリポジトリにどのトークンを渡したかは呼び出し側で記録しておく必要があります。
まとめ
Managed AgentsのGitHub連携は、リポジトリのマウント(ファイル操作用)とGitHub MCPサーバー(ブランチ・PR操作用)の2経路で成り立っています。トークンはfine-grainedな最小権限で発行し、エージェント定義ではなくセッションのリソースとして渡します。複数リポジトリはマウントパスを明示して衝突を避け、走行中セッションでできるのはトークンのローテーションまでで、リポジトリ構成自体の変更には新しいセッションが必要です。この構造を理解しておくと、「修正してブランチを切ってプッシュして」という1メッセージがなぜ1セッションで完結するのかが見通せます。GitHub連携そのものを増やすより先に、まずトークンのスコープ設計とマウントパスの衝突回避を固めておくと、複数リポジトリ・複数エージェントへ運用を広げたときの事故を減らせます。