Atlas / MCP servers / adcontextprotocol / @adcp/sdk

@adcp/sdkBLOCK

mcp/adcontextprotocol/adcp-client

A Typescript SDK for the AdCP protocol (client and server)

Verdict
BLOCK
Grade
F
Trust score
37 /100
Exposed tools
92 84r · 8w · 0d
Transport
stdio · streamable-http
License
Apache-2.0
Stars
18
01

Overview

From the repository's own README, as read at the audited commit. Badges and raw HTML are left out.

[](https://badge.fury.io/js/@adcp%2Fsdk) [](https://www.npmjs.com/package/@adcp/sdk) [](https://www.apache.org/licenses/LICENSE-2.0) [](https://www.typescriptlang.org/) [](https://adcontextprotocol.github.io/adcp-client/api/) [](https://github.com/adcontextprotocol/adcp-client/actions)

Official TypeScript/JavaScript SDK for the Ad Context Protocol (AdCP). Use its buyer client to call agents, server framework to build them, and conformance tools to test them. The SDK supports MCP and A2A, with both immediate and asynchronous task results.

For AI Agents

Start with docs/llms.txt — the full protocol spec in one file (tools, types, error codes, examples). Building a server? See docs/guides/BUILD-AN-AGENT.md. Calling an AdCP agent as a buyer? Load skills/call-adcp-agent/SKILL.md — wire contract, async flow, and error-recovery priors that aren't in the type signatures. Setting up request signing? See docs/guides/SIGNING-GUIDE.md. For type signatures, use docs/TYPE-SUMMARY.md. Skip src/lib/types/*.generated.ts — they're machine-generated and will burn context.

These docs are also available in node_modules/@adcp/sdk/docs/ after install.

The Core Concept

AdCP operations are distributed and asynchronous by default. An agent might:

  • Complete your request immediately (synchronous)
  • Need time to process and **
Read from source at commit 190ef4efa848OBSERVED · 2026-10-12
Advertisement
02

Connect

Built from this server's own package name, version and transport as found in its source — not copied from anyone's documentation, so it cannot drift against a page we do not control. Replace the environment placeholders with a token scoped to the least it needs.

claude-code
claude mcp add reference-renderers --env A2A_AUTH_TOKEN=${A2A_AUTH_TOKEN} --env ADCP_ACCOUNT_FEED_TRAINING_TOKEN=${ADCP_ACCOUNT_FEED_TRAINING_TOKEN} --env ADCP_AUTH_SCHEME=${ADCP_AUTH_SCHEME} --env ADCP_AUTH_TOKEN=${ADCP_AUTH_TOKEN} -- npx -y @adcp/[email protected]
claude-desktop
{
  "mcpServers": {
    "reference-renderers": {
      "command": "npx",
      "args": [
        "-y",
        "@adcp/[email protected]"
      ],
      "env": {
        "A2A_AUTH_TOKEN": "${A2A_AUTH_TOKEN}",
        "ADCP_ACCOUNT_FEED_TRAINING_TOKEN": "${ADCP_ACCOUNT_FEED_TRAINING_TOKEN}",
        "ADCP_AUTH_SCHEME": "${ADCP_AUTH_SCHEME}",
        "ADCP_AUTH_TOKEN": "${ADCP_AUTH_TOKEN}"
      }
    }
  }
}
03

Exposed tools (92)

84 read · 8 write · 0 destructive.

ToolRiskDescription
AreadA
BannerreadStandard banner
Customreadhand-written
Demoread...
DroppedreadNo canonical mapping
Exoticreadrequires something unknown
FeedreadMain feed placement
HomepagereadSerializable route fixture
MixedreadOne known and one custom legacy ref
NreadD
Nativereadv2 native
NestedreadNested placement formats
PartialreadOne canonical mapping remains
PrecedencereadDirect publisher wins
SellerreadSeller
SymmetryreadMCP+A2A validation symmetry
Treadt
TestreadTest product
UnrelatedreadSame id, different owner
a2a-stand-inreadA2A operation-resolution stand-in
another_opreadAdCP op
breadd
bidi-override-neutralizedreadUnicode bidi override characters (U+202E, U+2066-U+2069) in catalog values can spoof audit-log rendering. The unreserved-whitelist rule percent-encodes them as their UTF-8 bytes.
canonical_mcp_delivery_envelopereadAccepts a complete MCP webhook envelope with a delivery report nested under result.
check_governanceread
comply_test_controllerread
conformance-fixture-agentreadcard fixture
create_media_buywrite
crlf-injection-neutralizedwriteA catalog value containing CR/LF would enable request-header smuggling or log-row injection in downstream consumers. The unreserved-whitelist rule escapes both bytes, defeating the vector.
custom_hangingread
deadline-a2areaddeadline fixture
dispatchedread
docs-writerwriteWrite or revise AdCP documentation and walkthroughs while preserving schema accuracy, fictional examples, and character consistency.
echoread
errorread
fooread
greadd
get_adcp_capabilitiesread
get_media_buy_deliveryread
get_plan_audit_logsread
get_principalreadAuthenticated as ${echoed}
get_productsread
get_property_listreadFetch a property list by id.
get_reporting_statusread
get_signalsread
get_task_statusread
large_result_toolread
large_schema_toolread
legacyread
legacy-conformance-fixture-agentreadlegacy card fixture
list_creative_formatsreadCreative Formats
list_creativesreadCreatives
list_productsread
list_tasksread
mreadd
mixed-path-and-query-contextsreadVerifies encoding applies equally to path segments and query strings within the same URL.
nreadd
nativeread
nested-expansion-preserved-as-literalreadA catalog value containing AdCP macro syntax
non-ascii-utf8-percent-encodingreadNon-ASCII octets MUST be percent-encoded after UTF-8 encoding per RFC 3986 §2.5. A value containing
observe_authread
optsread
preadx
path-scoped-agentreadcard fixture
pingreadhealth
platformread
protocol-reviewerreadReview protocol, schema, and documentation changes for correctness, workflow regressions, versioning mistakes, and missing tests.
provenance-fixture-agentreadcard fixture
refine_proposalsread
reject_bare_delivery_resultwriteRejects delivery report content sent directly as the top-level POST body.
reject_invalid_signaturereadRejects a request whose signature does not cover the exact raw request body.
reject_mismatched_signature_targetreadRejects a valid signature that covers a different webhook target URI.
reject_missing_envelope_fieldsreadRejects an MCP-like envelope missing required transport fields.
reject_stale_signature_timestampreadRejects a request whose signature timestamp is outside the allowed freshness window.
reject_unsupported_statusreadRejects malformed top-level async task status values.
report_plan_outcomeread
reserved-character-breakoutreadA catalog value containing
retry_preserves_idempotency_keyreadAccepts a retry of the same logical event with the same idempotency_key.
routed-a2areadtransport fixture
rpc-onlyreadrpc only
sampleread
sellerreadseller
signing-a2a-stubreadA2A stub for request-signing integration tests
sync_accountswrite
sync_creativeswrite
sync_planswrite
tasks_getread
tenant-cardreadtenant scoped card
testreadtest
unsigned_opread
update_media_buywrite
url-scheme-injection-neutralizedreadA catalog value containing
04

Trust audit

BLOCKgrade F · trust 37/100 Do not install this without reading the findings. The audit found something that could harm you or your machine.

LayerWhat it checksResult
L0Provenance & inventoryFAIL
L1Static analysis of the codeFAIL
L2Instruction surface (what it tells the agent)PASS
L3Class-specific surfacePASS
L4Behavioural (sandbox)SKIPPED

What the source does

Filesystem
declared (10 observation(s))
Network
declared (13 observation(s))
Shell
declared (12 observation(s))
Dependencies
not all pinned
Secrets in source
found

Findings (25)

HIGHInventory / provenance · inv.suspicious_name · CWE-1104
src/lib/types/server-payload-aliases.ts
server-payload-aliases.ts
Why it matters. member named after an attack tool
Fix. remove or justify
HIGHInventory / provenance · inv.suspicious_name · CWE-1104
src/lib/types/server-payload.ts
server-payload.ts
Why it matters. member named after an attack tool
Fix. remove or justify
HIGHCode injection · code.eval_exec · CWE-78, CWE-94, CWE-95
scripts/reporting-interop/run.mjs:72
result = await exec(executable, argv, { cwd: output, timeout, maxBuffer: 4 * 1024 * 1024 });
Why it matters. evaluates text as code
Fix. remove; use a parser or a dispatch table
HIGHCode injection · code.eval_exec · CWE-78, CWE-94, CWE-95
scripts/reporting-interop/run.mjs:91
const exportResult = await exec(
Why it matters. evaluates text as code
Fix. remove; use a parser or a dispatch table
HIGHCode injection · code.eval_exec · CWE-78, CWE-94, CWE-95
scripts/reporting-interop/run.mjs:107
const installed = await exec(python, ['-I', path.join(here, 'verify.py'), packageRoot, archive, wheel], {
Why it matters. evaluates text as code
Fix. remove; use a parser or a dispatch table
HIGHCode injection · code.eval_exec · CWE-78, CWE-94, CWE-95
src/lib/server/idempotency/backends/redis.ts:82
eval(script: string, options: { keys: string[]; arguments: string[] }): Promise<unknown>;
Why it matters. evaluates text as code
Fix. remove; use a parser or a dispatch table
HIGHCode injection · code.eval_exec · CWE-78, CWE-94, CWE-95
src/lib/signing/redis-replay-store.ts:117
eval(script: string, options: { keys: string[]; arguments: string[] }): Promise<unknown>;
Why it matters. evaluates text as code
Fix. remove; use a parser or a dispatch table
HIGHNetwork egress · net.metadata_ip · CWE-200, CWE-319
src/lib/server/pin-and-bind-fetch.ts:80
'metadata.google.internal',
Why it matters. cloud metadata endpoint: the classic SSRF credential grab
HIGHNetwork egress · net.metadata_ip · CWE-200, CWE-319
src/lib/server/pin-and-bind-fetch.ts:123
'metadata.google.internal',
Why it matters. cloud metadata endpoint: the classic SSRF credential grab
MEDIUMCode injection · code.dynamic_import · CWE-78, CWE-94, CWE-95
scripts/reporting-interop/adjustment-buyer.py:58
origin = Path(importlib.import_module(name).__file__).resolve()
MEDIUMCode injection · code.dynamic_import · CWE-78, CWE-94, CWE-95
scripts/reporting-interop/buyer-submissions.py:58
module = importlib.import_module(name)
MEDIUMInformation disclosure · disclose.log_secret · CWE-209, CWE-532
bin/adcp.js:5789
console.log(`${prefix}  ↳ (no token / opaque token)`);
MEDIUMInformation disclosure · disclose.log_secret · CWE-209, CWE-532
bin/adcp.js:6250
console.log(`\n🔍 Discovering OAuth token endpoint from ${url}...`);
MEDIUMInformation disclosure · disclose.log_secret · CWE-209, CWE-532
bin/adcp.js:6268
console.log(`   Found token endpoint host: ${endpointHost}`);
MEDIUMInformation disclosure · disclose.log_secret · CWE-209, CWE-532
bin/adcp.js:6366
console.log(`Token URL:     ${resolvedOauthEndpoint}${oauthEndpoint ? '' : ' (discovered)'}`);
MEDIUMInformation disclosure · disclose.log_secret · CWE-209, CWE-532
bin/adcp.js:6428
console.log(`✅ Token exchange succeeded (expires_in: ${tokens.expires_in ?? 'unspecified'})\n`);
MEDIUMNetwork egress · net.beacon_words · CWE-200, CWE-319
src/lib/core/postgres-webhook-registration-store.ts:78
callback_url                     TEXT NOT NULL,
MEDIUMNetwork egress · net.beacon_words · CWE-200, CWE-319
src/lib/core/postgres-webhook-registration-store.ts:116
callback_url,
MEDIUMNetwork egress · net.beacon_words · CWE-200, CWE-319
src/lib/core/postgres-webhook-registration-store.ts:181
callbackUrl: requiredString(row, 'callback_url'),
MEDIUMNetwork egress · net.beacon_words · CWE-200, CWE-319
src/lib/core/postgres-webhook-registration-store.ts:254
agent_id, operation_id, agent_url, protocol, task_type, callback_url,
MEDIUMNetwork egress · net.beacon_words · CWE-200, CWE-319
src/lib/core/postgres-webhook-registration-store.ts:265
agent_url, protocol, task_type, callback_url, method, mode,
MEDIUMNetwork egress · net.raw_ip · CWE-200, CWE-319
.env.example:10
SALES_AGENTS_CONFIG='{"agents": [{"id": "test_mcp_local", "name": "Local Test MCP Server", "agent_uri": "http://127.0.0.1:3001/mcp", "protocol": "mcp", "requiresAuth": false}, {"id": "demo_agent_a2a",
MEDIUMNetwork egress · net.raw_ip · CWE-200, CWE-319
bin/adcp-grade.js:86
adcp grade request-signing http://127.0.0.1:3000/mcp --allow-http --skip-rate-abuse
MEDIUMHard-coded secrets · secret.db_uri · CWE-798, CWE-321
test/lib/reporting-gcp-validation-pg.test.js:78
report.fail('S', 'check', 'failed with postgres://user:hunter2@host/db and ya29.token-value and hunter2');
MEDIUMHard-coded secrets · secret.generic · CWE-798, CWE-321
src/lib/server/socket-mode/conformance-client.test.ts:114
token: 'irrelevant-for-this-test',

Gates applied: no_behavioural_pass.

Audited 2026-10-12 · audit v0.4.1 · source sha 190ef4efa848full audit observations/trust-audit/mcp-server/adcontextprotocol__adcp-client.json · Report an issue / request a re-scan
05

Audit history

Every audit this server has had. A grade with a past is a grade somebody is still checking.

DateSourceVerdictGradeScoreChange
2026-10-12190ef4efa848BLOCKF37first audit
06

Questions

What is the @adcp/sdk MCP server?

A Typescript SDK for the AdCP protocol (client and server)

What tools does @adcp/sdk expose?

92 in total: 84 read-only, 8 that write, and 0 that can delete or overwrite. Every one is listed on this page with its risk.

Is @adcp/sdk safe to connect to an agent?

No — not without reading the findings first. The audit graded it F (37/100) and found 9 critical or high issues in the source. Each one is listed on this page with the file and line it is on.

What credentials does @adcp/sdk need?

It reads A2A_AUTH_TOKEN, ADCP_ACCOUNT_FEED_TRAINING_TOKEN, ADCP_AUTH_SCHEME, ADCP_AUTH_TOKEN, ADCP_AUTH_TOKEN_CROSS_TENANT, ADCP_CONFORMANCE_TOKEN, ADCP_GRADE_INITIALIZE_AUTHORIZATION, ADCP_INTEROP_BUYER_TOKEN, ADCP_LOG_IDEMPOTENCY_KEYS, ADCP_PRIV_KEY, ADCP_REGISTRY_API_KEY and ADCP_TEST_AUTH_MODULE from the environment. Give it a token scoped to the least it needs — an agent that can be talked into calling a tool can be talked into calling it with your credentials.

How does @adcp/sdk run?

It speaks stdio and streamable-http, so it runs as a local process your client starts. It is published on npm as @adcp/reference-renderers at 1.0.0.

How current is this page?

The grade is for one exact copy of the source (190ef4efa848), read on 2026-10-12. The repository is watched and re-audited when it changes.

Advertisement