Skip to main content

Command Palette

Search for a command to run...

SDK

Cursor Python SDK

cursor-sdk 패키지를 사용하면 자체 Python 코드에서 Cursor의 Agent를 호출할 수 있습니다. Cursor IDE, CLI, 웹 앱에서 실행되는 동일한 에이전트를 동기·비동기 클라이언트, 타입이 지정된 데이터클래스, 스트림과 페이지를 위한 일반적인 반복 방식을 통해 Python에서 스크립트로 제어할 수 있습니다. 시작하려면 Cursor에서 /sdk 스킬을 실행하세요.

REST API는 Cloud Agents API를 참조하세요. 다른 언어는 SDK 브리지를 참조하세요.

개요

SDK는 로컬 및 클라우드 런타임을 하나의 인터페이스로 제공합니다. 에이전트가 어디에서 실행되든 동일한 코드를 작성할 수 있습니다.

런타임기능사용 시점
로컬디스크의 로컬 파일을 대상으로 에이전트를 실행합니다.작업 트리에서 개발 스크립트 및 CI 검사를 실행할 때.
클라우드(Cursor 호스팅)리포지토리가 클론된 격리된 VM에서 실행됩니다. VM은 Cursor가 관리합니다.호출자에게 리포지토리가 없거나, 여러 에이전트를 병렬로 실행해야 하거나, 호출자의 연결이 끊어진 후에도 실행이 계속되어야 할 때.

Agent.create()local 또는 cloud를 전달해 런타임을 설정합니다.

인증

에이전트를 생성하기 전에 CURSOR_API_KEY를 설정하거나 api_key를 전달하세요.

SDK는 로컬 및 클라우드 실행 모두에서 사용자 API 키와 서비스 계정 API 키를 지원합니다. Team Admin API 키는 아직 지원되지 않습니다.

export CURSOR_API_KEY="your-key"

사용량 및 결제

SDK 실행에는 IDE 및 클라우드 에이전트 실행과 동일한 요금, 요청 풀, 프라이버시 모드 규칙이 적용됩니다. 지출 내역은 팀의 사용량 대시보드에서 SDK 태그로 표시됩니다.

코드에서 실행별 토큰 수를 확인하려면 토큰 사용량을 참조하세요. 에이전트 실행의 청구된 사용량과 달러 비용을 가져오려면 agent.get_usage()를 참조하세요.

핵심 개념

개념설명
Agent대화 상태, 워크스페이스 구성, 모델 선택 및 설정을 보유하는 영속적 핸들입니다. 여러 프롬프트에 걸쳐 유지됩니다.
Run하나의 프롬프트 제출 단위입니다. 자체 스트림, 상태, 결과, 대화 및 취소를 관리합니다.
SDKMessage실행 중 생성되는 타입이 지정된 스트림 메시지입니다. 로컬 및 클라우드 런타임에서 동일한 구조를 가집니다.
CursorClient수명 주기 제어, 사용자 정의 HTTP 옵션 설정 또는 하나의 프로세스에서 여러 워크스페이스를 사용하기 위한 명시적 클라이언트입니다. Client는 별칭입니다.
AsyncClient비동기 미러 클라이언트입니다. 모든 비동기 작업에 필요합니다.

설치

pip install cursor-sdk

Python 3.10 이상이 필요합니다.

빠른 시작

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())

스트림 이벤트에서는 도우미 텍스트를 추출하고 도구 호출을 처리하며 실행 상태를 확인하는 방법을 설명합니다. 일회성 프롬프트(생성, 실행, 완료)는 Agent.prompt()를 참조하세요.

Cloud 빠른 시작

Python SDK는 Cursor의 클라우드 에이전트를 기본적으로 지원합니다. 연결된 리포지토리 목록을 확인하고, 그중 하나에서 에이전트를 시작한 다음, 실행이 완료될 때까지 기다렸다가 최종 결과를 리뷰할 수 있습니다.

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())

SDK로 시작한 클라우드 에이전트는 기본 에이전트 목록에 표시되지 않습니다. Cursor Web 또는 Cursor 에이전트 창에서 보려면 필터 > 소스 > SDK를 클릭하세요.

비동기 사용

비동기 클라이언트는 동기 클라이언트와 동일한 인터페이스를 제공하며, 서버, 봇, 동시 에이전트 오케스트레이션에 권장됩니다. AsyncAgent, AsyncClient, AsyncRun, AsyncCursorcursor_sdkcursor_sdk.asyncio 모두에서 가져올 수 있습니다.

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())

전역 기본 async 클라이언트는 없습니다. 각 이벤트 루프가 자체 클라이언트를 갖도록 AsyncClient를 명시적으로 인스턴스화하거나, AsyncClient.launch_bridge(...)를 async 컨텍스트 관리자로 사용하세요. 동일한 코드 경로에서 sync 클라이언트와 async 클라이언트를 함께 사용하지 마세요.

SyncAsync
CursorClient / ClientAsyncClient / AsyncCursorClient
AgentAsyncAgent
RunAsyncRun
CursorAsyncCursor
ListResultAsyncListResult
DefaultHttpxClientDefaultAsyncHttpxClient

에이전트 생성

Agent.create()는 옵션을 검증하고 즉시 핸들을 반환합니다. 런타임을 선택하려면 local 또는 cloud를 지정하세요.

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는 즉시 채워집니다. 로컬 에이전트에는 agent-<uuid> ID가, 클라우드 에이전트에는 bc-<uuid> ID가 할당됩니다. agent.model은 타입이 지정된 ModelSelection이므로 agent.model.idagent.model.params를 바로 사용할 수 있습니다.

세션 환경 변수

클라우드 에이전트 실행에 단기 자격 증명이나 해당 에이전트에서만 사용해야 하는 기타 값이 필요한 경우 env_vars를 전달합니다.

agent = 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"],        },    ),)

이 값들은 저장 시 암호화되며 Cloud Agent의 셸에 주입되고 에이전트와 함께 삭제됩니다. 호출자가 agent_id를 지정한 경우에는 env_vars를 사용할 수 없습니다. agent_id는 생략하고 agent.agent_id에서 서버가 발급한 ID를 읽으세요. 변수 이름은 CURSOR_로 시작할 수 없습니다.

한 번의 실행 동안에만 존재해야 하는 값은 agent.send()에 전달하세요. 실행별 환경 변수를 참조하세요.

Agent 메타데이터

Cloud Agent를 생성할 때 자체 식별자를 추가하세요. 메타데이터를 사용하면 에이전트를 시스템의 사용자, 테넌트, 워크플로 또는 티켓에 연결할 수 있으며, client.agents.get()client.agents.list()에서 SDKAgentInfo.metadata로 다시 읽을 수 있습니다.

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)

클라우드 에이전트를 생성할 때 메타데이터를 지정할 수 있습니다. 최대 50개의 키-값 쌍을 연결할 수 있습니다. 키는 비어 있을 수 없으며 255자를 초과할 수 없습니다. 값은 4096바이트 이하의 문자열이어야 합니다. 빈 문자열 값은 허용되며, 빈 mapping은 메타데이터가 없는 것으로 처리됩니다.

모델 파라미터

ModelSelection.params를 사용해 추론 수준이나 Cursor Router의 optimize_for와 같은 모델별 옵션을 전달합니다. 파라미터 ID와 값은 모델마다 다릅니다. Cursor.models.list()를 사용해 계정에서 지원되는 파라미터와 프리셋 변형을 확인하세요.

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="."),)

특정 모델의 파라미터 ID와 프리셋 변형을 확인하려면 Cursor.models.list()를 사용하세요. auto-smart 선택 계약에 대해서는 Cursor Router를 참조하세요.

