npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@atrib/agent

v0.1.9

Published

Agent middleware for atrib. Interceptor plus framework adapters for MCP attribution. Supports raw SDK, Claude Agent SDK, Cloudflare Agents, Vercel AI SDK, LangChain JS.

Readme

@atrib/agent

Verifiable agent actions, client side. Every outbound MCP tool call gets signed at the moment of dispatch, carries provable context to the receiver, and chains into the next action. Works with every major MCP framework. Sits above every major agent payment protocol so commerce-closing settlement is bundled in.

@atrib/agent is the client-side half of the atrib protocol. Each outbound MCP tool call becomes a signed, chainable record so anyone (the agent itself, downstream auditors, merchants closing a transaction, future agents picking up the work) can verify what happened without trusting any intermediary.

You set up one atrib() interceptor, plug it into your framework's adapter, and every outbound tools/call from that point on carries W3C trace context, an atrib chain token, and the full atrib session lifecycle. When a payment completes (through any of the supported commerce protocols), a transaction record closes the chain and the substrate produces a signed settlement document anyone can recompute. When commerce never closes the chain, the substrate still serves recall, audit, and cross-agent provenance.

Two coverage surfaces define what you get:

Coverage Matrix 1: MCP Framework Adapters

| Framework | Package | Adapter helper | Integration shape | Status | | ------------------------------------------ | -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | ----------- | | Raw @modelcontextprotocol/sdk Client | @modelcontextprotocol/sdk | wrapMcpClient(client, interceptor, { serverUrl? }) | Proxy-based wrapper, returns new client | ✅ Shipped | | Claude Agent SDK | @anthropic-ai/claude-agent-sdk | Case A (in-process tools): zero code. the SDK's createSdkMcpServer returns a real McpServer that @atrib/mcp wraps directly | Reuses @atrib/mcp's atrib() middleware on the server side | ✅ Shipped | | | | Case B (third-party servers): createAtribProxy({ upstream, interceptor }) from @atrib/mcp. in-process surrogate McpServer that forwards to an upstream | Proxy McpServer between SDK and upstream transport | ✅ Shipped | | Cloudflare Agents | agents | attributeCloudflareAgentMcp(agent, { interceptor, serverUrls }) | Walks agent.mcp.mcpConnections, replaces .client via wrapMcpClient | ✅ Shipped | | Vercel AI SDK MCP | @ai-sdk/mcp | attributeVercelAiSdkMcp(mcpClient, { interceptor, serverUrl }) | Monkey-patches mcpClient.request() (custom JSON-RPC, not SDK Client) | ✅ Shipped | | LangChain JS MCP adapters | @langchain/mcp-adapters | High-level: attributeLangchainMcp(multiClient, { interceptor, serverUrls }) | Walks multiClient.config.mcpServers, monkey-patches callTool + fork on each internal Client | ✅ Shipped | | | | Low-level: wrapMcpClient(rawClient, interceptor) passed to loadMcpTools(name, wrapped) | Reuses raw-SDK wrapper path | ✅ Shipped | | OpenAI Agents SDK | @openai/agents | (planned. custom transport architecture, not @modelcontextprotocol/sdk) | Planned: subclass MCPServerSSE / MCPServerStdio / MCPServerStreamableHttp | ⏳ Planned | | Mastra | @mastra/mcp | (planned. smaller footprint, needs source verification) |; | ⏳ Planned |

The pattern across every row is identical: one atrib() interceptor object, one adapter helper call, zero changes to your existing tool invocation code. The name of the helper varies because each host framework exposes a structurally different integration surface, but the ToolCallInterceptor type, the options shape, and the observable behavior are uniform.

Coverage Matrix 2: Agent Payment Protocols

@atrib/agent sits above every major agent payment protocol. It does not implement payments, move money, or enforce transactions; it detects transaction events in the response flow of whichever payment protocol your agent is using, and writes a signed transaction record that closes the attribution chain. You do not choose a payment protocol at install time; the detection logic for all six (ACP, UCP, x402, MPP, AP2, a2a-x402) runs simultaneously and fires on whichever one your tool responses happen to carry. Transaction records emitted by @atrib/agent carry the signers array per spec §1.7.6; the counterparty signature is collected via the payment protocol's settlement response.

All detection logic lives in packages/agent/src/transaction.ts and runs against unit tests for each protocol's published spec.

