Claude Media
Managed AgentsをGitHubに接続しトークン権限とPR作成を実装する

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は認証情報をエージェント定義から切り離しています。リポジトリのトークンはセッションのリソースとして、MCPの認証情報はセッション作成時に vault_ids で指定するVault(保存済みの認証情報)から渡す設計です。

手順

PRまでの3ステップ

  1. 1

    GitHub MCPを宣言したエージェントを作る

    宣言するのはMCPサーバーのURLと使うツールセットです。

  2. 2

    セッション作成時にリポジトリとVaultを渡す

    resources に github_repository を入れ、MCP用の認証情報は vault_ids で指定します。環境のネットワーク設定がここで効いてきます。

  3. 3

    必要ならトークンだけ差し替える

    走行中のセッションで変えられるのはトークンまでです。リポジトリの構成は変えられません。

GitHub MCPを使うエージェントを作る

最初に、GitHub MCPサーバーを宣言したエージェントを作成します。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-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のツール呼び出しが使えるエージェントになります。モデルIDは公式のサンプルに合わせて claude-opus-5-5 にしています。YAMLで管理するなら、同じ内容を ant apply code-reviewer.md で適用する書き方も公式にあります。

ネットワーク制限付きの環境ではMCPが400で止まる

セッションは環境の上で動きます。環境のネットワークが limited のとき、エージェントのMCPサーバーは既定でブロックされます。allow_mcp_servers: true を立てるか、サーバーのホストを allowed_hosts に並べないと、セッション作成が400で失敗します。

curl -fsS https://api.anthropic.com/v1/environments \
  -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 '{
    "name": "github-work",
    "config": {
      "type": "cloud",
      "networking": {
        "type": "limited",
        "allow_mcp_servers": true,
        "allow_package_managers": true
      }
    }
  }'

注意したいのは、環境をAPIで作るときに networking を省くと unrestricted(ほぼ全面的に外へ出られる設定)になる点です。Claude Consoleの作成フォームは逆に「Limited」を選んだ状態から始まり、何も許可されていません。APIで作った環境とConsoleで作った環境とで、同じ「何も指定しない」が別の結果になります。無人で走らせる前提なら、networking は明示します。

リポジトリをセッションにマウントする

エージェントと環境が揃ったら、セッション作成時の 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",
  "vault_ids": ["$vault_id"],
  "resources": [
    {
      "type": "github_repository",
      "url": "https://github.com/org/repo",
      "mount_path": "/workspace/repo",
      "authorization_token": "ghp_your_github_token"
    }
  ]
}
JSON
)

authorization_token はリポジトリのクローンに使うトークンです。GitHub MCPサーバーの認証は、vault_ids で参照するVaultの認証情報が受け持ちます。

github_repository リソースのフィールドは次の5つです。

フィールド必須内容
type必須必須内容"github_repository" 固定
url必須必須内容https://github.com/<owner>/<repo> の形。.git は付けない
authorization_token必須必須内容クローンに使うGitHubトークン
mount_path必須任意内容/workspace 配下のクローン先
checkout必須任意内容チェックアウトするブランチかコミット。省くとデフォルトブランチ

url はHTTPSの形だけが通ります。SSH形式(git@github.com:...)は invalid_request_error で拒否されるので、手元の git remote -v の値をそのまま貼ると落ちます。

checkout を使うと、デフォルトブランチ以外やコミット固定で始められます。ブランチは {"type": "branch", "name": "main"}、コミットは {"type": "commit", "sha": "..."} の形です。

resources='[
  {
    "type": "github_repository",
    "url": "https://github.com/org/repo",
    "authorization_token": "github_pat_your_token",
    "checkout": {"type": "branch", "name": "release/1.2"}
  }
]'

トークン権限は必要最小限にする

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

トークン権限をどこまで削るべきか

上の表は repo や public_repo といったクラシックなトークンのスコープ名で書かれています。一方、推奨されているfine-grainedトークンは、対象リポジトリと権限を個別に選ぶ方式で、この名前のスコープは出てきません。表は「クローンもPR作成も書き込み系の権限が要る」という目安として読み、実際の設定画面では対象リポジトリを1つずつ選びます。

「読むだけなら public_repo で足りるのでは」と考えたくなりますが、これはパブリックリポジトリに限った話です。プライベートリポジトリならIssueの読み取りでも repo が必要で、「読み取りだから緩いスコープで済む」という区分は成り立ちません。

authorization_token はAPIレスポンスに返りません。セッションやリソースを取得しても、渡した値は出てきません。そのため、どのリポジトリにどのトークンを渡したかは、呼び出し側で記録しておきます。

複数リポジトリをマウントする

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で済みますが、「途中から別のリポジトリを足したい」場合は新しいセッションを作り直します。

修正からプッシュまでを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の作成は含んでいません。PRまで任せたいなら、指示文に「PRを作成する」と書き足します。

マウントしたリポジトリは信頼境界の内側に入る

リポジトリをマウントすると、ルートの .claude/skills も同時に読まれます。見つかるのは .claude/skills/<skill-name>/SKILL.md という、ルート直下から1階層だけの位置にあるスキルです。探索はセッション開始時に1回で、そのときにチェックアウトされている状態が対象になります。checkout でブランチを固定していれば、そのブランチの .claude/skills が使われます。

便利さの裏に、公式がWarningで書いている注意点があります。リポジトリのスキルはエージェントへの指示そのもので、レビューの工程なしに読み込まれます。マージされた外部PRや侵害された依存、コントリビューターの変更でスキルが書き換わると、bash や web_fetch を持つセッションにその指示が届きます。外部からのコントリビュートを受けるリポジトリは、マウント前に .claude/skills の中身を確かめます。

スキル探索はエージェントツールセットの read に頼っているため、read を無効にしたエージェントではリポジトリのスキルは読まれません。また、セルフホストのサンドボックスはGitHubリポジトリのリソースに対応していません。自前で動かす構成の考え方はセルフホスト環境のセキュリティに、スキルを自分で作る手順はカスタムスキルの記事にあります。

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連携は別の記事で扱っている別の機能です。

よくあるつまずき

  • vault_ids を付けずにMCPを使おうとする。authorization_token はクローン用なので、MCPの認証は通りません。認証の失敗は mcp_authentication_failed_error として返り、サーバーが認証情報を拒否した場合、該当する認証情報が未設定の場合、OAuthトークンの更新に失敗した場合が当てはまります。
  • MCPサーバーを足しただけで400になる。環境が limited のとき、allow_mcp_servers も allowed_hosts も無いとセッション作成が失敗します。
  • SSH形式や .git 付きのURLを渡す。https://github.com/<owner>/<repo> の形に直します。
  • リポジトリの追加・変更をセッション更新で済ませようとする。マウントは作成時に決まるので、構成を変えるなら新しいセッションを作ります。
  • トークンの対象リポジトリを絞らずに発行する。想定外のリポジトリまでエージェントが触れる状態になります。

まとめ

GitHub連携で先に決めておくのは、環境のネットワーク設定とトークンの範囲です。この2つが固まっていれば、修正からプッシュまでは1メッセージで流れます。

この記事を共有:XはてブLinkedIn