Cursor Router

Cursor Router는 각 Auto 요청에 사용할 모델을 선택합니다. SDK에서 Router는 optimize_for 파라미터를 사용하는 auto-smart 모델입니다. 팀 및 엔터프라이즈에서 사용할 수 있습니다. auto-smart가 카탈로그에 표시되려면 엔터프라이즈 관리자가 먼저 팀에 Router를 활성화해야 합니다.

Cursor SDK는 독립형 모델 추론 또는 채팅 완료 API가 아닌 에이전트 SDK입니다. Router는 워크스페이스를 분석하고, 도구를 호출하며, 명령을 실행하고, 파일을 편집할 수 있는 Cursor 에이전트 실행에 적합한 모델을 선택합니다. Cursor는 현재 임의의 모델 호출을 위한 원시 Router 엔드포인트를 문서화하지 않습니다.

Cost, Balance 또는 Intelligence 선택

auto-smart를 전달하고 optimize_for를 명시적으로 설정합니다.

제품 라벨SDK 값
Costcost
Balancebalanced
Intelligenceintelligence

제품 문구에서는 Balance를 사용하세요. balanced는 SDK 와이어 값으로만 사용하세요.

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)

항상 optimize_for를 전달하세요. 생략하거나 레거시 default 값을 보내지 마세요. 카탈로그를 통한 디스커버리가 지원되는 방식입니다.

모델 카탈로그에서 Router 확인하기

Cursor.models.list()는 API 키의 현재 계정과 팀에서 사용할 수 있는 모델, 파라미터 정의, 프리셋 변형을 반환합니다. Router를 사용할 수 있으면 Cursor Router가 auto-smart로 표시됩니다. 팀 관리자는 Router를 비활성화하거나 멤버가 선택할 수 있는 최적화 모드를 제한할 수 있습니다.

선택 항목을 하드코딩하기 전에 카탈로그를 기준 정보로 사용하세요:

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)],)

실행별 모드 전환

agent.send()에서 모델을 재정의해 실행의 Router 모드를 변경합니다:

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")],        ),    ),)

실행별 모델 재정의는 이후 실행에도 유지됩니다. 이후 재정의 없이 전송하면 새로 선택한 모델이 계속 사용됩니다. 실행별 모델 재정의를 참조하세요.

모델 ID: auto-smart, auto, default

선택의미
optimize_for와 함께 사용하는 auto-smartCursor Router. Cost, Balance 또는 Intelligence를 원하는 경우 사용합니다.
ModelSelection(id="auto")특정 모델이 카탈로그에 없을 때 서버에서 선택하는 Auto 폴백입니다. 명시적으로 Router 모드를 지정해야 한다면 auto-smart를 사용하세요.
optimize_for를 생략하거나 default를 전송지원되는 Router 계약이 아닙니다. 항상 허용된 값을 확인하고 cost, balanced, intelligence 중 하나를 전달하세요.

결제 및 라우팅 풀

  • Cost는 기존 Auto 동작과 통합 Auto 요금을 따릅니다.
  • BalanceIntelligence는 Cursor Router를 사용하며, 요금제 또는 계약에 따라 라우팅된 모델의 요율로 과금됩니다.
  • 기본 모델은 요청마다 변경될 수 있습니다. 재현 가능한 비교가 필요하면 고정된 모델 ID를 사용하세요.
  • 엔터프라이즈 모델 허용 목록은 라우팅 풀을 결정합니다. 필수 모델을 차단하면 Router가 비활성화될 수 있습니다.

현재 요율과 라우팅 풀은 Cursor Router모델 및 요금에서 확인하세요.

Router가 없을 때 문제 해결

auto-smart가 없거나 최적화 모드가 거부되는 경우:

  1. Cursor.models.list()를 호출합니다.
  2. 결과에 auto-smart가 있는지 확인합니다.
  3. optimize_for에 원하는 값(cost, balanced 또는 intelligence)이 포함되어 있는지 확인합니다.
  4. API 키와 연결된 팀에서 Router가 활성화되어 있는지 확인합니다.
  5. 여러 팀에 속해 있다면 키가 의도한 팀 컨텍스트에서 작동하는지 확인합니다.
  6. Router를 사용할 수 없거나 유효한 기본 모델을 선택할 수 없는 경우 팀의 모델 접근 정책을 확인합니다.

원시 딕셔너리

IDE 자동 완성 및 타입 검사가 더 잘 지원되므로 애플리케이션 코드에는 타입이 지정된 데이터클래스를 사용하는 것이 좋습니다. SDK는 짧은 스크립트나 외부에서 제공된 JSON을 위해 일반 딕셔너리도 허용합니다. 스네이크 케이스 키는 정규화됩니다.

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

Agent

Agent.create(), Agent.resume(), client.agents.create(), client.agents.resume()가 반환하는 핸들입니다.

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 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: ...
멤버설명
agent_id안정적인 Agent 식별자입니다. 로컬에서는 agent-<uuid>, 클라우드에서는 bc-<uuid>입니다.
model현재 타입이 지정된 모델 선택입니다. 모델 재정의로 성공적으로 전송한 후 업데이트됩니다.
send지정된 프롬프트로 새 실행을 시작합니다. Run 핸들을 반환합니다.
reload해제하지 않고 파일 시스템 구성(훅, 프로젝트 MCP, 하위 에이전트)을 다시 읽습니다.
closeAgent를 닫고 리소스를 해제합니다.
list_messagesAgent의 메시지 기록을 나열합니다.
list_artifactsAgent가 생성한 파일을 나열합니다(클라우드 전용, 로컬에서는 빈 목록 반환).
download_artifact경로로 파일을 다운로드합니다(클라우드 전용, 로컬에서는 예외 발생).
archive / unarchive / delete클라우드 Agent의 수명 주기를 관리합니다.

자동 정리를 위해 컨텍스트 관리자를 사용하세요:

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

client=를 지정하지 않고 동기 Agent.* 또는 Cursor.* 헬퍼를 사용하면 SDK가 모듈 수준의 기본 클라이언트를 시작하거나 재사용합니다. 이 클라이언트는 프로세스 종료 시 자동으로 닫히며, 다음과 같이 명시적으로 닫을 수도 있습니다:

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

일회성 편의 기능: 에이전트를 생성하고 단일 프롬프트를 전송한 뒤 실행이 완료될 때까지 기다린 후 해제합니다.

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)

비동기 버전(AsyncClient가 이미 열려 있다고 가정):

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

수명 주기를 명시적으로 제어하거나, 사용자 정의 브리지 엔드포인트 또는 HTTP 옵션을 사용하거나, 하나의 프로세스에서 여러 워크스페이스를 사용하려면 CursorClient를 사용하세요. Client도 별칭으로 사용할 수 있습니다.

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())

리소스

명시적 클라이언트는 리소스 네임스페이스를 노출합니다.

리소스동기 메서드 예시비동기 메서드 예시
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()

client.create_agent(...)client.list_agents(...)와 같은 최상위 메서드도 계속 사용할 수 있지만, 애플리케이션 코드에서는 리소스 네임스페이스 방식이 권장됩니다.

사용자 정의 HTTP 클라이언트

동기 및 비동기 클라이언트 모두 프록시, 전송 및 기타 고급 HTTP 설정을 위한 사용자 정의 httpx 클라이언트를 지원합니다:

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:    ...

DefaultHttpxClientDefaultAsyncHttpxClient는 SDK의 기본 타임아웃 및 리디렉션 동작을 유지합니다. 일반 httpx.Clienthttpx.AsyncClient는 httpx의 기본값을 사용합니다.

