@atrib/agent 0.1.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 (39) hide show
  1. package/LICENSE +190 -0
  2. package/README.md +333 -0
  3. package/dist/adapters/cloudflare-agent.d.ts +46 -0
  4. package/dist/adapters/cloudflare-agent.d.ts.map +1 -0
  5. package/dist/adapters/cloudflare-agent.js +124 -0
  6. package/dist/adapters/cloudflare-agent.js.map +1 -0
  7. package/dist/adapters/langchain-mcp.d.ts +172 -0
  8. package/dist/adapters/langchain-mcp.d.ts.map +1 -0
  9. package/dist/adapters/langchain-mcp.js +145 -0
  10. package/dist/adapters/langchain-mcp.js.map +1 -0
  11. package/dist/adapters/mcp-client.d.ts +94 -0
  12. package/dist/adapters/mcp-client.d.ts.map +1 -0
  13. package/dist/adapters/mcp-client.js +91 -0
  14. package/dist/adapters/mcp-client.js.map +1 -0
  15. package/dist/adapters/vercel-ai-sdk-mcp.d.ts +129 -0
  16. package/dist/adapters/vercel-ai-sdk-mcp.d.ts.map +1 -0
  17. package/dist/adapters/vercel-ai-sdk-mcp.js +115 -0
  18. package/dist/adapters/vercel-ai-sdk-mcp.js.map +1 -0
  19. package/dist/index.d.ts +18 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +27 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/middleware.d.ts +53 -0
  24. package/dist/middleware.d.ts.map +1 -0
  25. package/dist/middleware.js +268 -0
  26. package/dist/middleware.js.map +1 -0
  27. package/dist/policy.d.ts +28 -0
  28. package/dist/policy.d.ts.map +1 -0
  29. package/dist/policy.js +196 -0
  30. package/dist/policy.js.map +1 -0
  31. package/dist/session.d.ts +50 -0
  32. package/dist/session.d.ts.map +1 -0
  33. package/dist/session.js +141 -0
  34. package/dist/session.js.map +1 -0
  35. package/dist/transaction.d.ts +52 -0
  36. package/dist/transaction.d.ts.map +1 -0
  37. package/dist/transaction.js +123 -0
  38. package/dist/transaction.js.map +1 -0
  39. package/package.json +50 -0