| Protocol | Sponsor / origin | Detection signal | Spec reference | | ------------------------------------- | ----------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------ | | ACP. Agentic Commerce Protocol | Stripe / OpenAI; github.com/agentic-commerce-protocol | status === "completed" + embedded order on /checkout_sessions/{id}/complete, or order_create / order_update webhook | §1.7.1 | | UCP. Universal Commerce Protocol | github.com/universal-commerce-protocol/ucp | Same shape as ACP + top-level ucp.version envelope | §1.7.2 | | x402 | Coinbase. github.com/coinbase/x402 | HTTP PAYMENT-RESPONSE header (v2) or legacy X-PAYMENT-RESPONSE (v1) on the 200 response | §1.7.3 | | MPP. Machine Payments Protocol | Tempo Labs / Stripe; IETF draft-ryan-httpauth-payment-01 | HTTP Payment-Receipt header on 200 success response | §1.7.4 | | AP2. Agent Payments Protocol | Google; github.com/google-agentic-commerce/ap2 | A2A Message with DataPart containing ap2.mandates.PaymentMandate | §1.7.5 | | a2a-x402 | Google. github.com/google-agentic-commerce/a2a-x402 | A2A task status.message.metadata["x402.payment.status"] === "payment-completed" + receipts[].success === true | §1.7.5 (reported as AP2 crypto path) |

The linking mechanism is the same across all six: the session context_id (16-byte anchor, equal to the W3C OTel trace-id by default) travels with the outbound payment request; via X-atrib-Context HTTP header for protocols that don't expose a free-form metadata field, or via params._meta.atrib for any payment protocol running over MCP transport. When the merchant's side sees the payment-completed signal, atrib writes a transaction record with that context_id, and the attribution graph can reconstruct the full chain from contributing tool calls → transaction → settlement.

You do not install a separate package for each protocol. ACP, UCP, x402, MPP, AP2 and a2a-x402 detection all ship in @atrib/agent and @atrib/mcp by default. Adding a new payment protocol happens by adding a detector in transaction.ts, not by asking users to install anything.

What each detector actually looks for on the wire

These are the exact shapes the production detectTransaction() function in packages/agent/src/transaction.ts matches against. Every shape below is covered by a unit test against a real spec fixture in packages/agent/test/fixtures/, the customer-facing question "what does atrib actually detect" has a one-paragraph answer per protocol.

ACP: Stripe / OpenAI Agentic Commerce Protocol

Detected on the success response of POST /checkout_sessions/{id}/complete. Required fields: top-level status: "completed" plus an order object with a string id. The optional order.permalink_url becomes the checkoutUrl for Path 2 content_id derivation per spec §5.4.5.

{
  "id": "checkout_session_abc123",
  "status": "completed",
  "order": {
    "id": "ord_xyz789",
    "permalink_url": "https://merchant.example.com/orders/ord_xyz789"
  }
}

The order_create and order_update webhook event shapes are also detected (type: "order_create" plus a data object containing the order fields).

UCP: Universal Commerce Protocol

Identical to ACP plus a top-level ucp envelope with a version string. The envelope is the only structural distinguisher between ACP and UCP, without it the same shape is reported as ACP.

{
  "ucp": { "version": "1.0", "capabilities": [] },
  "id": "checkout_session_abc123",
  "status": "completed",
  "order": { "id": "ord_xyz789", "permalink_url": "https://..." }
}

x402: Coinbase

Detected entirely from an HTTP response header, not the body. The v2 header is PAYMENT-RESPONSE (per github.com/coinbase/x402); the v1 legacy header X-PAYMENT-RESPONSE is also accepted. Header name lookup is case-insensitive per RFC 7230.

HTTP/1.1 200 OK
PAYMENT-RESPONSE: eyJzdWNjZXNzIjp0cnVlfQ==

The header value is base64-encoded JSON {success, transaction, network, payer, requirements} but detectTransaction() only checks for the header's presence; the surrounding wrapMcpClient / framework adapter is responsible for capturing response headers and passing them to the detector.

MPP: IETF draft draft-ryan-httpauth-payment-01

Also header-based, but a different header from x402 (the two were conflated in earlier drafts of this code; see DECISIONS.md D016). MPP uses Payment-Receipt per §5.3 of the IETF draft. Both headers may not co-exist on a real response, but if they do, x402 wins (deterministic precedence documented in the test suite).

