# Copilot CLI ACP サーバー

GitHub Copilot CLIのエージェント クライアント プロトコル サーバーについて説明します。

> \[!NOTE]
> GitHub Copilot CLIでの ACP のサポートはパブリック プレビューであり、変更される可能性があります。

## 概要

エージェント クライアント プロトコル (ACP) は、クライアント (コード エディターや IDE など) とエージェント ( Copilot CLI など) 間の通信を標準化するプロトコルです。 このプロトコルの詳細については、 [公式の概要](https://agentclientprotocol.com/get-started/introduction)を参照してください。

## 利用事例

* \*\*IDE 統合:\*\*Copilotサポートを任意のエディターまたは開発環境に組み込みます。
* **CI/CD パイプライン:** 自動化されたワークフローでエージェント コーディング タスクを調整します。
* **カスタム フロントエンド:** 特定の開発者ワークフロー用の特殊なインターフェイスを作成します。
* **マルチエージェント システム:** 標準プロトコルを使用して、 Copilot を他の AI エージェントと調整します。

## ACP サーバーの起動

cli の ACP サーバーを開始するには、`--acp` コマンドの `copilot` オプションを使用します。 トランスポート モードは、 `--stdio` または `--port` オプションで指定できます。 トランスポート モードが指定されていない場合、サーバーは既定で stdio モードになります。

ACP モードを使用すると、構成された Bring Your Own-Key (BYOK) プロバイダー (`COPILOT_PROVIDER_*` 環境変数) を使用したセッションをログインなしで実行でき、 GitHub`-p`/対話型モードの動作と一致します。

### すべてのセッションに適用されるオプション

ACP `session/new` 要求では、クライアントが使用する作業ディレクトリや MCP サーバーなど、いくつかのセッション パラメーターのみを設定できます。 ツールのフィルター処理や推論の設定は含まれません。 それらを構成するには、サーバーを起動するときに対応するオプション **を渡します**。 サーバーは値を格納し、接続するすべてのクライアントに対して、作成または読み込むすべてのセッションの初期構成として適用します。 接続するクライアントがこれらの値を選択するのではなく、サーバーを起動する側が選択します。

| サーバー オプション                                  | 受け入れ可能な値                 | すべてのセッションに対する影響                |
| ------------------------------------------- | ------------------------ | ------------------------------ |
| `--available-tools=TOOL ...`                | 引用符で囲んだツール名をコンマ区切りで並べた一覧 | セッションでは、一覧に示されているツールのみを使用できます。 |
| `--excluded-tools=TOOL ...`                 | 引用符で囲んだツール名をコンマ区切りで並べた一覧 | 一覧表示されたツールはセッションから削除されます。      |
| `--effort=LEVEL`、`--reasoning-effort=LEVEL` |                          |                                |
| `low`、`medium`、`high`、`xhigh`、または `max`     | セッションの最初の推論作業を設定します。     |                                |

たとえば、このコマンドは、セッションがすべて最大の推論作業を使用し、 `bash` および `view` ツールのみを公開するサーバーを起動します。

```bash
copilot --acp --port 3000 --effort=max --available-tools="bash,view"
```

接続されているクライアントがそのサーバーに対して開くすべてのセッションは、これらの設定を継承します。 サーバーの起動時に値が固定されるため、クライアントは `session/new`を介してセッションごとに値を変更することはできません。

### stdio モード

stdio モードは、ACP サーバーを起動するときに既定で推論されます。
`--stdio` オプションを使用してあいまいさを解消することもできます。

```bash
copilot --acp --stdio
```

### TCP モード

`--port` オプションが `--acp` オプションと組み合わせて指定されている場合、サーバーは TCP モードで開始されます。

```bash
copilot --acp --port 3000
```

### stdio と TCP の選択

どちらのトランスポート モードも、改行で区切られた JSON (NDJSON) としてエンコードされた同じ ACP メッセージを伝送します。 クライアントがサーバーに接続する方法と、サーバーのライフサイクルを管理する方法のみが異なります。 2 つのモードは相互に排他的です。 `--stdio` と `--port` の両方を渡すことは拒否されます。

| 特徴              | stdio モード                                                                | TCP モード                                                                                   |
| --------------- | ------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------- |
| **クライアントの接続方法** | クライアントは子プロセスとして `copilot --acp` を起動し、プロセスの標準入力と出力を介してメッセージを交換します。        | サーバーは、クライアントがネットワーク ソケット経由で接続する TCP リスナーを開きます。 既定では、ループバック アドレス `127.0.0.1`にバインドされます。     |
| **クライアントの数**    | 単一のクライアント:サーバーを生成し、パイプを所有するプロセス。                                         | リスナーはソケット接続を受け入れ、それぞれが独自のエージェント接続として処理されます。                                               |
| **ライフサイクル**     | 親プロセスに関連付けられています。 親プロセスが終了するかパイプを閉じることで入力ストリームが閉じると、サーバーは自動的にシャットダウンします。 | 任意の単一のクライアントに依存しません。 サーバーは、停止されるまでそのポートで待ち受けます。たとえば <kbd>Ctrl</kbd>+<kbd>C</kbd> で停止できます。 |
| **標準出力**        | NDJSON プロトコル ストリーム用に予約されているため、ログやその他のテキストには使用できません。                      | プロトコル トラフィックがソケット経由で移動するため、他の用途には無料です。                                                    |

各モードを使用する場合:

* エディター、IDE、またはスクリプトがサブプロセスとして直接\*\*\*\* 生成する場合は、Copilot CLIを使用します。 プロセスの開始時にトランスポートが自動的に確立され、終了時に切断されるため、これは IDE 統合の既定で推奨されるセットアップです。
* クライアントがパイプではなくソケット経由でサーバーに到達する必要がある場合 (たとえば、別のプロセスまたはコンテナーから、または既知のポートで有効期間の長いサーバーに接続する場合) に **TCP モード** を使用します。

## 例: ACP サーバーとの統合

次の例は、Copilotの ACP サーバーと対話してGitHub Copilot CLIを使用するクライアント アプリケーションです。 これは、stdio モードで ACP サーバーを起動し、セッションを開き、プロンプトを入力して送信し、ストリーミングされた応答を出力するように求めます。

ACP サーバーをプログラムで操作するためのライブラリのエコシステムが増えています。 この例では、 [ACP TypeScript ライブラリを使用します](https://agentclientprotocol.com/libraries/typescript)。

この例を実行するには、次の依存関係が必要です。

* [Node.js](https://nodejs.org) バージョン18以降。
* GitHub Copilot CLI、インストールされ、 GitHub で認証されるか、BYOK プロバイダーで構成されています ( [ACP サーバーの開始を](#starting-the-acp-server)参照)。
* ACP TypeScript ライブラリを提供する `@agentclientprotocol/sdk` パッケージ。
  `npm install @agentclientprotocol/sdk`を実行してインストールします。

```typescript copy
import * as acp from "@agentclientprotocol/sdk";
import { spawn } from "node:child_process";
import { Readable, Writable } from "node:stream";
import * as readline from "node:readline/promises";

async function main() {
  const executable = process.env.COPILOT_CLI_PATH ?? "copilot";

  // ACP uses standard input/output (stdin/stdout) for transport; we pipe these for the NDJSON stream.
  const copilotProcess = spawn(executable, ["--acp", "--stdio"], {
    stdio: ["pipe", "pipe", "inherit"],
  });

  if (!copilotProcess.stdin || !copilotProcess.stdout) {
    throw new Error("Failed to start Copilot ACP process with piped stdio.");
  }

  // Create ACP streams (NDJSON over stdio)
  const output = Writable.toWeb(copilotProcess.stdin) as WritableStream<Uint8Array>;
  const input = Readable.toWeb(copilotProcess.stdout) as ReadableStream<Uint8Array>;
  const stream = acp.ndJsonStream(output, input);

  const client: acp.Client = {
    async requestPermission(params) {
      // This example should not trigger tool calls; if it does, refuse.
      return { outcome: { outcome: "cancelled" } };
    },

    async sessionUpdate(params) {
      const update = params.update;

      if (update.sessionUpdate === "agent_message_chunk" && update.content.type === "text") {
        process.stdout.write(update.content.text);
      }
    },
  };

  const connection = new acp.ClientSideConnection((_agent) => client, stream);

  await connection.initialize({
    protocolVersion: acp.PROTOCOL_VERSION,
    clientCapabilities: {},
  });

  const sessionResult = await connection.newSession({
    cwd: process.cwd(),
    mcpServers: [],
  });

  process.stdout.write("Session started!\n");

  // Ask the user to enter a prompt instead of using a hard-coded one.
  const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
  });
  const promptText = await rl.question("Enter a prompt: ");
  rl.close();

  const promptResult = await connection.prompt({
    sessionId: sessionResult.sessionId,
    prompt: [{ type: "text", text: promptText }],
  });

  process.stdout.write("\n");

  if (promptResult.stopReason !== "end_turn") {
    process.stderr.write(`Prompt finished with stopReason=${promptResult.stopReason}\n`);
  }

  // Best-effort cleanup
  copilotProcess.stdin.end();
  copilotProcess.kill("SIGTERM");
  await new Promise<void>((resolve) => {
    copilotProcess.once("exit", () => resolve());
    setTimeout(() => resolve(), 2000);
  });
}

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});
```

例を実行するには:

1. 上記のコードを `acp-client.ts` という名前のファイルに保存します。
2. `npx tsx`を使用してファイルを実行します。これは、別のビルド手順なしで TypeScript を直接実行します。

   ```bash
   npx tsx acp-client.ts
   ```

## スラッシュ コマンドを使用する

GitHub Copilot CLIの組み込みのスラッシュ コマンドは、ACP で実行できます。 1 つを呼び出すには、テキストがコマンドである通常のプロンプトとして送信し、単一のテキスト コンテンツ ブロック ( `/context` や `/session info`など) として渡します。 サーバーはコマンドを認識して直接実行します。 `/usage` や `/context` などの情報コマンドは、モデルを呼び出さずに出力を返します。一方、 `/plan` などのアクション コマンドや、対応するエージェント タスクを開始 `/review` 。 いずれの場合も、コマンド テキストは質問としてモデルに送信されません。

### 使用可能なコマンドの検出

サーバーは、標準の ACP `available_commands_update` セッション通知を通じて、サポートするコマンドをアドバタイズします。 これは、セッションが作成または読み込まれた後、およびセットが変更されるたびに (たとえば、スキルの読み込みが完了したときに) 送信されます。 このアドバタイズされた一覧は、ACP で実行できる権限のある常に最新のコマンド セットであり、クライアントは通常、コマンド メニューに表示されます。

アドバタイズされたリストには次のものが含まれます。

* \*\*\*\*、`/compact`、`/context`、`/usage`、`/env`、`/model`、`/mcp`、`/plan`、`/review`、`/research`、`/session`などの`/rename`。
* \*\*\*\* コマンドとして表示される`/SKILL-NAME`。

クライアント自身が登録したコマンドは、そのクライアント自身には通知されません。

### クライアントからリストにアクセスする

リストは要求に応答するのではなく通知として到着するため、オンデマンドでフェッチする方法はありません。 クライアントは、`session/update` 通知を処理し、種類が `available_commands_update` である更新に対応することで、それを利用します。 各エントリには、コマンドの引数を記述する `name` (先頭のスラッシュなし)、 `description`、および省略可能な `input.hint` があります。 設定が変更されるたびに通知が再送信されるため、キャッシュしたリストの完全な置き換えとして各通知を処理します。

次の `sessionUpdate` ハンドラーは、アドバタイズされたコマンドをキャプチャし、前に示した例の `client` オブジェクトを拡張します。

```typescript copy
// Track the latest advertised commands for the session.
let availableCommands: acp.AvailableCommand[] = [];

const client: acp.Client = {
  async sessionUpdate(params) {
    const update = params.update;

    if (update.sessionUpdate === "available_commands_update") {
      // This notification is a full snapshot—replace any cached list.
      availableCommands = update.availableCommands;
      for (const command of availableCommands) {
        // command.name has no leading slash; invoke it by sending "/<name>" as a prompt.
        console.log(`/${command.name} — ${command.description}`);
      }
      return;
    }

    // ...handle other updates, such as agent_message_chunk
  },

  // ...other client methods, such as requestPermission
};
```

アドバタイズされたコマンドのいずれかを実行するには、「スラッシュ コマンドの使用」の説明に従って、その名前を単一のテキスト コンテンツ ブロック ( `{ type: "text", text: "/context" }` など) にプロンプトとして送信 [します](#using-slash-commands)。

### ACP 経由で使用できないコマンド

対話型ターミナル インターフェイスに依存するスラッシュ コマンドは、ACP サーバーでは処理されません。 これには、 `/diff`、 `/resume`、 `/theme`、 `/settings`、 `/login`、 `/help`、 `/tasks`、 `/undo`など、ピッカー、ダイアログ、または全画面表示を開くコマンドが含まれます。 原則として、 `available_commands_update` リストにコマンドが表示されない場合、ACP では実行されません。サーバーはテキストを通常のプロンプトとして扱い、実行するのではなくモデルに転送します。

ACP クライアントには対話型ピッカーがないため、通常サブメニューを開く組み込みコマンドは、代わりにそのオプションをテキストとして返します。 サブコマンドを明示的に指定して、直接的な結果を得る (`/session info`や`/mcp list`ではなく、`/session`や`/mcp`など)。

Copilot CLIのスラッシュ コマンドの完全な一覧については、[AUTOTITLE を](/ja/copilot/reference/copilot-cli-reference/cli-command-reference#slash-commands-in-the-interactive-interface)参照してください。

## 詳細については、次を参照してください。

* [ACP の公式ドキュメント](https://agentclientprotocol.com/protocol/overview)