Pular para o conteúdo principal

Agent Client Protocol (ACP) com o Cursor

Agent Client Protocol with Cursor

O Agent Client Protocol (ACP) é um padrão aberto que permite a um cliente de editor e a um agente de codificação conversarem entre si através de uma interface compartilhada baseada em JSON-RPC. Em vez de cada editor construir sua própria ponte para cada agente, o cliente e o agente falam ambos ACP, e o pareamento se torna intercambiável. O Cursor pode atuar como o lado agente dessa conversa através do cursor-agent, o que significa que qualquer cliente compatível com ACP pode conduzir o agente do Cursor. Este guia explica o protocolo, o ciclo de vida da sessão, como expor o Cursor via ACP, o fluxo de mensagens na prática, como construir um cliente próprio e onde estão as lacunas atuais.

O Que É o Agent Client Protocol​

ACP é um padrão aberto que define como um cliente de editor conversa com um agente de codificação. O protocolo foi popularizado pela Zed, que o usa para permitir que seu editor conduza diferentes agentes, mas ele é deliberadamente agnóstico em relação a editor e agente.

As escolhas centrais de design são simples:

  • O transporte é JSON-RPC sobre stdio. O cliente gera o agente como um subprocesso e troca mensagens JSON-RPC delimitadas por nova linha em stdin e stdout.
  • Qualquer um dos lados pode enviar requisições e notificações. O cliente pede ao agente para iniciar uma sessão e enviar prompts; o agente pede ao cliente permissão para executar ferramentas e transmite o progresso de volta.
  • As sessões são explícitas. O trabalho acontece dentro de uma sessão criada com newSession, que carrega um diretório de trabalho e opções.

Como o transporte é stdio simples e as mensagens são JSON simples, o ACP funciona em qualquer lugar onde um processo pode ser gerado: editores locais, ferramentas de terminal e executores de CI sem interface.

ACP não é MCP

O MCP conecta um agente a ferramentas e fontes de dados externas. O ACP conecta um cliente de editor a um agente. Eles resolvem problemas diferentes e são comumente usados juntos: um agente ACP pode ele mesmo ser um cliente MCP.

Arquitetura do ACP​

A arquitetura tem três partes: o cliente, o agente e o transporte entre eles. O cliente é dono da UI e das permissões; o agente é dono do modelo e das ferramentas.

CamadaPapelExemplos
ClienteRenderiza a conversa, coleta a entrada do usuário, responde a pedidos de permissãoZed, um editor personalizado, um script sem interface
AgenteRoda o modelo, executa ferramentas, transmite atualizaçõescursor-agent acp, outros agentes ACP
TransporteMove mensagens JSON-RPC em ambas as direçõesJSON delimitado por nova linha sobre stdio

O ciclo de vida da sessão é uma sequência fixa. Assim que você o entende, o fluxo de mensagens se lê como um roteiro.

initialize -> client and agent agree on protocol version and capabilities
newSession -> client asks the agent to create a session with a cwd and options
prompt -> client sends user input into the session
session/update -> agent streams progress, tool calls, and messages back (notification)
permission request-> agent asks the client to approve a tool action
cancel -> client aborts the current turn

O agente nunca age sobre um recurso protegido sem antes perguntar ao cliente. Essa ida e volta de permissão é o que mantém uma UI no controle de um agente autônomo.

Por Que o ACP Importa​

O ACP importa porque desacopla o editor do agente. O valor aparece em três lugares.

Portabilidade de Editor​

Se o Cursor e outro cliente falam ambos ACP, você pode usar o mesmo agente em qualquer um dos dois sem uma integração sob medida. Sua configuração de agente, escolha de modelo e regras viajam com o agente, não com o editor.

Reutilize o Agente do Cursor em Qualquer Cliente Compatível​

Em vez de reimplementar o comportamento do agente em cada editor, você pode apontar qualquer cliente ACP para o cursor-agent e obter o raciocínio, o uso de ferramentas e a seleção de modelos do Cursor dentro da UI desse cliente. Isso é especialmente útil para equipes padronizadas em um editor que não é o Cursor, mas que querem o comportamento de agente do Cursor.

