@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.
- package/LICENSE +190 -0
- package/README.md +333 -0
- package/dist/adapters/cloudflare-agent.d.ts +46 -0
- package/dist/adapters/cloudflare-agent.d.ts.map +1 -0
- package/dist/adapters/cloudflare-agent.js +124 -0
- package/dist/adapters/cloudflare-agent.js.map +1 -0
- package/dist/adapters/langchain-mcp.d.ts +172 -0
- package/dist/adapters/langchain-mcp.d.ts.map +1 -0
- package/dist/adapters/langchain-mcp.js +145 -0
- package/dist/adapters/langchain-mcp.js.map +1 -0
- package/dist/adapters/mcp-client.d.ts +94 -0
- package/dist/adapters/mcp-client.d.ts.map +1 -0
- package/dist/adapters/mcp-client.js +91 -0
- package/dist/adapters/mcp-client.js.map +1 -0
- package/dist/adapters/vercel-ai-sdk-mcp.d.ts +129 -0
- package/dist/adapters/vercel-ai-sdk-mcp.d.ts.map +1 -0
- package/dist/adapters/vercel-ai-sdk-mcp.js +115 -0
- package/dist/adapters/vercel-ai-sdk-mcp.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware.d.ts +53 -0
- package/dist/middleware.d.ts.map +1 -0
- package/dist/middleware.js +268 -0
- package/dist/middleware.js.map +1 -0
- package/dist/policy.d.ts +28 -0
- package/dist/policy.d.ts.map +1 -0
- package/dist/policy.js +196 -0
- package/dist/policy.js.map +1 -0
- package/dist/session.d.ts +50 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +141 -0
- package/dist/session.js.map +1 -0
- package/dist/transaction.d.ts +52 -0
- package/dist/transaction.d.ts.map +1 -0
- package/dist/transaction.js +123 -0
- package/dist/transaction.js.map +1 -0
- 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"}
|