시간 초과 및 재시도 설정

두 클라이언트 모두 연결 설정을 공유하고 기본값을 재정의하는 얕은 복사본을 반환하는 with_options(...)를 제공합니다:

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

비동기 버전:

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="."))

메시지 전송

agent.send()Run을 반환합니다. 각 await async_agent.send()AsyncRun을 반환합니다. 에이전트는 실행 간에도 대화 컨텍스트를 유지하며, 실행은 하나의 프롬프트를 처리하는 작업 단위입니다.

print(agent.send("Find the bug in src/auth.py").text())# 같은 에이전트이므로 전체 대화 컨텍스트가 유지됩니다.print(agent.send("Fix it and add a regression test").text())

비동기 예시:

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())

텍스트와 함께 이미지를 전송하려면:

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

헬퍼 데이터클래스도 사용할 수 있습니다. SDKImage.from_file(path)는 디스크에서 파일을 읽고 base64 인코딩을 자동으로 처리합니다:

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

인코딩된 바이트 또는 원격 URL이 이미 있는 호출자는 SDKImage.data_image(base64_data, mime_type)SDKImage.url_image(url)도 사용할 수 있습니다.

실행

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  # 누적값. 라이브 handle의 property    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()run.messages()의 별칭입니다. run을 직접 순회하면 run.events()와 마찬가지로 RunStreamEvent envelope가 반환됩니다.

AsyncRunusage를 포함해 동일한 상태 필드를 제공합니다. I/O를 수행하는 메서드는 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(), async for event in run.observe().

스트리밍

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

실행 스트림은 한 번만 소비할 수 있습니다. run.messages(), run.events(), run.iter_text()는 모두 동일한 기본 스트림을 사용하며 스트림을 앞으로 진행시킵니다. 스트림이 완료되면 실행 객체에 최종 결과(run.result, run.status, run.usage, run.git, ...)가 저장됩니다. run.wait()를 호출하면 남은 이벤트를 모두 소비하고 타입이 지정된 RunResult를 반환합니다.

스트리밍 없이 기다리기

result = run.wait()print(result.status)       # "finished" | "error" | "cancelled" | "expired"print(result.result)       # 최종 assistant text(있는 경우)print(result.model)        # 이 run에 사용된 resolved ModelSelectionprint(result.duration_ms)print(result.usage)        # 누적 TokenUsage, 사용할 수 없으면 Noneprint(result.git)          # Cloud에서의 RunGitInfo

비동기 버전:

result = await run.wait()

토큰 사용량

런타임에서 제공하는 경우 실행은 토큰 사용량을 보고합니다. 스트리밍 중이거나 wait() 후 라이브 핸들의 run.usage에서 누적 합계를 확인할 수 있으며, run.wait()가 반환하는 RunResultresult.usage에서도 확인할 수 있습니다. 두 값 모두 사용량을 보고한 모든 턴의 합산 TokenUsage를 담고 있으며, 어떤 턴도 사용량을 보고하지 않았다면 None입니다. 예를 들어 턴을 완료하지 못한 취소된 실행, 사용량을 제공하지 않는 런타임, 또는 아직 사용량을 조정하지 않은 분리된 Cloud 스냅샷의 경우입니다.

@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
필드설명
input_tokens모델에 전송된 프롬프트 토큰입니다.
output_tokens모델이 생성한 토큰입니다.
cache_read_tokens프롬프트 캐시에서 제공된 토큰입니다.
cache_write_tokens프롬프트 캐시에 기록된 토큰입니다.
total_tokensinput_tokens + output_tokens + cache_read_tokens + cache_write_tokens의 합계입니다. reasoning_tokens는 제외됩니다.
reasoning_tokensoutput_tokens의 일부인 추론 토큰입니다. 모델 또는 런타임이 이를 보고하지 않은 경우 None입니다.
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는 이미 output_tokens에 포함되어 있으므로, total_tokens에는 중복 계산을 방지하기 위해 포함되지 않습니다.

스트리밍 중 턴별 수치를 확인하려면 usage 스트림 이벤트(SDKUsageMessage)를 처리하세요. 이 이벤트는 사용량이 보고된 각 턴의 종료 시 한 번 발생하며 해당 턴의 TokenUsage를 포함합니다. run.usageresult.usage는 실행 전반에 걸쳐 누적됩니다. 스트림 턴 후에는 핸들이 이 합산된 총계를 우선 사용하고, 그렇지 않은 경우 브리지가 제공하면 wait()의 사용량 또는 get_run / list_runs 스냅샷의 사용량을 사용합니다.

for message in run.messages():    if message.type == "usage":        print(f"turn used {message.usage.total_tokens} tokens")# 또는 wait 이후 / 메시지를 직접 소비하지 않고:result = run.wait()print(run.usage, result.usage)

비동기 버전: async for message in run.messages()await run.wait(). run.usageAsyncRun에서도 동기 속성입니다.

TokenUsagecursor_sdk에서 내보냅니다(고급 호출자를 위한 to_token_usage / sum_token_usage 포함). 전송 JSON은 camelCase(inputTokens, …)를 사용하고, Python 데이터클래스는 snake_case를 사용합니다.

토큰 수는 런타임에서 보고하는 값이며 비용과는 관련이 없습니다. 청구된 사용량과 에이전트 실행의 달러 비용은 agent.get_usage()를 호출해 확인하세요.

텍스트 출력 읽기

iter_text()는 스트리밍되는 도우미 텍스트를 반환합니다. text()는 최종 터미널 텍스트를 반환하며, 실행이 아직 진행 중인 경우 wait()가 완료될 때까지 기다립니다.

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

비동기 방식:

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

실행 취소

run.cancel()

비동기 방식:

await run.cancel()

run.cancel()은 활성 실행의 취소를 요청합니다. 상태가 "cancelled"로 변경되고, 라이브 스트림과 진행 중인 도구 호출이 중지되며, run.wait()status: "cancelled"로 완료됩니다. 부분 출력(지금까지 작성된 도우미 텍스트)은 Run object에 유지됩니다.

이미 종료된 실행("finished", "error", "cancelled", "expired")을 취소하면 UnsupportedRunOperationError가 발생합니다. 확실하지 않다면 run.status로 확인하세요:

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

실행 상태 확인

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()  # 리스너 제거turns = run.conversation()

run.conversation()은 타입이 지정된 list[ConversationTurn]을 반환합니다. 라이브 스트림을 구독하지 않고 구조화된 기록을 렌더링하거나 저장하는 데 사용하세요. run.conversation_json()은 원시 JSON 문자열을 반환합니다.

비동기 실행에서는 await run.conversation()await run.conversation_json()을 사용하세요.

실행별 모델 재정의

agent.send()에 전달한 model은 해당 실행에서 에이전트가 선택한 모델을 재정의하며, 이후에도 유지됩니다. 이후 재정의 없이 전송하면 새 모델이 계속 사용됩니다. 이전 모델로 전환하려면 다른 model 재정의를 전달하거나 agent.model에서 현재 선택된 모델을 확인하세요.

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.modelresult.model은 이 실행에 사용된 모델 선택을 반영하며, 실행이 시작되면 변경할 수 없습니다.

실행별 환경 변수

클라우드 에이전트는 단일 실행에만 적용되는 환경 변수도 받을 수 있습니다. SendOptionscloud.env_vars를 전달하면 해당 값이 그 실행 동안에만 에이전트의 셸에 주입됩니다. 실행이 끝나면 VM에서 제거되므로 다음 실행에서는 사용할 수 없습니다. 이는 에이전트에 사용을 요청하기 직전에 발급하는 단기 배포 토큰처럼, 턴마다 갱신되는 자격 증명에 적합합니다.

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

