[Go to site: main page, start]

Skip to main content

Command Palette

Search for a command to run...

SDK

Cursor Python SDK

Mit dem Paket cursor-sdk kannst du den Cursor-Agent aus deinem eigenen Python-Code aufrufen. Derselbe Agent, der in der Cursor-IDE, der CLI und der Web-App läuft, lässt sich über Python mit Sync-Client und Async-Client, typisierten Dataclasses sowie gewöhnlicher Iteration über Streams und Seiten programmatisch steuern. Führe in Cursor den Skill /sdk aus, um loszulegen.

Informationen zur REST API findest du in der Cloud Agents API. Informationen zu anderen Sprachen findest du in der SDK Bridge.

Übersicht

Das SDK bietet über eine einheitliche Schnittstelle Zugriff auf lokale und Cloud-Runtimes. Du schreibst denselben Code, unabhängig davon, wo der Agent läuft.

RuntimeFunktionWann verwenden
LocalFührt den Agenten mit lokalen Dateien auf dem Datenträger aus.Entwicklungs-Skripte und CI-Checks in einem Working Tree.
Cloud (Cursor-hosted)Läuft in einer isolierten VM, in die dein Repo geklont wurde. Cursor betreibt die VMs.Wenn der Aufrufer das Repo nicht hat, du viele Agenten parallel nutzen möchtest oder Ausführungen auch nach einer Verbindungsunterbrechung des Aufrufers fortgesetzt werden müssen.

Lege die Runtime fest, indem du local oder cloud an Agent.create() übergibst.

Authentifizierung

Setze CURSOR_API_KEY oder übergib api_key, bevor du einen Agenten erstellst.

Das SDK akzeptiert User API Keys und Servicekonto-API-Schlüssel für lokale Ausführungen und Cloud-Runs. Team Admin API Keys werden noch nicht unterstützt.

export CURSOR_API_KEY="your-key"

Nutzung und Abrechnung

SDK-Ausführungen unterliegen denselben Preis-, Request-Pool- und Privacy-Mode-Regeln wie Ausführungen in der IDE und durch Cloud Agents. Die Ausgaben deines Teams werden im Nutzungs-Dashboard unter dem SDK-Tag angezeigt.

Wie du die Token-Anzahl pro Ausführung im Code abfragst, erfährst du unter Token-Nutzung. Wie du die abgerechnete Nutzung und die Kosten in US-Dollar für die Ausführungen eines Agenten abrufst, erfährst du unter agent.get_usage().

Grundkonzepte

KonzeptBeschreibung
AgentDauerhaftes Handle, das den Zustand der Unterhaltung, die Workspace-Konfiguration, die Modellauswahl und Einstellungen speichert. Bleibt über mehrere Prompts hinweg erhalten.
AusführungEine Prompt-Übermittlung. Verfügt über eigenen Stream, Status, Ergebnis, Unterhaltung und Abbruchmöglichkeit.
SDKMessageTypisierte Stream-Nachricht, die während einer Ausführung ausgegeben wird. Hat in lokalen und Cloud-Runtimes dieselbe Struktur.
CursorClientExpliziter Client zur Steuerung des Lebenszyklus, für benutzerdefinierte HTTP-Optionen oder mehrere Workspaces in einem Prozess. Client ist ein Alias.
AsyncClientAsynchrones Gegenstück zum Client. Für alle asynchronen Operationen erforderlich.

Installation

pip install cursor-sdk

Erfordert Python 3.10 oder neuer.

Schnellstart

import osfrom cursor_sdk import Agent, LocalAgentOptionswith Agent.create(    model="composer-2.5",    api_key="crsr_key",    local=LocalAgentOptions(cwd=os.getcwd()),) as agent:    print(agent.send("Summarize what this repository does").text())

Stream-Events zeigt, wie sich Assistententext extrahieren, Tool-Aufrufe verarbeiten und der Run-Status auslesen lassen. Für einen einmaligen Prompt (erstellen, ausführen, abschließen) siehe Agent.prompt().

Cloud-Schnellstart

Das Python SDK unterstützt die Cloud Agents von Cursor nativ. Du kannst verbundene Repositories auflisten, einen Agent für eines davon starten, auf dessen Abschluss warten und das Endergebnis prüfen.

from cursor_sdk import Agent, CloudAgentOptions, CloudRepositorywith Agent.create(    model="composer-2.5",    api_key="crsr_key",    cloud=CloudAgentOptions(        repos=[CloudRepository(url="https://github.com/your-org/your-repo", starting_ref="main")],        auto_create_pr=True,    ),) as agent:    print(agent.send("Add structured logging to the auth middleware").text())

Cloud Agents, die über das SDK gestartet wurden, werden in der Standard-Agentenliste nicht angezeigt. Um sie in Cursor Web oder im Cursor-Agentenfenster anzuzeigen, klicken Sie auf Filter > Quelle > SDK.

Asynchrone Nutzung

Der Async-Client bietet dieselbe API wie der Sync-Client und wird für Server, Bots und die parallele Orchestrierung von Agenten empfohlen. AsyncAgent, AsyncClient, AsyncRun und AsyncCursor werden sowohl aus cursor_sdk als auch aus cursor_sdk.asyncio exportiert.

import asyncioimport osfrom cursor_sdk import AsyncClient, LocalAgentOptionsasync def main():    async with await AsyncClient.launch_bridge(workspace=os.getcwd()) as client:        async with await client.agents.create(            model="composer-2.5",            api_key="crsr_key",            local=LocalAgentOptions(cwd=os.getcwd()),        ) as agent:            run = await agent.send("Summarize what this repository does")            print(await run.text())asyncio.run(main())

Es gibt keinen globalen Async-Standardclient. Erstellen Sie AsyncClient explizit oder verwenden Sie AsyncClient.launch_bridge(...) als asynchronen Kontextmanager, damit jede Ereignisschleife über einen eigenen Client verfügt. Verwenden Sie Sync- und Async-Clients nicht im selben Codepfad.

Direkte Klassenmethoden von AsyncAgent erfordern client=. Verwenden Sie await client.agents.create(...) oder await AsyncAgent.create(..., client=client).

SyncAsync
CursorClient / ClientAsyncClient / AsyncCursorClient
AgentAsyncAgent
RunAsyncRun
CursorAsyncCursor
ListResultAsyncListResult
DefaultHttpxClientDefaultAsyncHttpxClient

Agenten erstellen

Agent.create() validiert die Optionen und gibt sofort ein Handle zurück. Übergeben Sie entweder local oder cloud, um die Laufzeitumgebung auszuwählen.

from cursor_sdk import Agent, CloudAgentOptions, CloudRepository, LocalAgentOptionsagent = Agent.create(    model="composer-2.5",    local=LocalAgentOptions(cwd="."),)cloud_agent = Agent.create(    model="composer-2.5",    cloud=CloudAgentOptions(        repos=[CloudRepository(url="https://github.com/your-org/your-repo", starting_ref="main")],        auto_create_pr=True,    ),)

agent.agent_id wird sofort gesetzt. Lokale Agenten erhalten eine ID im Format agent-<uuid>, Cloud Agents eine ID im Format bc-<uuid>. agent.model ist eine typisierte ModelSelection, daher können Sie agent.model.id und agent.model.params direkt verwenden.

Cloud Agents ohne Repo

Cloud Agents können auf einer leeren VM ohne Repository ausgeführt werden. Übergeben Sie cloud mit einer leeren repos-Liste oder lassen Sie repos ganz weg. Wenn Sie cloud weglassen, wird stattdessen die lokale Runtime verwendet.

from cursor_sdk import Agent, CloudAgentOptionswith Agent.create(cloud=CloudAgentOptions(repos=[])) as agent:    run = agent.send("Research the top 3 Python testing frameworks and summarize.")    print(run.wait().result)

Agenten ohne Repo müssen für dein Konto oder dein Team aktiviert sein. Repository-spezifische API-Schlüssel können sie nicht erstellen. Verwende stattdessen einen uneingeschränkten Service-Account-Schlüssel oder einen User API Key.

Session-Umgebungsvariablen

Übergeben Sie bei Cloud Agents env_vars, wenn eine Ausführung kurzlebige Zugangsdaten oder andere Werte benötigt, die nur für diesen Agenten gelten sollen.

import osagent = Agent.create(    model="composer-2.5",    cloud=CloudAgentOptions(        repos=[CloudRepository(url="https://github.com/your-org/your-repo")],        env_vars={            "STAGING_API_TOKEN": os.environ["STAGING_API_TOKEN"],        },    ),)

Diese Werte werden verschlüsselt gespeichert, in die Shell des Cloud Agents eingefügt und mit dem Agenten gelöscht. env_vars kann nicht mit einer vom Aufrufer bereitgestellten agent_id verwendet werden; lasse agent_id weg und lies die vom Server geprägte ID aus agent.agent_id. Variablennamen dürfen nicht mit CURSOR_ beginnen.

Für Werte, die nur während einer einzelnen Ausführung vorhanden sein sollen, übergib sie stattdessen an agent.send(). Siehe Umgebungsvariablen pro Ausführung.

Agent-Metadaten

Füge einem Cloud-Agenten beim Erstellen eigene Kennungen hinzu. Mit Metadaten kannst du einen Agenten mit einem Nutzer, Mandanten, Workflow oder Ticket in deinem System verknüpfen. Sie werden über SDKAgentInfo.metadata von client.agents.get() und client.agents.list() zurückgegeben.

from cursor_sdk import Agent, CloudAgentOptions, CloudRepositorywith Agent.create(    model="composer-2.5",    cloud=CloudAgentOptions(        repos=[CloudRepository(url="https://github.com/your-org/your-repo")],        metadata={            "end_user_id": "user-123",            "ticket_id": "ENG-456",        },    ),) as agent:    print(agent.agent_id)

Metadaten können Cloud-Agents bei der Erstellung hinzugefügt werden. Du kannst bis zu 50 Schlüssel-Wert-Paare anhängen. Schlüssel dürfen nicht leer sein und maximal 255 Zeichen lang sein. Werte müssen Strings mit maximal 4096 Byte sein. Leere String-Werte sind zulässig, und eine leere Zuordnung wird wie keine Metadaten behandelt.

Modellparameter

Verwende ModelSelection.params, um modellspezifische Optionen wie den Denkaufwand oder optimize_for des Cursor Routers zu übergeben. Parameter-IDs und -werte variieren je nach Modell. Mit Cursor.models.list() kannst du unterstützte Parameter und vordefinierte Varianten für dein Konto ermitteln.

from cursor_sdk import Agent, LocalAgentOptions, ModelParameterValue, ModelSelectionagent = Agent.create(    model=ModelSelection(        id="composer-2.5",        params=[ModelParameterValue(id="fast", value="true")],    ),    local=LocalAgentOptions(cwd="."),)

