> ## Documentation Index
> Fetch the complete documentation index at: https://agenticadvertisingorg-snap-format-preview-links.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Context & Sessions

> AdCP context_id vs task_id explained. How to manage conversation state, session continuity, and extension fields across MCP and A2A protocol requests.

AdCP uses identifiers and data fields to maintain state across requests. Understanding these is essential for building effective integrations.

## Key Identifiers

AdCP uses two distinct identifiers for different purposes:

### context\_id vs task\_id

| Identifier      | Purpose                         | Lifespan                         | Scope                      |
| --------------- | ------------------------------- | -------------------------------- | -------------------------- |
| **context\_id** | Conversation/session continuity | \~1 hour                         | Across multiple task calls |
| **task\_id**    | Tracking specific operations    | Until completion (hours to days) | Single operation           |

**context\_id**:

* Comes from the protocol layer (built into A2A, manual in MCP)
* Provides conversation history and session continuity
* Used for maintaining state across multiple task calls
* Expires after conversation timeout (typically 1 hour)

**task\_id**:

* Specific to individual requests that could be asynchronous
* Lives beyond the conversation
* Used for tracking operation progress over time
* Persists until the task completes (may be days for complex media buys)
* Can be referenced across different conversations or sessions

### Usage Example

```javascript theme={null}
// First call - establishes context and creates task
const result = await call('create_media_buy', {
  brief: "Launch summer campaign"
});

const contextId = result.context_id;  // For conversation continuity
const taskId = result.task_id;        // For tracking this specific media buy

// Later in same conversation - uses context_id
const update1 = await call('update_media_buy', {
  context_id: contextId,    // Maintains conversation state
  task_id: taskId,          // References the specific media buy
  updates: {...}
});

// Days later in new conversation - only task_id needed
const delivery = await call('get_media_buy_delivery', {
  task_id: taskId          // No context_id - this is a new conversation
});
```

## Protocol Differences

* **A2A**: Context is handled automatically by the protocol
* **MCP**: Requires manual context\_id management

### A2A Context (Automatic)

A2A handles sessions natively - you don't need to manage context:

```javascript theme={null}
// A2A maintains context automatically
const task = await a2a.send({ message: {...} });
// contextId is managed by A2A protocol

// Follow-ups automatically use the same context
const followUp = await a2a.send({
  contextId: task.contextId,  // Optional - A2A tracks this
  message: {...}
});
```

### MCP Context (Manual)

MCP requires explicit context management to maintain state:

```javascript theme={null}
// First call - no context
const result1 = await mcp.call('get_products', {
  brief: "Video ads"
});
const contextId = result1.context_id;  // Save this!

// Follow-up - must include context_id
const result2 = await mcp.call('get_products', {
  context_id: contextId,  // Required for continuity
  brief: "Focus on premium inventory"
});
```

### MCP Context Management Pattern

```javascript theme={null}
class MCPSession {
  constructor(mcp) {
    this.mcp = mcp;
    this.contextId = null;
  }

  async call(method, params) {
    const result = await this.mcp.call(method, {
      ...params,
      context_id: this.contextId
    });
    this.contextId = result.context_id;  // Update for next call
    return result;
  }
}
```

### MCP Agent-Side: Session ID Fallback

Many MCP clients (ChatGPT, Claude) don't pass `context_id`. Agents should use the transport's session ID as a fallback to enable automatic session persistence:

```typescript theme={null}
server.tool('get_products', schema, async (args, extra) => {
  // Use explicit context_id if provided, fall back to MCP sessionId
  const contextId = args.context_id ?? extra?.sessionId;

  const products = await generateProducts(args.brief, contextId);
  await productStore.save(contextId, products);

  return products;
});
```