실행 범위 변수의 이름이 CloudAgentOptionsenv_vars에 정의된 에이전트 범위 변수와 같으면, 해당 실행에서는 실행 범위 값이 우선 적용되며 다음 실행에서는 에이전트 범위 값이 다시 적용됩니다.

실행별 변수는 첫 번째 전송에도 적용됩니다. SDK는 에이전트를 생성할 때 이를 초기 실행 범위로 함께 전달하므로 에이전트에 저장되지 않습니다. 에이전트 범위 변수와 마찬가지로 저장 시 암호화되며, 이름은 CURSOR_로 시작할 수 없습니다.

실행별 환경 변수는 클라우드 에이전트에서만 사용할 수 있으며, 공개 리포지토리에서 실행되는 에이전트에서는 사용할 수 없습니다. 로컬 에이전트의 경우 에이전트 프로세스가 사용자의 환경을 상속하므로 send()를 호출하기 전에 프로세스에 변수를 설정하세요.

대화 모드

실행 시 먼저 탐색과 계획 수립을 할지, 변경 사항을 바로 구현할지 제어하려면 mode="plan" 또는 mode="agent"를 전달하세요. 제품의 계획 모드에 대한 자세한 내용은 계획 모드를 참조하세요.

첫 번째 실행의 모드를 지정하려면 Agent.create()에 전달하는 AgentOptions에서 mode를 설정하세요. 후속 agent.send() 호출에서는 대화의 현재 모드를 유지하려면 mode를 생략하고, 해당 실행에만 다른 모드를 적용하려면 mode를 전달하세요.

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()

원시 델타 스트리밍

하위 수준의 업데이트를 받으려면 SendOptionson_deltaon_step 콜백을 전달하세요. 동기 콜백은 인라인으로 호출됩니다. 비동기 콜백은 동기 또는 비동기일 수 있으며, 다음 이벤트를 처리하기 전에 await 가능한 반환값을 대기합니다.

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()

구체적인 업데이트 및 단계 하위 클래스는 cursor_sdk.events에 정의되어 있습니다:

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

하위 호환성을 위해 cursor_sdk에서 계속 가져올 수 있지만, 새 코드에서는 cursor_sdk.events에서 가져와야 합니다.

SendOptions

속성유형설명
modelstr | ModelSelection | Mapping[str, Any]전송별 모델 재정의입니다. 생략하면 agent.model을 사용합니다. 전송에 성공한 후에도 유지됩니다.
mode"agent" | "plan"전송별 대화 모드 재정의입니다. 후속 메시지에서 생략하면 대화의 현재 모드를 유지합니다.
mcp_serversMapping[str, McpServerConfig]인라인 MCP 서버 정의입니다. 이 실행에서는 생성 시점에 지정한 서버를 완전히 대체합니다.
cloud.env_varsMapping[str, str]클라우드 에이전트 전용입니다. 이 실행에 주입되고 완료 시 제거되는 실행별 환경 변수입니다. 이 실행에서만 이름이 같은 에이전트 범위 env_vars를 재정의합니다.
local.forcebool로컬 에이전트 전용입니다. 기본값은 None(설정되지 않음)입니다. 이 메시지를 시작하기 전에 멈춘 활성 실행을 만료하려면 True로 설정합니다. Cloud는 서버 측에서 409 agent_busy를 반환하므로 이에 해당하는 기능이 필요하지 않습니다.
idempotency_keystr전송을 위한 선택적 클라이언트 생성 멱등성 키입니다.
on_stepCallable[[ConversationStep], Any]완료된 각 대화 단계(텍스트, 추론 또는 도구 배치) 후 호출되는 콜백입니다.
on_deltaCallable[[InteractionUpdate], Any]각 원시 InteractionUpdate에 대한 콜백입니다.

다음 세 섹션은 SDKMessage, InteractionUpdate, ConversationTurn에 대한 자세한 참고 자료입니다. 처음 읽을 때는 훑어보거나 건너뛰어도 됩니다. 에이전트 다시 시작하기에서 설명을 이어갑니다.

스트림 이벤트

run.messages()는 타입이 지정된 SDK 메시지 데이터클래스를 반환합니다. message.type을 기준으로 구분합니다. 런타임에서 제공하는 경우 모든 메시지에 agent_idrun_id가 포함됩니다.

SDKMessage = (    SDKSystemMessage    | SDKUserMessageEvent    | SDKAssistantMessage    | SDKThinkingMessage    | SDKToolUseMessage    | SDKStatusMessage    | SDKTaskMessage    | SDKRequestMessage    | SDKUsageMessage    | Mapping[str, Any])
typeDataclass주요 필드
"system"SDKSystemMessagesubtype, model, tools
"user"SDKUserMessageEventmessage.content
"assistant"SDKAssistantMessageTextBlockToolUseBlock 값을 포함하는 message.content
"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는 두 번 내보내집니다. 먼저 status="running"과 채워진 args를 포함해 내보내고, 완료 시에는 status="completed"(또는 "error")와 채워진 result를 포함해 다시 내보냅니다. truncated는 페이로드가 너무 커서 SDK가 args 또는 result를 잘랐는지 나타냅니다.

SDKUsageMessage는 토큰 사용량이 보고된 각 턴의 끝에 한 번 내보내며, 해당 턴의 TokenUsage를 포함합니다. 턴별 누적 합계는 run.usageresult.usage에 유지됩니다. 토큰 사용량을 참조하세요.

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

결과 데이터(최종 텍스트, 모델, 소요 시간, 누적 토큰 사용량, Git 메타데이터)는 스트림이 완료된 후 Run object에서 확인할 수 있습니다. 런타임에서 보고된 경우 result.usage를 포함해 읽으려면 run.wait()를 사용하세요.

도구 호출 스키마는 안정적이지 않습니다. tool_call 이벤트의 argsresult 페이로드는 각 도구의 내부 구조를 반영하므로, 도구가 발전하면서 변경될 수 있습니다. 도구 이름도 변경되거나 대체될 수 있습니다. argsresult는 비정형 데이터로 취급하고 방어적으로 파싱하세요. 이벤트 envelope(type, call_id, name, status)는 안정적입니다.

run.events()는 하위 수준의 RunStreamEvent envelope를 반환합니다. 오프셋, 터미널 결과 envelope 또는 원시 상호작용 업데이트가 필요할 때 사용하세요:

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

상호작용 업데이트

InteractionUpdateagent.send()on_delta 콜백에 전달되는 원시 델타 유형입니다. 업데이트는 SDKMessage 이벤트보다 더 세분화되어 있습니다. 텍스트는 토큰 단위로 스트리밍되며, 도구 호출은 인수가 누적됨에 따라 부분 상태를 보고합니다.

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

PartialToolCallUpdate는 모델이 도구 호출에 인수를 스트리밍하고 확정하기 전에 내보내집니다. SDKToolUseMessage.args에 적용되는 안정성 관련 고지가 여기에도 동일하게 적용됩니다.

대화 유형

run.conversation()에서 반환되는 실행의 구조화된 턴별 뷰입니다. 각 항목은 턴의 type 판별자와 turn에 담긴 타입이 지정된 페이로드를 함께 포함하는 래퍼입니다.

@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])

turn.type으로 유형을 구분하고 turn.turn을 통해 페이로드를 읽습니다:

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)

on_step 콜백에서 run.conversation()은 턴마다가 아니라 ConversationStep마다 실행됩니다. 도구 호출 대화 단계에는 Mapping[str, Any] 페이로드가 포함됩니다. 도구 호출 페이로드의 세부 정보는 타입이 지정되지 않은 데이터로 취급하세요. Stream events 아래의 안정성 참고 사항을 참조하세요.

