Zum Hauptinhalt springen

Agent Client Protocol (ACP) mit Cursor

Agent Client Protocol with Cursor

Das Agent Client Protocol (ACP) ist ein offener Standard, der einem Editor-Client und einem Coding-Agenten erlaubt, über eine gemeinsame, auf JSON-RPC basierende Schnittstelle miteinander zu sprechen. Statt dass jeder Editor seine eigene Brücke zu jedem Agenten baut, sprechen Client und Agent beide ACP, und die Paarung wird austauschbar. Cursor kann über cursor-agent die Agent-Seite dieser Konversation übernehmen, was bedeutet, dass jeder ACP-konforme Client Cursors Agenten steuern kann. Dieser Leitfaden erklärt das Protokoll, den Sitzungslebenszyklus, wie Sie Cursor über ACP bereitstellen, den Nachrichtenfluss in der Praxis, wie Sie einen eigenen Client bauen und wo die aktuellen Lücken liegen.

Was ist das Agent Client Protocol​

ACP ist ein offener Standard, der definiert, wie ein Editor-Client mit einem Coding-Agenten spricht. Das Protokoll wurde von Zed populär gemacht, das es nutzt, um verschiedene Agenten aus seinem Editor heraus zu steuern, aber es ist bewusst editor-agnostisch und agent-agnostisch.

Die zentralen Designentscheidungen sind einfach:

  • Der Transport ist JSON-RPC über stdio. Der Client startet den Agenten als Subprozess und tauscht zeilengetrennte JSON-RPC-Nachrichten auf stdin und stdout aus.
  • Beide Seiten können Anfragen und Benachrichtigungen senden. Der Client bittet den Agenten, eine Sitzung zu starten und Prompts zu senden; der Agent bittet den Client um Erlaubnis, Werkzeuge auszuführen, und streamt Fortschritt zurück.
  • Sitzungen sind explizit. Arbeit findet innerhalb einer mit newSession erstellten Sitzung statt, die ein Arbeitsverzeichnis und Optionen trägt.

Weil der Transport einfaches stdio und die Nachrichten einfaches JSON sind, funktioniert ACP überall dort, wo ein Prozess gestartet werden kann: lokale Editoren, Terminal-Werkzeuge und headless CI-Runner.

ACP ist nicht MCP

MCP verbindet einen Agenten mit externen Werkzeugen und Datenquellen. ACP verbindet einen Editor-Client mit einem Agenten. Sie lösen unterschiedliche Probleme und werden häufig zusammen verwendet: Ein ACP-Agent kann selbst ein MCP-Client sein.

ACP-Architektur​

Die Architektur hat drei Teile: den Client, den Agenten und den Transport zwischen ihnen. Der Client besitzt die UI und die Berechtigungen; der Agent besitzt das Modell und die Werkzeuge.

SchichtRolleBeispiele
ClientRendert die Konversation, sammelt Benutzereingaben, beantwortet BerechtigungsanfragenZed, ein benutzerdefinierter Editor, ein headless Skript
AgentFührt das Modell aus, führt Werkzeuge aus, streamt Aktualisierungencursor-agent acp, andere ACP-Agenten
TransportBewegt JSON-RPC-Nachrichten in beide RichtungenZeilengetrenntes JSON über stdio

Der Sitzungslebenszyklus ist eine feste Abfolge. Sobald Sie ihn verstehen, liest sich der Nachrichtenfluss wie ein Skript.

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

Der Agent handelt nie auf einer geschützten Ressource, ohne vorher den Client zu fragen. Dieser Berechtigungs-Hin-und-Rückweg ist das, was eine UI die Kontrolle über einen autonomen Agenten behalten lässt.

Warum ACP wichtig ist​

ACP ist wichtig, weil es den Editor vom Agenten entkoppelt. Der Wert zeigt sich an drei Stellen.

Editor-Portabilität​

Wenn Cursor und ein anderer Client beide ACP sprechen, können Sie denselben Agenten in beiden verwenden, ohne eine maßgeschneiderte Integration. Ihre Agentenkonfiguration, Modellwahl und Rules reisen mit dem Agenten, nicht mit dem Editor.

Cursors Agenten in jedem konformen Client wiederverwenden​

Statt Agentenverhalten in jedem Editor neu zu implementieren, können Sie jeden ACP-Client auf cursor-agent richten und Cursors Reasoning, Werkzeugnutzung und Modellwahl innerhalb der UI dieses Clients erhalten. Dies ist besonders nützlich für Teams, die auf einem Editor standardisiert sind, der nicht Cursor ist, aber Cursors Agentenverhalten wollen.

Headless-Automatisierung​

Weil der Transport stdio ist, können Sie den Agenten aus einem Skript oder CI-Job ganz ohne Editor steuern. Das macht skriptgesteuerte, wiederholbare Agentenläufe in Pipelines möglich.