Verwenden Sie Cursor.models.list(), um die Parameter-IDs und vordefinierten Varianten eines bestimmten Modells zu ermitteln. Informationen zum Auswahlvertrag für auto-smart finden Sie unter Cursor Router.

Cursor Router

Cursor Router wählt für jede Auto-Anfrage ein Modell aus. Im SDK ist Router das Modell auto-smart mit dem Parameter optimize_for. Es ist für Teams und Enterprise verfügbar. Enterprise-Admins müssen Router für das Team aktivieren, bevor auto-smart im Katalog erscheint.

Das Cursor SDK ist ein Agent-SDK und keine eigenständige API für Modellinferenz oder Chat-Vervollständigungen. Router wählt Modelle für Cursor-Agent-Ausführungen aus, die einen Workspace analysieren, Tools aufrufen, Befehle ausführen und Dateien bearbeiten können. Cursor dokumentiert derzeit keinen direkten Router-Endpunkt für beliebige Modellaufrufe.

Cost, Balance oder Intelligence auswählen

Übergeben Sie auto-smart und setzen Sie optimize_for explizit:

ProduktbezeichnungSDK-Wert
Costcost
Balancebalanced
Intelligenceintelligence

Verwenden Sie Balance in Produkttexten. Verwenden Sie balanced nur als SDK-Wert für die Übertragung.

import osfrom cursor_sdk import Agent, LocalAgentOptions, ModelParameterValue, ModelSelectionwith Agent.create(    model=ModelSelection(        id="auto-smart",        params=[ModelParameterValue(id="optimize_for", value="balanced")],    ),    local=LocalAgentOptions(cwd=os.getcwd()),) as agent:    run = agent.send("Find and fix the failing authentication test")    result = run.wait()    print(result.status)

Übergeben Sie stets optimize_for. Lassen Sie es nicht weg und senden Sie keinen Legacy-Wert für default; die Ermittlung über den Katalog ist der unterstützte Vertrag.

Router im Modellkatalog entdecken

Cursor.models.list() gibt die für das aktuelle Konto und Team des API-Schlüssels verfügbaren Modelle, Parameterdefinitionen und vordefinierten Varianten zurück. Cursor Router wird als auto-smart angezeigt, sofern Router verfügbar ist. Teamadministratoren können Router deaktivieren oder einschränken, welche Optimierungsmodi Teammitglieder auswählen dürfen.

Nutze den Katalog als maßgebliche Quelle, bevor du eine Auswahl fest codierst:

from cursor_sdk import Cursor, ModelParameterValue, ModelSelectionmodels = Cursor.models.list()router = next((model for model in models if model.id == "auto-smart"), None)optimize_for = next(    (        parameter        for parameter in (router.parameters if router else [])        if parameter.id == "optimize_for"    ),    None,)if router is None or optimize_for is None:    raise RuntimeError(        "Cursor Router is not available for this API key. "        "Verify that Router is enabled for the key's team."    )requested_mode = "balanced"allowed_values = {entry.value for entry in optimize_for.values}if requested_mode not in allowed_values:    raise RuntimeError(        f'Router mode "{requested_mode}" is not enabled for this team.'    )model = ModelSelection(    id=router.id,    params=[ModelParameterValue(id=optimize_for.id, value=requested_mode)],)

Modi für einzelne Ausführungen wechseln

Überschreibe das Modell in agent.send(), um den Router-Modus für eine Ausführung zu ändern:

from cursor_sdk import ModelParameterValue, ModelSelection, SendOptionsrun = agent.send(    "Handle this complex migration",    SendOptions(        model=ModelSelection(            id="auto-smart",            params=[ModelParameterValue(id="optimize_for", value="intelligence")],        ),    ),)

Modellüberschreibungen pro Ausführung bleiben für spätere Ausführungen erhalten. Spätere Sends ohne Überschreibung verwenden weiterhin die neue Auswahl. Siehe Modellüberschreibung pro Ausführung.

Modell-IDs: auto-smart, auto und default

AuswahlBedeutung
auto-smart mit optimize_forCursor Router. Verwende dies für Cost, Balance oder Intelligence.
ModelSelection(id="auto")Vom Server ausgewählter Auto-Fallback, wenn ein bestimmtes Modell im Katalog fehlt. Verwende auto-smart, wenn du einen expliziten Router-Modus benötigst.
Weglassen von optimize_for oder Senden von defaultKein unterstützter Router-Vertrag. Ermittle stets die zulässigen Werte und übergib cost, balanced oder intelligence.

Abrechnung und Routing-Pool

  • Cost folgt dem klassischen Auto-Verhalten und der gebündelten Auto-Preisgestaltung.
  • Balance und Intelligence verwenden Cursor Router und werden gemäß deinem Plan oder Vertrag zum Preis des gerouteten Modells abgerechnet.
  • Das zugrunde liegende Modell kann sich zwischen Anfragen ändern. Verwende eine feste Modell-ID, wenn du reproduzierbare Vergleiche benötigst.
  • Enterprise-Modell-Positivlisten bestimmen den Routing-Pool. Das Blockieren erforderlicher Modelle kann Router deaktivieren.

Aktuelle Preise und den Routing-Pool findest du unter Cursor Router und Modelle & Preise.

Fehlerbehebung bei fehlendem Router

Wenn auto-smart fehlt oder ein Optimierungsmodus abgelehnt wird:

  1. Rufe Cursor.models.list() auf.
  2. Stelle sicher, dass auto-smart im Ergebnis enthalten ist.
  3. Stelle sicher, dass optimize_for den gewünschten Wert enthält (cost, balanced oder intelligence).
  4. Stelle sicher, dass Router für das mit dem API-Schlüssel verknüpfte Team aktiviert ist.
  5. Wenn du mehreren Teams angehörst, stelle sicher, dass der Schlüssel im vorgesehenen Teamkontext verwendet wird.
  6. Überprüfe die Modellzugriffsrichtlinie des Teams, wenn Router nicht verfügbar ist oder kein gültiges zugrunde liegendes Modell auswählen kann.

Rohe Dictionaries

Für Anwendungscode sind typisierte Dataclasses vorzuziehen, da IDE-Autovervollständigung und Typprüfung besser funktionieren. Das SDK akzeptiert auch einfache Dictionaries für kurze Skripte oder extern bereitgestelltes JSON. Schlüssel im Snake-Case werden normalisiert.

from cursor_sdk import Agentwith Agent.create(    {        "api_key": "crsr_key",        "model": {"id": "composer-2.5"},        "local": {"cwd": "."},    }) as agent:    ...

Agent

Das von Agent.create(), Agent.resume(), client.agents.create() und client.agents.resume() zurückgegebene Handle.

class Agent:    agent_id: str    model: ModelSelection | None    client: CursorClient    def send(        self,        message: str | Mapping[str, Any] | UserMessage,        options: SendOptions | Mapping[str, Any] | None = None,        *,        idempotency_key: str | None = None,    ) -> Run: ...    def reload(self) -> None: ...    def close(self) -> None: ...    def list_messages(        self, options: Mapping[str, Any] | None = None    ) -> list[AgentMessage]: ...    def list_artifacts(self) -> list[SDKArtifact]: ...    def download_artifact(self, path: str) -> bytes: ...    def get_usage(self, *, run_id: str | None = None) -> AgentUsage: ...    def archive(self, options: Mapping[str, Any] | None = None) -> None: ...    def unarchive(self, options: Mapping[str, Any] | None = None) -> None: ...    def delete(self, options: Mapping[str, Any] | None = None) -> None: ...
MitgliedBeschreibung
agent_idStabile Agent-ID. agent-<uuid> für lokal, bc-<uuid> für die Cloud.
modelAktuelle typisierte Modellauswahl. Wird nach einem erfolgreichen Senden mit einer Modellüberschreibung aktualisiert.
sendStartet eine neue Ausführung mit dem angegebenen Prompt. Gibt ein Run-Handle zurück.
reloadLiest die Dateisystemkonfiguration (Hooks, Projekt-MCP, Subagents) erneut ein, ohne Ressourcen freizugeben.
closeSchließt den Agent und gibt Ressourcen frei.
list_messagesListet den Nachrichtenverlauf des Agent auf.
list_artifactsListet die vom Agent erzeugten Dateien auf (nur Cloud; lokal wird eine leere Liste zurückgegeben).
download_artifactLädt eine Datei über ihren Pfad herunter (nur Cloud; lokal wird ein Fehler ausgelöst).
get_usageRuft die abgerechnete Tokennutzung und die Kosten in US-Dollar für den Agent ab.
archive / unarchive / deleteVerwaltet den Lebenszyklus von Cloud-Agenten.

Verwenden Sie einen Kontextmanager für die automatische Bereinigung:

with Agent.create(model="composer-2.5", local=LocalAgentOptions(cwd=".")) as agent:    print(agent.send("Explain this repository").text())

Wenn du die synchronen Agent.*- oder Cursor.*-Hilfsfunktionen ohne client= nutzt, startet das SDK einen Standard-Client auf Modulebene oder verwendet ihn erneut. Er wird beim Beenden des Prozesses automatisch geschlossen, kann aber auch explizit geschlossen werden:

from cursor_sdk import close_default_clientclose_default_client()

Agent.prompt()

Agent.prompt(    message: str | Mapping[str, Any] | UserMessage,    options: AgentOptions | Mapping[str, Any] | None = None,    *,    client: CursorClient | None = None,) -> RunResult

Praktische One-Shot-Methode: Erstellt einen Agenten, sendet einen einzelnen Prompt, wartet, bis der Run abgeschlossen ist, und gibt ihn frei.

from cursor_sdk import Agent, AgentOptions, LocalAgentOptionsresult = Agent.prompt(    "What does the auth middleware do?",    AgentOptions(model="composer-2.5", local=LocalAgentOptions(cwd=".")),)print(result.result)

Asynchrone Variante (setzt voraus, dass du bereits einen AsyncClient geöffnet hast):

from cursor_sdk import AgentOptions, AsyncAgent, LocalAgentOptionsresult = await AsyncAgent.prompt(    "What does the auth middleware do?",    AgentOptions(model="composer-2.5", local=LocalAgentOptions(cwd=".")),    client=client,)

CursorClient

Verwende CursorClient, wenn du den Lebenszyklus explizit steuern, einen eigenen Bridge-Endpunkt oder eigene HTTP-Optionen verwenden oder mehrere Workspaces in einem Prozess nutzen möchtest. Client ist weiterhin als Alias verfügbar.

from cursor_sdk import CursorClient, LocalAgentOptionswith CursorClient.launch_bridge(workspace=".") as client:    with client.agents.create(        model="composer-2.5",        api_key="crsr_key",        local=LocalAgentOptions(cwd="."),    ) as agent:        print(agent.send("Summarize what this repository does").text())

