@adcp/sdk 5.25.0 → 6.0.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 (298) hide show
  1. package/README.md +45 -7
  2. package/dist/lib/compliance-fixtures/index.d.ts +1 -1
  3. package/dist/lib/compliance-fixtures/index.js +1 -1
  4. package/dist/lib/conformance/runners.d.ts.map +1 -1
  5. package/dist/lib/conformance/runners.js +13 -1
  6. package/dist/lib/conformance/runners.js.map +1 -1
  7. package/dist/lib/core/AgentClient.d.ts.map +1 -1
  8. package/dist/lib/core/SingleAgentClient.d.ts.map +1 -1
  9. package/dist/lib/core/SingleAgentClient.js +15 -0
  10. package/dist/lib/core/SingleAgentClient.js.map +1 -1
  11. package/dist/lib/core/TaskExecutor.d.ts +7 -0
  12. package/dist/lib/core/TaskExecutor.d.ts.map +1 -1
  13. package/dist/lib/core/TaskExecutor.js +9 -2
  14. package/dist/lib/core/TaskExecutor.js.map +1 -1
  15. package/dist/lib/index.d.ts +1 -1
  16. package/dist/lib/index.d.ts.map +1 -1
  17. package/dist/lib/index.js +7 -8
  18. package/dist/lib/index.js.map +1 -1
  19. package/dist/lib/protocols/index.d.ts +3 -1
  20. package/dist/lib/protocols/index.d.ts.map +1 -1
  21. package/dist/lib/protocols/index.js +23 -14
  22. package/dist/lib/protocols/index.js.map +1 -1
  23. package/dist/lib/schemas/index.d.ts +1 -1
  24. package/dist/lib/schemas/index.js +1 -1
  25. package/dist/lib/server/create-adcp-server.d.ts +142 -11
  26. package/dist/lib/server/create-adcp-server.d.ts.map +1 -1
  27. package/dist/lib/server/create-adcp-server.js +211 -2
  28. package/dist/lib/server/create-adcp-server.js.map +1 -1
  29. package/dist/lib/server/ctx-metadata/backends/memory.d.ts +27 -0
  30. package/dist/lib/server/ctx-metadata/backends/memory.d.ts.map +1 -0
  31. package/dist/lib/server/ctx-metadata/backends/memory.js +72 -0
  32. package/dist/lib/server/ctx-metadata/backends/memory.js.map +1 -0
  33. package/dist/lib/server/ctx-metadata/backends/pg.d.ts +62 -0
  34. package/dist/lib/server/ctx-metadata/backends/pg.d.ts.map +1 -0
  35. package/dist/lib/server/ctx-metadata/backends/pg.js +145 -0
  36. package/dist/lib/server/ctx-metadata/backends/pg.js.map +1 -0
  37. package/dist/lib/server/ctx-metadata/index.d.ts +15 -0
  38. package/dist/lib/server/ctx-metadata/index.d.ts.map +1 -0
  39. package/dist/lib/server/ctx-metadata/index.js +28 -0
  40. package/dist/lib/server/ctx-metadata/index.js.map +1 -0
  41. package/dist/lib/server/ctx-metadata/store.d.ts +177 -0
  42. package/dist/lib/server/ctx-metadata/store.d.ts.map +1 -0
  43. package/dist/lib/server/ctx-metadata/store.js +327 -0
  44. package/dist/lib/server/ctx-metadata/store.js.map +1 -0
  45. package/dist/lib/server/ctx-metadata/wire-shape.d.ts +55 -0
  46. package/dist/lib/server/ctx-metadata/wire-shape.d.ts.map +1 -0
  47. package/dist/lib/server/ctx-metadata/wire-shape.js +121 -0
  48. package/dist/lib/server/ctx-metadata/wire-shape.js.map +1 -0
  49. package/dist/lib/server/decisioning/account.d.ts +309 -0
  50. package/dist/lib/server/decisioning/account.d.ts.map +1 -0
  51. package/dist/lib/server/decisioning/account.js +102 -0
  52. package/dist/lib/server/decisioning/account.js.map +1 -0
  53. package/dist/lib/server/decisioning/admin-router.d.ts +75 -0
  54. package/dist/lib/server/decisioning/admin-router.d.ts.map +1 -0
  55. package/dist/lib/server/decisioning/admin-router.js +120 -0
  56. package/dist/lib/server/decisioning/admin-router.js.map +1 -0
  57. package/dist/lib/server/decisioning/assembly-helpers.d.ts +204 -0
  58. package/dist/lib/server/decisioning/assembly-helpers.d.ts.map +1 -0
  59. package/dist/lib/server/decisioning/assembly-helpers.js +173 -0
  60. package/dist/lib/server/decisioning/assembly-helpers.js.map +1 -0
  61. package/dist/lib/server/decisioning/async-outcome.d.ts +154 -0
  62. package/dist/lib/server/decisioning/async-outcome.d.ts.map +1 -0
  63. package/dist/lib/server/decisioning/async-outcome.js +239 -0
  64. package/dist/lib/server/decisioning/async-outcome.js.map +1 -0
  65. package/dist/lib/server/decisioning/capabilities.d.ts +251 -0
  66. package/dist/lib/server/decisioning/capabilities.d.ts.map +1 -0
  67. package/dist/lib/server/decisioning/capabilities.js +16 -0
  68. package/dist/lib/server/decisioning/capabilities.js.map +1 -0
  69. package/dist/lib/server/decisioning/context.d.ts +212 -0
  70. package/dist/lib/server/decisioning/context.d.ts.map +1 -0
  71. package/dist/lib/server/decisioning/context.js +26 -0
  72. package/dist/lib/server/decisioning/context.js.map +1 -0
  73. package/dist/lib/server/decisioning/errors-typed.d.ts +104 -0
  74. package/dist/lib/server/decisioning/errors-typed.d.ts.map +1 -0
  75. package/dist/lib/server/decisioning/errors-typed.js +304 -0
  76. package/dist/lib/server/decisioning/errors-typed.js.map +1 -0
  77. package/dist/lib/server/decisioning/helpers.d.ts +131 -0
  78. package/dist/lib/server/decisioning/helpers.d.ts.map +1 -0
  79. package/dist/lib/server/decisioning/helpers.js +134 -0
  80. package/dist/lib/server/decisioning/helpers.js.map +1 -0
  81. package/dist/lib/server/decisioning/index.d.ts +46 -0
  82. package/dist/lib/server/decisioning/index.d.ts.map +1 -0
  83. package/dist/lib/server/decisioning/index.js +120 -0
  84. package/dist/lib/server/decisioning/index.js.map +1 -0
  85. package/dist/lib/server/decisioning/list-helpers.d.ts +53 -0
  86. package/dist/lib/server/decisioning/list-helpers.d.ts.map +1 -0
  87. package/dist/lib/server/decisioning/list-helpers.js +96 -0
  88. package/dist/lib/server/decisioning/list-helpers.js.map +1 -0
  89. package/dist/lib/server/decisioning/manifest-helpers.d.ts +56 -0
  90. package/dist/lib/server/decisioning/manifest-helpers.d.ts.map +1 -0
  91. package/dist/lib/server/decisioning/manifest-helpers.js +78 -0
  92. package/dist/lib/server/decisioning/manifest-helpers.js.map +1 -0
  93. package/dist/lib/server/decisioning/pagination.d.ts +21 -0
  94. package/dist/lib/server/decisioning/pagination.d.ts.map +1 -0
  95. package/dist/lib/server/decisioning/pagination.js +12 -0
  96. package/dist/lib/server/decisioning/pagination.js.map +1 -0
  97. package/dist/lib/server/decisioning/platform.d.ts +188 -0
  98. package/dist/lib/server/decisioning/platform.d.ts.map +1 -0
  99. package/dist/lib/server/decisioning/platform.js +19 -0
  100. package/dist/lib/server/decisioning/platform.js.map +1 -0
  101. package/dist/lib/server/decisioning/runtime/from-platform.d.ts +510 -0
  102. package/dist/lib/server/decisioning/runtime/from-platform.d.ts.map +1 -0
  103. package/dist/lib/server/decisioning/runtime/from-platform.js +2196 -0
  104. package/dist/lib/server/decisioning/runtime/from-platform.js.map +1 -0
  105. package/dist/lib/server/decisioning/runtime/postgres-task-registry.d.ts +114 -0
  106. package/dist/lib/server/decisioning/runtime/postgres-task-registry.d.ts.map +1 -0
  107. package/dist/lib/server/decisioning/runtime/postgres-task-registry.js +247 -0
  108. package/dist/lib/server/decisioning/runtime/postgres-task-registry.js.map +1 -0
  109. package/dist/lib/server/decisioning/runtime/protocol-for-tool.d.ts +32 -0
  110. package/dist/lib/server/decisioning/runtime/protocol-for-tool.d.ts.map +1 -0
  111. package/dist/lib/server/decisioning/runtime/protocol-for-tool.js +127 -0
  112. package/dist/lib/server/decisioning/runtime/protocol-for-tool.js.map +1 -0
  113. package/dist/lib/server/decisioning/runtime/task-registry.d.ts +105 -0
  114. package/dist/lib/server/decisioning/runtime/task-registry.d.ts.map +1 -0
  115. package/dist/lib/server/decisioning/runtime/task-registry.js +96 -0
  116. package/dist/lib/server/decisioning/runtime/task-registry.js.map +1 -0
  117. package/dist/lib/server/decisioning/runtime/to-context.d.ts +54 -0
  118. package/dist/lib/server/decisioning/runtime/to-context.d.ts.map +1 -0
  119. package/dist/lib/server/decisioning/runtime/to-context.js +166 -0
  120. package/dist/lib/server/decisioning/runtime/to-context.js.map +1 -0
  121. package/dist/lib/server/decisioning/runtime/validate-platform.d.ts +20 -0
  122. package/dist/lib/server/decisioning/runtime/validate-platform.d.ts.map +1 -0
  123. package/dist/lib/server/decisioning/runtime/validate-platform.js +93 -0
  124. package/dist/lib/server/decisioning/runtime/validate-platform.js.map +1 -0
  125. package/dist/lib/server/decisioning/specialisms/audiences.d.ts +72 -0
  126. package/dist/lib/server/decisioning/specialisms/audiences.d.ts.map +1 -0
  127. package/dist/lib/server/decisioning/specialisms/audiences.js +15 -0
  128. package/dist/lib/server/decisioning/specialisms/audiences.js.map +1 -0
  129. package/dist/lib/server/decisioning/specialisms/brand-rights.d.ts +92 -0
  130. package/dist/lib/server/decisioning/specialisms/brand-rights.d.ts.map +1 -0
  131. package/dist/lib/server/decisioning/specialisms/brand-rights.js +28 -0
  132. package/dist/lib/server/decisioning/specialisms/brand-rights.js.map +1 -0
  133. package/dist/lib/server/decisioning/specialisms/campaign-governance.d.ts +67 -0
  134. package/dist/lib/server/decisioning/specialisms/campaign-governance.d.ts.map +1 -0
  135. package/dist/lib/server/decisioning/specialisms/campaign-governance.js +31 -0
  136. package/dist/lib/server/decisioning/specialisms/campaign-governance.js.map +1 -0
  137. package/dist/lib/server/decisioning/specialisms/content-standards.d.ts +78 -0
  138. package/dist/lib/server/decisioning/specialisms/content-standards.d.ts.map +1 -0
  139. package/dist/lib/server/decisioning/specialisms/content-standards.js +35 -0
  140. package/dist/lib/server/decisioning/specialisms/content-standards.js.map +1 -0
  141. package/dist/lib/server/decisioning/specialisms/creative-ad-server.d.ts +81 -0
  142. package/dist/lib/server/decisioning/specialisms/creative-ad-server.d.ts.map +1 -0
  143. package/dist/lib/server/decisioning/specialisms/creative-ad-server.js +28 -0
  144. package/dist/lib/server/decisioning/specialisms/creative-ad-server.js.map +1 -0
  145. package/dist/lib/server/decisioning/specialisms/creative.d.ts +144 -0
  146. package/dist/lib/server/decisioning/specialisms/creative.d.ts.map +1 -0
  147. package/dist/lib/server/decisioning/specialisms/creative.js +19 -0
  148. package/dist/lib/server/decisioning/specialisms/creative.js.map +1 -0
  149. package/dist/lib/server/decisioning/specialisms/lists.d.ts +61 -0
  150. package/dist/lib/server/decisioning/specialisms/lists.d.ts.map +1 -0
  151. package/dist/lib/server/decisioning/specialisms/lists.js +30 -0
  152. package/dist/lib/server/decisioning/specialisms/lists.js.map +1 -0
  153. package/dist/lib/server/decisioning/specialisms/sales.d.ts +163 -0
  154. package/dist/lib/server/decisioning/specialisms/sales.d.ts.map +1 -0
  155. package/dist/lib/server/decisioning/specialisms/sales.js +64 -0
  156. package/dist/lib/server/decisioning/specialisms/sales.js.map +1 -0
  157. package/dist/lib/server/decisioning/specialisms/signals.d.ts +64 -0
  158. package/dist/lib/server/decisioning/specialisms/signals.d.ts.map +1 -0
  159. package/dist/lib/server/decisioning/specialisms/signals.js +28 -0
  160. package/dist/lib/server/decisioning/specialisms/signals.js.map +1 -0
  161. package/dist/lib/server/decisioning/start-time.d.ts +76 -0
  162. package/dist/lib/server/decisioning/start-time.d.ts.map +1 -0
  163. package/dist/lib/server/decisioning/start-time.js +81 -0
  164. package/dist/lib/server/decisioning/start-time.js.map +1 -0
  165. package/dist/lib/server/decisioning/status-changes.d.ts +165 -0
  166. package/dist/lib/server/decisioning/status-changes.d.ts.map +1 -0
  167. package/dist/lib/server/decisioning/status-changes.js +131 -0
  168. package/dist/lib/server/decisioning/status-changes.js.map +1 -0
  169. package/dist/lib/server/decisioning/status-mappers.d.ts +46 -0
  170. package/dist/lib/server/decisioning/status-mappers.d.ts.map +1 -0
  171. package/dist/lib/server/decisioning/status-mappers.js +46 -0
  172. package/dist/lib/server/decisioning/status-mappers.js.map +1 -0
  173. package/dist/lib/server/decisioning/tenant-registry.d.ts +289 -0
  174. package/dist/lib/server/decisioning/tenant-registry.d.ts.map +1 -0
  175. package/dist/lib/server/decisioning/tenant-registry.js +503 -0
  176. package/dist/lib/server/decisioning/tenant-registry.js.map +1 -0
  177. package/dist/lib/server/express-adapter.d.ts +1 -1
  178. package/dist/lib/server/express-adapter.js +1 -1
  179. package/dist/lib/server/governance.d.ts +1 -1
  180. package/dist/lib/server/governance.js +1 -1
  181. package/dist/lib/server/idempotency/store.d.ts +1 -1
  182. package/dist/lib/server/idempotency/store.js +1 -1
  183. package/dist/lib/server/index.d.ts +9 -2
  184. package/dist/lib/server/index.d.ts.map +1 -1
  185. package/dist/lib/server/index.js +79 -4
  186. package/dist/lib/server/index.js.map +1 -1
  187. package/dist/lib/server/legacy/v5/index.d.ts +38 -0
  188. package/dist/lib/server/legacy/v5/index.d.ts.map +1 -0
  189. package/dist/lib/server/legacy/v5/index.js +60 -0
  190. package/dist/lib/server/legacy/v5/index.js.map +1 -0
  191. package/dist/lib/server/normalize-errors.d.ts +88 -0
  192. package/dist/lib/server/normalize-errors.d.ts.map +1 -0
  193. package/dist/lib/server/normalize-errors.js +146 -0
  194. package/dist/lib/server/normalize-errors.js.map +1 -0
  195. package/dist/lib/server/pick-safe-details.d.ts +90 -0
  196. package/dist/lib/server/pick-safe-details.d.ts.map +1 -0
  197. package/dist/lib/server/pick-safe-details.js +148 -0
  198. package/dist/lib/server/pick-safe-details.js.map +1 -0
  199. package/dist/lib/server/postgres-state-store.d.ts +1 -1
  200. package/dist/lib/server/postgres-state-store.js +1 -1
  201. package/dist/lib/server/responses.d.ts +38 -0
  202. package/dist/lib/server/responses.d.ts.map +1 -1
  203. package/dist/lib/server/responses.js +38 -0
  204. package/dist/lib/server/responses.js.map +1 -1
  205. package/dist/lib/server/state-store.d.ts +1 -1
  206. package/dist/lib/server/state-store.js +1 -1
  207. package/dist/lib/server/test-controller.d.ts +10 -3
  208. package/dist/lib/server/test-controller.d.ts.map +1 -1
  209. package/dist/lib/server/test-controller.js +10 -3
  210. package/dist/lib/server/test-controller.js.map +1 -1
  211. package/dist/lib/testing/comply-controller.d.ts +47 -1
  212. package/dist/lib/testing/comply-controller.d.ts.map +1 -1
  213. package/dist/lib/testing/comply-controller.js +11 -4
  214. package/dist/lib/testing/comply-controller.js.map +1 -1
  215. package/dist/lib/testing/index.d.ts +1 -1
  216. package/dist/lib/testing/index.d.ts.map +1 -1
  217. package/dist/lib/testing/index.js.map +1 -1
  218. package/dist/lib/testing/personas/index.d.ts +143 -0
  219. package/dist/lib/testing/personas/index.d.ts.map +1 -0
  220. package/dist/lib/testing/personas/index.js +190 -0
  221. package/dist/lib/testing/personas/index.js.map +1 -0
  222. package/dist/lib/testing/storyboard/index.d.ts +1 -1
  223. package/dist/lib/testing/storyboard/index.d.ts.map +1 -1
  224. package/dist/lib/testing/storyboard/index.js +3 -2
  225. package/dist/lib/testing/storyboard/index.js.map +1 -1
  226. package/dist/lib/testing/storyboard/runner.d.ts +13 -0
  227. package/dist/lib/testing/storyboard/runner.d.ts.map +1 -1
  228. package/dist/lib/testing/storyboard/runner.js +179 -7
  229. package/dist/lib/testing/storyboard/runner.js.map +1 -1
  230. package/dist/lib/types/adcp.d.ts.map +1 -1
  231. package/dist/lib/types/adcp.js +1 -0
  232. package/dist/lib/types/adcp.js.map +1 -1
  233. package/dist/lib/types/asset-instances.d.ts +1 -0
  234. package/dist/lib/types/asset-instances.d.ts.map +1 -1
  235. package/dist/lib/types/core.generated.d.ts +203 -98
  236. package/dist/lib/types/core.generated.d.ts.map +1 -1
  237. package/dist/lib/types/core.generated.js +1 -1
  238. package/dist/lib/types/index.d.ts +1 -0
  239. package/dist/lib/types/index.d.ts.map +1 -1
  240. package/dist/lib/types/index.js.map +1 -1
  241. package/dist/lib/types/schemas.generated.d.ts +599 -159
  242. package/dist/lib/types/schemas.generated.d.ts.map +1 -1
  243. package/dist/lib/types/schemas.generated.js +175 -94
  244. package/dist/lib/types/schemas.generated.js.map +1 -1
  245. package/dist/lib/types/tools.generated.d.ts +315 -46
  246. package/dist/lib/types/tools.generated.d.ts.map +1 -1
  247. package/dist/lib/utils/capabilities.d.ts +1 -1
  248. package/dist/lib/utils/capabilities.d.ts.map +1 -1
  249. package/dist/lib/utils/capabilities.js +6 -0
  250. package/dist/lib/utils/capabilities.js.map +1 -1
  251. package/dist/lib/validation/schema-validator.d.ts +13 -0
  252. package/dist/lib/validation/schema-validator.d.ts.map +1 -1
  253. package/dist/lib/validation/schema-validator.js +240 -3
  254. package/dist/lib/validation/schema-validator.js.map +1 -1
  255. package/dist/lib/version.d.ts +3 -3
  256. package/dist/lib/version.d.ts.map +1 -1
  257. package/dist/lib/version.js +3 -3
  258. package/dist/lib/version.js.map +1 -1
  259. package/docs/guides/BUILD-AN-AGENT.md +30 -5
  260. package/docs/llms.txt +28 -17
  261. package/examples/README.md +3 -1
  262. package/examples/decisioning-platform-broadcast-tv.ts +300 -0
  263. package/examples/decisioning-platform-identity-graph.ts +214 -0
  264. package/examples/decisioning-platform-mock-seller.ts +332 -0
  265. package/examples/decisioning-platform-multi-tenant.ts +128 -0
  266. package/examples/decisioning-platform-programmatic.ts +254 -0
  267. package/examples/signals-agent.ts +1 -1
  268. package/package.json +13 -2
  269. package/skills/build-brand-rights-agent/SKILL.md +10 -3
  270. package/skills/build-creative-agent/SKILL.md +94 -64
  271. package/skills/build-decisioning-creative-template/SKILL.md +554 -0
  272. package/skills/build-decisioning-platform/SKILL.md +304 -0
  273. package/skills/build-decisioning-platform/advanced/BRAND-RIGHTS.md +25 -0
  274. package/skills/build-decisioning-platform/advanced/COMPLIANCE.md +23 -0
  275. package/skills/build-decisioning-platform/advanced/GOVERNANCE.md +24 -0
  276. package/skills/build-decisioning-platform/advanced/HITL.md +34 -0
  277. package/skills/build-decisioning-platform/advanced/IDEMPOTENCY.md +52 -0
  278. package/skills/build-decisioning-platform/advanced/MULTI-TENANT.md +47 -0
  279. package/skills/build-decisioning-platform/advanced/OAUTH.md +22 -0
  280. package/skills/build-decisioning-platform/advanced/REFERENCE.md +991 -0
  281. package/skills/build-decisioning-platform/advanced/SANDBOX.md +24 -0
  282. package/skills/build-decisioning-platform/advanced/STATE-MACHINE.md +52 -0
  283. package/skills/build-decisioning-signal-marketplace/SKILL.md +269 -0
  284. package/skills/build-generative-seller-agent/SKILL.md +89 -53
  285. package/skills/build-governance-agent/SKILL.md +76 -45
  286. package/skills/build-retail-media-agent/SKILL.md +87 -62
  287. package/skills/build-seller-agent/SKILL.md +384 -255
  288. package/skills/build-seller-agent/deployment.md +5 -3
  289. package/skills/build-seller-agent/specialisms/audience-sync.md +0 -2
  290. package/skills/build-seller-agent/specialisms/sales-broadcast-tv.md +0 -2
  291. package/skills/build-seller-agent/specialisms/sales-guaranteed.md +0 -2
  292. package/skills/build-seller-agent/specialisms/sales-non-guaranteed.md +0 -2
  293. package/skills/build-seller-agent/specialisms/sales-proposal-mode.md +0 -2
  294. package/skills/build-seller-agent/specialisms/sales-social.md +0 -2
  295. package/skills/build-seller-agent/specialisms/signed-requests.md +0 -2
  296. package/skills/build-si-agent/SKILL.md +40 -32
  297. package/skills/build-signals-agent/SKILL.md +139 -92
  298. package/skills/call-adcp-agent.previous/SKILL.md +5 -0
