Skip to main content

Command Palette

Search for a command to run...

CLI

ACP

Обзор

CLI Cursor поддерживает ACP (Agent Client Protocol) для расширенной интеграции. Вы можете запустить agent acp и подключить пользовательский клиент через stdio с помощью JSON-RPC.

Подробнее — в официальной документации Agent Client Protocol.

Запуск сервера ACP

Запустите CLI Cursor в режиме ACP:

agent acp

Транспорт и формат сообщений

  • Транспорт: stdio
  • Обёртка протокола: JSON-RPC 2.0
  • Кадрирование: JSON с разделением переводами строк (одно сообщение на строку)
  • Направление:
    • Клиент записывает запросы/уведомления в stdin
    • CLI Cursor записывает ответы/уведомления в stdout
    • Логи могут записываться в stderr

Последовательность запросов

Типичный сценарий ACP-сессии:

  1. initialize
  2. authenticate с methodId: "cursor_login"
  3. session/new (или session/load)
  4. session/prompt
  5. Обрабатывайте уведомления session/update, пока модель передаёт выходные данные
  6. Обрабатывайте session/request_permission, возвращая решение
  7. При необходимости отправьте session/cancel

Аутентификация

CLI Cursor указывает cursor_login в качестве метода аутентификации ACP. Однако перед запуском можно пройти аутентификацию одним из существующих способов CLI:

  • agent login
  • --api-key (или CURSOR_API_KEY)
  • --auth-token (или CURSOR_AUTH_TOKEN)

Также можно передать параметры endpoint и TLS из корневой команды CLI:

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

Сессии, режимы и права доступа

Сессии

  • Создайте сессию с помощью session/new
  • Продолжите существующий диалог с помощью session/load

Режимы

Сессии ACP поддерживают те же основные режимы, что и CLI:

  • agent (полный доступ к инструментам)
  • plan (планирование, режим только для чтения)
  • ask (вопросы и ответы, режим только для чтения)

Права доступа

Когда для использования инструментов требуется одобрение, Cursor отправляет session/request_permission. Клиент должен вернуть один из следующих вариантов:

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

Если клиент не отвечает на запросы прав доступа, выполнение инструмента может быть заблокировано.

MCP‑серверы

ACP поддерживает MCP‑серверы, определённые в файле .cursor/mcp.json на уровне проекта или пользователя. Запустите agent из каталога проекта и подтвердите серверы, которые хотите использовать.

Методы расширения Cursor

Cursor отправляет методы расширения ACP, чтобы улучшить UX клиента. Они бывают двух типов:

  • Блокирующие методы (cursor/ask_question, cursor/create_plan): Agent ждёт ответа, прежде чем продолжить работу. Ваш клиент должен отправить JSON-RPC-ответ.
  • Методы уведомлений (cursor/update_todos, cursor/task, cursor/generate_image): Agent отправляет их как уведомления fire-and-forget. Ваш клиент может отображать их, но отвечать не обязан.
МетодТипНазначение
cursor/ask_questionБлокирующийЗадавать пользователям вопросы с вариантами ответа
cursor/create_planБлокирующийЗапрашивать явное одобрение тарифа
cursor/update_todosУведомлениеУведомлять клиента об изменениях состояния задач
cursor/taskУведомлениеУведомлять клиента о завершении задачи субагент
cursor/generate_imageУведомлениеУведомлять клиента о выходных данных сгенерированного изображения

cursor/ask_question

Предлагает пользователю вопросы с несколькими вариантами ответа. Agent ожидает ответа клиента.

Запрос:

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

Запрашивает у пользователя одобрение тарифа. Agent ожидает, пока клиент не примет или не отклонит тариф.

Запрос:

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: Необязательное разделение задач на именованные этапы для больших тарифов.

Ответ:

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

Обновляет список задач клиента. Отправляется как уведомление и не требует ответа.

Запрос:

interface CursorUpdateTodosRequest {  toolCallId: string;  todos: Array<{    id: string;    content: string;    status: "pending" | "in_progress" | "completed" | "cancelled";  }>;  merge: boolean;}
  • merge: Если true, добавить эти задачи к существующему списку. Если 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 работать с редакторами за пределами десктопного приложения Cursor. Создавайте или используйте сторонние интеграции для предпочитаемой инфраструктуры разработки.

Примеры использования

  • IDE от JetBrains — Подключите IntelliJ IDEA, WebStorm, PyCharm или другие IDE от JetBrains к Agent Cursor. Инструкции по настройке см. в руководстве по интеграции с JetBrains.

  • Neovim (avante.nvim) — Используйте avante.nvim, чтобы подключить Neovim к Agent Cursor через ACP. См. раздел Настройка Neovim ниже.

  • Zed — Интегрируйте Zed с Agent Cursor: запустите agent acp и обменивайтесь данными через stdio. Расширения Zed могут реализовывать клиентский протокол ACP для направления запросов к ИИ в Cursor.

  • Пользовательские редакторы — Любой редактор с поддержкой расширений может реализовать ACP-клиент. Запустите процесс Agent, отправляйте сообщения JSON-RPC через stdio и обрабатывайте ответы в интерфейсе редактора.

Neovim (avante.nvim)

avante.nvim — плагин для Neovim, предоставляющий ИИ-помощника для программирования. Он поддерживает ACP, поэтому вы можете подключить его к Agent Cursor для агентного программирования прямо в Neovim.

Добавьте следующее в конфигурацию плагина 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", чтобы направлять запросы через Agent Cursor'а.
  • mode: Задайте значение "agentic" для полного доступа к инструментам (редактирования файлов, терминальных команд). Используйте "normal" для режима только чата.
  • command: Указывает на исполняемый файл agent. Путь установки по умолчанию — ~/.local/bin/agent. Измените его, если установили его в другом месте.
  • auth_method: Использует "cursor_login". Сначала выполните agent login в терминале, чтобы пройти аутентификацию.

Создание интеграции

  1. Запустите agent acp как дочерний процесс
  2. Обменивайтесь данными через stdin/stdout с помощью JSON-RPC
  3. Обрабатывайте уведомления session/update, чтобы отображать потоковые ответы
  4. Отвечайте на session/request_permission, когда инструментам требуется одобрение
  5. При необходимости реализуйте методы расширений Cursor для более удобного UX

Рабочий пример реализации приведён выше: минимальный клиент Node.js.

Связанные материалы