Ressourcen

Explizite Clients bieten Ressourcen-Namespaces:

RessourceBeispiele für synchrone MethodenBeispiele für asynchrone Methoden
agentsclient.agents.create(...), client.agents.list(...), client.agents.get(...)await client.agents.create(...), await client.agents.list(...)
modelsclient.models.list()await client.models.list()
repositoriesclient.repositories.list()await client.repositories.list()

Top-Level-Methoden wie client.create_agent(...) und client.list_agents(...) bleiben verfügbar, für Anwendungscode werden jedoch Ressourcen-Namespaces bevorzugt.

Benutzerdefinierte HTTP-Clients

Sowohl Sync- als auch Async-Clients unterstützen einen benutzerdefinierten httpx-Client für Proxys, Transports und andere erweiterte HTTP-Konfigurationen:

from cursor_sdk import CursorClient, DefaultHttpxClientwith CursorClient.launch_bridge(    workspace=".",    http_client=DefaultHttpxClient(proxy="http://proxy.example.com"),) as client:    ...
from cursor_sdk import AsyncClient, DefaultAsyncHttpxClientasync with await AsyncClient.launch_bridge(    workspace=".",    http_client=DefaultAsyncHttpxClient(proxy="http://proxy.example.com"),) as client:    ...

DefaultHttpxClient und DefaultAsyncHttpxClient behalten das Standard-Timeout und das Weiterleitungsverhalten des SDK bei. httpx.Client und httpx.AsyncClient verwenden stattdessen die httpx-Standardeinstellungen.

Timeouts und Wiederholungsversuche konfigurieren

Beide Clients bieten with_options(...), das eine flache Kopie mit denselben Verbindungseinstellungen zurückgibt und Standardwerte überschreibt. Verwenden Sie timeout für alle Anfragen oder legen Sie unary_timeout und stream_timeout separat fest. max_retries steuert Wiederholungsversuche des Clients:

short = client.with_options(timeout=5.0, max_retries=2)agent = short.agents.create(model="composer-2.5", local=LocalAgentOptions(cwd="."))

Asynchrones Äquivalent:

short_async = async_client.with_options(timeout=5.0, max_retries=2)agent = await short_async.agents.create(model="composer-2.5", local=LocalAgentOptions(cwd="."))

Nachrichten senden

Jeder Aufruf von agent.send() gibt einen Run zurück. Jeder Aufruf von await async_agent.send() gibt einen AsyncRun zurück. Der Agent behält den Gesprächskontext über mehrere Ausführungen hinweg bei; eine Ausführung ist die Arbeitseinheit für einen Prompt.

print(agent.send("Find the bug in src/auth.py").text())# Derselbe Agent, der vollständige Unterhaltungskontext bleibt erhalten.print(agent.send("Fix it and add a regression test").text())

Asynchrone Entsprechung:

run = await agent.send("Find the bug in src/auth.py")print(await run.text())run = await agent.send("Fix it and add a regression test")print(await run.text())

Um Bilder zusammen mit Text zu senden:

run = agent.send(    {        "text": "What's in this screenshot?",        "images": [{"data": base64_png, "mime_type": "image/png"}],    })

Du kannst auch Hilfs-Dataclasses verwenden. SDKImage.from_file(path) liest die Datei von der Festplatte und übernimmt die Base64-Kodierung für dich:

from cursor_sdk import SDKImage, UserMessagerun = agent.send(    UserMessage(        text="What's in this screenshot?",        images=[SDKImage.from_file("screenshot.png")],    ))

SDKImage.data_image(base64_data, mime_type) und SDKImage.url_image(url) stehen auch Aufrufern zur Verfügung, die bereits kodierte Bytes oder eine Remote-URL haben.

Ausführung

class Run:    id: str    agent_id: str    status: str  # "running" | "finished" | "error" | "cancelled" | "expired"    result: str    model: ModelSelection | None    duration_ms: int    git: RunGitInfo | None    created_at: str | None    usage: TokenUsage | None  # kumulativ; Property am aktiven Handle    def stream(self) -> Iterator[SDKMessage]: ...    def messages(self) -> Iterator[SDKMessage]: ...    def events(self) -> Iterator[RunStreamEvent]: ...    def iter_text(self) -> Iterator[str]: ...    def text(self) -> str: ...    def wait(self) -> RunResult: ...    def cancel(self) -> None: ...    def conversation(self) -> list[ConversationTurn]: ...    def conversation_json(self) -> str: ...    def observe(self, *, after_offset: str | None = None) -> Iterator[RunStreamEvent]: ...    def supports(self, operation: str) -> bool: ...    def unsupported_reason(self, operation: str) -> str | None: ...    def on_did_change_status(        self, listener: Callable[[str], None]    ) -> Callable[[], None]: ...

run.stream() ist ein Alias für run.messages(). Die direkte Iteration über run liefert RunStreamEvent-Ereignisrahmen – genauso wie run.events().

AsyncRun bietet dieselben Statusfelder, einschließlich usage. Methoden mit I/O sind async: async for message in run.stream(), async for message in run.messages(), async for event in run.events(), async for text in run.iter_text(), await run.text(), await run.wait(), await run.cancel(), await run.conversation(), await run.conversation_json() und async for event in run.observe().

Streaming

run = agent.send("Find the bug in src/auth.py")for message in run.messages():    if message.type == "assistant":        for block in message.message.content:            if block.type == "text":                print(block.text, end="")    elif message.type == "thinking":        print(message.text, end="")    elif message.type == "tool_call":        print(f"[tool] {message.name}: {message.status}")    elif message.type == "status":        print(f"[status] {message.status}")    elif message.type == "usage":        print(f"[usage] turn total={message.usage.total_tokens}")

Ein Ausführungsstream kann nur einmal verarbeitet werden. run.messages(), run.events() und run.iter_text() greifen alle auf denselben zugrunde liegenden Stream zu und lesen ihn weiter. Nach Abschluss des Streams enthält die Ausführung das Endergebnis (run.result, run.status, run.usage, run.git, ...). Rufen Sie run.wait() auf, um alle verbleibenden Ereignisse zu verarbeiten und das typisierte RunResult zurückzugeben.

Warten ohne Streaming

result = run.wait()print(result.status)       # "finished" | "error" | "cancelled" | "expired"print(result.result)       # finaler Assistententext, sofern vorhandenprint(result.model)        # aufgelöste ModelSelection für diesen Runprint(result.duration_ms)print(result.usage)        # kumulierte TokenUsage oder None, wenn nicht verfügbarprint(result.git)          # RunGitInfo in der Cloud

Asynchrone Entsprechung:

result = await run.wait()

Tokennutzung

Ausführungen melden die Tokennutzung, wenn die Runtime sie bereitstellt. Die kumulierte Summe findest du in run.usage auf dem Live-Handle (während des Streamings oder nach wait()) oder in result.usage im von run.wait() zurückgegebenen RunResult. Beide enthalten eine TokenUsage, die über alle Runden mit gemeldeter Nutzung summiert wird, und sind None, wenn keine Runde eine Nutzung gemeldet hat – etwa bei einer abgebrochenen Ausführung, die keine Runde abgeschlossen hat, bei einer Runtime, die keine Nutzung bereitstellt, oder bei einem entkoppelten Cloud-Snapshot, dessen Nutzung noch nicht abgeglichen wurde.

@dataclass(frozen=True)class TokenUsage:    input_tokens: int    output_tokens: int    cache_read_tokens: int    cache_write_tokens: int    total_tokens: int    reasoning_tokens: int | None = None
FeldBeschreibung
input_tokensAn das Modell gesendete Prompt-Tokens.
output_tokensVom Modell generierte Tokens.
cache_read_tokensAus dem Prompt-Cache abgerufene Tokens.
cache_write_tokensIn den Prompt-Cache geschriebene Tokens.
total_tokensinput_tokens + output_tokens + cache_read_tokens + cache_write_tokens. Ohne reasoning_tokens.
reasoning_tokensDenk-Tokens, eine Teilmenge von output_tokens. None, wenn das Modell oder die Laufzeit sie nicht gemeldet hat.
result = run.wait()if result.usage is not None:    print(f"total: {result.usage.total_tokens}")    print(f"in: {result.usage.input_tokens}, out: {result.usage.output_tokens}")    print(        f"cache read/write: {result.usage.cache_read_tokens}/{result.usage.cache_write_tokens}"    )else:    print("no usage reported for this run")

reasoning_tokens ist bereits in output_tokens enthalten, daher lässt total_tokens sie weg, um Doppelzählungen zu vermeiden.

Für Werte pro Runde während des Streamings verarbeiten Sie das usage-Stream-Event (SDKUsageMessage). Es wird am Ende jeder Runde, die Nutzung gemeldet hat, einmal ausgelöst und enthält die TokenUsage dieser Runde. run.usage und result.usage bleiben über die gesamte Ausführung hinweg kumulativ. Nach Stream-Runden bevorzugt das Handle diese aufsummierten Gesamtwerte; andernfalls verwendet es die Nutzungsdaten aus wait() oder aus einem get_run- / list_runs-Snapshot, sofern die Bridge sie bereitstellt.

for message in run.messages():    if message.type == "usage":        print(f"turn used {message.usage.total_tokens} tokens")# Oder nach wait / ohne die Nachrichten selbst zu verarbeiten:result = run.wait()print(run.usage, result.usage)

Asynchrone Entsprechung: async for message in run.messages() und await run.wait(). run.usage ist bei AsyncRun weiterhin eine synchrone Property.

TokenUsage wird aus cursor_sdk exportiert (zusätzlich to_token_usage / sum_token_usage für fortgeschrittene Aufrufer). Das Wire-JSON verwendet camelCase (inputTokens, …); die Python-Dataclasses verwenden snake_case.

Die Token-Anzahlen entsprechen den Angaben der Runtime und sagen nichts über die Kosten aus. Informationen zur abgerechneten Nutzung und zu den Dollarkosten der Ausführungen eines Agenten erhalten Sie mit agent.get_usage().

Textausgabe lesen

iter_text() liefert Assistententext, während dieser gestreamt wird. text() gibt den endgültigen Terminaltext zurück und wartet auf wait(), falls die Ausführung noch läuft.

for chunk in run.iter_text():    print(chunk, end="")final_text = run.text()

Asynchrones Äquivalent:

async for chunk in run.iter_text():    print(chunk, end="")final_text = await run.text()

Eine Ausführung abbrechen

run.cancel()

Asynchrone Entsprechung:

await run.cancel()

run.cancel() fordert den Abbruch einer aktiven Ausführung an. Der Status wechselt zu "cancelled", der Live-Stream wird beendet, laufende Tool-Aufrufe werden abgebrochen und run.wait() wird mit status: "cancelled" aufgelöst. Die Teilausgabe (der bisher geschriebene Assistententext) bleibt im Run-Objekt erhalten.