Automação Sem Interface​

Como o transporte é stdio, você pode conduzir o agente a partir de um script ou job de CI sem nenhum editor. Isso torna possíveis execuções de agente repetíveis e roteirizadas em pipelines.

# A headless run is just a client that writes JSON-RPC to the agent's stdin
cat initialize.json newSession.json prompt.json | cursor-agent acp
Execuções sem interface ainda precisam de permissões

Quando você conduz o agente a partir de um script, não há um humano para clicar em "aprovar" em uma chamada de ferramenta. Decida seu modo de permissão de antemão e nunca adote auto-run como padrão em um ambiente com credenciais sensíveis.

Expondo o Cursor via ACP com cursor-agent​

O cursor-agent é o CLI que pode atuar como o lado agente ACP da conexão. Instale-o da mesma forma que você instala o CLI do Cursor.

# Install via npm
npm install -g cursor-agent

# Or install via the Cursor CLI script
curl https://cursor.com/install -fsS | bash

# Confirm it is on your PATH
cursor-agent --version

Executando em Modo ACP​

O ponto de entrada do ACP é um subcomando. Quando você o executa, o processo fala JSON-RPC em stdio e aguarda um cliente se conectar.

# Start the agent as an ACP server, talking JSON-RPC over stdio
cursor-agent acp

# Useful flags
cursor-agent acp --cwd /path/to/project # set the working directory
cursor-agent acp --model claude-sonnet-4-5 # pin a model for the session
cursor-agent acp --verbose # log messages for debugging

Autenticação​

O agente precisa de credenciais antes de poder servir prompts. Faça login uma vez e as credenciais são armazenadas localmente.

# Interactive login, opens a browser flow
cursor-agent login

# Check current auth status
cursor-agent status

# Log out and clear stored credentials
cursor-agent logout

Se o agente iniciar mas todos os prompts falharem, a causa é quase sempre autenticação ausente ou expirada. Execute cursor-agent status antes de depurar qualquer outra coisa.

Configurando uma Sessão​

Uma sessão é criada com um diretório de trabalho e opções que governam como o agente se comporta nessa conversa.

Seleção de Modelo​

O modelo pode ser fixado no lançamento ou escolhido por sessão. Passá-lo por sessão permite que um único processo de agente sirva diferentes clientes com preferências de modelo diferentes.

{
"method": "session/new",
"params": {
"cwd": "/home/dev/project",
"model": "claude-sonnet-4-5",
"mcpServers": []
}
}

Relatório de Uso da Janela de Contexto​

Alguns clientes exibem quão cheia está a janela de contexto. O agente relata o uso de tokens como parte das atualizações de sessão onde o cliente suporta isso.

{
"method": "session/update",
"params": {
"sessionId": "sess_01HXYZ",
"update": {
"type": "usage",
"inputTokens": 12480,
"outputTokens": 2310,
"contextLimit": 200000
}
}
}

Modos de Permissão e Diretório de Trabalho​

Os modos de permissão decidem se o agente pergunta antes de executar uma ferramenta. Em um cliente interativo, o padrão é perguntar. Na automação sem interface, você escolhe deliberadamente.

  • Perguntar por ferramenta: o agente envia um pedido de permissão e espera. O mais seguro, melhor para editores interativos.
  • Auto-run: o agente executa dentro do diretório de trabalho sem perguntar. Rápido, e apropriado apenas em um sandbox.
  • Somente leitura: o agente pode ler e buscar, mas nunca escrever. Bom para sessões somente de revisão.

O cwd no newSession delimita o que o agente trata como o projeto. Arquivos fora dele não devem ser tocados.

Exemplo de Fluxo de Mensagens JSON-RPC​

O seguinte é uma conversa mínima, mas completa. Cada mensagem é uma linha de JSON no fio.

Initialize​