@@ -15,8 +15,9 @@ Companion to [`SKILL.md`](./SKILL.md). Read this only when you need deployment s
15
15
  Pass functions for `publicUrl` and `protectedResource`, branch on `ctx.host` in the factory, and turn on `trustForwardedHost` when a proxy terminates TLS:
16
16
 
17
17
  ```typescript
18
- import { serve, createAdcpServer, UnknownHostError, hostname } from '@adcp/sdk';
18
+ import { UnknownHostError, hostname } from '@adcp/sdk';
19
19
  import { verifyBearer } from '@adcp/sdk/server';
20
+ import { serve, createAdcpServer } from '@adcp/sdk/server/legacy/v5';
20
21
 
21
22
  // Host → adapter config. Whatever shape suits your deployment (DB, env, static).
22
23
  // Cache the CONFIG (not the AdcpServer). serve() still instantiates the
@@ -116,7 +117,8 @@ When your agent is _both_ an OAuth 2.1 AS (issues tokens) and a protected resour
116
117
 
117
118
  ```typescript
118
119
  import express from 'express';
119
- import { createAdcpServer, createExpressAdapter, verifyBearer, anyOf, verifyApiKey } from '@adcp/sdk/server';
120
+ import { createExpressAdapter, verifyBearer, anyOf, verifyApiKey } from '@adcp/sdk/server';
121
+ import { createAdcpServer } from '@adcp/sdk/server/legacy/v5';
120
122
  import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