Das Abbrechen einer bereits abgeschlossenen Ausführung ("finished", "error", "cancelled", "expired") löst UnsupportedRunOperationError aus. Prüfe im Zweifel run.status:

if run.status == "running":    run.cancel()

Run-Status abrufen

print(run.id)print(run.status)  # "running" | "finished" | "error" | "cancelled" | "expired"stop = run.on_did_change_status(lambda status: print(f"status changed to {status}"))stop()  # Listener entfernenturns = run.conversation()

run.conversation() gibt eine typisierte list[ConversationTurn] zurück. Nutzen Sie sie, um den strukturierten Verlauf darzustellen oder dauerhaft zu speichern, ohne den Live-Stream zu abonnieren. run.conversation_json() gibt den unverarbeiteten JSON-String zurück.

Verwenden Sie für asynchrone Ausführungen await run.conversation() und await run.conversation_json().

Modellüberschreibung pro Run

Das model, das du an agent.send() übergibst, überschreibt die Modellauswahl des Agenten für diesen Run und bleibt anschließend aktiv: Bei nachfolgenden Sends ohne Überschreibung wird weiterhin das neue Modell verwendet. Um zurückzuwechseln, übergib eine weitere model-Überschreibung oder lies die aktuelle Auswahl über agent.model aus.

from cursor_sdk import ModelParameterValue, ModelSelection, SendOptionsrun = agent.send(    "Plan the refactor",    SendOptions(        model=ModelSelection(            id="composer-2.5",            params=[ModelParameterValue(id="fast", value="true")],        ),    ),)

run.model und result.model geben die für diesen Run verwendete Auswahl wieder und sind nach dem Start des Runs unveränderlich.

Umgebungsvariablen pro Ausführung

Cloud Agents können auch Umgebungsvariablen für eine einzelne Ausführung erhalten. Übergib cloud.env_vars in SendOptions; die Werte werden nur für diese Ausführung in die Shell des Agents eingefügt. Nach Abschluss der Ausführung werden sie von der VM entfernt und sind für die nächste Ausführung nicht verfügbar. Das eignet sich für Zugangsdaten, die sich zwischen Runden ändern, etwa ein kurzlebiges Deploy-Token, das du direkt vor der Aufforderung an den Agent, es zu verwenden, prägst.

from cursor_sdk import CloudSendOptions, SendOptionsrun = agent.send(    "Deploy the preview environment",    SendOptions(        cloud=CloudSendOptions(env_vars={"DEPLOY_TOKEN": mint_short_lived_token()}),    ),)

Wenn eine ausführungsspezifische Variable denselben Namen wie eine agentbezogene Variable aus env_vars in CloudAgentOptions hat, hat der ausführungsspezifische Wert für diese Ausführung Vorrang. Bei der nächsten Ausführung gilt wieder der agentbezogene Wert.

Ausführungsspezifische Variablen funktionieren auch beim ersten Senden. Das SDK übergibt sie bei der Erstellung des Agenten und beschränkt sie auf die erste Ausführung, sodass sie nicht im Agenten gespeichert werden. Wie agentbezogene Variablen werden sie verschlüsselt gespeichert, und ihre Namen dürfen nicht mit CURSOR_ beginnen.

Ausführungsspezifische Umgebungsvariablen sind nur für Cloud Agents verfügbar und nicht für Agents, die mit öffentlichen Repositories arbeiten. Bei lokalen Agents übernimmt der Agent-Prozess deine eigene Umgebung. Lege Variablen daher für den Prozess fest, bevor du send() aufrufst.

Unterhaltungsmodus

Übergeben Sie mode="plan" oder mode="agent", um festzulegen, ob eine Ausführung zunächst den Kontext erkundet und plant oder Änderungen direkt umsetzt. Weitere Informationen zum Plan-Modus im Produkt finden Sie unter Plan-Modus.

Legen Sie mode in den an Agent.create() übergebenen AgentOptions fest, um die erste Ausführung zu initialisieren. Lassen Sie bei nachfolgenden Aufrufen von agent.send() mode weg, um den aktuellen Unterhaltungsmodus beizubehalten, oder übergeben Sie mode, um ihn nur für diese Ausführung zu ändern.

from cursor_sdk import Agent, AgentOptions, CloudAgentOptions, CloudRepository, SendOptionswith Agent.create(    AgentOptions(        model="composer-2.5",        mode="plan",        cloud=CloudAgentOptions(            repos=[CloudRepository(url="https://github.com/your-org/your-repo")],        ),    )) as agent:    agent.send("Design the auth refactor").wait()    agent.send(        "Looks good, start building",        SendOptions(mode="agent"),    ).wait()

Streaming von raw-Deltas

Übergeben Sie die Callbacks on_delta und on_step in SendOptions, um Updates auf niedrigerer Ebene zu erhalten. Synchrone Callbacks werden inline aufgerufen. Asynchrone Callbacks können synchron oder asynchron sein; awaitable Rückgabewerte werden abgewartet, bevor das nächste Event verarbeitet wird.

from cursor_sdk import SendOptionsdef on_delta(update):    if update.type in ("text-delta", "thinking-delta"):        print(update.text, end="")run = agent.send(    "Refactor the utils module",    SendOptions(on_delta=on_delta, on_step=lambda step: print(f"[step] {step.type}")),)run.wait()

Die konkreten Unterklassen für Updates und Schritte befinden sich in cursor_sdk.events:

from cursor_sdk.events import TextDeltaUpdate, ToolCallStartedUpdateif isinstance(update, TextDeltaUpdate):    print(update.text)

Sie können aus Gründen der Abwärtskompatibilität weiterhin aus cursor_sdk importiert werden, neuer Code sollte sie jedoch aus cursor_sdk.events importieren.

SendOptions

EigenschaftTypBeschreibung
modelstr | ModelSelection | Mapping[str, Any]Modellüberschreibung pro Sendevorgang. Wenn nicht angegeben, wird agent.model verwendet. Bleibt nach einem erfolgreichen Sendevorgang bestehen.
mode"agent" | "plan"Überschreibung des Unterhaltungsmodus pro Sendevorgang. Wenn bei Folgeanfragen nicht angegeben, bleibt der aktuelle Unterhaltungsmodus erhalten.
mcp_serversMapping[str, McpServerConfig]Inline-MCP-Serverdefinitionen. Ersetzt die beim Erstellen festgelegten Server für diese Ausführung vollständig.
cloud.env_varsMapping[str, str]Nur für Cloud Agents. Umgebungsvariablen pro Ausführung, die für diese Ausführung gesetzt und nach ihrem Abschluss entfernt werden. Überschreibt die agentbezogenen env_vars für diese Ausführung nur anhand des Namens.
local.forceboolNur für lokale Agenten. Standardmäßig None (nicht gesetzt). Setzen Sie True, um eine festgefahrene aktive Ausführung zu beenden, bevor diese Nachricht gestartet wird. Cloud gibt serverseitig 409 agent_busy zurück, daher ist kein Äquivalent erforderlich.
idempotency_keystrOptionaler, vom Client generierter Idempotenzschlüssel für den Sendevorgang.
on_stepCallable[[ConversationStep], Any]Callback nach jedem abgeschlossenen Unterhaltungsschritt (Text, Thinking oder Tool-Batch).
on_deltaCallable[[InteractionUpdate], Any]Callback für jedes rohe InteractionUpdate.

Die nächsten drei Abschnitte enthalten eine detaillierte Referenz zu SDKMessage, InteractionUpdate und ConversationTurn. Überfliegen oder überspringen Sie sie beim ersten Lesen; Agent wieder aufnehmen setzt die Einführung fort.

Stream-Events

run.messages() liefert typisierte SDK-Nachrichten-Dataclasses. Unterscheiden Sie anhand von message.type. Alle Nachrichten enthalten agent_id und run_id, sofern die Laufzeitumgebung sie bereitstellt.

SDKMessage = (    SDKSystemMessage    | SDKUserMessageEvent    | SDKAssistantMessage    | SDKThinkingMessage    | SDKToolUseMessage    | SDKStatusMessage    | SDKTaskMessage    | SDKRequestMessage    | SDKUsageMessage    | Mapping[str, Any])
typeDataclassSchlüsselfelder
"system"SDKSystemMessagesubtype, model, tools
"user"SDKUserMessageEventmessage.content
"assistant"SDKAssistantMessagemessage.content mit TextBlock- und ToolUseBlock-Werten
"thinking"SDKThinkingMessagetext, thinking_duration_ms
"tool_call"SDKToolUseMessagecall_id, name, status, args, result, truncated
"status"SDKStatusMessagestatus, message
"task"SDKTaskMessagestatus, text
"request"SDKRequestMessagerequest_id
"usage"SDKUsageMessageusage (TokenUsage)

SDKToolUseMessage wird für die meisten Tool-Aufrufe zweimal ausgegeben: zuerst mit status="running" und ausgefülltem args, dann nach Abschluss erneut mit status="completed" (oder "error") und ausgefülltem result. truncated gibt an, ob das SDK args oder result gekürzt hat, weil die Nutzlast zu groß war.

SDKUsageMessage wird am Ende jeder Runde mit gemeldeter Token-Nutzung einmal ausgegeben und enthält die TokenUsage dieser Runde. Die kumulierte Nutzung über alle Runden hinweg bleibt in run.usage und result.usage. Siehe Token-Nutzung.

@dataclass(frozen=True)class SDKUsageMessage:    type: Literal["usage"]    agent_id: str    run_id: str    usage: TokenUsage

Ergebnisdaten (endgültiger Text, Modell, Dauer, kumulative Token-Nutzung, Git-Metadaten) befinden sich nach Abschluss des Streams im Run-Objekt. Verwende run.wait(), um sie auszulesen, einschließlich result.usage, sofern die Laufzeitumgebung diese Daten gemeldet hat.

Das Tool-call-Schema ist nicht stabil. Die args- und result-Payloads bei tool_call-Ereignissen entsprechen der internen Struktur des jeweiligen Tools und können sich weiterentwickeln, wenn sich die Tools ändern. Tool-Namen können ebenfalls umbenannt oder ersetzt werden. Behandle args und result als untypisierte Daten und parse sie defensiv. Der Ereignisrahmen (type, call_id, name, status) ist stabil.

run.events() liefert RunStreamEvent-Ereignisrahmen auf niedrigerer Ebene. Verwende sie, wenn du Offsets, Ereignisrahmen mit Endergebnissen oder rohe Interaktionsaktualisierungen benötigst:

for event in run.events():    print(event.kind, event.offset)

Interaktionsupdates

InteractionUpdate ist der rohe Delta-Typ, der beim Aufruf von agent.send() an den on_delta-Callback übergeben wird. Updates sind feingranularer als SDKMessage-Events: Text wird Token für Token gestreamt, und Tool-Aufrufe melden Teilzustände, während sich Argumente ansammeln.

