StaticfromCreate an AgentClient backed by a pre-connected MCP Client instead of
an HTTP endpoint. Useful for in-process compliance testing without spinning
up a loopback HTTP server.
MCP only. This factory wraps an MCP Client from
@modelcontextprotocol/sdk. There is no equivalent in-process bridge for
A2A today — for A2A agents, run them on a loopback HTTP server and use the
standard AgentClient constructor with the agent's agent_uri.
What this gives you over dispatchTestRequest:
All client-side pipeline stages still apply — idempotency key auto-injection,
request/response schema validation hooks, governance middleware, and the typed
TaskResult<T> discriminated-union response shape. None of these apply when
calling dispatchTestRequest() directly.
Usage:
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { InMemoryTransport } from '@modelcontextprotocol/sdk/inMemory.js';
import { AgentClient } from '@adcp/sdk';
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
const mcpClient = new Client({ name: 'test', version: '1.0.0' });
await Promise.all([
mcpClient.connect(clientTransport),
adcpServer.connect(serverTransport),
]);
const agent = AgentClient.fromMCPClient(mcpClient, {
validation: { requests: 'strict' },
});
const result = await agent.createMediaBuy({ ... });
Unsupported methods on in-process instances: resolveCanonicalUrl,
getWebhookUrl, registerWebhook, unregisterWebhook — these require HTTP
and will throw Error with a descriptive message. Use getAgentId() /
getAgentName() for identification instead.
An already-connected MCP Client (see example above).
Optional narrowed config. HTTP-only fields are excluded.
Handle webhook from agent (async task completion or notifications)
Webhook payload from agent
Task type (e.g create_media_buy) from url param or url part of the webhook delivery
Operation id (e.g used for client app to track the operation) from the param or url part of the webhook delivery
Optionalsignature: WebhookHeaderValueOptional signature for verification (X-ADCP-Signature)
Optionaltimestamp: WebhookHeaderValueOptional timestamp for verification (X-ADCP-Timestamp)
OptionalrawBody: string | Uint8Array<ArrayBufferLike> | Buffer<ArrayBufferLike>Whether webhook was handled successfully
Verify and normalize an inbound webhook without dispatching handlers.
Verify webhook signature using HMAC-SHA256 per AdCP spec.
Prefer passing the raw HTTP body string for correct cross-language interop. Passing a parsed object still works but re-serializes with JSON.stringify, which may not match the sender's byte representation.
Raw HTTP body string (preferred) or parsed payload object (deprecated)
X-ADCP-Signature header value (format: "sha256=...")
X-ADCP-Timestamp header value (Unix timestamp)
true if signature is valid
Discover available advertising products.
By default, response products are augmented with the AdCP 3.1
format_options[] declaration (the V2 mental model). When the
seller emitted v1 format_ids[], the SDK projects them via the
AAO canonical-formats catalog so buyers always read the same
V2 shape regardless of wire version. The original format_ids[]
is preserved alongside format_options[] (additive — 7.x
callers reading format_ids keep working).
Projection diagnostics surface on
result.data.projection.diagnostics (structured
source: 'sdk' markers; codes mirror the spec's error-code
vocabulary plus three SDK-local codes — see the projection
module's ProjectionDiagnostic type for the full set).
Pass { project: false } to opt out and receive the raw wire
response unmodified — useful for storyboard / compliance
harnesses asserting exact seller emission. The opt-out narrows
the return type back to GetProductsResponse (no projection
envelope, no guaranteed format_options[]).
The 8.0 release narrows further by removing format_ids[] from
the public Product type entirely.
OptionalinputHandler: InputHandlerOptionaloptions: TaskOptions & { project?: true }Discover available advertising products.
By default, response products are augmented with the AdCP 3.1
format_options[] declaration (the V2 mental model). When the
seller emitted v1 format_ids[], the SDK projects them via the
AAO canonical-formats catalog so buyers always read the same
V2 shape regardless of wire version. The original format_ids[]
is preserved alongside format_options[] (additive — 7.x
callers reading format_ids keep working).
Projection diagnostics surface on
result.data.projection.diagnostics (structured
source: 'sdk' markers; codes mirror the spec's error-code
vocabulary plus three SDK-local codes — see the projection
module's ProjectionDiagnostic type for the full set).
Pass { project: false } to opt out and receive the raw wire
response unmodified — useful for storyboard / compliance
harnesses asserting exact seller emission. The opt-out narrows
the return type back to GetProductsResponse (no projection
envelope, no guaranteed format_options[]).
The 8.0 release narrows further by removing format_ids[] from
the public Product type entirely.
OptionalinputHandler: InputHandlerOptionaloptions: TaskOptions & { project: false }List available creative formats
OptionalinputHandler: InputHandlerOptionaloptions: TaskOptionsCreate a new media buy.
3.1+ format-option write flow (preferred at 3.1.0-beta.5+). After
getProducts() returns the V2-augmented response (format_options[]
auto-populated), pick declarations by format_option_id and use
packageRefsForFormatOptions to author the package. The helper emits
BOTH format_option_refs[] (the 3.1+ path) AND format_ids[]
(legacy named-format dual emission) so a single request works against
both format-option-aware and legacy sellers.
import { packageRefsForFormatOptions } from '@adcp/sdk/v2/projection';
const { data: { products } } = await agent.getProducts({ brief: '...' });
const product = products[0];
await agent.createMediaBuy({
packages: [{
package_id: 'pkg-1',
product_id: product.product_id,
pricing_option_id: product.pricing_options[0].pricing_option_id,
...packageRefsForFormatOptions(product, ['nytimes_mrec', 'nytimes_video_30s']),
// ↑ spreads `{ format_option_refs, format_ids? }`
budget: { currency: 'USD', total: 5000 },
}],
// ...
});
The resulting wire payload for the package looks like:
{
"package_id": "pkg-1",
"product_id": "...",
"pricing_option_id": "...",
"format_option_refs": [
{"scope": "product", "format_option_id": "nytimes_mrec"},
{"scope": "product", "format_option_id": "nytimes_video_30s"}
],
"format_ids": [
{"agent_url": "https://creative.adcontextprotocol.org/", "id": "display_300x250_image"},
{"agent_url": "https://creative.adcontextprotocol.org/", "id": "video_standard_30s"}
],
"budget": {"currency": "USD", "total": 5000}
}
format_ids is omitted entirely when every chosen format option is V2-only
(the spec's "neither present" fallback fires for v1 sellers in that case).
Inline creative fallback. Sellers that do not advertise a creative
library (supportsSyncCreatives(await agent.getCapabilities()) === false)
can still accept package-scoped creative uploads when they advertise
caps.features.inlineCreativeManagement. Use
inlineCreativesForPackages(packages, creatives, { assignments }) to
project sync_creatives-style creative assets into create-media-buy
package payloads without rewriting a raw sync_creatives call. If using
assignments for create payloads, give each package a stable key such as
context.buyer_ref, or pass a custom packageId resolver.
For adopters writing strictly to v1 sellers — or for products whose
format_options[] entries don't publish format_option_id — see the
legacyFormatIdsFromOptions / tryLegacyFormatIdsFromOptions /
legacyFormatIdsForFormatOption helpers in @adcp/sdk/v2/projection.
packageRefsForFormatOptions throws FormatOptionRefsLookupError
with a normalized .code in { 'unknown_format_option_id' | 'format_option_refs_not_published' | 'empty_input' | 'invalid_product' }
— branch on .code to fall back to the legacy* helpers when the
product is V1-shape only. See the helper JSDoc for the full
recovery example.
OptionalinputHandler: InputHandlerOptionaloptions: TaskOptionsUpdate an existing media buy.
For sellers without a creative library but with
caps.features.inlineCreativeManagement, post-create creative replacement
can be represented as package-scoped inline packages[].creatives on this
request. Build the package patch with inlineCreativesForPackages() and
preflight it with preflightUpdateMediaBuy(currentBuy, patch) so
available_actions[] allows replace_creative before dispatch.
OptionalinputHandler: InputHandlerOptionaloptions: TaskOptionsSync creative assets into the seller's reusable creative library.
This is library-scoped: assignments can reference packages, but a raw
sync_creatives request does not contain enough media-buy context for the
SDK to safely rewrite it into inline package creatives. When the seller
lacks creative.has_creative_library but does advertise
media_buy.features.inline_creative_management, use
inlineCreativesForPackages() with explicit package/media-buy context and
send a separate create_media_buy or update_media_buy request with its
own idempotency key. If neither capability is advertised, creative upload
is not available through this SDK helper surface.
OptionalinputHandler: InputHandlerOptionaloptions: TaskOptionsList creative assets
OptionalinputHandler: InputHandlerOptionaloptions: TaskOptionsGet media buy status, creative approvals, and optional delivery snapshots
OptionalinputHandler: InputHandlerOptionaloptions: TaskOptionsGet media buy delivery information
OptionalinputHandler: InputHandlerOptionaloptions: TaskOptionsProvide performance feedback
OptionalinputHandler: InputHandlerOptionaloptions: TaskOptionsGet audience signals
OptionalinputHandler: InputHandlerOptionaloptions: TaskOptionsActivate audience signals
OptionalinputHandler: InputHandlerOptionaloptions: TaskOptionsGet AdCP capabilities (v3 tool call)
OptionalinputHandler: InputHandlerOptionaloptions: TaskOptionsGet normalized capabilities with v2/v3 fallback
For v3 servers: calls get_adcp_capabilities tool For v2 servers: builds synthetic capabilities from tool list
Optionaloptions: Pick<TaskOptions, "signal" | "transport">Return the seller's declared adcp.idempotency.replay_ttl_seconds, or
throw when a v3 seller omits the (required) declaration.
Returns undefined for v2 agents — v2 pre-dates the idempotency envelope.
Assert that the seller's capabilities corroborate this client's pinned
AdCP major (per getAdcpVersion()). Throws VersionUnsupportedError
otherwise. Set ADCP_ALLOW_V2=1 to bypass.
Deprecated alias for requireSupportedMajor.
Preview a creative
OptionalinputHandler: InputHandlerOptionaloptions: TaskOptionsBuild a creative from format and brand context
OptionalinputHandler: InputHandlerOptionaloptions: TaskOptionsList accounts
OptionalinputHandler: InputHandlerOptionaloptions: TaskOptionsSync accounts
OptionalinputHandler: InputHandlerOptionaloptions: TaskOptionsSync audiences
OptionalinputHandler: InputHandlerOptionaloptions: TaskOptionsCreate a property list
OptionalinputHandler: InputHandlerOptionaloptions: TaskOptionsGet a property list
OptionalinputHandler: InputHandlerOptionaloptions: TaskOptionsUpdate a property list
OptionalinputHandler: InputHandlerOptionaloptions: TaskOptionsList property lists
OptionalinputHandler: InputHandlerOptionaloptions: TaskOptionsDelete a property list
OptionalinputHandler: InputHandlerOptionaloptions: TaskOptionsList content standards
OptionalinputHandler: InputHandlerOptionaloptions: TaskOptionsGet content standards
OptionalinputHandler: InputHandlerOptionaloptions: TaskOptionsCalibrate content against standards
OptionalinputHandler: InputHandlerOptionaloptions: TaskOptionsValidate content delivery
OptionalinputHandler: InputHandlerOptionaloptions: TaskOptionsGet an SI offering
OptionalinputHandler: InputHandlerOptionaloptions: TaskOptionsInitiate an SI session
OptionalinputHandler: InputHandlerOptionaloptions: TaskOptionsSend a message in an SI session
OptionalinputHandler: InputHandlerOptionaloptions: TaskOptionsTerminate an SI session
OptionalinputHandler: InputHandlerOptionaloptions: TaskOptionsContinue the conversation with a natural language message
Natural language message to send to the agent
OptionalinputHandler: InputHandlerHandler for any clarification requests
Optionaloptions: TaskOptionsGet the full conversation history
Clear the conversation context (start fresh).
Equivalent to resetContext() — clears both the retained contextId
and any pending server-side taskId, and drops cached history.
Reset conversation state. Call with no args to start a fresh conversation; pass a seed to rehydrate a persisted session id (e.g., across a process restart).
Always clears the retained pending-task handle — a persisted contextId
places the next send into the same server-side session, but any old
taskId is stale.
Optionalseed: stringGet the current conversation context ID
Get the pending server-side taskId from the last non-terminal
response, if any. Populated when the server returned
input-required / working / submitted / auth-required;
cleared when the task reaches a terminal state.
Persist this alongside getContextId() if you need to resume a
specific task (not just a conversation) across a process restart.
Set a specific conversation context ID
Get the agent configuration
Get the agent ID
Get the agent name
Get the agent protocol
Get the canonical base URL for this agent
Returns the canonical URL if already resolved, or computes it synchronously. For guaranteed canonical URL (especially for A2A), use resolveCanonicalUrl() first.
Resolve and return the canonical base URL for this agent
For A2A: Fetches the agent card and uses its 'url' field For MCP: Performs endpoint discovery and strips /mcp suffix
Not supported on in-process instances (created via fromMCPClient).
Use getAgentId() / getAgentName() for identification instead.
Check if this agent is the same as another agent by canonical URL
Async version that resolves canonical URLs first for more accurate comparison
Get the fully resolved agent configuration with canonical URL
Get agent information including capabilities
Optionaloptions: Pick<TaskOptions, "signal" | "transport">Check if there's an active conversation
Get active tasks for this agent
Execute any ADCP task by name with full type safety
OptionalinputHandler: InputHandlerOptionaloptions: TaskOptions// ✅ TYPE-SAFE: Automatic response type inference
const result = await agent.executeTask('get_products', params);
// result is TaskResult<GetProductsResponse> - no casting needed!
// ✅ CUSTOM TYPES: For non-standard tasks
const customResult = await agent.executeTask<MyCustomResponse>('custom_task', params);
Execute a task by name with custom response type
OptionalinputHandler: InputHandlerOptionaloptions: TaskOptionsList all tasks for this agent
Get detailed information about a specific task
Subscribe to task notifications for this agent
Subscribe to all task events
Generate webhook URL for a specific task and operation.
Not supported on in-process instances (created via fromMCPClient).
In-process clients have no HTTP listener to receive webhook callbacks.
Register webhook for task notifications.
Not supported on in-process instances (created via fromMCPClient).
OptionaltaskTypes: string[]Unregister webhook notifications.
Not supported on in-process instances (created via fromMCPClient).
Returns the AdCP protocol version this client speaks. Mirrors
SingleAgentClient.getAdcpVersion(). See SingleAgentClientConfig.adcpVersion.