package/LICENSE ADDED
@@ -0,0 +1,190 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship made available under
36
+ the License, as indicated by a copyright notice that is included in
37
+ or attached to the work (an example is provided in the Appendix below).
38
+
39
+ "Derivative Works" shall mean any work, whether in Source or Object
40
+ form, that is based on (or derived from) the Work and for which the
41
+ editorial revisions, annotations, elaborations, or other modifications
42
+ represent, as a whole, an original work of authorship. For the purposes
43
+ of this License, Derivative Works shall not include works that remain
44
+ separable from, or merely link (or bind by name) to the interfaces of,
45
+ the Work and Derivative Works thereof.
46
+
47
+ "Contribution" shall mean, as submitted to the Licensor for inclusion
48
+ in the Work by the copyright owner or by an individual or Legal Entity
49
+ authorized to submit on behalf of the copyright owner. For the purposes
50
+ of this definition, "submitted" means any form of electronic, verbal,
51
+ or written communication sent to the Licensor or its representatives,
52
+ including but not limited to communication on electronic mailing lists,
53
+ source code control systems, and issue tracking systems that are managed
54
+ by, or on behalf of, the Licensor for the purpose of discussing and
55
+ improving the Work, but excluding communication that is conspicuously
56
+ marked or otherwise designated in writing by the copyright owner as
57
+ "Not a Contribution."
58
+
59
+ "Contributor" shall mean Licensor and any Legal Entity on behalf of
60
+ whom a Contribution has been received by the Licensor and subsequently
61
+ incorporated within the Work.
62
+
63
+ 2. Grant of Copyright License. Subject to the terms and conditions of
64
+ this License, each Contributor hereby grants to You a perpetual,
65
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
66
+ copyright license to reproduce, prepare Derivative Works of,
67
+ publicly display, publicly perform, sublicense, and distribute the
68
+ Work and such Derivative Works in Source or Object form.
69
+
70
+ 3. Grant of Patent License. Subject to the terms and conditions of
71
+ this License, each Contributor hereby grants to You a perpetual,
72
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
73
+ (except as stated in this section) patent license to make, have made,
74
+ use, offer to sell, sell, import, and otherwise transfer the Work,
75
+ where such license applies only to those patent claims licensable
76
+ by such Contributor that are necessarily infringed by their
77
+ Contribution(s) alone or by combination of their Contribution(s)
78
+ with the Work to which such Contribution(s) was submitted. If You
79
+ institute patent litigation against any entity (including a cross-claim
80
+ or counterclaim in a lawsuit) alleging that the Work or a Contribution
81
+ incorporated within the Work constitutes direct or contributory patent
82
+ infringement, then any patent licenses granted to You under this License
83
+ for that Work shall terminate as of the date such litigation is filed.
84
+
85
+ 4. Redistribution. You may reproduce and distribute copies of the
86
+ Work or Derivative Works thereof in any medium, with or without
87
+ modifications, and in Source or Object form, provided that You
88
+ meet the following conditions:
89
+
90
+ (a) You must give any other recipients of the Work or Derivative Works
91
+ a copy of this License; and
92
+
93
+ (b) You must cause any modified files to carry prominent notices
94
+ stating that You changed the files; and
95
+
96
+ (c) You must retain, in the Source form of any Derivative Works
97
+ that You distribute, all copyright, patent, trademark, and
98
+ attribution notices from the Source form of the Work,
99
+ excluding those notices that do not pertain to any part of
100
+ the Derivative Works; and
101
+
102
+ (d) If the Work includes a "NOTICE" text file as part of its
103
+ distribution, You must include a readable copy of the attribution
104
+ notices contained within such NOTICE file, in at least one
105
+ of the following places: within a NOTICE text file distributed
106
+ as part of the Derivative Works; within the Source form or
107
+ documentation, if provided along with the Derivative Works; or,
108
+ within a display generated by the Derivative Works, if and
109
+ wherever such third-party notices normally appear. The contents
110
+ of the NOTICE file are for informational purposes only and
111
+ do not modify the License. You may add Your own attribution
112
+ notices within Derivative Works that You distribute, alongside
113
+ or as an addendum to the NOTICE text from the Work, provided
114
+ that such additional attribution notices cannot be construed
115
+ as modifying the License.
116
+
117
+ You may add Your own license statement for Your modifications and
118
+ may provide additional grant of rights to use, modify, or distribute
119
+ those modifications in accordance with this License.
120
+
121
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
122
+ any Contribution intentionally submitted for inclusion in the Work
123
+ by You to the Licensor shall be under the terms and conditions of
124
+ this License, without any additional terms or conditions.
125
+ Notwithstanding the above, nothing herein shall supersede or modify
126
+ the terms of any separate license agreement you may have executed
127
+ with Licensor regarding such Contributions.
128
+
129
+ 6. Trademarks. This License does not grant permission to use the trade
130
+ names, trademarks, service marks, or product names of the Licensor,
131
+ except as required for reasonable and customary use in describing the
132
+ origin of the Work and reproducing the content of the NOTICE file.
133
+
134
+ 7. Disclaimer of Warranty. Unless required by applicable law or
135
+ agreed to in writing, Licensor provides the Work (and each
136
+ Contributor provides its Contributions) on an "AS IS" BASIS,
137
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
138
+ implied, including, without limitation, any warranties or conditions
139
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
140
+ PARTICULAR PURPOSE. You are solely responsible for determining the
141
+ appropriateness of using or reproducing the Work and assume any
142
+ risks associated with Your exercise of permissions under this License.
143
+
144
+ 8. Limitation of Liability. In no event and under no legal theory,
145
+ whether in tort (including negligence), contract, or otherwise,
146
+ unless required by applicable law (such as deliberate and grossly
147
+ negligent acts) or agreed to in writing, shall any Contributor be
148
+ liable to You for damages, including any direct, indirect, special,
149
+ incidental, or exemplary damages of any character arising as a
150
+ result of this License or out of the use or inability to use the
151
+ Work (including but not limited to damages for loss of goodwill,
152
+ work stoppage, computer failure or malfunction, or all other
153
+ commercial damages or losses), even if such Contributor has been
154
+ advised of the possibility of such damages.
155
+
156
+ 9. Accepting Warranty or Additional Liability. While redistributing
157
+ the Work or Derivative Works thereof, You may choose to offer,
158
+ and charge a fee for, acceptance of support, warranty, indemnity,
159
+ or other liability obligations and/or rights consistent with this
160
+ License. However, in accepting such obligations, You may act only
161
+ on Your own behalf and on Your sole responsibility, not on behalf
162
+ of any other Contributor, and only if You agree to indemnify,
163
+ defend, and hold each Contributor harmless for any liability
164
+ incurred by, or claims asserted against, such Contributor by reason
165
+ of your accepting any such warranty or additional liability.
166
+
167
+ END OF TERMS AND CONDITIONS
168
+
169
+ APPENDIX: How to apply the Apache License to your work.
170
+
171
+ To apply the Apache License to your work, attach the following
172
+ boilerplate notice, with the fields enclosed by brackets "[]"
173
+ replaced with your own identifying information. (Don't include
174
+ the brackets!) The text should be enclosed in the appropriate
175
+ comment syntax for the file format in question. Also, an optional
176
+ "Statement of Purpose" appears after the copyright notice.
177
+
178
+ Copyright 2025-2026 Atrib contributors
179
+
180
+ Licensed under the Apache License, Version 2.0 (the "License");
181
+ you may not use this file except in compliance with the License.
182
+ You may obtain a copy of the License at
183
+
184
+ http://www.apache.org/licenses/LICENSE-2.0
185
+
186
+ Unless required by applicable law or agreed to in writing, software
187
+ distributed under the License is distributed on an "AS IS" BASIS,
188
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
189
+ implied. See the License for the specific language governing
190
+ permissions and limitations under the License.
package/README.md ADDED
@@ -0,0 +1,333 @@
1
+ # `@atrib/agent`
2
+
3
+ **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.**
4
+
5
+ `@atrib/agent` is the client-side half of the [atrib protocol](https://github.com/creatornader/atrib/blob/main/atrib-spec.md). 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.
6
+
7
+ 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.
8
+
9
+ Two coverage surfaces define what you get:
10
+
11
+ ## Coverage Matrix 1: MCP Framework Adapters
12
+
13
+ | Framework | Package | Adapter helper | Integration shape | Status |
14
+ | ------------------------------------------ | -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | ----------- |
15
+ | **Raw `@modelcontextprotocol/sdk` Client** | `@modelcontextprotocol/sdk` | `wrapMcpClient(client, interceptor, { serverUrl? })` | Proxy-based wrapper, returns new client | ✅ Shipped |
16
+ | **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 |
17
+ | | | **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 |
18
+ | **Cloudflare Agents** | `agents` | `attributeCloudflareAgentMcp(agent, { interceptor, serverUrls })` | Walks `agent.mcp.mcpConnections`, replaces `.client` via `wrapMcpClient` | ✅ Shipped |
19
+ | **Vercel AI SDK MCP** | `@ai-sdk/mcp` | `attributeVercelAiSdkMcp(mcpClient, { interceptor, serverUrl })` | Monkey-patches `mcpClient.request()` (custom JSON-RPC, not SDK Client) | ✅ Shipped |
20
+ | **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 |
21
+ | | | **Low-level:** `wrapMcpClient(rawClient, interceptor)` passed to `loadMcpTools(name, wrapped)` | Reuses raw-SDK wrapper path | ✅ Shipped |
22
+ | **OpenAI Agents SDK** | `@openai/agents` | _(planned. custom transport architecture, not `@modelcontextprotocol/sdk`)_ | Planned: subclass `MCPServerSSE` / `MCPServerStdio` / `MCPServerStreamableHttp` | ⏳ Planned |
23
+ | **Mastra** | `@mastra/mcp` | _(planned. smaller footprint, needs source verification)_ |; | ⏳ Planned |
24
+
25
+ **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.
26
+
27
+ ## Coverage Matrix 2: Agent Payment Protocols
28
+
29
+ `@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](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#176-cross-attestation-requirement-for-transaction-records); the counterparty signature is collected via the payment protocol's settlement response.
30
+
31
+ All detection logic lives in `packages/agent/src/transaction.ts` and runs against unit tests for each protocol's published spec.
32
+
33
+ | Protocol | Sponsor / origin | Detection signal | Spec reference |
34
+ | ------------------------------------- | ----------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------ |
35
+ | **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](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#171-acp-agentic-commerce-protocol) |
36
+ | **UCP**. Universal Commerce Protocol | `github.com/universal-commerce-protocol/ucp` | Same shape as ACP + top-level `ucp.version` envelope | [§1.7.2](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#172-ucp-universal-commerce-protocol) |
37
+ | **x402** | Coinbase. `github.com/coinbase/x402` | HTTP `PAYMENT-RESPONSE` header (v2) or legacy `X-PAYMENT-RESPONSE` (v1) on the 200 response | [§1.7.3](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#173-x402) |
38
+ | **MPP**. Machine Payments Protocol | Tempo Labs / Stripe; IETF `draft-ryan-httpauth-payment-01` | HTTP `Payment-Receipt` header on 200 success response | [§1.7.4](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#174-mpp-machine-payments-protocol) |
39
+ | **AP2**. Agent Payments Protocol | Google; `github.com/google-agentic-commerce/ap2` | A2A Message with DataPart containing `ap2.mandates.PaymentMandate` | [§1.7.5](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#175-ap2-and-a2a-x402) |
40
+ | **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](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#175-ap2-and-a2a-x402) (reported as AP2 crypto path) |
41
+
42
+ **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.
43
+
44
+ **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.
45
+
46
+ ### What each detector actually looks for on the wire
47
+
48
+ These are the exact shapes the production `detectTransaction()` function in [`packages/agent/src/transaction.ts`](src/transaction.ts) matches against. Every shape below is covered by a unit test against a real spec fixture in [`packages/agent/test/fixtures/`](test/fixtures/), the customer-facing question "what does atrib actually detect" has a one-paragraph answer per protocol.
49
+
50
+ #### ACP: Stripe / OpenAI Agentic Commerce Protocol
51
+
52
+ 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](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#545-transaction-detection).
53
+
54
+ ```json
55
+ {
56
+ "id": "checkout_session_abc123",
57
+ "status": "completed",
58
+ "order": {
59
+ "id": "ord_xyz789",
60
+ "permalink_url": "https://merchant.example.com/orders/ord_xyz789"
61
+ }
62
+ }
63
+ ```
64
+
65
+ The `order_create` and `order_update` webhook event shapes are also detected (`type: "order_create"` plus a `data` object containing the order fields).
66
+
67
+ #### UCP: Universal Commerce Protocol
68
+
69
+ 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.
70
+
71
+ ```json
72
+ {
73
+ "ucp": { "version": "1.0", "capabilities": [] },
74
+ "id": "checkout_session_abc123",
75
+ "status": "completed",
76
+ "order": { "id": "ord_xyz789", "permalink_url": "https://..." }
77
+ }
78
+ ```
79
+
80
+ #### x402: Coinbase
81
+
82
+ Detected entirely from an HTTP **response header**, not the body. The v2 header is `PAYMENT-RESPONSE` (per [github.com/coinbase/x402](https://github.com/coinbase/x402)); the v1 legacy header `X-PAYMENT-RESPONSE` is also accepted. Header name lookup is case-insensitive per RFC 7230.
83
+
84
+ ```http
85
+ HTTP/1.1 200 OK
86
+ PAYMENT-RESPONSE: eyJzdWNjZXNzIjp0cnVlfQ==
87
+ ```
88
+
89
+ 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.
90
+
91
+ #### MPP: IETF draft `draft-ryan-httpauth-payment-01`
92
+
93
+ Also header-based, but a **different** header from x402 (the two were conflated in earlier drafts of this code; see [`DECISIONS.md` D016](https://github.com/creatornader/atrib/blob/main/DECISIONS.md)). MPP uses `Payment-Receipt` per [§5.3](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#53-atribmcp-mcp-server-middleware) 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).
94
+
95
+ ```http
96
+ HTTP/1.1 200 OK
97
+ Payment-Receipt: eyJzdGF0dXMiOiJzdWNjZXNzIn0
98
+ ```
99
+
100
+ #### AP2: Google Agent Payments Protocol (v0.1)
101
+
102
+ 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).
103
+
104
+ ```json
105
+ {
106
+ "messageId": "b5951b1a-8d5b-4ad3-a06f-92bf74e76589",
107
+ "contextId": "sample-payment-context",
108
+ "role": "user",
109
+ "parts": [
110
+ {
111
+ "kind": "data",
112
+ "data": {
113
+ "ap2.mandates.PaymentMandate": {
114
+ "payment_details": { "payment_request_id": "order_shoes_123", "...": "..." }
115
+ }
116
+ }
117
+ }
118
+ ]
119
+ }
120
+ ```
121
+
122
+ `IntentMandate` and `CartMandate` are **not** detected; they are upstream funnel events, not transaction events. Only `PaymentMandate` closes the chain.
123
+
124
+ #### a2a-x402: Google AP2 crypto path
125
+
126
+ 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.
127
+
128
+ ```json
129
+ {
130
+ "kind": "task",
131
+ "status": {
132
+ "message": {
133
+ "metadata": {
134
+ "x402.payment.status": "payment-completed",
135
+ "x402.payment.receipts": [{ "success": true, "transaction": "0xabc...", "network": "base" }]
136
+ }
137
+ }
138
+ }
139
+ }
140
+ ```
141
+
142
+ #### Heuristic fallback (last resort)
143
+
144
+ 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.
145
+
146
+ ---
147
+
148
+ ## Quick start: one interceptor, any framework
149
+
150
+ Every adapter wiring looks the same:
151
+
152
+ ```ts
153
+ import { atrib } from '@atrib/agent'
154
+
155
+ const interceptor = atrib({
156
+ // 32-byte Ed25519 seed in base64url. Generate with:
157
+ // node -e 'console.log(Buffer.from(crypto.randomBytes(32)).toString("base64url"))'
158
+ creatorKey: process.env.ATRIB_PRIVATE_KEY!,
159
+
160
+ // Your merchant identity (used for Path 1 transaction detection per §5.4.5).
161
+ merchantDomain: 'https://merchant.example.com',
162
+
163
+ // Canonical URLs of MCP servers this agent will call (drives policy negotiation).
164
+ serverUrls: ['https://search.example.com', 'https://shop.example.com'],
165
+
166
+ // Optional: where to submit signed records. Omit in development.
167
+ logEndpoint: process.env.ATRIB_LOG_ENDPOINT,
168
+ })
169
+ ```
170
+
171
+ That's the interceptor. Now plug it into whichever framework you use:
172
+
173
+ ### Raw `@modelcontextprotocol/sdk`
174
+
175
+ ```ts
176
+ import { Client } from '@modelcontextprotocol/sdk/client/index.js'
177
+ import { wrapMcpClient } from '@atrib/agent'
178
+
179
+ const raw = new Client({ name: 'my-agent', version: '1.0.0' }, { capabilities: {} })
180
+ await raw.connect(transport)
181
+ const client = wrapMcpClient(raw, interceptor, {
182
+ serverUrl: 'https://my-tool.example.com',
183
+ })
184
+ // Use `client` anywhere the raw Client would have been used.
185
+ ```
186
+
187
+ ### Claude Agent SDK: Case A (in-process tools, zero atrib code on this side)
188
+
189
+ ```ts
190
+ import { createSdkMcpServer, tool } from '@anthropic-ai/claude-agent-sdk'
191
+ import { atrib as wrapServer } from '@atrib/mcp' // note: server-side package
192
+
193
+ const sdkServer = createSdkMcpServer({
194
+ name: 'my-tools',
195
+ tools: [tool('search', 'Search the web', { q: z.string() }, async ({ q }) => ({ ... }))],
196
+ })
197
+ wrapServer(sdkServer.instance, { creatorKey: process.env.ATRIB_PRIVATE_KEY! })
198
+
199
+ // Pass sdkServer to the Claude Agent SDK as a normal `{ type: 'sdk', ... }` config.
200
+ // Attribution flows at the server side; the interceptor on this side is not needed.
201
+ ```
202
+
203
+ ### Claude Agent SDK: Case B (third-party MCP servers via proxy)
204
+
205
+ ```ts
206
+ import { createAtribProxy } from '@atrib/mcp'
207
+
208
+ const proxy = await createAtribProxy({
209
+ upstream: { type: 'http', url: 'https://my-tool.example.com/mcp' },
210
+ interceptor,
211
+ })
212
+
213
+ // Pass `proxy.mcpServer` to the Claude Agent SDK as `{ type: 'sdk', instance: proxy.mcpServer, ... }`.
214
+ ```
215
+
216
+ ### Cloudflare Agents
217
+
218
+ ```ts
219
+ import { Agent } from 'agents'
220
+ import { attributeCloudflareAgentMcp } from '@atrib/agent'
221
+
222
+ class MyAgent extends Agent {
223
+ async onRequest() {
224
+ await this.mcp.addMcpServer('search', 'https://search.example.com/mcp')
225
+ attributeCloudflareAgentMcp(this, {
226
+ interceptor,
227
+ serverUrls: { search: 'https://search.example.com' },
228
+ })
229
+ // ... call MCP tools as normal
230
+ }
231
+ }
232
+ ```
233
+
234
+ ### Vercel AI SDK
235
+
236
+ ```ts
237
+ import { createMCPClient } from '@ai-sdk/mcp'
238
+ import { streamText } from 'ai'
239
+ import { attributeVercelAiSdkMcp } from '@atrib/agent'
240
+
241
+ const mcpClient = await createMCPClient({
242
+ transport: { type: 'http', url: 'https://my-tool.example.com/mcp' },
243
+ })
244
+ attributeVercelAiSdkMcp(mcpClient, {
245
+ interceptor,
246
+ serverUrl: 'https://my-tool.example.com',
247
+ })
248
+
249
+ const tools = await mcpClient.tools()
250
+ const result = await streamText({ model: 'openai/gpt-5.4', tools, prompt: '...' })
251
+ ```
252
+
253
+ ### LangChain JS
254
+
255
+ ```ts
256
+ import { MultiServerMCPClient } from '@langchain/mcp-adapters'
257
+ import { attributeLangchainMcp } from '@atrib/agent'
258
+
259
+ const multi = new MultiServerMCPClient({
260
+ mcpServers: { search: { transport: 'http', url: 'https://search.example.com/mcp' } },
261
+ })
262
+ await multi.initializeConnections()
263
+ await attributeLangchainMcp(multi, {
264
+ interceptor,
265
+ serverUrls: { search: 'https://search.example.com' },
266
+ })
267
+
268
+ const tools = await multi.getTools()
269
+ // ... pass `tools` to your LangChain agent as normal
270
+ ```
271
+
272
+ **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.
273
+
274
+ ---
275
+
276
+ ## What you get
277
+
278
+ Once the adapter is wired in, every successful `tools/call` from your agent:
279
+
280
+ 1. **Carries W3C trace context** (`traceparent`, `tracestate`, `baggage`) in `params._meta`, so downstream servers can correlate calls with your OTel traces.
281
+ 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](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#152-http-transport-tracestate)).
282
+ 3. **Emits a signed attribution record** to the submission queue asynchronously, zero blocking on the hot path ([§5.3.5](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#535-log-submission)).
283
+ 4. **Updates session state** with the response's own `_meta.atrib` token, so the next call chains correctly from the current response.
284
+ 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.
285
+ 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](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#58-degradation-contract).
286
+
287
+ ---
288
+
289
+ ## Runnable examples
290
+
291
+ - [`claude-agent-sdk/`](https://github.com/creatornader/atrib/tree/main/packages/integration/examples/claude-agent-sdk). Case A (in-process tools) and Case B (proxy) side-by-side
292
+ - [`cloudflare-agents/`](https://github.com/creatornader/atrib/tree/main/packages/integration/examples/cloudflare-agents); `McpAgent` server-side and `Agent` client-side surfaces
293
+ - [`vercel-ai-sdk/`](https://github.com/creatornader/atrib/tree/main/packages/integration/examples/vercel-ai-sdk); `createMCPClient` with AI Gateway model routing
294
+ - [`langchain-js/`](https://github.com/creatornader/atrib/tree/main/packages/integration/examples/langchain-js); `MultiServerMCPClient` and the low-level `loadMcpTools` path
295
+
296
+ Each example directory contains a `README.md` with framework-specific rationale and a runnable `integration.ts` snippet.
297
+
298
+ ---
299
+
300
+ ## Failure model (spec §5.8)
301
+
302
+ 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:
303
+
304
+ - `onBeforeToolCall` throws → forward the request with original `_meta` (no injection)
305
+ - `onAfterToolResponse` throws → return the result to the caller anyway
306
+ - Signing throws → skip the record for that call
307
+ - Submission network error → the submission queue retries with exponential backoff; final failure drops the record silently
308
+ - `creatorKey` missing → pass-through mode with one console warning per process
309
+
310
+ **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.
311
+
312
+ ---
313
+
314
+ ## Spec references
315
+
316
+ | Spec section | What it defines |
317
+ | ------------ | ------------------------------------------------------------ |
318
+ | [§1.3](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#13-canonical-serialization) | JCS canonical serialization of records |
319
+ | [§1.4](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#14-signing-and-verification) | Ed25519 signing and verification |
320
+ | [§1.5](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#15-context-propagation) | Context propagation via `params._meta` and W3C trace context |
321
+ | [§1.7](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#17-transaction-event-hooks) | Transaction event hooks for all 6 payment protocols |
322
+ | [§2](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#2-merkle-log-protocol) | Merkle log protocol (Tessera-backed, tlog-tiles spec) |
323
+ | [§3](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#3-graph-query-interface) | Graph query interface (fact layer only) |
324
+ | [§4](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#4-attribution-policy-format) | Policy format (merchant-side value distribution) |
325
+ | [§5.3](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#53-atribmcp-mcp-server-middleware) | Agent-side middleware behavior |
326
+ | [§5.4](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#54-atribagent-agent-middleware) | Path 1 / Path 2 transaction detection |
327
+ | [§5.8](https://github.com/creatornader/atrib/blob/main/atrib-spec.md#58-degradation-contract) | Degradation contract; silent failure never breaks the host |
328
+
329
+ The full protocol spec is at [`atrib-spec.md`](https://github.com/creatornader/atrib/blob/main/atrib-spec.md).
330
+
331
+ ---
332
+
333
+ > **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`](https://atrib.dev) for the protocol overview.
@@ -0,0 +1,46 @@
1
+ import type { ToolCallInterceptor } from '../middleware.js';
2
+ /**
3
+ * Minimal structural type for a Cloudflare `Agent` we can attribute. Mirrors
4
+ * the public surface of `agents`'s `Agent` class without importing from
5
+ * `agents` (we don't want a hard dependency on the Cloudflare package).
6
+ *
7
+ * `client` is typed as `unknown` here rather than `MinimalMcpClient` so the
8
+ * real Cloudflare `MCPClientConnection.client: Client` from
9
+ * `@modelcontextprotocol/sdk` is structurally assignable without forcing
10
+ * users to cast at the call site. The helper performs a runtime check on
11
+ * each connection's `client` shape before wrapping.
12
+ */
13
+ export interface CloudflareAgentLike {
14
+ mcp: {
15
+ mcpConnections: Record<string, {
16
+ client: unknown;
17
+ url?: URL | string;
18
+ }>;
19
+ };
20
+ }
21
+ /** Options for `attributeCloudflareAgentMcp`. */
22
+ export interface AttributeCloudflareAgentMcpOptions {
23
+ /** The atrib interceptor that should observe tool calls on this agent. */
24
+ interceptor: ToolCallInterceptor;
25
+ /**
26
+ * Optional override map of server name → canonical serverUrl. If a server
27
+ * name appears here, the helper passes that URL as the `serverUrl` option
28
+ * to `wrapMcpClient`. If a server name is missing from this map, the helper
29
+ * derives serverUrl from the connection's own `url.origin`.
30
+ *
31
+ * Override when the upstream URL the agent connects to is not the canonical
32
+ * URL you want to record in attribution records (e.g. you're hitting a
33
+ * reverse proxy or staging endpoint but want production identity).
34
+ */
35
+ serverUrls?: Record<string, string>;
36
+ }
37
+ /**
38
+ * Wrap every currently-connected MCP client on a Cloudflare Agent with atrib
39
+ * attribution. Returns the number of connections wrapped (excluding ones that
40
+ * were already wrapped). Idempotent. safe to call multiple times.
41
+ *
42
+ * Call this in `onStart()` after your `addMcpServer()` calls. If you add more
43
+ * MCP servers later (in a message handler, after OAuth, etc.), call again.
44
+ */
45
+ export declare function attributeCloudflareAgentMcp(agent: CloudflareAgentLike, options: AttributeCloudflareAgentMcpOptions): number;
46
+ //# sourceMappingURL=cloudflare-agent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudflare-agent.d.ts","sourceRoot":"","sources":["../../src/adapters/cloudflare-agent.ts"],"names":[],"mappings":"AA4DA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AAkB3D;;;;;;;;;;GAUG;AACH,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE;QACH,cAAc,EAAE,MAAM,CACpB,MAAM,EACN;YACE,MAAM,EAAE,OAAO,CAAA;YACf,GAAG,CAAC,EAAE,GAAG,GAAG,MAAM,CAAA;SACnB,CACF,CAAA;KACF,CAAA;CACF;AAED,iDAAiD;AACjD,MAAM,WAAW,kCAAkC;IACjD,0EAA0E;IAC1E,WAAW,EAAE,mBAAmB,CAAA;IAEhC;;;;;;;;;OASG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACpC;AAED;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,mBAAmB,EAC1B,OAAO,EAAE,kCAAkC,GAC1C,MAAM,CA4DR"}