《Cursor文档》-ACP

概述

Cursor 命令行界面支持用于高级集成的 ACP (智能体客户端协议) 。您可以运行 agent acp,并通过 JSON-RPC 在 stdio 上连接自定义客户端。

更多信息请参阅官方 智能体客户端协议文档

ACP 旨在用于构建自定义客户端和集成。对于常规终端
工作流,请使用带 agent 的交互式命令行界面。

启动 ACP 服务器

以 ACP 模式启动 Cursor 命令行界面:

agent acp

传输与消息格式

  • 传输方式:stdio
  • 协议封装:JSON-RPC 2.0
  • 分帧:以换行符分隔的 JSON (每行一条消息)
  • 方向:
  • 客户端将请求/通知写入 stdin
  • Cursor 命令行界面将响应/通知写入 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 命令行界面将 cursor_login 作为 ACP 认证方法提供。实际上,你可以在启动前通过现有的 CLI 认证方式预先完成认证:

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

你还可以通过根 CLI 命令传入端点和 TLS 选项:

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

会话、模式与权限

会话

  • 使用 session/new 创建会话
  • 使用 session/load 恢复现有会话

模式

ACP 会话支持与命令行界面 (CLI) 相同的核心模式:

  • agent (完整工具访问权限)
  • plan (规划模式,仅可读取)
  • ask (问答模式,仅可读取)

权限

当工具需要获得批准时,Cursor 会发送 session/request_permission。客户端应返回以下选项之一:

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

如果客户端未响应权限请求,工具执行可能会被阻塞。

MCP 服务器

ACP 支持使用项目级或用户级 .cursor/mcp.json 中定义的 MCP 服务器。在项目目录中启动 agent,然后批准要使用的服务器。

ACP 模式不支持通过 Cursor 仪表盘配置的团队级 MCP 服务器。

Cursor 扩展方法

Cursor 会发送 ACP 扩展方法,以提供更丰富的客户端体验。分为两类:

  • 阻塞方法 (cursor/ask_questioncursor/create_plan):智能体会等待响应后再继续。客户端必须返回 JSON-RPC 响应。
  • 通知方法 (cursor/update_todoscursor/taskcursor/generate_image):智能体会以即发即弃的方式发送这些通知。客户端可以显示这些通知,但无需响应。
方法 类型 用途
cursor/ask_question 阻塞 向用户提出多项选择题
cursor/create_plan 阻塞 请求明确批准方案
cursor/update_todos 通知 通知客户端待办事项状态更新
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 string。
  • phases:可选。对于较大的方案,可将 todos 按命名阶段分组。

响应:

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 的 AI 智能体能够在 Cursor 桌面端应用以外的编辑器中工作。您可以为偏好的开发环境构建或使用第三方集成。

使用示例

  • JetBrains IDEs — 将 IntelliJ IDEA、WebStorm、PyCharm 或其他 JetBrains IDE 连接到 Cursor 智能体。设置说明请参阅 JetBrains 集成指南

  • Neovim (avante.nvim) — 使用 avante.nvim 通过 ACP 将 Neovim 连接到 Cursor 智能体。请参阅下方的 Neovim 设置

  • Zed — 启动 agent acp 并通过 stdio 通信,即可与 Zed 的现代编辑器集成。Zed 扩展可以实现 ACP 客户端协议,将 AI 请求路由至 Cursor。

  • 自定义编辑器 — 任何支持扩展的编辑器都可以实现 ACP 客户端。启动智能体进程,通过 stdio 发送 JSON-RPC 消息,并在编辑器 UI 中处理响应。

Neovim (avante.nvim)

avante.nvim 是一款提供 AI 编程助手的 Neovim 插件。它支持 ACP,因此你可以将其连接到 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",将请求路由至 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 扩展方法,以提供更丰富的用户体验

可参考上方的最简 Node.js 客户端,了解可运行的参考实现。

相关内容

CLI 中的 MCP

在 Cursor 命令行界面中管理和使用 MCP 服务器

MCP 概览

了解 MCP 传输方式、配置及服务器设置

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