@adcp/client 4.22.1 → 4.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -9
- package/bin/adcp.js +83 -18
- package/dist/lib/index.d.ts +3 -5
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/index.js +16 -12
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/server/index.d.ts +5 -1
- package/dist/lib/server/index.d.ts.map +1 -1
- package/dist/lib/server/index.js +10 -1
- package/dist/lib/server/index.js.map +1 -1
- package/dist/lib/server/postgres-task-store.d.ts +105 -0
- package/dist/lib/server/postgres-task-store.d.ts.map +1 -0
- package/dist/lib/server/postgres-task-store.js +267 -0
- package/dist/lib/server/postgres-task-store.js.map +1 -0
- package/dist/lib/server/responses.d.ts +1 -0
- package/dist/lib/server/responses.d.ts.map +1 -1
- package/dist/lib/server/responses.js +1 -0
- package/dist/lib/server/responses.js.map +1 -1
- package/dist/lib/server/test-controller.d.ts +88 -0
- package/dist/lib/server/test-controller.d.ts.map +1 -0
- package/dist/lib/server/test-controller.js +227 -0
- package/dist/lib/server/test-controller.js.map +1 -0
- package/dist/lib/testing/agent-tester.d.ts +1 -1
- package/dist/lib/testing/agent-tester.d.ts.map +1 -1
- package/dist/lib/testing/agent-tester.js +13 -1
- package/dist/lib/testing/agent-tester.js.map +1 -1
- package/dist/lib/testing/compliance/comply.d.ts +24 -5
- package/dist/lib/testing/compliance/comply.d.ts.map +1 -1
- package/dist/lib/testing/compliance/comply.js +318 -277
- package/dist/lib/testing/compliance/comply.js.map +1 -1
- package/dist/lib/testing/compliance/index.d.ts +2 -1
- package/dist/lib/testing/compliance/index.d.ts.map +1 -1
- package/dist/lib/testing/compliance/index.js +6 -1
- package/dist/lib/testing/compliance/index.js.map +1 -1
- package/dist/lib/testing/compliance/platform-storyboards.d.ts +44 -0
- package/dist/lib/testing/compliance/platform-storyboards.d.ts.map +1 -0
- package/dist/lib/testing/compliance/platform-storyboards.js +232 -0
- package/dist/lib/testing/compliance/platform-storyboards.js.map +1 -0
- package/dist/lib/testing/compliance/storyboard-tracks.d.ts +2 -9
- package/dist/lib/testing/compliance/storyboard-tracks.d.ts.map +1 -1
- package/dist/lib/testing/compliance/storyboard-tracks.js +15 -46
- package/dist/lib/testing/compliance/storyboard-tracks.js.map +1 -1
- package/dist/lib/testing/compliance/types.d.ts +22 -1
- package/dist/lib/testing/compliance/types.d.ts.map +1 -1
- package/dist/lib/testing/index.d.ts +1 -1
- package/dist/lib/testing/index.d.ts.map +1 -1
- package/dist/lib/testing/index.js +6 -1
- package/dist/lib/testing/index.js.map +1 -1
- package/dist/lib/testing/orchestrator.d.ts.map +1 -1
- package/dist/lib/testing/orchestrator.js +5 -1
- package/dist/lib/testing/orchestrator.js.map +1 -1
- package/dist/lib/testing/scenarios/brand-rights.d.ts +19 -1
- package/dist/lib/testing/scenarios/brand-rights.d.ts.map +1 -1
- package/dist/lib/testing/scenarios/brand-rights.js +138 -1
- package/dist/lib/testing/scenarios/brand-rights.js.map +1 -1
- package/dist/lib/testing/scenarios/deterministic.js +7 -7
- package/dist/lib/testing/scenarios/deterministic.js.map +1 -1
- package/dist/lib/testing/scenarios/index.d.ts +1 -1
- package/dist/lib/testing/scenarios/index.d.ts.map +1 -1
- package/dist/lib/testing/scenarios/index.js +4 -2
- package/dist/lib/testing/scenarios/index.js.map +1 -1
- package/dist/lib/testing/scenarios/media-buy.js +4 -4
- package/dist/lib/testing/scenarios/media-buy.js.map +1 -1
- package/dist/lib/testing/storyboard/loader.d.ts +1 -0
- package/dist/lib/testing/storyboard/loader.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/loader.js +14 -0
- package/dist/lib/testing/storyboard/loader.js.map +1 -1
- package/dist/lib/testing/storyboard/request-builder.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/request-builder.js +88 -11
- package/dist/lib/testing/storyboard/request-builder.js.map +1 -1
- package/dist/lib/testing/storyboard/runner.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/runner.js +83 -5
- package/dist/lib/testing/storyboard/runner.js.map +1 -1
- package/dist/lib/testing/storyboard/task-map.d.ts +2 -0
- package/dist/lib/testing/storyboard/task-map.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/task-map.js +23 -9
- package/dist/lib/testing/storyboard/task-map.js.map +1 -1
- package/dist/lib/testing/storyboard/types.d.ts +6 -2
- package/dist/lib/testing/storyboard/types.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/validations.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/validations.js +21 -4
- package/dist/lib/testing/storyboard/validations.js.map +1 -1
- package/dist/lib/testing/types.d.ts +1 -1
- package/dist/lib/testing/types.d.ts.map +1 -1
- package/dist/lib/types/core.generated.d.ts +242 -3
- package/dist/lib/types/core.generated.d.ts.map +1 -1
- package/dist/lib/types/core.generated.js +1 -1
- package/dist/lib/types/schemas.generated.d.ts +3697 -3468
- package/dist/lib/types/schemas.generated.d.ts.map +1 -1
- package/dist/lib/types/schemas.generated.js +226 -118
- package/dist/lib/types/schemas.generated.js.map +1 -1
- package/dist/lib/types/tools.generated.d.ts +281 -79
- package/dist/lib/types/tools.generated.d.ts.map +1 -1
- package/dist/lib/utils/capabilities.d.ts +2 -2
- package/dist/lib/utils/capabilities.d.ts.map +1 -1
- package/dist/lib/utils/capabilities.js +9 -3
- package/dist/lib/utils/capabilities.js.map +1 -1
- package/dist/lib/utils/response-schemas.d.ts.map +1 -1
- package/dist/lib/utils/response-schemas.js +9 -0
- package/dist/lib/utils/response-schemas.js.map +1 -1
- package/dist/lib/version.d.ts +3 -3
- package/dist/lib/version.js +3 -3
- package/docs/llms.txt +56 -32
- package/package.json +8 -2
- package/skills/adcp/SKILL.md +118 -33
- package/skills/build-creative-agent/SKILL.md +221 -0
- package/skills/build-generative-seller-agent/SKILL.md +288 -0
- package/skills/build-retail-media-agent/SKILL.md +237 -0
- package/skills/build-seller-agent/SKILL.md +313 -0
- package/skills/build-signals-agent/SKILL.md +203 -0
- package/storyboards/audience_sync.yaml +18 -29
- package/storyboards/behavioral_analysis.yaml +40 -72
- package/storyboards/brand_rights.yaml +172 -75
- package/storyboards/campaign_governance_conditions.yaml +187 -0
- package/storyboards/campaign_governance_delivery.yaml +231 -0
- package/storyboards/campaign_governance_denied.yaml +136 -0
- package/storyboards/capability_discovery.yaml +106 -0
- package/storyboards/content_standards.yaml +251 -0
- package/storyboards/creative_ad_server.yaml +108 -16
- package/storyboards/creative_generative.yaml +317 -0
- package/storyboards/creative_lifecycle.yaml +284 -0
- package/storyboards/creative_sales_agent.yaml +2 -6
- package/storyboards/creative_template.yaml +3 -6
- package/storyboards/deterministic_testing.yaml +271 -245
- package/storyboards/error_compliance.yaml +105 -108
- package/storyboards/media_buy_catalog_creative.yaml +8 -5
- package/storyboards/media_buy_generative_seller.yaml +581 -0
- package/storyboards/media_buy_governance_escalation.yaml +10 -6
- package/storyboards/media_buy_guaranteed_approval.yaml +21 -19
- package/storyboards/media_buy_non_guaranteed.yaml +9 -8
- package/storyboards/media_buy_proposal_mode.yaml +12 -11
- package/storyboards/media_buy_seller.yaml +161 -173
- package/storyboards/media_buy_state_machine.yaml +102 -101
- package/storyboards/property_governance.yaml +239 -0
- package/storyboards/schema.yaml +3 -2
- package/storyboards/schema_validation.yaml +58 -51
- package/storyboards/si_session.yaml +99 -317
- package/storyboards/signal_marketplace.yaml +9 -5
- package/storyboards/signal_owned.yaml +6 -5
- package/storyboards/social_platform.yaml +274 -0
- package/storyboards/test-kits/acme-outdoor.yaml +118 -0
- package/storyboards/test-kits/nova-motors.yaml +134 -0
- package/storyboards/governance_content_standards.yaml +0 -213
- package/storyboards/governance_property_lists.yaml +0 -372
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: build-creative-agent
|
|
3
|
+
description: Use when building an AdCP creative agent — an ad server, creative management platform, or any system that accepts, stores, transforms, and serves ad creatives.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Build a Creative Agent
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
A creative agent manages the creative lifecycle: accepts assets from buyers, stores them in a library, builds serving tags, and renders previews. Unlike a generative seller (which also sells inventory), a creative agent is a standalone creative platform — it manages creatives but doesn't sell media.
|
|
11
|
+
|
|
12
|
+
## When to Use
|
|
13
|
+
|
|
14
|
+
- User wants to build an ad server, creative management platform, or creative rendering service
|
|
15
|
+
- User mentions `build_creative`, `preview_creative`, `sync_creatives`, or `list_creatives`
|
|
16
|
+
- User references creative formats, VAST tags, serving tags, or creative libraries
|
|
17
|
+
|
|
18
|
+
**Not this skill:**
|
|
19
|
+
- Selling inventory + generating creatives → `skills/build-generative-seller-agent/`
|
|
20
|
+
- Selling inventory (no creative management) → `skills/build-seller-agent/`
|
|
21
|
+
- Serving audience segments → `skills/build-signals-agent/`
|
|
22
|
+
|
|
23
|
+
## Before Writing Code
|
|
24
|
+
|
|
25
|
+
Determine these things. Ask the user — don't guess.
|
|
26
|
+
|
|
27
|
+
### 1. What kind of creative platform?
|
|
28
|
+
|
|
29
|
+
- **Ad server** (Innovid, Flashtalking, CM360) — stateful library, builds serving tags (VAST, display tags), tracks delivery
|
|
30
|
+
- **Creative management platform** (Celtra) — format transformation, template rendering, asset management
|
|
31
|
+
- **Publisher creative service** — accepts buyer assets, validates against publisher specs, renders previews
|
|
32
|
+
|
|
33
|
+
### 2. What formats?
|
|
34
|
+
|
|
35
|
+
Get specific formats the platform supports. Common ones:
|
|
36
|
+
- **Display**: `display_300x250`, `display_728x90`, `display_160x600`
|
|
37
|
+
- **Video**: `video_30s`, `vast_30s`, `video_15s`
|
|
38
|
+
- **Native**: `native_content` (image + headline + description)
|
|
39
|
+
- **Rich media**: `html5_300x250` (interactive HTML)
|
|
40
|
+
|
|
41
|
+
Each format needs: dimensions, accepted asset types (image, video, html, text), mime types.
|
|
42
|
+
|
|
43
|
+
### 3. What operations?
|
|
44
|
+
|
|
45
|
+
- **Sync** — accept and store creatives from buyers (always needed)
|
|
46
|
+
- **List** — query the creative library with filtering (recommended)
|
|
47
|
+
- **Preview** — render a visual preview of a creative (recommended)
|
|
48
|
+
- **Build** — produce serving tags (VAST, display tags, etc.) from stored creatives (recommended)
|
|
49
|
+
|
|
50
|
+
### 4. Review pipeline?
|
|
51
|
+
|
|
52
|
+
What happens when a creative is synced:
|
|
53
|
+
- **Instant accept** — creative passes validation, immediately available
|
|
54
|
+
- **Pending review** — human or automated review before going live
|
|
55
|
+
- **Rejection** — creative fails validation (wrong dimensions, prohibited content)
|
|
56
|
+
|
|
57
|
+
## Tools and Required Response Shapes
|
|
58
|
+
|
|
59
|
+
**`get_adcp_capabilities`** — register first, empty `{}` schema
|
|
60
|
+
```
|
|
61
|
+
capabilitiesResponse({
|
|
62
|
+
adcp: { major_versions: [3] },
|
|
63
|
+
supported_protocols: ['creative'],
|
|
64
|
+
})
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**`list_creative_formats`** — `ListCreativeFormatsRequestSchema.shape`
|
|
68
|
+
```
|
|
69
|
+
taskToolResponse({
|
|
70
|
+
formats: [{
|
|
71
|
+
format_id: { agent_url: string, id: string }, // required
|
|
72
|
+
name: string, // required
|
|
73
|
+
description: string,
|
|
74
|
+
renders: [{ width: number, height: number }], // output dimensions
|
|
75
|
+
assets: [{ // what the format accepts
|
|
76
|
+
item_type: 'individual',
|
|
77
|
+
asset_id: string,
|
|
78
|
+
asset_type: 'image' | 'video' | 'html' | 'text',
|
|
79
|
+
required: boolean,
|
|
80
|
+
accepted_media_types: string[], // e.g., ['image/png', 'image/jpeg']
|
|
81
|
+
}],
|
|
82
|
+
}],
|
|
83
|
+
})
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**`sync_creatives`** — `SyncCreativesRequestSchema.shape`
|
|
87
|
+
|
|
88
|
+
Store creatives in the library. Echo back creative_id and action.
|
|
89
|
+
```
|
|
90
|
+
taskToolResponse({
|
|
91
|
+
creatives: [{
|
|
92
|
+
creative_id: string, // required — echo from request
|
|
93
|
+
action: 'created' | 'updated', // required
|
|
94
|
+
status: 'accepted' | 'pending_review' | 'rejected',
|
|
95
|
+
}],
|
|
96
|
+
})
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
**`list_creatives`** — `ListCreativesRequestSchema.shape`
|
|
100
|
+
|
|
101
|
+
Return creatives from the library. Support filtering by format_id.
|
|
102
|
+
```
|
|
103
|
+
taskToolResponse({
|
|
104
|
+
creatives: [{
|
|
105
|
+
creative_id: string,
|
|
106
|
+
name: string,
|
|
107
|
+
format_id: { agent_url: string, id: string },
|
|
108
|
+
status: 'accepted' | 'pending_review' | 'rejected',
|
|
109
|
+
}],
|
|
110
|
+
})
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
The handler should check `args.filters?.format_ids` — if present, return only creatives matching those formats.
|
|
114
|
+
|
|
115
|
+
**`preview_creative`** — `PreviewCreativeRequestSchema.shape`
|
|
116
|
+
|
|
117
|
+
Render a preview of a stored creative. Each preview has a `renders` array with output_format discriminator.
|
|
118
|
+
```
|
|
119
|
+
taskToolResponse({
|
|
120
|
+
response_type: 'single',
|
|
121
|
+
previews: [{
|
|
122
|
+
preview_id: string,
|
|
123
|
+
input: { format_id: { agent_url: string, id: string }, name: string, assets: {} },
|
|
124
|
+
renders: [{
|
|
125
|
+
render_id: string,
|
|
126
|
+
output_format: 'url', // discriminator: 'url' or 'html'
|
|
127
|
+
preview_url: string, // URL to rendered preview (for output_format: 'url')
|
|
128
|
+
role: 'primary',
|
|
129
|
+
dimensions: { width: number, height: number },
|
|
130
|
+
}],
|
|
131
|
+
}],
|
|
132
|
+
expires_at: string, // ISO timestamp
|
|
133
|
+
})
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**`build_creative`** — `BuildCreativeRequestSchema.shape`
|
|
137
|
+
|
|
138
|
+
Produce a serving tag from a stored creative.
|
|
139
|
+
```
|
|
140
|
+
taskToolResponse({
|
|
141
|
+
creative_manifest: {
|
|
142
|
+
format_id: { agent_url: string, id: string },
|
|
143
|
+
name: string,
|
|
144
|
+
assets: {}, // built output assets
|
|
145
|
+
},
|
|
146
|
+
sandbox: true,
|
|
147
|
+
})
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## SDK Quick Reference
|
|
151
|
+
|
|
152
|
+
| SDK piece | Usage |
|
|
153
|
+
|-----------|-------|
|
|
154
|
+
| `serve(createAgent)` | Start HTTP server on `:3001/mcp` |
|
|
155
|
+
| `createTaskCapableServer(name, version, { taskStore })` | Create MCP server with task support |
|
|
156
|
+
| `server.tool(name, Schema.shape, handler)` | Register tool — `.shape` unwraps Zod |
|
|
157
|
+
| `capabilitiesResponse(data)` | Build `get_adcp_capabilities` response |
|
|
158
|
+
| `taskToolResponse(data, summary)` | Build generic tool response |
|
|
159
|
+
| `adcpError(code, { message })` | Structured error |
|
|
160
|
+
|
|
161
|
+
Schemas: `ListCreativeFormatsRequestSchema`, `SyncCreativesRequestSchema`, `ListCreativesRequestSchema`, `PreviewCreativeRequestSchema`, `BuildCreativeRequestSchema`.
|
|
162
|
+
|
|
163
|
+
Import everything from `@adcp/client`. Types from `@adcp/client` with `import type`.
|
|
164
|
+
|
|
165
|
+
## Implementation
|
|
166
|
+
|
|
167
|
+
1. Single `.ts` file — all tools in one file
|
|
168
|
+
2. Always register `get_adcp_capabilities` as the **first** tool with empty `{}` schema
|
|
169
|
+
3. Use `Schema.shape` (not `Schema`) when registering tools
|
|
170
|
+
4. Use an in-memory Map to store synced creatives (the creative library)
|
|
171
|
+
5. Set `sandbox: true` on all mock/demo responses
|
|
172
|
+
6. Use `ServeContext` pattern: `function createAgent({ taskStore }: ServeContext)`
|
|
173
|
+
|
|
174
|
+
The skill contains everything you need. Do not read additional docs before writing code.
|
|
175
|
+
|
|
176
|
+
### Key implementation detail: creative library
|
|
177
|
+
|
|
178
|
+
Use a `Map<string, Creative>` to store synced creatives. The `sync_creatives` handler adds/updates entries. The `list_creatives` handler queries the map. The `preview_creative` and `build_creative` handlers look up by `creative_id`.
|
|
179
|
+
|
|
180
|
+
## Validation
|
|
181
|
+
|
|
182
|
+
**After writing the agent, validate it. Fix failures. Repeat.**
|
|
183
|
+
|
|
184
|
+
**Full validation** (if you can bind ports):
|
|
185
|
+
```bash
|
|
186
|
+
npx tsx agent.ts &
|
|
187
|
+
npx @adcp/client storyboard run http://localhost:3001/mcp creative_lifecycle --json
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
**Sandbox validation** (if ports are blocked):
|
|
191
|
+
```bash
|
|
192
|
+
npx tsc --noEmit agent.ts
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
**Keep iterating until all steps pass.**
|
|
196
|
+
|
|
197
|
+
## Common Mistakes
|
|
198
|
+
|
|
199
|
+
| Mistake | Fix |
|
|
200
|
+
|---------|-----|
|
|
201
|
+
| Skip `get_adcp_capabilities` | Must be the first tool registered |
|
|
202
|
+
| Pass `Schema` instead of `Schema.shape` | MCP SDK needs unwrapped Zod fields |
|
|
203
|
+
| `list_creatives` ignores format filter | Check `args.filters?.format_ids` and filter results |
|
|
204
|
+
| `preview_creative` returns wrong response_type | Must be `'single'` for single creative previews |
|
|
205
|
+
| `build_creative` missing creative_manifest | Required field — contains the built output |
|
|
206
|
+
| No in-memory store for synced creatives | `list_creatives` and `preview_creative` need to find previously synced creatives |
|
|
207
|
+
|
|
208
|
+
## Storyboards
|
|
209
|
+
|
|
210
|
+
| Storyboard | Tests |
|
|
211
|
+
|-----------|-------|
|
|
212
|
+
| `creative_lifecycle` | Full lifecycle: format discovery → sync → list → preview → build |
|
|
213
|
+
| `creative_template` | Stateless template rendering (build + preview only) |
|
|
214
|
+
| `creative_sales_agent` | Sales agent that accepts pushed assets |
|
|
215
|
+
| `creative_ad_server` | Ad server with pre-loaded library |
|
|
216
|
+
|
|
217
|
+
## Reference
|
|
218
|
+
|
|
219
|
+
- `storyboards/creative_lifecycle.yaml` — full creative lifecycle storyboard
|
|
220
|
+
- `docs/guides/BUILD-AN-AGENT.md` — SDK patterns
|
|
221
|
+
- `docs/llms.txt` — full protocol reference
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: build-generative-seller-agent
|
|
3
|
+
description: Use when building an AdCP generative seller — an AI ad network, generative DSP, or platform that sells inventory AND generates creatives from briefs.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Build a Generative Seller Agent
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
A generative seller does everything a standard seller does (products, media buys, delivery) plus generates creatives from briefs. The buyer sends a creative brief instead of uploading pre-built assets. Your platform resolves the brand identity, generates the creative, and serves it.
|
|
11
|
+
|
|
12
|
+
A generative seller that sells programmatic inventory MUST also accept standard IAB formats (display images, VAST tags, HTML banners). The generative capability is additive — buyers who already have creatives need to upload them directly.
|
|
13
|
+
|
|
14
|
+
## When to Use
|
|
15
|
+
|
|
16
|
+
- User wants to build a generative DSP or AI ad network
|
|
17
|
+
- User's platform both sells inventory and creates/generates creatives
|
|
18
|
+
- User mentions "creative from brief", "AI-generated ads", or "generative"
|
|
19
|
+
|
|
20
|
+
**Not this skill:**
|
|
21
|
+
- Standard seller (no creative generation) → `skills/build-seller-agent/`
|
|
22
|
+
- Standalone creative agent (renders but doesn't sell) → creative agent
|
|
23
|
+
- Signals/audience data → `skills/build-signals-agent/`
|
|
24
|
+
|
|
25
|
+
## Before Writing Code
|
|
26
|
+
|
|
27
|
+
Determine these things. Ask the user — don't guess.
|
|
28
|
+
|
|
29
|
+
### 1. What kind of platform?
|
|
30
|
+
|
|
31
|
+
- **AI ad network** — sells inventory across publishers, generates creatives from briefs
|
|
32
|
+
- **Generative DSP** — programmatic buying + AI creative generation
|
|
33
|
+
- **Retail media with creative** — retail inventory + dynamic ad generation from catalogs
|
|
34
|
+
|
|
35
|
+
### 2. Products and pricing
|
|
36
|
+
|
|
37
|
+
Same as standard seller. Each product needs: name, channel, delivery_type, pricing_options.
|
|
38
|
+
|
|
39
|
+
### 3. Generative formats
|
|
40
|
+
|
|
41
|
+
What creative formats does your platform generate?
|
|
42
|
+
- **Display** — generated static images (300x250, 728x90, etc.)
|
|
43
|
+
- **Video** — generated video ads (15s, 30s pre-roll)
|
|
44
|
+
- **HTML** — generated interactive/rich media
|
|
45
|
+
|
|
46
|
+
Each generative format needs a brief asset slot. Standard formats need traditional asset slots (image, video, VAST).
|
|
47
|
+
|
|
48
|
+
### 4. What inputs does the brief accept?
|
|
49
|
+
|
|
50
|
+
At minimum: `name`, `objective`, `tone`, `messaging` (headline, cta, key_messages).
|
|
51
|
+
Optional: `audience`, `territory`, `compliance` (required_disclosures, prohibited_claims).
|
|
52
|
+
|
|
53
|
+
### 5. Brand resolution
|
|
54
|
+
|
|
55
|
+
The buyer's brand domain should be resolvable (via AgenticAdvertising.org or brand.json). If the brand domain is invalid, reject the creative — don't generate with unknown brand identity.
|
|
56
|
+
|
|
57
|
+
## Tools and Required Response Shapes
|
|
58
|
+
|
|
59
|
+
Everything from the standard seller skill applies. The delta is in `list_creative_formats` and `sync_creatives`.
|
|
60
|
+
|
|
61
|
+
**`get_adcp_capabilities`** — register first, empty `{}` schema
|
|
62
|
+
```
|
|
63
|
+
capabilitiesResponse({
|
|
64
|
+
adcp: { major_versions: [3] },
|
|
65
|
+
supported_protocols: ['media_buy'],
|
|
66
|
+
})
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**`sync_accounts`** — `SyncAccountsRequestSchema.shape`
|
|
70
|
+
```
|
|
71
|
+
taskToolResponse({
|
|
72
|
+
accounts: [{
|
|
73
|
+
account_id: string,
|
|
74
|
+
brand: { domain: string },
|
|
75
|
+
operator: string,
|
|
76
|
+
action: 'created' | 'updated',
|
|
77
|
+
status: 'active' | 'pending_approval',
|
|
78
|
+
}]
|
|
79
|
+
})
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
**`get_products`** — `GetProductsRequestSchema.shape`
|
|
83
|
+
```
|
|
84
|
+
productsResponse({
|
|
85
|
+
products: Product[], // each needs product_id, delivery_type, pricing_options
|
|
86
|
+
sandbox: true,
|
|
87
|
+
})
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**`create_media_buy`** — `CreateMediaBuyRequestSchema.shape`
|
|
91
|
+
```
|
|
92
|
+
mediaBuyResponse({
|
|
93
|
+
media_buy_id: string,
|
|
94
|
+
packages: [{ package_id, product_id, pricing_option_id, budget }],
|
|
95
|
+
})
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
**`list_creative_formats`** — `ListCreativeFormatsRequestSchema.shape`
|
|
99
|
+
|
|
100
|
+
Return BOTH generative and standard formats:
|
|
101
|
+
```
|
|
102
|
+
taskToolResponse({
|
|
103
|
+
formats: [
|
|
104
|
+
// Generative format — accepts brief input
|
|
105
|
+
{
|
|
106
|
+
format_id: { agent_url: string, id: 'display_300x250_generative' },
|
|
107
|
+
name: 'Generated Display 300x250',
|
|
108
|
+
description: 'AI-generated display ad from creative brief',
|
|
109
|
+
renders: [{ width: 300, height: 250 }],
|
|
110
|
+
assets: [{
|
|
111
|
+
item_type: 'individual',
|
|
112
|
+
asset_id: 'brief',
|
|
113
|
+
asset_type: 'brief',
|
|
114
|
+
required: true,
|
|
115
|
+
description: 'Creative brief with messaging and brand guidelines',
|
|
116
|
+
}],
|
|
117
|
+
},
|
|
118
|
+
// Standard format — accepts pre-built assets
|
|
119
|
+
{
|
|
120
|
+
format_id: { agent_url: string, id: 'display_300x250' },
|
|
121
|
+
name: 'Display 300x250',
|
|
122
|
+
description: 'Standard IAB display banner',
|
|
123
|
+
renders: [{ width: 300, height: 250 }],
|
|
124
|
+
assets: [{
|
|
125
|
+
item_type: 'individual',
|
|
126
|
+
asset_id: 'image',
|
|
127
|
+
asset_type: 'image',
|
|
128
|
+
required: true,
|
|
129
|
+
accepted_media_types: ['image/jpeg', 'image/png'],
|
|
130
|
+
}],
|
|
131
|
+
},
|
|
132
|
+
],
|
|
133
|
+
})
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**`sync_creatives`** — `SyncCreativesRequestSchema.shape`
|
|
137
|
+
|
|
138
|
+
Handle both brief-based and standard creatives:
|
|
139
|
+
```
|
|
140
|
+
taskToolResponse({
|
|
141
|
+
creatives: [{
|
|
142
|
+
creative_id: string, // echo from request
|
|
143
|
+
action: 'created' | 'updated', // required
|
|
144
|
+
status: 'accepted' | 'pending_review', // pending_review if generation is async
|
|
145
|
+
}],
|
|
146
|
+
})
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
For invalid brand domains, return rejection:
|
|
150
|
+
```
|
|
151
|
+
taskToolResponse({
|
|
152
|
+
creatives: [{
|
|
153
|
+
creative_id: string,
|
|
154
|
+
action: 'created',
|
|
155
|
+
status: 'rejected',
|
|
156
|
+
errors: ['Brand domain not found: nonexistent-brand.example'],
|
|
157
|
+
}],
|
|
158
|
+
})
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
**`get_media_buys`** — `GetMediaBuysRequestSchema.shape`
|
|
162
|
+
```
|
|
163
|
+
taskToolResponse({
|
|
164
|
+
media_buys: [{
|
|
165
|
+
media_buy_id: string,
|
|
166
|
+
status: 'active' | 'pending_start' | ...,
|
|
167
|
+
currency: 'USD',
|
|
168
|
+
packages: [{ package_id: string }],
|
|
169
|
+
}]
|
|
170
|
+
})
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
**`get_media_buy_delivery`** — `GetMediaBuyDeliveryRequestSchema.shape`
|
|
174
|
+
```
|
|
175
|
+
deliveryResponse({
|
|
176
|
+
reporting_period: { start: string, end: string },
|
|
177
|
+
media_buy_deliveries: [{
|
|
178
|
+
media_buy_id: string,
|
|
179
|
+
status: 'active',
|
|
180
|
+
totals: { impressions: number, spend: number },
|
|
181
|
+
by_package: [],
|
|
182
|
+
}]
|
|
183
|
+
})
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## Compliance Testing (Optional)
|
|
187
|
+
|
|
188
|
+
Add `registerTestController` so the comply framework can deterministically test your state machines. One function call — the SDK handles request parsing, status validation, and response formatting.
|
|
189
|
+
|
|
190
|
+
```
|
|
191
|
+
import { registerTestController, TestControllerError } from '@adcp/client';
|
|
192
|
+
import type { TestControllerStore } from '@adcp/client';
|
|
193
|
+
|
|
194
|
+
const store: TestControllerStore = {
|
|
195
|
+
async forceAccountStatus(accountId, status) {
|
|
196
|
+
const prev = accounts.get(accountId);
|
|
197
|
+
if (!prev) throw new TestControllerError('NOT_FOUND', `Account ${accountId} not found`);
|
|
198
|
+
accounts.set(accountId, status);
|
|
199
|
+
return { success: true, previous_state: prev, current_state: status };
|
|
200
|
+
},
|
|
201
|
+
async forceMediaBuyStatus(mediaBuyId, status) { /* same pattern */ },
|
|
202
|
+
async forceCreativeStatus(creativeId, status) { /* same pattern */ },
|
|
203
|
+
// simulateDelivery, simulateBudgetSpend — implement as needed
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
registerTestController(server, store);
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Declare `compliance_testing` in `supported_protocols` in your `get_adcp_capabilities` response. Only implement the store methods for scenarios your agent supports — unimplemented methods are excluded from `list_scenarios` automatically.
|
|
210
|
+
|
|
211
|
+
Validate with: `adcp storyboard run <agent> deterministic_testing --json`
|
|
212
|
+
|
|
213
|
+
## SDK Quick Reference
|
|
214
|
+
|
|
215
|
+
| SDK piece | Usage |
|
|
216
|
+
|-----------|-------|
|
|
217
|
+
| `serve(createAgent)` | Start HTTP server on `:3001/mcp` |
|
|
218
|
+
| `createTaskCapableServer(name, version, { taskStore })` | Create MCP server with task support |
|
|
219
|
+
| `server.tool(name, Schema.shape, handler)` | Register tool — `.shape` unwraps Zod |
|
|
220
|
+
| `capabilitiesResponse(data)` | Build `get_adcp_capabilities` response |
|
|
221
|
+
| `productsResponse(data)` | Build `get_products` response |
|
|
222
|
+
| `mediaBuyResponse(data)` | Build `create_media_buy` response |
|
|
223
|
+
| `deliveryResponse(data)` | Build `get_media_buy_delivery` response |
|
|
224
|
+
| `taskToolResponse(data, summary)` | Build generic tool response |
|
|
225
|
+
| `adcpError(code, { message })` | Structured error |
|
|
226
|
+
| `registerTestController(server, store)` | Add `comply_test_controller` for deterministic testing |
|
|
227
|
+
|
|
228
|
+
Import everything from `@adcp/client`. Types from `@adcp/client` with `import type`.
|
|
229
|
+
|
|
230
|
+
## Implementation
|
|
231
|
+
|
|
232
|
+
1. Single `.ts` file — all tools in one file
|
|
233
|
+
2. Always register `get_adcp_capabilities` as the **first** tool with empty `{}` schema
|
|
234
|
+
3. Use `Schema.shape` (not `Schema`) when registering tools
|
|
235
|
+
4. Use response builders — never return raw JSON
|
|
236
|
+
5. Set `sandbox: true` on all mock/demo responses
|
|
237
|
+
6. Use `ServeContext` pattern: `function createAgent({ taskStore }: ServeContext)`
|
|
238
|
+
|
|
239
|
+
The skill contains everything you need. Do not read additional docs before writing code.
|
|
240
|
+
|
|
241
|
+
### Key implementation detail: sync_creatives handler
|
|
242
|
+
|
|
243
|
+
The sync_creatives handler must check the format_id to decide how to process:
|
|
244
|
+
- If the format is generative (e.g., id contains "generative"): read the `brief` asset from the creative's assets
|
|
245
|
+
- If the format is standard: read the image/video/html asset
|
|
246
|
+
- Validate the brand domain from the account — reject if invalid
|
|
247
|
+
- Return `pending_review` for generative (async generation) or `accepted` for standard
|
|
248
|
+
|
|
249
|
+
## Validation
|
|
250
|
+
|
|
251
|
+
**After writing the agent, validate it. Fix failures. Repeat.**
|
|
252
|
+
|
|
253
|
+
**Full validation** (if you can bind ports):
|
|
254
|
+
```bash
|
|
255
|
+
npx tsx agent.ts &
|
|
256
|
+
npx @adcp/client storyboard run http://localhost:3001/mcp media_buy_generative_seller --json
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
**Sandbox validation** (if ports are blocked):
|
|
260
|
+
```bash
|
|
261
|
+
npx tsc --noEmit agent.ts
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
When storyboard output shows failures, fix each one:
|
|
265
|
+
- `response_schema` → response doesn't match Zod schema
|
|
266
|
+
- `field_present` → required field missing
|
|
267
|
+
- MCP error → check tool registration (schema, name)
|
|
268
|
+
|
|
269
|
+
**Keep iterating until all steps pass.**
|
|
270
|
+
|
|
271
|
+
## Common Mistakes
|
|
272
|
+
|
|
273
|
+
| Mistake | Fix |
|
|
274
|
+
|---------|-----|
|
|
275
|
+
| Only generative formats, no standard IAB | Programmatic sellers must accept pre-built assets too |
|
|
276
|
+
| Ignore brand domain on brief sync | Validate brand, reject if unresolvable |
|
|
277
|
+
| Same handler for brief and standard creatives | Check format_id to decide processing path |
|
|
278
|
+
| Skip `get_adcp_capabilities` | Must be the first tool registered |
|
|
279
|
+
| Pass `Schema` instead of `Schema.shape` | MCP SDK needs unwrapped Zod fields |
|
|
280
|
+
| `sandbox: false` on mock data | Buyers may treat mock data as real |
|
|
281
|
+
|
|
282
|
+
## Reference
|
|
283
|
+
|
|
284
|
+
- `storyboards/media_buy_generative_seller.yaml` — full generative seller storyboard
|
|
285
|
+
- `storyboards/media_buy_seller.yaml` — base seller storyboard (for standard seller parts)
|
|
286
|
+
- `skills/build-seller-agent/SKILL.md` — standard seller skill (generative extends this)
|
|
287
|
+
- `docs/guides/BUILD-AN-AGENT.md` — SDK patterns
|
|
288
|
+
- `docs/llms.txt` — full protocol reference
|