Skip to main content

Command Palette

Search for a command to run...

CLI

ACP

概要

Cursor CLI は、高度な連携向けに **ACP (Agent Client Protocol) **をサポートしています。agent acp を実行すると、JSON-RPC を使用して stdio 経由でカスタムクライアントを接続できます。

詳細は、公式の Agent Client Protocol ドキュメントをご覧ください。

ACP サーバーを起動する

ACP モードで Cursor CLI を起動します。

agent acp

トランスポートとメッセージ形式

  • トランスポート: stdio
  • プロトコルエンベロープ: JSON-RPC 2.0
  • フレーミング: 改行区切り JSON (1行につき1メッセージ)
  • 方向:
    • クライアントはリクエスト/通知をstdinに書き込む
    • Cursor CLIはレスポンス/通知をstdoutに書き込む
    • ログはstderrに書き込まれる場合がある

リクエストフロー

一般的な ACP セッションのフロー:

  1. initialize
  2. methodId: "cursor_login" を指定して authenticate
  3. session/new (または session/load)
  4. session/prompt
  5. モデルが出力をストリーミングしている間に、session/update 通知を処理
  6. 判断を返して session/request_permission を処理
  7. 必要に応じて session/cancel を送信

認証

Cursor CLI では、ACP の認証方法として cursor_login が通知されます。実際には、既存の CLI 認証方法を使って、起動前にあらかじめ認証できます。

  • agent login
  • --api-key (または CURSOR_API_KEY)
  • --auth-token (または CURSOR_AUTH_TOKEN)

ルート CLI コマンドからエンドポイントと TLS のオプションを指定することもできます。

agent --api-key "$CURSOR_API_KEY" acpagent -e https://api2.cursor.sh acpagent -k acp

セッション、モード、権限

セッション

  • session/newでセッションを作成
  • session/loadで既存の会話を再開

モード

ACP セッションでは、CLI と同じ基本モードを利用できます。

  • agent (すべてのツールを使用可能)
  • plan (プランニング、参照専用)
  • ask (Q&A、参照専用)

権限

ツールの実行に承認が必要な場合、Cursor は session/request_permission を送信します。クライアントは次のいずれかを返す必要があります。

  • allow-once
  • allow-always
  • reject-once

クライアントが権限リクエストに応答しない場合、ツールの実行がブロックされる可能性があります。

MCP サーバー

ACP は、プロジェクトレベルまたはユーザーレベルの .cursor/mcp.json で定義された MCP サーバー をサポートします。プロジェクトディレクトリから agent を起動し、使用するサーバーを承認してください。

Cursor 拡張メソッド

Cursor は、より充実したクライアント UX を実現するために ACP 拡張メソッドを送信します。メソッドには 2 種類あります。

  • ブロッキングメソッド (cursor/ask_questioncursor/create_plan) :エージェントはレスポンスを受け取るまで待機します。クライアントは JSON-RPC レスポンスを返す必要があります。
  • 通知メソッド (cursor/update_todoscursor/taskcursor/generate_image) :エージェントはこれらを fire-and-forget 通知として送信します。クライアントで表示できますが、応答は不要です。
メソッド種類用途
cursor/ask_questionブロッキングユーザーに選択式の質問をする
cursor/create_planブロッキングプランの明示的な承認をリクエストする
cursor/update_todos通知todo の状態更新をクライアントに通知する
cursor/task通知サブエージェントのタスク完了をクライアントに通知する
cursor/generate_image通知生成画像の出力をクライアントに通知する

cursor/ask_question

ユーザーに選択肢付きの質問を提示します。クライアントから応答があるまで、エージェントは待機します。

リクエスト:

interface CursorAskQuestionRequest {  toolCallId: string;  title?: string;  questions: Array<{    id: string;    prompt: string;    options: Array<{ id: string; label: string }>;    allowMultiple?: boolean;  }>;}

レスポンス:

interface CursorAskQuestionResponse {  outcome:    | {        outcome: "answered";        answers: Array<{          questionId: string;          selectedOptionIds: string[];        }>;      }    | { outcome: "skipped"; reason?: string }    | { outcome: "cancelled" };}

リクエスト例:

{  "toolCallId": "call_123",  "title": "Need input",  "questions": [    {      "id": "q1",      "prompt": "Which mode should I use?",      "options": [        { "id": "agent", "label": "Agent" },        { "id": "plan", "label": "Plan" }      ],      "allowMultiple": false    }  ]}

cursor/create_plan

ユーザーにプランの承認を求めます。クライアントがプランを承認または拒否するまで、エージェントは待機します。

リクエスト:

interface CursorCreatePlanRequest {  toolCallId: string;  name?: string;  overview?: string;  plan: string;  todos: Array<{    id: string;    content: string;    status: "pending" | "in_progress" | "completed" | "cancelled";  }>;  isProject?: boolean;  phases?: Array<{    name: string;    todos: Array<{      id: string;      content: string;      status: "pending" | "in_progress" | "completed" | "cancelled";    }>;  }>;}
  • plan: 完全なプランを説明する markdown 文字列。
  • phases: 大規模なプラン向けに todo を名前付きフェーズに任意でグループ化します。

レスポンス:

interface CursorCreatePlanResponse {  outcome:    | { outcome: "accepted"; planUri?: string }    | { outcome: "rejected"; reason?: string }    | { outcome: "cancelled" };}

リクエストの例:

{  "toolCallId": "call_124",  "name": "Refactor tabs layout",  "overview": "Tighten layout behavior and preserve existing UX.",  "plan": "1. Inspect current tab sizing logic.\n2. Update layout calculations.\n3. Verify editor behavior.",  "todos": [    { "id": "todo-1", "content": "Inspect current tab sizing logic", "status": "completed" },    { "id": "todo-2", "content": "Update layout calculations", "status": "in_progress" },    { "id": "todo-3", "content": "Verify editor behavior", "status": "pending" }  ],  "isProject": false}

cursor/update_todos

クライアントのtodoリストを更新します。通知として送信されるため、レスポンスは不要です。

リクエスト:

interface CursorUpdateTodosRequest {  toolCallId: string;  todos: Array<{    id: string;    content: string;    status: "pending" | "in_progress" | "completed" | "cancelled";  }>;  merge: boolean;}
  • merge: trueの場合、これらのtodoを既存のリストに統合します。falseの場合、リスト全体を置き換えます。

レスポンス:

interface CursorUpdateTodosResponse {  outcome:    | {        outcome: "accepted";        todos: Array<{          id: string;          content: string;          status: "pending" | "in_progress" | "completed" | "cancelled";        }>;      }    | { outcome: "rejected"; reason?: string }    | { outcome: "cancelled" };}

リクエスト例:

{  "toolCallId": "call_125",  "todos": [    { "id": "1", "content": "Set up project structure", "status": "completed" },    { "id": "2", "content": "Add authentication", "status": "in_progress" },    { "id": "3", "content": "Write unit tests", "status": "pending" }  ],  "merge": true}

cursor/task

サブエージェントのタスクをクライアントに通知します。通知として送信されるため、レスポンスは不要です。

リクエスト:

interface CursorTaskRequest {  toolCallId: string;  description: string;  prompt: string;  subagentType:    | "unspecified"    | "computer_use"    | "explore"    | "video_review"    | "browser_use"    | "shell"    | "vm_setup_helper"    | { custom: string };  model?: string;  agentId?: string;  durationMs?: number;}
  • subagentType: 実行するサブエージェントの種類。カスタムサブエージェントタイプには { custom: "your_type" } を使用します。
  • agentId: 以前に作成したサブエージェントを再開するには、これを設定します。
  • durationMs: タスクの実行時間。レスポンスに含まれます。

レスポンス:

interface CursorTaskResponse {  outcome:    | { outcome: "completed"; agentId?: string; durationMs?: number }    | { outcome: "rejected"; reason?: string }    | { outcome: "cancelled" };}

リクエスト例:

{  "toolCallId": "call_126",  "description": "Explore codebase",  "prompt": "Find where authentication is handled and report the file paths.",  "subagentType": "explore"}

cursor/generate_image

生成された画像をクライアントに通知します。通知として送信されるため、レスポンスは不要です。

リクエスト:

interface CursorGenerateImageRequest {  toolCallId: string;  description: string;  filePath?: string;  referenceImagePaths?: string[];}
  • filePath: 生成画像の推奨ファイルパス。
  • referenceImagePaths: 入力として使用するリファレンス画像のパス。

レスポンス:

interface CursorGenerateImageResponse {  outcome:    | { outcome: "generated"; filePath: string; imageData?: string }    | { outcome: "rejected"; reason?: string }    | { outcome: "cancelled" };}

リクエスト例:

{  "toolCallId": "call_127",  "description": "Minimal flat app icon for a note-taking app",  "filePath": "/tmp/icon.png",  "referenceImagePaths": ["/tmp/reference.png"]}

最小限の Node.js クライアント

この例では、カスタム ACP クライアントの最小限の制御フローを示します。