에이전트 다시 시작하기

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

Agent.resume() 또는 client.agents.resume()를 사용해 ID로 기존 에이전트에 다시 연결합니다. 일반적으로 이전에 시작한 장기 실행 Cloud Agent에 다시 연결하거나, 로컬 프로세스 재시작 후 대화를 이어갈 때 사용합니다. 런타임은 ID 접두사로 자동 감지됩니다(bc-는 cloud, 그 외는 local).

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

비동기 버전:

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

재개 시 model을 다시 전달하지 않으면 agent.modelNone입니다. 인라인 MCP 서버는 재개 후에도 유지되지 않습니다. 시크릿을 포함하는 경우가 많으며 메모리에만 존재하기 때문입니다. 재개할 때 다시 전달하거나, 유지해야 하는 서버에는 파일 기반 MCP 구성(.cursor/mcp.jsonlocal.setting_sources)을 사용하세요.

로컬 영속성

로컬 에이전트는 브리지를 통해 대화 상태와 실행 메타데이터를 저장하므로 후속 요청과 Agent.resume()이 프로세스 재시작 후에도 유지됩니다. 브리지는 기본적으로 이를 워크스페이스별 상태 루트 아래 디스크에 저장합니다. Cloud Agent는 서버 측에 저장되므로 어디서든 Cloud Agent를 재개하면 동일한 대화가 반환됩니다.

로컬 영속성은 워크스페이스 단위로 적용됩니다. 브리지가 장기 실행 사이드카 또는 하위 프로세스로 실행되는 경우, 로컬 list, get, resume 호출이 올바른 에이전트를 찾도록 에이전트와 동일한 워크스페이스를 지정하세요. 클라이언트에서 한 번 설정하고 로컬 list 및 get 호출에 cwd를 전달하세요:

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")

에이전트 및 실행 조회

목록 조회, 가져오기, 페이지네이션 API에는 CursorClient를 사용합니다.

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)

비동기 버전:

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)

에이전트 핸들에서 agent.list_messages()를 사용해 메시지 기록을 읽습니다. ID만 있는 경우에는 동일한 호출을 위해 타입이 지정된 속성을 편리하게 사용할 수 있는 Agent.messages.list(agent_id)를 사용합니다.

목록 엔드포인트는 ListResult[T]를 반환합니다. .items.next_cursor를 직접 사용하거나, for item in page로 현재 페이지를 순회하거나, .auto_paging_iter()로 모든 페이지를 순회합니다. 비동기 목록 엔드포인트는 AsyncListResult[T]를 반환합니다. async for item in page는 현재 페이지를 순회하며, async for item in page.auto_paging_iter()는 결과 집합의 모든 페이지를 순회합니다.

SDKAgentInfo

Agent.list(), Agent.get(), client.agents.list(), client.agents.get()가 반환하는 메타데이터 구조입니다.

@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] = {}  # CloudAgentOptions.metadata에서 가져옴, 로컬 에이전트는 비어 있음

클라우드 에이전트 수명 주기

클라우드 에이전트는 보관하거나 삭제할 때까지 팀 워크스페이스에 유지됩니다. client.agents.list(runtime="cloud")은 기본적으로 보관된 에이전트를 숨깁니다. 보관된 에이전트를 보려면 include_archived=True를 전달하세요. 특정 풀 리퀘스트를 생성한 에이전트를 찾으려면 pr_url로 필터링하세요.

# ID로 호출, agent handle 불필요:Agent.archive(agent_id)Agent.unarchive(agent_id)Agent.delete(agent_id)# 명시적인 client를 통해 호출:client.agents.archive(agent_id)client.agents.unarchive(agent_id)client.agents.delete(agent_id)# 기존 agent handle에서 호출:agent.archive()agent.unarchive()agent.delete()

archive는 에이전트를 소프트 삭제하여 transcript를 계속 읽을 수 있게 합니다. unarchive는 이를 복원합니다. delete는 영구 삭제되며, 이후 읽기 작업은 NotFoundError를 반환합니다.

비동기 수명 주기 메서드도 같은 이름을 사용하며 await할 수 있습니다.

agent.get_usage()

에이전트 실행에 청구된 토큰 사용량과 달러 비용을 가져옵니다. 클라우드 에이전트는 실행별 세부 내역을 반환하고, 로컬 에이전트는 턴별 세부 내역을 반환합니다. 결과를 하나의 항목으로 제한하려면 run_id를 전달하세요. 클라우드 에이전트에는 run-<uuid> 형식의 실행 ID를, 로컬 에이전트에는 이전 get_usage().runs[].run_id에서 얻은 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              # `runs` 전체 합계    runs: Sequence[RunUsage] = ()    cost: UsageCost | None = None  # `runs` 전체 합계@dataclass(frozen=True)class RunUsage:    run_id: str    usage: TokenUsage    cost: UsageCost | None = None@dataclass(frozen=True)class UsageCost:    raw_cost_cents: float  # 할인 적용 전 모델 토큰 비용, 요청 단위 과금 사용량은 0    charged_cents: float   # 청구 금액, 할인과 Cursor 토큰 요율 반영

비용에는 할인 금액이 포함되며, 실행이 끝난 후 정산되기까지 잠시 걸릴 수 있습니다. 정산되기 전까지 costNone입니다. 요금제 포함 사용량, BYOK 및 크레딧 부여 사용량의 경우 charged_cents0.0입니다.

이는 토큰 사용량과는 다른 관점입니다. run.usage는 한 번의 실행에 대한 실시간 토큰 수이고, get_usage()는 에이전트의 모든 실행에 대한 청구 기록입니다. Async 에이전트에서는 await agent.get_usage()도 동일합니다. AgentUsage, RunUsage, UsageCostcursor_sdk에서 내보냅니다.

Cursor 네임스페이스

계정 수준 및 카탈로그 조회 기능을 제공합니다. 동기화 메서드는 선택적으로 api_key를 받으며, 지정하지 않으면 CURSOR_API_KEY를 사용합니다.

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

명시적 클라이언트 사용 예시:

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

비동기 버전:

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

Agent.create() 또는 agent.send()를 호출하기 전에 Cursor.models.list()를 사용해 유효한 모델 ID와 모델별 파라미터를 확인하세요. 파라미터는 모델마다 다릅니다. 일반적인 예로는 추론 수준과 auto-smart의 Cursor Router optimize_for가 있습니다.

카탈로그는 계정과 팀에 따라 다릅니다. Cursor Router는 API 키의 팀에서 Router를 사용할 수 있을 때만 auto-smart로 표시됩니다. 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"),#       ),#   ),# ]

SDKModel의 사전 설정된 variants에는 이미 유효한 params가 포함되어 있으므로, 이를 ModelSelection에 복사할 수 있습니다.

대상 모델이 없고 Cost, Balance 또는 Intelligence를 원하는 경우 명시적으로 Router를 선택하세요(auto-smart + optimize_for). Router mode를 선택하지 않고 서버가 선택한 Auto를 사용하려는 경우에만 ModelSelection(id="auto")로 대체하세요. Cursor Router에서는 항상 optimize_for를 명시적으로 전달하세요.

Cursor.repositories.list()는 호출한 계정 또는 팀의 클라우드 에이전트에서 사용할 수 있는 SCM 리포지토리(연결된 서비스에 따라 GitHub, GitLab, Bitbucket, Azure DevOps)를 반환합니다. 각 항목에는 url이 제공됩니다. 이를 사용해 CloudAgentOptions.repos를 채우세요.