# 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
Headless-Läufe brauchen trotzdem Berechtigungen

Wenn Sie den Agenten aus einem Skript steuern, gibt es keinen Menschen, der bei einem Werkzeugaufruf auf „Erlauben“ klickt. Legen Sie Ihren Berechtigungsmodus im Voraus fest und wählen Sie niemals Auto-Ausführung als Standard in einer Umgebung mit sensiblen Credentials.

Cursor über ACP mit cursor-agent bereitstellen​

cursor-agent ist die CLI, die die ACP-Agentenseite der Verbindung übernehmen kann. Installieren Sie sie auf dieselbe Weise, wie Sie die Cursor-CLI installieren.

# 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

Im ACP-Modus ausführen​

Der ACP-Einstiegspunkt ist ein Subbefehl. Wenn Sie ihn ausführen, spricht der Prozess JSON-RPC auf stdio und wartet auf einen sich verbindenden Client.

# 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

Authentifizierung​

Der Agent braucht Credentials, bevor er Prompts bedienen kann. Melden Sie sich einmal an, und die Credentials werden lokal gespeichert.

# 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

Wenn der Agent startet, aber jeder Prompt fehlschlägt, ist die Ursache fast immer eine fehlende oder abgelaufene Authentifizierung. Führen Sie cursor-agent status aus, bevor Sie irgendetwas anderes debuggen.

Eine Sitzung konfigurieren​

Eine Sitzung wird mit einem Arbeitsverzeichnis und Optionen erstellt, die regeln, wie sich der Agent für diese Konversation verhält.

Modellwahl​

Das Modell kann beim Start festgelegt oder pro Sitzung gewählt werden. Es pro Sitzung zu übergeben erlaubt einem einzigen Agentenprozess, verschiedene Clients mit unterschiedlichen Modellpräferenzen zu bedienen.

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

Berichterstattung zur Kontextfenster-Nutzung​

Einige Clients zeigen an, wie voll das Kontextfenster ist. Der Agent meldet die Token-Nutzung als Teil der Sitzungsaktualisierungen, wo der Client dies unterstützt.

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

Berechtigungsmodi und Arbeitsverzeichnis​

Berechtigungsmodi entscheiden, ob der Agent vor der Ausführung eines Werkzeugs fragt. In einem interaktiven Client ist der Standard zu fragen. In der Headless-Automatisierung wählen Sie bewusst.

  • Frage pro Werkzeug: Der Agent sendet eine Berechtigungsanfrage und wartet. Am sichersten, am besten für interaktive Editoren.
  • Auto-Ausführung: Der Agent führt innerhalb des Arbeitsverzeichnisses aus, ohne zu fragen. Schnell und nur in einer Sandbox angemessen.
  • Read-only: Der Agent darf lesen und suchen, aber nie schreiben. Gut für reine Prüf-Sitzungen.

Das cwd in newSession begrenzt, was der Agent als Projekt behandelt. Dateien außerhalb davon sollten nicht berührt werden.

Beispielhafter JSON-RPC-Nachrichtenfluss​

Das Folgende ist eine minimalistische, aber vollständige Konversation. Jede Nachricht ist eine Zeile JSON auf der Leitung.

Initialisieren​

Der Client eröffnet mit initialize, und der Agent antwortet mit seinen Fähigkeiten und der Protokollversion.

{
"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
}
}
}

Neue Sitzung​

Sobald die Fähigkeiten vereinbart sind, erstellt der Client eine Sitzung und erhält eine ID zurück.

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

Prompt​

Der Client sendet die Runde des Nutzers. Beachten Sie, dass dies eine Anfrage ist; der Agent bestätigt sie, aber der eigentliche Inhalt kommt als streamende Benachrichtigungen an.

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

Streamende Aktualisierungen​

Während der Agent arbeitet, sendet er session/update-Benachrichtigungen ohne ID, weil sie einseitig sind.

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

Berechtigungsanfrage​

Vor einer geschützten Aktion bittet der Agent den Client. Der Client antwortet über den standardmäßigen JSON-RPC-Anfragemechanismus.

{
"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" } }
}

Abbrechen​

Um eine Runde abzubrechen, sendet der Client session/cancel. Der Agent stoppt die aktuelle Arbeit und beendet die Prompt-Anfrage mit einem Abbruch-Stoppgrund.

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

Ihren eigenen ACP-Client bauen​

Ein minimaler Client startet den Agenten, schreibt JSON-RPC-Zeilen auf stdin und parst zeilengetrenntes JSON von stdout. Das folgende Snippet zeigt die Form in 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: [] });

Die wichtigsten Regeln zum Merken: Jede Anfrage hat eine id und erwartet eine passende Antwort, Benachrichtigungen haben nie eine id, und der Agent kann auch Anfragen an Sie senden, sodass Ihr Reader beide Richtungen handhaben muss.

Die rohe Leitung loggen