HTTP/1.1 200 OK
Payment-Receipt: eyJzdGF0dXMiOiJzdWNjZXNzIn0

AP2: Google Agent Payments Protocol (v0.1)

Detected from an A2A Message containing a DataPart whose data object has the literal key "ap2.mandates.PaymentMandate". AP2 v0.1 does not use W3C Verifiable Credentials despite earlier drafts assuming it would (a legacy VC fallback is kept for research forks).

{
  "messageId": "b5951b1a-8d5b-4ad3-a06f-92bf74e76589",
  "contextId": "sample-payment-context",
  "role": "user",
  "parts": [
    {
      "kind": "data",
      "data": {
        "ap2.mandates.PaymentMandate": {
          "payment_details": { "payment_request_id": "order_shoes_123", "...": "..." }
        }
      }
    }
  ]
}

IntentMandate and CartMandate are not detected; they are upstream funnel events, not transaction events. Only PaymentMandate closes the chain.

a2a-x402: Google AP2 crypto path

Detected from an A2A task whose status.message.metadata contains "x402.payment.status": "payment-completed" and at least one entry in "x402.payment.receipts" with success: true. A payment-completed status with no successful receipt does NOT detect (a failed receipt is not a transaction). Reported as protocol: 'AP2' because a2a-x402 is the AP2 crypto path, not a separate protocol.

{
  "kind": "task",
  "status": {
    "message": {
      "metadata": {
        "x402.payment.status": "payment-completed",
        "x402.payment.receipts": [{ "success": true, "transaction": "0xabc...", "network": "base" }]
      }
    }
  }
}

Heuristic fallback (last resort)

If none of the above match, the detector falls back to checking the tool name against a set of common keywords: create_order, complete_checkout, process_payment, place_order, purchase, checkout. A match returns protocol: 'heuristic' and is included in the chain, but it's a weaker signal than any of the protocol-specific detectors above. Use this only when no payment protocol is in play and you want the chain to still close on a domain-specific tool name.


Quick start: one interceptor, any framework

Every adapter wiring looks the same:

import { atrib } from '@atrib/agent'

const interceptor = atrib({
  // 32-byte Ed25519 seed in base64url. Generate with:
  //   node -e 'console.log(Buffer.from(crypto.randomBytes(32)).toString("base64url"))'
  creatorKey: process.env.ATRIB_PRIVATE_KEY!,

  // Your merchant identity (used for Path 1 transaction detection per §5.4.5).
  merchantDomain: 'https://merchant.example.com',

  // Canonical URLs of MCP servers this agent will call (drives policy negotiation).
  serverUrls: ['https://search.example.com', 'https://shop.example.com'],

  // Optional: where to submit signed records. Omit in development.
  logEndpoint: process.env.ATRIB_LOG_ENDPOINT,
})

That's the interceptor. Now plug it into whichever framework you use:

Raw @modelcontextprotocol/sdk

import { Client } from '@modelcontextprotocol/sdk/client/index.js'
import { wrapMcpClient } from '@atrib/agent'

const raw = new Client({ name: 'my-agent', version: '1.0.0' }, { capabilities: {} })
await raw.connect(transport)
const client = wrapMcpClient(raw, interceptor, {
  serverUrl: 'https://my-tool.example.com',
})
// Use `client` anywhere the raw Client would have been used.

Claude Agent SDK: Case A (in-process tools, zero atrib code on this side)

import { createSdkMcpServer, tool } from '@anthropic-ai/claude-agent-sdk'
import { atrib as wrapServer } from '@atrib/mcp'  // note: server-side package

const sdkServer = createSdkMcpServer({
  name: 'my-tools',
  tools: [tool('search', 'Search the web', { q: z.string() }, async ({ q }) => ({ ... }))],
})
wrapServer(sdkServer.instance, { creatorKey: process.env.ATRIB_PRIVATE_KEY! })

// Pass sdkServer to the Claude Agent SDK as a normal `{ type: 'sdk', ... }` config.
// Attribution flows at the server side; the interceptor on this side is not needed.

Claude Agent SDK: Case B (third-party MCP servers via proxy)

import { createAtribProxy } from '@atrib/mcp'

const proxy = await createAtribProxy({
  upstream: { type: 'http', url: 'https://my-tool.example.com/mcp' },
  interceptor,
})

// Pass `proxy.mcpServer` to the Claude Agent SDK as `{ type: 'sdk', instance: proxy.mcpServer, ... }`.