InteractionUpdate = (    TextDeltaUpdate    | ThinkingDeltaUpdate    | ThinkingCompletedUpdate    | ToolCallStartedUpdate    | ToolCallCompletedUpdate    | PartialToolCallUpdate    | TokenDeltaUpdate    | StepStartedUpdate    | StepCompletedUpdate    | TurnEndedUpdate    | UserMessageAppendedUpdate    | SummaryUpdate    | SummaryStartedUpdate    | SummaryCompletedUpdate    | ShellOutputDeltaUpdate    | UnknownInteractionUpdate    | Mapping[str, Any])

PartialToolCallUpdate wird ausgegeben, während das Modell Argumente in einen Tool-Aufruf streamt, bevor dieser festgeschrieben wird. Der gleiche Stabilitätshinweis wie für SDKToolUseMessage.args gilt auch hier.

Unterhaltungstypen

Die strukturierte Ansicht der einzelnen Runden einer Ausführung, die von run.conversation() zurückgegeben wird. Jedes Element ist ein Wrapper, der den type-Diskriminator der Runde sowie die typisierte Nutzlast in turn enthält.

@dataclass(frozen=True)class ConversationTurn:    type: str  # "agentConversationTurn" | "shellConversationTurn"    turn: AgentConversationTurn | ShellConversationTurn | Mapping[str, Any]@dataclass(frozen=True)class AgentConversationTurn:    user_message: Mapping[str, Any] | None = None    steps: Sequence[ConversationStep] = ()@dataclass(frozen=True)class ShellConversationTurn:    shell_command: ShellCommand | None = None    shell_output: ShellOutput | None = NoneConversationStep = (    AssistantConversationStep    | ToolCallConversationStep    | ThinkingConversationStep    | Mapping[str, Any])

Unterscheide nach turn.type und lies die Nutzdaten über turn.turn aus:

for turn in run.conversation():    if turn.type == "agentConversationTurn":        for step in turn.turn.steps:            print(step.type)    elif turn.type == "shellConversationTurn":        print(turn.turn.shell_command, turn.turn.shell_output)

run.conversation() wird in on_step-Callbacks pro ConversationStep, nicht pro Runde ausgelöst. Tool-Call-Konversationsschritte enthalten eine Mapping[str, Any]-Nutzlast. Behandeln Sie Details von Tool-Call-Nutzlasten als untypisierte Daten; siehe den Stabilitätshinweis unter Stream-Events.

Agent wieder aufnehmen

Agent.resume(    agent_id: str,    options: AgentOptions | Mapping[str, Any] | None = None,    *,    client: CursorClient | None = None,) -> Agent

Verwenden Sie Agent.resume() oder client.agents.resume(), um anhand der ID die Verbindung zu einem bestehenden Agenten wiederherzustellen. Häufige Anwendungsfälle: erneutes Verbinden mit einem zuvor gestarteten lang laufenden Cloud-Agenten oder Fortsetzen einer Unterhaltung nach einem Neustart des lokalen Prozesses. Die Laufzeitumgebung wird anhand des ID-Präfixes automatisch erkannt (bc- steht für Cloud, alles andere für lokal).

agent = Agent.resume("bc-abc123")run = agent.send("Also update the changelog")run.wait()

Asynchrone Entsprechung:

agent = await client.agents.resume("bc-abc123")run = await agent.send("Also update the changelog")await run.wait()

agent.model ist beim Fortsetzen None, sofern du model nicht erneut übergibst. Inline-MCP-Server werden beim Fortsetzen nicht gespeichert; sie enthalten häufig Secrets und sind nur im Arbeitsspeicher vorhanden. Übergib sie beim Fortsetzen erneut oder verwende eine dateibasierte MCP-Konfiguration (.cursor/mcp.json plus local.setting_sources) für Server, die dauerhaft verfügbar sein sollen.

Lokale Persistenz

Lokale Agenten speichern den Zustand der Unterhaltung und Metadaten von Ausführungen über die Bridge, sodass Follow-ups und Agent.resume() einen Prozessneustart überstehen. Standardmäßig legt die Bridge diese Daten auf dem Datenträger in einem arbeitsbereichsspezifischen Zustandsverzeichnis ab. Cloud Agents speichern serverseitig, sodass beim Fortsetzen eines Cloud Agents von überall dieselbe Unterhaltung zurückgegeben wird.

Die lokale Persistenz ist an den Arbeitsbereich gebunden. Wenn die Bridge als langlebiger Sidecar oder Unterprozess läuft, geben Sie ihr denselben Arbeitsbereich wie dem Agenten, damit lokale List-, Get- und Resume-Aufrufe die richtigen Agenten finden. Legen Sie ihn einmal im Client fest und übergeben Sie cwd an die lokalen List- und Get-Aufrufe:

from cursor_sdk import CursorClientwith CursorClient.launch_bridge(workspace="/path/to/repo") as client:    agents = client.agents.list(runtime="local", cwd="/path/to/repo")    info = client.agents.get(agents.items[0].agent_id, cwd="/path/to/repo")

Agenten und Ausführungen prüfen

Verwenden Sie CursorClient für Listen-, Abruf- und Paginierungs-APIs.

from cursor_sdk import CursorClientwith CursorClient.launch_bridge(workspace=".") as client:    agents = client.agents.list(runtime="local", cwd=".")    for agent_info in agents.auto_paging_iter():        print(agent_info.agent_id)    info = client.agents.get(agents.items[0].agent_id)    runs = client.agents.list_runs(info.agent_id)    run = client.agents.get_run(runs.items[0].id)

Asynchrones Äquivalent:

agents = await client.agents.list(runtime="local", cwd=".")async for agent_info in agents.auto_paging_iter():    print(agent_info.agent_id)info = await client.agents.get(agents.items[0].agent_id)runs = await client.agents.list_runs(info.agent_id)run = await client.agents.get_run(runs.items[0].id)

Verwende agent.list_messages() mit einem Agent-Handle, um den Nachrichtenverlauf abzurufen. Agent.messages.list(agent_id) ist eine praktische Alternative mit typisierten Attributen für denselben Aufruf, wenn du nur eine ID hast.

Verwende Agent.get_run(run_id) oder client.agents.get_run(run_id), um eine Ausführung ohne Agent-Handle abzurufen. Brich sie mit Agent.cancel_run(run_id, agent_id=...) oder client.agents.cancel_run(run_id, agent_id=...) ab. Die Methoden des Async-Clients sind awaitable und verwenden dieselben Argumente.

AgentMessage unterscheidet sich von einer gestreamten SDKMessage:

@dataclass(frozen=True)class AgentMessage:    type: str    uuid: str    agent_id: str    message: Any = None

List-Endpunkte geben ListResult[T] zurück. Verwende .items und .next_cursor direkt, iteriere mit for item in page über die aktuelle Seite oder mit .auto_paging_iter() über alle Seiten. Asynchrone List-Endpunkte geben AsyncListResult[T] zurück; async for item in page durchläuft die aktuelle Seite und async for item in page.auto_paging_iter() alle Seiten im Ergebnissatz.

SDKAgentInfo

Die von Agent.list(), Agent.get(), client.agents.list() und client.agents.get() zurückgegebene Metadatenstruktur.

@dataclass(frozen=True)class SDKAgentInfo:    agent_id: str    name: str    summary: str    last_modified: str | None = None    status: str | None = None  # "running" | "finished" | "error"    created_at: str | None = None    archived: bool = False    runtime: Literal["local", "cloud"] | None = None    cwd: str = ""    env: CloudEnvironment | None = None    repos: Sequence[str] = ()    metadata: Mapping[str, str] = {}  # aus CloudAgentOptions.metadata; leer bei lokalen Agents

Lebenszyklus von Cloud Agents

Cloud Agents bleiben im Arbeitsbereich deines Teams, bis du sie archivierst oder löschst. client.agents.list(runtime="cloud") blendet archivierte Agents standardmäßig aus; übergib include_archived=True, um sie anzuzeigen. Filtere nach pr_url, um den Agent zu finden, der einen bestimmten Pull Request erstellt hat.

# Per ID, kein Agent-Handle erforderlich:Agent.archive(agent_id)Agent.unarchive(agent_id)Agent.delete(agent_id)# Über einen expliziten Client:client.agents.archive(agent_id)client.agents.unarchive(agent_id)client.agents.delete(agent_id)# Auf einem vorhandenen Agent-Handle:agent.archive()agent.unarchive()agent.delete()

archive archiviert den Agenten, sodass das Transkript lesbar bleibt. unarchive stellt ihn wieder her. delete löscht ihn dauerhaft; nachfolgende Lesevorgänge geben NotFoundError zurück.

Asynchrone Lifecycle-Methoden haben dieselben Namen und sind awaitable.

agent.get_usage()

Ruft die abgerechnete Token-Nutzung und die Kosten in US-Dollar für die Ausführungen eines Agenten ab. Cloud Agents geben eine Aufschlüsselung pro Ausführung zurück, lokale Agenten eine Aufschlüsselung pro Runde. Übergeben Sie run_id, um das Ergebnis auf einen Eintrag zu beschränken: für Cloud Agents eine run-<uuid>-Ausführungs-ID, für lokale Agenten eine ID aus einem vorherigen get_usage().runs[].run_id.

usage = agent.get_usage()print(f"tokens: {usage.usage.total_tokens}")if usage.cost is not None:    print(f"charged: ${usage.cost.charged_cents / 100:.2f}")for run in usage.runs:    print(run.run_id, run.usage.total_tokens)
@dataclass(frozen=True)class AgentUsage:    usage: TokenUsage              # summiert über alle `runs`    runs: Sequence[RunUsage] = ()    cost: UsageCost | None = None  # summiert über alle `runs`@dataclass(frozen=True)class RunUsage:    run_id: str    usage: TokenUsage    cost: UsageCost | None = None@dataclass(frozen=True)class UsageCost:    raw_cost_cents: float  # Modell-Token-Kosten ohne Rabatte; 0 bei anfragebasierter Nutzung    charged_cents: float   # berechneter Betrag, inklusive Rabatten und Cursor-Token-Rate

Kosten enthalten Rabatte und werden möglicherweise erst kurz nach Ende einer Ausführung endgültig abgerechnet; bis dahin ist cost None. charged_cents ist bei im Plan enthaltener Nutzung, BYOK und durch Gutschriften gewährter Nutzung 0.0.

Dies ist eine andere Ansicht als Token usage: run.usage ist die aktuelle Tokenanzahl für eine einzelne Ausführung, während get_usage() den abgerechneten Datensatz über die Ausführungen des Agenten hinweg liefert. Bei asynchronen Agenten entspricht await agent.get_usage() diesem Wert. AgentUsage, RunUsage und UsageCost werden aus cursor_sdk exportiert.

