Agent Client Protocol (ACP) mit 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
newSessionerstellten 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.
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.
| Schicht | Rolle | Beispiele |
|---|---|---|
| Client | Rendert die Konversation, sammelt Benutzereingaben, beantwortet Berechtigungsanfragen | Zed, ein benutzerdefinierter Editor, ein headless Skript |
| Agent | Führt das Modell aus, führt Werkzeuge aus, streamt Aktualisierungen | cursor-agent acp, andere ACP-Agenten |
| Transport | Bewegt JSON-RPC-Nachrichten in beide Richtungen | Zeilengetrenntes 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
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.
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.
| Symptom | Ursache | Lösung |
|---|---|---|
ENOENT beim Spawn | Agenten-Binärdatei nicht auf dem PATH | Einen absoluten Pfad im Spawn-Aufruf verwenden |
| Jeder Prompt schlägt fehl | Fehlende oder abgelaufene Auth | cursor-agent status und dann cursor-agent login ausführen |
Keine session/update-Nachrichten | Reader handhabt nur Antworten mit einer id | Benachrichtigungen ohne id handhaben |
| Keine Berechtigungs-Prompts | Auto-Ausführungsmodus oder fehlende Client-Fähigkeit | Frage-pro-Werkzeug setzen und die Fähigkeit ankündigen |
| Prompt hängt für immer | Antwort auf eine Anfrage nie gesendet | Jede Agenten-Anfrage mit passender id beantworten |
| Parse-Fehler bei Antworten | Nachrichten ohne Zeilenumbrüche konkateniert | Genau 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.