Cloudflare Agents

import { Agent } from 'agents'
import { attributeCloudflareAgentMcp } from '@atrib/agent'

class MyAgent extends Agent {
  async onRequest() {
    await this.mcp.addMcpServer('search', 'https://search.example.com/mcp')
    attributeCloudflareAgentMcp(this, {
      interceptor,
      serverUrls: { search: 'https://search.example.com' },
    })
    // ... call MCP tools as normal
  }
}

Vercel AI SDK

import { createMCPClient } from '@ai-sdk/mcp'
import { streamText } from 'ai'
import { attributeVercelAiSdkMcp } from '@atrib/agent'

const mcpClient = await createMCPClient({
  transport: { type: 'http', url: 'https://my-tool.example.com/mcp' },
})
attributeVercelAiSdkMcp(mcpClient, {
  interceptor,
  serverUrl: 'https://my-tool.example.com',
})

const tools = await mcpClient.tools()
const result = await streamText({ model: 'openai/gpt-5.4', tools, prompt: '...' })

LangChain JS

import { MultiServerMCPClient } from '@langchain/mcp-adapters'
import { attributeLangchainMcp } from '@atrib/agent'

const multi = new MultiServerMCPClient({
  mcpServers: { search: { transport: 'http', url: 'https://search.example.com/mcp' } },
})
await multi.initializeConnections()
await attributeLangchainMcp(multi, {
  interceptor,
  serverUrls: { search: 'https://search.example.com' },
})

const tools = await multi.getTools()
// ... pass `tools` to your LangChain agent as normal

In every case: same interceptor, one adapter call, identical behavior. The differences between adapters are forced by differences between host frameworks; not invented by atrib.


What you get

Once the adapter is wired in, every successful tools/call from your agent:

  1. Carries W3C trace context (traceparent, tracestate, baggage) in params._meta, so downstream servers can correlate calls with your OTel traces.
  2. Carries an attribution chain token in params._meta.atrib, a ~87-char base64url token identifying the prior call in the chain (§1.5.2).
  3. Emits a signed attribution record to the submission queue asynchronously, zero blocking on the hot path (§5.3.5).
  4. Updates session state with the response's own _meta.atrib token, so the next call chains correctly from the current response.
  5. Detects transaction events in the response via the transaction.ts detector, across all six payment protocols in coverage matrix 2. When a transaction is detected, a transaction record is emitted linking the session context_id to the transaction.
  6. Fails silent: if any internal atrib step (signing, submission, interceptor logic) throws, the error is caught, logged with the atrib: prefix, and the tool call proceeds normally per spec §5.8.

Runnable examples

Each example directory contains a README.md with framework-specific rationale and a runnable integration.ts snippet.


Failure model (spec §5.8)

The entire atrib integration is wrapped in defensive error handling at every adapter boundary. If any of the following fails, the original tool call continues normally and an atrib:-prefixed warning is logged:

  • onBeforeToolCall throws → forward the request with original _meta (no injection)
  • onAfterToolResponse throws → return the result to the caller anyway
  • Signing throws → skip the record for that call
  • Submission network error → the submission queue retries with exponential backoff; final failure drops the record silently
  • creatorKey missing → pass-through mode with one console warning per process

atrib failures never affect the primary tool call or agent response. This is invariant #1 in CLAUDE.md and is enforced by unit tests in each adapter's test file.


Spec references

| Spec section | What it defines | | ------------ | ------------------------------------------------------------ | | §1.3 | JCS canonical serialization of records | | §1.4 | Ed25519 signing and verification | | §1.5 | Context propagation via params._meta and W3C trace context | | §1.7 | Transaction event hooks for all 6 payment protocols | | §2 | Merkle log protocol (Tessera-backed, tlog-tiles spec) | | §3 | Graph query interface (fact layer only) | | §4 | Policy format (merchant-side value distribution) | | §5.3 | Agent-side middleware behavior | | §5.4 | Path 1 / Path 2 transaction detection | | §5.8 | Degradation contract; silent failure never breaks the host |

The full protocol spec is at atrib-spec.md.


A note on documentation links. The atrib protocol repository is currently private (in-progress public preparation). Links in this README to the spec and sister packages (atrib-spec.md, packages/agent/README.md, etc.) point at github.com/creatornader/atrib/blob/main/... URLs that will resolve once the repository goes public. Until then, see atrib.dev for the protocol overview.