> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://respan.ai/docs/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://respan.ai/docs/_mcp/server.

# Cursor SDK (tracing)

> Trace Cursor hook events and Cursor TypeScript SDK agent runs with Respan.

Respan supports Cursor tracing in Python through Cursor hook payloads and in TypeScript through the Cursor SDK (`@cursor/sdk`). Use the Python setup for Cursor hook events, or the TypeScript setup for programmatic Cursor SDK agent runs.

#### Set up Respan

Create an account at [platform.respan.ai](https://platform.respan.ai) and grab an [API key](https://platform.respan.ai/platform/gateway/api-keys).

Run `npx @respan/cli setup` to set up with your coding agent.

#### Example projects

* [Python package README](https://github.com/RespanAI/respan/tree/main/python-sdks/instrumentations/respan-instrumentation-cursor-sdk)
* [TypeScript examples](https://github.com/respanai/respan-example-projects/tree/main/typescript/tracing/cursor-sdk)

## Setup

#### Install packages

```python
pip install respan-ai respan-instrumentation-cursor-sdk
```

```typescript
npm install @cursor/sdk @respan/respan @respan/tracing @respan/instrumentation-cursor
```

#### Set environment variables

```bash
export RESPAN_API_KEY="YOUR_RESPAN_API_KEY"
export RESPAN_BASE_URL="https://api.respan.ai/api"
```

#### Initialize and run

**`Python`**

```python Python
from respan import Respan
from respan_instrumentation_cursor_sdk import CursorSDKInstrumentor

respan = Respan(instrumentations=[CursorSDKInstrumentor()])
processor = CursorSDKInstrumentor.create_processor()

processor.process_event(
    {
        "hook_event_name": "afterAgentThought",
        "conversation_id": "conv_123",
        "generation_id": "gen_456",
        "text": "Inspecting repository files to find the right implementation.",
        "duration_ms": 320,
    }
)

respan.shutdown()
```

**`TypeScript`**

```typescript TypeScript
import * as CursorSDK from "@cursor/sdk";
import { Respan } from "@respan/respan";
import { CursorSDKInstrumentor } from "@respan/instrumentation-cursor";

const cursorSdkModule = { ...CursorSDK };

const respan = new Respan({
  apiKey: process.env.RESPAN_API_KEY,
  baseURL: process.env.RESPAN_BASE_URL,
  appName: "cursor-sdk-tracing",
  instrumentations: [
    new CursorSDKInstrumentor({
      sdkModule: cursorSdkModule,
      agentName: "cursor-agent",
    }),
  ],
});
await respan.initialize();

const result = await respan.withWorkflow({ name: "cursor-sdk-agent-prompt" }, async () => {
  return await cursorSdkModule.Agent.prompt("Summarize how Cursor SDK runs are traced.", {
    name: "cursor_prompt_agent",
    model: { id: "cursor-small" },
  });
});

console.log(result.result);
```

> **Note**
>
> For TypeScript, pass `sdkModule` when your app imports `@cursor/sdk` directly. This ensures the instrumentor patches the same Cursor SDK module instance your application uses.

#### Configure Cursor hooks for Python

Use `respan-cursor-hook` as your Cursor hook command when using the Python hook integration.

```json
{
  "version": 1,
  "hooks": {
    "beforeSubmitPrompt": [{ "command": "respan-cursor-hook" }],
    "afterAgentThought": [{ "command": "respan-cursor-hook" }],
    "afterShellExecution": [{ "command": "respan-cursor-hook" }],
    "afterFileEdit": [{ "command": "respan-cursor-hook" }],
    "afterMCPExecution": [{ "command": "respan-cursor-hook" }],
    "afterAgentResponse": [{ "command": "respan-cursor-hook" }],
    "stop": [{ "command": "respan-cursor-hook" }]
  }
}
```

#### Trace streamed runs in TypeScript

```typescript
const agent = await cursorSdkModule.Agent.create({
  name: "cursor_stream_agent",
  model: { id: "cursor-small" },
});

const run = await agent.send("Use the docs MCP server and explain Cursor SDK streaming.", {
  mcpServers: {
    docs: {
      type: "stdio",
      command: "node",
      args: ["docs-server.js"],
    },
  },
});

for await (const event of run.stream()) {
  console.log(event.type);
}

const finalResult = await run.wait();
console.log(finalResult.result);
```

#### View your trace

Open the [Traces page](https://platform.respan.ai/platform/traces) to inspect Cursor hook spans or Cursor TypeScript SDK agent spans, generation spans, tool spans, streamed events, and local custom tool activity.

## Captured data

```python
- Cursor hook payloads
- Conversation and generation identifiers
- Agent thoughts
- Shell execution events
- File edit events
- MCP execution events
- Agent responses
- Stop events
```

```typescript
- Agent.prompt() calls and final summary results
- Agent.create() and Agent.resume() activity
- SDKAgent.send() calls and run metadata
- Run.stream() message and status events
- Run.wait() final status, result, and duration
- Assistant, user, thinking, status, task, request, and tool-call messages
- MCP server configuration passed to Cursor runs
- Per-run local custom tools passed through local.customTools
```

## Local custom tools

Cursor TypeScript SDK runs can define local custom tools. The instrumentor captures the tool definition and the tool call result.

```typescript
const agent = await cursorSdkModule.Agent.create({
  name: "cursor_custom_tools_agent",
  model: { id: "cursor-small" },
});

const run = await agent.send("Look up Tokyo weather with a local custom tool.", {
  local: {
    customTools: {
      lookup_weather: {
        description: "Return deterministic weather for a city.",
        inputSchema: {
          type: "object",
          properties: { city: { type: "string" } },
          required: ["city"],
        },
        execute: async ({ city }: { city: string }) => ({
          city,
          condition: "clear",
          temperatureC: 21,
        }),
      },
    },
  },
});

await run.wait();
```

## Attributes

Use Respan attributes to group Cursor runs by user, thread, or workflow.

**`Python`**

```python Python
from respan import Respan, propagate_attributes
from respan_instrumentation_cursor_sdk import CursorSDKInstrumentor

respan = Respan(instrumentations=[CursorSDKInstrumentor()])

with propagate_attributes(
    customer_identifier="user_123",
    thread_identifier="cursor-session-abc",
    metadata={"environment": "production"},
):
    processor = CursorSDKInstrumentor.create_processor()
    processor.process_event({...})
```

**`TypeScript`**

```typescript TypeScript
await respan.propagateAttributes(
  {
    customer_identifier: "user_123",
    thread_identifier: "cursor-session-abc",
    trace_group_identifier: "Cursor SDK Support.workflow",
    metadata: {
      environment: "production",
      feature: "repository-assistant",
    },
  },
  async () => {
    await respan.withWorkflow({ name: "Cursor SDK Support" }, async () => {
      await cursorSdkModule.Agent.prompt("Summarize this repository.");
    });
  }
);
```

| Attribute                | Type             | Description                                                   |
| ------------------------ | ---------------- | ------------------------------------------------------------- |
| `customer_identifier`    | `str \| string`  | Identifies the end user in Respan analytics.                  |
| `thread_identifier`      | `str \| string`  | Groups related Cursor activity into a session.                |
| `trace_group_identifier` | `string`         | Groups related TypeScript SDK spans into a named trace group. |
| `metadata`               | `dict \| object` | Custom key-value pairs attached to spans.                     |