121
123
  import { mcpAuthRouter } from '@modelcontextprotocol/sdk/server/auth/router.js';
122
124
 
@@ -388,7 +390,7 @@ You own: the `mcpAuthRouter` wiring (provider-specific), the per-request `transp
388
390
 
389
391
  ```typescript
390
392
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
391
- import { createAdcpServer } from '@adcp/sdk/server';
393
+ import { createAdcpServer } from '@adcp/sdk/server/legacy/v5';
392
394
 
393
395
  const server = createAdcpServer({
394
396
  name: 'Local Seller',
@@ -2,7 +2,6 @@
2
2
 
3
3
  Companion to [`../SKILL.md`](../SKILL.md). The SKILL.md baseline applies; this file covers only the deltas for `audience-sync`.
4
4
 
5
-
6
5
  Storyboard: `audience_sync`. Track is `audiences` — separate from the core seller lifecycle, but lives in this skill because identifier sync and account discovery sit next to media-buying.
7
6
 
8
7
  Required tools: `sync_audiences` and `list_accounts`. `sync_audiences` is overloaded — it handles three cases through its request payload:
@@ -60,4 +59,3 @@ createAdcpServer({
60
59
  **Identifier rules:** each `add` entry is a single-identifier object (`{hashed_email}` OR `{hashed_phone}`, not both). Values are SHA-256 of lowercased, trimmed input. Salting/normalization is out-of-band between buyer and platform — document your expected input format.
61
60
 
62
61
  **Platform types:** destinations span `['dsp', 'retail_media', 'social', 'audio', 'pmax']`. Each has its own `activation_key` shape — see `skills/build-signals-agent/SKILL.md` for activation patterns, which are shared across signals and audience sync.
63
-
@@ -2,7 +2,6 @@
2
2
 
3
3
  Companion to [`../SKILL.md`](../SKILL.md). The SKILL.md baseline applies; this file covers only the deltas for `sales-broadcast-tv`.
4
4
 
5
-
6
5
  Storyboard: `media_buy_broadcast_seller`. Broadcast has four protocol surfaces not used in digital.
7
6
 
8
7
  **Pricing** — unit-based (cost per spot). Until a `pricing_model: 'unit'` lands, express as CPM with a very high `fixed_price` that represents the cost per thousand spots equivalent, or use a custom pricing option ID and clarify in `description`.
@@ -68,4 +67,3 @@ Don't declare `measurement_windows: ['live', 'c3', 'c7']` — the Zod schema rej
68
67
  **Measurement windows on delivery** — each delivery row tags `measurement_window: 'live' | 'c3' | 'c7'`, `is_final: boolean`, and `supersedes_window` (for window upgrades). Live ratings mature in 24h, C3 in ~4d, C7 in ~8d. Final reconciliation lands ~15d after last air date.
69
68
 
70
69
  **Emit window_update webhooks** via `ctx.emitWebhook` (see [§ Webhooks](#webhooks-async-completion-signed-outbound) above). Use `operation_id: \`window_update.${media_buy_id}.${stage}\`` so C3 → C7 supersession retries share a stable idempotency_key.
71
-
@@ -2,7 +2,6 @@
2
2
 
3
3
  Companion to [`../SKILL.md`](../SKILL.md). The SKILL.md baseline applies; this file covers only the deltas for `sales-guaranteed`.
4
4
 
5
-
6
5
  Storyboard: `sales_guaranteed`. `create_media_buy` has **three return shapes**. Route on request signals FIRST — the specialism's name is about IO signing, but the baseline `media_buy_seller` storyboard exercises all three in sequence.
7
6
 
8
7
  | Request signal | Return | Why |
@@ -64,4 +63,3 @@ When the task completes, emit the final `create_media_buy` result (carrying `med
64
63
  Declare `requires_io_approval` in your `capabilities.features` for this path. For deterministic compliance testing, implement `forceTaskStatus` (not `forceMediaBuyStatus`) in your `TestControllerStore` to drive the task from `submitted → completed` without waiting for a human.
65
64
 
66
65
  **Governance denial (`GOVERNANCE_DENIED`).** Baseline `media_buy_seller/governance_denied*` scenarios exercise governance refusal. For sellers that compose with a governance agent, call `checkGovernance(...)` from `@adcp/sdk/server` at the top of `create_media_buy`. If the governance agent returns denial, surface with `governanceDeniedError(result)` so the error code is `GOVERNANCE_DENIED` and context echoes. Sellers that don't compose with governance will see these scenarios fail with `INVALID_REQUEST` — expected until upstream gates the scenarios behind a composition-claim specialism (tracked at adcontextprotocol/adcp#2521).
67
-
@@ -2,7 +2,6 @@
2
2
 
3
3
  Companion to [`../SKILL.md`](../SKILL.md). The SKILL.md baseline applies; this file covers only the deltas for `sales-non-guaranteed`.
4
4
 
5
-
6
5
  Storyboard: `media_buy_non_guaranteed`. The specialism hinges on `bid_price` and `update_media_buy`, neither of which the baseline example shows.
7
6
 
8
7
  Packages on `create_media_buy` carry `bid_price`. Validate it against the product's `floor_price`:
@@ -36,4 +35,3 @@ updateMediaBuy: async (params, ctx) => {
36
35
  ```
37
36
 
38
37
  `valid_actions` on an active non-guaranteed buy should include `pause`, `update_bid`, `get_delivery`. The framework auto-populates this when `createMediaBuy`/`updateMediaBuy` return with `status: 'active'`.
39
-
@@ -2,7 +2,6 @@
2
2
 
3
3
  Companion to [`../SKILL.md`](../SKILL.md). The SKILL.md baseline applies; this file covers only the deltas for `sales-proposal-mode`.
4
4
 
5
-
6
5
  Storyboard: `media_buy_proposal_mode`. The acceptance path inverts the baseline — buyer sends `proposal_id` + `total_budget`, no `packages`.
7
6
 
8
7
  `get_products` returns a `proposals[]` array alongside products:
@@ -48,4 +47,3 @@ createMediaBuy: async (params, ctx) => {
48
47
  // ... fall through to baseline packages path
49
48
  },
50
49
  ```
51
-
@@ -2,7 +2,6 @@
2
2
 
3
3
  Companion to [`../SKILL.md`](../SKILL.md). The SKILL.md baseline applies; this file covers only the deltas for `sales-social`.
4
4
 
5
-
6
5
  Storyboard: `social_platform` (category `sales_social`, track `audiences`).
7
6
 
8
7
  **`sales-social` is additive, not a replacement.** The storyboard's own metadata declares `interaction_model: media_buy_seller` with `capabilities: [sells_media, accepts_briefs, supports_non_guaranteed]` and lists Snap, Meta, TikTok, and Pinterest as example agents — all of which have product catalogs (ad formats, placements, audience offerings as products) AND accept media buys (campaigns with flights, budgets, ad sets). The storyboard only exercises the audience / catalog / native-creative / events / financials leg because the baseline buyer-flow is covered by `sales-non-guaranteed` (or `sales-guaranteed`). Claim BOTH specialisms and implement the full surface.
@@ -27,4 +26,3 @@ Storyboard: `social_platform` (category `sales_social`, track `audiences`).
27
26
  **Handler grouping in `createAdcpServer`:** `sync_audiences`, `sync_catalogs`, and `log_event` live under `eventTracking`, NOT `mediaBuy`. `get_account_financials` and `sync_accounts` live under `accounts`. Baseline `get_products`/`create_media_buy`/etc. stay under `mediaBuy`.
28
27
 
29
28
  **Don't** rip out `get_products` or `create_media_buy` when adding `sales-social` — you need them. The failure mode from doing so: buyers who discover your agent via `get_adcp_capabilities` expecting a media-buy seller hit immediate compliance failures when every baseline storyboard fails with "tool not registered," and your entire `sales-non-guaranteed` bundle regresses to 0/N passing.
30
-
@@ -2,7 +2,6 @@
2
2
 
3
3
  Companion to [`../SKILL.md`](../SKILL.md). The SKILL.md baseline applies; this file covers only the deltas for `signed-requests`.
4
4
 
5
-
6
5
  Storyboard: `signed_requests`. Transport-layer security specialism — certifies that your agent correctly verifies incoming RFC 9421 HTTP Signatures on mutating AdCP operations.
7
6
 
8
7
  **If you run this behind OAuth or combine it with idempotency,** also read [§ Composing OAuth, signing, and idempotency](#composing-oauth-signing-and-idempotency) for middleware mount order, 401 disambiguation (Bearer vs Signature challenge), and how the verified signing `keyid` threads into the idempotency principal.
@@ -86,4 +85,3 @@ npx @adcp/sdk@latest storyboard run http://localhost:3001/mcp signed_requests --
86
85
  ```
87
86
 
88
87
  Every negative vector must return the exact `expected_outcome.error_code` in `WWW-Authenticate: Signature error="<code>"`. A non-claiming agent is not graded against this specialism.
89
-
@@ -25,7 +25,7 @@ A sponsored intelligence (SI) agent serves conversational sponsored content with
25
25
 
26
26
  | Specialism | Status | Delta |
27
27
  | ------------ | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
28
- | _(none yet)_ | — | SI has no specialisms in AdCP 3.0 — pass the `sponsored-intelligence` protocol baseline. Specialism storyboards for conversational-ad-specific patterns are pending future AdCP releases. |
28
+ | _(none yet)_ | — | SI has no specialisms in AdCP 3.0 — pass the `sponsored_intelligence` *protocol* baseline (declared via `supported_protocols: ['sponsored_intelligence']`). Specialism storyboards for conversational-ad-specific patterns are pending future AdCP releases. |
29
29
 
30
30
  ## Before Writing Code
31
31
 
@@ -51,7 +51,7 @@ How should the agent respond during a session?
51
51
  >
52
52
  > **Cross-cutting pitfalls matrix runs keep catching:**
53
53
  >
54
- > - **Declare `capabilities: { specialisms: ['sponsored-intelligence'] }` on `createAdcpServer`.** Value is `string[]` of enum ids (not `[{id, version}]`). Agents that don't declare their specialism fail the grader with "No applicable tracks found" even if every tool workstracks are gated on the specialism claim.
54
+ > - **Do NOT declare a `sponsored-intelligence` specialism.** SI is a *protocol* in AdCP 3.0 — declared via `supported_protocols: ['sponsored_intelligence']` on the `get_adcp_capabilities` response. There is no SI specialism in the `AdCPSpecialism` enum yet, so adopters wire SI through the v5 handler-bag path (`createAdcpServer` from `@adcp/sdk/server/legacy/v5`). The v6 `DecisioningPlatform` interface does not yet expose a `sponsoredIntelligence` field. (Tracking: SI specialism + auto-hydration of `req.session` is planned for a later v6.x adopters today persist sessions explicitly via `ctx.store`.)
55
55
 
56
56
  **`get_adcp_capabilities`** — register first, empty `{}` schema
57
57
 
@@ -113,7 +113,7 @@ taskToolResponse({
113
113
 
114
114
  ### Context and Ext Passthrough
115
115
 
116
- `createAdcpServer` auto-echoes the request's `context` into every response — **do not set `context` yourself** on responses for tools whose request-side `context` is the protocol echo object (`core/context.json`).
116
+ The framework auto-echoes the request's `context` into every response — **do not set `context` yourself** on responses for tools whose request-side `context` is the protocol echo object (`core/context.json`).
117
117
 
118
118
  **SI override.** `si_get_offering` and `si_initiate_session` override `context` on the request as a domain-specific **string** (natural-language intent hint, per spec: _'mens size 14 near Cincinnati'_). The response schema still keeps `context` as the protocol echo object. The framework detects this mismatch and skips the auto-echo for non-object values — your response simply won't carry a `context` field unless you populate it. If you want correlation tracking for SI responses, construct the context object in your handler (e.g., from a buyer-supplied `ext.correlation_id` or your own generator) and return it on the response.
119
119
 
@@ -121,16 +121,16 @@ taskToolResponse({
121
121
 
122
122
  ## SDK Quick Reference
123
123
 
124
- | SDK piece | Usage |
125
- | --------------------------------------------------- | -------------------------------------------------------------------------- |
126
- | `createAdcpServer({ name, sponsoredIntelligence })` | Create server with domain-grouped handlers and auto-generated capabilities |
127
- | `serve(() => createAdcpServer(...))` | Start HTTP server on `:3001/mcp` |
128
- | `ctx.store` | State persistence — `get/put/patch/delete/list` domain objects |
129
- | `adcpError(code, { message })` | Structured error |
124
+ | SDK piece | Usage |
125
+ | -------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
126
+ | `createAdcpServer(config)` *(use this for SI)* | v5 handler-bag entry. The only path that ships SI dispatch (the `sponsoredIntelligence: { getOffering, initiateSession, sendMessage, terminateSession }` sub-bag). Reach via `@adcp/sdk/server/legacy/v5`. v6 `createAdcpServerFromPlatform` does not yet expose an SI specialism — when it does, this skill will document the migration. |
127
+ | `serve(() => createAdcpServer(config))` | Start HTTP server on `:3001/mcp` |
128
+ | `ctx.store` | State persistence — `get/put/patch/delete/list` domain objects. SI sessions live here today (no auto-hydration yet). |
129
+ | `adcpError(code, { message })` | Structured error |
130
130
 
131
131
  Handlers return raw data objects. The framework auto-wraps responses and auto-generates `get_adcp_capabilities` from registered handlers.
132
132
 
133
- Import: `import { createAdcpServer, serve, adcpError } from '@adcp/sdk';`
133
+ Import: `import { createAdcpServer, serve, adcpError } from '@adcp/sdk/server/legacy/v5';`
134
134
 
135
135
  ## Setup
136
136
 
@@ -159,16 +159,21 @@ Minimal `tsconfig.json`:
159
159
 
160
160
  ## Implementation
161
161
 
162
- 1. Single `.ts` file — use `createAdcpServer` with the `sponsoredIntelligence` domain group
162
+ 1. Single `.ts` file — wire `createAdcpServer` from `@adcp/sdk/server/legacy/v5` with a `sponsoredIntelligence` handler bag
163
163
  2. Do not register `get_adcp_capabilities` — the framework generates it from registered handlers
164
164
  3. Return raw data objects from handlers — the framework wraps responses automatically
165
- 4. Use `ctx.store` to persist active sessions — track state: active → terminated
166
- 5. Handlers receive `(params, ctx)` — `ctx.store` for state, `ctx.account` for resolved account
165
+ 4. Use `ctx.store` to persist active sessions — track state: active → terminated. **Sessions are NOT auto-hydrated yet** (planned for v6.x). Read `req.session_id` and look the session up in `ctx.store` on every `si_send_message`.
166
+ 5. Handlers receive `(params, ctx)` — `ctx.store` for state, `ctx.account` (when `resolveAccount` is wired) for resolved account
167
167
 
168
168
  ```typescript
169
169
  import { randomUUID } from 'node:crypto';
170
- import { createAdcpServer, serve, adcpError } from '@adcp/sdk';
171
- import { createIdempotencyStore, memoryBackend } from '@adcp/sdk/server';
170
+ import {
171
+ createAdcpServer,
172
+ serve,
173
+ adcpError,
174
+ createIdempotencyStore,
175
+ memoryBackend,
176
+ } from '@adcp/sdk/server/legacy/v5';
172
177
 
173
178
  const idempotency = createIdempotencyStore({
174
179
  backend: memoryBackend(),
@@ -180,21 +185,22 @@ serve(() =>
180
185
  name: 'SI Agent',
181
186
  version: '1.0.0',
182
187
  idempotency,
183
- // Principal scope for idempotency. MUST never return undefined. A
184
- // constant is fine for a demo; for multi-tenant production, type the
185
- // account via `createAdcpServer<MyAccount>({...})` and use
186
- // `(ctx) => ctx.account?.id`. The framework additionally auto-scopes
187
- // `si_send_message` by `session_id`, so the same key under two
188
- // sessions doesn't cross-replay.
188
+ // Principal scope for idempotency. MUST never return undefined. The
189
+ // framework additionally auto-scopes `si_send_message` by `session_id`,
190
+ // so the same key under two sessions doesn't cross-replay.
189
191
  resolveSessionKey: () => 'default-principal',
190
-
192
+ capabilities: {
193
+ // SI is a *protocol*, not a specialism. Declare it here; the framework
194
+ // adds it to `get_adcp_capabilities.supported_protocols`.
195
+ supported_protocols: ['sponsored_intelligence'],
196
+ },
191
197
  sponsoredIntelligence: {
192
- getOffering: async (params, ctx) => ({
198
+ getOffering: async (req, ctx) => ({
193
199
  available: true,
194
200
  offering_token: `tok_${randomUUID()}`,
195
201
  ttl_seconds: 300,
196
202
  }),
197
- initiateSession: async (params, ctx) => {
203
+ initiateSession: async (req, ctx) => {
198
204
  // session_id MUST be high-entropy (≥122 bits) per spec — it's the
199
205
  // scope key for conversational isolation. Never use Date.now() or
200
206
  // predictable counters; a guessable session_id lets one buyer
@@ -206,14 +212,17 @@ serve(() =>
206
212
  session_status: 'active',
207
213
  };
208
214
  },
209
- sendMessage: async (params, ctx) => {
210
- const session = await ctx.store.get('session', params.session_id);
215
+ sendMessage: async (req, ctx) => {
216
+ // No auto-hydration of sessions yet — read explicitly. (v6.x will
217
+ // attach `req.session` for free; until then this lookup is your
218
+ // session-loss guard.)
219
+ const session = await ctx.store.get('session', req.session_id);
211
220
  // Return the error — the framework echoes returned adcpError
212
221
  // responses verbatim. Thrown errors are caught and converted to
213
222
  // SERVICE_UNAVAILABLE, which hides your custom code from the buyer.
214
223
  if (!session) return adcpError('RESOURCE_NOT_FOUND', { message: 'Session not found' });
215
224
  return {
216
- session_id: params.session_id,
225
+ session_id: req.session_id,
217
226
  session_status: 'active' as const,
218
227
  response: {
219
228
  content: 'Sponsored content response',
@@ -221,10 +230,10 @@ serve(() =>
221
230
  },
222
231
  };
223
232
  },
224
- terminateSession: async (params, ctx) => {
225
- await ctx.store.delete('session', params.session_id);
233
+ terminateSession: async (req, ctx) => {
234
+ await ctx.store.delete('session', req.session_id);
226
235
  return {
227
- session_id: params.session_id,
236
+ session_id: req.session_id,
228
237
  terminated: true,
229
238
  };
230
239
  },
@@ -254,8 +263,7 @@ Idempotency is wired in the example above. What the framework handles for you:
254
263
  **An AdCP agent that accepts unauthenticated requests is non-compliant** (see `security_baseline` in the universal storyboard bundle). Ask the operator: "API key, OAuth, or both?" — then wire one of these into `serve()`.
255
264
 
256
265
  ```typescript
257
- import { serve } from '@adcp/sdk';
258
- import { verifyApiKey, verifyBearer, anyOf } from '@adcp/sdk/server';
266
+ import { serve, verifyApiKey, verifyBearer, anyOf } from '@adcp/sdk/server/legacy/v5';
259
267
 
260
268
  // API key — simplest, good for B2B integrations
261
269
  serve(createAgent, {
@@ -32,7 +32,7 @@ A signals agent serves audience segments to buyers for campaign targeting. Two t
32
32
 
33
33
  Full treatment lives in `skills/build-seller-agent/SKILL.md` §Protocol-Wide Requirements and §Composing. Minimum viable pointers for a signals agent:
34
34
 
35
- - **`idempotency_key`** on every mutating request (`activate_signal`, and any future mutating signals tools). Wire `createIdempotencyStore` into `createAdcpServer({ idempotency })`.
35
+ - **`idempotency_key`** on every mutating request (`activate_signal`, and any future mutating signals tools). Pass `createIdempotencyStore` to `createAdcpServerFromPlatform(platform, { idempotency })`.
36
36
  - **Authentication** via `serve({ authenticate })` with `verifyApiKey`/`verifyBearer` from `@adcp/sdk/server`. Unauthenticated agents fail the universal `security_baseline` storyboard.
37
37
  - **Signature-header transparency**: accept requests with `Signature-Input`/`Signature` headers even if you don't claim `signed-requests`.
38
38
 
@@ -77,9 +77,9 @@ If implementing `activate_signal`:
77
77
  >
78
78
  > **Cross-cutting pitfalls matrix runs keep catching:**
79
79
  >
80
- > - **Declare `capabilities: { specialisms: ['signal-marketplace'] }` (or `'signal-owned'`) on `createAdcpServer`.** Value is `string[]` of enum ids (not `[{id, version}]`). Agents that don't declare their specialism fail the grader with "No applicable tracks found" even if every tool works — tracks are gated on the specialism claim.
80
+ > - **Declare `capabilities.specialisms: ['signal-marketplace'] as const` (or `'signal-owned'`) on the `DecisioningPlatform` you pass to `createAdcpServerFromPlatform`.** Value is `string[]` of enum ids (not `[{id, version}]`). Agents that don't declare their specialism fail the grader with "No applicable tracks found" even if every tool works — tracks are gated on the specialism claim.
81
81
 
82
- **`get_adcp_capabilities`** — auto-generated by `createAdcpServer` from registered handlers. Do not register manually.
82
+ **`get_adcp_capabilities`** — auto-generated by `createAdcpServerFromPlatform` from your typed `DecisioningPlatform`. Do not register manually.
83
83
 
84
84
  **`get_signals`** — handled by `signals.getSignals`
85
85
 
@@ -158,7 +158,7 @@ activateSignalResponse({
158
158
 
159
159
  ### Context and Ext Passthrough
160
160
 
161
- `createAdcpServer` auto-echoes the request's `context` into every response — **do not set `context` yourself in your handler return values.** The framework injects it post-handler only when the field isn't already present.
161
+ The framework auto-echoes the request's `context` into every response — **do not set `context` yourself in your handler return values.** It's injected post-handler only when the field isn't already present.
162
162
 
163
163
  **Crucial:** `context` is schema-typed as an object. If your handler hand-sets a string or narrative description, validation fails with `/context: must be object` and the framework does not overwrite. Leave the field out entirely; the framework handles it.
164
164
 
@@ -168,19 +168,20 @@ Some schemas also define an `ext` field for vendor-namespaced extensions. If you
168
168
 
169
169
  | SDK piece | Usage |
170
170
  | ----------------------------------------------------- | ------------------------------------------------------------------------------ |
171
- | `createAdcpServer(config)` | Create server with domain-grouped handlers and auto-capabilities |
172
- | `serve(() => createAdcpServer(config))` | Start HTTP server on `:3001/mcp` |
171
+ | `createAdcpServerFromPlatform(platform, opts)` | Create server from a typed `DecisioningPlatform` — compile-time specialism enforcement, auto-capabilities |
172
+ | `createAdcpServer(config)` *(legacy)* | v5 handler-bag entry. Mid-migration / escape-hatch only; reach via `@adcp/sdk/server/legacy/v5` |
173
+ | `serve(() => createAdcpServerFromPlatform(platform, opts))` | Start HTTP server on `:3001/mcp` |
173
174
  | `signals: { getSignals, activateSignal }` | Domain group — register handlers by name |
174
175
  | `ctx.store.put(collection, id, data)` | Persist state (activations, segment cache) across requests |
175
176
  | `ctx.store.get(collection, id)` | Retrieve persisted state |
176
177
  | `getSignalsResponse(data)` | Auto-applied response builder (don't call manually) |
177
178
  | `activateSignalResponse(data)` | Auto-applied response builder (don't call manually) |
178
179
  | `adcpError(code, { message })` | Structured error (`SIGNAL_NOT_FOUND`, `INVALID_DESTINATION`) |
179
- | `createIdempotencyStore({ backend, ttlSeconds })` | Required on every mutating tool — pass via `createAdcpServer({ idempotency })` |
180
- | `memoryBackend()` / `pgBackend(pool)` | Idempotency backends (from `@adcp/sdk/server`) |
180
+ | `createIdempotencyStore({ backend, ttlSeconds })` | Required on every mutating tool — pass via `createAdcpServerFromPlatform(platform, { idempotency })` |
181
+ | `memoryBackend()` / `pgBackend(pool)` | Idempotency backends (from `@adcp/sdk/server`) |
181
182
  | `type Signal = GetSignalsResponse['signals'][number]` | Type for a single signal object |
182
183
 
183
- Import: `import { createAdcpServer, serve, adcpError } from '@adcp/sdk';`
184
+ Import: `import { createAdcpServerFromPlatform, serve, adcpError } from '@adcp/sdk/server';`
184
185
  Server-only: `import { createIdempotencyStore, memoryBackend } from '@adcp/sdk/server';`
185
186
  Types: `import type { GetSignalsResponse } from '@adcp/sdk';`
186
187
 
@@ -212,20 +213,41 @@ Minimal `tsconfig.json`:
212
213
  ## Implementation
213
214
 
214
215
  1. Single `.ts` file — all tools in one file
215
- 2. Use `createAdcpServer` with a `signals` domain group — `get_adcp_capabilities` is auto-generated
216
+ 2. Use `createAdcpServerFromPlatform` with `signals: SignalsPlatform` on a typed `DecisioningPlatform` class — `get_adcp_capabilities` is auto-generated
216
217
  3. Handlers return raw data objects — response builders (`getSignalsResponse`, `activateSignalResponse`) are auto-applied
217
218
  4. Use `ctx.store` for persisting signal activations across requests (InMemoryStateStore by default)
218
219
  5. Set `sandbox: true` for mock/demo data
219
220
  6. Context passthrough is handled by the framework — no need to manually echo `args.context`
220
221
 
221
222
  ```typescript
222
- import { createAdcpServer, serve, adcpError } from '@adcp/sdk';
223
- import { createIdempotencyStore, memoryBackend } from '@adcp/sdk/server';
224
-
225
- const signals = [
226
- /* your signal objects */
223
+ import {
224
+ createAdcpServerFromPlatform,
225
+ serve,
226
+ AdcpError,
227
+ createIdempotencyStore,
228
+ memoryBackend,
229
+ type DecisioningPlatform,
230
+ type SignalsPlatform,
231
+ type AccountStore,
232
+ } from '@adcp/sdk/server';
233
+ import type { GetSignalsResponse } from '@adcp/sdk';
234
+
235
+ // Type the catalog explicitly. Each entry MUST include `signal_agent_segment_id`
236
+ // — it's the key buyers pass to `activate_signal` and the field the framework
237
+ // uses to auto-store the signal for hydration on the activate call. If you
238
+ // omit it, `tsc` flags every entry; the response validator rejects the
239
+ // `get_signals` reply at runtime in dev/test (strict mode default).
240
+ type Signal = GetSignalsResponse['signals'][number];
241
+ const signals: Signal[] = [
242
+ /* your signal objects — `signal_agent_segment_id` is required on each */
227
243
  ];
228
244
 
245
+ // Publisher-internal storage for activations. Persist to your real DB in
246
+ // production; this Map is for the worked example. Note: a module-level Map
247
+ // is fine for single-tenant agents but leaks across tenants in a
248
+ // multi-tenant deployment — partition by `account.id` if you front many.
249
+ const activations = new Map<string, { destinations: unknown[]; activated_at: string }>();
250
+
229
251
  // Idempotency — required for v3 compliance. `activate_signal` is mutating;
230
252
  // `get_signals` is read-only and exempt from key validation.
231
253
  const idempotency = createIdempotencyStore({
@@ -233,86 +255,110 @@ const idempotency = createIdempotencyStore({
233
255
  ttlSeconds: 86400, // 24 hours (spec bounds: 1h–7d)
234
256
  });
235
257
 
236
- serve(() =>
237
- createAdcpServer({
238
- name: 'My Signals Agent',
239
- version: '1.0.0',
240
- idempotency,
241
-
242
- // Principal scoping for idempotency. MUST never return undefined — or
243
- // every mutating request rejects as SERVICE_UNAVAILABLE. A constant
244
- // works for a demo; for multi-tenant use ctx.account.
245
- resolveSessionKey: () => 'default-principal',
258
+ class MySignals implements DecisioningPlatform {
259
+ capabilities = {
260
+ specialisms: ['signal-marketplace'] as const,
261
+ config: {},
262
+ };
263
+
264
+ // Single-tenant agent: AccountStore.resolve returns the same synthetic
265
+ // account every request. `upsert` and `list` are optional — omit them on
266
+ // stateless platforms (the framework returns `UNSUPPORTED_FEATURE` to
267
+ // buyers calling `sync_accounts` / `list_accounts`).
268
+ accounts: AccountStore = {
269
+ resolve: async () => ({
270
+ id: 'sg_acc_1',
271
+ operator: 'me',
272
+ ctx_metadata: {},
273
+ }),
274
+ };
275
+
276
+ signals: SignalsPlatform = {
277
+ getSignals: async params => {
278
+ let results = signals;
279
+ if (params.signal_spec) {
280
+ const query = params.signal_spec.toLowerCase();
281
+ results = results.filter(
282
+ s => s.name.toLowerCase().includes(query) || s.description.toLowerCase().includes(query)
283
+ );
284
+ }
285
+ if (params.signal_ids) {
286
+ results = results.filter(s => params.signal_ids!.some(id => id.id === s.signal_id.id));
287
+ }
288
+ return { signals: results, sandbox: true };
289
+ },
246
290
 
247
- signals: {
248
- getSignals: async (params, ctx) => {
249
- let results = signals;
250
- if (params.signal_spec) {
251
- const query = params.signal_spec.toLowerCase();
252
- results = results.filter(
253
- s => s.name.toLowerCase().includes(query) || s.description.toLowerCase().includes(query)
254
- );
255
- }
256
- if (params.signal_ids) {
257
- results = results.filter(s => params.signal_ids!.some(id => id.id === s.signal_id.id));
258
- }
259
- return { signals: results, sandbox: true };
260
- },
261
-
262
- activateSignal: async (params, ctx) => {
263
- const signal = signals.find(s => s.signal_agent_segment_id === params.signal_agent_segment_id);
264
- // Return the error — the framework echoes returned adcpError
265
- // responses verbatim. Thrown errors are caught and converted to
266
- // SERVICE_UNAVAILABLE, which hides your custom code from the buyer.
267
- if (!signal)
268
- return adcpError('SIGNAL_NOT_FOUND', { message: `Unknown segment: ${params.signal_agent_segment_id}` });
269
-
270
- // Persist activation in state store
271
- await ctx.store.put('activations', params.signal_agent_segment_id, {
272
- signal_agent_segment_id: params.signal_agent_segment_id,
273
- destinations: params.destinations,
274
- activated_at: new Date().toISOString(),
291
+ activateSignal: async params => {
292
+ const signal = signals.find(s => s.signal_agent_segment_id === params.signal_agent_segment_id);
293
+ // Throw `AdcpError` for buyer-fixable rejection. The framework
294
+ // catches the throw, projects to the spec's error envelope, and
295
+ // returns it to the buyer. Returning `adcpError(...)` from the
296
+ // success arm doesn't typecheck — `activateSignal` is declared
297
+ // `Promise<ActivateSignalSuccess>`, error is the throw path.
298
+ if (!signal) {
299
+ throw new AdcpError('SIGNAL_NOT_FOUND', {
300
+ recovery: 'correctable',
301
+ message: `Unknown segment: ${params.signal_agent_segment_id}`,
275
302
  });
303
+ }
276
304
 
277
- // Platform (DSP) activation is ASYNC per spec — return `is_live: false`
278
- // with `estimated_activation_duration_minutes`. The buyer polls
279
- // (a subsequent `activate_signal` with the same destinations, or a
280
- // provider-specific status tool) until `is_live: true`.
281
- //
282
- // Agent (sales-agent) activation is SYNC — return `is_live: true` with
283
- // `activation_key.type: 'key_value'` and a `deployed_at` timestamp.
284
- //
285
- // Both shapes include `activation_key` so the buyer knows how to
286
- // reference the segment when building media buys through the DSP or SA.
287
- const deployments = params.destinations.map(dest => {
288
- if (dest.type === 'platform') {
289
- return {
290
- type: 'platform' as const,
291
- platform: dest.platform,
292
- is_live: false,
293
- estimated_activation_duration_minutes: 30,
294
- // Return activation_key even while is_live is false — the
295
- // buyer needs to know the planned segment_id now so it can
296
- // reference it in downstream media buys. `is_live` just
297
- // flags whether the DSP has confirmed provisioning;
298
- // `activation_key` is the agent's commitment.
299
- activation_key: {
300
- type: 'segment_id' as const,
301
- segment_id: `${dest.platform}_${signal.signal_id.id}`,
302
- },
303
- };
304
- }
305
+ // Persist activation. Single-tenant: module-level Map is fine.
306
+ // Multi-tenant: partition by ctx.account.id (passed as 2nd arg).
307
+ activations.set(params.signal_agent_segment_id, {
308
+ destinations: params.destinations,
309
+ activated_at: new Date().toISOString(),
310
+ });
311
+
312
+ // Platform (DSP) activation is ASYNC per spec — return `is_live: false`
313
+ // with `estimated_activation_duration_minutes`. The buyer polls
314
+ // (a subsequent `activate_signal` with the same destinations, or a
315
+ // provider-specific status tool) until `is_live: true`.
316
+ //
317
+ // Agent (sales-agent) activation is SYNC — return `is_live: true` with
318
+ // `activation_key.type: 'key_value'` and a `deployed_at` timestamp.
319
+ //
320
+ // Both shapes include `activation_key` so the buyer knows how to
321
+ // reference the segment when building media buys through the DSP or SA.
322
+ const deployments = params.destinations.map(dest => {
323
+ if (dest.type === 'platform') {
305
324
  return {
306
- type: 'agent' as const,
307
- agent_url: dest.agent_url,
308
- is_live: true,
309
- activation_key: { type: 'key_value' as const, key: 'audience', value: signal.signal_id.id },
310
- deployed_at: new Date().toISOString(),
325
+ type: 'platform' as const,
326
+ platform: dest.platform,
327
+ is_live: false,
328
+ estimated_activation_duration_minutes: 30,
329
+ // Return activation_key even while is_live is false — the
330
+ // buyer needs to know the planned segment_id now so it can
331
+ // reference it in downstream media buys. `is_live` just
332
+ // flags whether the DSP has confirmed provisioning;
333
+ // `activation_key` is the agent's commitment.
334
+ activation_key: {
335
+ type: 'segment_id' as const,
336
+ segment_id: `${dest.platform}_${signal.signal_id.id}`,
337
+ },
311
338
  };
312
- });
313
- return { deployments, sandbox: true };
314
- },
339
+ }
340
+ return {
341
+ type: 'agent' as const,
342
+ agent_url: dest.agent_url,
343
+ is_live: true,
344
+ activation_key: { type: 'key_value' as const, key: 'audience', value: signal.signal_id.id },
345
+ deployed_at: new Date().toISOString(),
346
+ };
347
+ });
348
+ return { deployments, sandbox: true };
315
349
  },
350
+ };
351
+ }
352
+
353
+ const platform = new MySignals();
354
+
355
+ serve(() =>
356
+ createAdcpServerFromPlatform(platform, {
357
+ name: 'My Signals Agent',
358
+ version: '1.0.0',
359
+ idempotency,
360
+ // Principal scoping for idempotency. MUST never return undefined.
361
+ resolveSessionKey: () => 'default-principal',
316
362
  })
317
363
  );
318
364
  ```
@@ -335,7 +381,7 @@ Scoping is per-principal via `resolveSessionKey` (override with `resolveIdempote
335
381
 
336
382
  ```ts
337
383
  const store = createIdempotencyStore({ backend: pgBackend(pool), ttlSeconds: 86400 });
338
- pool.on('error', (err) => console.error('pg pool error', err)); // prevent crash on idle-client errors
384
+ pool.on('error', err => console.error('pg pool error', err)); // prevent crash on idle-client errors
339
385
  serve(createAgent, {
340
386
  readinessCheck: () => store.probe(), // throws with a descriptive error if pool/table is broken
341
387
  });
@@ -417,9 +463,10 @@ Common failure decoder:
417
463
 
418
464
  | Mistake | Fix |
419
465
  | ------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
420
- | Using `createTaskCapableServer` + `server.tool()` | Use `createAdcpServer` with `signals` domain group |
466
+ | Using `createTaskCapableServer` + `server.tool()` | Use `createAdcpServerFromPlatform` with `signals: SignalsPlatform` on a typed `DecisioningPlatform` class |
467
+ | Calling `createAdcpServer` directly in new code | Reach for `createAdcpServerFromPlatform`; `createAdcpServer` lives at `@adcp/sdk/server/legacy/v5` for mid-migration / escape-hatch only |
421
468
  | Using module-level Maps for state | Use `ctx.store.put/get` — framework provides `InMemoryStateStore` by default |
422
- | Manually registering `get_adcp_capabilities` | Auto-generated by `createAdcpServer` from registered handlers |
469
+ | Manually registering `get_adcp_capabilities` | Auto-generated by `createAdcpServerFromPlatform` from your typed `DecisioningPlatform` |
423
470
  | Calling response builders manually | Handlers return raw data — `getSignalsResponse`/`activateSignalResponse` are auto-applied |
424
471
  | Missing `signal_agent_segment_id` on signals | Buyers can't activate without it |
425
472
  | Wrong `signal_id` shape | Marketplace: `{ source: "catalog", data_provider_domain, id }`. Owned: `{ source: "agent", agent_url, id }` |
@@ -205,6 +205,7 @@ Returns `{ signals: [{ signal_agent_segment_id, match_rate, pricing, ... }] }`.
205
205
  ## Transport notes
206
206
 
207
207
  - **MCP**: `tools/call` with `{ name: 'tool_name', arguments: {...} }`. Returns `{ content, structuredContent, isError? }`. Read `structuredContent` for the typed response.
208
+ - **Use the official `@modelcontextprotocol/sdk` client.** The Streamable HTTP transport requires `Accept: application/json, text/event-stream` on every request — a raw `fetch()` with only `Accept: application/json` gets an unhelpful `406 Not Acceptable` from the server before any AdCP framing runs. The official client sets the header correctly; reach for it instead of rolling your own HTTP plumbing.
208
209
  - **A2A**: `message/send` with a `DataPart` of shape `{ skill: 'tool_name', input: {...} }` (the legacy key `parameters` is also accepted). Returns an A2A `Task`; the typed response is at `task.artifacts[0].parts[0].data`.
209
210
 
210
211
  Both transports share: idempotency, error shape, schema enforcement, and handler semantics. If a call works on one, the equivalent call works on the other.
@@ -232,6 +233,10 @@ Quick lookup before reading the full envelope. Match what you see in `adcp_error
232
233
  | `keyword: 'enum'` at `/destinations/*/type` | Made-up destination type | Use `'platform'` (with `platform`) or `'agent'` (with `agent_url`). |
233
234
  | Response carries `status: 'submitted'` and `task_id` | Async — work is queued, NOT done | Poll via `tasks/get` (A2A) or the MCP async task extension using `task_id`. |
234
235
  | `recovery: 'transient'` (rate limit, 5xx, timeout) | Server-side, retry-safe | Retry with the **same** `idempotency_key`. |
236
+ <<<<<<< Updated upstream
237
+ | `406 Not Acceptable` before any AdCP framing | Hand-rolled HTTP without `Accept: text/event-stream` (MCP transport) | Use `@modelcontextprotocol/sdk` client; it sets the right Accept header. |
238
+ =======
239
+ >>>>>>> Stashed changes
235
240
  | `recovery: 'correctable'` | Buyer-side fix | Read `issues[]`, patch the pointers, resend. Most cases close in one attempt. |
236
241
  | `recovery: 'terminal'` (account suspended, payment required, …) | Requires human action | Don't retry. Surface to the user. |
237
242
  | HTTP 401 with `WWW-Authenticate` header | Missing or expired credential | Add `Authorization` per the agent's auth spec; re-auth if applicable. |