MCP 서버

에이전트는 런타임에 따라 인라인 정의, 프로젝트/사용자 설정, 플러그인 또는 대시보드에서 관리되는 구성의 MCP 서버를 사용할 수 있습니다.

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", "."],            ),        },    ))

평면 구조 딕셔너리({"type": "http", "url": ...}{"type": "stdio", "command": ...})도 빠른 스크립트 작성을 위해 간편하게 사용할 수 있습니다.

로드되는 항목

로컬 에이전트는 최대 5개 소스에서 서버를 로드합니다. 이름이 충돌하면 먼저 일치하는 항목이 우선합니다.

  1. agent.send()mcp_servers: 해당 실행의 생성 시점 서버를 완전히 대체합니다(병합되지 않음).
  2. Agent.create()mcp_servers: 전송별 재정의가 없을 때 사용됩니다.
  3. local.setting_sources"plugins"가 포함된 경우의 플러그인 서버.
  4. local.setting_sources"project"가 포함된 경우 .cursor/mcp.json의 프로젝트 서버.
  5. local.setting_sources"user"가 포함된 경우 ~/.cursor/mcp.json의 사용자 서버.

local.setting_sources가 없으면 인라인 서버만 로드됩니다. 로컬 MCP 서버에 OAuth 로그인이 필요한 경우 SDK는 Cursor 앱에 저장된 로그인 정보를 재사용할 수 있지만, 로그인할 수 있도록 브라우저를 열 수는 없습니다.

클라우드 에이전트는 다음 소스에서 서버를 로드합니다.

  1. agent.send()mcp_servers: 해당 실행의 생성 시점 서버를 완전히 대체합니다(병합되지 않음).
  2. Agent.create()mcp_servers: 전송별 재정의가 없을 때 사용됩니다.
  3. cursor.com/agents의 사용자 및 팀 MCP 서버.

인라인 서버에 auth 또는 headers가 없고 이전에 cursor.com/agents에서 해당 서버 URL을 승인한 경우, 개인 API 토큰으로 인증된 실행은 해당 OAuth 토큰을 자동으로 재사용합니다. 서비스 계정 API 키는 사용자와 연결되어 있지 않으므로 사용자 인증으로 대체할 수 없습니다.

local.setting_sources는 클라우드 에이전트에 적용되지 않습니다.

Cloud

클라우드 에이전트는 인증된 MCP config도 인라인으로 지원합니다. Cloud MCP는 HTTP 및 stdio 전송 방식을 지원합니다. 정적 API 키 또는 Bearer 토큰에는 HTTP headers를 사용하세요. OAuth로 보호되는 서버에는 HTTP auth를 사용하세요. 서버가 클라우드 VM에서 실행되며 환경 변수에서 자격 증명을 읽는 경우 stdio env를 사용하세요.

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 headersauth는 Cursor 백엔드에서 처리됩니다. 민감한 필드는 마스킹되며 VM으로 전달되지 않습니다.
  • 서버가 VM에서 실행되므로 Stdio env 값은 VM으로 전달됩니다. 다른 런타임 시크릿과 마찬가지로 취급하세요.
  • cursor.com/agents에서 구성된 MCP 서버의 OAuth는 팀 단위 서버에서도 사용자별로 유지됩니다.

전체 구성 형식은 MCP를, Cloud 관련 동작은 Cloud Agent 기능을 참조하세요.

하위 에이전트

주 에이전트가 Agent 도구를 통해 생성할 수 있도록 이름을 지정한 하위 에이전트를 정의합니다. 인라인으로 전달합니다:

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.",            ),        },    ))