Der Cursor-Namespace

Lesevorgänge auf Konto- und Katalogebene. Sync-Methoden akzeptieren optional api_key; andernfalls verwenden sie CURSOR_API_KEY.

from cursor_sdk import Cursorme = Cursor.me()models = Cursor.models.list()repositories = Cursor.repositories.list()

Entsprechende Variante mit explizitem Client:

me = client.me()models = client.models.list()repositories = client.repositories.list()

Asynchrone Entsprechung:

from cursor_sdk import AsyncCursorme = await AsyncCursor.me(client=client)models = await AsyncCursor.models.list(client=client)repositories = await AsyncCursor.repositories.list(client=client)

Cursor.me() gibt einen SDKUser mit den Feldern api_key_name, created_at sowie den optionalen Feldern user_id, user_email, user_first_name und user_last_name zurück.

Verwenden Sie Cursor.models.list(), um gültige Modell-IDs und modellspezifische Parameter zu ermitteln, bevor Sie Agent.create() oder agent.send() aufrufen. Parameter sind modellspezifisch. Häufige Beispiele sind Denkaufwand und Cursor Routers optimize_for für auto-smart.

Der Katalog ist konto- und teamspezifisch. Cursor Router wird nur als auto-smart angezeigt, wenn Router für das Team des API-Schlüssels verfügbar ist. Siehe Cursor Router.

models = Cursor.models.list()composer = next((model for model in models if model.id == "composer-2.5"), None)print(composer.parameters if composer else [])# [#   ModelParameterDefinition(#       id="fast",#       display_name="Fast",#       values=(#           ModelParameterDefinitionValue(value="false"),#           ModelParameterDefinitionValue(value="true", display_name="Fast"),#       ),#   ),# ]

Voreingestellte variants jedes SDKModel enthalten bereits gültige params, sodass du sie in eine ModelSelection kopieren kannst.

Bevorzuge eine explizite Router-Auswahl (auto-smart + optimize_for), wenn ein Zielmodell fehlt und du Cost, Balance oder Intelligence verwenden möchtest. Greife nur auf ModelSelection(id="auto") zurück, wenn du serverseitig ausgewähltes Auto ohne Wahl eines Router-Modus verwenden möchtest. Übergib für Cursor Router optimize_for stets explizit.

Cursor.repositories.list() gibt die SCM-Repos zurück (GitHub, GitLab, Bitbucket, Azure DevOps – je nachdem, was verbunden ist), die für Cloud Agents im Konto oder Team des aufrufenden Nutzers verfügbar sind. Jedes Element stellt eine url bereit. Nutze diese, um CloudAgentOptions.repos zu befüllen.

MCP-Server

Je nach Laufzeitumgebung können Agenten MCP-Server aus Inline-Definitionen, Projekt- und Nutzereinstellungen, Plugins sowie Dashboard-verwalteten Konfigurationen übernehmen.

from cursor_sdk import (    Agent,    AgentOptions,    HttpMcpServerConfig,    LocalAgentOptions,    McpAuth,    StdioMcpServerConfig,)agent = Agent.create(    AgentOptions(        model="composer-2.5",        local=LocalAgentOptions(cwd="."),        mcp_servers={            "docs": HttpMcpServerConfig(                url="https://example.com/mcp",                auth=McpAuth(client_id="client-id", scopes=["read", "write"]),            ),            "filesystem": StdioMcpServerConfig(                command="npx",                args=["-y", "@modelcontextprotocol/server-filesystem", "."],            ),        },    ))

Flache Dictionaries ({"type": "http", "url": ...} und {"type": "stdio", "command": ...}) werden auch als praktische Kurzform für Skripte akzeptiert.

Was geladen wird

Lokale Agenten laden Server aus bis zu fünf Quellen. Bei Namenskonflikten hat die zuerst gefundene Quelle Vorrang:

  1. mcp_servers in agent.send(). Ersetzt die beim Erstellen festgelegten Server für diese Ausführung vollständig (keine Zusammenführung).
  2. mcp_servers in Agent.create(). Wird verwendet, wenn kein Override für den einzelnen Sendevorgang angegeben ist.
  3. Plugin-Server, wenn local.setting_sources "plugins" enthält.
  4. Projekt-Server aus .cursor/mcp.json, wenn local.setting_sources "project" enthält.
  5. Nutzer-Server aus ~/.cursor/mcp.json, wenn local.setting_sources "user" enthält.

Ohne local.setting_sources werden nur Inline-Server geladen. Wenn ein lokaler MCP-Server eine OAuth-Anmeldung erfordert, kann das SDK eine gespeicherte Anmeldung aus der Cursor-App wiederverwenden, aber keinen Browser öffnen, um dich anzumelden.

Cloud Agents laden Server aus:

  1. mcp_servers in agent.send(). Ersetzt die beim Erstellen festgelegten Server für diese Ausführung vollständig (keine Zusammenführung).
  2. mcp_servers in Agent.create(). Wird verwendet, wenn kein Override für den einzelnen Sendevorgang angegeben ist.
  3. Deinen Nutzer- und Team-MCP-Servern auf cursor.com/agents.

Wenn ein Inline-Server weder auth noch headers enthält und du diese Server-URL zuvor auf cursor.com/agents autorisiert hast, verwenden mit einem persönlichen API-Token authentifizierte Ausführungen diese OAuth-Token automatisch wieder. Servicekonto-API-Schlüssel können nicht auf Nutzerauthentifizierung zurückgreifen, da sie keinem Nutzer zugeordnet sind.

local.setting_sources gilt nicht für Cloud Agents.

Cloud

Cloud Agents akzeptieren auch authentifizierte MCP-Konfigurationen inline. Cloud MCP unterstützt HTTP- und stdio-Transporte. Verwenden Sie HTTP-headers für statische API-Schlüssel oder Bearer-Tokens. Verwenden Sie HTTP-auth für OAuth-geschützte Server. Verwenden Sie stdio-env, wenn der Server auf der Cloud-VM läuft und Zugangsdaten aus Umgebungsvariablen liest.

from cursor_sdk import (    Agent,    AgentOptions,    CloudAgentOptions,    CloudRepository,    HttpMcpServerConfig,    StdioMcpServerConfig,)agent = Agent.create(    AgentOptions(        model="composer-2.5",        cloud=CloudAgentOptions(            repos=[CloudRepository(url="https://github.com/your-org/your-repo")],        ),        mcp_servers={            "linear": HttpMcpServerConfig(                url="https://mcp.linear.app/mcp",                headers={"Authorization": "Bearer linear_pat_xxx"},            ),            "github": StdioMcpServerConfig(                command="npx",                args=["-y", "@modelcontextprotocol/server-github"],                env={"GITHUB_TOKEN": "ghp_xxx"},            ),        },    ))
  • HTTP-headers und auth werden von Cursors Backend verarbeitet. Sensible Felder werden geschwärzt und gelangen nicht in die VM.
  • Stdio-env-Werte werden in die VM übergeben, da der Server dort läuft. Behandeln Sie sie wie jedes andere Laufzeit-Secret.
  • OAuth für MCP-Server, die auf cursor.com/agents konfiguriert sind, bleibt nutzerbezogen – auch bei Servern auf Teamebene.

Unter MCP finden Sie das vollständige Konfigurationsformat sowie unter Cloud-Agent-Funktionen cloud-spezifisches Verhalten.

Subagenten

Definieren Sie benannte Subagenten, die der Hauptagent mit dem Tool Agent starten kann. Übergeben Sie sie inline:

from cursor_sdk import Agent, AgentDefinition, AgentOptions, LocalAgentOptionsagent = Agent.create(    AgentOptions(        model="composer-2.5",        local=LocalAgentOptions(cwd="."),        agents={            "code-reviewer": AgentDefinition(                description="Expert code reviewer for quality and security.",                prompt="Review code for bugs, security issues, and proven approaches.",                model="inherit",            ),            "test-writer": AgentDefinition(                description="Writes tests for code changes.",                prompt="Write comprehensive tests for the given code.",            ),        },    ))