Wenn eine Client-Integration sich falsch verhält, loggen Sie jede Zeile in beide Richtungen, bevor Sie die Logik anfassen. ACP-Bugs sind meist eine fehlende id, ein verlorener Zeilenumbruch oder eine Antwort, die nie gesendet wurde, und die rohe Leitung macht alle drei offensichtlich.

Einschränkungen und aktuelle Lücken​

ACP ist jung, und nicht jede Cursor-Fähigkeit wird darüber offengelegt. Wissen Sie, was Sie aufgeben, bevor Sie darauf aufbauen.

Keine Anpassung des System-Prompts​

Die ACP-Sitzungsoptionen erlauben einem Client derzeit nicht, den System-Prompt des Agenten zu ersetzen oder zu erweitern, wie es .cursor/rules innerhalb der IDE tut. Im Projekt konfigurierte Rules werden weiterhin vom Agenten angewendet, aber der Client kann seine eigenen nicht injizieren.

Unvollständige Kontextfenster-Berichterstattung​

Nutzungsberichterstattung existiert, ist aber nicht garantiert vollständig oder in Echtzeit. Ein Client, der ein exaktes Kontext-Meter wünscht, sollte sich nicht allein auf ACP-Nutzungsaktualisierungen verlassen.

Unterschiede in der Funktionsgleichheit zur IDE​

Mehrere IDE-Funktionen sind über ACP nicht verfügbar oder reduziert:

  • Keine visuelle Diff-Prüfung vorgeschlagener Bearbeitungen innerhalb des Clients, es sei denn, der Client implementiert sie.
  • Hintergrund-Agenten und Cloud-Agenten werden nicht über diesen Pfad gesteuert.
  • Einige Werkzeug- und MCP-Verhaltensweisen unterscheiden sich vom Agent-Modus der IDE.
  • Die Tab-Vervollständigung ist ein separates System und überhaupt nicht Teil von ACP.

Fehlerbehebung​

Agent nicht gefunden​

Wenn der Client cursor-agent startet und ENOENT erhält, liegt die Binärdatei nicht auf dem PATH des startenden Prozesses. Verwenden Sie einen absoluten Pfad im Spawn-Aufruf und denken Sie daran, dass ein GUI-Client einen anderen PATH erben kann als Ihr Terminal.

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

Authentifizierungsfehler​

Wenn jeder Prompt mit einem Auth-Fehler fehlschlägt, hat der Agent keine gültigen Credentials. Führen Sie cursor-agent status aus, dann cursor-agent login, und prüfen Sie, dass der Client nicht unter einem anderen Benutzer oder Home-Verzeichnis läuft als dem, mit dem Sie sich angemeldet haben.

Keine streamenden Aktualisierungen​

Wenn die Prompt-Anfrage zurückkehrt, aber Aktualisierungen nie ankommen, parst der Client Benachrichtigungen wahrscheinlich nicht korrekt. Benachrichtigungen haben keine id, also verwirft ein Reader, der nur Antworten handhabt, sie. Bestätigen Sie, dass Ihr Zeilen-Reader bei einem Zeilenumbruch auslöst und Ihr Parser Nachrichten ohne id handhabt.

Client empfängt nie Berechtigungs-Prompts​

Wenn der Agent Werkzeuge ausführt, ohne zu fragen, wurde die Sitzung mit einem Auto-Ausführungs-Berechtigungsmodus erstellt, oder der Client hat während initialize nie die Fähigkeit angekündigt, Berechtigungsanfragen zu handhaben. Prüfen Sie sowohl die Sitzungsoptionen als auch die gesendeten Fähigkeiten.

SymptomUrsacheLösung
ENOENT beim SpawnAgenten-Binärdatei nicht auf dem PATHEinen absoluten Pfad im Spawn-Aufruf verwenden
Jeder Prompt schlägt fehlFehlende oder abgelaufene Authcursor-agent status und dann cursor-agent login ausführen
Keine session/update-NachrichtenReader handhabt nur Antworten mit einer idBenachrichtigungen ohne id handhaben
Keine Berechtigungs-PromptsAuto-Ausführungsmodus oder fehlende Client-FähigkeitFrage-pro-Werkzeug setzen und die Fähigkeit ankündigen
Prompt hängt für immerAntwort auf eine Anfrage nie gesendetJede Agenten-Anfrage mit passender id beantworten
Parse-Fehler bei AntwortenNachrichten ohne Zeilenumbrüche konkateniertGenau ein JSON-Objekt pro Zeile schreiben und lesen

ACP verwandelt die Editor-Agenten-Beziehung in einen Vertrag, und dieser Vertrag ist das, was Cursors Agenten von überall nutzbar macht, wo das Protokoll gesprochen wird. Beginnen Sie mit dem obigen Nachrichtenfluss, loggen Sie die Leitung, und die Integration wird zu einer kleinen Menge Verrohrung statt zu einer Neuschreibung.