O cliente abre com initialize, e o agente responde com suas capacidades e versão do protocolo.

{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": 1,
"clientCapabilities": {
"fs": { "readTextFile": true, "writeTextFile": true },
"terminal": true
}
}
}
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": 1,
"agentCapabilities": {
"promptCapabilities": { "image": false },
"loadSession": true
}
}
}

Nova Sessão​

Assim que as capacidades são acordadas, o cliente cria uma sessão e recebe de volta um ID.

{
"jsonrpc": "2.0",
"id": 2,
"method": "session/new",
"params": { "cwd": "/home/dev/project", "mcpServers": [] }
}
{
"jsonrpc": "2.0",
"id": 2,
"result": { "sessionId": "sess_01HXYZ" }
}

Prompt​

O cliente envia o turno do usuário. Observe que esta é uma requisição; o agente a reconhece, mas o conteúdo real chega como notificações em streaming.

{
"jsonrpc": "2.0",
"id": 3,
"method": "session/prompt",
"params": {
"sessionId": "sess_01HXYZ",
"content": [{ "type": "text", "text": "Add input validation to the signup route." }]
}
}

Atualizações em Streaming​

Conforme o agente trabalha, ele emite notificações session/update sem um ID, porque são unidirecionais.

{
"jsonrpc": "2.0",
"method": "session/update",
"params": {
"sessionId": "sess_01HXYZ",
"update": { "type": "agent_message_chunk", "text": "Reading src/routes/signup.ts" }
}
}

Pedido de Permissão​

Antes de uma ação protegida, o agente pergunta ao cliente. O cliente responde através do mecanismo de requisição JSON-RPC padrão.

{
"jsonrpc": "2.0",
"id": "perm-1",
"method": "session/request_permission",
"params": {
"sessionId": "sess_01HXYZ",
"toolCall": {
"title": "Write file",
"path": "src/routes/signup.ts"
}
}
}
{
"jsonrpc": "2.0",
"id": "perm-1",
"result": { "outcome": { "outcome": "selected", "optionId": "allow" } }
}

Cancel​

Para abortar um turno, o cliente envia session/cancel. O agente interrompe o trabalho atual e finaliza a requisição de prompt com um motivo de parada de cancelamento.

{
"jsonrpc": "2.0",
"method": "session/cancel",
"params": { "sessionId": "sess_01HXYZ" }
}

Construindo Seu Próprio Cliente ACP​

Um cliente mínimo gera o agente, escreve linhas JSON-RPC em stdin e analisa JSON delimitado por nova linha de stdout. O trecho abaixo mostra a forma em TypeScript.

import { spawn } from "node:child_process";
import { createInterface } from "node:readline";

const agent = spawn("cursor-agent", ["acp", "--cwd", process.cwd()], {
stdio: ["pipe", "pipe", "inherit"],
});

let nextId = 1;

function send(method: string, params: unknown): void {
const message = { jsonrpc: "2.0", id: nextId++, method, params };
agent.stdin.write(JSON.stringify(message) + "\n");
}

// Read newline-delimited JSON-RPC from the agent
const reader = createInterface({ input: agent.stdout });
reader.on("line", (line) => {
if (!line.trim()) return;
const msg = JSON.parse(line);

// Notifications have no id
if (!("id" in msg)) {
if (msg.method === "session/update") {
console.log("update:", JSON.stringify(msg.params.update));
}
return;
}

// A request from the agent needs a reply
if (msg.method === "session/request_permission") {
const reply = {
jsonrpc: "2.0",
id: msg.id,
result: { outcome: { outcome: "selected", optionId: "allow" } },
};
agent.stdin.write(JSON.stringify(reply) + "\n");
return;
}

console.log("response:", JSON.stringify(msg.result ?? msg.error));
});

// Kick off the session
send("initialize", { protocolVersion: 1, clientCapabilities: {} });
send("session/new", { cwd: process.cwd(), mcpServers: [] });

