@clawpify/skills 1.0.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 +73 -0
- package/clawpify/SKILL.md +134 -0
- package/clawpify/references/blogs.md +385 -0
- package/clawpify/references/bulk-operations.md +386 -0
- package/clawpify/references/collections.md +71 -0
- package/clawpify/references/customers.md +141 -0
- package/clawpify/references/discounts.md +431 -0
- package/clawpify/references/draft-orders.md +495 -0
- package/clawpify/references/files.md +355 -0
- package/clawpify/references/fulfillments.md +437 -0
- package/clawpify/references/gift-cards.md +453 -0
- package/clawpify/references/inventory.md +107 -0
- package/clawpify/references/locations.md +349 -0
- package/clawpify/references/marketing.md +352 -0
- package/clawpify/references/markets.md +346 -0
- package/clawpify/references/menus.md +313 -0
- package/clawpify/references/metafields.md +461 -0
- package/clawpify/references/orders.md +164 -0
- package/clawpify/references/pages.md +308 -0
- package/clawpify/references/products.md +277 -0
- package/clawpify/references/refunds.md +401 -0
- package/clawpify/references/segments.md +319 -0
- package/clawpify/references/shipping.md +406 -0
- package/clawpify/references/shop.md +307 -0
- package/clawpify/references/subscriptions.md +429 -0
- package/clawpify/references/translations.md +270 -0
- package/clawpify/references/webhooks.md +400 -0
- package/dist/agent.d.ts +18 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +100 -0
- package/dist/auth.d.ts +34 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +58 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/mcp-server.d.ts +3 -0
- package/dist/mcp-server.d.ts.map +1 -0
- package/dist/mcp-server.js +236 -0
- package/dist/shopify.d.ts +29 -0
- package/dist/shopify.d.ts.map +1 -0
- package/dist/shopify.js +41 -0
- package/dist/skills.d.ts +8 -0
- package/dist/skills.d.ts.map +1 -0
- package/dist/skills.js +36 -0
- package/package.json +100 -0
- package/src/agent.ts +133 -0
- package/src/auth.ts +109 -0
- package/src/index.ts +55 -0
- package/src/mcp-server.ts +190 -0
- package/src/shopify.ts +63 -0
- package/src/skills.ts +42 -0
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
# Shopify Webhooks
|
|
2
|
+
|
|
3
|
+
Subscribe to event notifications via the GraphQL Admin API.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Webhooks push real-time notifications to your app when events occur in a Shopify store, eliminating the need for polling.
|
|
8
|
+
|
|
9
|
+
## List Webhook Subscriptions
|
|
10
|
+
|
|
11
|
+
```graphql
|
|
12
|
+
query ListWebhooks($first: Int!) {
|
|
13
|
+
webhookSubscriptions(first: $first) {
|
|
14
|
+
nodes {
|
|
15
|
+
id
|
|
16
|
+
topic
|
|
17
|
+
endpoint {
|
|
18
|
+
... on WebhookHttpEndpoint {
|
|
19
|
+
callbackUrl
|
|
20
|
+
}
|
|
21
|
+
... on WebhookPubSubEndpoint {
|
|
22
|
+
pubSubProject
|
|
23
|
+
pubSubTopic
|
|
24
|
+
}
|
|
25
|
+
... on WebhookEventBridgeEndpoint {
|
|
26
|
+
arn
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
format
|
|
30
|
+
createdAt
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
Variables: `{ "first": 50 }`
|
|
36
|
+
|
|
37
|
+
## Get Webhook Subscription
|
|
38
|
+
|
|
39
|
+
```graphql
|
|
40
|
+
query GetWebhook($id: ID!) {
|
|
41
|
+
webhookSubscription(id: $id) {
|
|
42
|
+
id
|
|
43
|
+
topic
|
|
44
|
+
endpoint {
|
|
45
|
+
... on WebhookHttpEndpoint {
|
|
46
|
+
callbackUrl
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
format
|
|
50
|
+
includeFields
|
|
51
|
+
metafieldNamespaces
|
|
52
|
+
filter
|
|
53
|
+
createdAt
|
|
54
|
+
updatedAt
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
Variables: `{ "id": "gid://shopify/WebhookSubscription/123" }`
|
|
59
|
+
|
|
60
|
+
## Get Webhooks Count
|
|
61
|
+
|
|
62
|
+
```graphql
|
|
63
|
+
query GetWebhooksCount {
|
|
64
|
+
webhookSubscriptionsCount {
|
|
65
|
+
count
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Create HTTP Webhook
|
|
71
|
+
|
|
72
|
+
```graphql
|
|
73
|
+
mutation CreateWebhook($topic: WebhookSubscriptionTopic!, $webhookSubscription: WebhookSubscriptionInput!) {
|
|
74
|
+
webhookSubscriptionCreate(topic: $topic, webhookSubscription: $webhookSubscription) {
|
|
75
|
+
webhookSubscription {
|
|
76
|
+
id
|
|
77
|
+
topic
|
|
78
|
+
endpoint {
|
|
79
|
+
... on WebhookHttpEndpoint {
|
|
80
|
+
callbackUrl
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
userErrors {
|
|
85
|
+
field
|
|
86
|
+
message
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
Variables:
|
|
92
|
+
```json
|
|
93
|
+
{
|
|
94
|
+
"topic": "ORDERS_CREATE",
|
|
95
|
+
"webhookSubscription": {
|
|
96
|
+
"callbackUrl": "https://myapp.example.com/webhooks/orders",
|
|
97
|
+
"format": "JSON"
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Create Webhook with Filters
|
|
103
|
+
|
|
104
|
+
```graphql
|
|
105
|
+
mutation CreateFilteredWebhook($topic: WebhookSubscriptionTopic!, $webhookSubscription: WebhookSubscriptionInput!) {
|
|
106
|
+
webhookSubscriptionCreate(topic: $topic, webhookSubscription: $webhookSubscription) {
|
|
107
|
+
webhookSubscription {
|
|
108
|
+
id
|
|
109
|
+
topic
|
|
110
|
+
filter
|
|
111
|
+
}
|
|
112
|
+
userErrors {
|
|
113
|
+
field
|
|
114
|
+
message
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
Variables:
|
|
120
|
+
```json
|
|
121
|
+
{
|
|
122
|
+
"topic": "ORDERS_CREATE",
|
|
123
|
+
"webhookSubscription": {
|
|
124
|
+
"callbackUrl": "https://myapp.example.com/webhooks/orders",
|
|
125
|
+
"format": "JSON",
|
|
126
|
+
"filter": "total_price:>=100.00"
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Create Webhook with Field Selection
|
|
132
|
+
|
|
133
|
+
```graphql
|
|
134
|
+
mutation CreateWebhookWithFields($topic: WebhookSubscriptionTopic!, $webhookSubscription: WebhookSubscriptionInput!) {
|
|
135
|
+
webhookSubscriptionCreate(topic: $topic, webhookSubscription: $webhookSubscription) {
|
|
136
|
+
webhookSubscription {
|
|
137
|
+
id
|
|
138
|
+
includeFields
|
|
139
|
+
}
|
|
140
|
+
userErrors {
|
|
141
|
+
field
|
|
142
|
+
message
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
Variables:
|
|
148
|
+
```json
|
|
149
|
+
{
|
|
150
|
+
"topic": "PRODUCTS_UPDATE",
|
|
151
|
+
"webhookSubscription": {
|
|
152
|
+
"callbackUrl": "https://myapp.example.com/webhooks/products",
|
|
153
|
+
"format": "JSON",
|
|
154
|
+
"includeFields": ["id", "title", "variants"]
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Create Webhook with Metafields
|
|
160
|
+
|
|
161
|
+
```graphql
|
|
162
|
+
mutation CreateWebhookWithMetafields($topic: WebhookSubscriptionTopic!, $webhookSubscription: WebhookSubscriptionInput!) {
|
|
163
|
+
webhookSubscriptionCreate(topic: $topic, webhookSubscription: $webhookSubscription) {
|
|
164
|
+
webhookSubscription {
|
|
165
|
+
id
|
|
166
|
+
metafieldNamespaces
|
|
167
|
+
}
|
|
168
|
+
userErrors {
|
|
169
|
+
field
|
|
170
|
+
message
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
Variables:
|
|
176
|
+
```json
|
|
177
|
+
{
|
|
178
|
+
"topic": "PRODUCTS_UPDATE",
|
|
179
|
+
"webhookSubscription": {
|
|
180
|
+
"callbackUrl": "https://myapp.example.com/webhooks/products",
|
|
181
|
+
"format": "JSON",
|
|
182
|
+
"metafieldNamespaces": ["custom", "my_app"]
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Create Google Pub/Sub Webhook
|
|
188
|
+
|
|
189
|
+
```graphql
|
|
190
|
+
mutation CreatePubSubWebhook($topic: WebhookSubscriptionTopic!, $webhookSubscription: WebhookSubscriptionInput!) {
|
|
191
|
+
webhookSubscriptionCreate(topic: $topic, webhookSubscription: $webhookSubscription) {
|
|
192
|
+
webhookSubscription {
|
|
193
|
+
id
|
|
194
|
+
endpoint {
|
|
195
|
+
... on WebhookPubSubEndpoint {
|
|
196
|
+
pubSubProject
|
|
197
|
+
pubSubTopic
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
userErrors {
|
|
202
|
+
field
|
|
203
|
+
message
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
Variables:
|
|
209
|
+
```json
|
|
210
|
+
{
|
|
211
|
+
"topic": "ORDERS_CREATE",
|
|
212
|
+
"webhookSubscription": {
|
|
213
|
+
"pubSubProject": "my-gcp-project",
|
|
214
|
+
"pubSubTopic": "shopify-orders",
|
|
215
|
+
"format": "JSON"
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## Create AWS EventBridge Webhook
|
|
221
|
+
|
|
222
|
+
```graphql
|
|
223
|
+
mutation CreateEventBridgeWebhook($topic: WebhookSubscriptionTopic!, $webhookSubscription: WebhookSubscriptionInput!) {
|
|
224
|
+
webhookSubscriptionCreate(topic: $topic, webhookSubscription: $webhookSubscription) {
|
|
225
|
+
webhookSubscription {
|
|
226
|
+
id
|
|
227
|
+
endpoint {
|
|
228
|
+
... on WebhookEventBridgeEndpoint {
|
|
229
|
+
arn
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
userErrors {
|
|
234
|
+
field
|
|
235
|
+
message
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
Variables:
|
|
241
|
+
```json
|
|
242
|
+
{
|
|
243
|
+
"topic": "ORDERS_CREATE",
|
|
244
|
+
"webhookSubscription": {
|
|
245
|
+
"arn": "arn:aws:events:us-east-1:123456789:event-source/aws.partner/shopify.com/12345/my-source",
|
|
246
|
+
"format": "JSON"
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
## Update Webhook
|
|
252
|
+
|
|
253
|
+
```graphql
|
|
254
|
+
mutation UpdateWebhook($id: ID!, $webhookSubscription: WebhookSubscriptionInput!) {
|
|
255
|
+
webhookSubscriptionUpdate(id: $id, webhookSubscription: $webhookSubscription) {
|
|
256
|
+
webhookSubscription {
|
|
257
|
+
id
|
|
258
|
+
endpoint {
|
|
259
|
+
... on WebhookHttpEndpoint {
|
|
260
|
+
callbackUrl
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
userErrors {
|
|
265
|
+
field
|
|
266
|
+
message
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
```
|
|
271
|
+
Variables:
|
|
272
|
+
```json
|
|
273
|
+
{
|
|
274
|
+
"id": "gid://shopify/WebhookSubscription/123",
|
|
275
|
+
"webhookSubscription": {
|
|
276
|
+
"callbackUrl": "https://myapp.example.com/webhooks/orders/v2"
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
## Delete Webhook
|
|
282
|
+
|
|
283
|
+
> REQUIRES PERMISSION: Deleting a webhook subscription permanently stops event notifications and may break integrations or automated workflows. Always ask the user for explicit confirmation, show the webhook topic and endpoint, and wait for approval before executing this operation.
|
|
284
|
+
|
|
285
|
+
```graphql
|
|
286
|
+
mutation DeleteWebhook($id: ID!) {
|
|
287
|
+
webhookSubscriptionDelete(id: $id) {
|
|
288
|
+
deletedWebhookSubscriptionId
|
|
289
|
+
userErrors {
|
|
290
|
+
field
|
|
291
|
+
message
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
## Common Webhook Topics
|
|
298
|
+
|
|
299
|
+
### Orders
|
|
300
|
+
| Topic | Event |
|
|
301
|
+
|-------|-------|
|
|
302
|
+
| `ORDERS_CREATE` | New order placed |
|
|
303
|
+
| `ORDERS_UPDATED` | Order modified |
|
|
304
|
+
| `ORDERS_CANCELLED` | Order cancelled |
|
|
305
|
+
| `ORDERS_FULFILLED` | Order fulfilled |
|
|
306
|
+
| `ORDERS_PAID` | Order paid |
|
|
307
|
+
|
|
308
|
+
### Products
|
|
309
|
+
| Topic | Event |
|
|
310
|
+
|-------|-------|
|
|
311
|
+
| `PRODUCTS_CREATE` | Product created |
|
|
312
|
+
| `PRODUCTS_UPDATE` | Product updated |
|
|
313
|
+
| `PRODUCTS_DELETE` | Product deleted |
|
|
314
|
+
|
|
315
|
+
### Customers
|
|
316
|
+
| Topic | Event |
|
|
317
|
+
|-------|-------|
|
|
318
|
+
| `CUSTOMERS_CREATE` | Customer created |
|
|
319
|
+
| `CUSTOMERS_UPDATE` | Customer updated |
|
|
320
|
+
| `CUSTOMERS_DELETE` | Customer deleted |
|
|
321
|
+
|
|
322
|
+
### Inventory
|
|
323
|
+
| Topic | Event |
|
|
324
|
+
|-------|-------|
|
|
325
|
+
| `INVENTORY_LEVELS_UPDATE` | Inventory changed |
|
|
326
|
+
|
|
327
|
+
### Fulfillment
|
|
328
|
+
| Topic | Event |
|
|
329
|
+
|-------|-------|
|
|
330
|
+
| `FULFILLMENTS_CREATE` | Fulfillment created |
|
|
331
|
+
| `FULFILLMENTS_UPDATE` | Fulfillment updated |
|
|
332
|
+
|
|
333
|
+
### Refunds
|
|
334
|
+
| Topic | Event |
|
|
335
|
+
|-------|-------|
|
|
336
|
+
| `REFUNDS_CREATE` | Refund processed |
|
|
337
|
+
|
|
338
|
+
### App
|
|
339
|
+
| Topic | Event |
|
|
340
|
+
|-------|-------|
|
|
341
|
+
| `APP_UNINSTALLED` | App uninstalled |
|
|
342
|
+
| `APP_SUBSCRIPTIONS_UPDATE` | Subscription changed |
|
|
343
|
+
|
|
344
|
+
## Webhook Formats
|
|
345
|
+
|
|
346
|
+
| Format | Description |
|
|
347
|
+
|--------|-------------|
|
|
348
|
+
| `JSON` | JSON payload |
|
|
349
|
+
| `XML` | XML payload |
|
|
350
|
+
|
|
351
|
+
## Filter Syntax Examples
|
|
352
|
+
|
|
353
|
+
```
|
|
354
|
+
# Orders over $100
|
|
355
|
+
total_price:>=100.00
|
|
356
|
+
|
|
357
|
+
# Specific customer
|
|
358
|
+
customer_id:123456
|
|
359
|
+
|
|
360
|
+
# Products with tag
|
|
361
|
+
tags:sale
|
|
362
|
+
|
|
363
|
+
# Combined filters
|
|
364
|
+
total_price:>=50.00 AND financial_status:paid
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
## API Scopes Required
|
|
368
|
+
|
|
369
|
+
Different topics require different scopes:
|
|
370
|
+
|
|
371
|
+
| Topic | Required Scope |
|
|
372
|
+
|-------|----------------|
|
|
373
|
+
| `ORDERS_*` | `read_orders` |
|
|
374
|
+
| `PRODUCTS_*` | `read_products` |
|
|
375
|
+
| `CUSTOMERS_*` | `read_customers` |
|
|
376
|
+
| `INVENTORY_*` | `read_inventory` |
|
|
377
|
+
|
|
378
|
+
## Notes
|
|
379
|
+
|
|
380
|
+
- App-specific webhooks in `shopify.app.toml` are preferred for most apps
|
|
381
|
+
- API-created webhooks are shop-scoped, not app-scoped
|
|
382
|
+
- Webhooks retry failed deliveries with exponential backoff
|
|
383
|
+
- Verify webhook signatures for security
|
|
384
|
+
- Maximum 3 attempts before webhook is marked failed
|
|
385
|
+
- Webhook API version is set at app level, not per subscription
|
|
386
|
+
|
|
387
|
+
## Dangerous Operations in This Skill
|
|
388
|
+
|
|
389
|
+
The following operations require explicit user permission before execution:
|
|
390
|
+
|
|
391
|
+
| Operation | Impact | Reversible |
|
|
392
|
+
|-----------|--------|------------|
|
|
393
|
+
| `webhookSubscriptionDelete` | Permanently stops event notifications, may break integrations | Yes (can recreate, but data in transit is lost) |
|
|
394
|
+
|
|
395
|
+
Permission Protocol: Before executing `webhookSubscriptionDelete`:
|
|
396
|
+
1. Show the webhook ID and subscription topic
|
|
397
|
+
2. Display the endpoint/callback URL or destination
|
|
398
|
+
3. Explain that event notifications will stop immediately
|
|
399
|
+
4. Warn about potential impact on integrations and automation
|
|
400
|
+
5. Wait for explicit user confirmation with "yes", "confirm", or "proceed"
|
package/dist/agent.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import Anthropic from "@anthropic-ai/sdk";
|
|
2
|
+
import { ShopifyClient } from "./shopify";
|
|
3
|
+
export declare class ShopifyAgent {
|
|
4
|
+
private anthropic;
|
|
5
|
+
private shopify;
|
|
6
|
+
private skillContent;
|
|
7
|
+
private model;
|
|
8
|
+
constructor(config: {
|
|
9
|
+
shopify: ShopifyClient;
|
|
10
|
+
skillContent: string;
|
|
11
|
+
model?: string;
|
|
12
|
+
});
|
|
13
|
+
chat(userMessage: string, conversationHistory?: Anthropic.MessageParam[]): Promise<{
|
|
14
|
+
response: string;
|
|
15
|
+
history: Anthropic.MessageParam[];
|
|
16
|
+
}>;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=agent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAsB1C,qBAAa,YAAY;IACvB,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,KAAK,CAAS;gBAEV,MAAM,EAAE;QAClB,OAAO,EAAE,aAAa,CAAC;QACvB,YAAY,EAAE,MAAM,CAAC;QACrB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB;IAOK,IAAI,CACR,WAAW,EAAE,MAAM,EACnB,mBAAmB,GAAE,SAAS,CAAC,YAAY,EAAO,GACjD,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,SAAS,CAAC,YAAY,EAAE,CAAA;KAAE,CAAC;CAyFpE"}
|
package/dist/agent.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
// src/agent.ts
|
|
2
|
+
import Anthropic from "@anthropic-ai/sdk";
|
|
3
|
+
var SHOPIFY_GRAPHQL_TOOL = {
|
|
4
|
+
name: "shopify_graphql",
|
|
5
|
+
description: "Execute a GraphQL query against the Shopify Admin API. Use this to interact with products, orders, customers, inventory, and other Shopify resources.",
|
|
6
|
+
input_schema: {
|
|
7
|
+
type: "object",
|
|
8
|
+
properties: {
|
|
9
|
+
query: {
|
|
10
|
+
type: "string",
|
|
11
|
+
description: "The GraphQL query or mutation to execute"
|
|
12
|
+
},
|
|
13
|
+
variables: {
|
|
14
|
+
type: "object",
|
|
15
|
+
description: "Optional variables for the GraphQL query"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
required: ["query"]
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
class ShopifyAgent {
|
|
23
|
+
anthropic;
|
|
24
|
+
shopify;
|
|
25
|
+
skillContent;
|
|
26
|
+
model;
|
|
27
|
+
constructor(config) {
|
|
28
|
+
this.anthropic = new Anthropic;
|
|
29
|
+
this.shopify = config.shopify;
|
|
30
|
+
this.skillContent = config.skillContent;
|
|
31
|
+
this.model = config.model ?? "claude-sonnet-4-5";
|
|
32
|
+
}
|
|
33
|
+
async chat(userMessage, conversationHistory = []) {
|
|
34
|
+
const systemPrompt = `You are a helpful Shopify assistant that can query and manage a Shopify store using the GraphQL Admin API.
|
|
35
|
+
|
|
36
|
+
${this.skillContent}
|
|
37
|
+
|
|
38
|
+
When the user asks about products, orders, customers, or any Shopify data, use the shopify_graphql tool to fetch or modify the data. Always explain what you're doing and present results clearly.`;
|
|
39
|
+
const messages = [
|
|
40
|
+
...conversationHistory,
|
|
41
|
+
{ role: "user", content: userMessage }
|
|
42
|
+
];
|
|
43
|
+
let response = await this.anthropic.messages.create({
|
|
44
|
+
model: this.model,
|
|
45
|
+
max_tokens: 4096,
|
|
46
|
+
system: systemPrompt,
|
|
47
|
+
tools: [SHOPIFY_GRAPHQL_TOOL],
|
|
48
|
+
messages
|
|
49
|
+
});
|
|
50
|
+
const assistantMessages = [];
|
|
51
|
+
while (response.stop_reason === "tool_use") {
|
|
52
|
+
const toolUseBlocks = response.content.filter((block) => block.type === "tool_use");
|
|
53
|
+
assistantMessages.push(...response.content);
|
|
54
|
+
const toolResults = [];
|
|
55
|
+
for (const toolUse of toolUseBlocks) {
|
|
56
|
+
if (toolUse.name === "shopify_graphql") {
|
|
57
|
+
const input = toolUse.input;
|
|
58
|
+
try {
|
|
59
|
+
const result = await this.shopify.graphql(input.query, input.variables);
|
|
60
|
+
toolResults.push({
|
|
61
|
+
type: "tool_result",
|
|
62
|
+
tool_use_id: toolUse.id,
|
|
63
|
+
content: JSON.stringify(result, null, 2)
|
|
64
|
+
});
|
|
65
|
+
} catch (error) {
|
|
66
|
+
toolResults.push({
|
|
67
|
+
type: "tool_result",
|
|
68
|
+
tool_use_id: toolUse.id,
|
|
69
|
+
content: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
70
|
+
is_error: true
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
messages.push({ role: "assistant", content: assistantMessages.slice() });
|
|
76
|
+
messages.push({ role: "user", content: toolResults });
|
|
77
|
+
assistantMessages.length = 0;
|
|
78
|
+
response = await this.anthropic.messages.create({
|
|
79
|
+
model: this.model,
|
|
80
|
+
max_tokens: 4096,
|
|
81
|
+
system: systemPrompt,
|
|
82
|
+
tools: [SHOPIFY_GRAPHQL_TOOL],
|
|
83
|
+
messages
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
const textBlocks = response.content.filter((block) => block.type === "text");
|
|
87
|
+
const finalResponse = textBlocks.map((b) => b.text).join(`
|
|
88
|
+
`);
|
|
89
|
+
const updatedHistory = [
|
|
90
|
+
...messages,
|
|
91
|
+
{ role: "assistant", content: response.content }
|
|
92
|
+
];
|
|
93
|
+
return { response: finalResponse, history: updatedHistory };
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
export {
|
|
97
|
+
ShopifyAgent
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
export { ShopifyAgent };
|
package/dist/auth.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shopify OAuth Client Credentials
|
|
3
|
+
* For apps installed on stores you own (server-to-server)
|
|
4
|
+
*/
|
|
5
|
+
export interface AccessTokenResponse {
|
|
6
|
+
accessToken: string;
|
|
7
|
+
scope: string;
|
|
8
|
+
expiresIn: number;
|
|
9
|
+
}
|
|
10
|
+
export interface ClientCredentialsConfig {
|
|
11
|
+
storeUrl: string;
|
|
12
|
+
clientId: string;
|
|
13
|
+
clientSecret: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Get an access token using the Client Credentials grant.
|
|
17
|
+
* Token expires in 24 hours and must be refreshed with the same request.
|
|
18
|
+
*
|
|
19
|
+
* @see https://shopify.dev/docs/apps/build/authentication-authorization/access-tokens/client-credentials-grant
|
|
20
|
+
*/
|
|
21
|
+
export declare function getAccessToken(config: ClientCredentialsConfig): Promise<AccessTokenResponse>;
|
|
22
|
+
/**
|
|
23
|
+
* Create a Shopify client config from environment variables.
|
|
24
|
+
* Supports two authentication methods:
|
|
25
|
+
* 1. Direct access token (SHOPIFY_ACCESS_TOKEN) - uses token directly
|
|
26
|
+
* 2. Client credentials (SHOPIFY_CLIENT_ID + SHOPIFY_CLIENT_SECRET) - fetches token via OAuth
|
|
27
|
+
*/
|
|
28
|
+
export declare function createAuthenticatedConfig(): Promise<{
|
|
29
|
+
storeUrl: string;
|
|
30
|
+
accessToken: string;
|
|
31
|
+
scope?: string;
|
|
32
|
+
expiresIn?: number;
|
|
33
|
+
}>;
|
|
34
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,uBAAuB,GAC9B,OAAO,CAAC,mBAAmB,CAAC,CAoC9B;AAED;;;;;GAKG;AACH,wBAAsB,yBAAyB,IAAI,OAAO,CAAC;IACzD,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC,CAkCD"}
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// src/auth.ts
|
|
2
|
+
async function getAccessToken(config) {
|
|
3
|
+
const storeUrl = config.storeUrl.replace(/^https?:\/\//, "").replace(/\/$/, "");
|
|
4
|
+
const response = await fetch(`https://${storeUrl}/admin/oauth/access_token`, {
|
|
5
|
+
method: "POST",
|
|
6
|
+
headers: {
|
|
7
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
8
|
+
},
|
|
9
|
+
body: new URLSearchParams({
|
|
10
|
+
grant_type: "client_credentials",
|
|
11
|
+
client_id: config.clientId,
|
|
12
|
+
client_secret: config.clientSecret
|
|
13
|
+
})
|
|
14
|
+
});
|
|
15
|
+
if (!response.ok) {
|
|
16
|
+
const text = await response.text();
|
|
17
|
+
throw new Error(`OAuth error (${response.status}): ${text}`);
|
|
18
|
+
}
|
|
19
|
+
const data = await response.json();
|
|
20
|
+
return {
|
|
21
|
+
accessToken: data.access_token,
|
|
22
|
+
scope: data.scope,
|
|
23
|
+
expiresIn: data.expires_in
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
async function createAuthenticatedConfig() {
|
|
27
|
+
const storeUrl = process.env.SHOPIFY_STORE_URL;
|
|
28
|
+
const directToken = process.env.SHOPIFY_ACCESS_TOKEN;
|
|
29
|
+
const clientId = process.env.SHOPIFY_CLIENT_ID;
|
|
30
|
+
const clientSecret = process.env.SHOPIFY_CLIENT_SECRET;
|
|
31
|
+
if (!storeUrl) {
|
|
32
|
+
throw new Error("Missing required environment variable: SHOPIFY_STORE_URL");
|
|
33
|
+
}
|
|
34
|
+
if (directToken) {
|
|
35
|
+
return {
|
|
36
|
+
storeUrl,
|
|
37
|
+
accessToken: directToken
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
if (clientId && clientSecret) {
|
|
41
|
+
const token = await getAccessToken({ storeUrl, clientId, clientSecret });
|
|
42
|
+
return {
|
|
43
|
+
storeUrl,
|
|
44
|
+
accessToken: token.accessToken,
|
|
45
|
+
scope: token.scope,
|
|
46
|
+
expiresIn: token.expiresIn
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
throw new Error(`Missing authentication credentials. Provide either:
|
|
50
|
+
` + ` - SHOPIFY_ACCESS_TOKEN (direct token), or
|
|
51
|
+
` + " - SHOPIFY_CLIENT_ID and SHOPIFY_CLIENT_SECRET (OAuth client credentials)");
|
|
52
|
+
}
|
|
53
|
+
export {
|
|
54
|
+
getAccessToken,
|
|
55
|
+
createAuthenticatedConfig
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export { getAccessToken, createAuthenticatedConfig };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clawpify - Shopify Agent SDK
|
|
3
|
+
*
|
|
4
|
+
* Query and manage Shopify stores via GraphQL Admin API with AI agents.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { ShopifyClient } from "clawpify";
|
|
9
|
+
*
|
|
10
|
+
* const client = new ShopifyClient({
|
|
11
|
+
* storeUrl: "my-store.myshopify.com",
|
|
12
|
+
* accessToken: "shpat_xxxxx",
|
|
13
|
+
* });
|
|
14
|
+
*
|
|
15
|
+
* const { data } = await client.graphql(`{
|
|
16
|
+
* products(first: 5) {
|
|
17
|
+
* nodes { id title }
|
|
18
|
+
* }
|
|
19
|
+
* }`);
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* @example Using the AI agent (requires @anthropic-ai/sdk)
|
|
23
|
+
* ```ts
|
|
24
|
+
* import { ShopifyClient } from "clawpify";
|
|
25
|
+
* import { ShopifyAgent } from "clawpify/agent";
|
|
26
|
+
* import { loadSkills } from "clawpify/skills";
|
|
27
|
+
*
|
|
28
|
+
* const client = new ShopifyClient({ storeUrl, accessToken });
|
|
29
|
+
* const skills = await loadSkills();
|
|
30
|
+
* const agent = new ShopifyAgent({ shopify: client, skillContent: skills });
|
|
31
|
+
*
|
|
32
|
+
* const result = await agent.chat("List my products");
|
|
33
|
+
* console.log(result.response);
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export { ShopifyClient, createShopifyClient } from "./shopify";
|
|
37
|
+
export { createAuthenticatedConfig, getAccessToken, type AccessTokenResponse, type ClientCredentialsConfig, } from "./auth";
|
|
38
|
+
export { ShopifyAgent } from "./agent";
|
|
39
|
+
export { loadSkills } from "./skills";
|
|
40
|
+
export type { ShopifyClientConfig, GraphQLResponse } from "./shopify";
|
|
41
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAGH,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAG/D,OAAO,EACL,yBAAyB,EACzB,cAAc,EACd,KAAK,mBAAmB,EACxB,KAAK,uBAAuB,GAC7B,MAAM,QAAQ,CAAC;AAGhB,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAGvC,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAGtC,YAAY,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ShopifyAgent
|
|
3
|
+
} from "./agent.js";
|
|
4
|
+
import {
|
|
5
|
+
ShopifyClient,
|
|
6
|
+
createShopifyClient
|
|
7
|
+
} from "./shopify.js";
|
|
8
|
+
import {
|
|
9
|
+
createAuthenticatedConfig,
|
|
10
|
+
getAccessToken
|
|
11
|
+
} from "./auth.js";
|
|
12
|
+
import {
|
|
13
|
+
loadSkills
|
|
14
|
+
} from "./skills.js";
|
|
15
|
+
export {
|
|
16
|
+
loadSkills,
|
|
17
|
+
getAccessToken,
|
|
18
|
+
createShopifyClient,
|
|
19
|
+
createAuthenticatedConfig,
|
|
20
|
+
ShopifyClient,
|
|
21
|
+
ShopifyAgent
|
|
22
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-server.d.ts","sourceRoot":"","sources":["../src/mcp-server.ts"],"names":[],"mappings":""}
|