Subagents, die im Repo unter .cursor/agents/*.md committed sind (mit name, description und optionalem model im Frontmatter), werden ebenfalls berücksichtigt. Inline-Definitionen überschreiben dateibasierte Definitionen mit demselben Namen.

Verschachtelte Subagenten

Subagenten können bis zu einer bestimmten Verschachtelungstiefe eigene Subagenten starten. Wenn ein Subagent das Tool Agent verwendet, greift er auf denselben Subagent-Executor wie der übergeordnete Agent zu. Dadurch kann ein übergeordneter Agent an einen Subagenten delegieren, der wiederum weiterdelegiert. Auf jeder Ebene ist dieselbe Gruppe benannter Subagenten verfügbar. Der Agent der obersten Ebene und seine direkten Subagenten können Subagenten starten, aber ein von einem anderen Subagenten gestarteter Subagent kann keine weiteren Subagenten starten.

Einschränkung des Toolsets

tools legt eine Allowlist für die integrierten Tools fest, die dem Modell zur Verfügung stehen; disallowed_tools entfernt Tools und lässt die übrigen zu, einschließlich der Tools, die nach Veröffentlichung deiner SDK-Version zur Plattform hinzugefügt wurden. Beide Optionen sind derzeit nur für lokale Agenten verfügbar und werden nicht im Agenten gespeichert: Übergib sie beim Fortsetzen erneut, um die Einschränkung beizubehalten.

from cursor_sdk import Agent, AgentOptions, LocalAgentOptions# Read-only-Agent: Nur diese Tools werden angeboten.reader = Agent.create(    AgentOptions(        model="composer-2.5",        tools=["read", "grep", "glob", "ls"],        local=LocalAgentOptions(cwd="."),    ))# Alles außer Shell-Zugriff.no_shell = Agent.create(    AgentOptions(        model="composer-2.5",        disallowed_tools=["shell"],        local=LocalAgentOptions(cwd="."),    ))
  • Wenn tools weggelassen wird, steht das Standard-Toolset des ausgewählten Modells zur Verfügung; tools=[] stellt keine integrierten Tools bereit, sodass das Modell nur mit Text antworten kann.
  • Beide Felder akzeptieren öffentliche Namen ("read", "edit", "task", "webSearch", ...) sowie die Fähigkeitsgruppen "shell" und "mcp". Unbekannte Namen lösen beim Erstellen einen BadRequestError aus.
  • Deny hat Vorrang: Damit ein Tool verfügbar ist, muss es in tools enthalten sein (falls gesetzt) und darf nicht in disallowed_tools stehen.
  • Das Deaktivieren von "mcp" entfernt auch benutzerdefinierte Tools. Das Deaktivieren von "task" verhindert Subagenten; andernfalls behalten Subagenten ihre eigenen kuratierten Toolsets.

Benutzerdefinierte Tools

Mit benutzerdefinierten Tools kannst du Python-Funktionen lokalen Agenten verfügbar machen, ohne einen separaten MCP-Server einzurichten. Übergib sie in LocalAgentOptions.custom_tools.

from cursor_sdk import Agent, CustomTool, CustomToolContext, LocalAgentOptionsdef get_deployment_status(args, context: CustomToolContext):    service = args["service"]    return f"Service {service} is healthy."with Agent.create(    model="composer-2.5",    local=LocalAgentOptions(        cwd=".",        custom_tools={            "get_deployment_status": CustomTool(                description="Look up the current deployment status for a service.",                input_schema={                    "type": "object",                    "properties": {                        "service": {"type": "string", "description": "Service name"},                    },                    "required": ["service"],                },                execute=get_deployment_status,            ),        },    ),) as agent:    agent.send("Is the checkout service healthy?").wait()

execute erhält die geparsten Argumente und, sofern verfügbar, einen CustomToolContext mit tool_call_id. Es kann einen String, einen JSON-kompatiblen Wert oder eine Zuordnung mit einer content-Liste zurückgeben. Benutzerdefinierte Tools sind ausschließlich für lokale Agenten verfügbar.

Hooks

Hooks sind ausschließlich dateibasiert. Es gibt keinen programmatischen Hook-Callback. Hooks bilden eine Richtliniengrenze auf Projektebene und sind keine Einstellung pro Ausführung.

  • Local: Füge .cursor/hooks.json zum Repo hinzu, das als local.cwd übergeben wird, oder füge ~/.cursor/hooks.json für Hooks auf Nutzerebene hinzu.
  • Cloud: Übertrage .cursor/hooks.json und die zugehörigen Skripte in das in cloud.repos übergebene Repo. Vom SDK erstellte Cloud Agents laden Projekt-Hooks automatisch. In Enterprise-Plänen führen sie außerdem Team-Hooks und Enterprise-verwaltete Hooks aus.

Unter Hooks findest du das Konfigurationsformat und unter Hook-Unterstützung für Cloud Agents Informationen zum Cloud-Verhalten.

Artefakte

Dateien aus dem Arbeitsbereich des Agenten auflisten und herunterladen.

@dataclass(frozen=True)class SDKArtifact:    path: str    size_bytes: int = 0    updated_at: str = ""
from pathlib import Pathartifacts = agent.list_artifacts()for artifact in artifacts:    print(artifact.path, artifact.size_bytes)# Ein einzelnes Artifact auf die Festplatte herunterladen.content = agent.download_artifact(artifacts[0].path)Path("review.md").write_bytes(content)

Asynchrone Agenten bieten await agent.list_artifacts() und await agent.download_artifact(path).

Die Unterstützung für Artefakte hängt von der Laufzeitumgebung ab. Lokale SDK-Agenten geben bei list_artifacts() eine leere Liste zurück und lösen bei download_artifact() eine Ausnahme aus.

Ressourcenverwaltung

Schließen Sie Agents stets, wenn Sie sie nicht mehr benötigen. Das sauberste Muster für die Synchronisierung ist ein Kontextmanager:

from cursor_sdk import Agent, LocalAgentOptionswith Agent.create(model="composer-2.5", local=LocalAgentOptions(cwd=".")) as agent:    agent.send("Summarize the repository").wait()

Zur expliziten Freigabe:

agent.close()

Asynchrone Agenten und Clients unterstützen asynchrone Kontextmanager und Bereinigung mit await:

from cursor_sdk import AsyncClient, LocalAgentOptionsasync with await AsyncClient.launch_bridge(workspace=".") as client:    async with await client.agents.create(        model="composer-2.5",        local=LocalAgentOptions(cwd="."),    ) as agent:        run = await agent.send("Summarize the repository")        await run.wait()

Zur expliziten Freigabe:

await agent.close()await client.aclose()

Der standardmäßige synchrone Client auf Modulebene wird beim Beenden des Prozesses automatisch geschlossen. Lang laufende Prozesse können ihn explizit schließen und zurücksetzen:

from cursor_sdk import close_default_clientclose_default_client()

Konfigurationsreferenz

Das Python SDK akzeptiert Hilfs-Dataclasses und einfache Dictionaries. Dataclasses verwenden Python-Felder im snake_case-Format und werden für Anwendungscode empfohlen.

AgentOptions

EigenschaftTypStandardBeschreibung
modelstr | ModelSelection | Mapping[str, Any]Für Local erforderlich; bei Cloud wird der vom Server aufgelöste Standard verwendetZu verwendendes Modell. Siehe ModelSelection.
api_keystrUmgebungsvariable CURSOR_API_KEYUser API Key oder Service-Account-Key. Team-Admin-Keys werden noch nicht unterstützt.
namestrAutomatisch generiertMenschenlesbarer Agent-Name, der in client.agents.list() / client.agents.get() angezeigt wird.
localLocalAgentOptions | Mapping[str, Any]NoneKonfiguration für Local-Agent. Übergeben Sie diese, um einen Local-Agent zu erstellen.
cloudCloudAgentOptions | Mapping[str, Any]NoneKonfiguration für Cloud-Agent. Übergeben Sie diese, um einen Cloud-Agent zu erstellen.
mcp_serversMapping[str, McpServerConfig]NoneInline-MCP-Server-Definitionen.
agentsMapping[str, AgentDefinition | Mapping[str, Any]]NoneSubagent-Definitionen.
toolsSequence[str]Standard-ToolsetDem Modell werden nur die aufgeführten integrierten Tools zur Verfügung gestellt. [] bedeutet keine integrierten Tools; das Modell kann nur mit Text antworten. Nur für Local-Agents.
disallowed_toolsSequence[str]NoneEntfernt die aufgeführten integrierten Tools; alle anderen bleiben verfügbar. Bei Kombination mit tools hat Deny Vorrang. Nur für Local-Agents.
agent_idstrAutomatisch generiertDauerhafte Agent-ID. Übergeben Sie diese, um eine stabile ID über mehrere Aufrufe hinweg beizubehalten.
idempotency_keystrFür Cloud automatisch generiertOptionaler, vom Client generierter Idempotenzschlüssel. Nur für Cloud.
mode"agent" | "plan"NoneAnfänglicher Unterhaltungsmodus für die erste Ausführung des Agent. Wenn nicht angegeben, startet der Server im Agent-Modus. Siehe Unterhaltungsmodus.

LocalAgentOptions

EigenschaftTypStandardBeschreibung
cwdstr | os.PathLikeNonePrimäres Arbeitsverzeichnis. Listen mit mehreren Einträgen werden abgelehnt; für mehrere Wurzeln dirs verwenden.
dirsSequence[str | os.PathLike]NoneZusätzliche Workspace-Ordner für Setups mit mehreren Wurzeln. Wird mit cwd zusammengeführt, sodass Regeln, Skills und Workspace-Kontext aus jedem Pfad geladen werden.
setting_sourcesSequence[SettingSource]NoneEinstellungsebenen aus der Umgebung: "project", "user", "team", "mdm", "plugins" oder "all".
sandbox_optionsSandboxOptions | Mapping[str, Any]NoneLokale Sandbox-Optionen.
storeLocalAgentStoreConfig | Mapping[str, Any]NoneLokale Store-Konfiguration, die an die Bridge übergeben wird.
auto_reviewboolNoneLokale Tool-Aufrufe über Auto-review leiten, wenn das verbundene Backend dies unterstützt.
custom_toolsMapping[str, CustomTool | Mapping[str, Any]]NoneBenutzerdefinierte Tools, die lokalen Agenten bereitgestellt werden.

CloudAgentOptions

EigenschaftTypStandardBeschreibung
envCloudEnvironment | Mapping[str, Any]NoneAusführungsumgebung. Wenn nicht angegeben, verwendet der Server von Cursor gehostete Cloud-VMs. pool und machine beziehen sich auf selbstgehostete Worker, die Sie betreiben.
reposSequence[CloudRepository | Mapping[str, Any]]NoneRepositories, die in die VM geklont werden. Lassen Sie die Angabe weg oder übergeben Sie [], um einen Agent ohne Repo mit leerem Workspace zu erstellen. Übergeben Sie für ein Repo pr_url, um den Agent an eine bestehende PR anzuhängen.
work_on_current_branchboolNoneÜberträgt Commits auf den bestehenden Branch statt auf einen neuen. Der Server behandelt einen nicht angegebenen Wert als False.
auto_create_prboolNoneÖffnet eine PR, wenn die Ausführung abgeschlossen ist. Der Server behandelt einen nicht angegebenen Wert als False.
open_as_cursor_github_appboolTrue für Service-Konto-Schlüssel, False für NutzerschlüsselÖffnet PRs als Cursor GitHub App statt als Besitzer des API-Schlüssels. Der aufgelöste Wert wird beim Erstellen, Abrufen und Auflisten zurückgegeben.
skip_reviewer_requestboolNoneÜberspringt die Anfrage, den aufrufenden Nutzer als Reviewer für die PR hinzuzufügen. Der Server behandelt einen nicht angegebenen Wert als False.
env_varsMapping[str, str]NoneAuf die Session beschränkte Umgebungsvariablen für Cloud Agents.
metadataMapping[str, str]NoneString-Tags des Aufrufers, die auf dem Cloud-Agent gespeichert werden. Siehe Agent-Metadaten.

AgentDefinition

EigenschaftTypStandardBeschreibung
descriptionstrerforderlichWann dieser Subagent verwendet werden soll. Wird dem übergeordneten Agenten angezeigt, damit dieser weiß, wann er ihn starten soll.
promptstrerforderlichSystemprompt für den Subagenten.
modelstr | ModelSelection | Mapping[str, Any] | "inherit"NoneModellüberschreibung. None und "inherit" verwenden beide die Auswahl des übergeordneten Agenten.
mcp_serversSequence[str | AgentDefinitionMcpServer | Mapping[str, Any]]NoneMCP-Server, die diesem Subagenten zur Verfügung stehen. Die Namen verweisen auf Server aus den mcp_servers des übergeordneten Agenten.

CustomTool

@dataclassclass CustomTool:    execute: Callable[[Mapping[str, Any], CustomToolContext], Any]    description: str | None = None    input_schema: Mapping[str, Any] | None = Noneclass CustomToolContext:    tool_call_id: str | None = None

ModelSelection

@dataclass(frozen=True)class ModelSelection:    id: str    params: Sequence[ModelParameterValue] = ()@dataclass(frozen=True)class ModelParameterValue:    id: str    value: str

id ist die Modellkennung (zum Beispiel "composer-2.5" oder "auto-smart"). params enthält modellspezifische Parameter wie den Denkaufwand oder optimize_for des Routers. Verwende Cursor.models.list(), um gültige IDs, Parameterdefinitionen und vordefinierte Varianten für dein Konto zu ermitteln. Informationen zum Auswahlvertrag des Routers findest du unter Cursor Router.

McpServerConfig

from cursor_sdk.types import McpServerConfig@dataclass(frozen=True)class HttpMcpServerConfig:    url: str    type: Literal["http", "sse"] | str = "http"    headers: Mapping[str, str] | None = None    auth: McpAuth | Mapping[str, Any] | None = None@dataclass(frozen=True)class SseMcpServerConfig(HttpMcpServerConfig):    type: Literal["sse"] = "sse"@dataclass(frozen=True)class StdioMcpServerConfig:    command: str    args: Sequence[str] | None = None    env: Mapping[str, str] | None = None    cwd: str | os.PathLike | None = None  # nur lokal; Cloud lehnt dieses Feld ab@dataclass(frozen=True)class McpAuth:    client_id: str    client_secret: str | None = None    scopes: Sequence[str] = ()

Bei HTTP-Servern in der Cloud werden headers und auth vom Cursor-Backend verarbeitet. Sensible Felder werden geschwärzt, bevor die VM sie sieht. Bei stdio-Servern in der Cloud werden env-Werte an die VM übergeben (behandeln Sie sie wie jedes andere Laufzeit-Secret).

Nutzernachricht

@dataclass(frozen=True)class UserMessage:    text: str    images: Sequence[SDKImage | Mapping[str, Any]] | None = None

Die strukturierte Form des Nachrichtenarguments von agent.send(). Verwenden Sie sie, um Bilder zusammen mit Text zu senden.

SDKImage

@dataclass(frozen=True)class SDKImage:    url: str | None = None    data: str | None = None    mime_type: str | None = None    dimension: SDKImageDimension | Mapping[str, Any] | None = None    @classmethod    def from_url(cls, url: str, dimension=None) -> SDKImage: ...    @classmethod    def from_data(cls, data: bytes | str, mime_type: str, dimension=None) -> SDKImage: ...    @classmethod    def url_image(cls, url: str, dimension=None) -> SDKImage: ...    @classmethod    def data_image(cls, data: str, mime_type: str, dimension=None) -> SDKImage: ...    @classmethod    def from_file(cls, path, *, mime_type=None, dimension=None) -> SDKImage: ...

Übergeben Sie entweder eine Remote-url oder base64-data mit einem mime_type. from_data() akzeptiert Bytes oder einen base64-String. from_file() liest eine Datei von der Festplatte und base64-kodiert sie.

SettingSource

SettingSource ist in cursor_sdk.types verfügbar.

from cursor_sdk.types import SettingSource

Steuert, welche Einstellungsebenen im Dateisystem ein lokaler Agent lädt. Cloud Agents laden stets project, team und plugins und ignorieren dieses Feld.

WertQuelle
"project".cursor/ im Workspace
"user"~/.cursor/
"team"Team-Einstellungen, die mit dem Dashboard synchronisiert werden
"mdm"Von MDM verwaltete Enterprise-Einstellungen
"plugins"Von Plugins bereitgestellte Einstellungen
"all"Kurzform für alle oben genannten

ListResult

@dataclass(frozen=True)class ListResult(Generic[T]):    items: list[T]    next_cursor: str = ""    def to_dict(self) -> dict[str, Any]: ...    def has_next_page(self) -> bool: ...    def next_page_info(self) -> dict[str, str]: ...    def get_next_page(self) -> ListResult[T]: ...    def auto_paging_iter(self) -> Iterator[T]: ...

Wird von client.agents.list(), client.agents.list_runs() und Agent.list() zurückgegeben. next_cursor ist leer, wenn keine weiteren Seiten verfügbar sind. Asynchrone List-Endpunkte geben AsyncListResult[T] mit awaitbaren Varianten zurück.

Fehler

Alle SDK-Fehler leiten sich von CursorAgentError ab. CursorSDKError ist der abwärtskompatible Alias als Basisklasse für ältere Aufrufer. Verwenden Sie is_retryable und retry_after, um die Wiederholungslogik zu steuern.

class CursorAgentError(Exception):    message: str    code: str | None    status: int | None    status_code: int | None    details: list[Mapping[str, Any]]    is_retryable: bool    cause: BaseException | None    proto_error_code: str | None    request_id: str | None    headers: Mapping[str, str]    retry_after: str | None
FehlerWann
AuthenticationErrorUngültiger API-Schlüssel oder nicht angemeldet.
PermissionDeniedErrorDer authentifizierte Aufrufer hat keine Berechtigung für die angeforderte Operation.
RateLimitErrorZu viele Anfragen oder Nutzungslimits überschritten.
ConfigurationErrorUngültiges Modell, fehlende erforderliche Konfiguration oder ungültige Anfrageparameter.
AgentBusyErrorSenden einer Folgeanfrage, während der Agent bereits eine Ausführung im Status CREATING oder RUNNING hat (HTTP 409, Code agent_busy).
BadRequestErrorAnfrage ist fehlerhaft.
IntegrationNotConnectedErrorErstellen eines Cloud-Agenten für ein Repo, dessen SCM-Anbieter nicht verbunden ist.
NetworkErrorDienst nicht verfügbar oder Netzwerkfehler.
APITimeoutErrorZeitüberschreitung bei der Anfrage.
InternalServerErrorDer Cursor-Dienst hat einen Serverfehler zurückgegeben.
NotFoundErrorAngeforderte Ressource wurde nicht gefunden.
AgentNotFoundErrorDer Agent existiert nicht oder ist im aktuellen Arbeitsverzeichnis nicht sichtbar.
UnsupportedRunOperationErrorDie Ausführungsoperation wird für den aktuellen Run-Status nicht unterstützt.

Wiederholungsversuche mit Backoff

is_retryable und retry_after steuern die Wiederholungslogik auf der Aufruferseite. retry_after ist ein HTTP-ähnlicher String (Sekunden oder ein HTTP-Datum), der vom Server bereitgestellt wird, wenn er gesetzt ist.

import timefrom cursor_sdk import Agent, AgentOptions, CursorAgentError, LocalAgentOptions, RateLimitErrorfor attempt in range(3):    try:        result = Agent.prompt(            "Audit the auth middleware for missing input validation",            AgentOptions(model="composer-2.5", local=LocalAgentOptions(cwd=".")),        )        break    except RateLimitError as err:        time.sleep(float(err.retry_after) if err.retry_after else 2**attempt)    except CursorAgentError as err:        if not err.is_retryable:            raise        time.sleep(2**attempt)

Jeder CursorAgentError enthält request_id, wenn der Server eine zurückgegeben hat. Protokolliere sie immer, wenn du einen Fehler anzeigst, damit der Support den Fehler nachvollziehen kann.

IntegrationNotConnectedError

class IntegrationNotConnectedError(ConfigurationError):    provider: str   # e.g. "github", "gitlab", "azuredevops"    help_url: str   # Dashboard-Link zum erneuten Verbinden

Verwenden Sie help_url, um Nutzer zum richtigen Ablauf für die erneute Verbindung zu führen. Neue Anbieter können ohne SDK-Release hinzugefügt werden.

AgentBusyError

Cloud Agents erlauben jeweils nur eine aktive Ausführung. AgentBusyError wird ausgelöst, wenn du agent.send() aufrufst (oder auf andere Weise eine Ausführung erstellst), während eine andere Ausführung auf demselben Agent noch den Status CREATING oder RUNNING hat.

is_retryable ist False. Ein sofortiger erneuter Versuch schlägt weiterhin fehl, bis die aktive Ausführung einen Endstatus erreicht oder du sie abbrichst. Andere 409-Antworten wie agent_archived lösen stattdessen ConfigurationError aus.

Warte, bis die aktive Ausführung abgeschlossen ist, brich sie mit run.cancel() ab oder frage vor dem erneuten Senden mit Agent.list_runs() regelmäßig den Status ab:

from cursor_sdk import Agent, AgentBusyErroragent = Agent.resume("bc-00000000-0000-0000-0000-000000000001")try:    agent.send("Also add tests for the auth middleware.")except AgentBusyError:    runs = Agent.list_runs(agent.agent_id, {"runtime": "cloud", "limit": 1})    active = runs.items[0] if runs.items else None    if active is not None and active.status == "running":        active.cancel()    agent.send("Also add tests for the auth middleware.")

Lokale Agenten lösen keinen AgentBusyError aus. Übergeben Sie local={"force": True} an send(), um einen hängenden lokalen Lauf zu beenden, bevor Sie einen neuen starten.

UnsupportedRunOperationError

class UnsupportedRunOperationError(ConfigurationError):    operation: str

Wird ausgelöst, wenn eine Run-Operation für die aktuelle Ausführung nicht zulässig ist. Der häufigste Fall ist run.cancel() bei einer bereits abgeschlossenen Ausführung.

run.supports(operation) und run.unsupported_reason(operation) geben an, ob eine Operation auf SDK-Ebene unterstützt wird ("stream", "wait", "cancel", "conversation"), und prüfen nicht den Run-Status. Lesen Sie run.status, bevor Sie statusabhängige Aufrufe ausführen.

Fehlerbehebung

Setzen Sie CURSOR_SDK_LOG=debug (oder info), um dem eigenen Logger des SDK einen stderr-Handler hinzuzufügen. Das SDK konfiguriert nur seinen eigenen cursor_sdk-Logger, sodass die Logging-Konfiguration der Hostanwendung nicht beeinträchtigt wird.

CURSOR_SDK_LOG=debug python my_script.py

Die mitgelieferte Bridge-Binärdatei wird zusammen mit dem Paket als cursor-sdk-bridge im PATH installiert. Führe sie direkt aus, um zu prüfen, ob dein Wheel den erwarteten Build enthält:

cursor-sdk-bridge --help

Bekannte Einschränkungen

  • Schemas für Tool-Call-Payloads sind absichtlich nicht stark typisiert.
  • Inline-MCP-Server werden nicht über Agent.resume() hinweg gespeichert. Übergeben Sie sie bei Bedarf beim Fortsetzen erneut.
  • Benutzerdefinierte Tools (local.custom_tools) und Toolset-Einschränkungen (tools, disallowed_tools) sind nur für lokale Agenten verfügbar. Die Einschränkungen werden nicht im Agenten gespeichert; übergeben Sie sie beim Fortsetzen erneut.
  • Der Download von Artefakten ist für lokale Agenten nicht implementiert.
  • local.setting_sources (und die dadurch gesteuerten dateibasierten MCP- und Subagent-Pfade) gilt nicht für Cloud Agents. Cloud lädt stets project, team und plugins.
  • Hooks sind nur dateibasiert (.cursor/hooks.json). Programmatische Callbacks werden nicht unterstützt.