리포지토리의 .cursor/agents/*.md에 커밋된 하위 에이전트(name, description, 선택 사항인 model 프론트매터 포함)도 자동으로 감지됩니다. 이름이 같은 경우 인라인 정의가 파일 기반 정의보다 우선합니다.

중첩된 하위 에이전트

하위 에이전트는 중첩 한도 내에서 자체 하위 에이전트를 생성할 수 있습니다. 하위 에이전트가 Agent 도구를 사용하면 부모 에이전트와 동일한 하위 에이전트 executor에 연결되므로, 부모 에이전트는 추가로 작업을 위임하는 하위 에이전트에 작업을 위임할 수 있습니다. 각 수준에서 동일한 이름의 하위 에이전트 집합을 확인할 수 있습니다. 최상위 에이전트와 그 직속 하위 에이전트는 하위 에이전트를 시작할 수 있지만, 다른 하위 에이전트가 시작한 하위 에이전트는 더 이상 하위 에이전트를 시작할 수 없습니다.

도구 세트 제한

tools는 모델에 제공되는 기본 제공 도구의 허용 목록을 지정합니다. disallowed_tools는 지정한 도구를 제외하고, SDK 버전 출시 후 플랫폼에 추가된 도구를 포함한 나머지 도구는 유지합니다. 현재 둘 다 로컬 에이전트에서만 사용할 수 있으며, 에이전트에 저장되지 않습니다. 제한을 유지하려면 재개할 때 다시 전달하세요.

from cursor_sdk import Agent, AgentOptions, LocalAgentOptions# 읽기 전용 Agent: 이 도구들만 제공됩니다.reader = Agent.create(    AgentOptions(        model="composer-2.5",        tools=["read", "grep", "glob", "ls"],        local=LocalAgentOptions(cwd="."),    ))# shell 접근만 제외한 나머지 전체.no_shell = Agent.create(    AgentOptions(        model="composer-2.5",        disallowed_tools=["shell"],        local=LocalAgentOptions(cwd="."),    ))
  • tools를 생략하면 선택한 모델에 표준 도구 세트가 제공됩니다. tools=[]를 지정하면 기본 제공 도구가 없으므로 모델은 텍스트로만 응답할 수 있습니다.
  • 두 필드 모두 공개 이름("read", "edit", "task", "webSearch", ...)과 기능 그룹 "shell", "mcp"를 허용합니다. 알 수 없는 이름을 지정하면 생성 시 BadRequestError가 발생합니다.
  • 거부가 우선합니다. 도구가 제공되려면 tools(설정된 경우)에 포함되어 있으면서 disallowed_tools에는 없어야 합니다.
  • "mcp"를 비활성화하면 사용자 정의 도구도 제거됩니다. "task"를 비활성화하면 하위 에이전트를 사용할 수 없습니다. 그렇지 않으면 하위 에이전트는 자체적으로 선별된 도구 세트를 유지합니다.

사용자 정의 도구

별도의 MCP 서버를 구축하지 않고도 Python 함수를 로컬 에이전트에서 사용할 수 있도록 사용자 정의 도구로 노출할 수 있습니다. 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는 파싱된 인수와, उपलब्ध한 경우 tool_call_id를 포함하는 CustomToolContext를 받습니다. 문자열, JSON 호환 값 또는 content 목록을 포함하는 매핑을 반환할 수 있습니다. 사용자 정의 도구는 로컬 에이전트에서만 사용할 수 있습니다.

훅은 파일 기반으로만 지원됩니다. 프로그래밍 방식의 훅 콜백은 없습니다. 훅은 실행마다 조정하는 옵션이 아니라 프로젝트 정책의 경계입니다.

  • Local: local.cwd로 전달한 리포지토리에 .cursor/hooks.json을 추가하거나, 사용자 수준 훅에는 ~/.cursor/hooks.json을 추가합니다.
  • Cloud: cloud.repos로 전달한 리포지토리에 .cursor/hooks.json과 해당 스크립트를 커밋합니다. SDK로 생성한 클라우드 에이전트는 프로젝트 훅을 자동으로 로드합니다. 엔터프라이즈 요금제에서는 팀 훅과 엔터프라이즈 관리 훅도 실행합니다.

구성 형식은 을, 클라우드 동작은 Cloud Agents 훅 지원을 참조하세요.

아티팩트

에이전트의 워크스페이스에 있는 파일을 확인하고 다운로드합니다.

@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)# artifact 하나를 디스크에 다운로드합니다.content = agent.download_artifact(artifacts[0].path)Path("review.md").write_bytes(content)

Async 에이전트에서는 await agent.list_artifacts()await agent.download_artifact(path)를 사용할 수 있습니다.

Artifact 지원 여부는 런타임에 따라 다릅니다. Local SDK 에이전트의 list_artifacts()는 빈 목록을 반환하며, download_artifact()는 예외를 발생시킵니다.

리소스 관리

작업이 끝나면 항상 에이전트를 종료하세요. 가장 깔끔한 동기화 방식은 컨텍스트 관리자를 사용하는 것입니다:

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

명시적으로 리소스를 해제하려면:

agent.close()

Async 에이전트와 클라이언트는 비동기 컨텍스트 관리자 및 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()

명시적으로 리소스를 해제하려면:

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

모듈 수준의 동기 기본 클라이언트는 프로세스 종료 시 자동으로 닫힙니다. 장기 실행 프로세스에서는 이를 명시적으로 닫고 재설정할 수 있습니다:

from cursor_sdk import close_default_clientclose_default_client()

구성 참고

Python SDK는 헬퍼 데이터클래스와 원시 딕셔너리를 지원합니다. 데이터클래스는 Python snake_case 필드를 사용하며, 애플리케이션 코드에서는 데이터클래스 사용을 권장합니다.

AgentOptions

속성유형기본값설명
modelstr | ModelSelection | Mapping[str, Any]로컬에서는 필수, 클라우드에서는 서버에서 확인된 기본값 사용사용할 모델입니다. ModelSelection을 참조하세요.
api_keystrCURSOR_API_KEY 환경 변수사용자 API 키 또는 서비스 계정 키입니다. 팀 관리자 키는 아직 지원되지 않습니다.
namestr자동 생성client.agents.list() / client.agents.get()에 표시되는 사람이 읽기 쉬운 에이전트 이름입니다.
localLocalAgentOptions | Mapping[str, Any]None로컬 에이전트 구성입니다. 로컬 에이전트를 생성할 때 전달합니다.
cloudCloudAgentOptions | Mapping[str, Any]NoneCloud Agent 구성입니다. Cloud Agent를 생성할 때 전달합니다.
mcp_serversMapping[str, McpServerConfig]None인라인 MCP 서버 정의입니다.
agentsMapping[str, AgentDefinition | Mapping[str, Any]]None하위 에이전트 정의입니다.
toolsSequence[str]기본 도구 세트나열된 기본 제공 도구만 모델에서 사용할 수 있습니다. []는 기본 제공 도구가 없음을 의미하며, 모델은 텍스트로만 응답할 수 있습니다. 로컬 에이전트 전용입니다.
disallowed_toolsSequence[str]None나열된 기본 제공 도구를 제외하며, 그 외의 모든 도구는 계속 사용할 수 있습니다. tools와 함께 사용하면 거부가 우선합니다. 로컬 에이전트 전용입니다.
agent_idstr자동 생성영속적인 에이전트 ID입니다. 호출 간에 동일한 ID를 유지하려면 전달하세요.
idempotency_keystr클라우드에서 자동 생성선택 사항인 클라이언트 생성 멱등성 키입니다. 클라우드 전용입니다.
mode"agent" | "plan"None에이전트의 첫 실행에 적용되는 초기 대화 모드입니다. 생략하면 서버는 Agent 모드로 시작합니다. 대화 모드를 참조하세요.

LocalAgentOptions

속성유형기본값설명
cwdstr | os.PathLikeNone기본 작업 디렉터리입니다. 여러 항목이 포함된 목록은 허용되지 않으므로, 다중 루트에는 dirs를 사용하세요.
dirsSequence[str | os.PathLike]None다중 루트 설정을 위한 추가 워크스페이스 폴더입니다. cwd와 병합되며, 모든 경로에서 규칙, 스킬, 워크스페이스 컨텍스트를 로드합니다.
setting_sourcesSequence[SettingSource]None적용되는 설정 계층입니다: "project", "user", "team", "mdm", "plugins" 또는 "all".
sandbox_optionsSandboxOptions | Mapping[str, Any]None로컬 샌드박스 옵션입니다.
storeLocalAgentStoreConfig | Mapping[str, Any]None브리지에 전달되는 로컬 스토어 구성입니다.
auto_reviewboolNone연결된 백엔드에서 지원하는 경우 로컬 도구 호출을 Auto-review를 통해 라우팅합니다.
custom_toolsMapping[str, CustomTool | Mapping[str, Any]]None로컬 에이전트에 노출되는 사용자 정의 도구입니다.

CloudAgentOptions

속성유형기본값설명
envCloudEnvironment | Mapping[str, Any]None실행 환경입니다. 생략하면 서버에서 Cursor 호스팅 클라우드 VM을 사용합니다. poolmachine은 사용자가 운영하는 자체 호스팅 워커를 대상으로 합니다.
reposSequence[CloudRepository | Mapping[str, Any]]NoneVM에 클론할 저장소입니다. 빈 워크스페이스를 사용하는 저장소 없는 에이전트의 경우 reposenv를 모두 생략하세요. 기존 PR에 에이전트를 연결하려면 저장소에 pr_url을 전달하세요.
work_on_current_branchboolNone새 브랜치 대신 기존 브랜치에 커밋을 푸시합니다. 서버는 생략된 값을 False로 처리합니다.
auto_create_prboolNone실행이 완료되면 PR을 엽니다. 서버는 생략된 값을 False로 처리합니다.
open_as_cursor_github_appbool서비스 계정 키의 경우 True, 사용자 키의 경우 FalseAPI 키 소유자 대신 Cursor GitHub App으로 PR을 엽니다. 확인된 값은 생성, 가져오기, 목록 조회 시 반환됩니다.
skip_reviewer_requestboolNonePR에서 호출한 사용자를 리뷰어로 요청하지 않습니다. 서버는 생략된 값을 False로 처리합니다.
env_varsMapping[str, str]None클라우드 에이전트용 세션 범위 환경 변수입니다.
metadataMapping[str, str]None클라우드 에이전트에 유지되는 호출자 소유 문자열 태그입니다. 에이전트 메타데이터를 참조하세요.

AgentDefinition

속성유형기본값설명
descriptionstr필수이 하위 에이전트를 언제 사용할지 설명합니다. 상위 에이전트가 언제 생성해야 하는지 알 수 있도록 표시됩니다.
promptstr필수하위 에이전트의 시스템 프롬프트입니다.
modelstr | ModelSelection | Mapping[str, Any] | "inherit"None모델 재정의입니다. None"inherit"는 모두 상위 에이전트의 선택을 사용합니다.
mcp_serversSequence[str | AgentDefinitionMcpServer | Mapping[str, Any]]None이 하위 에이전트에서 사용할 수 있는 MCP 서버입니다. 이름은 상위 에이전트의 mcp_servers에 있는 서버를 참조합니다.

사용자 정의 도구

@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는 모델 식별자입니다(예: "composer-2.5" 또는 "auto-smart"). params에는 추론 노력이나 Router's optimize_for 같은 모델별 파라미터가 포함됩니다. Cursor.models.list()를 사용하여 계정에서 사용할 수 있는 ID, 파라미터 정의 및 프리셋 변형을 확인하세요. Router 선택 계약은 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  # 로컬 전용, 클라우드에서는 이 필드를 거부함@dataclass(frozen=True)class McpAuth:    client_id: str    client_secret: str | None = None    scopes: Sequence[str] = ()

클라우드에서 실행되는 HTTP 서버의 경우 headersauth는 Cursor 백엔드에서 처리합니다. 민감한 필드는 VM에 전달되기 전에 가려집니다. 클라우드에서 실행되는 stdio 서버의 경우 env 값은 VM에 전달됩니다(다른 런타임 시크릿과 마찬가지로 취급하세요).

UserMessage

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

agent.send()message 인수에 사용하는 구조화된 형식입니다. 텍스트와 함께 이미지를 전송할 때 사용합니다.

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: ...

mime_type와 함께 원격 url 또는 base64 data를 전달합니다. from_data()는 바이트 또는 base64 문자열을 허용합니다. from_file()는 디스크의 파일을 읽어 base64로 인코딩합니다.

SettingSource

SettingSourcecursor_sdk.types에서 제공됩니다.

from cursor_sdk.types import SettingSource

로컬 에이전트가 로드할 로컬 디스크 설정 계층을 제어합니다. 클라우드 에이전트는 항상 project, team, plugins를 로드하며 이 필드는 무시합니다.

소스
"project"워크스페이스의 .cursor/
"user"~/.cursor/
"team"대시보드에서 동기화된 팀 설정
"mdm"MDM으로 관리되는 엔터프라이즈 설정
"plugins"플러그인에서 제공하는 설정
"all"위 항목 전체의 약칭

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]: ...

client.agents.list(), client.agents.list_runs(), Agent.list()에서 반환됩니다. 더 이상 페이지가 없으면 next_cursor는 비어 있습니다. 비동기 목록 엔드포인트는 대기 가능한 해당 메서드와 함께 AsyncListResult[T]를 반환합니다.

오류

모든 SDK 오류는 CursorAgentError를 상속합니다. CursorSDKError는 이전 호출자와의 호환성을 위해 제공되는 루트 별칭입니다. is_retryableretry_after를 사용해 재시도 로직을 구현하세요.

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    request_id: str | None    headers: Mapping[str, str]    retry_after: str | None
오류발생 조건
AuthenticationErrorAPI 키가 유효하지 않거나 로그인되지 않았습니다.
PermissionDeniedError인증된 호출자에게 요청한 작업을 수행할 권한이 없습니다.
RateLimitError요청이 너무 많거나 사용량 한도를 초과했습니다.
ConfigurationError모델이 유효하지 않거나, 필수 구성이 누락되었거나, 요청 파라미터가 잘못되었습니다.
AgentBusyError에이전트에 이미 CREATING 또는 RUNNING 상태의 실행이 있을 때 후속 요청을 보냅니다(HTTP 409, 코드 agent_busy).
BadRequestError요청 형식이 잘못되었습니다.
IntegrationNotConnectedErrorSCM 공급자가 연결되지 않은 리포지토리에 대해 Cloud Agent를 생성합니다.
NetworkError서비스를 사용할 수 없거나 네트워크 오류가 발생했습니다.
APITimeoutError요청 시간이 초과되었습니다.
InternalServerErrorCursor 서비스가 서버 오류를 반환했습니다.
NotFoundError요청한 리소스를 찾을 수 없습니다.
AgentNotFoundError에이전트가 존재하지 않거나 현재 작업 디렉터리에서 확인할 수 없습니다.
UnsupportedRunOperationError현재 실행 상태에서는 실행 작업이 지원되지 않습니다.

백오프 재시도

is_retryableretry_after는 호출자 측의 재시도 로직을 결정합니다. retry_after는 설정된 경우 서버가 제공하는 HTTP 형식의 문자열(초 또는 HTTP 날짜)입니다.

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)

서버에서 반환된 경우 모든 CursorAgentErrorrequest_id가 포함됩니다. 오류를 노출할 때마다 이를 로그에 기록해 지원팀이 실패 원인을 파악할 수 있도록 하세요.

IntegrationNotConnectedError

class IntegrationNotConnectedError(ConfigurationError):    provider: str   # e.g. "github", "gitlab", "azuredevops"    help_url: str   # 다시 연결할 수 있는 대시보드 링크

help_url을 사용해 사용자에게 올바른 재연결 절차를 안내하세요. SDK 릴리스 없이 새 공급자가 추가될 수 있습니다.

AgentBusyError

클라우드 에이전트는 한 번에 하나의 활성 실행만 허용합니다. 동일한 에이전트에서 다른 실행이 아직 CREATING 또는 RUNNING 상태일 때 agent.send()를 호출하거나 다른 방식으로 실행을 생성하면 AgentBusyError가 발생합니다.

is_retryableFalse입니다. 활성 실행이 종료 상태에 도달하거나 취소되기 전까지 즉시 재시도하면 계속 실패합니다. agent_archived와 같은 다른 409 응답은 대신 ConfigurationError를 발생시킵니다.

다시 전송하기 전에 활성 실행이 완료될 때까지 기다리거나, run.cancel()로 취소하거나, Agent.list_runs()를 폴링하세요:

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.")

로컬 에이전트는 AgentBusyError를 발생시키지 않습니다. 새 실행을 시작하기 전에 중단된 로컬 실행을 종료하려면 send()local={"force": True}를 전달하세요.

UnsupportedRunOperationError

class UnsupportedRunOperationError(ConfigurationError):    operation: str

현재 실행에서 Run 작업이 허용되지 않는 경우 발생합니다. 가장 일반적인 경우는 이미 종료된 실행에서 run.cancel()을 호출하는 것입니다.

run.supports(operation)run.unsupported_reason(operation)은 작업 이름("stream", "wait", "cancel", "conversation")에 대한 SDK 수준의 지원 여부를 반환하며, 실행 상태는 확인하지 않습니다. 상태에 따라 달라지는 호출을 보호하려면 run.status를 확인하세요.

문제 해결

SDK 자체 로거에 stderr 핸들러를 연결하려면 CURSOR_SDK_LOG=debug(또는 info)로 설정합니다. SDK는 자체 cursor_sdk 로거만 구성하므로 호스트 애플리케이션의 로깅 설정에 영향을 주지 않습니다.

CURSOR_SDK_LOG=debug python my_script.py

번들로 제공되는 브리지 바이너리는 패키지와 함께 PATH에 cursor-sdk-bridge라는 이름으로 설치됩니다. wheel에 포함된 build를 확인하려면 직접 실행하세요:

cursor-sdk-bridge --help

알려진 제한 사항

  • 도구 호출 페이로드 스키마는 의도적으로 강한 타입 지정을 지원하지 않습니다.
  • 인라인 MCP 서버는 Agent.resume() 후에도 유지되지 않습니다. 필요하면 재개 시 다시 전달하세요.
  • 사용자 정의 도구(local.custom_tools) 및 도구 세트 제한(tools, disallowed_tools)은 로컬 에이전트에서만 사용할 수 있습니다. 이러한 제한은 에이전트에 유지되지 않으므로 재개 시 다시 전달하세요.
  • 로컬 에이전트에서는 아티팩트를 다운로드할 수 없습니다.
  • local.setting_sources(및 이 설정이 제어하는 파일 기반 MCP 및 하위 에이전트 경로)는 클라우드 에이전트에 적용되지 않습니다. 클라우드는 항상 project, team, plugins를 로드합니다.
  • 훅은 파일 기반으로만 지원됩니다(.cursor/hooks.json). 프로그래밍 방식의 콜백은 지원되지 않습니다.