ACP
Обзор
CLI Cursor поддерживает ACP (Agent Client Protocol) для расширенной интеграции. Вы можете запустить agent acp и подключить пользовательский клиент через stdio с помощью JSON-RPC.
Подробнее — в официальной документации Agent Client Protocol.
ACP предназначен для создания пользовательских клиентов и интеграций. Для обычной работы
в терминале используйте интерактивный CLI с agent.
Запуск сервера ACP
Запустите CLI Cursor в режиме ACP:
agent acpТранспорт и формат сообщений
- Транспорт:
stdio - Обёртка протокола: JSON-RPC 2.0
- Кадрирование: JSON с разделением переводами строк (одно сообщение на строку)
- Направление:
- Клиент записывает запросы/уведомления в
stdin - CLI Cursor записывает ответы/уведомления в
stdout - Логи могут записываться в
stderr
- Клиент записывает запросы/уведомления в
Последовательность запросов
Типичный сценарий ACP-сессии:
initializeauthenticateсmethodId: "cursor_login"session/new(илиsession/load)session/prompt- Обрабатывайте уведомления
session/update, пока модель передаёт выходные данные - Обрабатывайте
session/request_permission, возвращая решение - При необходимости отправьте
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-onceallow-alwaysreject-once
Если клиент не отвечает на запросы прав доступа, выполнение инструмента может быть заблокировано.
MCP‑серверы
ACP поддерживает MCP‑серверы, определённые в файле .cursor/mcp.json на уровне проекта или пользователя. Запустите agent из каталога проекта и подтвердите серверы, которые хотите использовать.
MCP‑серверы уровня команды, настроенные через дашборд Cursor, не поддерживаются в режиме ACP.
Методы расширения 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в терминале, чтобы пройти аутентификацию.
Создание интеграции
- Запустите
agent acpкак дочерний процесс - Обменивайтесь данными через stdin/stdout с помощью JSON-RPC
- Обрабатывайте уведомления
session/update, чтобы отображать потоковые ответы - Отвечайте на
session/request_permission, когда инструментам требуется одобрение - При необходимости реализуйте методы расширений Cursor для более удобного UX
Рабочий пример реализации приведён выше: минимальный клиент Node.js.