@omnixhq/ucp-client 0.1.1
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 +21 -0
- package/README.md +193 -0
- package/dist/index.cjs +1053 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +8061 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.ts +8061 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +996 -0
- package/dist/index.js.map +1 -0
- package/package.json +92 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 OmnixHQ
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# @omnixhq/ucp-client
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@omnixhq/ucp-client)
|
|
4
|
+
[](https://github.com/OmnixHQ/ucp-client/actions/workflows/ci.yml)
|
|
5
|
+
[](./LICENSE)
|
|
6
|
+
[](https://www.typescriptlang.org/)
|
|
7
|
+
[](https://nodejs.org/)
|
|
8
|
+
|
|
9
|
+
TypeScript client that connects to any [UCP](https://ucp.dev)-compliant server, discovers what it supports, and gives your AI agent ready-to-use tools.
|
|
10
|
+
|
|
11
|
+
## Why
|
|
12
|
+
|
|
13
|
+
Every AI agent that wants to buy something from a UCP store needs to discover capabilities, construct headers, handle idempotency, parse errors, manage escalation. That's a lot of boilerplate.
|
|
14
|
+
|
|
15
|
+
`@omnixhq/ucp-client` handles all of it. You connect, get tools, give them to the LLM — and the LLM orchestrates the checkout flow on its own.
|
|
16
|
+
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install @omnixhq/ucp-client
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import Anthropic from '@anthropic-ai/sdk';
|
|
27
|
+
import { UCPClient } from '@omnixhq/ucp-client';
|
|
28
|
+
|
|
29
|
+
// Connect to any UCP server — discovers capabilities automatically
|
|
30
|
+
const client = await UCPClient.connect({
|
|
31
|
+
gatewayUrl: 'https://store.example.com',
|
|
32
|
+
agentProfileUrl: 'https://your-app.com/.well-known/ucp',
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// Get tools — only what this server supports, with schemas + executors
|
|
36
|
+
const tools = client.getAgentTools();
|
|
37
|
+
const anthropic = new Anthropic();
|
|
38
|
+
const messages: Anthropic.MessageParam[] = [
|
|
39
|
+
{ role: 'user', content: 'Buy me running shoes under $100' },
|
|
40
|
+
];
|
|
41
|
+
|
|
42
|
+
// Agent loop — Claude decides which tools to call and in what order
|
|
43
|
+
while (true) {
|
|
44
|
+
const response = await anthropic.messages.create({
|
|
45
|
+
model: 'claude-sonnet-4-20250514',
|
|
46
|
+
max_tokens: 4096,
|
|
47
|
+
tools: tools.map((t) => ({
|
|
48
|
+
name: t.name,
|
|
49
|
+
description: t.description,
|
|
50
|
+
input_schema: t.parameters,
|
|
51
|
+
})),
|
|
52
|
+
messages,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// Add Claude's response to the conversation
|
|
56
|
+
messages.push({ role: 'assistant', content: response.content });
|
|
57
|
+
|
|
58
|
+
// Find tool calls and execute them
|
|
59
|
+
const toolBlocks = response.content.filter((b) => b.type === 'tool_use');
|
|
60
|
+
|
|
61
|
+
if (toolBlocks.length === 0) break;
|
|
62
|
+
|
|
63
|
+
const toolResults: Anthropic.ToolResultBlockParam[] = [];
|
|
64
|
+
for (const block of toolBlocks) {
|
|
65
|
+
const tool = tools.find((t) => t.name === block.name);
|
|
66
|
+
if (tool) {
|
|
67
|
+
const result = await tool.execute(block.input as Record<string, unknown>);
|
|
68
|
+
toolResults.push({
|
|
69
|
+
type: 'tool_result',
|
|
70
|
+
tool_use_id: block.id,
|
|
71
|
+
content: JSON.stringify(result),
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
messages.push({ role: 'user', content: toolResults });
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
You write the loop. Claude decides the flow: search → create checkout → set shipping → complete → done.
|
|
81
|
+
|
|
82
|
+
Each tool returned by `getAgentTools()` has: `name`, `description`, `parameters` (JSON Schema), and `execute(params)` — everything an LLM needs.
|
|
83
|
+
|
|
84
|
+
## Error handling
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
import { UCPError, UCPEscalationError } from '@omnixhq/ucp-client';
|
|
88
|
+
|
|
89
|
+
try {
|
|
90
|
+
await client.checkout.complete(sessionId, payload);
|
|
91
|
+
} catch (err) {
|
|
92
|
+
if (err instanceof UCPEscalationError) {
|
|
93
|
+
// Redirect buyer to err.continue_url for merchant-hosted checkout
|
|
94
|
+
}
|
|
95
|
+
if (err instanceof UCPError) {
|
|
96
|
+
// err.code — e.g., 'PRODUCT_NOT_FOUND'
|
|
97
|
+
// err.messages[] — all messages from the server
|
|
98
|
+
// err.path — JSONPath to the field that caused the error
|
|
99
|
+
// err.type — 'error' | 'warning' | 'info'
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Capabilities
|
|
105
|
+
|
|
106
|
+
The tools you get depend on what the server declares:
|
|
107
|
+
|
|
108
|
+
| Server declares | Tools you get |
|
|
109
|
+
| --------------------------------- | -------------------------------------------------------------------------------------------- |
|
|
110
|
+
| `dev.ucp.shopping.checkout` | `create_checkout`, `get_checkout`, `update_checkout`, `complete_checkout`, `cancel_checkout` |
|
|
111
|
+
| `dev.ucp.shopping.fulfillment` | + `set_fulfillment`, `select_destination`, `select_fulfillment_option` |
|
|
112
|
+
| `dev.ucp.shopping.discount` | + `apply_discount_codes` |
|
|
113
|
+
| `dev.ucp.shopping.order` | + `get_order` |
|
|
114
|
+
| `dev.ucp.common.identity_linking` | + `get_authorization_url`, `exchange_auth_code`, `refresh_access_token`, `revoke_token` |
|
|
115
|
+
| _(always)_ | `search_products`, `get_product` |
|
|
116
|
+
|
|
117
|
+
Connect to a different server → get different tools. Your agent code stays the same.
|
|
118
|
+
|
|
119
|
+
### Checking capabilities manually
|
|
120
|
+
|
|
121
|
+
If you need more control than `getAgentTools()`:
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
const client = await UCPClient.connect(config);
|
|
125
|
+
|
|
126
|
+
client.checkout; // CheckoutCapability | null
|
|
127
|
+
client.order; // OrderCapability | null
|
|
128
|
+
client.identityLinking; // IdentityLinkingCapability | null
|
|
129
|
+
client.products; // ProductsCapability (always available)
|
|
130
|
+
|
|
131
|
+
if (client.checkout) {
|
|
132
|
+
client.checkout.extensions.fulfillment; // boolean
|
|
133
|
+
client.checkout.extensions.discount; // boolean
|
|
134
|
+
client.checkout.extensions.buyerConsent; // boolean
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
console.log(Object.keys(client.paymentHandlers));
|
|
138
|
+
// e.g., ['com.google.pay', 'dev.shopify.shop_pay']
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Other agent frameworks
|
|
142
|
+
|
|
143
|
+
The `AgentTool` format maps directly to every major framework:
|
|
144
|
+
|
|
145
|
+
**OpenAI:**
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
tools.map((t) => ({
|
|
149
|
+
type: 'function',
|
|
150
|
+
function: { name: t.name, description: t.description, parameters: t.parameters },
|
|
151
|
+
}));
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
**Vercel AI SDK:**
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
import { tool, jsonSchema } from 'ai';
|
|
158
|
+
|
|
159
|
+
Object.fromEntries(
|
|
160
|
+
tools.map((t) => [
|
|
161
|
+
t.name,
|
|
162
|
+
tool({ description: t.description, parameters: jsonSchema(t.parameters), execute: t.execute }),
|
|
163
|
+
]),
|
|
164
|
+
);
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
**MCP server:**
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
for (const t of tools) {
|
|
171
|
+
server.tool(t.name, t.description, t.parameters, async (params) => ({
|
|
172
|
+
content: [{ type: 'text', text: JSON.stringify(await t.execute(params)) }],
|
|
173
|
+
}));
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Development
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
npm install
|
|
181
|
+
npm run build # tsdown (dual ESM + CJS)
|
|
182
|
+
npm test # vitest (116 unit tests)
|
|
183
|
+
npm run typecheck # tsc --noEmit
|
|
184
|
+
npm run lint # eslint
|
|
185
|
+
npm run check:exports # attw
|
|
186
|
+
npm run check:publish # publint
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
See [CONTRIBUTING.md](./CONTRIBUTING.md) for code style and CLA.
|
|
190
|
+
|
|
191
|
+
## License
|
|
192
|
+
|
|
193
|
+
[MIT](./LICENSE)
|