As regras-chave a lembrar: toda requisição tem um id e espera uma resposta correspondente, notificações nunca têm um id, e o agente também pode enviar requisições para você, então seu leitor deve lidar com ambas as direções.

Registre o fio bruto

Quando uma integração de cliente se comporta mal, registre cada linha em ambas as direções antes de tocar na lógica. Bugs de ACP geralmente são um id ausente, uma nova linha perdida, ou uma resposta que nunca foi enviada, e o fio bruto torna os três óbvios.

Limitações e Lacunas Atuais​

O ACP é jovem, e nem toda capacidade do Cursor é exposta através dele. Saiba o que você está abrindo mão antes de construir sobre ele.

Sem Personalização do System Prompt​

As opções de sessão do ACP atualmente não permitem que um cliente substitua ou estenda o system prompt do agente como .cursor/rules faz dentro do IDE. Regras configuradas no projeto ainda são aplicadas pelo agente, mas o cliente não pode injetar as suas próprias.

Relatório Incompleto de Janela de Contexto​

O relatório de uso existe, mas não é garantido que seja completo ou em tempo real. Um cliente que quer um medidor exato de contexto não deve confiar apenas nas atualizações de uso do ACP.

Diferenças de Paridade de Recursos vs o IDE​

Vários recursos do IDE estão indisponíveis ou reduzidos via ACP:

  • Sem revisão visual de diff das edições propostas dentro do cliente, a menos que o cliente a implemente.
  • Agentes em segundo plano e agentes na nuvem não são conduzidos por este caminho.
  • Alguns comportamentos de ferramentas e de MCP diferem do modo Agent do IDE.
  • A Tab completion é um sistema separado e não faz parte do ACP de forma alguma.

Solução de Problemas​

Agente Não Encontrado​

Se o cliente gera cursor-agent e recebe ENOENT, o binário não está no PATH do processo que faz a geração. Use um caminho absoluto na chamada de spawn, e lembre que um cliente com GUI pode herdar um PATH diferente do seu terminal.

# Find the absolute path and use it in the client config
which cursor-agent

Erros de Autenticação​

Todo prompt falhando com um erro de autenticação significa que o agente não tem credenciais válidas. Execute cursor-agent status, depois cursor-agent login, e verifique se o cliente não está rodando sob um usuário ou diretório home diferente daquele com o qual você fez login.

Sem Atualizações em Streaming​

Se a requisição de prompt retorna, mas as atualizações nunca chegam, o cliente provavelmente não está analisando as notificações corretamente. Notificações não têm id, então um leitor que só lida com respostas as descarta. Confirme que seu leitor de linhas emite em nova linha e que seu analisador lida com mensagens sem um id.

O Cliente Nunca Recebe Pedidos de Permissão​

Se o agente executa ferramentas sem perguntar, a sessão foi criada com um modo de permissão de auto-run, ou o cliente nunca anunciou a capacidade de lidar com pedidos de permissão durante o initialize. Verifique tanto as opções de sessão quanto as capacidades que você enviou.

SintomaCausaCorreção
ENOENT no spawnBinário do agente não está no PATHUse um caminho absoluto na chamada de spawn
Todo prompt falhaAutenticação ausente ou expiradaExecute cursor-agent status depois cursor-agent login
Sem mensagens session/updateO leitor só lida com respostas com um idLide com notificações sem um id
Sem pedidos de permissãoModo auto-run ou capacidade de cliente ausenteDefina perguntar-por-ferramenta e anuncie a capacidade
Prompt trava para sempreResposta a uma requisição nunca enviadaResponda com id correspondente a toda requisição do agente
Erros de análise de respostaMensagens concatenadas sem novas linhasEscreva e leia exatamente um objeto JSON por linha

O ACP transforma a relação editor-agente em um contrato, e esse contrato é o que torna o agente do Cursor utilizável de qualquer lugar que fale o protocolo. Comece com o fluxo de mensagens acima, registre o fio, e a integração se torna uma pequena quantidade de encanamento em vez de uma reescrita.