import { spawn } from "node:child_process";import readline from "node:readline";const agent = spawn("agent", ["acp"], { stdio: ["pipe", "pipe", "inherit"] });let nextId = 1;const pending = new Map();function send(method, params) {  const id = nextId++;  agent.stdin.write(JSON.stringify({ jsonrpc: "2.0", id, method, params }) + "\n");  return new Promise((resolve, reject) => pending.set(id, { resolve, reject }));}function respond(id, result) {  agent.stdin.write(JSON.stringify({ jsonrpc: "2.0", id, result }) + "\n");}const rl = readline.createInterface({ input: agent.stdout });rl.on("line", line => {  const msg = JSON.parse(line);  if (msg.id && (msg.result || msg.error)) {    const waiter = pending.get(msg.id);    if (!waiter) return;    pending.delete(msg.id);    msg.error ? waiter.reject(msg.error) : waiter.resolve(msg.result);    return;  }  if (msg.method === "session/update") {    const update = msg.params?.update;    if (update?.sessionUpdate === "agent_message_chunk" && update.content?.text) {      process.stdout.write(update.content.text);    }    return;  }  if (msg.method === "session/request_permission") {    respond(msg.id, { outcome: { outcome: "selected", optionId: "allow-once" } });  }});const init = async () => {  await send("initialize", {    protocolVersion: 1,    clientCapabilities: { fs: { readTextFile: false, writeTextFile: false }, terminal: false },    clientInfo: { name: "acp-minimal-client", version: "0.1.0" }  });  await send("authenticate", { methodId: "cursor_login" });  const { sessionId } = await send("session/new", { cwd: process.cwd(), mcpServers: [] });  const result = await send("session/prompt", {    sessionId,    prompt: [{ type: "text", text: "Say hello in one sentence." }]  });  console.log(`\n\n[stopReason=${result.stopReason}]`);};init().finally(() => {  agent.stdin.end();  agent.kill();});

IDE 連携

ACP を使用すると、Cursor の AI エージェントを Cursor デスクトップアプリ以外のエディターでも利用できます。好みの開発環境向けにサードパーティ連携を構築または利用できます。

使用例

  • JetBrains IDEs — IntelliJ IDEA、WebStorm、PyCharmなどのJetBrains IDEをCursorのエージェントに接続できます。セットアップ手順はJetBrains連携ガイドを参照してください。

  • Neovim (avante.nvim)avante.nvimを使用して、ACP経由でNeovimをCursorのエージェントに接続できます。下記のNeovimのセットアップを参照してください。

  • Zedagent acpを起動してstdio経由で通信することで、Zedのモダンなエディターと連携できます。Zedの拡張機能では、ACPクライアントプロトコルを実装してAIリクエストをCursorにルーティングできます。

  • カスタムエディター — 拡張機能をサポートする任意のエディターでACPクライアントを実装できます。エージェントプロセスを起動し、stdio経由でJSON-RPCメッセージを送信して、エディターのUIでレスポンスを処理します。

Neovim (avante.nvim)

avante.nvim は、AI 搭載のコーディングアシスタントを提供する Neovim プラグインです。ACP をサポートしているため、Neovim 内でエージェント型コーディングを行うために Cursor のエージェントに接続できます。

以下を lazy.nvim のプラグイン設定 (例:~/.config/nvim/lua/plugins/avante.lua) に追加します。

return {  {    "yetone/avante.nvim",    event = "VeryLazy",    version = false,    build = "make",    opts = {      provider = "cursor",      mode = "agentic",      acp_providers = {        cursor = {          command = os.getenv("HOME") .. "/.local/bin/agent",          args = { "acp" },          auth_method = "cursor_login",          env = {            HOME = os.getenv("HOME"),            PATH = os.getenv("PATH"),          },        },      },    },    dependencies = {      "nvim-lua/plenary.nvim",      "MunifTanjim/nui.nvim",      "nvim-tree/nvim-web-devicons",      {        "MeanderingProgrammer/render-markdown.nvim",        opts = {          file_types = { "markdown", "Avante" },        },        ft = { "markdown", "Avante" },      },    },  },}

主な設定:

  • provider: リクエストを Cursor のエージェント経由で送信するには "cursor" に設定します。
  • mode: ファイル編集やターミナルコマンドを含むすべてのツールを使用するには "agentic" に設定します。チャットのみを使用する場合は "normal" を指定します。
  • command: agent バイナリへのパスを指定します。デフォルトのインストールパスは ~/.local/bin/agent です。別の場所にインストールした場合は変更してください。
  • auth_method: "cursor_login" を使用します。認証するには、まずターミナルで agent login を実行してください。

連携を作る

  1. agent acp を子プロセスとして起動する
  2. JSON-RPC を使用して stdin/stdout 経由で通信する
  3. session/update 通知を処理してストリーミングレスポンスを表示する
  4. ツールに承認が必要な場合は session/request_permission に応答する
  5. より充実した UX のために、必要に応じて Cursor 拡張メソッドを実装する

動作するリファレンス実装については、上記の最小限の Node.js クライアントを参照してください。

関連