@adcp/client 4.20.0 → 4.22.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.
Files changed (210) hide show
  1. package/AGENTS.md +278 -0
  2. package/README.md +96 -61
  3. package/bin/adcp.js +342 -4
  4. package/dist/lib/agents/index.generated.d.ts +9 -1
  5. package/dist/lib/agents/index.generated.d.ts.map +1 -1
  6. package/dist/lib/agents/index.generated.js +12 -0
  7. package/dist/lib/agents/index.generated.js.map +1 -1
  8. package/dist/lib/core/AgentClient.d.ts.map +1 -1
  9. package/dist/lib/core/SingleAgentClient.d.ts +2 -1
  10. package/dist/lib/core/SingleAgentClient.d.ts.map +1 -1
  11. package/dist/lib/core/SingleAgentClient.js +10 -1
  12. package/dist/lib/core/SingleAgentClient.js.map +1 -1
  13. package/dist/lib/discovery/property-crawler.d.ts +4 -0
  14. package/dist/lib/discovery/property-crawler.d.ts.map +1 -1
  15. package/dist/lib/discovery/property-crawler.js +10 -2
  16. package/dist/lib/discovery/property-crawler.js.map +1 -1
  17. package/dist/lib/index.d.ts +9 -9
  18. package/dist/lib/index.d.ts.map +1 -1
  19. package/dist/lib/index.js +13 -5
  20. package/dist/lib/index.js.map +1 -1
  21. package/dist/lib/protocols/index.d.ts.map +1 -1
  22. package/dist/lib/protocols/index.js +8 -6
  23. package/dist/lib/protocols/index.js.map +1 -1
  24. package/dist/lib/protocols/mcp.d.ts.map +1 -1
  25. package/dist/lib/protocols/mcp.js +24 -11
  26. package/dist/lib/protocols/mcp.js.map +1 -1
  27. package/dist/lib/registry/cursor-store.d.ts +19 -0
  28. package/dist/lib/registry/cursor-store.d.ts.map +1 -0
  29. package/dist/lib/registry/cursor-store.js +44 -0
  30. package/dist/lib/registry/cursor-store.js.map +1 -0
  31. package/dist/lib/registry/index.d.ts +21 -3
  32. package/dist/lib/registry/index.d.ts.map +1 -1
  33. package/dist/lib/registry/index.js +94 -1
  34. package/dist/lib/registry/index.js.map +1 -1
  35. package/dist/lib/registry/property-registry.d.ts +57 -0
  36. package/dist/lib/registry/property-registry.d.ts.map +1 -0
  37. package/dist/lib/registry/property-registry.js +92 -0
  38. package/dist/lib/registry/property-registry.js.map +1 -0
  39. package/dist/lib/registry/sync.d.ts +4 -0
  40. package/dist/lib/registry/sync.d.ts.map +1 -1
  41. package/dist/lib/registry/sync.js +14 -0
  42. package/dist/lib/registry/sync.js.map +1 -1
  43. package/dist/lib/registry/types.d.ts +35 -2
  44. package/dist/lib/registry/types.d.ts.map +1 -1
  45. package/dist/lib/registry/types.generated.d.ts +349 -321
  46. package/dist/lib/registry/types.generated.d.ts.map +1 -1
  47. package/dist/lib/registry/types.generated.js +1 -1
  48. package/dist/lib/server/index.d.ts +2 -0
  49. package/dist/lib/server/index.d.ts.map +1 -1
  50. package/dist/lib/server/index.js +3 -1
  51. package/dist/lib/server/index.js.map +1 -1
  52. package/dist/lib/server/serve.d.ts +45 -0
  53. package/dist/lib/server/serve.d.ts.map +1 -0
  54. package/dist/lib/server/serve.js +86 -0
  55. package/dist/lib/server/serve.js.map +1 -0
  56. package/dist/lib/testing/agent-tester.d.ts +1 -1
  57. package/dist/lib/testing/agent-tester.d.ts.map +1 -1
  58. package/dist/lib/testing/agent-tester.js +10 -1
  59. package/dist/lib/testing/agent-tester.js.map +1 -1
  60. package/dist/lib/testing/client.d.ts.map +1 -1
  61. package/dist/lib/testing/client.js +3 -0
  62. package/dist/lib/testing/client.js.map +1 -1
  63. package/dist/lib/testing/compliance/comply.d.ts.map +1 -1
  64. package/dist/lib/testing/compliance/comply.js +158 -203
  65. package/dist/lib/testing/compliance/comply.js.map +1 -1
  66. package/dist/lib/testing/compliance/storyboard-tracks.d.ts +24 -0
  67. package/dist/lib/testing/compliance/storyboard-tracks.d.ts.map +1 -0
  68. package/dist/lib/testing/compliance/storyboard-tracks.js +157 -0
  69. package/dist/lib/testing/compliance/storyboard-tracks.js.map +1 -0
  70. package/dist/lib/testing/compliance/types.d.ts +1 -1
  71. package/dist/lib/testing/compliance/types.d.ts.map +1 -1
  72. package/dist/lib/testing/index.d.ts +2 -1
  73. package/dist/lib/testing/index.d.ts.map +1 -1
  74. package/dist/lib/testing/index.js +26 -1
  75. package/dist/lib/testing/index.js.map +1 -1
  76. package/dist/lib/testing/orchestrator.d.ts +8 -0
  77. package/dist/lib/testing/orchestrator.d.ts.map +1 -1
  78. package/dist/lib/testing/orchestrator.js +11 -0
  79. package/dist/lib/testing/orchestrator.js.map +1 -1
  80. package/dist/lib/testing/scenarios/brand-rights.d.ts +23 -0
  81. package/dist/lib/testing/scenarios/brand-rights.d.ts.map +1 -0
  82. package/dist/lib/testing/scenarios/brand-rights.js +144 -0
  83. package/dist/lib/testing/scenarios/brand-rights.js.map +1 -0
  84. package/dist/lib/testing/scenarios/capabilities.d.ts.map +1 -1
  85. package/dist/lib/testing/scenarios/capabilities.js +11 -2
  86. package/dist/lib/testing/scenarios/capabilities.js.map +1 -1
  87. package/dist/lib/testing/scenarios/governance.d.ts.map +1 -1
  88. package/dist/lib/testing/scenarios/governance.js +5 -0
  89. package/dist/lib/testing/scenarios/governance.js.map +1 -1
  90. package/dist/lib/testing/scenarios/index.d.ts +2 -0
  91. package/dist/lib/testing/scenarios/index.d.ts.map +1 -1
  92. package/dist/lib/testing/scenarios/index.js +10 -2
  93. package/dist/lib/testing/scenarios/index.js.map +1 -1
  94. package/dist/lib/testing/scenarios/media-buy.d.ts.map +1 -1
  95. package/dist/lib/testing/scenarios/media-buy.js +22 -3
  96. package/dist/lib/testing/scenarios/media-buy.js.map +1 -1
  97. package/dist/lib/testing/scenarios/trusted-match.d.ts +22 -0
  98. package/dist/lib/testing/scenarios/trusted-match.d.ts.map +1 -0
  99. package/dist/lib/testing/scenarios/trusted-match.js +128 -0
  100. package/dist/lib/testing/scenarios/trusted-match.js.map +1 -0
  101. package/dist/lib/testing/storyboard/context.d.ts +34 -0
  102. package/dist/lib/testing/storyboard/context.d.ts.map +1 -0
  103. package/dist/lib/testing/storyboard/context.js +257 -0
  104. package/dist/lib/testing/storyboard/context.js.map +1 -0
  105. package/dist/lib/testing/storyboard/index.d.ts +15 -0
  106. package/dist/lib/testing/storyboard/index.d.ts.map +1 -0
  107. package/dist/lib/testing/storyboard/index.js +48 -0
  108. package/dist/lib/testing/storyboard/index.js.map +1 -0
  109. package/dist/lib/testing/storyboard/loader.d.ts +53 -0
  110. package/dist/lib/testing/storyboard/loader.d.ts.map +1 -0
  111. package/dist/lib/testing/storyboard/loader.js +114 -0
  112. package/dist/lib/testing/storyboard/loader.js.map +1 -0
  113. package/dist/lib/testing/storyboard/path.d.ts +29 -0
  114. package/dist/lib/testing/storyboard/path.d.ts.map +1 -0
  115. package/dist/lib/testing/storyboard/path.js +121 -0
  116. package/dist/lib/testing/storyboard/path.js.map +1 -0
  117. package/dist/lib/testing/storyboard/request-builder.d.ts +28 -0
  118. package/dist/lib/testing/storyboard/request-builder.d.ts.map +1 -0
  119. package/dist/lib/testing/storyboard/request-builder.js +410 -0
  120. package/dist/lib/testing/storyboard/request-builder.js.map +1 -0
  121. package/dist/lib/testing/storyboard/runner.d.ts +24 -0
  122. package/dist/lib/testing/storyboard/runner.d.ts.map +1 -0
  123. package/dist/lib/testing/storyboard/runner.js +280 -0
  124. package/dist/lib/testing/storyboard/runner.js.map +1 -0
  125. package/dist/lib/testing/storyboard/task-map.d.ts +21 -0
  126. package/dist/lib/testing/storyboard/task-map.d.ts.map +1 -0
  127. package/dist/lib/testing/storyboard/task-map.js +84 -0
  128. package/dist/lib/testing/storyboard/task-map.js.map +1 -0
  129. package/dist/lib/testing/storyboard/types.d.ts +156 -0
  130. package/dist/lib/testing/storyboard/types.d.ts.map +1 -0
  131. package/dist/lib/testing/storyboard/types.js +10 -0
  132. package/dist/lib/testing/storyboard/types.js.map +1 -0
  133. package/dist/lib/testing/storyboard/validations.d.ts +17 -0
  134. package/dist/lib/testing/storyboard/validations.d.ts.map +1 -0
  135. package/dist/lib/testing/storyboard/validations.js +166 -0
  136. package/dist/lib/testing/storyboard/validations.js.map +1 -0
  137. package/dist/lib/testing/types.d.ts +4 -1
  138. package/dist/lib/testing/types.d.ts.map +1 -1
  139. package/dist/lib/types/core.generated.d.ts +36 -23
  140. package/dist/lib/types/core.generated.d.ts.map +1 -1
  141. package/dist/lib/types/core.generated.js +1 -1
  142. package/dist/lib/types/schemas.generated.d.ts +1098 -770
  143. package/dist/lib/types/schemas.generated.d.ts.map +1 -1
  144. package/dist/lib/types/schemas.generated.js +163 -76
  145. package/dist/lib/types/schemas.generated.js.map +1 -1
  146. package/dist/lib/types/tools.generated.d.ts +314 -24
  147. package/dist/lib/types/tools.generated.d.ts.map +1 -1
  148. package/dist/lib/utils/capabilities.d.ts +4 -1
  149. package/dist/lib/utils/capabilities.d.ts.map +1 -1
  150. package/dist/lib/utils/capabilities.js +25 -1
  151. package/dist/lib/utils/capabilities.js.map +1 -1
  152. package/dist/lib/utils/response-schemas.d.ts.map +1 -1
  153. package/dist/lib/utils/response-schemas.js +34 -3
  154. package/dist/lib/utils/response-schemas.js.map +1 -1
  155. package/dist/lib/utils/validate-user-agent.d.ts +8 -0
  156. package/dist/lib/utils/validate-user-agent.d.ts.map +1 -0
  157. package/dist/lib/utils/validate-user-agent.js +15 -0
  158. package/dist/lib/utils/validate-user-agent.js.map +1 -0
  159. package/dist/lib/version.d.ts +9 -3
  160. package/dist/lib/version.d.ts.map +1 -1
  161. package/dist/lib/version.js +10 -4
  162. package/dist/lib/version.js.map +1 -1
  163. package/docs/README.md +42 -0
  164. package/docs/guides/BUILD-AN-AGENT.md +292 -0
  165. package/docs/llms.txt +634 -0
  166. package/examples/README.md +106 -0
  167. package/examples/adcp.config.json +30 -0
  168. package/examples/basic-a2a.ts +76 -0
  169. package/examples/basic-mcp.ts +50 -0
  170. package/examples/batch-preview-test.ts +266 -0
  171. package/examples/conversation-client.ts +291 -0
  172. package/examples/debug-preview-response.ts +73 -0
  173. package/examples/debug-preview-with-logging.ts +50 -0
  174. package/examples/easy-config-demo.ts +242 -0
  175. package/examples/env-config.ts +51 -0
  176. package/examples/error-compliant-server.ts +237 -0
  177. package/examples/generative-creative-demo.ts +205 -0
  178. package/examples/inspect-card-formats.ts +161 -0
  179. package/examples/logger-usage.ts +165 -0
  180. package/examples/oauth-cli-example.ts +154 -0
  181. package/examples/pr78-async-patterns-demo.ts +247 -0
  182. package/examples/signals-agent.ts +162 -0
  183. package/examples/simple-getting-started.ts +225 -0
  184. package/examples/simple-protocol-demo.ts +75 -0
  185. package/examples/test-helpers-demo.ts +239 -0
  186. package/examples/zod-validation-example.ts +126 -0
  187. package/package.json +12 -2
  188. package/skills/adcp/SKILL.md +13 -2
  189. package/storyboards/audience_sync.yaml +199 -0
  190. package/storyboards/behavioral_analysis.yaml +244 -0
  191. package/storyboards/brand_rights.yaml +131 -0
  192. package/storyboards/creative_ad_server.yaml +171 -0
  193. package/storyboards/creative_sales_agent.yaml +169 -0
  194. package/storyboards/creative_template.yaml +306 -0
  195. package/storyboards/deterministic_testing.yaml +925 -0
  196. package/storyboards/error_compliance.yaml +231 -0
  197. package/storyboards/governance_content_standards.yaml +213 -0
  198. package/storyboards/governance_property_lists.yaml +372 -0
  199. package/storyboards/media_buy_catalog_creative.yaml +457 -0
  200. package/storyboards/media_buy_governance_escalation.yaml +467 -0
  201. package/storyboards/media_buy_guaranteed_approval.yaml +396 -0
  202. package/storyboards/media_buy_non_guaranteed.yaml +288 -0
  203. package/storyboards/media_buy_proposal_mode.yaml +369 -0
  204. package/storyboards/media_buy_seller.yaml +560 -0
  205. package/storyboards/media_buy_state_machine.yaml +254 -0
  206. package/storyboards/schema.yaml +65 -0
  207. package/storyboards/schema_validation.yaml +166 -0
  208. package/storyboards/si_session.yaml +384 -0
  209. package/storyboards/signal_marketplace.yaml +283 -0
  210. package/storyboards/signal_owned.yaml +211 -0