This allows simple clients to get automatic session persistence while preserving explicit control for advanced buyers who need resumable sessions. For a working implementation, see the [Snap AdCP Agent](https://github.com/scope3data/snap-adcp).

## What Context Maintains

The `context_id` maintains conversation state, regardless of protocol:

* Current media buy and products being discussed
* Search results and applied filters
* Conversation history and user intent
* User preferences expressed in the session
* Workflow state and temporary decisions

Note: Long-term task state (like media buy status, creative assets, performance data) is tracked via `task_id`, not `context_id`.

## Extension Fields (`ext`)

Extension fields enable platform-specific functionality while maintaining protocol compatibility.

### Schema Pattern

Extensions appear consistently across requests, responses, and domain objects:

```json theme={null}
{
  "product_id": "ctv_premium",
  "name": "Connected TV Premium Inventory",
  "ext": {
    "gam": {
      "order_id": "1234567890",
      "dashboard_url": "https://..."
    },
    "roku": {
      "content_genres": ["comedy", "drama"]
    }
  }
}
```

The `ext` object:

* Is always **optional** (never required)
* Accepts any valid JSON structure
* Must be preserved by implementations (even unknown fields)
* Is not validated by AdCP schemas (implementation-specific validation allowed)

### Namespacing (Critical)

Extensions MUST use vendor/platform namespacing:

```json theme={null}
// ✅ Correct - Namespaced
{
  "ext": {
    "gam": { "test_mode": true },
    "roku": { "app_ids": ["123"] }
  }
}

// ❌ Incorrect - Not namespaced
{
  "ext": {
    "test_mode": true,  // Missing namespace!
    "app_ids": ["123"]  // Which platform?
  }
}
```

## Application Context (`context`)

Context provides opaque correlation data that is echoed unchanged in responses and webhooks.

### Key Properties

* Agents NEVER parse or use context to affect behavior
* Exists solely for the initiator's internal tracking needs
* Echoed unchanged in responses and webhook payloads

### Normative echo contract

Agents MUST obey the following rules. The compliance runner asserts on these literally, and buyers rely on them for correlation.

1. **Echo on success.** When the caller includes a top-level `context` object on a request, the agent MUST include the same object, byte-for-byte equivalent, in the response. This applies whether the response status is `completed`, `submitted`, `working`, `input-required`, or any other terminal or intermediate state.
2. **Echo on error.** Failure responses MUST also echo `context` verbatim. Dropping context on the error path breaks correlation exactly when the buyer needs it most. Agents that return `adcp_error`, `errors[]`, or any other error envelope MUST still carry through the caller's `context`.
3. **Echo on async updates.** Push notifications, webhook payloads, and any subsequent messages the agent emits for the same operation MUST carry the original `context`. The agent MUST NOT drop context between the initial response and a later status update — a buyer that correlated by `context.trace_id` expects every message for that operation to surface the same trace.
4. **No synthesis.** When the caller does NOT provide a `context` object, the agent MUST NOT fabricate one. Responses to context-less requests MUST omit the `context` field (or emit it as null / absent per the transport's normal serialization). Synthetic context from the agent side is a conformance failure — the whole point of context is that it is owned by the caller.
5. **No mutation.** Agents MUST NOT add, remove, rename, reorder, or retype fields in the echoed context. JSON equivalence applies: `{"a":1,"b":2}` and `{"b":2,"a":1}` may serialize differently but are considered equivalent for the echo rule provided key set and values match. Verifiers that rely on byte-literal equality (e.g., MCP clients that hash the raw JSON) SHOULD serialize with stable key ordering on the agent side.
6. **No action.** Agents MUST NOT parse, validate, log fields from, or branch on any value inside `context`. Context is opaque to the agent — a value that looks like a structured identifier is not an invitation to interpret it.

### Schema Pattern

```json theme={null}
{
  "tool": "create_media_buy",
  "arguments": {
    "packages": [...],
    "context": {
      "ui_session_id": "sess_abc123",
      "trace_id": "trace_xyz789",
      "internal_campaign_id": "camp_456"
    }
  }
}
```

Response echoes the context:

```json theme={null}
{
  "status": "input-required",
  "message": "Media buy requires manual approval before activation.",
  "context_id": "ctx_ghi789",
  "context": {
    "ui_session_id": "sess_abc123",
    "trace_id": "trace_xyz789",
    "internal_campaign_id": "camp_456"
  }
}
```

### Common Context Uses

1. **UI/Session tracking** - Maintaining state across async operations
2. **Request correlation** - Tracing requests through distributed systems
3. **Internal identifiers** - Mapping to your internal data structures
4. **Organization context** - Multi-tenant tracking

## When to Use What

| Field        | Purpose                  | Agent Reads? | Agent Modifies?       |
| ------------ | ------------------------ | ------------ | --------------------- |
| `context_id` | Session continuity       | Yes          | Yes (creates/updates) |
| `task_id`    | Operation tracking       | Yes          | Yes (creates)         |
| `ext`        | Platform-specific config | MAY          | MAY add response data |
| `context`    | Opaque correlation       | NEVER        | NEVER                 |

### Use `ext` when:

* Platform needs to parse the data
* Data MAY affect operational behavior
* Data represents platform-specific configuration
* Data should persist across operations

### Use `context` when:

* Data is only for caller's internal use
* Data should never affect agent behavior
* Data is for correlation/tracking only
* Data needs to be echoed unchanged

## Best Practices

### For A2A

* Let the protocol handle context
* Use contextId for explicit conversation threading
* Trust the session management

### For MCP

* Always preserve context\_id between calls
* Implement a session wrapper (see pattern above)
* Handle context expiration (1 hour timeout)
* Start fresh context for new workflows
* **Agents**: Use transport session ID as fallback when `context_id` is not provided (see [Session ID Fallback](#mcp-agent-side-session-id-fallback))

### For Extensions

* Always namespace under vendor keys
* Document your extensions extensively
* Consider proposing standardization for common patterns

### For Application Context

* Keep it opaque - don't structure for agents to parse
* Avoid large payloads - context is echoed in every response
* Use for correlation only - never for operational data