@@ -0,0 +1,51 @@
1
+ // Environment Configuration Example
2
+ import { AdCPClient } from '@adcp/client';
3
+
4
+ async function envConfigExample() {
5
+ // Load agents from environment using factory method
6
+ // Set ADCP_AGENTS_CONFIG (or SALES_AGENTS_CONFIG) in your .env file like:
7
+ // ADCP_AGENTS_CONFIG='[{"id":"test-agent","name":"Test Agent","agent_uri":"https://test-agent.example.com","protocol":"mcp","auth_token":"your-token"}]'
8
+
9
+ const client = AdCPClient.fromEnv();
10
+
11
+ if (client.agentCount === 0) {
12
+ console.log('No agents configured. Set ADCP_AGENTS_CONFIG environment variable.');
13
+ return;
14
+ }
15
+
16
+ console.log(`Loaded ${client.agentCount} agents from environment:`);
17
+ client.getAgentConfigs().forEach(agent => {
18
+ console.log(` - ${agent.name} (${agent.protocol.toUpperCase()}) at ${agent.agent_uri}`);
19
+ });
20
+
21
+ // Test all agents
22
+ try {
23
+ const agentCollection = client.allAgents();
24
+ const results = await agentCollection.getProducts({
25
+ brief: 'Looking for advertising inventory for Q4 campaigns',
26
+ promoted_offering: 'Holiday season promotions',
27
+ });
28
+
29
+ console.log('\nTest Results:');
30
+ results.forEach(result => {
31
+ if (result.status === 'completed') {
32
+ console.log(`${result.metadata.agent.name}: āœ… (${result.data?.products?.length || 0} products)`);
33
+ } else {
34
+ console.log(`${result.metadata.agent.name}: āŒ Error: ${result.error || 'Unknown error'}`);
35
+ }
36
+ });
37
+
38
+ // Summary
39
+ const successful = results.filter(r => r.status === 'completed').length;
40
+ const failed = results.length - successful;
41
+
42
+ console.log(`\nSummary: ${successful} successful, ${failed} failed`);
43
+ } catch (error) {
44
+ console.error('Error testing agents:', error);
45
+ }
46
+ }
47
+
48
+ // Run example
49
+ if (require.main === module) {
50
+ envConfigExample();
51
+ }
@@ -0,0 +1,237 @@
1
+ /**
2
+ * Example: AdCP-Compliant MCP Server
3
+ *
4
+ * Demonstrates building a server using @adcp/client response builders
5
+ * for type-safe responses. Run with:
6
+ *
7
+ * npx tsx examples/error-compliant-server.ts
8
+ *
9
+ * Then test with:
10
+ *
11
+ * npx @adcp/client comply http://localhost:3456/mcp
12
+ */
13
+
14
+ import {
15
+ createTaskCapableServer,
16
+ adcpError,
17
+ capabilitiesResponse,
18
+ productsResponse,
19
+ mediaBuyResponse,
20
+ deliveryResponse,
21
+ serve,
22
+ GetProductsRequestSchema,
23
+ CreateMediaBuyRequestSchema,
24
+ GetMediaBuyDeliveryRequestSchema,
25
+ } from '@adcp/client';
26
+ import type { Product, GetAdCPCapabilitiesResponse } from '@adcp/client';
27
+
28
+ // CreateMediaBuyRequestSchema requires account/brand per spec, but a lenient
29
+ // version lets intentionally-incomplete requests reach the handler so it can
30
+ // return proper AdCP structured errors instead of generic MCP validation errors.
31
+ const LenientCreateMediaBuyInput = CreateMediaBuyRequestSchema.extend({
32
+ account: CreateMediaBuyRequestSchema.shape.account.optional(),
33
+ brand: CreateMediaBuyRequestSchema.shape.brand.optional(),
34
+ });
35
+
36
+ // ---------------------------------------------------------------------------
37
+ // Product catalog — typed as Product[] so the compiler enforces the schema
38
+ // ---------------------------------------------------------------------------
39
+ const PRODUCTS: Product[] = [
40
+ {
41
+ product_id: 'prod_display_300x250',
42
+ name: 'Display Banner 300x250',
43
+ description: 'Standard IAB display banner ad unit served across premium news and lifestyle sites.',
44
+ publisher_properties: [{ publisher_domain: 'example-publisher.com', selection_type: 'all' }],
45
+ channels: ['display'],
46
+ format_ids: [
47
+ { agent_url: 'https://creatives.adcontextprotocol.org', id: 'display_static', width: 300, height: 250 },
48
+ ],
49
+ delivery_type: 'non_guaranteed',
50
+ pricing_options: [
51
+ {
52
+ pricing_option_id: 'po_cpm',
53
+ pricing_model: 'cpm',
54
+ fixed_price: 5.0,
55
+ currency: 'USD',
56
+ min_spend_per_package: 500,
57
+ },
58
+ ],
59
+ },
60
+ {
61
+ product_id: 'prod_video_pre_roll',
62
+ name: 'Pre-Roll Video 15s',
63
+ description: 'Skippable pre-roll video ads served on premium video content.',
64
+ publisher_properties: [{ publisher_domain: 'example-publisher.com', selection_type: 'all' }],
65
+ channels: ['olv'],
66
+ format_ids: [{ agent_url: 'https://creatives.adcontextprotocol.org', id: 'video_hosted' }],
67
+ delivery_type: 'non_guaranteed',
68
+ pricing_options: [
69
+ {
70
+ pricing_option_id: 'po_cpm',
71
+ pricing_model: 'cpm',
72
+ fixed_price: 12.0,
73
+ currency: 'USD',
74
+ min_spend_per_package: 1000,
75
+ },
76
+ ],
77
+ },
78
+ ];
79
+
80
+ // ---------------------------------------------------------------------------
81
+ // Rate limit state (module-scoped — persists across per-request server instances)
82
+ // ---------------------------------------------------------------------------
83
+ let requestCount = 0;
84
+ const RATE_LIMIT = 50;
85
+ const RATE_WINDOW_MS = 60_000;
86
+ let windowStart = Date.now();
87
+
88
+ function checkRateLimit() {
89
+ const now = Date.now();
90
+ if (now - windowStart > RATE_WINDOW_MS) {
91
+ requestCount = 0;
92
+ windowStart = now;
93
+ }
94
+ requestCount++;
95
+ if (requestCount > RATE_LIMIT) {
96
+ return adcpError('RATE_LIMITED', {
97
+ message: 'Request rate exceeded',
98
+ retry_after: Math.ceil((windowStart + RATE_WINDOW_MS - now) / 1000),
99
+ details: { limit: RATE_LIMIT, remaining: 0, window_seconds: RATE_WINDOW_MS / 1000, scope: 'global' },
100
+ });
101
+ }
102
+ return null;
103
+ }
104
+
105
+ // ---------------------------------------------------------------------------
106
+ // Server factory (McpServer.connect() can only be called once per instance)
107
+ // ---------------------------------------------------------------------------
108
+ function createAgentServer() {
109
+ const server = createTaskCapableServer('Example AdCP Agent', '1.0.0');
110
+
111
+ // --- get_adcp_capabilities ---
112
+ server.tool('get_adcp_capabilities', {}, async () => {
113
+ const limited = checkRateLimit();
114
+ if (limited) return limited;
115
+
116
+ const capabilities: GetAdCPCapabilitiesResponse = {
117
+ adcp: { major_versions: [3] },
118
+ supported_protocols: ['media_buy'],
119
+ media_buy: {
120
+ features: {
121
+ inline_creative_management: false,
122
+ property_list_filtering: false,
123
+ content_standards: false,
124
+ },
125
+ },
126
+ };
127
+ return capabilitiesResponse(capabilities);
128
+ });
129
+
130
+ // --- get_products ---
131
+ server.tool('get_products', GetProductsRequestSchema.shape, async () => {
132
+ const limited = checkRateLimit();
133
+ if (limited) return limited;
134
+
135
+ return productsResponse({ products: PRODUCTS });
136
+ });
137
+
138
+ // --- create_media_buy ---
139
+ server.tool(
140
+ 'create_media_buy',
141
+ LenientCreateMediaBuyInput.shape,
142
+ async ({ buyer_ref, start_time, end_time, packages }) => {
143
+ const limited = checkRateLimit();
144
+ if (limited) return limited;
145
+
146
+ if (new Date(end_time) <= new Date(start_time)) {
147
+ return adcpError('INVALID_REQUEST', {
148
+ message: 'end_time must be after start_time',
149
+ field: 'end_time',
150
+ suggestion: 'Set end_time to a date after start_time',
151
+ });
152
+ }
153
+
154
+ if (packages) {
155
+ for (let i = 0; i < packages.length; i++) {
156
+ const pkg = packages[i]!;
157
+
158
+ if (pkg.budget < 0) {
159
+ return adcpError('INVALID_REQUEST', {
160
+ message: 'Budget must be non-negative',
161
+ field: `packages[${i}].budget`,
162
+ suggestion: 'Set budget to 0 or greater',
163
+ });
164
+ }
165
+
166
+ const product = PRODUCTS.find(p => p.product_id === pkg.product_id);
167
+ if (!product) {
168
+ return adcpError('PRODUCT_NOT_FOUND', {
169
+ message: `Product '${pkg.product_id}' not found`,
170
+ field: `packages[${i}].product_id`,
171
+ suggestion: 'Use get_products to discover available products',
172
+ });
173
+ }
174
+
175
+ const pricing = product.pricing_options.find(po => po.pricing_option_id === pkg.pricing_option_id);
176
+ if (
177
+ pricing &&
178
+ 'min_spend_per_package' in pricing &&
179
+ pricing.min_spend_per_package != null &&
180
+ pkg.budget < pricing.min_spend_per_package
181
+ ) {
182
+ return adcpError('BUDGET_TOO_LOW', {
183
+ message: `Budget ${pkg.budget} is below minimum ${pricing.min_spend_per_package} for ${product.name}`,
184
+ field: `packages[${i}].budget`,
185
+ suggestion: `Increase budget to at least ${pricing.min_spend_per_package}`,
186
+ details: { minimum_budget: pricing.min_spend_per_package, currency: 'USD' },
187
+ });
188
+ }
189
+ }
190
+ }
191
+
192
+ const mediaBuyId = `mb_${Date.now()}`;
193
+
194
+ return mediaBuyResponse({
195
+ media_buy_id: mediaBuyId,
196
+ buyer_ref,
197
+ packages: (packages ?? []).map((pkg, i) => ({
198
+ package_id: `pkg_${i}_${Date.now()}`,
199
+ buyer_ref: pkg.buyer_ref,
200
+ product_id: pkg.product_id,
201
+ pricing_option_id: pkg.pricing_option_id,
202
+ budget: pkg.budget,
203
+ })),
204
+ });
205
+ }
206
+ );
207
+
208
+ // --- get_media_buy_delivery ---
209
+ server.tool('get_media_buy_delivery', GetMediaBuyDeliveryRequestSchema.shape, async ({ media_buy_ids }) => {
210
+ const limited = checkRateLimit();
211
+ if (limited) return limited;
212
+
213
+ const ids = media_buy_ids ?? [];
214
+ const now = new Date();
215
+ const yesterday = new Date(now.getTime() - 86400000);
216
+
217
+ return deliveryResponse({
218
+ reporting_period: {
219
+ start: yesterday.toISOString(),
220
+ end: now.toISOString(),
221
+ },
222
+ media_buy_deliveries: ids.map(id => ({
223
+ media_buy_id: id,
224
+ status: 'active' as const,
225
+ totals: { impressions: 0, spend: 0 },
226
+ by_package: [],
227
+ })),
228
+ });
229
+ });
230
+
231
+ return server;
232
+ }
233
+
234
+ // ---------------------------------------------------------------------------
235
+ // Start the server
236
+ // ---------------------------------------------------------------------------
237
+ serve(createAgentServer, { port: 3456 });
@@ -0,0 +1,205 @@
1
+ #!/usr/bin/env tsx
2
+ // Demonstrates the new generative creative format support introduced in AdCP v1.7.0
3
+ // This example shows how to use the new format_id and assets structure for both
4
+ // static and generative creative workflows
5
+
6
+ import { ADCPMultiAgentClient, type SyncCreativesRequest } from '../src/lib';
7
+
8
+ async function demonstrateGenerativeCreatives() {
9
+ console.log('šŸŽØ Generative Creative Format Demo');
10
+ console.log('===================================\n');
11
+
12
+ // Initialize client from environment config
13
+ const client = ADCPMultiAgentClient.fromEnv();
14
+
15
+ // Get first available agent (just for demo purposes)
16
+ const agentIds = client.getAgentIds();
17
+ if (agentIds.length === 0) {
18
+ throw new Error('No agents configured. Please set SALES_AGENTS_CONFIG environment variable.');
19
+ }
20
+
21
+ const agent = client.agent(agentIds[0]);
22
+ console.log(`āœ… Using agent: ${agent.config.name}`);
23
+ console.log(` URI: ${agent.config.agent_uri}`);
24
+ console.log(` Protocol: ${agent.config.protocol}\n`);
25
+
26
+ // Example 1: Traditional static creative with new format
27
+ console.log('šŸ“ Example 1: Static Creative with new format_id structure\n');
28
+
29
+ const staticCreativeRequest: SyncCreativesRequest = {
30
+ creatives: [
31
+ {
32
+ creative_id: `static_banner_${Date.now()}`,
33
+ name: 'Static Display Banner 300x250',
34
+ format_id: {
35
+ agent_url: 'https://creative.adcontextprotocol.org',
36
+ id: 'display_300x250',
37
+ },
38
+ assets: {
39
+ image: {
40
+ asset_type: 'image',
41
+ url: 'https://example.com/banner-300x250.jpg',
42
+ width: 300,
43
+ height: 250,
44
+ alt_text: 'Summer sale banner',
45
+ },
46
+ click_url: {
47
+ asset_type: 'url',
48
+ url: 'https://example.com/summer-sale',
49
+ description: 'Landing page for summer sale campaign',
50
+ },
51
+ },
52
+ tags: ['display', 'static', 'summer-sale'],
53
+ },
54
+ ],
55
+ };
56
+
57
+ console.log('Static Creative Structure:');
58
+ console.log(JSON.stringify(staticCreativeRequest, null, 2));
59
+ console.log('\n' + '-'.repeat(50) + '\n');
60
+
61
+ // Example 2: Generative creative with brand context
62
+ console.log('šŸ“ Example 2: Generative Creative with brand_manifest\n');
63
+
64
+ const generativeCreativeRequest: SyncCreativesRequest = {
65
+ creatives: [
66
+ {
67
+ creative_id: `gen_banner_${Date.now()}`,
68
+ name: 'AI-Generated Display Banner',
69
+ format_id: {
70
+ agent_url: 'https://creative.adcontextprotocol.org',
71
+ id: 'display_300x250_generative',
72
+ },
73
+ assets: {
74
+ brand_context: {
75
+ asset_type: 'url',
76
+ url: 'https://example.com',
77
+ description: 'Brand website for context extraction',
78
+ },
79
+ generation_prompt: {
80
+ asset_type: 'text',
81
+ content: 'Create a vibrant summer sale banner highlighting 30% off outdoor furniture',
82
+ },
83
+ logo: {
84
+ asset_type: 'image',
85
+ url: 'https://example.com/logo.png',
86
+ width: 100,
87
+ height: 100,
88
+ },
89
+ },
90
+ inputs: [
91
+ {
92
+ name: 'Desktop View',
93
+ macros: {
94
+ DEVICE_TYPE: 'desktop',
95
+ },
96
+ context_description: 'Preview for desktop browsers at 1920x1080',
97
+ },
98
+ {
99
+ name: 'Mobile View',
100
+ macros: {
101
+ DEVICE_TYPE: 'mobile',
102
+ },
103
+ context_description: 'Preview for mobile devices at 375x667',
104
+ },
105
+ ],
106
+ tags: ['display', 'generative', 'ai', 'summer-sale'],
107
+ },
108
+ ],
109
+ };
110
+
111
+ console.log('Generative Creative Structure:');
112
+ console.log(JSON.stringify(generativeCreativeRequest, null, 2));
113
+ console.log('\n' + '-'.repeat(50) + '\n');
114
+
115
+ // Example 3: Approval workflow for generative creative
116
+ console.log('šŸ“ Example 3: Approving a Generative Creative\n');
117
+
118
+ const approvalRequest: SyncCreativesRequest = {
119
+ creatives: [
120
+ {
121
+ creative_id: 'gen_banner_12345', // Existing creative ID from previous sync
122
+ name: 'AI-Generated Display Banner',
123
+ format_id: {
124
+ agent_url: 'https://creative.adcontextprotocol.org',
125
+ id: 'display_300x250_generative',
126
+ },
127
+ assets: {
128
+ brand_context: {
129
+ asset_type: 'url',
130
+ url: 'https://example.com',
131
+ description: 'Brand website for context extraction',
132
+ },
133
+ generation_prompt: {
134
+ asset_type: 'text',
135
+ content: 'Create a vibrant summer sale banner highlighting 30% off outdoor furniture',
136
+ },
137
+ },
138
+ approved: true, // Approve the generated preview
139
+ },
140
+ ],
141
+ patch: true, // Only update the approval status
142
+ };
143
+
144
+ console.log('Approval Request Structure:');
145
+ console.log(JSON.stringify(approvalRequest, null, 2));
146
+ console.log('\n' + '-'.repeat(50) + '\n');
147
+
148
+ // Example 4: Request regeneration with updated prompt
149
+ console.log('šŸ“ Example 4: Request Regeneration\n');
150
+
151
+ const regenerationRequest: SyncCreativesRequest = {
152
+ creatives: [
153
+ {
154
+ creative_id: 'gen_banner_12345',
155
+ name: 'AI-Generated Display Banner',
156
+ format_id: {
157
+ agent_url: 'https://creative.adcontextprotocol.org',
158
+ id: 'display_300x250_generative',
159
+ },
160
+ assets: {
161
+ brand_context: {
162
+ asset_type: 'url',
163
+ url: 'https://example.com',
164
+ description: 'Brand website for context extraction',
165
+ },
166
+ generation_prompt: {
167
+ asset_type: 'text',
168
+ content:
169
+ 'Create a warm, inviting summer sale banner with emphasis on comfort and quality. Show 30% off outdoor furniture with natural colors.',
170
+ },
171
+ },
172
+ approved: false, // Request regeneration with updated prompt
173
+ },
174
+ ],
175
+ patch: true,
176
+ };
177
+
178
+ console.log('Regeneration Request Structure:');
179
+ console.log(JSON.stringify(regenerationRequest, null, 2));
180
+ console.log('\n' + '-'.repeat(50) + '\n');
181
+
182
+ console.log('šŸŽ‰ Demo complete!');
183
+ console.log('\nšŸ“š Key Changes in AdCP v1.7.0:');
184
+ console.log(' āœ“ format_id is now an object with agent_url and id');
185
+ console.log(' āœ“ assets is now a flexible object keyed by asset_role');
186
+ console.log(' āœ“ New asset types: url and brand_manifest');
187
+ console.log(' āœ“ inputs array for defining preview contexts');
188
+ console.log(' āœ“ approved field for generative creative workflows');
189
+ console.log(' āœ“ context_description for AI-generated content guidance');
190
+ }
191
+
192
+ // Run the demo
193
+ if (require.main === module) {
194
+ demonstrateGenerativeCreatives()
195
+ .then(() => {
196
+ console.log('\n✨ Done!');
197
+ process.exit(0);
198
+ })
199
+ .catch(error => {
200
+ console.error('Fatal error:', error);
201
+ process.exit(1);
202
+ });
203
+ }
204
+
205
+ export { demonstrateGenerativeCreatives };
@@ -0,0 +1,161 @@
1
+ #!/usr/bin/env tsx
2
+
3
+ /**
4
+ * Inspect card format definitions from creative agent
5
+ *
6
+ * This will help us understand:
7
+ * 1. What format IDs are available for cards (product_card, format_card)
8
+ * 2. What assets those formats expect (using new `assets` field or deprecated `assets_required`)
9
+ * 3. How to properly structure creative_manifest for cards
10
+ */
11
+
12
+ import { AdCPClient } from '../src/lib/core/AdCPClient';
13
+ import { getFormatAssets, getRequiredAssets, getOptionalAssets, usesDeprecatedAssetsField } from '../src/lib';
14
+
15
+ const CREATIVE_AGENT_URL = process.env.CREATIVE_AGENT_URL || 'https://creative.adcontextprotocol.org/mcp';
16
+ const CREATIVE_AGENT_PROTOCOL = (process.env.CREATIVE_AGENT_PROTOCOL || 'mcp') as 'mcp' | 'a2a';
17
+
18
+ async function main() {
19
+ console.log('šŸ” Inspecting Card Format Definitions\n');
20
+
21
+ const creativeAgent = new AdCPClient({
22
+ id: 'creative_agent',
23
+ name: 'Creative Agent',
24
+ agent_uri: CREATIVE_AGENT_URL,
25
+ protocol: CREATIVE_AGENT_PROTOCOL,
26
+ });
27
+
28
+ console.log(`šŸ“” Connected to: ${CREATIVE_AGENT_URL}\n`);
29
+
30
+ // List all formats
31
+ console.log('šŸ“‹ Fetching all creative formats...');
32
+ const result = await creativeAgent.listCreativeFormats({});
33
+
34
+ if (!result.success || !result.data) {
35
+ console.error('āŒ Failed to fetch formats:', result.error);
36
+ process.exit(1);
37
+ }
38
+
39
+ const formats = result.data.formats || [];
40
+ console.log(`āœ… Found ${formats.length} formats\n`);
41
+
42
+ // Look for card formats
43
+ const cardFormats = formats.filter(
44
+ f =>
45
+ f.format_id.id.includes('card') ||
46
+ f.name?.toLowerCase().includes('card') ||
47
+ f.description?.toLowerCase().includes('card')
48
+ );
49
+
50
+ if (cardFormats.length === 0) {
51
+ console.log('āš ļø No formats with "card" in name/description found');
52
+ console.log('\nšŸ“‹ All available format IDs:');
53
+ formats.forEach(f => {
54
+ console.log(` - ${f.format_id.id}: ${f.name || 'Unnamed'}`);
55
+ });
56
+ } else {
57
+ console.log('═══════════════════════════════════════════════════════════');
58
+ console.log('CARD FORMATS FOUND');
59
+ console.log('═══════════════════════════════════════════════════════════\n');
60
+
61
+ cardFormats.forEach((format, index) => {
62
+ console.log(`\n${'═'.repeat(60)}`);
63
+ console.log(`Format ${index + 1}: ${format.name || 'Unnamed'}`);
64
+ console.log('─'.repeat(60));
65
+ console.log(`Format ID: ${format.format_id.id}`);
66
+ console.log(`Agent URL: ${format.format_id.agent_url}`);
67
+ console.log(`Type: ${format.type || 'N/A'}`);
68
+ console.log(`Description: ${format.description || 'N/A'}`);
69
+
70
+ const assets = getFormatAssets(format);
71
+ if (assets.length > 0) {
72
+ const requiredAssets = getRequiredAssets(format);
73
+ const optionalAssets = getOptionalAssets(format);
74
+ console.log(
75
+ `\nšŸ“¦ Assets: ${assets.length} total (${requiredAssets.length} required, ${optionalAssets.length} optional)`
76
+ );
77
+ if (usesDeprecatedAssetsField(format)) {
78
+ console.log(' āš ļø Using deprecated assets_required field');
79
+ }
80
+ assets.forEach(asset => {
81
+ if (asset.item_type === 'individual') {
82
+ console.log(`\n Asset: ${asset.asset_id}`);
83
+ console.log(` Type: ${asset.asset_type}`);
84
+ console.log(` Required: ${asset.required ? 'yes' : 'no'}`);
85
+ if ((asset as any).description) {
86
+ console.log(` Description: ${(asset as any).description}`);
87
+ }
88
+ if ((asset as any).default_value) {
89
+ console.log(` Default: ${JSON.stringify((asset as any).default_value)}`);
90
+ }
91
+ } else {
92
+ console.log(`\n Asset Group: ${asset.asset_group_id}`);
93
+ console.log(` Required: ${asset.required ? 'yes' : 'no'}`);
94
+ console.log(` Count: ${asset.min_count}-${asset.max_count}`);
95
+ }
96
+ });
97
+ } else {
98
+ console.log('\nāš ļø No assets defined (flexible format)');
99
+ }
100
+
101
+ if (format.preview_image) {
102
+ console.log(`\nšŸ–¼ļø Preview Image: ${format.preview_image}`);
103
+ }
104
+
105
+ if (format.format_card) {
106
+ console.log('\nšŸŽ“ This format has its own format_card:');
107
+ console.log(` Format ID: ${format.format_card.format_id.agent_url}/${format.format_card.format_id.id}`);
108
+ console.log(` Manifest: ${JSON.stringify(format.format_card.manifest, null, 2)}`);
109
+ }
110
+ });
111
+ }
112
+
113
+ // Also show what a typical format looks like
114
+ console.log('\n\n═══════════════════════════════════════════════════════════');
115
+ console.log('EXAMPLE: Standard Display Format (for reference)');
116
+ console.log('═══════════════════════════════════════════════════════════\n');
117
+
118
+ const displayFormat = formats.find(f => f.format_id.id.includes('display') && f.format_id.id.includes('300x250'));
119
+
120
+ if (displayFormat) {
121
+ console.log(`Format ID: ${displayFormat.format_id.id}`);
122
+ console.log(`Name: ${displayFormat.name || 'Unnamed'}`);
123
+ console.log(`Type: ${displayFormat.type || 'N/A'}`);
124
+
125
+ const displayAssets = getFormatAssets(displayFormat);
126
+ if (displayAssets.length > 0) {
127
+ const requiredAssets = getRequiredAssets(displayFormat);
128
+ const optionalAssets = getOptionalAssets(displayFormat);
129
+ console.log(
130
+ `\nšŸ“¦ Assets: ${displayAssets.length} total (${requiredAssets.length} required, ${optionalAssets.length} optional)`
131
+ );
132
+ if (usesDeprecatedAssetsField(displayFormat)) {
133
+ console.log(' āš ļø Using deprecated assets_required field');
134
+ }
135
+ displayAssets.forEach(asset => {
136
+ if (asset.item_type === 'individual') {
137
+ console.log(` - ${asset.asset_id} (${asset.asset_type})${asset.required ? ' *required*' : ' (optional)'}`);
138
+ } else {
139
+ console.log(
140
+ ` - [Group] ${asset.asset_group_id} (${asset.min_count}-${asset.max_count})${asset.required ? ' *required*' : ' (optional)'}`
141
+ );
142
+ }
143
+ });
144
+ }
145
+ } else {
146
+ console.log('āš ļø No standard 300x250 display format found');
147
+ }
148
+
149
+ console.log('\n\nšŸ’” Key Insights:');
150
+ console.log('─'.repeat(60));
151
+ console.log('1. Formats define their assets using `assets` field (v2.6+) or deprecated `assets_required`');
152
+ console.log('2. Use getFormatAssets() helper to access assets with backward compatibility');
153
+ console.log('3. creative_manifest.assets should map asset_id -> asset object');
154
+ console.log("4. Each asset_id must match the format's assets definition");
155
+ console.log('5. Asset types (ImageAsset, TextAsset, etc) depend on asset_type\n');
156
+ }
157
+
158
+ main().catch(error => {
159
+ console.error('Fatal error:', error);
160
+ process.exit(1);
161
+ });