@01.software/cli 0.7.1 → 0.9.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/dist/index.js +5 -9
- package/dist/index.js.map +1 -1
- package/dist/mcp/{chunk-3ZSKJM43.js → chunk-GJOQ4SE2.js} +1140 -854
- package/dist/mcp/chunk-GJOQ4SE2.js.map +1 -0
- package/dist/mcp/http.js +271 -125
- package/dist/mcp/http.js.map +1 -1
- package/dist/mcp/stdio.js +1 -1
- package/dist/mcp/vercel.js +1400 -982
- package/package.json +3 -3
- package/dist/mcp/chunk-3ZSKJM43.js.map +0 -1
package/dist/mcp/vercel.js
CHANGED
|
@@ -1,71 +1,47 @@
|
|
|
1
1
|
// src/handler.ts
|
|
2
2
|
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
3
3
|
|
|
4
|
+
// ../../packages/auth-contracts/dist/index.js
|
|
5
|
+
var MCP_RESOURCE_AUDIENCE = "https://mcp.01.software/mcp";
|
|
6
|
+
var MCP_OAUTH_ISSUER = "https://01.software";
|
|
7
|
+
var MCP_PROTECTED_RESOURCE_METADATA_PATH = "/.well-known/oauth-protected-resource/mcp";
|
|
8
|
+
var MCP_TENANT_CLAIM = "tenant_id";
|
|
9
|
+
var MCP_TENANT_ROLE_CLAIM = "tenant_role";
|
|
10
|
+
var MCP_SCOPES = {
|
|
11
|
+
read: "mcp:read",
|
|
12
|
+
write: "mcp:write"
|
|
13
|
+
};
|
|
14
|
+
var MCP_CONSOLE_SERVICE_AUDIENCE = "https://api.01.software/internal/mcp";
|
|
15
|
+
var MCP_CONSOLE_SERVICE_SCOPE = "console:mcp_proxy";
|
|
16
|
+
var MCP_SERVICE_TOKEN_LIFETIME_SECONDS = 60;
|
|
17
|
+
|
|
4
18
|
// src/server.ts
|
|
5
19
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
6
20
|
|
|
7
|
-
// src/tools/query-collection.ts
|
|
8
|
-
import { z } from "zod";
|
|
9
|
-
|
|
10
21
|
// src/lib/request-context.ts
|
|
11
22
|
import { AsyncLocalStorage } from "async_hooks";
|
|
12
23
|
var requestContext = new AsyncLocalStorage();
|
|
13
|
-
function
|
|
14
|
-
|
|
15
|
-
if (!ctx) return null;
|
|
16
|
-
return Object.fromEntries(ctx.headers.entries());
|
|
24
|
+
function tenantAuthContext() {
|
|
25
|
+
return requestContext.getStore()?.auth ?? null;
|
|
17
26
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
import { createServerClient } from "@01.software/sdk";
|
|
21
|
-
function getClient() {
|
|
22
|
-
let secretKey;
|
|
23
|
-
let publishableKey;
|
|
24
|
-
try {
|
|
25
|
-
const h = headers();
|
|
26
|
-
secretKey = h?.["x-api-key"];
|
|
27
|
-
publishableKey = h?.["x-publishable-key"] ?? h?.["x-client-key"];
|
|
28
|
-
} catch {
|
|
29
|
-
}
|
|
30
|
-
if (!secretKey) {
|
|
31
|
-
secretKey = process.env.SOFTWARE_SECRET_KEY;
|
|
32
|
-
}
|
|
33
|
-
if (!publishableKey) {
|
|
34
|
-
publishableKey = process.env.SOFTWARE_PUBLISHABLE_KEY || process.env.NEXT_PUBLIC_SOFTWARE_PUBLISHABLE_KEY;
|
|
35
|
-
}
|
|
36
|
-
if (!secretKey) {
|
|
37
|
-
throw new Error(
|
|
38
|
-
"Authentication required. Provide x-api-key header (HTTP) or SOFTWARE_SECRET_KEY env var (stdio)."
|
|
39
|
-
);
|
|
40
|
-
}
|
|
41
|
-
if (!secretKey.startsWith("sk01_") && !secretKey.startsWith("pat01_")) {
|
|
42
|
-
throw new Error("Invalid API key format. Expected sk01_ or pat01_ token.");
|
|
43
|
-
}
|
|
44
|
-
if (!publishableKey) {
|
|
45
|
-
throw new Error(
|
|
46
|
-
"publishableKey is required. Provide X-Publishable-Key header (HTTP) or SOFTWARE_PUBLISHABLE_KEY env var (stdio). It is used for rate limiting and monthly quota enforcement via the edge proxy."
|
|
47
|
-
);
|
|
48
|
-
}
|
|
49
|
-
return createServerClient({
|
|
50
|
-
publishableKey,
|
|
51
|
-
secretKey
|
|
52
|
-
});
|
|
27
|
+
function hasRequestContext() {
|
|
28
|
+
return requestContext.getStore() !== void 0;
|
|
53
29
|
}
|
|
54
30
|
|
|
55
|
-
// src/tools/query-collection.ts
|
|
56
|
-
import { COLLECTIONS } from "@01.software/sdk";
|
|
57
|
-
|
|
58
31
|
// src/lib/tool-utils.ts
|
|
59
32
|
function toolSuccess(data) {
|
|
60
33
|
return JSON.stringify({ success: true, ...data }, null, 2);
|
|
61
34
|
}
|
|
62
35
|
function toolError(error) {
|
|
63
36
|
const base = { success: false };
|
|
64
|
-
|
|
37
|
+
const isStructured = !!error && typeof error === "object" && ("code" in error || "reason" in error);
|
|
38
|
+
if (isStructured) {
|
|
65
39
|
const sdkErr = error;
|
|
66
40
|
base.error = sdkErr.message || "Unknown error";
|
|
67
41
|
if (sdkErr.status) base.status = sdkErr.status;
|
|
68
42
|
if (sdkErr.code) base.code = sdkErr.code;
|
|
43
|
+
if (sdkErr.reason) base.reason = sdkErr.reason;
|
|
44
|
+
if (sdkErr.requestId) base.requestId = sdkErr.requestId;
|
|
69
45
|
if (sdkErr.suggestion) base.suggestion = sdkErr.suggestion;
|
|
70
46
|
if (sdkErr.details?.errors) base.errors = sdkErr.details.errors;
|
|
71
47
|
} else {
|
|
@@ -115,7 +91,479 @@ function parseJsonWhere(where) {
|
|
|
115
91
|
}
|
|
116
92
|
}
|
|
117
93
|
|
|
94
|
+
// src/tool-policy.ts
|
|
95
|
+
var READ_ONLY_ANNOTATION = {
|
|
96
|
+
readOnly: true,
|
|
97
|
+
destructive: false,
|
|
98
|
+
idempotent: true,
|
|
99
|
+
openWorld: false
|
|
100
|
+
};
|
|
101
|
+
var NON_DESTRUCTIVE_MUTATION_ANNOTATION = {
|
|
102
|
+
readOnly: false,
|
|
103
|
+
destructive: false,
|
|
104
|
+
idempotent: false,
|
|
105
|
+
openWorld: false
|
|
106
|
+
};
|
|
107
|
+
var NON_DESTRUCTIVE_IDEMPOTENT_MUTATION_ANNOTATION = {
|
|
108
|
+
readOnly: false,
|
|
109
|
+
destructive: false,
|
|
110
|
+
idempotent: true,
|
|
111
|
+
openWorld: false
|
|
112
|
+
};
|
|
113
|
+
var DESTRUCTIVE_NON_IDEMPOTENT_MUTATION_ANNOTATION = {
|
|
114
|
+
readOnly: false,
|
|
115
|
+
destructive: true,
|
|
116
|
+
idempotent: false,
|
|
117
|
+
openWorld: false
|
|
118
|
+
};
|
|
119
|
+
var DESTRUCTIVE_IDEMPOTENT_MUTATION_ANNOTATION = {
|
|
120
|
+
readOnly: false,
|
|
121
|
+
destructive: true,
|
|
122
|
+
idempotent: true,
|
|
123
|
+
openWorld: false
|
|
124
|
+
};
|
|
125
|
+
var REASON_IDEMPOTENT_DESTRUCTIVE_UPDATE = "Update operations mutate persisted state but converge to the same end state under repeated identical input.";
|
|
126
|
+
var REASON_CART_EPHEMERAL = "Cart is pre-checkout ephemeral state; reversal is possible by reissuing the prior input. Console enforces tenant scope.";
|
|
127
|
+
var TOOL_POLICY_MANIFEST = {
|
|
128
|
+
// ── Read-only collection / validation (mcp:read, tenant-viewer) ──
|
|
129
|
+
"query-collection": {
|
|
130
|
+
category: "read-only-collection",
|
|
131
|
+
oauthScope: MCP_SCOPES.read,
|
|
132
|
+
consoleRole: "tenant-viewer",
|
|
133
|
+
consoleSurface: "GET /api/{collection}",
|
|
134
|
+
annotationPolicy: READ_ONLY_ANNOTATION
|
|
135
|
+
},
|
|
136
|
+
"get-collection-by-id": {
|
|
137
|
+
category: "read-only-collection",
|
|
138
|
+
oauthScope: MCP_SCOPES.read,
|
|
139
|
+
consoleRole: "tenant-viewer",
|
|
140
|
+
consoleSurface: "GET /api/{collection}/{id}",
|
|
141
|
+
annotationPolicy: READ_ONLY_ANNOTATION
|
|
142
|
+
},
|
|
143
|
+
"get-order": {
|
|
144
|
+
category: "read-only-collection",
|
|
145
|
+
oauthScope: MCP_SCOPES.read,
|
|
146
|
+
consoleRole: "tenant-viewer",
|
|
147
|
+
consoleSurface: "GET /api/orders/{id}",
|
|
148
|
+
annotationPolicy: READ_ONLY_ANNOTATION
|
|
149
|
+
},
|
|
150
|
+
"stock-check": {
|
|
151
|
+
category: "read-only-collection",
|
|
152
|
+
oauthScope: MCP_SCOPES.read,
|
|
153
|
+
consoleRole: "tenant-viewer",
|
|
154
|
+
consoleSurface: "GET /api/products/{id}/stock",
|
|
155
|
+
annotationPolicy: READ_ONLY_ANNOTATION
|
|
156
|
+
},
|
|
157
|
+
"validate-discount": {
|
|
158
|
+
category: "read-only-collection",
|
|
159
|
+
oauthScope: MCP_SCOPES.read,
|
|
160
|
+
consoleRole: "tenant-viewer",
|
|
161
|
+
consoleSurface: "POST /api/discounts/validate",
|
|
162
|
+
annotationPolicy: READ_ONLY_ANNOTATION
|
|
163
|
+
},
|
|
164
|
+
"calculate-shipping": {
|
|
165
|
+
category: "read-only-collection",
|
|
166
|
+
oauthScope: MCP_SCOPES.read,
|
|
167
|
+
consoleRole: "tenant-viewer",
|
|
168
|
+
consoleSurface: "POST /api/shipping/calculate",
|
|
169
|
+
annotationPolicy: READ_ONLY_ANNOTATION
|
|
170
|
+
},
|
|
171
|
+
"get-collection-schema": {
|
|
172
|
+
category: "read-only-collection",
|
|
173
|
+
oauthScope: MCP_SCOPES.read,
|
|
174
|
+
consoleRole: "tenant-viewer",
|
|
175
|
+
consoleSurface: "GET /api/tenants/schema/{collectionSlug}",
|
|
176
|
+
annotationPolicy: READ_ONLY_ANNOTATION
|
|
177
|
+
},
|
|
178
|
+
"list-configurable-fields": {
|
|
179
|
+
category: "read-only-collection",
|
|
180
|
+
oauthScope: MCP_SCOPES.read,
|
|
181
|
+
consoleRole: "tenant-viewer",
|
|
182
|
+
consoleSurface: "GET /api/tenants/field-config",
|
|
183
|
+
annotationPolicy: READ_ONLY_ANNOTATION
|
|
184
|
+
},
|
|
185
|
+
// ── Tenant context (mcp:read, tenant-viewer) ──
|
|
186
|
+
"get-tenant-context": {
|
|
187
|
+
category: "read-only-tenant",
|
|
188
|
+
oauthScope: MCP_SCOPES.read,
|
|
189
|
+
consoleRole: "tenant-viewer",
|
|
190
|
+
consoleSurface: "GET /api/tenants/context",
|
|
191
|
+
annotationPolicy: READ_ONLY_ANNOTATION
|
|
192
|
+
},
|
|
193
|
+
// ── Cart mutations (mcp:write, tenant-editor) ──
|
|
194
|
+
"add-cart-item": {
|
|
195
|
+
category: "mutation-cart",
|
|
196
|
+
oauthScope: MCP_SCOPES.write,
|
|
197
|
+
consoleRole: "tenant-editor",
|
|
198
|
+
consoleSurface: "POST /api/carts/{id}/items",
|
|
199
|
+
annotationPolicy: NON_DESTRUCTIVE_IDEMPOTENT_MUTATION_ANNOTATION
|
|
200
|
+
},
|
|
201
|
+
"update-cart-item": {
|
|
202
|
+
category: "mutation-cart",
|
|
203
|
+
oauthScope: MCP_SCOPES.write,
|
|
204
|
+
consoleRole: "tenant-editor",
|
|
205
|
+
consoleSurface: "PATCH /api/carts/{id}/items/{itemId}",
|
|
206
|
+
annotationPolicy: DESTRUCTIVE_IDEMPOTENT_MUTATION_ANNOTATION,
|
|
207
|
+
exemptionReason: REASON_CART_EPHEMERAL
|
|
208
|
+
},
|
|
209
|
+
"remove-cart-item": {
|
|
210
|
+
category: "mutation-cart",
|
|
211
|
+
oauthScope: MCP_SCOPES.write,
|
|
212
|
+
consoleRole: "tenant-editor",
|
|
213
|
+
consoleSurface: "DELETE /api/carts/{id}/items/{itemId}",
|
|
214
|
+
annotationPolicy: DESTRUCTIVE_IDEMPOTENT_MUTATION_ANNOTATION,
|
|
215
|
+
exemptionReason: REASON_CART_EPHEMERAL
|
|
216
|
+
},
|
|
217
|
+
"clear-cart": {
|
|
218
|
+
category: "mutation-cart",
|
|
219
|
+
oauthScope: MCP_SCOPES.write,
|
|
220
|
+
consoleRole: "tenant-editor",
|
|
221
|
+
consoleSurface: "POST /api/carts/{id}/clear",
|
|
222
|
+
annotationPolicy: DESTRUCTIVE_IDEMPOTENT_MUTATION_ANNOTATION,
|
|
223
|
+
exemptionReason: REASON_CART_EPHEMERAL
|
|
224
|
+
},
|
|
225
|
+
"apply-discount": {
|
|
226
|
+
category: "mutation-cart",
|
|
227
|
+
oauthScope: MCP_SCOPES.write,
|
|
228
|
+
consoleRole: "tenant-editor",
|
|
229
|
+
consoleSurface: "POST /api/carts/{id}/discount",
|
|
230
|
+
annotationPolicy: DESTRUCTIVE_IDEMPOTENT_MUTATION_ANNOTATION,
|
|
231
|
+
exemptionReason: REASON_CART_EPHEMERAL
|
|
232
|
+
},
|
|
233
|
+
"remove-discount": {
|
|
234
|
+
category: "mutation-cart",
|
|
235
|
+
oauthScope: MCP_SCOPES.write,
|
|
236
|
+
consoleRole: "tenant-editor",
|
|
237
|
+
consoleSurface: "DELETE /api/carts/{id}/discount",
|
|
238
|
+
annotationPolicy: DESTRUCTIVE_IDEMPOTENT_MUTATION_ANNOTATION,
|
|
239
|
+
exemptionReason: REASON_CART_EPHEMERAL
|
|
240
|
+
},
|
|
241
|
+
// ── Order mutations (mcp:write, tenant-admin) ──
|
|
242
|
+
"checkout": {
|
|
243
|
+
category: "mutation-order",
|
|
244
|
+
oauthScope: MCP_SCOPES.write,
|
|
245
|
+
consoleRole: "tenant-admin",
|
|
246
|
+
consoleSurface: "POST /api/checkout",
|
|
247
|
+
annotationPolicy: DESTRUCTIVE_NON_IDEMPOTENT_MUTATION_ANNOTATION
|
|
248
|
+
},
|
|
249
|
+
"create-order": {
|
|
250
|
+
category: "mutation-order",
|
|
251
|
+
oauthScope: MCP_SCOPES.write,
|
|
252
|
+
consoleRole: "tenant-admin",
|
|
253
|
+
consoleSurface: "POST /api/orders",
|
|
254
|
+
annotationPolicy: DESTRUCTIVE_NON_IDEMPOTENT_MUTATION_ANNOTATION
|
|
255
|
+
},
|
|
256
|
+
"update-order": {
|
|
257
|
+
category: "mutation-order",
|
|
258
|
+
oauthScope: MCP_SCOPES.write,
|
|
259
|
+
consoleRole: "tenant-admin",
|
|
260
|
+
consoleSurface: "PATCH /api/orders/{id}",
|
|
261
|
+
annotationPolicy: DESTRUCTIVE_IDEMPOTENT_MUTATION_ANNOTATION,
|
|
262
|
+
exemptionReason: REASON_IDEMPOTENT_DESTRUCTIVE_UPDATE
|
|
263
|
+
},
|
|
264
|
+
// ── Fulfillment mutations (mcp:write, tenant-admin) ──
|
|
265
|
+
"create-fulfillment": {
|
|
266
|
+
category: "mutation-fulfillment",
|
|
267
|
+
oauthScope: MCP_SCOPES.write,
|
|
268
|
+
consoleRole: "tenant-admin",
|
|
269
|
+
consoleSurface: "POST /api/orders/{id}/fulfillments",
|
|
270
|
+
annotationPolicy: NON_DESTRUCTIVE_MUTATION_ANNOTATION
|
|
271
|
+
},
|
|
272
|
+
"update-fulfillment": {
|
|
273
|
+
category: "mutation-fulfillment",
|
|
274
|
+
oauthScope: MCP_SCOPES.write,
|
|
275
|
+
consoleRole: "tenant-admin",
|
|
276
|
+
consoleSurface: "PATCH /api/fulfillments/{id}",
|
|
277
|
+
annotationPolicy: DESTRUCTIVE_IDEMPOTENT_MUTATION_ANNOTATION,
|
|
278
|
+
exemptionReason: REASON_IDEMPOTENT_DESTRUCTIVE_UPDATE
|
|
279
|
+
},
|
|
280
|
+
// ── Return mutations (mcp:write, tenant-admin) ──
|
|
281
|
+
"create-return": {
|
|
282
|
+
category: "mutation-return",
|
|
283
|
+
oauthScope: MCP_SCOPES.write,
|
|
284
|
+
consoleRole: "tenant-admin",
|
|
285
|
+
consoleSurface: "POST /api/returns",
|
|
286
|
+
annotationPolicy: DESTRUCTIVE_NON_IDEMPOTENT_MUTATION_ANNOTATION
|
|
287
|
+
},
|
|
288
|
+
"update-return": {
|
|
289
|
+
category: "mutation-return",
|
|
290
|
+
oauthScope: MCP_SCOPES.write,
|
|
291
|
+
consoleRole: "tenant-admin",
|
|
292
|
+
consoleSurface: "PATCH /api/returns/{id}",
|
|
293
|
+
annotationPolicy: DESTRUCTIVE_IDEMPOTENT_MUTATION_ANNOTATION,
|
|
294
|
+
exemptionReason: REASON_IDEMPOTENT_DESTRUCTIVE_UPDATE
|
|
295
|
+
},
|
|
296
|
+
"return-with-refund": {
|
|
297
|
+
category: "mutation-return",
|
|
298
|
+
oauthScope: MCP_SCOPES.write,
|
|
299
|
+
consoleRole: "tenant-admin",
|
|
300
|
+
consoleSurface: "POST /api/returns/with-refund",
|
|
301
|
+
annotationPolicy: DESTRUCTIVE_NON_IDEMPOTENT_MUTATION_ANNOTATION
|
|
302
|
+
},
|
|
303
|
+
// ── Transaction mutations (mcp:write, tenant-admin) ──
|
|
304
|
+
"update-transaction": {
|
|
305
|
+
category: "mutation-transaction",
|
|
306
|
+
oauthScope: MCP_SCOPES.write,
|
|
307
|
+
consoleRole: "tenant-admin",
|
|
308
|
+
consoleSurface: "PATCH /api/transactions/{id}",
|
|
309
|
+
annotationPolicy: DESTRUCTIVE_NON_IDEMPOTENT_MUTATION_ANNOTATION
|
|
310
|
+
},
|
|
311
|
+
// ── Field-config mutations (mcp:write, tenant-admin) ──
|
|
312
|
+
"update-field-config": {
|
|
313
|
+
category: "mutation-field-config",
|
|
314
|
+
oauthScope: MCP_SCOPES.write,
|
|
315
|
+
consoleRole: "tenant-admin",
|
|
316
|
+
consoleSurface: "PATCH /api/tenants/field-config",
|
|
317
|
+
annotationPolicy: NON_DESTRUCTIVE_IDEMPOTENT_MUTATION_ANNOTATION
|
|
318
|
+
},
|
|
319
|
+
// ── SDK doc tools (mcp:read, tenant-viewer, sdk-static surface) ──
|
|
320
|
+
"sdk-get-recipe": {
|
|
321
|
+
category: "sdk-doc",
|
|
322
|
+
oauthScope: MCP_SCOPES.read,
|
|
323
|
+
consoleRole: "tenant-viewer",
|
|
324
|
+
consoleSurface: "sdk-static",
|
|
325
|
+
annotationPolicy: READ_ONLY_ANNOTATION
|
|
326
|
+
},
|
|
327
|
+
"sdk-search-docs": {
|
|
328
|
+
category: "sdk-doc",
|
|
329
|
+
oauthScope: MCP_SCOPES.read,
|
|
330
|
+
consoleRole: "tenant-viewer",
|
|
331
|
+
consoleSurface: "sdk-static",
|
|
332
|
+
annotationPolicy: READ_ONLY_ANNOTATION
|
|
333
|
+
},
|
|
334
|
+
"sdk-get-auth-setup": {
|
|
335
|
+
category: "sdk-doc",
|
|
336
|
+
oauthScope: MCP_SCOPES.read,
|
|
337
|
+
consoleRole: "tenant-viewer",
|
|
338
|
+
consoleSurface: "sdk-static",
|
|
339
|
+
annotationPolicy: READ_ONLY_ANNOTATION
|
|
340
|
+
},
|
|
341
|
+
"sdk-get-collection-pattern": {
|
|
342
|
+
category: "sdk-doc",
|
|
343
|
+
oauthScope: MCP_SCOPES.read,
|
|
344
|
+
consoleRole: "tenant-viewer",
|
|
345
|
+
consoleSurface: "sdk-static",
|
|
346
|
+
annotationPolicy: READ_ONLY_ANNOTATION
|
|
347
|
+
}
|
|
348
|
+
};
|
|
349
|
+
function evaluateToolPolicy(toolName, scopes) {
|
|
350
|
+
const entry = TOOL_POLICY_MANIFEST[toolName];
|
|
351
|
+
if (!entry) {
|
|
352
|
+
return {
|
|
353
|
+
allowed: false,
|
|
354
|
+
reason: "tool_policy_missing",
|
|
355
|
+
message: `No tool-policy entry for ${toolName}`
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
if (!scopes.includes(entry.oauthScope)) {
|
|
359
|
+
return {
|
|
360
|
+
allowed: false,
|
|
361
|
+
reason: "insufficient_scope",
|
|
362
|
+
message: `Tool ${toolName} requires ${entry.oauthScope}`
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
return { allowed: true, entry };
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// src/tools/query-collection.ts
|
|
369
|
+
import { z } from "zod";
|
|
370
|
+
|
|
371
|
+
// src/lib/client.ts
|
|
372
|
+
import {
|
|
373
|
+
CollectionClient,
|
|
374
|
+
CommunityClient,
|
|
375
|
+
ModerationApi,
|
|
376
|
+
ServerCommerceClient,
|
|
377
|
+
createServerClient
|
|
378
|
+
} from "@01.software/sdk";
|
|
379
|
+
|
|
380
|
+
// src/service-auth.ts
|
|
381
|
+
import { createPrivateKey, randomUUID, sign as signBytes } from "crypto";
|
|
382
|
+
var KEYSET_ENV = "MCP_SERVICE_KEYSET";
|
|
383
|
+
function assertProductionKeysetUse(source) {
|
|
384
|
+
const vercelEnv = process.env.VERCEL_ENV;
|
|
385
|
+
if (vercelEnv && vercelEnv !== "production") {
|
|
386
|
+
throw new Error(
|
|
387
|
+
`${source} is only allowed in production Vercel deployments; non-production MCP service auth needs environment-specific issuer, audience, JWKS URI, and key material`
|
|
388
|
+
);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
function parsePrivateJwk() {
|
|
392
|
+
const keyset = signingKeyset();
|
|
393
|
+
const jwk = keyset.current;
|
|
394
|
+
const source = keyset.source;
|
|
395
|
+
if (typeof jwk.d !== "string" || jwk.d.length === 0) {
|
|
396
|
+
throw new Error(`${source} current key must be a private JWK`);
|
|
397
|
+
}
|
|
398
|
+
if (typeof jwk.kid !== "string" || jwk.kid.length === 0) {
|
|
399
|
+
throw new Error(`${source} must include kid`);
|
|
400
|
+
}
|
|
401
|
+
return jwk;
|
|
402
|
+
}
|
|
403
|
+
function signingKeyset() {
|
|
404
|
+
const raw = process.env[KEYSET_ENV];
|
|
405
|
+
const source = KEYSET_ENV;
|
|
406
|
+
if (raw) assertProductionKeysetUse(source);
|
|
407
|
+
const parsed = (() => {
|
|
408
|
+
if (!raw) return null;
|
|
409
|
+
try {
|
|
410
|
+
return JSON.parse(raw);
|
|
411
|
+
} catch {
|
|
412
|
+
throw new Error(`${KEYSET_ENV} is invalid JSON`);
|
|
413
|
+
}
|
|
414
|
+
})();
|
|
415
|
+
if (!parsed) throw new Error("MCP service JWT signing key is not configured");
|
|
416
|
+
const keys = Array.isArray(parsed.keys) ? parsed.keys : [parsed];
|
|
417
|
+
if (keys.length === 0 || keys.length > 2) {
|
|
418
|
+
throw new Error(
|
|
419
|
+
`${source} must contain one current key and at most one previous key`
|
|
420
|
+
);
|
|
421
|
+
}
|
|
422
|
+
const currentKid = parsed.current_kid;
|
|
423
|
+
if (typeof currentKid !== "string" && keys.length > 1) {
|
|
424
|
+
throw new Error(
|
|
425
|
+
`${source} must include current_kid when multiple keys are present`
|
|
426
|
+
);
|
|
427
|
+
}
|
|
428
|
+
const current = typeof currentKid === "string" ? keys.find((key) => key.kid === currentKid) : keys[0];
|
|
429
|
+
if (!current) throw new Error(`${source} current_kid is not in keys`);
|
|
430
|
+
return { current, keys, source };
|
|
431
|
+
}
|
|
432
|
+
function algForJwk(jwk) {
|
|
433
|
+
if (jwk.kty === "RSA") return "RS256";
|
|
434
|
+
if (jwk.kty === "EC" && jwk.crv === "P-256") return "ES256";
|
|
435
|
+
throw new Error("MCP service JWT signing key must be RSA or P-256 EC");
|
|
436
|
+
}
|
|
437
|
+
function toPublicJwk(jwk) {
|
|
438
|
+
const {
|
|
439
|
+
d: _d,
|
|
440
|
+
p: _p,
|
|
441
|
+
q: _q,
|
|
442
|
+
dp: _dp,
|
|
443
|
+
dq: _dq,
|
|
444
|
+
qi: _qi,
|
|
445
|
+
oth: _oth,
|
|
446
|
+
...publicJwk
|
|
447
|
+
} = jwk;
|
|
448
|
+
return {
|
|
449
|
+
...publicJwk,
|
|
450
|
+
alg: typeof publicJwk.alg === "string" ? publicJwk.alg : algForJwk(jwk),
|
|
451
|
+
use: "sig"
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
function base64urlJson(value) {
|
|
455
|
+
return Buffer.from(JSON.stringify(value)).toString("base64url");
|
|
456
|
+
}
|
|
457
|
+
function apiScopesFor(context) {
|
|
458
|
+
return context.scopes.includes("mcp:write") ? ["read", "write"] : ["read"];
|
|
459
|
+
}
|
|
460
|
+
function mcpServicePublicJwks() {
|
|
461
|
+
const keyset = signingKeyset();
|
|
462
|
+
const keys = /* @__PURE__ */ new Map();
|
|
463
|
+
for (const jwk of keyset.keys.map(toPublicJwk)) {
|
|
464
|
+
if (typeof jwk.kid === "string" && jwk.kid.length > 0) {
|
|
465
|
+
keys.set(jwk.kid, jwk);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
return { keys: [...keys.values()] };
|
|
469
|
+
}
|
|
470
|
+
function signMcpServiceToken(context) {
|
|
471
|
+
if (!context.principalId) {
|
|
472
|
+
throw new Error("MCP OAuth principal is required for Console service auth");
|
|
473
|
+
}
|
|
474
|
+
const jwk = parsePrivateJwk();
|
|
475
|
+
const alg = algForJwk(jwk);
|
|
476
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
477
|
+
const payload = {
|
|
478
|
+
iss: MCP_OAUTH_ISSUER,
|
|
479
|
+
aud: MCP_CONSOLE_SERVICE_AUDIENCE,
|
|
480
|
+
iat: now,
|
|
481
|
+
nbf: now,
|
|
482
|
+
exp: now + MCP_SERVICE_TOKEN_LIFETIME_SECONDS,
|
|
483
|
+
jti: randomUUID(),
|
|
484
|
+
sub: context.principalId,
|
|
485
|
+
act: {
|
|
486
|
+
sub: context.principalId,
|
|
487
|
+
tenant_id: context.tenantId
|
|
488
|
+
},
|
|
489
|
+
[MCP_TENANT_CLAIM]: context.tenantId,
|
|
490
|
+
[MCP_TENANT_ROLE_CLAIM]: context.tenantRole,
|
|
491
|
+
scope: MCP_CONSOLE_SERVICE_SCOPE,
|
|
492
|
+
api_scopes: apiScopesFor(context),
|
|
493
|
+
mcp_scopes: context.scopes
|
|
494
|
+
};
|
|
495
|
+
const header = { alg, kid: jwk.kid, typ: "JWT" };
|
|
496
|
+
const encodedHeader = base64urlJson(header);
|
|
497
|
+
const encodedPayload = base64urlJson(payload);
|
|
498
|
+
const signingInput = `${encodedHeader}.${encodedPayload}`;
|
|
499
|
+
const key = createPrivateKey({ key: jwk, format: "jwk" });
|
|
500
|
+
const signature = alg === "RS256" ? signBytes("RSA-SHA256", Buffer.from(signingInput), key) : signBytes("SHA256", Buffer.from(signingInput), {
|
|
501
|
+
key,
|
|
502
|
+
dsaEncoding: "ieee-p1363"
|
|
503
|
+
});
|
|
504
|
+
return `${signingInput}.${signature.toString("base64url")}`;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
// src/lib/client.ts
|
|
508
|
+
var MISSING_HTTP_AUTH_CONTEXT_ERROR = "MCP HTTP requests require a validated OAuth tenant context before tool execution.";
|
|
509
|
+
function getClient() {
|
|
510
|
+
const oauthContext = tenantAuthContext();
|
|
511
|
+
if (oauthContext) {
|
|
512
|
+
const serviceToken = signMcpServiceToken(oauthContext);
|
|
513
|
+
const client = {
|
|
514
|
+
lastRequestId: null,
|
|
515
|
+
commerce: void 0,
|
|
516
|
+
collections: void 0,
|
|
517
|
+
community: void 0
|
|
518
|
+
};
|
|
519
|
+
const onRequestId = (id) => {
|
|
520
|
+
client.lastRequestId = id;
|
|
521
|
+
};
|
|
522
|
+
client.commerce = new ServerCommerceClient({
|
|
523
|
+
secretKey: serviceToken,
|
|
524
|
+
onRequestId
|
|
525
|
+
});
|
|
526
|
+
client.collections = new CollectionClient(
|
|
527
|
+
"",
|
|
528
|
+
serviceToken,
|
|
529
|
+
void 0,
|
|
530
|
+
void 0,
|
|
531
|
+
onRequestId
|
|
532
|
+
);
|
|
533
|
+
const community = new CommunityClient({ secretKey: serviceToken });
|
|
534
|
+
const moderation = new ModerationApi({ secretKey: serviceToken, onRequestId });
|
|
535
|
+
client.community = Object.assign(community, {
|
|
536
|
+
moderation: {
|
|
537
|
+
banCustomer: moderation.banCustomer.bind(moderation),
|
|
538
|
+
unbanCustomer: moderation.unbanCustomer.bind(moderation)
|
|
539
|
+
}
|
|
540
|
+
});
|
|
541
|
+
return client;
|
|
542
|
+
}
|
|
543
|
+
if (hasRequestContext()) throw new Error(MISSING_HTTP_AUTH_CONTEXT_ERROR);
|
|
544
|
+
const secretKey = process.env.SOFTWARE_SECRET_KEY;
|
|
545
|
+
const publishableKey = process.env.SOFTWARE_PUBLISHABLE_KEY || process.env.NEXT_PUBLIC_SOFTWARE_PUBLISHABLE_KEY;
|
|
546
|
+
if (!secretKey) {
|
|
547
|
+
throw new Error(
|
|
548
|
+
"Authentication required. Set SOFTWARE_SECRET_KEY for stdio transport."
|
|
549
|
+
);
|
|
550
|
+
}
|
|
551
|
+
if (!secretKey.startsWith("sk01_") && !secretKey.startsWith("pat01_")) {
|
|
552
|
+
throw new Error("Invalid SOFTWARE_SECRET_KEY format. Expected sk01_ or pat01_ token.");
|
|
553
|
+
}
|
|
554
|
+
if (!publishableKey) {
|
|
555
|
+
throw new Error(
|
|
556
|
+
"publishableKey is required. Set SOFTWARE_PUBLISHABLE_KEY for stdio transport. It is used for rate limiting and monthly quota enforcement via the edge proxy."
|
|
557
|
+
);
|
|
558
|
+
}
|
|
559
|
+
return createServerClient({
|
|
560
|
+
publishableKey,
|
|
561
|
+
secretKey
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
|
|
118
565
|
// src/tools/query-collection.ts
|
|
566
|
+
import { COLLECTIONS } from "@01.software/sdk";
|
|
119
567
|
var schema = {
|
|
120
568
|
collection: z.enum(COLLECTIONS).describe("Collection name (required)"),
|
|
121
569
|
where: z.string().optional().describe(
|
|
@@ -206,201 +654,12 @@ async function getCollectionById({
|
|
|
206
654
|
}
|
|
207
655
|
}
|
|
208
656
|
|
|
209
|
-
// src/tools/
|
|
657
|
+
// src/tools/get-order.ts
|
|
210
658
|
import { z as z3 } from "zod";
|
|
211
|
-
import { COLLECTIONS as COLLECTIONS3 } from "@01.software/sdk";
|
|
212
659
|
var schema3 = {
|
|
213
|
-
|
|
214
|
-
data: z3.record(z3.string(), z3.unknown()).describe(
|
|
215
|
-
"Data to create (required). Use get-collection-schema first to understand writable fields, hidden fields, and required metadata. Server will validate and reject invalid fields."
|
|
216
|
-
)
|
|
660
|
+
orderNumber: z3.string().min(1).describe("Order number to look up (required)")
|
|
217
661
|
};
|
|
218
662
|
var metadata3 = {
|
|
219
|
-
name: "create-collection",
|
|
220
|
-
description: "Create a new collection item",
|
|
221
|
-
annotations: {
|
|
222
|
-
title: "Create collection item",
|
|
223
|
-
readOnlyHint: false,
|
|
224
|
-
destructiveHint: false,
|
|
225
|
-
idempotentHint: false
|
|
226
|
-
}
|
|
227
|
-
};
|
|
228
|
-
async function createCollection({
|
|
229
|
-
collection,
|
|
230
|
-
data
|
|
231
|
-
}) {
|
|
232
|
-
try {
|
|
233
|
-
const client = getClient().collections;
|
|
234
|
-
const result = await client.from(collection).create(data);
|
|
235
|
-
return toolSuccess({ data: result.doc, message: result.message });
|
|
236
|
-
} catch (error) {
|
|
237
|
-
return toolError(error);
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
// src/tools/update-collection.ts
|
|
242
|
-
import { z as z4 } from "zod";
|
|
243
|
-
import { COLLECTIONS as COLLECTIONS4 } from "@01.software/sdk";
|
|
244
|
-
var schema4 = {
|
|
245
|
-
collection: z4.enum(COLLECTIONS4).describe("Collection name (required)"),
|
|
246
|
-
id: z4.string().min(1).describe("Item ID (required)"),
|
|
247
|
-
data: z4.record(z4.string(), z4.unknown()).describe(
|
|
248
|
-
"Data to update (required). Use get-collection-by-id first to check current structure, then get-collection-schema to confirm writable fields and required metadata. Server will validate and reject invalid fields."
|
|
249
|
-
)
|
|
250
|
-
};
|
|
251
|
-
var metadata4 = {
|
|
252
|
-
name: "update-collection",
|
|
253
|
-
description: "Update an existing collection item",
|
|
254
|
-
annotations: {
|
|
255
|
-
title: "Update collection item",
|
|
256
|
-
readOnlyHint: false,
|
|
257
|
-
destructiveHint: true,
|
|
258
|
-
idempotentHint: true
|
|
259
|
-
}
|
|
260
|
-
};
|
|
261
|
-
async function updateCollection({
|
|
262
|
-
collection,
|
|
263
|
-
id,
|
|
264
|
-
data
|
|
265
|
-
}) {
|
|
266
|
-
try {
|
|
267
|
-
const client = getClient().collections;
|
|
268
|
-
const result = await client.from(collection).update(id, data);
|
|
269
|
-
return toolSuccess({ data: result.doc, message: result.message });
|
|
270
|
-
} catch (error) {
|
|
271
|
-
return toolError(error);
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
// src/tools/delete-collection.ts
|
|
276
|
-
import { z as z5 } from "zod";
|
|
277
|
-
import { COLLECTIONS as COLLECTIONS5 } from "@01.software/sdk";
|
|
278
|
-
var schema5 = {
|
|
279
|
-
collection: z5.enum(COLLECTIONS5).describe("Collection name (required)"),
|
|
280
|
-
id: z5.string().min(1).describe("Item ID (required)")
|
|
281
|
-
};
|
|
282
|
-
var metadata5 = {
|
|
283
|
-
name: "delete-collection",
|
|
284
|
-
description: "Delete a collection item",
|
|
285
|
-
annotations: {
|
|
286
|
-
title: "Delete collection item",
|
|
287
|
-
readOnlyHint: false,
|
|
288
|
-
destructiveHint: true,
|
|
289
|
-
idempotentHint: true
|
|
290
|
-
}
|
|
291
|
-
};
|
|
292
|
-
async function deleteCollection({
|
|
293
|
-
collection,
|
|
294
|
-
id
|
|
295
|
-
}) {
|
|
296
|
-
try {
|
|
297
|
-
const client = getClient();
|
|
298
|
-
await client.collections.from(collection).remove(id);
|
|
299
|
-
return toolSuccess({ message: "Deleted successfully." });
|
|
300
|
-
} catch (error) {
|
|
301
|
-
return toolError(error);
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
// src/tools/delete-many-collection.ts
|
|
306
|
-
import { z as z6 } from "zod";
|
|
307
|
-
import { COLLECTIONS as COLLECTIONS6 } from "@01.software/sdk";
|
|
308
|
-
var schema6 = {
|
|
309
|
-
collection: z6.enum(COLLECTIONS6).describe("Collection name (required)"),
|
|
310
|
-
where: z6.string().describe(
|
|
311
|
-
`Filter conditions (JSON string, required). Determines which items to delete. Example: '{"status":{"equals":"archived"}}'`
|
|
312
|
-
)
|
|
313
|
-
};
|
|
314
|
-
var metadata6 = {
|
|
315
|
-
name: "delete-many-collection",
|
|
316
|
-
description: "Bulk delete collection items matching a filter. All matching items will be permanently deleted.",
|
|
317
|
-
annotations: {
|
|
318
|
-
title: "Bulk delete collection items",
|
|
319
|
-
readOnlyHint: false,
|
|
320
|
-
destructiveHint: true,
|
|
321
|
-
idempotentHint: true
|
|
322
|
-
}
|
|
323
|
-
};
|
|
324
|
-
async function deleteManyCollection({
|
|
325
|
-
collection,
|
|
326
|
-
where
|
|
327
|
-
}) {
|
|
328
|
-
try {
|
|
329
|
-
const client = getClient().collections;
|
|
330
|
-
const parsed = parseJsonWhere(where);
|
|
331
|
-
if (!parsed.success) return parsed.error;
|
|
332
|
-
if (!parsed.data || typeof parsed.data !== "object" || Object.keys(parsed.data).length === 0) {
|
|
333
|
-
return toolError(
|
|
334
|
-
new Error(
|
|
335
|
-
'Empty "where" filter is not allowed for bulk deletes. Provide at least one filter condition.'
|
|
336
|
-
)
|
|
337
|
-
);
|
|
338
|
-
}
|
|
339
|
-
const result = await client.from(collection).removeMany(parsed.data);
|
|
340
|
-
return toolSuccess({
|
|
341
|
-
totalDocs: result.totalDocs,
|
|
342
|
-
message: `Deleted ${result.totalDocs} item(s).`
|
|
343
|
-
});
|
|
344
|
-
} catch (error) {
|
|
345
|
-
return toolError(error);
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
// src/tools/update-many-collection.ts
|
|
350
|
-
import { z as z7 } from "zod";
|
|
351
|
-
import { COLLECTIONS as COLLECTIONS7 } from "@01.software/sdk";
|
|
352
|
-
var schema7 = {
|
|
353
|
-
collection: z7.enum(COLLECTIONS7).describe("Collection name (required)"),
|
|
354
|
-
where: z7.string().describe(
|
|
355
|
-
`Filter conditions (JSON string, required). Determines which items to update. Example: '{"status":{"equals":"draft"}}'`
|
|
356
|
-
),
|
|
357
|
-
data: z7.record(z7.string(), z7.unknown()).describe(
|
|
358
|
-
"Data to update (required). Partial updates supported. Server will validate and reject invalid fields."
|
|
359
|
-
)
|
|
360
|
-
};
|
|
361
|
-
var metadata7 = {
|
|
362
|
-
name: "update-many-collection",
|
|
363
|
-
description: "Bulk update collection items matching a filter. All matching items will be updated with the provided data.",
|
|
364
|
-
annotations: {
|
|
365
|
-
title: "Bulk update collection items",
|
|
366
|
-
readOnlyHint: false,
|
|
367
|
-
destructiveHint: true,
|
|
368
|
-
idempotentHint: true
|
|
369
|
-
}
|
|
370
|
-
};
|
|
371
|
-
async function updateManyCollection({
|
|
372
|
-
collection,
|
|
373
|
-
where,
|
|
374
|
-
data
|
|
375
|
-
}) {
|
|
376
|
-
try {
|
|
377
|
-
const client = getClient().collections;
|
|
378
|
-
const parsed = parseJsonWhere(where);
|
|
379
|
-
if (!parsed.success) return parsed.error;
|
|
380
|
-
if (!parsed.data || typeof parsed.data !== "object" || Object.keys(parsed.data).length === 0) {
|
|
381
|
-
return toolError(
|
|
382
|
-
new Error(
|
|
383
|
-
'Empty "where" filter is not allowed for bulk updates. Provide at least one filter condition.'
|
|
384
|
-
)
|
|
385
|
-
);
|
|
386
|
-
}
|
|
387
|
-
const result = await client.from(collection).updateMany(parsed.data, data);
|
|
388
|
-
return toolSuccess({
|
|
389
|
-
data: result.docs,
|
|
390
|
-
totalDocs: result.totalDocs,
|
|
391
|
-
message: `Updated ${result.totalDocs} item(s).`
|
|
392
|
-
});
|
|
393
|
-
} catch (error) {
|
|
394
|
-
return toolError(error);
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
// src/tools/get-order.ts
|
|
399
|
-
import { z as z8 } from "zod";
|
|
400
|
-
var schema8 = {
|
|
401
|
-
orderNumber: z8.string().min(1).describe("Order number to look up (required)")
|
|
402
|
-
};
|
|
403
|
-
var metadata8 = {
|
|
404
663
|
name: "get-order",
|
|
405
664
|
description: "Get order details by order number. Returns order with related data (depth:1).",
|
|
406
665
|
annotations: {
|
|
@@ -428,26 +687,26 @@ async function getOrder({
|
|
|
428
687
|
}
|
|
429
688
|
|
|
430
689
|
// src/tools/create-order.ts
|
|
431
|
-
import { z as
|
|
432
|
-
var
|
|
433
|
-
pgPaymentId:
|
|
434
|
-
orderNumber:
|
|
435
|
-
customerSnapshot:
|
|
436
|
-
name:
|
|
437
|
-
email:
|
|
438
|
-
phone:
|
|
690
|
+
import { z as z4 } from "zod";
|
|
691
|
+
var schema4 = {
|
|
692
|
+
pgPaymentId: z4.string().optional().describe("PG payment ID (optional \u2014 omit for free orders)"),
|
|
693
|
+
orderNumber: z4.string().min(1).describe("Unique order number (required)"),
|
|
694
|
+
customerSnapshot: z4.object({
|
|
695
|
+
name: z4.string().optional().describe("Customer name"),
|
|
696
|
+
email: z4.string().describe("Customer email (required)"),
|
|
697
|
+
phone: z4.string().optional().describe("Customer phone")
|
|
439
698
|
}).describe("Customer snapshot at time of order (required)"),
|
|
440
|
-
shippingAddress:
|
|
699
|
+
shippingAddress: z4.record(z4.string(), z4.unknown()).describe(
|
|
441
700
|
"Shipping address object (required). Fields: postalCode, address1, address2, deliveryMessage, recipientName, phone"
|
|
442
701
|
),
|
|
443
|
-
orderItems:
|
|
702
|
+
orderItems: z4.array(z4.record(z4.string(), z4.unknown())).describe(
|
|
444
703
|
"Array of order item objects (required). Each: { product, variant, option, quantity, unitPrice?, totalPrice? }"
|
|
445
704
|
),
|
|
446
|
-
totalAmount:
|
|
447
|
-
shippingAmount:
|
|
448
|
-
discountCode:
|
|
705
|
+
totalAmount: z4.number().nonnegative().describe("Total order amount (required, min 0)"),
|
|
706
|
+
shippingAmount: z4.number().nonnegative().optional().describe("Shipping amount (optional, default 0)"),
|
|
707
|
+
discountCode: z4.string().optional().describe("Discount code to apply (optional)")
|
|
449
708
|
};
|
|
450
|
-
var
|
|
709
|
+
var metadata4 = {
|
|
451
710
|
name: "create-order",
|
|
452
711
|
description: "Create a new order with products and shipping information. Supports idempotency.",
|
|
453
712
|
annotations: {
|
|
@@ -470,10 +729,10 @@ async function createOrder(params) {
|
|
|
470
729
|
}
|
|
471
730
|
|
|
472
731
|
// src/tools/update-order.ts
|
|
473
|
-
import { z as
|
|
474
|
-
var
|
|
475
|
-
orderNumber:
|
|
476
|
-
status:
|
|
732
|
+
import { z as z5 } from "zod";
|
|
733
|
+
var schema5 = {
|
|
734
|
+
orderNumber: z5.string().min(1).describe("Order number (required)"),
|
|
735
|
+
status: z5.enum([
|
|
477
736
|
"pending",
|
|
478
737
|
"paid",
|
|
479
738
|
"failed",
|
|
@@ -486,7 +745,7 @@ var schema10 = {
|
|
|
486
745
|
"New order status. Return-related statuses (return_requested, return_processing, returned) must be set via Return endpoints."
|
|
487
746
|
)
|
|
488
747
|
};
|
|
489
|
-
var
|
|
748
|
+
var metadata5 = {
|
|
490
749
|
name: "update-order",
|
|
491
750
|
description: "Update order status. Automatically adjusts stock on status changes (e.g., canceled restores stock).",
|
|
492
751
|
annotations: {
|
|
@@ -510,17 +769,17 @@ async function updateOrder({
|
|
|
510
769
|
}
|
|
511
770
|
|
|
512
771
|
// src/tools/checkout.ts
|
|
513
|
-
import { z as
|
|
514
|
-
var
|
|
515
|
-
cartId:
|
|
516
|
-
pgPaymentId:
|
|
517
|
-
orderNumber:
|
|
518
|
-
customerSnapshot:
|
|
772
|
+
import { z as z6 } from "zod";
|
|
773
|
+
var schema6 = {
|
|
774
|
+
cartId: z6.string().min(1).describe("Cart ID to convert to order (required)"),
|
|
775
|
+
pgPaymentId: z6.string().optional().describe("PG payment ID (optional \u2014 omit for free orders)"),
|
|
776
|
+
orderNumber: z6.string().min(1).describe("Unique order number (required)"),
|
|
777
|
+
customerSnapshot: z6.record(z6.string(), z6.unknown()).describe(
|
|
519
778
|
"Customer snapshot object (required). Fields: { name?, email, phone? }"
|
|
520
779
|
),
|
|
521
|
-
discountCode:
|
|
780
|
+
discountCode: z6.string().optional().describe("Discount code to apply (optional)")
|
|
522
781
|
};
|
|
523
|
-
var
|
|
782
|
+
var metadata6 = {
|
|
524
783
|
name: "checkout",
|
|
525
784
|
description: "Convert a cart to an order. Validates stock, creates order and transaction, marks cart as completed. Supports idempotency.",
|
|
526
785
|
annotations: {
|
|
@@ -543,21 +802,21 @@ async function checkout(params) {
|
|
|
543
802
|
}
|
|
544
803
|
|
|
545
804
|
// src/tools/create-fulfillment.ts
|
|
546
|
-
import { z as
|
|
547
|
-
var
|
|
548
|
-
orderNumber:
|
|
549
|
-
carrier:
|
|
550
|
-
trackingNumber:
|
|
805
|
+
import { z as z7 } from "zod";
|
|
806
|
+
var schema7 = {
|
|
807
|
+
orderNumber: z7.string().min(1).describe("Order number (required)"),
|
|
808
|
+
carrier: z7.string().optional().describe("Shipping carrier name (optional)"),
|
|
809
|
+
trackingNumber: z7.string().optional().describe(
|
|
551
810
|
'Tracking number (optional). Setting carrier + tracking triggers "shipped" status'
|
|
552
811
|
),
|
|
553
|
-
items:
|
|
554
|
-
|
|
555
|
-
orderItem:
|
|
556
|
-
quantity:
|
|
812
|
+
items: z7.array(
|
|
813
|
+
z7.object({
|
|
814
|
+
orderItem: z7.string().min(1).describe("Order item ID"),
|
|
815
|
+
quantity: z7.number().int().positive().describe("Quantity to fulfill")
|
|
557
816
|
})
|
|
558
817
|
).describe("Array of items to fulfill (required)")
|
|
559
818
|
};
|
|
560
|
-
var
|
|
819
|
+
var metadata7 = {
|
|
561
820
|
name: "create-fulfillment",
|
|
562
821
|
description: "Create a shipment/fulfillment for order items. Auto-updates order status (paid \u2192 preparing \u2192 shipped).",
|
|
563
822
|
annotations: {
|
|
@@ -588,20 +847,20 @@ async function createFulfillment({
|
|
|
588
847
|
}
|
|
589
848
|
|
|
590
849
|
// src/tools/update-fulfillment.ts
|
|
591
|
-
import { z as
|
|
592
|
-
var
|
|
593
|
-
fulfillmentId:
|
|
594
|
-
status:
|
|
850
|
+
import { z as z8 } from "zod";
|
|
851
|
+
var schema8 = {
|
|
852
|
+
fulfillmentId: z8.string().min(1).describe("Fulfillment ID (required)"),
|
|
853
|
+
status: z8.enum(["packed", "shipped", "delivered", "failed"]).describe(
|
|
595
854
|
"New fulfillment status (required). FSM: pending\u2192packed/shipped/failed, packed\u2192shipped/failed, shipped\u2192delivered/failed"
|
|
596
855
|
),
|
|
597
|
-
carrier:
|
|
856
|
+
carrier: z8.string().optional().describe(
|
|
598
857
|
"Shipping carrier (optional, changeable only in pending/packed status)"
|
|
599
858
|
),
|
|
600
|
-
trackingNumber:
|
|
859
|
+
trackingNumber: z8.string().optional().describe(
|
|
601
860
|
"Tracking number (optional, changeable only in pending/packed status)"
|
|
602
861
|
)
|
|
603
862
|
};
|
|
604
|
-
var
|
|
863
|
+
var metadata8 = {
|
|
605
864
|
name: "update-fulfillment",
|
|
606
865
|
description: "Update fulfillment status, carrier, and tracking number. Auto-updates order status when all fulfillments are delivered.",
|
|
607
866
|
annotations: {
|
|
@@ -631,15 +890,134 @@ async function updateFulfillment({
|
|
|
631
890
|
}
|
|
632
891
|
}
|
|
633
892
|
|
|
893
|
+
// ../../packages/contracts/src/tenant/index.ts
|
|
894
|
+
import { z as z9 } from "zod";
|
|
895
|
+
var tenantFieldConfigStateSchema = z9.object({
|
|
896
|
+
hiddenFields: z9.array(z9.string()),
|
|
897
|
+
isHidden: z9.boolean()
|
|
898
|
+
}).strict();
|
|
899
|
+
var tenantContextQuerySchema = z9.object({
|
|
900
|
+
counts: z9.literal("true").optional()
|
|
901
|
+
}).strict();
|
|
902
|
+
var tenantContextToolInputSchema = z9.object({
|
|
903
|
+
includeCounts: z9.boolean().optional().default(false).describe(
|
|
904
|
+
"Include per-collection document counts and config status (bypasses cache, slower)"
|
|
905
|
+
)
|
|
906
|
+
}).strict();
|
|
907
|
+
var tenantContextResponseSchema = z9.object({
|
|
908
|
+
tenant: z9.object({
|
|
909
|
+
id: z9.string(),
|
|
910
|
+
name: z9.string(),
|
|
911
|
+
plan: z9.string(),
|
|
912
|
+
planSource: z9.string().optional(),
|
|
913
|
+
authoritative: z9.boolean().optional(),
|
|
914
|
+
capabilityVersion: z9.string().optional(),
|
|
915
|
+
isDevMode: z9.boolean()
|
|
916
|
+
}).strict(),
|
|
917
|
+
features: z9.array(z9.string()),
|
|
918
|
+
collections: z9.object({
|
|
919
|
+
active: z9.array(z9.string()),
|
|
920
|
+
inactive: z9.array(z9.string())
|
|
921
|
+
}).strict(),
|
|
922
|
+
fieldConfigs: z9.record(z9.string(), tenantFieldConfigStateSchema),
|
|
923
|
+
counts: z9.record(z9.string(), z9.number()).optional(),
|
|
924
|
+
config: z9.object({
|
|
925
|
+
webhookConfigured: z9.boolean()
|
|
926
|
+
}).strict().optional()
|
|
927
|
+
}).strict();
|
|
928
|
+
var COLLECTION_SCHEMA_CONTRACT_VERSION = 1;
|
|
929
|
+
var collectionSchemaEndpointParamsSchema = z9.object({
|
|
930
|
+
collectionSlug: z9.string().min(1, "collectionSlug is required")
|
|
931
|
+
}).strict();
|
|
932
|
+
function createCollectionSchemaToolInputSchema(collections) {
|
|
933
|
+
return z9.object({
|
|
934
|
+
collection: z9.enum(collections).describe("Collection name (required)")
|
|
935
|
+
}).strict();
|
|
936
|
+
}
|
|
937
|
+
var collectionFieldOptionSchema = z9.object({
|
|
938
|
+
label: z9.string(),
|
|
939
|
+
value: z9.string()
|
|
940
|
+
}).strict();
|
|
941
|
+
var collectionFieldSchema = z9.lazy(
|
|
942
|
+
() => z9.object({
|
|
943
|
+
name: z9.string(),
|
|
944
|
+
path: z9.string(),
|
|
945
|
+
type: z9.string(),
|
|
946
|
+
required: z9.literal(true).optional(),
|
|
947
|
+
unique: z9.literal(true).optional(),
|
|
948
|
+
hasMany: z9.literal(true).optional(),
|
|
949
|
+
relationTo: z9.union([z9.string(), z9.array(z9.string())]).optional(),
|
|
950
|
+
options: z9.array(collectionFieldOptionSchema).optional(),
|
|
951
|
+
hidden: z9.literal(true).optional(),
|
|
952
|
+
systemManaged: z9.literal(true).optional(),
|
|
953
|
+
writable: z9.boolean().optional(),
|
|
954
|
+
fields: z9.array(collectionFieldSchema).optional()
|
|
955
|
+
}).strict()
|
|
956
|
+
);
|
|
957
|
+
var collectionSchemaResponseSchema = z9.object({
|
|
958
|
+
contractVersion: z9.literal(COLLECTION_SCHEMA_CONTRACT_VERSION),
|
|
959
|
+
mode: z9.literal("effective"),
|
|
960
|
+
collection: z9.object({
|
|
961
|
+
slug: z9.string(),
|
|
962
|
+
timestamps: z9.boolean(),
|
|
963
|
+
alwaysActive: z9.boolean(),
|
|
964
|
+
feature: z9.string().nullable(),
|
|
965
|
+
systemFields: z9.array(z9.string()),
|
|
966
|
+
visibility: z9.object({
|
|
967
|
+
collectionHidden: z9.boolean(),
|
|
968
|
+
hiddenFields: z9.array(z9.string())
|
|
969
|
+
}).strict(),
|
|
970
|
+
fields: z9.array(collectionFieldSchema)
|
|
971
|
+
}).strict()
|
|
972
|
+
}).strict();
|
|
973
|
+
|
|
974
|
+
// ../../packages/contracts/src/ecommerce/index.ts
|
|
975
|
+
import { z as z10 } from "zod";
|
|
976
|
+
var transactionStatusSchema = z10.enum([
|
|
977
|
+
"pending",
|
|
978
|
+
"paid",
|
|
979
|
+
"failed",
|
|
980
|
+
"canceled"
|
|
981
|
+
]);
|
|
982
|
+
var updateTransactionSchema = z10.object({
|
|
983
|
+
pgPaymentId: z10.string().min(1, "pgPaymentId is required").describe("PG payment ID (required)"),
|
|
984
|
+
status: transactionStatusSchema.describe(
|
|
985
|
+
"New transaction status (required)"
|
|
986
|
+
),
|
|
987
|
+
paymentMethod: z10.string().optional().describe("Payment method (optional)"),
|
|
988
|
+
receiptUrl: z10.string().optional().describe("Receipt URL (optional)"),
|
|
989
|
+
paymentKey: z10.string().min(1).optional().describe("Provider payment key for verified paid confirmation"),
|
|
990
|
+
amount: z10.number().int().positive().optional().describe("Provider-confirmed amount for verified paid confirmation")
|
|
991
|
+
}).strict();
|
|
992
|
+
var UpdateTransactionSchema = updateTransactionSchema;
|
|
993
|
+
var returnReasonSchema = z10.enum([
|
|
994
|
+
"change_of_mind",
|
|
995
|
+
"defective",
|
|
996
|
+
"wrong_delivery",
|
|
997
|
+
"damaged",
|
|
998
|
+
"other"
|
|
999
|
+
]);
|
|
1000
|
+
var restockActionSchema = z10.enum(["return_to_stock", "discard"]);
|
|
1001
|
+
var returnWithRefundItemSchema = z10.object({
|
|
1002
|
+
orderItem: z10.union([z10.string(), z10.number()]).transform(String),
|
|
1003
|
+
quantity: z10.number().int().positive("quantity must be a positive integer"),
|
|
1004
|
+
restockAction: restockActionSchema.default("return_to_stock")
|
|
1005
|
+
}).strict();
|
|
1006
|
+
var returnWithRefundSchema = z10.object({
|
|
1007
|
+
orderNumber: z10.string().min(1, "orderNumber is required").describe("Order number (required)"),
|
|
1008
|
+
reason: returnReasonSchema.optional().describe("Return reason (optional)"),
|
|
1009
|
+
reasonDetail: z10.string().optional().describe("Detailed reason text (optional)"),
|
|
1010
|
+
returnItems: z10.array(returnWithRefundItemSchema).min(1, "At least one return item is required").max(100, "Too many return items").describe("Array of products to return (required)"),
|
|
1011
|
+
refundAmount: z10.number().min(0, "refundAmount must be non-negative").describe("Refund amount (required, min 0)"),
|
|
1012
|
+
pgPaymentId: z10.string().min(1, "pgPaymentId is required").describe("PG payment ID for refund (required)"),
|
|
1013
|
+
paymentKey: z10.string().min(1).optional().describe("Provider payment key for verified refund"),
|
|
1014
|
+
refundReceiptUrl: z10.string().optional().describe("Refund receipt URL (optional)")
|
|
1015
|
+
}).strict();
|
|
1016
|
+
var ReturnWithRefundSchema = returnWithRefundSchema;
|
|
1017
|
+
|
|
634
1018
|
// src/tools/update-transaction.ts
|
|
635
|
-
|
|
636
|
-
var
|
|
637
|
-
pgPaymentId: z14.string().min(1).describe("PG payment ID (required)"),
|
|
638
|
-
status: z14.enum(["pending", "paid", "failed", "canceled"]).describe("New transaction status (required)"),
|
|
639
|
-
paymentMethod: z14.string().optional().describe("Payment method (optional)"),
|
|
640
|
-
receiptUrl: z14.string().optional().describe("Receipt URL (optional)")
|
|
641
|
-
};
|
|
642
|
-
var metadata14 = {
|
|
1019
|
+
var schema9 = UpdateTransactionSchema.shape;
|
|
1020
|
+
var metadata9 = {
|
|
643
1021
|
name: "update-transaction",
|
|
644
1022
|
description: "Update transaction status, payment method, and receipt URL.",
|
|
645
1023
|
annotations: {
|
|
@@ -653,16 +1031,21 @@ async function updateTransaction({
|
|
|
653
1031
|
pgPaymentId,
|
|
654
1032
|
status,
|
|
655
1033
|
paymentMethod,
|
|
656
|
-
receiptUrl
|
|
1034
|
+
receiptUrl,
|
|
1035
|
+
paymentKey,
|
|
1036
|
+
amount
|
|
657
1037
|
}) {
|
|
658
1038
|
try {
|
|
659
1039
|
const client = getClient();
|
|
660
|
-
const
|
|
1040
|
+
const params = {
|
|
661
1041
|
pgPaymentId,
|
|
662
1042
|
status,
|
|
663
1043
|
paymentMethod,
|
|
664
|
-
receiptUrl
|
|
665
|
-
|
|
1044
|
+
receiptUrl,
|
|
1045
|
+
paymentKey,
|
|
1046
|
+
amount
|
|
1047
|
+
};
|
|
1048
|
+
const result = await client.commerce.orders.updateTransaction(params);
|
|
666
1049
|
return toolSuccess({ data: result });
|
|
667
1050
|
} catch (error) {
|
|
668
1051
|
return toolError(error);
|
|
@@ -670,20 +1053,20 @@ async function updateTransaction({
|
|
|
670
1053
|
}
|
|
671
1054
|
|
|
672
1055
|
// src/tools/create-return.ts
|
|
673
|
-
import { z as
|
|
674
|
-
var
|
|
675
|
-
orderNumber:
|
|
676
|
-
reason:
|
|
677
|
-
reasonDetail:
|
|
678
|
-
returnItems:
|
|
679
|
-
|
|
680
|
-
orderItem:
|
|
681
|
-
quantity:
|
|
1056
|
+
import { z as z11 } from "zod";
|
|
1057
|
+
var schema10 = {
|
|
1058
|
+
orderNumber: z11.string().min(1).describe("Order number (required)"),
|
|
1059
|
+
reason: z11.enum(["change_of_mind", "defective", "wrong_delivery", "damaged", "other"]).optional().describe("Return reason (optional)"),
|
|
1060
|
+
reasonDetail: z11.string().optional().describe("Detailed reason text (optional)"),
|
|
1061
|
+
returnItems: z11.array(
|
|
1062
|
+
z11.object({
|
|
1063
|
+
orderItem: z11.string().min(1).describe("Order item ID"),
|
|
1064
|
+
quantity: z11.number().int().positive().describe("Quantity to return")
|
|
682
1065
|
})
|
|
683
1066
|
).describe("Array of products to return (required)"),
|
|
684
|
-
refundAmount:
|
|
1067
|
+
refundAmount: z11.number().nonnegative().describe("Refund amount (required, min 0)")
|
|
685
1068
|
};
|
|
686
|
-
var
|
|
1069
|
+
var metadata10 = {
|
|
687
1070
|
name: "create-return",
|
|
688
1071
|
description: "Create a return request for an order. Only works for delivered/confirmed orders. Updates order status to return_requested.",
|
|
689
1072
|
annotations: {
|
|
@@ -716,14 +1099,14 @@ async function createReturn({
|
|
|
716
1099
|
}
|
|
717
1100
|
|
|
718
1101
|
// src/tools/update-return.ts
|
|
719
|
-
import { z as
|
|
720
|
-
var
|
|
721
|
-
returnId:
|
|
722
|
-
status:
|
|
1102
|
+
import { z as z12 } from "zod";
|
|
1103
|
+
var schema11 = {
|
|
1104
|
+
returnId: z12.string().min(1).describe("Return ID (required)"),
|
|
1105
|
+
status: z12.enum(["processing", "approved", "rejected", "completed"]).describe(
|
|
723
1106
|
"New return status (required). Valid transitions: requested\u2192processing/rejected, processing\u2192approved/rejected, approved\u2192completed"
|
|
724
1107
|
)
|
|
725
1108
|
};
|
|
726
|
-
var
|
|
1109
|
+
var metadata11 = {
|
|
727
1110
|
name: "update-return",
|
|
728
1111
|
description: "Update return status with FSM validation. Restores inventory on completion, reverts order status on rejection.",
|
|
729
1112
|
annotations: {
|
|
@@ -747,22 +1130,8 @@ async function updateReturn({
|
|
|
747
1130
|
}
|
|
748
1131
|
|
|
749
1132
|
// src/tools/return-with-refund.ts
|
|
750
|
-
|
|
751
|
-
var
|
|
752
|
-
orderNumber: z17.string().min(1).describe("Order number (required)"),
|
|
753
|
-
reason: z17.enum(["change_of_mind", "defective", "wrong_delivery", "damaged", "other"]).optional().describe("Return reason (optional)"),
|
|
754
|
-
reasonDetail: z17.string().optional().describe("Detailed reason text (optional)"),
|
|
755
|
-
returnItems: z17.array(
|
|
756
|
-
z17.object({
|
|
757
|
-
orderItem: z17.string().min(1).describe("Order item ID"),
|
|
758
|
-
quantity: z17.number().int().positive().describe("Quantity to return")
|
|
759
|
-
})
|
|
760
|
-
).describe("Array of products to return (required)"),
|
|
761
|
-
refundAmount: z17.number().nonnegative().describe("Refund amount (required, min 0)"),
|
|
762
|
-
pgPaymentId: z17.string().min(1).describe("PG payment ID for refund (required)"),
|
|
763
|
-
refundReceiptUrl: z17.string().optional().describe("Refund receipt URL (optional)")
|
|
764
|
-
};
|
|
765
|
-
var metadata17 = {
|
|
1133
|
+
var schema12 = ReturnWithRefundSchema.shape;
|
|
1134
|
+
var metadata12 = {
|
|
766
1135
|
name: "return-with-refund",
|
|
767
1136
|
description: "Combined return + refund operation. Creates return, restores stock, cancels transaction, updates order status.",
|
|
768
1137
|
annotations: {
|
|
@@ -779,19 +1148,22 @@ async function returnWithRefund({
|
|
|
779
1148
|
returnItems,
|
|
780
1149
|
refundAmount,
|
|
781
1150
|
pgPaymentId,
|
|
1151
|
+
paymentKey,
|
|
782
1152
|
refundReceiptUrl
|
|
783
1153
|
}) {
|
|
784
1154
|
try {
|
|
785
1155
|
const client = getClient();
|
|
786
|
-
const
|
|
1156
|
+
const params = {
|
|
787
1157
|
orderNumber,
|
|
788
1158
|
reason,
|
|
789
1159
|
reasonDetail,
|
|
790
1160
|
returnItems,
|
|
791
1161
|
refundAmount,
|
|
792
1162
|
pgPaymentId,
|
|
1163
|
+
paymentKey,
|
|
793
1164
|
refundReceiptUrl
|
|
794
|
-
}
|
|
1165
|
+
};
|
|
1166
|
+
const result = await client.commerce.orders.returnWithRefund(params);
|
|
795
1167
|
return toolSuccess({ data: result });
|
|
796
1168
|
} catch (error) {
|
|
797
1169
|
return toolError(error);
|
|
@@ -799,15 +1171,15 @@ async function returnWithRefund({
|
|
|
799
1171
|
}
|
|
800
1172
|
|
|
801
1173
|
// src/tools/add-cart-item.ts
|
|
802
|
-
import { z as
|
|
803
|
-
var
|
|
804
|
-
cartId:
|
|
805
|
-
product:
|
|
806
|
-
variant:
|
|
807
|
-
option:
|
|
808
|
-
quantity:
|
|
1174
|
+
import { z as z13 } from "zod";
|
|
1175
|
+
var schema13 = {
|
|
1176
|
+
cartId: z13.string().min(1).describe("Cart ID (required)"),
|
|
1177
|
+
product: z13.string().min(1).describe("Product ID (required)"),
|
|
1178
|
+
variant: z13.string().min(1).describe("Product variant ID (required)"),
|
|
1179
|
+
option: z13.string().min(1).describe("Product option ID (required)"),
|
|
1180
|
+
quantity: z13.number().int().positive().describe("Quantity to add (required, positive integer)")
|
|
809
1181
|
};
|
|
810
|
-
var
|
|
1182
|
+
var metadata13 = {
|
|
811
1183
|
name: "add-cart-item",
|
|
812
1184
|
description: "Add a product to cart. Validates stock, merges quantity if item already exists, recalculates totals.",
|
|
813
1185
|
annotations: {
|
|
@@ -840,12 +1212,12 @@ async function addCartItem({
|
|
|
840
1212
|
}
|
|
841
1213
|
|
|
842
1214
|
// src/tools/update-cart-item.ts
|
|
843
|
-
import { z as
|
|
844
|
-
var
|
|
845
|
-
cartItemId:
|
|
846
|
-
quantity:
|
|
1215
|
+
import { z as z14 } from "zod";
|
|
1216
|
+
var schema14 = {
|
|
1217
|
+
cartItemId: z14.string().min(1).describe("Cart item ID (required)"),
|
|
1218
|
+
quantity: z14.number().int().positive().describe("New quantity (required, positive integer)")
|
|
847
1219
|
};
|
|
848
|
-
var
|
|
1220
|
+
var metadata14 = {
|
|
849
1221
|
name: "update-cart-item",
|
|
850
1222
|
description: "Update cart item quantity. Validates stock availability, recalculates cart totals.",
|
|
851
1223
|
annotations: {
|
|
@@ -869,11 +1241,11 @@ async function updateCartItem({
|
|
|
869
1241
|
}
|
|
870
1242
|
|
|
871
1243
|
// src/tools/remove-cart-item.ts
|
|
872
|
-
import { z as
|
|
873
|
-
var
|
|
874
|
-
cartItemId:
|
|
1244
|
+
import { z as z15 } from "zod";
|
|
1245
|
+
var schema15 = {
|
|
1246
|
+
cartItemId: z15.string().min(1).describe("Cart item ID to remove (required)")
|
|
875
1247
|
};
|
|
876
|
-
var
|
|
1248
|
+
var metadata15 = {
|
|
877
1249
|
name: "remove-cart-item",
|
|
878
1250
|
description: "Remove an item from cart. Recalculates cart totals after removal.",
|
|
879
1251
|
annotations: {
|
|
@@ -896,12 +1268,12 @@ async function removeCartItem({
|
|
|
896
1268
|
}
|
|
897
1269
|
|
|
898
1270
|
// src/tools/apply-discount.ts
|
|
899
|
-
import { z as
|
|
900
|
-
var
|
|
901
|
-
cartId:
|
|
902
|
-
discountCode:
|
|
1271
|
+
import { z as z16 } from "zod";
|
|
1272
|
+
var schema16 = {
|
|
1273
|
+
cartId: z16.string().min(1).describe("Cart ID (required)"),
|
|
1274
|
+
discountCode: z16.string().describe("Discount code to apply (required)")
|
|
903
1275
|
};
|
|
904
|
-
var
|
|
1276
|
+
var metadata16 = {
|
|
905
1277
|
name: "apply-discount",
|
|
906
1278
|
description: "Apply a discount code to a cart. Validates the code, updates cart totals, and sets free shipping if applicable.",
|
|
907
1279
|
annotations: {
|
|
@@ -925,11 +1297,11 @@ async function applyDiscount({
|
|
|
925
1297
|
}
|
|
926
1298
|
|
|
927
1299
|
// src/tools/remove-discount.ts
|
|
928
|
-
import { z as
|
|
929
|
-
var
|
|
930
|
-
cartId:
|
|
1300
|
+
import { z as z17 } from "zod";
|
|
1301
|
+
var schema17 = {
|
|
1302
|
+
cartId: z17.string().min(1).describe("Cart ID (required)")
|
|
931
1303
|
};
|
|
932
|
-
var
|
|
1304
|
+
var metadata17 = {
|
|
933
1305
|
name: "remove-discount",
|
|
934
1306
|
description: "Remove the applied discount code from a cart and recalculate totals.",
|
|
935
1307
|
annotations: {
|
|
@@ -952,11 +1324,11 @@ async function removeDiscount({
|
|
|
952
1324
|
}
|
|
953
1325
|
|
|
954
1326
|
// src/tools/clear-cart.ts
|
|
955
|
-
import { z as
|
|
956
|
-
var
|
|
957
|
-
cartId:
|
|
1327
|
+
import { z as z18 } from "zod";
|
|
1328
|
+
var schema18 = {
|
|
1329
|
+
cartId: z18.string().min(1).describe("Cart ID (required)")
|
|
958
1330
|
};
|
|
959
|
-
var
|
|
1331
|
+
var metadata18 = {
|
|
960
1332
|
name: "clear-cart",
|
|
961
1333
|
description: "Remove all items from a cart, reset discount and amounts. Shipping fee is preserved.",
|
|
962
1334
|
annotations: {
|
|
@@ -979,12 +1351,12 @@ async function clearCart({
|
|
|
979
1351
|
}
|
|
980
1352
|
|
|
981
1353
|
// src/tools/validate-discount.ts
|
|
982
|
-
import { z as
|
|
983
|
-
var
|
|
984
|
-
code:
|
|
985
|
-
orderAmount:
|
|
1354
|
+
import { z as z19 } from "zod";
|
|
1355
|
+
var schema19 = {
|
|
1356
|
+
code: z19.string().describe("Discount code to validate (required)"),
|
|
1357
|
+
orderAmount: z19.number().describe("Order amount for validation (required)")
|
|
986
1358
|
};
|
|
987
|
-
var
|
|
1359
|
+
var metadata19 = {
|
|
988
1360
|
name: "validate-discount",
|
|
989
1361
|
description: "Validate a discount code. Checks active status, date range, usage limits, minimum order amount, and calculates discount.",
|
|
990
1362
|
annotations: {
|
|
@@ -1011,13 +1383,13 @@ async function validateDiscount({
|
|
|
1011
1383
|
}
|
|
1012
1384
|
|
|
1013
1385
|
// src/tools/calculate-shipping.ts
|
|
1014
|
-
import { z as
|
|
1015
|
-
var
|
|
1016
|
-
shippingPolicyId:
|
|
1017
|
-
orderAmount:
|
|
1018
|
-
postalCode:
|
|
1386
|
+
import { z as z20 } from "zod";
|
|
1387
|
+
var schema20 = {
|
|
1388
|
+
shippingPolicyId: z20.string().optional().describe("Shipping policy ID (uses default policy if omitted)"),
|
|
1389
|
+
orderAmount: z20.number().describe("Order amount for fee calculation (required)"),
|
|
1390
|
+
postalCode: z20.string().optional().describe("Postal code for Jeju surcharge detection (63000-63644)")
|
|
1019
1391
|
};
|
|
1020
|
-
var
|
|
1392
|
+
var metadata20 = {
|
|
1021
1393
|
name: "calculate-shipping",
|
|
1022
1394
|
description: "Calculate shipping fee based on order amount and postal code. Supports free shipping threshold and Jeju surcharge.",
|
|
1023
1395
|
annotations: {
|
|
@@ -1046,18 +1418,18 @@ async function calculateShipping({
|
|
|
1046
1418
|
}
|
|
1047
1419
|
|
|
1048
1420
|
// src/tools/stock-check.ts
|
|
1049
|
-
import { z as
|
|
1050
|
-
var
|
|
1051
|
-
items:
|
|
1052
|
-
|
|
1053
|
-
variantId:
|
|
1054
|
-
quantity:
|
|
1421
|
+
import { z as z21 } from "zod";
|
|
1422
|
+
var schema21 = {
|
|
1423
|
+
items: z21.array(
|
|
1424
|
+
z21.object({
|
|
1425
|
+
variantId: z21.string().describe("Product variant ID"),
|
|
1426
|
+
quantity: z21.number().int().positive().describe("Requested quantity")
|
|
1055
1427
|
})
|
|
1056
1428
|
).describe(
|
|
1057
1429
|
"Array of items to check stock for (required, max 100). Each: { variantId, quantity }"
|
|
1058
1430
|
)
|
|
1059
1431
|
};
|
|
1060
|
-
var
|
|
1432
|
+
var metadata21 = {
|
|
1061
1433
|
name: "stock-check",
|
|
1062
1434
|
description: "Batch check product option stock availability. Returns per-item availability and an allAvailable flag.",
|
|
1063
1435
|
annotations: {
|
|
@@ -1080,56 +1452,46 @@ async function stockCheck({
|
|
|
1080
1452
|
}
|
|
1081
1453
|
|
|
1082
1454
|
// src/tools/get-collection-schema.ts
|
|
1083
|
-
import {
|
|
1084
|
-
import { COLLECTIONS as COLLECTIONS8 } from "@01.software/sdk";
|
|
1455
|
+
import { COLLECTIONS as COLLECTIONS3 } from "@01.software/sdk";
|
|
1085
1456
|
|
|
1086
1457
|
// src/lib/console-api.ts
|
|
1087
1458
|
import { createHash } from "crypto";
|
|
1088
1459
|
var BASE_URL = process.env.SOFTWARE_API_URL || "http://localhost:3000";
|
|
1089
1460
|
var TIMEOUT_MS = 5e3;
|
|
1461
|
+
var MISSING_HTTP_AUTH_CONTEXT_ERROR2 = "MCP HTTP requests require a validated OAuth tenant context before tool execution.";
|
|
1090
1462
|
function resolveAuthHeaderContext() {
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
publishableKey: h?.["x-publishable-key"] ?? h?.["x-client-key"]
|
|
1463
|
+
const oauthContext = tenantAuthContext();
|
|
1464
|
+
if (oauthContext) {
|
|
1465
|
+
return {
|
|
1466
|
+
apiKey: signMcpServiceToken(oauthContext),
|
|
1467
|
+
mode: "oauth"
|
|
1097
1468
|
};
|
|
1098
|
-
} catch {
|
|
1099
1469
|
}
|
|
1470
|
+
if (hasRequestContext()) throw new Error(MISSING_HTTP_AUTH_CONTEXT_ERROR2);
|
|
1100
1471
|
return {
|
|
1101
|
-
apiKey:
|
|
1102
|
-
|
|
1472
|
+
apiKey: process.env.SOFTWARE_SECRET_KEY,
|
|
1473
|
+
mode: "stdio",
|
|
1474
|
+
publishableKey: process.env.SOFTWARE_PUBLISHABLE_KEY ?? process.env.NEXT_PUBLIC_SOFTWARE_PUBLISHABLE_KEY
|
|
1103
1475
|
};
|
|
1104
1476
|
}
|
|
1105
1477
|
function resolveApiKey() {
|
|
1106
1478
|
const { apiKey } = resolveAuthHeaderContext();
|
|
1107
1479
|
if (!apiKey || typeof apiKey !== "string") {
|
|
1108
1480
|
throw new Error(
|
|
1109
|
-
"Authentication required.
|
|
1481
|
+
"Authentication required. Set SOFTWARE_SECRET_KEY for stdio transport."
|
|
1110
1482
|
);
|
|
1111
1483
|
}
|
|
1112
1484
|
return apiKey;
|
|
1113
1485
|
}
|
|
1114
|
-
function hashKey(apiKey) {
|
|
1115
|
-
return createHash("sha256").update(apiKey).digest("hex");
|
|
1116
|
-
}
|
|
1117
|
-
function resolveAuthCacheKey(apiKey) {
|
|
1118
|
-
const { publishableKey } = resolveAuthHeaderContext();
|
|
1119
|
-
return hashKey(
|
|
1120
|
-
JSON.stringify({
|
|
1121
|
-
apiKey,
|
|
1122
|
-
publishableKey: publishableKey ?? ""
|
|
1123
|
-
})
|
|
1124
|
-
);
|
|
1125
|
-
}
|
|
1126
1486
|
function buildAuthHeaders(apiKey) {
|
|
1127
|
-
const { publishableKey } = resolveAuthHeaderContext();
|
|
1128
|
-
const
|
|
1487
|
+
const { mode, publishableKey } = resolveAuthHeaderContext();
|
|
1488
|
+
const headers = {
|
|
1129
1489
|
Authorization: `Bearer ${apiKey}`
|
|
1130
1490
|
};
|
|
1131
|
-
if (
|
|
1132
|
-
|
|
1491
|
+
if (mode === "stdio" && publishableKey) {
|
|
1492
|
+
headers["X-Publishable-Key"] = publishableKey;
|
|
1493
|
+
}
|
|
1494
|
+
return headers;
|
|
1133
1495
|
}
|
|
1134
1496
|
function extractErrorMessage(body) {
|
|
1135
1497
|
if (!body || typeof body !== "object") return void 0;
|
|
@@ -1185,17 +1547,16 @@ async function consolePost(path, body, apiKey) {
|
|
|
1185
1547
|
// src/lib/collection-schema.ts
|
|
1186
1548
|
async function getCollectionSchema(collection) {
|
|
1187
1549
|
const apiKey = resolveApiKey();
|
|
1188
|
-
|
|
1550
|
+
const data = await consoleGet(
|
|
1189
1551
|
`/api/tenants/schema/${encodeURIComponent(collection)}`,
|
|
1190
1552
|
apiKey
|
|
1191
1553
|
);
|
|
1554
|
+
return collectionSchemaResponseSchema.parse(data);
|
|
1192
1555
|
}
|
|
1193
1556
|
|
|
1194
1557
|
// src/tools/get-collection-schema.ts
|
|
1195
|
-
var
|
|
1196
|
-
|
|
1197
|
-
};
|
|
1198
|
-
var metadata27 = {
|
|
1558
|
+
var schema22 = createCollectionSchemaToolInputSchema(COLLECTIONS3).shape;
|
|
1559
|
+
var metadata22 = {
|
|
1199
1560
|
name: "get-collection-schema",
|
|
1200
1561
|
description: "Get the authoritative tenant-aware collection schema from console. Use this before create/update to understand writable fields, hidden fields, required metadata, and collection-level visibility.",
|
|
1201
1562
|
annotations: {
|
|
@@ -1219,48 +1580,22 @@ async function getCollectionSchemaTool({
|
|
|
1219
1580
|
}
|
|
1220
1581
|
}
|
|
1221
1582
|
|
|
1222
|
-
// src/tools/get-tenant-context.ts
|
|
1223
|
-
import { z as z28 } from "zod";
|
|
1224
|
-
|
|
1225
1583
|
// src/lib/tenant-context.ts
|
|
1226
|
-
var TENANT_CONTEXT_CACHE_TTL_MS = 6e4;
|
|
1227
|
-
var cache = /* @__PURE__ */ new Map();
|
|
1228
1584
|
function getTenantContextPath(includeCounts) {
|
|
1229
1585
|
return includeCounts ? "/api/tenants/context?counts=true" : "/api/tenants/context";
|
|
1230
1586
|
}
|
|
1231
|
-
function getCachedTenantContext(cacheKey) {
|
|
1232
|
-
const cached = cache.get(cacheKey);
|
|
1233
|
-
if (!cached || cached.expiry <= Date.now()) return void 0;
|
|
1234
|
-
return cached.data;
|
|
1235
|
-
}
|
|
1236
1587
|
async function getTenantContext(includeCounts = false) {
|
|
1237
1588
|
const apiKey = resolveApiKey();
|
|
1238
|
-
const cacheKey = resolveAuthCacheKey(apiKey);
|
|
1239
|
-
if (!includeCounts) {
|
|
1240
|
-
const cached = getCachedTenantContext(cacheKey);
|
|
1241
|
-
if (cached) return cached;
|
|
1242
|
-
}
|
|
1243
1589
|
const data = await consoleGet(
|
|
1244
1590
|
getTenantContextPath(includeCounts),
|
|
1245
1591
|
apiKey
|
|
1246
1592
|
);
|
|
1247
|
-
|
|
1248
|
-
cache.set(cacheKey, {
|
|
1249
|
-
data,
|
|
1250
|
-
expiry: Date.now() + TENANT_CONTEXT_CACHE_TTL_MS
|
|
1251
|
-
});
|
|
1252
|
-
}
|
|
1253
|
-
return data;
|
|
1254
|
-
}
|
|
1255
|
-
function invalidateTenantContextCache() {
|
|
1256
|
-
cache.clear();
|
|
1593
|
+
return tenantContextResponseSchema.parse(data);
|
|
1257
1594
|
}
|
|
1258
1595
|
|
|
1259
1596
|
// src/tools/get-tenant-context.ts
|
|
1260
|
-
var
|
|
1261
|
-
|
|
1262
|
-
};
|
|
1263
|
-
var metadata28 = {
|
|
1597
|
+
var schema23 = tenantContextToolInputSchema.shape;
|
|
1598
|
+
var metadata23 = {
|
|
1264
1599
|
name: "get-tenant-context",
|
|
1265
1600
|
description: "Get current tenant features, active collections, and field visibility. Call this at the start of every session. Use includeCounts=true to also get per-collection document counts for setup diagnostics.",
|
|
1266
1601
|
annotations: {
|
|
@@ -1270,7 +1605,9 @@ var metadata28 = {
|
|
|
1270
1605
|
idempotentHint: true
|
|
1271
1606
|
}
|
|
1272
1607
|
};
|
|
1273
|
-
async function handler({
|
|
1608
|
+
async function handler({
|
|
1609
|
+
includeCounts
|
|
1610
|
+
}) {
|
|
1274
1611
|
try {
|
|
1275
1612
|
const ctx = await getTenantContext(includeCounts);
|
|
1276
1613
|
const lines = [
|
|
@@ -1323,11 +1660,10 @@ async function handler({ includeCounts }) {
|
|
|
1323
1660
|
}
|
|
1324
1661
|
}
|
|
1325
1662
|
if (ctx.config) {
|
|
1663
|
+
lines.push("", "## Config Status");
|
|
1326
1664
|
lines.push(
|
|
1327
|
-
""
|
|
1328
|
-
"## Config Status"
|
|
1665
|
+
`- Webhook configured: ${ctx.config.webhookConfigured ? "Yes" : "No"}`
|
|
1329
1666
|
);
|
|
1330
|
-
lines.push(`- Webhook configured: ${ctx.config.webhookConfigured ? "Yes" : "No"}`);
|
|
1331
1667
|
}
|
|
1332
1668
|
return toolSuccess({ context: lines.join("\n") });
|
|
1333
1669
|
} catch (error) {
|
|
@@ -1336,21 +1672,15 @@ async function handler({ includeCounts }) {
|
|
|
1336
1672
|
}
|
|
1337
1673
|
|
|
1338
1674
|
// src/tools/list-configurable-fields.ts
|
|
1339
|
-
import { z as
|
|
1675
|
+
import { z as z22 } from "zod";
|
|
1340
1676
|
|
|
1341
1677
|
// src/lib/field-config.ts
|
|
1342
|
-
var cache2 = /* @__PURE__ */ new Map();
|
|
1343
|
-
var CACHE_TTL = 6e4;
|
|
1344
1678
|
async function fetchFieldConfigs() {
|
|
1345
1679
|
const apiKey = resolveApiKey();
|
|
1346
|
-
const cacheKey = resolveAuthCacheKey(apiKey);
|
|
1347
|
-
const cached = cache2.get(cacheKey);
|
|
1348
|
-
if (cached && cached.expiry > Date.now()) return cached.data;
|
|
1349
1680
|
const data = await consoleGet(
|
|
1350
1681
|
"/api/field-configs/list",
|
|
1351
1682
|
apiKey
|
|
1352
1683
|
);
|
|
1353
|
-
cache2.set(cacheKey, { data, expiry: Date.now() + CACHE_TTL });
|
|
1354
1684
|
return data;
|
|
1355
1685
|
}
|
|
1356
1686
|
async function saveFieldConfig(body) {
|
|
@@ -1362,16 +1692,15 @@ async function saveFieldConfig(body) {
|
|
|
1362
1692
|
);
|
|
1363
1693
|
}
|
|
1364
1694
|
function invalidateFieldConfigCache() {
|
|
1365
|
-
cache2.clear();
|
|
1366
1695
|
}
|
|
1367
1696
|
|
|
1368
1697
|
// src/tools/list-configurable-fields.ts
|
|
1369
|
-
var
|
|
1370
|
-
collection:
|
|
1698
|
+
var schema24 = {
|
|
1699
|
+
collection: z22.string().optional().describe(
|
|
1371
1700
|
"Filter by collection slug (optional \u2014 returns all if omitted). Use this filter to reduce response size when you know which collection to check."
|
|
1372
1701
|
)
|
|
1373
1702
|
};
|
|
1374
|
-
var
|
|
1703
|
+
var metadata24 = {
|
|
1375
1704
|
name: "list-configurable-fields",
|
|
1376
1705
|
description: "List all configurable fields for tenant collections with current visibility state. Shows which fields can be shown/hidden and their current status. Returns all collections including inactive features \u2014 cross-reference with get-tenant-context for active features. Response includes ~300 fields across 47 collections \u2014 use collection filter when possible.",
|
|
1377
1706
|
annotations: {
|
|
@@ -1402,17 +1731,17 @@ async function listConfigurableFields(params) {
|
|
|
1402
1731
|
}
|
|
1403
1732
|
|
|
1404
1733
|
// src/tools/update-field-config.ts
|
|
1405
|
-
import { z as
|
|
1406
|
-
var
|
|
1407
|
-
collection:
|
|
1408
|
-
hiddenFields:
|
|
1734
|
+
import { z as z23 } from "zod";
|
|
1735
|
+
var schema25 = {
|
|
1736
|
+
collection: z23.string().min(1).describe("Collection slug (required)"),
|
|
1737
|
+
hiddenFields: z23.array(z23.string().min(1).max(200)).max(300).describe(
|
|
1409
1738
|
"Fields to hide (required). This is a FULL REPLACE \u2014 fields NOT in this list will be shown. Pass [] to show all fields. Use list-configurable-fields first to see available field paths."
|
|
1410
1739
|
),
|
|
1411
|
-
isHidden:
|
|
1740
|
+
isHidden: z23.boolean().optional().describe(
|
|
1412
1741
|
"Hide the entire collection from Admin Panel (optional). When true, individual hiddenFields are irrelevant."
|
|
1413
1742
|
)
|
|
1414
1743
|
};
|
|
1415
|
-
var
|
|
1744
|
+
var metadata25 = {
|
|
1416
1745
|
name: "update-field-config",
|
|
1417
1746
|
description: "Update field visibility configuration for a tenant collection. Hidden fields are removed from the Admin Panel UI. IMPORTANT: hiddenFields is a full replace, not a merge. Always call list-configurable-fields first to see current state.",
|
|
1418
1747
|
annotations: {
|
|
@@ -1430,7 +1759,6 @@ async function updateFieldConfig(params) {
|
|
|
1430
1759
|
isHidden: params.isHidden
|
|
1431
1760
|
});
|
|
1432
1761
|
invalidateFieldConfigCache();
|
|
1433
|
-
invalidateTenantContextCache();
|
|
1434
1762
|
return toolSuccess({
|
|
1435
1763
|
message: `Field config updated for '${params.collection}'`,
|
|
1436
1764
|
data: result
|
|
@@ -1441,7 +1769,7 @@ async function updateFieldConfig(params) {
|
|
|
1441
1769
|
}
|
|
1442
1770
|
|
|
1443
1771
|
// src/tools/sdk-get-recipe.ts
|
|
1444
|
-
import { z as
|
|
1772
|
+
import { z as z24 } from "zod";
|
|
1445
1773
|
|
|
1446
1774
|
// src/lib/sdk-recipes.ts
|
|
1447
1775
|
var recipes = {
|
|
@@ -1593,7 +1921,7 @@ const result = await client.collections.from('products').create({
|
|
|
1593
1921
|
"Returns result.doc (not the document directly)"
|
|
1594
1922
|
],
|
|
1595
1923
|
relatedResources: ["docs://sdk/query-builder"],
|
|
1596
|
-
relatedTools: ["
|
|
1924
|
+
relatedTools: ["query-collection", "get-collection-schema"]
|
|
1597
1925
|
}
|
|
1598
1926
|
},
|
|
1599
1927
|
"update-item": {
|
|
@@ -1622,7 +1950,7 @@ const result = await client.collections.from('products').update('product-id', {
|
|
|
1622
1950
|
"Partial updates are supported \u2014 omitted fields retain their current value"
|
|
1623
1951
|
],
|
|
1624
1952
|
relatedResources: ["docs://sdk/query-builder"],
|
|
1625
|
-
relatedTools: ["
|
|
1953
|
+
relatedTools: ["get-collection-by-id", "get-collection-schema"]
|
|
1626
1954
|
}
|
|
1627
1955
|
},
|
|
1628
1956
|
"delete-item": {
|
|
@@ -1646,7 +1974,7 @@ console.log('Deleted:', deleted.title)`,
|
|
|
1646
1974
|
"Throws if the item does not exist"
|
|
1647
1975
|
],
|
|
1648
1976
|
relatedResources: ["docs://sdk/query-builder"],
|
|
1649
|
-
relatedTools: ["
|
|
1977
|
+
relatedTools: ["get-collection-by-id", "query-collection"]
|
|
1650
1978
|
}
|
|
1651
1979
|
},
|
|
1652
1980
|
"infinite-scroll": {
|
|
@@ -1760,18 +2088,13 @@ const client = createClient({
|
|
|
1760
2088
|
})
|
|
1761
2089
|
|
|
1762
2090
|
// --- Register ---
|
|
1763
|
-
const { customer
|
|
2091
|
+
const { customer } = await client.customer.register({
|
|
1764
2092
|
name: 'Jane Doe',
|
|
1765
2093
|
email: 'jane@example.com',
|
|
1766
2094
|
password: 'securePassword123',
|
|
1767
2095
|
phone: '+821012345678', // optional
|
|
1768
2096
|
})
|
|
1769
2097
|
|
|
1770
|
-
if (verificationRequired) {
|
|
1771
|
-
// Tenant has requireEmailVerification enabled.
|
|
1772
|
-
// Token delivered via webhook \u2014 prompt user to check email.
|
|
1773
|
-
}
|
|
1774
|
-
|
|
1775
2098
|
// --- Login ---
|
|
1776
2099
|
const { token, customer: loggedIn } = await client.customer.login({
|
|
1777
2100
|
email: 'jane@example.com',
|
|
@@ -1792,9 +2115,9 @@ await client.customer.forgotPassword('jane@example.com') // sends token via webh
|
|
|
1792
2115
|
await client.customer.resetPassword(token, 'newPassword123')`,
|
|
1793
2116
|
cautions: [
|
|
1794
2117
|
"customer.register/login/me are only available on Client (not ServerClient)",
|
|
1795
|
-
"
|
|
2118
|
+
"registration creates a local customer account; add app-level verification if your project requires it",
|
|
1796
2119
|
"updateProfile only accepts name, phone, and marketingConsent \u2014 not email or password",
|
|
1797
|
-
"forgotPassword sends the token
|
|
2120
|
+
"forgotPassword sends the token to configured tenant webhooks; your webhook handler owns email/SMS delivery"
|
|
1798
2121
|
],
|
|
1799
2122
|
relatedResources: ["docs://sdk/customer-auth", "docs://sdk/getting-started"],
|
|
1800
2123
|
relatedTools: []
|
|
@@ -1828,7 +2151,7 @@ const result = await client.collections.from('images').create(formData as unknow
|
|
|
1828
2151
|
"Always set alt text for accessibility"
|
|
1829
2152
|
],
|
|
1830
2153
|
relatedResources: ["docs://sdk/query-builder"],
|
|
1831
|
-
relatedTools: ["
|
|
2154
|
+
relatedTools: ["query-collection", "get-collection-schema"]
|
|
1832
2155
|
}
|
|
1833
2156
|
},
|
|
1834
2157
|
"bulk-operations": {
|
|
@@ -1864,7 +2187,7 @@ const removed = await client.collections.from('products').removeMany(
|
|
|
1864
2187
|
"Very broad where clauses (or empty) will affect all documents in the collection"
|
|
1865
2188
|
],
|
|
1866
2189
|
relatedResources: ["docs://sdk/query-builder"],
|
|
1867
|
-
relatedTools: ["
|
|
2190
|
+
relatedTools: ["query-collection", "get-collection-schema"]
|
|
1868
2191
|
}
|
|
1869
2192
|
}
|
|
1870
2193
|
};
|
|
@@ -1878,8 +2201,8 @@ function getRecipe(goal, runtime = "both") {
|
|
|
1878
2201
|
}
|
|
1879
2202
|
|
|
1880
2203
|
// src/tools/sdk-get-recipe.ts
|
|
1881
|
-
var
|
|
1882
|
-
goal:
|
|
2204
|
+
var schema26 = {
|
|
2205
|
+
goal: z24.enum([
|
|
1883
2206
|
"fetch-list",
|
|
1884
2207
|
"fetch-by-id",
|
|
1885
2208
|
"create-item",
|
|
@@ -1891,11 +2214,11 @@ var schema31 = {
|
|
|
1891
2214
|
"file-upload",
|
|
1892
2215
|
"bulk-operations"
|
|
1893
2216
|
]).describe("What the user wants to accomplish"),
|
|
1894
|
-
runtime:
|
|
1895
|
-
collection:
|
|
1896
|
-
includeExample:
|
|
2217
|
+
runtime: z24.enum(["browser", "server", "both"]).default("both").describe("Target runtime environment"),
|
|
2218
|
+
collection: z24.string().optional().describe("Specific collection name if applicable"),
|
|
2219
|
+
includeExample: z24.boolean().default(true).describe("Whether to include a full code example")
|
|
1897
2220
|
};
|
|
1898
|
-
var
|
|
2221
|
+
var metadata26 = {
|
|
1899
2222
|
name: "sdk-get-recipe",
|
|
1900
2223
|
description: "Get a complete SDK code recipe for a specific task. Returns recommended approach, code example, and related documentation links. Use this FIRST when the user asks how to do something with the SDK.",
|
|
1901
2224
|
annotations: {
|
|
@@ -1938,7 +2261,7 @@ function handler2({
|
|
|
1938
2261
|
}
|
|
1939
2262
|
|
|
1940
2263
|
// src/tools/sdk-search-docs.ts
|
|
1941
|
-
import { z as
|
|
2264
|
+
import { z as z25 } from "zod";
|
|
1942
2265
|
|
|
1943
2266
|
// src/lib/sdk-doc-index.ts
|
|
1944
2267
|
var docIndex = [
|
|
@@ -2040,8 +2363,8 @@ var docIndex = [
|
|
|
2040
2363
|
// Customer Auth
|
|
2041
2364
|
{
|
|
2042
2365
|
title: "Customer Auth \u2014 Login and Register",
|
|
2043
|
-
keywords: ["customer", "login", "register", "auth", "authentication", "customer auth"
|
|
2044
|
-
summary: "client.customer.login({ email, password }) and register({ name, email, password }).
|
|
2366
|
+
keywords: ["customer", "login", "register", "auth", "authentication", "customer auth"],
|
|
2367
|
+
summary: "client.customer.login({ email, password }) and register({ name, email, password }).",
|
|
2045
2368
|
resourceUri: "docs://sdk/customer-auth"
|
|
2046
2369
|
},
|
|
2047
2370
|
{
|
|
@@ -2067,7 +2390,7 @@ var docIndex = [
|
|
|
2067
2390
|
{
|
|
2068
2391
|
title: "Webhooks",
|
|
2069
2392
|
keywords: ["webhook", "hmac", "signature", "WEBHOOK_SECRET", "server-to-server", "event"],
|
|
2070
|
-
summary: "Tenant webhooks deliver server-to-server events
|
|
2393
|
+
summary: "Tenant webhooks deliver server-to-server events such as password reset tokens. Signed with HMAC-SHA256 using PAYLOAD_SECRET.",
|
|
2071
2394
|
resourceUri: "docs://sdk/webhook"
|
|
2072
2395
|
},
|
|
2073
2396
|
// Order API
|
|
@@ -2113,11 +2436,11 @@ function searchDocs(query, limit = 5) {
|
|
|
2113
2436
|
}
|
|
2114
2437
|
|
|
2115
2438
|
// src/tools/sdk-search-docs.ts
|
|
2116
|
-
var
|
|
2117
|
-
query:
|
|
2118
|
-
limit:
|
|
2439
|
+
var schema27 = {
|
|
2440
|
+
query: z25.string().min(2).describe('Search keyword or phrase (e.g. "infinite scroll", "webhook", "customer login")'),
|
|
2441
|
+
limit: z25.number().min(1).max(10).default(5).describe("Maximum results to return (1-10, default: 5)")
|
|
2119
2442
|
};
|
|
2120
|
-
var
|
|
2443
|
+
var metadata27 = {
|
|
2121
2444
|
name: "sdk-search-docs",
|
|
2122
2445
|
description: "Search SDK documentation by keyword. Returns matching topics with summaries and resource links. Use when looking for specific SDK features or patterns.",
|
|
2123
2446
|
annotations: {
|
|
@@ -2152,20 +2475,20 @@ function handler3({
|
|
|
2152
2475
|
}
|
|
2153
2476
|
|
|
2154
2477
|
// src/tools/sdk-get-auth-setup.ts
|
|
2155
|
-
import { z as
|
|
2156
|
-
var
|
|
2157
|
-
scenario:
|
|
2478
|
+
import { z as z26 } from "zod";
|
|
2479
|
+
var schema28 = {
|
|
2480
|
+
scenario: z26.enum([
|
|
2158
2481
|
"browser-client",
|
|
2159
2482
|
"server-client",
|
|
2160
2483
|
"customer-auth",
|
|
2161
2484
|
"mcp-connection",
|
|
2162
|
-
"
|
|
2485
|
+
"server-credentials",
|
|
2163
2486
|
"webhook-verification"
|
|
2164
2487
|
]).describe("Authentication scenario")
|
|
2165
2488
|
};
|
|
2166
|
-
var
|
|
2489
|
+
var metadata28 = {
|
|
2167
2490
|
name: "sdk-get-auth-setup",
|
|
2168
|
-
description: "Get the
|
|
2491
|
+
description: "Get the current authentication setup for a specific scenario. Returns env var names, code snippets, and security notes.",
|
|
2169
2492
|
annotations: {
|
|
2170
2493
|
title: "Get Auth Setup",
|
|
2171
2494
|
readOnlyHint: true,
|
|
@@ -2198,15 +2521,14 @@ const { data } = client.query.useQuery({ collection: 'products' })`,
|
|
|
2198
2521
|
|
|
2199
2522
|
const client = createServerClient({
|
|
2200
2523
|
publishableKey: process.env.SOFTWARE_PUBLISHABLE_KEY!,
|
|
2201
|
-
secretKey: process.env.SOFTWARE_SECRET_KEY!
|
|
2524
|
+
secretKey: process.env.SOFTWARE_SECRET_KEY!
|
|
2202
2525
|
})
|
|
2203
2526
|
|
|
2204
2527
|
// Full CRUD operations
|
|
2205
2528
|
const result = await client.collections.from('products').create({ title: 'New Product' })`,
|
|
2206
2529
|
notes: [
|
|
2207
|
-
"ServerClient has full CRUD access
|
|
2208
|
-
"
|
|
2209
|
-
"Browser-based CLI/init login flows may provision a user-scoped PAT (pat01_...) with a default tenant",
|
|
2530
|
+
"ServerClient has full CRUD access and must run only in trusted server code",
|
|
2531
|
+
"Store server credentials in environment variables and rotate them from the Console",
|
|
2210
2532
|
"Use in API routes, server actions, or backend services only",
|
|
2211
2533
|
"React Query hooks available for reads (useQuery, prefetchQuery, etc.) + mutations (useCreate, useUpdate, useRemove)"
|
|
2212
2534
|
]
|
|
@@ -2238,90 +2560,68 @@ client.customer.isAuthenticated()`,
|
|
|
2238
2560
|
notes: [
|
|
2239
2561
|
"Customer auth uses the browser Client (not ServerClient)",
|
|
2240
2562
|
"JWT tokens are managed automatically by the SDK",
|
|
2241
|
-
"
|
|
2563
|
+
"Registration creates a local customer account; add application-level verification if needed"
|
|
2242
2564
|
]
|
|
2243
2565
|
},
|
|
2244
2566
|
"mcp-connection": {
|
|
2245
2567
|
title: "MCP Server Connection",
|
|
2246
|
-
envVars: [
|
|
2568
|
+
envVars: [],
|
|
2247
2569
|
code: `# Claude Code
|
|
2248
|
-
claude mcp add --transport http
|
|
2249
|
-
--header "x-api-key: $SOFTWARE_SECRET_KEY" \\
|
|
2250
|
-
--header "x-publishable-key: $SOFTWARE_PUBLISHABLE_KEY" \\
|
|
2251
|
-
01software https://mcp.01.software/mcp
|
|
2570
|
+
claude mcp add --transport http 01software https://mcp.01.software/mcp
|
|
2252
2571
|
|
|
2253
|
-
# Codex
|
|
2572
|
+
# Codex .codex/config.toml
|
|
2254
2573
|
[mcp_servers.01software]
|
|
2255
2574
|
url = "https://mcp.01.software/mcp"
|
|
2256
2575
|
|
|
2257
|
-
|
|
2258
|
-
x-api-key = "SOFTWARE_SECRET_KEY"
|
|
2259
|
-
x-publishable-key = "SOFTWARE_PUBLISHABLE_KEY"
|
|
2260
|
-
|
|
2261
|
-
# Or use .mcp.json
|
|
2576
|
+
# Or use JSON clients that support OAuth discovery
|
|
2262
2577
|
{
|
|
2263
2578
|
"mcpServers": {
|
|
2264
2579
|
"01software": {
|
|
2265
2580
|
"type": "http",
|
|
2266
|
-
"url": "https://mcp.01.software/mcp"
|
|
2267
|
-
"headers": {
|
|
2268
|
-
"x-api-key": "\${env:SOFTWARE_SECRET_KEY}",
|
|
2269
|
-
"x-publishable-key": "\${env:SOFTWARE_PUBLISHABLE_KEY}"
|
|
2270
|
-
}
|
|
2581
|
+
"url": "https://mcp.01.software/mcp"
|
|
2271
2582
|
}
|
|
2272
2583
|
}
|
|
2273
2584
|
}`,
|
|
2274
2585
|
notes: [
|
|
2275
|
-
"MCP
|
|
2276
|
-
"
|
|
2277
|
-
"
|
|
2278
|
-
"Use tenant API keys for shared service integrations; PATs are useful for user-scoped local workflows",
|
|
2279
|
-
"Never commit raw bearer tokens to repo-local MCP config; prefer environment interpolation, client prompts, OS secret managers, or ignored local files",
|
|
2280
|
-
"Avoid passing real tokens directly on shared-machine command lines because shell history and process listings can expose them",
|
|
2281
|
-
"stdio transport: use `npx @01.software/cli mcp` with SOFTWARE_PUBLISHABLE_KEY and SOFTWARE_SECRET_KEY env vars"
|
|
2586
|
+
"HTTP MCP uses OAuth discovery and Authorization Code + PKCE",
|
|
2587
|
+
"Clients that cannot complete OAuth discovery are unsupported until a smoke test proves compatibility",
|
|
2588
|
+
"stdio transport remains a local CLI path and is separate from HTTP MCP OAuth discovery"
|
|
2282
2589
|
]
|
|
2283
2590
|
},
|
|
2284
|
-
"
|
|
2285
|
-
title: "
|
|
2591
|
+
"server-credentials": {
|
|
2592
|
+
title: "Server Credential Management",
|
|
2286
2593
|
envVars: ["SOFTWARE_PUBLISHABLE_KEY", "SOFTWARE_SECRET_KEY"],
|
|
2287
|
-
code: `#
|
|
2288
|
-
#
|
|
2289
|
-
# The generated key has the format: sk01_{40hex}
|
|
2290
|
-
# Copy the publishable key from the same tenant.
|
|
2594
|
+
code: `# Server credentials are managed from the Console, not in code.
|
|
2595
|
+
# Copy both values from the same tenant.
|
|
2291
2596
|
|
|
2292
|
-
# Use them together for
|
|
2293
|
-
export SOFTWARE_PUBLISHABLE_KEY=
|
|
2597
|
+
# Use them together for CLI and server SDK calls.
|
|
2598
|
+
export SOFTWARE_PUBLISHABLE_KEY=pk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
|
2294
2599
|
export SOFTWARE_SECRET_KEY=sk01_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`,
|
|
2295
2600
|
notes: [
|
|
2296
|
-
"API keys are sk01_{40hex} opaque bearer tokens",
|
|
2297
2601
|
"The matching SOFTWARE_PUBLISHABLE_KEY is still required for tenant routing, rate limits, and quota enforcement",
|
|
2298
|
-
"
|
|
2299
|
-
"
|
|
2300
|
-
"Generate keys from Console > Settings > API Keys \u2014 never derive them in code"
|
|
2602
|
+
"Used for REST/SDK authentication in trusted server contexts",
|
|
2603
|
+
"Manage credentials from the Console and rotate them on exposure"
|
|
2301
2604
|
]
|
|
2302
2605
|
},
|
|
2303
2606
|
"webhook-verification": {
|
|
2304
2607
|
title: "Webhook Verification",
|
|
2305
2608
|
envVars: ["WEBHOOK_SECRET"],
|
|
2306
|
-
code: `import { handleWebhook } from '@01.software/sdk/webhook'
|
|
2609
|
+
code: `import { handleWebhook, createCustomerAuthWebhookHandler } from '@01.software/sdk/webhook'
|
|
2610
|
+
|
|
2611
|
+
const customerAuthHandler = createCustomerAuthWebhookHandler({
|
|
2612
|
+
passwordReset: sendPasswordResetEmail,
|
|
2613
|
+
})
|
|
2307
2614
|
|
|
2308
2615
|
export async function POST(request: Request) {
|
|
2309
|
-
return handleWebhook(request,
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
case 'verification':
|
|
2313
|
-
await sendVerificationEmail(event.data)
|
|
2314
|
-
break
|
|
2315
|
-
case 'password-reset':
|
|
2316
|
-
await sendPasswordResetEmail(event.data)
|
|
2317
|
-
break
|
|
2318
|
-
}
|
|
2319
|
-
}, { secret: process.env.WEBHOOK_SECRET! })
|
|
2616
|
+
return handleWebhook(request, customerAuthHandler, {
|
|
2617
|
+
secret: process.env.WEBHOOK_SECRET!,
|
|
2618
|
+
})
|
|
2320
2619
|
}`,
|
|
2321
2620
|
notes: [
|
|
2322
2621
|
"handleWebhook() takes (request, handler, options) \u2014 handler receives the parsed event",
|
|
2323
2622
|
"WEBHOOK_SECRET is set per-tenant in Console > Settings",
|
|
2324
|
-
"handleWebhook() verifies HMAC-SHA256 signature automatically before calling handler"
|
|
2623
|
+
"handleWebhook() verifies HMAC-SHA256 signature automatically before calling handler",
|
|
2624
|
+
"createCustomerAuthWebhookHandler() is optional; it just routes auth events to your own email/SMS delivery code"
|
|
2325
2625
|
]
|
|
2326
2626
|
}
|
|
2327
2627
|
};
|
|
@@ -2340,14 +2640,14 @@ function handler4({
|
|
|
2340
2640
|
}
|
|
2341
2641
|
|
|
2342
2642
|
// src/tools/sdk-get-collection-pattern.ts
|
|
2343
|
-
import { z as
|
|
2344
|
-
import { COLLECTIONS as
|
|
2345
|
-
var
|
|
2346
|
-
collection:
|
|
2347
|
-
operation:
|
|
2348
|
-
surface:
|
|
2643
|
+
import { z as z27 } from "zod";
|
|
2644
|
+
import { COLLECTIONS as COLLECTIONS4 } from "@01.software/sdk";
|
|
2645
|
+
var schema29 = {
|
|
2646
|
+
collection: z27.enum(COLLECTIONS4).describe("Collection name"),
|
|
2647
|
+
operation: z27.enum(["read", "write", "full-crud"]).default("read").describe("What operations are needed"),
|
|
2648
|
+
surface: z27.enum(["query-builder", "react-query", "server-api"]).default("query-builder").describe("Preferred API surface")
|
|
2349
2649
|
};
|
|
2350
|
-
var
|
|
2650
|
+
var metadata29 = {
|
|
2351
2651
|
name: "sdk-get-collection-pattern",
|
|
2352
2652
|
description: "Get the recommended CRUD pattern for a specific collection. Returns code examples for the chosen API surface and operation type.",
|
|
2353
2653
|
annotations: {
|
|
@@ -2514,7 +2814,6 @@ function handler5({
|
|
|
2514
2814
|
relatedTools: [
|
|
2515
2815
|
"query-collection",
|
|
2516
2816
|
"get-collection-by-id",
|
|
2517
|
-
...operation !== "read" ? ["create-collection", "update-collection", "delete-collection"] : [],
|
|
2518
2817
|
"get-collection-schema"
|
|
2519
2818
|
],
|
|
2520
2819
|
relatedResources: [
|
|
@@ -2528,14 +2827,14 @@ function handler5({
|
|
|
2528
2827
|
}
|
|
2529
2828
|
|
|
2530
2829
|
// src/prompts/sdk-usage-guide.ts
|
|
2531
|
-
import { z as
|
|
2532
|
-
var
|
|
2533
|
-
goal:
|
|
2534
|
-
runtime:
|
|
2535
|
-
surface:
|
|
2536
|
-
collection:
|
|
2830
|
+
import { z as z28 } from "zod";
|
|
2831
|
+
var schema30 = {
|
|
2832
|
+
goal: z28.string().describe('What the user wants to accomplish (e.g., "query product list", "create order")'),
|
|
2833
|
+
runtime: z28.enum(["browser", "server"]).optional().describe("Target runtime: browser (React/Next.js client) or server (Node.js)"),
|
|
2834
|
+
surface: z28.enum(["query-builder", "react-query", "customer-api", "server-api"]).optional().describe("Preferred API surface"),
|
|
2835
|
+
collection: z28.string().optional().describe("Specific collection if relevant")
|
|
2537
2836
|
};
|
|
2538
|
-
var
|
|
2837
|
+
var metadata30 = {
|
|
2539
2838
|
name: "sdk-usage-guide",
|
|
2540
2839
|
title: "SDK Usage Guide",
|
|
2541
2840
|
description: "Provides guidance on how to perform a specific task using the 01.software SDK",
|
|
@@ -2632,8 +2931,8 @@ await client.collections.from('products').remove('id')
|
|
|
2632
2931
|
const { totalDocs } = await client.collections.from('products').count()
|
|
2633
2932
|
|
|
2634
2933
|
// Metadata - generate Next.js Metadata from collection fields
|
|
2635
|
-
// Auto-maps per-collection fields (e.g.
|
|
2636
|
-
const
|
|
2934
|
+
// Auto-maps per-collection fields (e.g. articles: description\u2192description, thumbnail\u2192image)
|
|
2935
|
+
const articleMeta = await client.collections.from('articles').findMetadataById(id, { siteName: 'My Blog' })
|
|
2637
2936
|
const productMeta = await client.collections.from('products').findMetadata(
|
|
2638
2937
|
{ where: { slug: { equals: 'my-product' } } },
|
|
2639
2938
|
{ siteName: 'My Store' }
|
|
@@ -2672,14 +2971,14 @@ You can perform the "${goal}" task by following the patterns above.`;
|
|
|
2672
2971
|
}
|
|
2673
2972
|
|
|
2674
2973
|
// src/prompts/collection-query-help.ts
|
|
2675
|
-
import { z as
|
|
2676
|
-
import { COLLECTIONS as
|
|
2677
|
-
var
|
|
2678
|
-
collection:
|
|
2679
|
-
operation:
|
|
2680
|
-
filters:
|
|
2974
|
+
import { z as z29 } from "zod";
|
|
2975
|
+
import { COLLECTIONS as COLLECTIONS5 } from "@01.software/sdk";
|
|
2976
|
+
var schema31 = {
|
|
2977
|
+
collection: z29.enum(COLLECTIONS5).describe("Collection name"),
|
|
2978
|
+
operation: z29.enum(["find", "create", "update", "delete"]).describe("Operation to perform (find, create, update, delete)"),
|
|
2979
|
+
filters: z29.string().optional().describe("Filter conditions (JSON string, optional)")
|
|
2681
2980
|
};
|
|
2682
|
-
var
|
|
2981
|
+
var metadata31 = {
|
|
2683
2982
|
name: "collection-query-help",
|
|
2684
2983
|
title: "Collection Query Help",
|
|
2685
2984
|
description: "Provides guidance on how to write queries for a specific collection",
|
|
@@ -2766,16 +3065,16 @@ ${operation === "find" ? `- Use \`where\` option for filtering (Payload query sy
|
|
|
2766
3065
|
}
|
|
2767
3066
|
|
|
2768
3067
|
// src/prompts/order-flow-guide.ts
|
|
2769
|
-
import { z as
|
|
2770
|
-
var
|
|
2771
|
-
scenario:
|
|
3068
|
+
import { z as z30 } from "zod";
|
|
3069
|
+
var schema32 = {
|
|
3070
|
+
scenario: z30.enum([
|
|
2772
3071
|
"simple-order",
|
|
2773
3072
|
"cart-checkout",
|
|
2774
3073
|
"return-refund",
|
|
2775
3074
|
"fulfillment-tracking"
|
|
2776
3075
|
]).describe("Order flow scenario")
|
|
2777
3076
|
};
|
|
2778
|
-
var
|
|
3077
|
+
var metadata32 = {
|
|
2779
3078
|
name: "order-flow-guide",
|
|
2780
3079
|
title: "Order Flow Guide",
|
|
2781
3080
|
description: "Provides step-by-step guidance for ecommerce order flows including creation, checkout, returns, and fulfillment.",
|
|
@@ -2790,8 +3089,8 @@ var SCENARIOS = {
|
|
|
2790
3089
|
- Provide: orderNumber, customerSnapshot (email required), shippingAddress, orderItems, totalAmount
|
|
2791
3090
|
- Optional: pgPaymentId (omit for free orders), shippingAmount, discountCode
|
|
2792
3091
|
|
|
2793
|
-
2. **Payment Confirmation** \u2192 \`update-
|
|
2794
|
-
-
|
|
3092
|
+
2. **Payment Confirmation** \u2192 \`update-transaction\` tool
|
|
3093
|
+
- Confirm provider payment with pgPaymentId, paymentKey, and amount
|
|
2795
3094
|
- Stock is automatically adjusted (stock -= qty, reservedStock += qty)
|
|
2796
3095
|
|
|
2797
3096
|
3. **Fulfillment** \u2192 \`create-fulfillment\` tool
|
|
@@ -2818,8 +3117,13 @@ const order = await client.commerce.orders.create({
|
|
|
2818
3117
|
pgPaymentId: 'pay_xxx' // omit for free orders
|
|
2819
3118
|
})
|
|
2820
3119
|
|
|
2821
|
-
// 2. After payment confirmed
|
|
2822
|
-
await client.commerce.orders.
|
|
3120
|
+
// 2. After payment confirmed by provider
|
|
3121
|
+
await client.commerce.orders.updateTransaction({
|
|
3122
|
+
pgPaymentId: 'pay_xxx',
|
|
3123
|
+
status: 'paid',
|
|
3124
|
+
paymentKey: 'payment_key_xxx',
|
|
3125
|
+
amount: 59800
|
|
3126
|
+
})
|
|
2823
3127
|
|
|
2824
3128
|
// 3. Ship items
|
|
2825
3129
|
await client.commerce.orders.createFulfillment({
|
|
@@ -2837,7 +3141,7 @@ await client.commerce.orders.createFulfillment({
|
|
|
2837
3141
|
2. **Apply Discount** (optional) \u2192 \`apply-discount\` tool
|
|
2838
3142
|
3. **Calculate Shipping** \u2192 \`calculate-shipping\` tool
|
|
2839
3143
|
4. **Checkout** \u2192 \`checkout\` tool (converts cart to order)
|
|
2840
|
-
5. **Payment** \u2192 \`update-
|
|
3144
|
+
5. **Payment** \u2192 \`update-transaction\` for provider-verified paid transitions
|
|
2841
3145
|
|
|
2842
3146
|
### Key Points
|
|
2843
3147
|
- Cart has a customer linked \u2014 auto-copied to order on checkout
|
|
@@ -2874,7 +3178,7 @@ const order = await client.commerce.orders.checkout({
|
|
|
2874
3178
|
1. **Return with Refund** \u2192 \`return-with-refund\` tool
|
|
2875
3179
|
- Handles return + stock restoration + transaction update in one call
|
|
2876
3180
|
- Return immediately completed (bypasses FSM)
|
|
2877
|
-
- Requires pgPaymentId
|
|
3181
|
+
- Requires pgPaymentId and paymentKey for provider-verified refund
|
|
2878
3182
|
|
|
2879
3183
|
### Key Points
|
|
2880
3184
|
- Full refund: original transaction \u2192 \`canceled\`
|
|
@@ -2891,7 +3195,8 @@ await client.commerce.orders.returnWithRefund({
|
|
|
2891
3195
|
reasonDetail: 'Product arrived damaged',
|
|
2892
3196
|
returnItems: [{ orderItem: 'oi-id', quantity: 1 }],
|
|
2893
3197
|
refundAmount: 29900,
|
|
2894
|
-
pgPaymentId: 'pay_xxx'
|
|
3198
|
+
pgPaymentId: 'pay_xxx',
|
|
3199
|
+
paymentKey: 'payment_key_xxx'
|
|
2895
3200
|
})
|
|
2896
3201
|
\`\`\``,
|
|
2897
3202
|
"fulfillment-tracking": `## Fulfillment & Tracking
|
|
@@ -2954,12 +3259,12 @@ ${SCENARIOS[scenario] || "Unknown scenario."}
|
|
|
2954
3259
|
}
|
|
2955
3260
|
|
|
2956
3261
|
// src/prompts/feature-setup-guide.ts
|
|
2957
|
-
import { z as
|
|
2958
|
-
var
|
|
2959
|
-
feature:
|
|
3262
|
+
import { z as z31 } from "zod";
|
|
3263
|
+
var schema33 = {
|
|
3264
|
+
feature: z31.enum([
|
|
2960
3265
|
"ecommerce",
|
|
2961
3266
|
"customers",
|
|
2962
|
-
"
|
|
3267
|
+
"articles",
|
|
2963
3268
|
"documents",
|
|
2964
3269
|
"playlists",
|
|
2965
3270
|
"galleries",
|
|
@@ -2971,7 +3276,7 @@ var schema38 = {
|
|
|
2971
3276
|
"community"
|
|
2972
3277
|
]).describe("Feature to get setup guide for")
|
|
2973
3278
|
};
|
|
2974
|
-
var
|
|
3279
|
+
var metadata33 = {
|
|
2975
3280
|
name: "feature-setup-guide",
|
|
2976
3281
|
title: "Feature Setup Guide",
|
|
2977
3282
|
description: "Setup checklist and remediation guide for a tenant feature. Load before using get-tenant-context to diagnose setup gaps.",
|
|
@@ -2984,8 +3289,8 @@ var FEATURES = {
|
|
|
2984
3289
|
|
|
2985
3290
|
### Required Collections (count > 0)
|
|
2986
3291
|
|
|
2987
|
-
1. **products** \u2014
|
|
2988
|
-
- Minimum fields: \`{ title, slug, status: '
|
|
3292
|
+
1. **products** \u2014 Create via Console UI or SDK \`client.collections.from('products').create({ ... })\`
|
|
3293
|
+
- Minimum fields: \`{ title, slug, status: 'published', _status: 'published' }\`
|
|
2989
3294
|
|
|
2990
3295
|
2. **product-variants** \u2014 At least 1 sellable variant per product
|
|
2991
3296
|
- Minimum fields: \`{ product, title, price, stock }\`
|
|
@@ -3018,26 +3323,26 @@ customer-addresses
|
|
|
3018
3323
|
|
|
3019
3324
|
### Optional Collections
|
|
3020
3325
|
|
|
3021
|
-
customer-groups \u2014
|
|
3326
|
+
customer-groups \u2014 Create via Console UI or SDK \`client.collections.from('customer-groups').create({ title })\`
|
|
3022
3327
|
|
|
3023
3328
|
### Config
|
|
3024
3329
|
|
|
3025
|
-
-
|
|
3330
|
+
- Customer registration creates a local account; add app-level verification if needed
|
|
3026
3331
|
- Customer auth uses custom JWT (separate from Payload auth)`,
|
|
3027
|
-
|
|
3332
|
+
articles: `## Articles Setup Guide
|
|
3028
3333
|
|
|
3029
3334
|
### Required Collections (count > 0)
|
|
3030
3335
|
|
|
3031
|
-
1. **
|
|
3336
|
+
1. **articles** \u2014 At least 1 article
|
|
3032
3337
|
- Minimum fields: \`{ title, slug }\`
|
|
3033
3338
|
|
|
3034
|
-
2. **
|
|
3339
|
+
2. **article-authors** \u2014 At least 1 author
|
|
3035
3340
|
- Minimum fields: \`{ title, slug }\`
|
|
3036
|
-
- Link authors to
|
|
3341
|
+
- Link authors to articles via the \`authors\` relationship field
|
|
3037
3342
|
|
|
3038
3343
|
### Optional Collections
|
|
3039
3344
|
|
|
3040
|
-
|
|
3345
|
+
article-categories, article-tags`,
|
|
3041
3346
|
documents: `## Documents Setup Guide
|
|
3042
3347
|
|
|
3043
3348
|
### Required Collections (count > 0)
|
|
@@ -3057,10 +3362,10 @@ document-categories`,
|
|
|
3057
3362
|
### Required Collections (count > 0)
|
|
3058
3363
|
|
|
3059
3364
|
1. **playlists** \u2014 At least 1 playlist
|
|
3060
|
-
- Minimum fields: \`{ title, slug }\`
|
|
3365
|
+
- Minimum fields: \`{ title, slug, status: 'published', _status: 'published' }\`
|
|
3061
3366
|
|
|
3062
3367
|
2. **tracks** \u2014 At least 1 track
|
|
3063
|
-
- Minimum fields: \`{ title }\`
|
|
3368
|
+
- Minimum fields: \`{ title, sourceUrl, status: 'published', _status: 'published' }\`
|
|
3064
3369
|
|
|
3065
3370
|
3. **playlists.tracks** \u2014 Link at least 1 track from a playlist
|
|
3066
3371
|
- Minimum fields: \`{ tracks: [trackId] }\`
|
|
@@ -3073,11 +3378,11 @@ playlist-categories, playlist-tags, track-categories, track-tags, track-assets`,
|
|
|
3073
3378
|
### Required Collections (count > 0)
|
|
3074
3379
|
|
|
3075
3380
|
1. **galleries** \u2014 At least 1 gallery
|
|
3076
|
-
- Minimum fields: \`{ title, slug }\`
|
|
3381
|
+
- Minimum fields: \`{ title, slug, status: 'published', _status: 'published' }\`
|
|
3077
3382
|
|
|
3078
3383
|
2. **gallery-items** \u2014 At least 1 item per gallery
|
|
3079
3384
|
- References \`images\` collection (non-upload)
|
|
3080
|
-
- Minimum fields: \`{ gallery, image }\`
|
|
3385
|
+
- Minimum fields: \`{ gallery, image, _status: 'published' }\`
|
|
3081
3386
|
|
|
3082
3387
|
### Optional Collections
|
|
3083
3388
|
|
|
@@ -3087,7 +3392,7 @@ gallery-categories, gallery-tags`,
|
|
|
3087
3392
|
### Required Collections (count > 0)
|
|
3088
3393
|
|
|
3089
3394
|
1. **links** \u2014 At least 1 link
|
|
3090
|
-
- Minimum fields: \`{ title, slug, url }\`
|
|
3395
|
+
- Minimum fields: \`{ title, slug, url, status: 'published', _status: 'published' }\`
|
|
3091
3396
|
|
|
3092
3397
|
### Optional Collections
|
|
3093
3398
|
|
|
@@ -3147,7 +3452,7 @@ form-submissions \u2014 Auto-created when forms are submitted by end users`,
|
|
|
3147
3452
|
|
|
3148
3453
|
### Required Collections (count > 0)
|
|
3149
3454
|
|
|
3150
|
-
1. **
|
|
3455
|
+
1. **posts** \u2014 At least 1 post
|
|
3151
3456
|
- Minimum fields: \`{ title, slug }\`
|
|
3152
3457
|
|
|
3153
3458
|
2. **reaction-types** \u2014 At least 1 reaction type defined
|
|
@@ -3159,7 +3464,7 @@ comments, reactions, bookmarks, reports, community-bans
|
|
|
3159
3464
|
|
|
3160
3465
|
### Optional Collections
|
|
3161
3466
|
|
|
3162
|
-
|
|
3467
|
+
post-categories`
|
|
3163
3468
|
};
|
|
3164
3469
|
function featureSetupGuide({ feature }) {
|
|
3165
3470
|
return `# Feature Setup Guide: ${feature}
|
|
@@ -3168,12 +3473,12 @@ ${FEATURES[feature] || "Unknown feature."}
|
|
|
3168
3473
|
|
|
3169
3474
|
## Related MCP Tools
|
|
3170
3475
|
- \`get-tenant-context\` \u2014 check current collection counts and feature status
|
|
3171
|
-
- \`
|
|
3172
|
-
- \`
|
|
3476
|
+
- \`query-collection\` \u2014 verify existing documents in a collection
|
|
3477
|
+
- \`get-collection-schema\` \u2014 inspect tenant-aware fields before creating data via SDK or Console UI`;
|
|
3173
3478
|
}
|
|
3174
3479
|
|
|
3175
3480
|
// src/resources/(config)/app.ts
|
|
3176
|
-
var
|
|
3481
|
+
var metadata34 = {
|
|
3177
3482
|
name: "app-config",
|
|
3178
3483
|
title: "Application Config",
|
|
3179
3484
|
description: "01.software SDK and MCP server configuration information"
|
|
@@ -3188,35 +3493,20 @@ function handler6() {
|
|
|
3188
3493
|
|
|
3189
3494
|
## Authentication
|
|
3190
3495
|
|
|
3191
|
-
|
|
3496
|
+
HTTP MCP uses OAuth discovery and Authorization Code + PKCE.
|
|
3192
3497
|
|
|
3498
|
+
\`\`\`toml
|
|
3499
|
+
[mcp_servers.01software]
|
|
3500
|
+
url = "https://mcp.01.software/mcp"
|
|
3193
3501
|
\`\`\`
|
|
3194
|
-
x-api-key: <sk01_... or pat01_...>
|
|
3195
|
-
x-publishable-key: <pk01_...>
|
|
3196
|
-
\`\`\`
|
|
3197
|
-
|
|
3198
|
-
\`x-client-key\` is accepted as a legacy alias for \`x-publishable-key\`.
|
|
3199
3502
|
|
|
3200
|
-
|
|
3503
|
+
## Available Tools (29)
|
|
3201
3504
|
|
|
3202
|
-
- \`
|
|
3203
|
-
- \`pat01_{40hex}\` \u2014 personal access token for user-scoped local workflows
|
|
3505
|
+
> Generic write tools (create/update/delete/update-many/delete-many) are intentionally absent. Use the dedicated workflow tools below or the SDK (\`client.collections.from(slug).create()\` / \`update()\` / \`remove()\` / \`updateMany()\` / \`removeMany()\`) for stateful mutations.
|
|
3204
3506
|
|
|
3205
|
-
|
|
3206
|
-
SOFTWARE_SECRET_KEY=sk01_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
|
3207
|
-
SOFTWARE_PUBLISHABLE_KEY=pk01_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
|
3208
|
-
\`\`\`
|
|
3209
|
-
|
|
3210
|
-
## Available Tools (34)
|
|
3211
|
-
|
|
3212
|
-
### Generic CRUD (7)
|
|
3507
|
+
### Generic Read (2)
|
|
3213
3508
|
- \`query-collection\` - Query collection with filters, pagination, sorting
|
|
3214
3509
|
- \`get-collection-by-id\` - Get single item by ID
|
|
3215
|
-
- \`create-collection\` - Create new item
|
|
3216
|
-
- \`update-collection\` - Update existing item
|
|
3217
|
-
- \`delete-collection\` - Delete item (destructive)
|
|
3218
|
-
- \`update-many-collection\` - Bulk update items matching filter
|
|
3219
|
-
- \`delete-many-collection\` - Bulk delete items matching filter (destructive)
|
|
3220
3510
|
|
|
3221
3511
|
### Orders (7)
|
|
3222
3512
|
- \`create-order\` - Create a new order with products and shipping
|
|
@@ -3274,70 +3564,86 @@ Rate limits depend on your tenant plan:
|
|
|
3274
3564
|
}
|
|
3275
3565
|
|
|
3276
3566
|
// src/resources/(collections)/schema.ts
|
|
3277
|
-
import { COLLECTIONS as
|
|
3278
|
-
var
|
|
3567
|
+
import { COLLECTIONS as COLLECTIONS6 } from "@01.software/sdk";
|
|
3568
|
+
var metadata35 = {
|
|
3279
3569
|
name: "collections-schema",
|
|
3280
3570
|
title: "Collection Schema Info",
|
|
3281
3571
|
description: "Available collections and their schema information"
|
|
3282
3572
|
};
|
|
3573
|
+
var COLLECTIONS_BY_CATEGORY = {
|
|
3574
|
+
"Tenant Management": ["tenants", "tenant-metadata", "tenant-logos"],
|
|
3575
|
+
Products: [
|
|
3576
|
+
"products",
|
|
3577
|
+
"product-variants",
|
|
3578
|
+
"product-options",
|
|
3579
|
+
"product-option-values",
|
|
3580
|
+
"product-categories",
|
|
3581
|
+
"product-tags",
|
|
3582
|
+
"product-collections"
|
|
3583
|
+
],
|
|
3584
|
+
Brands: ["brands", "brand-logos"],
|
|
3585
|
+
"Orders & Fulfillment": [
|
|
3586
|
+
"orders",
|
|
3587
|
+
"order-items",
|
|
3588
|
+
"transactions",
|
|
3589
|
+
"fulfillments",
|
|
3590
|
+
"fulfillment-items"
|
|
3591
|
+
],
|
|
3592
|
+
"Shipping & Returns": ["returns", "return-items", "shipping-policies"],
|
|
3593
|
+
Customers: [
|
|
3594
|
+
"customers",
|
|
3595
|
+
"customer-profiles",
|
|
3596
|
+
"customer-addresses",
|
|
3597
|
+
"customer-groups"
|
|
3598
|
+
],
|
|
3599
|
+
Carts: ["carts", "cart-items"],
|
|
3600
|
+
"Discounts & Promotions": ["discounts", "promotions"],
|
|
3601
|
+
Documents: ["documents", "document-categories", "document-types"],
|
|
3602
|
+
Articles: ["articles", "article-authors", "article-categories", "article-tags"],
|
|
3603
|
+
Community: [
|
|
3604
|
+
"posts",
|
|
3605
|
+
"comments",
|
|
3606
|
+
"reactions",
|
|
3607
|
+
"reaction-types",
|
|
3608
|
+
"bookmarks",
|
|
3609
|
+
"post-categories",
|
|
3610
|
+
"reports",
|
|
3611
|
+
"community-bans"
|
|
3612
|
+
],
|
|
3613
|
+
Playlists: [
|
|
3614
|
+
"playlists",
|
|
3615
|
+
"tracks",
|
|
3616
|
+
"playlist-categories",
|
|
3617
|
+
"playlist-tags",
|
|
3618
|
+
"track-categories",
|
|
3619
|
+
"track-tags"
|
|
3620
|
+
],
|
|
3621
|
+
Galleries: ["galleries", "gallery-items", "gallery-categories", "gallery-tags"],
|
|
3622
|
+
Links: ["links", "link-categories", "link-tags"],
|
|
3623
|
+
Canvas: [
|
|
3624
|
+
"canvases",
|
|
3625
|
+
"canvas-node-types",
|
|
3626
|
+
"canvas-edge-types",
|
|
3627
|
+
"canvas-categories",
|
|
3628
|
+
"canvas-tags",
|
|
3629
|
+
"canvas-nodes",
|
|
3630
|
+
"canvas-edges"
|
|
3631
|
+
],
|
|
3632
|
+
Videos: ["videos", "video-categories", "video-tags"],
|
|
3633
|
+
"Live Streams": ["live-streams"],
|
|
3634
|
+
Images: ["images"],
|
|
3635
|
+
Forms: ["forms", "form-submissions"],
|
|
3636
|
+
Events: [
|
|
3637
|
+
"event-calendars",
|
|
3638
|
+
"events",
|
|
3639
|
+
"event-categories",
|
|
3640
|
+
"event-occurrences",
|
|
3641
|
+
"event-tags"
|
|
3642
|
+
]
|
|
3643
|
+
};
|
|
3283
3644
|
function handler7() {
|
|
3284
|
-
const
|
|
3285
|
-
|
|
3286
|
-
Products: [
|
|
3287
|
-
"products",
|
|
3288
|
-
"product-variants",
|
|
3289
|
-
"product-options",
|
|
3290
|
-
"product-categories",
|
|
3291
|
-
"product-tags",
|
|
3292
|
-
"product-collections"
|
|
3293
|
-
],
|
|
3294
|
-
Brands: ["brands", "brand-logos"],
|
|
3295
|
-
"Orders & Fulfillment": [
|
|
3296
|
-
"orders",
|
|
3297
|
-
"order-items",
|
|
3298
|
-
"transactions",
|
|
3299
|
-
"fulfillments",
|
|
3300
|
-
"fulfillment-items"
|
|
3301
|
-
],
|
|
3302
|
-
"Shipping & Returns": [
|
|
3303
|
-
"returns",
|
|
3304
|
-
"return-items",
|
|
3305
|
-
"shipping-policies"
|
|
3306
|
-
],
|
|
3307
|
-
Customers: ["customers", "customer-addresses", "customer-groups"],
|
|
3308
|
-
Carts: ["carts", "cart-items"],
|
|
3309
|
-
Discounts: ["discounts"],
|
|
3310
|
-
Documents: ["documents", "document-categories", "document-types"],
|
|
3311
|
-
"Posts (Blog)": ["posts", "post-categories", "post-tags"],
|
|
3312
|
-
Playlists: [
|
|
3313
|
-
"playlists",
|
|
3314
|
-
"tracks",
|
|
3315
|
-
"track-assets",
|
|
3316
|
-
"playlist-categories",
|
|
3317
|
-
"playlist-tags",
|
|
3318
|
-
"track-categories",
|
|
3319
|
-
"track-tags"
|
|
3320
|
-
],
|
|
3321
|
-
Galleries: [
|
|
3322
|
-
"galleries",
|
|
3323
|
-
"gallery-items",
|
|
3324
|
-
"gallery-categories",
|
|
3325
|
-
"gallery-tags"
|
|
3326
|
-
],
|
|
3327
|
-
Canvas: [
|
|
3328
|
-
"canvases",
|
|
3329
|
-
"canvas-node-types",
|
|
3330
|
-
"canvas-edge-types",
|
|
3331
|
-
"canvas-categories",
|
|
3332
|
-
"canvas-tags"
|
|
3333
|
-
],
|
|
3334
|
-
Videos: ["videos", "video-categories", "video-tags"],
|
|
3335
|
-
"Live Streams": ["live-streams"],
|
|
3336
|
-
Images: ["images"],
|
|
3337
|
-
Forms: ["forms", "form-submissions"]
|
|
3338
|
-
};
|
|
3339
|
-
const categoryDocs = Object.entries(collectionsByCategory).map(([category, collections]) => {
|
|
3340
|
-
const collectionList = collections.filter((c) => COLLECTIONS11.includes(c)).map((c) => `- **${c}**`).join("\n");
|
|
3645
|
+
const categoryDocs = Object.entries(COLLECTIONS_BY_CATEGORY).map(([category, collections]) => {
|
|
3646
|
+
const collectionList = collections.filter((c) => COLLECTIONS6.includes(c)).map((c) => `- **${c}**`).join("\n");
|
|
3341
3647
|
return `## ${category}
|
|
3342
3648
|
${collectionList}`;
|
|
3343
3649
|
}).join("\n\n");
|
|
@@ -3358,6 +3664,9 @@ Each collection supports the following operations:
|
|
|
3358
3664
|
- \`updateMany(where, data)\` - Bulk update items matching filter
|
|
3359
3665
|
- \`removeMany(where)\` - Bulk delete items matching filter
|
|
3360
3666
|
|
|
3667
|
+
Draft-enabled public collections expose only \`_status: 'published'\` rows to
|
|
3668
|
+
publishable-key reads unless server-side access explicitly includes drafts.
|
|
3669
|
+
|
|
3361
3670
|
## Query Examples
|
|
3362
3671
|
|
|
3363
3672
|
### Filtering
|
|
@@ -3379,11 +3688,11 @@ Each collection supports the following operations:
|
|
|
3379
3688
|
}
|
|
3380
3689
|
\`\`\`
|
|
3381
3690
|
|
|
3382
|
-
Total available collections: ${
|
|
3691
|
+
Total available collections: ${COLLECTIONS6.length}`;
|
|
3383
3692
|
}
|
|
3384
3693
|
|
|
3385
3694
|
// src/resources/(docs)/getting-started.ts
|
|
3386
|
-
var
|
|
3695
|
+
var metadata36 = {
|
|
3387
3696
|
name: "docs-getting-started",
|
|
3388
3697
|
title: "Getting Started",
|
|
3389
3698
|
description: "01.software SDK getting started guide"
|
|
@@ -3428,7 +3737,7 @@ const result = await client.collections.from('products').find({
|
|
|
3428
3737
|
}
|
|
3429
3738
|
|
|
3430
3739
|
// src/resources/(docs)/guides.ts
|
|
3431
|
-
var
|
|
3740
|
+
var metadata37 = {
|
|
3432
3741
|
name: "docs-guides",
|
|
3433
3742
|
title: "Guides",
|
|
3434
3743
|
description: "01.software SDK usage guides"
|
|
@@ -3639,7 +3948,7 @@ For more detailed guides, see the [Guides page](/docs/guides).`;
|
|
|
3639
3948
|
}
|
|
3640
3949
|
|
|
3641
3950
|
// src/resources/(docs)/api.ts
|
|
3642
|
-
var
|
|
3951
|
+
var metadata38 = {
|
|
3643
3952
|
name: "docs-api",
|
|
3644
3953
|
title: "API Reference",
|
|
3645
3954
|
description: "01.software SDK API reference documentation"
|
|
@@ -3859,7 +4168,7 @@ Customer authentication and profile management. Available on \`Client\` only (\`
|
|
|
3859
4168
|
### Authentication
|
|
3860
4169
|
\`\`\`typescript
|
|
3861
4170
|
// Register
|
|
3862
|
-
const { customer
|
|
4171
|
+
const { customer } = await client.customer.register({
|
|
3863
4172
|
name: 'John',
|
|
3864
4173
|
email: 'john@example.com',
|
|
3865
4174
|
password: 'password123',
|
|
@@ -3894,7 +4203,7 @@ const updated = await client.customer.updateProfile({
|
|
|
3894
4203
|
|
|
3895
4204
|
### Password
|
|
3896
4205
|
\`\`\`typescript
|
|
3897
|
-
// Forgot password (sends reset token
|
|
4206
|
+
// Forgot password (sends reset token to configured tenant webhooks)
|
|
3898
4207
|
await client.customer.forgotPassword(email)
|
|
3899
4208
|
|
|
3900
4209
|
// Reset password with token
|
|
@@ -3904,11 +4213,6 @@ await client.customer.resetPassword(token, newPassword)
|
|
|
3904
4213
|
await client.customer.changePassword(currentPassword, newPassword)
|
|
3905
4214
|
\`\`\`
|
|
3906
4215
|
|
|
3907
|
-
### Email Verification
|
|
3908
|
-
\`\`\`typescript
|
|
3909
|
-
await client.customer.verifyEmail(token)
|
|
3910
|
-
\`\`\`
|
|
3911
|
-
|
|
3912
4216
|
### Orders
|
|
3913
4217
|
\`\`\`typescript
|
|
3914
4218
|
const orders = await client.commerce.orders.listMine({
|
|
@@ -3930,7 +4234,7 @@ For more details, see the [full API documentation](/docs/api).`;
|
|
|
3930
4234
|
}
|
|
3931
4235
|
|
|
3932
4236
|
// src/resources/(docs)/query-builder.ts
|
|
3933
|
-
var
|
|
4237
|
+
var metadata39 = {
|
|
3934
4238
|
name: "docs-query-builder",
|
|
3935
4239
|
title: "Query Builder",
|
|
3936
4240
|
description: "01.software SDK Query Builder API reference (client.collections.from)"
|
|
@@ -4087,7 +4391,7 @@ if (page1.hasNextPage) {
|
|
|
4087
4391
|
|
|
4088
4392
|
\`\`\`typescript
|
|
4089
4393
|
// Descending (newest first)
|
|
4090
|
-
const result = await client.collections.from('
|
|
4394
|
+
const result = await client.collections.from('articles').find({ sort: '-createdAt' })
|
|
4091
4395
|
|
|
4092
4396
|
// Ascending
|
|
4093
4397
|
const result2 = await client.collections.from('products').find({ sort: 'price' })
|
|
@@ -4124,7 +4428,7 @@ console.log(result.hasNextPage) // true
|
|
|
4124
4428
|
}
|
|
4125
4429
|
|
|
4126
4430
|
// src/resources/(docs)/react-query.ts
|
|
4127
|
-
var
|
|
4431
|
+
var metadata40 = {
|
|
4128
4432
|
name: "docs-react-query",
|
|
4129
4433
|
title: "React Query Hooks",
|
|
4130
4434
|
description: "01.software SDK React Query hooks reference (client.query)"
|
|
@@ -4372,7 +4676,7 @@ export function ProductList() {
|
|
|
4372
4676
|
}
|
|
4373
4677
|
|
|
4374
4678
|
// src/resources/(docs)/server-api.ts
|
|
4375
|
-
var
|
|
4679
|
+
var metadata41 = {
|
|
4376
4680
|
name: "docs-server-api",
|
|
4377
4681
|
title: "Server-side API",
|
|
4378
4682
|
description: "01.software SDK server-side API reference (client.commerce) for orders, fulfillments, returns, carts, and validation"
|
|
@@ -4382,19 +4686,19 @@ function handler13() {
|
|
|
4382
4686
|
|
|
4383
4687
|
Server-side operations are available via \`client.commerce\` on \`ServerClient\`. Use \`createServerClient\` with both \`publishableKey\` and \`secretKey\`.
|
|
4384
4688
|
|
|
4385
|
-
For backend services, prefer a tenant API key (\`sk01_...\`) in \`SOFTWARE_SECRET_KEY\`.
|
|
4386
|
-
Browser-based CLI/init login flows may instead provision a user-scoped PAT (\`pat01_...\`) with a default tenant.
|
|
4387
|
-
|
|
4388
4689
|
\`\`\`typescript
|
|
4389
4690
|
import { createServerClient } from '@01.software/sdk'
|
|
4390
4691
|
|
|
4391
4692
|
const client = createServerClient({
|
|
4392
4693
|
publishableKey: process.env.SOFTWARE_PUBLISHABLE_KEY!,
|
|
4393
|
-
secretKey: process.env.SOFTWARE_SECRET_KEY!,
|
|
4694
|
+
secretKey: process.env.SOFTWARE_SECRET_KEY!,
|
|
4394
4695
|
})
|
|
4395
4696
|
\`\`\`
|
|
4396
4697
|
|
|
4397
|
-
|
|
4698
|
+
Use server components, API routes, or server actions only. Never expose
|
|
4699
|
+
\`SOFTWARE_SECRET_KEY\` to browser code, client bundles, logs, or public
|
|
4700
|
+
repositories. If a secret key leaks, rotate it from the Console before deploying
|
|
4701
|
+
again.
|
|
4398
4702
|
|
|
4399
4703
|
## Order API
|
|
4400
4704
|
|
|
@@ -4513,7 +4817,7 @@ const ret = await client.commerce.orders.updateReturn({
|
|
|
4513
4817
|
\`\`\`
|
|
4514
4818
|
|
|
4515
4819
|
### returnWithRefund()
|
|
4516
|
-
Create a return and process refund in one atomic operation.
|
|
4820
|
+
Create a return and process a provider-verified refund in one atomic operation.
|
|
4517
4821
|
|
|
4518
4822
|
\`\`\`typescript
|
|
4519
4823
|
const result = await client.commerce.orders.returnWithRefund({
|
|
@@ -4525,6 +4829,7 @@ const result = await client.commerce.orders.returnWithRefund({
|
|
|
4525
4829
|
],
|
|
4526
4830
|
refundAmount: 29900,
|
|
4527
4831
|
pgPaymentId: 'toss-payment-id', // required
|
|
4832
|
+
paymentKey: 'toss-payment-key', // required for provider refund
|
|
4528
4833
|
refundReceiptUrl?: 'https://...',
|
|
4529
4834
|
})
|
|
4530
4835
|
\`\`\`
|
|
@@ -4532,12 +4837,15 @@ const result = await client.commerce.orders.returnWithRefund({
|
|
|
4532
4837
|
## Transaction API
|
|
4533
4838
|
|
|
4534
4839
|
### updateTransaction()
|
|
4535
|
-
|
|
4840
|
+
Confirm or annotate a transaction. Paid transitions require provider
|
|
4841
|
+
verification; non-financial annotations can still update pending transactions.
|
|
4536
4842
|
|
|
4537
4843
|
\`\`\`typescript
|
|
4538
4844
|
const tx = await client.commerce.orders.updateTransaction({
|
|
4539
4845
|
pgPaymentId: 'toss-payment-id',
|
|
4540
|
-
status: 'paid', // paid | failed | canceled
|
|
4846
|
+
status: 'paid', // pending | paid | failed | canceled
|
|
4847
|
+
paymentKey: 'toss-payment-key', // required when status is paid
|
|
4848
|
+
amount: 29900, // required when status is paid
|
|
4541
4849
|
})
|
|
4542
4850
|
\`\`\`
|
|
4543
4851
|
|
|
@@ -4630,7 +4938,7 @@ const result = await client.commerce.shipping.calculate({
|
|
|
4630
4938
|
}
|
|
4631
4939
|
|
|
4632
4940
|
// src/resources/(docs)/customer-auth.ts
|
|
4633
|
-
var
|
|
4941
|
+
var metadata42 = {
|
|
4634
4942
|
name: "docs-customer-auth",
|
|
4635
4943
|
title: "Customer Auth API",
|
|
4636
4944
|
description: "01.software SDK Customer Auth API reference (client.customer)"
|
|
@@ -4663,11 +4971,9 @@ const result = await client.customer.register({
|
|
|
4663
4971
|
phone?: '+821012345678',
|
|
4664
4972
|
})
|
|
4665
4973
|
// result.customer - created customer object
|
|
4666
|
-
// result.token? - JWT token (set if email verification not required)
|
|
4667
|
-
// result.verificationRequired? - true if tenant requires email verification
|
|
4668
4974
|
\`\`\`
|
|
4669
4975
|
|
|
4670
|
-
|
|
4976
|
+
Registration creates a local customer account. Projects that need additional email verification should enforce it in application code.
|
|
4671
4977
|
|
|
4672
4978
|
### login()
|
|
4673
4979
|
Authenticate with email and password.
|
|
@@ -4721,12 +5027,12 @@ const updated = await client.customer.updateProfile({
|
|
|
4721
5027
|
## Password
|
|
4722
5028
|
|
|
4723
5029
|
### forgotPassword()
|
|
4724
|
-
Request a password reset. Sends reset token
|
|
5030
|
+
Request a password reset. Sends the reset token to configured tenant webhooks; your webhook handler owns delivery.
|
|
4725
5031
|
|
|
4726
5032
|
\`\`\`typescript
|
|
4727
5033
|
await client.customer.forgotPassword('john@example.com')
|
|
4728
5034
|
// Rate limited: 5 requests/min per tenant+email
|
|
4729
|
-
// Webhook receives: { resetPasswordToken,
|
|
5035
|
+
// Webhook receives: { resetPasswordToken, resetPasswordExpiresAt }
|
|
4730
5036
|
\`\`\`
|
|
4731
5037
|
|
|
4732
5038
|
### resetPassword()
|
|
@@ -4743,15 +5049,6 @@ Change password while authenticated (requires current password).
|
|
|
4743
5049
|
await client.customer.changePassword('currentPassword', 'newPassword123')
|
|
4744
5050
|
\`\`\`
|
|
4745
5051
|
|
|
4746
|
-
## Email Verification
|
|
4747
|
-
|
|
4748
|
-
### verifyEmail()
|
|
4749
|
-
Verify email address using the token received via webhook.
|
|
4750
|
-
|
|
4751
|
-
\`\`\`typescript
|
|
4752
|
-
await client.customer.verifyEmail('verification-token')
|
|
4753
|
-
\`\`\`
|
|
4754
|
-
|
|
4755
5052
|
## Orders
|
|
4756
5053
|
|
|
4757
5054
|
### listMine()
|
|
@@ -4797,12 +5094,7 @@ const client = createClient({
|
|
|
4797
5094
|
async function handleRegister(email: string, password: string, name: string) {
|
|
4798
5095
|
const result = await client.customer.register({ email, password, name })
|
|
4799
5096
|
|
|
4800
|
-
|
|
4801
|
-
// Redirect to "check your email" page
|
|
4802
|
-
return { status: 'verify-email' }
|
|
4803
|
-
}
|
|
4804
|
-
|
|
4805
|
-
// Token is automatically stored; customer is now logged in
|
|
5097
|
+
// Customer is created as a local account.
|
|
4806
5098
|
return { status: 'success', customer: result.customer }
|
|
4807
5099
|
}
|
|
4808
5100
|
|
|
@@ -4824,7 +5116,7 @@ async function loadProfile() {
|
|
|
4824
5116
|
}
|
|
4825
5117
|
|
|
4826
5118
|
// src/resources/(docs)/browser-vs-server.ts
|
|
4827
|
-
var
|
|
5119
|
+
var metadata43 = {
|
|
4828
5120
|
name: "docs-browser-vs-server",
|
|
4829
5121
|
title: "Client vs ServerClient",
|
|
4830
5122
|
description: "When to use Client (createClient) vs ServerClient (createServerClient) in the 01.software SDK"
|
|
@@ -4904,7 +5196,11 @@ await client.commerce.orders.checkout({ ... })
|
|
|
4904
5196
|
|
|
4905
5197
|
**Environment variables**:
|
|
4906
5198
|
- \`SOFTWARE_PUBLISHABLE_KEY\` \u2014 publishable key (no NEXT_PUBLIC prefix, server-only)
|
|
4907
|
-
- \`SOFTWARE_SECRET_KEY\` \u2014
|
|
5199
|
+
- \`SOFTWARE_SECRET_KEY\` \u2014 server credential
|
|
5200
|
+
|
|
5201
|
+
Never expose \`SOFTWARE_SECRET_KEY\` in browser code, client bundles, logs, or
|
|
5202
|
+
public repositories. If a secret key leaks, rotate it from the Console before
|
|
5203
|
+
deploying again.
|
|
4908
5204
|
|
|
4909
5205
|
## Decision Matrix
|
|
4910
5206
|
|
|
@@ -4970,15 +5266,16 @@ export function ProductList() {
|
|
|
4970
5266
|
|
|
4971
5267
|
## Security Rules
|
|
4972
5268
|
|
|
4973
|
-
-
|
|
5269
|
+
- Keep server credentials in server-only modules.
|
|
4974
5270
|
- Only \`NEXT_PUBLIC_SOFTWARE_PUBLISHABLE_KEY\` is safe to use in client components.
|
|
4975
|
-
-
|
|
5271
|
+
- Never import a module that reads \`SOFTWARE_SECRET_KEY\` from a client component.
|
|
5272
|
+
- Rotate any exposed secret key immediately from the Console.
|
|
4976
5273
|
|
|
4977
5274
|
> Ecommerce note: product card pricing lives on \`products.listing.*\`, but authoritative sellable pricing still lives on \`product-variants.price\`.`;
|
|
4978
5275
|
}
|
|
4979
5276
|
|
|
4980
5277
|
// src/resources/(docs)/file-upload.ts
|
|
4981
|
-
var
|
|
5278
|
+
var metadata44 = {
|
|
4982
5279
|
name: "docs-file-upload",
|
|
4983
5280
|
title: "File Upload",
|
|
4984
5281
|
description: "01.software SDK file upload patterns using the images collection"
|
|
@@ -5129,7 +5426,7 @@ The platform stores files in Cloudflare R2 and serves via CDN (\`cdn.01.software
|
|
|
5129
5426
|
}
|
|
5130
5427
|
|
|
5131
5428
|
// src/resources/(docs)/webhook.ts
|
|
5132
|
-
var
|
|
5429
|
+
var metadata45 = {
|
|
5133
5430
|
name: "docs-webhook",
|
|
5134
5431
|
title: "Webhooks",
|
|
5135
5432
|
description: "01.software SDK webhook verification and event handling"
|
|
@@ -5137,27 +5434,23 @@ var metadata50 = {
|
|
|
5137
5434
|
function handler17() {
|
|
5138
5435
|
return `# Webhooks
|
|
5139
5436
|
|
|
5140
|
-
The platform dispatches HMAC-SHA256 signed webhook events to your registered URLs
|
|
5437
|
+
The platform dispatches HMAC-SHA256 signed webhook events to your registered URLs. Tenant developers own routing inside their webhook handler.
|
|
5141
5438
|
|
|
5142
5439
|
## Webhook Handling
|
|
5143
5440
|
|
|
5144
|
-
Use the SDK \`handleWebhook\` helper to verify signatures
|
|
5441
|
+
Use the SDK \`handleWebhook\` helper to verify signatures. For customer auth events, use \`createCustomerAuthWebhookHandler\` to wire delivery behavior in your app.
|
|
5145
5442
|
|
|
5146
5443
|
\`\`\`typescript
|
|
5147
|
-
import { handleWebhook } from '@01.software/sdk/webhook'
|
|
5444
|
+
import { handleWebhook, createCustomerAuthWebhookHandler } from '@01.software/sdk/webhook'
|
|
5445
|
+
|
|
5446
|
+
const handler = createCustomerAuthWebhookHandler({
|
|
5447
|
+
passwordReset: async (data) => {
|
|
5448
|
+
await sendPasswordResetEmail(data)
|
|
5449
|
+
},
|
|
5450
|
+
})
|
|
5148
5451
|
|
|
5149
5452
|
export async function POST(request: Request) {
|
|
5150
|
-
return handleWebhook(request,
|
|
5151
|
-
// event.collection, event.operation, event.data
|
|
5152
|
-
switch (event.operation) {
|
|
5153
|
-
case 'verification':
|
|
5154
|
-
await sendVerificationEmail(event.data)
|
|
5155
|
-
break
|
|
5156
|
-
case 'password-reset':
|
|
5157
|
-
await sendPasswordResetEmail(event.data)
|
|
5158
|
-
break
|
|
5159
|
-
}
|
|
5160
|
-
}, {
|
|
5453
|
+
return handleWebhook(request, handler, {
|
|
5161
5454
|
secret: process.env.WEBHOOK_SECRET!,
|
|
5162
5455
|
})
|
|
5163
5456
|
}
|
|
@@ -5169,19 +5462,17 @@ export async function POST(request: Request) {
|
|
|
5169
5462
|
|
|
5170
5463
|
\`\`\`typescript
|
|
5171
5464
|
// app/api/webhooks/route.ts
|
|
5172
|
-
import { handleWebhook } from '@01.software/sdk/webhook'
|
|
5465
|
+
import { handleWebhook, createCustomerAuthWebhookHandler } from '@01.software/sdk/webhook'
|
|
5466
|
+
|
|
5467
|
+
const customerAuthHandler = createCustomerAuthWebhookHandler({
|
|
5468
|
+
passwordReset: sendPasswordResetEmail,
|
|
5469
|
+
})
|
|
5173
5470
|
|
|
5174
5471
|
export async function POST(request: Request) {
|
|
5175
5472
|
return handleWebhook(request, async (event) => {
|
|
5176
5473
|
console.log('Webhook received:', event.collection, event.operation)
|
|
5177
5474
|
|
|
5178
|
-
|
|
5179
|
-
if (event.operation === 'verification') {
|
|
5180
|
-
await sendVerificationEmail(event.data)
|
|
5181
|
-
} else if (event.operation === 'password-reset') {
|
|
5182
|
-
await sendPasswordResetEmail(event.data)
|
|
5183
|
-
}
|
|
5184
|
-
}
|
|
5475
|
+
await customerAuthHandler(event)
|
|
5185
5476
|
}, {
|
|
5186
5477
|
secret: process.env.WEBHOOK_SECRET!,
|
|
5187
5478
|
})
|
|
@@ -5195,49 +5486,13 @@ All webhook events share this envelope:
|
|
|
5195
5486
|
\`\`\`typescript
|
|
5196
5487
|
{
|
|
5197
5488
|
collection: string, // e.g. 'customers'
|
|
5198
|
-
operation: string, // e.g. '
|
|
5489
|
+
operation: string, // e.g. 'password-reset'
|
|
5199
5490
|
data: object, // event-specific payload
|
|
5200
5491
|
}
|
|
5201
5492
|
\`\`\`
|
|
5202
5493
|
|
|
5203
5494
|
## Event Types
|
|
5204
5495
|
|
|
5205
|
-
### Customer Email Verification
|
|
5206
|
-
|
|
5207
|
-
Dispatched when a customer registers on a tenant with \`requireEmailVerification: true\`.
|
|
5208
|
-
|
|
5209
|
-
\`\`\`typescript
|
|
5210
|
-
{
|
|
5211
|
-
collection: 'customers',
|
|
5212
|
-
operation: 'verification',
|
|
5213
|
-
data: {
|
|
5214
|
-
customerId: string,
|
|
5215
|
-
email: string,
|
|
5216
|
-
name: string,
|
|
5217
|
-
verificationToken: string, // raw token to include in verification link
|
|
5218
|
-
}
|
|
5219
|
-
}
|
|
5220
|
-
\`\`\`
|
|
5221
|
-
|
|
5222
|
-
**Usage**: Send the \`verificationToken\` to the customer's email. The customer calls \`client.customer.verifyEmail(token)\` to complete verification.
|
|
5223
|
-
|
|
5224
|
-
\`\`\`typescript
|
|
5225
|
-
// Example: send verification email
|
|
5226
|
-
async function sendVerificationEmail(data: {
|
|
5227
|
-
customerId: string
|
|
5228
|
-
email: string
|
|
5229
|
-
name: string
|
|
5230
|
-
verificationToken: string
|
|
5231
|
-
}) {
|
|
5232
|
-
const verifyUrl = \`https://yourstore.com/verify-email?token=\${data.verificationToken}\`
|
|
5233
|
-
await emailService.send({
|
|
5234
|
-
to: data.email,
|
|
5235
|
-
subject: 'Verify your email',
|
|
5236
|
-
body: \`Click here to verify: \${verifyUrl}\`,
|
|
5237
|
-
})
|
|
5238
|
-
}
|
|
5239
|
-
\`\`\`
|
|
5240
|
-
|
|
5241
5496
|
### Customer Password Reset
|
|
5242
5497
|
|
|
5243
5498
|
Dispatched when a customer calls \`client.customer.forgotPassword(email)\`.
|
|
@@ -5251,7 +5506,7 @@ Dispatched when a customer calls \`client.customer.forgotPassword(email)\`.
|
|
|
5251
5506
|
email: string,
|
|
5252
5507
|
name: string,
|
|
5253
5508
|
resetPasswordToken: string, // raw token to include in reset link
|
|
5254
|
-
|
|
5509
|
+
resetPasswordExpiresAt: string, // ISO 8601 expiry (1 hour from dispatch)
|
|
5255
5510
|
}
|
|
5256
5511
|
}
|
|
5257
5512
|
\`\`\`
|
|
@@ -5264,13 +5519,13 @@ async function sendPasswordResetEmail(data: {
|
|
|
5264
5519
|
email: string
|
|
5265
5520
|
name: string
|
|
5266
5521
|
resetPasswordToken: string
|
|
5267
|
-
|
|
5522
|
+
resetPasswordExpiresAt: string
|
|
5268
5523
|
}) {
|
|
5269
5524
|
const resetUrl = \`https://yourstore.com/reset-password?token=\${data.resetPasswordToken}\`
|
|
5270
5525
|
await emailService.send({
|
|
5271
5526
|
to: data.email,
|
|
5272
5527
|
subject: 'Reset your password',
|
|
5273
|
-
body: \`Reset link (expires \${data.
|
|
5528
|
+
body: \`Reset link (expires \${data.resetPasswordExpiresAt}): \${resetUrl}\`,
|
|
5274
5529
|
})
|
|
5275
5530
|
}
|
|
5276
5531
|
\`\`\`
|
|
@@ -5285,28 +5540,54 @@ Configure webhook URLs in the 01.software console under Tenant Settings > Webhoo
|
|
|
5285
5540
|
}
|
|
5286
5541
|
|
|
5287
5542
|
// src/server.ts
|
|
5288
|
-
|
|
5543
|
+
var REGISTERED_TOOLS_BY_SERVER = /* @__PURE__ */ new WeakMap();
|
|
5544
|
+
function registerTool(server, schema34, meta, handler19) {
|
|
5545
|
+
let registered = REGISTERED_TOOLS_BY_SERVER.get(server);
|
|
5546
|
+
if (!registered) {
|
|
5547
|
+
registered = /* @__PURE__ */ new Set();
|
|
5548
|
+
REGISTERED_TOOLS_BY_SERVER.set(server, registered);
|
|
5549
|
+
}
|
|
5550
|
+
registered.add(meta.name);
|
|
5289
5551
|
server.registerTool(
|
|
5290
5552
|
meta.name,
|
|
5291
5553
|
{
|
|
5292
5554
|
description: meta.description,
|
|
5293
|
-
inputSchema:
|
|
5555
|
+
inputSchema: schema34,
|
|
5294
5556
|
annotations: meta.annotations
|
|
5295
5557
|
},
|
|
5296
5558
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5297
5559
|
async (params) => {
|
|
5560
|
+
const ctx = tenantAuthContext();
|
|
5561
|
+
if (ctx) {
|
|
5562
|
+
const decision = evaluateToolPolicy(meta.name, ctx.scopes);
|
|
5563
|
+
if (!decision.allowed) {
|
|
5564
|
+
const status = decision.reason === "insufficient_scope" ? 403 : 500;
|
|
5565
|
+
return {
|
|
5566
|
+
content: [
|
|
5567
|
+
{
|
|
5568
|
+
type: "text",
|
|
5569
|
+
text: toolError({
|
|
5570
|
+
status,
|
|
5571
|
+
reason: decision.reason,
|
|
5572
|
+
message: decision.message
|
|
5573
|
+
})
|
|
5574
|
+
}
|
|
5575
|
+
]
|
|
5576
|
+
};
|
|
5577
|
+
}
|
|
5578
|
+
}
|
|
5298
5579
|
const result = await handler19(params);
|
|
5299
5580
|
return { content: [{ type: "text", text: result }] };
|
|
5300
5581
|
}
|
|
5301
5582
|
);
|
|
5302
5583
|
}
|
|
5303
|
-
function registerPrompt(server,
|
|
5584
|
+
function registerPrompt(server, schema34, meta, handler19) {
|
|
5304
5585
|
server.registerPrompt(
|
|
5305
5586
|
meta.name,
|
|
5306
5587
|
{
|
|
5307
5588
|
title: meta.title,
|
|
5308
5589
|
description: meta.description,
|
|
5309
|
-
argsSchema:
|
|
5590
|
+
argsSchema: schema34
|
|
5310
5591
|
},
|
|
5311
5592
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5312
5593
|
(params) => ({
|
|
@@ -5333,80 +5614,248 @@ function registerStaticResource(server, uri, meta, handler19) {
|
|
|
5333
5614
|
})
|
|
5334
5615
|
);
|
|
5335
5616
|
}
|
|
5336
|
-
function createServer() {
|
|
5617
|
+
function createServer(options = {}) {
|
|
5618
|
+
const toolSurface = options.toolSurface ?? "full";
|
|
5337
5619
|
const server = new McpServer({
|
|
5338
5620
|
name: "01.software MCP Server",
|
|
5339
5621
|
version: "0.1.0"
|
|
5340
5622
|
});
|
|
5341
|
-
|
|
5342
|
-
|
|
5343
|
-
|
|
5344
|
-
|
|
5345
|
-
|
|
5346
|
-
|
|
5347
|
-
|
|
5348
|
-
|
|
5349
|
-
|
|
5350
|
-
|
|
5351
|
-
|
|
5352
|
-
|
|
5353
|
-
|
|
5354
|
-
|
|
5355
|
-
|
|
5356
|
-
|
|
5357
|
-
|
|
5358
|
-
|
|
5359
|
-
|
|
5360
|
-
|
|
5361
|
-
|
|
5362
|
-
|
|
5363
|
-
|
|
5364
|
-
registerTool(server,
|
|
5365
|
-
registerTool(server,
|
|
5366
|
-
registerTool(server,
|
|
5367
|
-
registerTool(server,
|
|
5368
|
-
registerTool(server,
|
|
5369
|
-
registerTool(server,
|
|
5370
|
-
registerTool(server,
|
|
5371
|
-
registerTool(server,
|
|
5372
|
-
|
|
5373
|
-
|
|
5374
|
-
|
|
5375
|
-
registerPrompt(server,
|
|
5376
|
-
|
|
5377
|
-
|
|
5378
|
-
|
|
5379
|
-
registerStaticResource(server, "
|
|
5380
|
-
registerStaticResource(server, "
|
|
5381
|
-
registerStaticResource(server, "docs://sdk/
|
|
5382
|
-
registerStaticResource(server, "docs://sdk/
|
|
5383
|
-
registerStaticResource(server, "docs://sdk/api",
|
|
5384
|
-
registerStaticResource(server, "docs://sdk/
|
|
5385
|
-
registerStaticResource(server, "docs://sdk/
|
|
5386
|
-
registerStaticResource(server, "docs://sdk/
|
|
5387
|
-
registerStaticResource(server, "docs://sdk/
|
|
5388
|
-
registerStaticResource(server, "docs://sdk/browser-vs-server", metadata48, handler15);
|
|
5389
|
-
registerStaticResource(server, "docs://sdk/file-upload", metadata49, handler16);
|
|
5390
|
-
registerStaticResource(server, "docs://sdk/webhook", metadata50, handler17);
|
|
5623
|
+
if (toolSurface === "full") {
|
|
5624
|
+
registerTool(server, schema, metadata, queryCollection);
|
|
5625
|
+
registerTool(server, schema2, metadata2, getCollectionById);
|
|
5626
|
+
registerTool(server, schema3, metadata3, getOrder);
|
|
5627
|
+
registerTool(server, schema4, metadata4, createOrder);
|
|
5628
|
+
registerTool(server, schema5, metadata5, updateOrder);
|
|
5629
|
+
registerTool(server, schema6, metadata6, checkout);
|
|
5630
|
+
registerTool(server, schema7, metadata7, createFulfillment);
|
|
5631
|
+
registerTool(server, schema8, metadata8, updateFulfillment);
|
|
5632
|
+
registerTool(server, schema9, metadata9, updateTransaction);
|
|
5633
|
+
registerTool(server, schema10, metadata10, createReturn);
|
|
5634
|
+
registerTool(server, schema11, metadata11, updateReturn);
|
|
5635
|
+
registerTool(server, schema12, metadata12, returnWithRefund);
|
|
5636
|
+
registerTool(server, schema13, metadata13, addCartItem);
|
|
5637
|
+
registerTool(server, schema14, metadata14, updateCartItem);
|
|
5638
|
+
registerTool(server, schema15, metadata15, removeCartItem);
|
|
5639
|
+
registerTool(server, schema16, metadata16, applyDiscount);
|
|
5640
|
+
registerTool(server, schema17, metadata17, removeDiscount);
|
|
5641
|
+
registerTool(server, schema18, metadata18, clearCart);
|
|
5642
|
+
registerTool(server, schema19, metadata19, validateDiscount);
|
|
5643
|
+
registerTool(server, schema20, metadata20, calculateShipping);
|
|
5644
|
+
registerTool(server, schema21, metadata21, stockCheck);
|
|
5645
|
+
}
|
|
5646
|
+
registerTool(server, schema22, metadata22, getCollectionSchemaTool);
|
|
5647
|
+
registerTool(server, schema23, metadata23, handler);
|
|
5648
|
+
registerTool(server, schema24, metadata24, listConfigurableFields);
|
|
5649
|
+
registerTool(server, schema25, metadata25, updateFieldConfig);
|
|
5650
|
+
registerTool(server, schema26, metadata26, handler2);
|
|
5651
|
+
registerTool(server, schema27, metadata27, handler3);
|
|
5652
|
+
registerTool(server, schema28, metadata28, handler4);
|
|
5653
|
+
registerTool(server, schema29, metadata29, handler5);
|
|
5654
|
+
registerPrompt(server, schema30, metadata30, sdkUsageGuide);
|
|
5655
|
+
registerPrompt(server, schema31, metadata31, collectionQueryHelp);
|
|
5656
|
+
registerPrompt(server, schema32, metadata32, orderFlowGuide);
|
|
5657
|
+
registerPrompt(server, schema33, metadata33, featureSetupGuide);
|
|
5658
|
+
registerStaticResource(server, "config://app", metadata34, handler6);
|
|
5659
|
+
registerStaticResource(server, "collections://schema", metadata35, handler7);
|
|
5660
|
+
registerStaticResource(server, "docs://sdk/getting-started", metadata36, handler8);
|
|
5661
|
+
registerStaticResource(server, "docs://sdk/guides", metadata37, handler9);
|
|
5662
|
+
registerStaticResource(server, "docs://sdk/api", metadata38, handler10);
|
|
5663
|
+
registerStaticResource(server, "docs://sdk/query-builder", metadata39, handler11);
|
|
5664
|
+
registerStaticResource(server, "docs://sdk/react-query", metadata40, handler12);
|
|
5665
|
+
registerStaticResource(server, "docs://sdk/server-api", metadata41, handler13);
|
|
5666
|
+
registerStaticResource(server, "docs://sdk/customer-auth", metadata42, handler14);
|
|
5667
|
+
registerStaticResource(server, "docs://sdk/browser-vs-server", metadata43, handler15);
|
|
5668
|
+
registerStaticResource(server, "docs://sdk/file-upload", metadata44, handler16);
|
|
5669
|
+
registerStaticResource(server, "docs://sdk/webhook", metadata45, handler17);
|
|
5391
5670
|
return server;
|
|
5392
5671
|
}
|
|
5393
5672
|
|
|
5394
5673
|
// src/auth.ts
|
|
5395
|
-
|
|
5396
|
-
|
|
5397
|
-
|
|
5674
|
+
import { createPublicKey, verify as verifySignature } from "crypto";
|
|
5675
|
+
var ALLOWED_ALGORITHMS = /* @__PURE__ */ new Set(["RS256", "ES256"]);
|
|
5676
|
+
var DEFAULT_CLOCK_SKEW_SECONDS = 30;
|
|
5677
|
+
var DEFAULT_JWKS_URI = `${MCP_OAUTH_ISSUER}/.well-known/jwks.json`;
|
|
5678
|
+
var MAX_ACCESS_TOKEN_LIFETIME_SECONDS = 300;
|
|
5679
|
+
function invalid(errorDescription) {
|
|
5680
|
+
return { valid: false, error: "invalid_token", errorDescription };
|
|
5681
|
+
}
|
|
5682
|
+
function isProduction() {
|
|
5683
|
+
return process.env.NODE_ENV === "production";
|
|
5684
|
+
}
|
|
5685
|
+
function insufficientScope(errorDescription) {
|
|
5686
|
+
return { valid: false, error: "insufficient_scope", errorDescription };
|
|
5687
|
+
}
|
|
5688
|
+
function decodeBase64UrlJson(value) {
|
|
5689
|
+
try {
|
|
5690
|
+
return JSON.parse(Buffer.from(value, "base64url").toString("utf8"));
|
|
5691
|
+
} catch {
|
|
5692
|
+
return null;
|
|
5398
5693
|
}
|
|
5399
|
-
|
|
5400
|
-
|
|
5401
|
-
|
|
5402
|
-
|
|
5403
|
-
|
|
5694
|
+
}
|
|
5695
|
+
function parseScopes(payload) {
|
|
5696
|
+
const rawScopes = typeof payload.scope === "string" ? payload.scope.split(/\s+/).filter(Boolean) : Array.isArray(payload.scp) ? payload.scp : [];
|
|
5697
|
+
return rawScopes.filter(
|
|
5698
|
+
(scope) => scope === MCP_SCOPES.read || scope === MCP_SCOPES.write
|
|
5699
|
+
);
|
|
5700
|
+
}
|
|
5701
|
+
function audienceMatches(aud, expected) {
|
|
5702
|
+
if (typeof aud === "string") return aud === expected;
|
|
5703
|
+
return Array.isArray(aud) && aud.includes(expected);
|
|
5704
|
+
}
|
|
5705
|
+
function verifyJwtSignature(alg, jwk, signingInput, signature) {
|
|
5706
|
+
const key = createPublicKey({ key: jwk, format: "jwk" });
|
|
5707
|
+
const input = Buffer.from(signingInput);
|
|
5708
|
+
if (alg === "RS256") {
|
|
5709
|
+
return verifySignature("RSA-SHA256", input, key, signature);
|
|
5710
|
+
}
|
|
5711
|
+
if (alg === "ES256") {
|
|
5712
|
+
return verifySignature("SHA256", input, { key, dsaEncoding: "ieee-p1363" }, signature);
|
|
5713
|
+
}
|
|
5714
|
+
return false;
|
|
5715
|
+
}
|
|
5716
|
+
var cachedRemoteJwks = null;
|
|
5717
|
+
function jwksUriFor(options) {
|
|
5718
|
+
const raw = isProduction() ? DEFAULT_JWKS_URI : options.jwksUri ?? DEFAULT_JWKS_URI;
|
|
5719
|
+
let url;
|
|
5720
|
+
try {
|
|
5721
|
+
url = new URL(raw);
|
|
5722
|
+
} catch {
|
|
5723
|
+
return null;
|
|
5724
|
+
}
|
|
5725
|
+
if (url.protocol !== "https:" || url.username || url.password || url.search || url.hash) {
|
|
5726
|
+
return null;
|
|
5727
|
+
}
|
|
5728
|
+
return url.toString();
|
|
5729
|
+
}
|
|
5730
|
+
async function remoteJwks(options = {}, forceRefresh = false) {
|
|
5731
|
+
const uri = jwksUriFor(options);
|
|
5732
|
+
if (!uri) return null;
|
|
5733
|
+
const now = Date.now();
|
|
5734
|
+
if (!forceRefresh && cachedRemoteJwks && cachedRemoteJwks.uri === uri && cachedRemoteJwks.expiresAt > now) {
|
|
5735
|
+
return cachedRemoteJwks.jwks;
|
|
5736
|
+
}
|
|
5737
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
5738
|
+
let response;
|
|
5739
|
+
try {
|
|
5740
|
+
response = await fetchImpl(uri, {
|
|
5741
|
+
headers: { Accept: "application/json" }
|
|
5742
|
+
});
|
|
5743
|
+
} catch {
|
|
5744
|
+
return null;
|
|
5745
|
+
}
|
|
5746
|
+
if (!response.ok) return null;
|
|
5747
|
+
const parsed = await response.json().catch(() => null);
|
|
5748
|
+
if (!parsed || !Array.isArray(parsed.keys)) return null;
|
|
5749
|
+
cachedRemoteJwks = {
|
|
5750
|
+
expiresAt: now + 3e5,
|
|
5751
|
+
jwks: parsed,
|
|
5752
|
+
uri
|
|
5753
|
+
};
|
|
5754
|
+
return parsed;
|
|
5755
|
+
}
|
|
5756
|
+
function validateAccessToken(token, options = {}) {
|
|
5757
|
+
const parts = token.split(".");
|
|
5758
|
+
if (parts.length !== 3 || parts.some((part) => part.length === 0)) {
|
|
5759
|
+
return invalid("Bearer token must be a compact JWT");
|
|
5760
|
+
}
|
|
5761
|
+
const [encodedHeader, encodedPayload, encodedSignature] = parts;
|
|
5762
|
+
const header = decodeBase64UrlJson(encodedHeader);
|
|
5763
|
+
const payload = decodeBase64UrlJson(encodedPayload);
|
|
5764
|
+
if (!header || !payload) return invalid("Bearer token contains invalid JSON");
|
|
5765
|
+
if (typeof header.alg !== "string" || !ALLOWED_ALGORITHMS.has(header.alg)) {
|
|
5766
|
+
return invalid("Bearer token uses an unsupported signing algorithm");
|
|
5767
|
+
}
|
|
5768
|
+
if (typeof header.kid !== "string" || header.kid.length === 0) {
|
|
5769
|
+
return invalid("Bearer token is missing kid");
|
|
5770
|
+
}
|
|
5771
|
+
const jwks = options.jwks;
|
|
5772
|
+
if (!jwks) return invalid("JWKS is not configured");
|
|
5773
|
+
const jwk = jwks.keys.find((key) => key.kid === header.kid);
|
|
5774
|
+
if (!jwk) return invalid("Bearer token kid is unknown");
|
|
5775
|
+
const signingInput = `${encodedHeader}.${encodedPayload}`;
|
|
5776
|
+
const signature = Buffer.from(encodedSignature, "base64url");
|
|
5777
|
+
if (!verifyJwtSignature(header.alg, jwk, signingInput, signature)) {
|
|
5778
|
+
return invalid("Bearer token signature is invalid");
|
|
5779
|
+
}
|
|
5780
|
+
const issuer = options.issuer ?? MCP_OAUTH_ISSUER;
|
|
5781
|
+
if (payload.iss !== issuer) return invalid("Bearer token issuer is invalid");
|
|
5782
|
+
const audience = options.audience ?? MCP_RESOURCE_AUDIENCE;
|
|
5783
|
+
if (!audienceMatches(payload.aud, audience)) {
|
|
5784
|
+
return invalid("Bearer token audience is invalid");
|
|
5785
|
+
}
|
|
5786
|
+
if (typeof payload.iat !== "number") return invalid("Bearer token is missing iat");
|
|
5787
|
+
if (typeof payload.exp !== "number") return invalid("Bearer token is missing exp");
|
|
5788
|
+
if (payload.exp <= payload.iat) {
|
|
5789
|
+
return invalid("Bearer token lifetime is invalid");
|
|
5790
|
+
}
|
|
5791
|
+
if (payload.exp - payload.iat > MAX_ACCESS_TOKEN_LIFETIME_SECONDS) {
|
|
5792
|
+
return invalid("Bearer token lifetime exceeds 300 seconds");
|
|
5793
|
+
}
|
|
5794
|
+
const nowSeconds = Math.floor((options.now ?? /* @__PURE__ */ new Date()).getTime() / 1e3);
|
|
5795
|
+
const leeway = options.clockSkewSeconds ?? DEFAULT_CLOCK_SKEW_SECONDS;
|
|
5796
|
+
if (payload.iat > nowSeconds + leeway) {
|
|
5797
|
+
return invalid("Bearer token iat is too far in the future");
|
|
5798
|
+
}
|
|
5799
|
+
if (typeof payload.nbf === "number" && payload.nbf > nowSeconds + leeway) {
|
|
5800
|
+
return invalid("Bearer token is not yet valid");
|
|
5404
5801
|
}
|
|
5405
|
-
return
|
|
5802
|
+
if (payload.exp < nowSeconds - leeway) return invalid("Bearer token is expired");
|
|
5803
|
+
const tenantId = payload[MCP_TENANT_CLAIM];
|
|
5804
|
+
if (typeof tenantId !== "string" || tenantId.length === 0) {
|
|
5805
|
+
return invalid("Bearer token tenant_id claim is invalid");
|
|
5806
|
+
}
|
|
5807
|
+
const tenantRole = payload[MCP_TENANT_ROLE_CLAIM];
|
|
5808
|
+
if (tenantRole !== "tenant-admin" && tenantRole !== "tenant-editor" && tenantRole !== "tenant-viewer") {
|
|
5809
|
+
return invalid("Bearer token tenant_role claim is invalid");
|
|
5810
|
+
}
|
|
5811
|
+
if (typeof payload.sub !== "string" || payload.sub.length === 0) {
|
|
5812
|
+
return invalid("Bearer token subject claim is invalid");
|
|
5813
|
+
}
|
|
5814
|
+
const scopes = parseScopes(payload);
|
|
5815
|
+
const requiredScopes = options.requiredScopes ?? [MCP_SCOPES.read];
|
|
5816
|
+
const missingScope = requiredScopes.find((scope) => !scopes.includes(scope));
|
|
5817
|
+
if (missingScope) return insufficientScope(`Bearer token is missing ${missingScope}`);
|
|
5818
|
+
return {
|
|
5819
|
+
valid: true,
|
|
5820
|
+
context: {
|
|
5821
|
+
tenantId,
|
|
5822
|
+
principalId: payload.sub,
|
|
5823
|
+
scopes,
|
|
5824
|
+
tenantRole,
|
|
5825
|
+
authMode: "oauth"
|
|
5826
|
+
}
|
|
5827
|
+
};
|
|
5828
|
+
}
|
|
5829
|
+
function shouldRefreshRemoteJwks(result) {
|
|
5830
|
+
return !result.valid && (result.errorDescription === "Bearer token kid is unknown" || result.errorDescription === "Bearer token signature is invalid");
|
|
5831
|
+
}
|
|
5832
|
+
async function validateBearerAuthorizationHeaderAsync(authorization, options) {
|
|
5833
|
+
if (!authorization) return invalid("Authorization Bearer token is required");
|
|
5834
|
+
const match = authorization.match(/^Bearer\s+(.+)$/i);
|
|
5835
|
+
if (!match) return invalid("Authorization header must use Bearer");
|
|
5836
|
+
if (options?.jwks) {
|
|
5837
|
+
return validateAccessToken(match[1], options);
|
|
5838
|
+
}
|
|
5839
|
+
const jwks = await remoteJwks(options);
|
|
5840
|
+
const result = validateAccessToken(match[1], {
|
|
5841
|
+
...options,
|
|
5842
|
+
jwks: jwks ?? void 0
|
|
5843
|
+
});
|
|
5844
|
+
if (shouldRefreshRemoteJwks(result)) {
|
|
5845
|
+
const refreshedJwks = await remoteJwks(options, true);
|
|
5846
|
+
if (refreshedJwks) {
|
|
5847
|
+
return validateAccessToken(match[1], {
|
|
5848
|
+
...options,
|
|
5849
|
+
jwks: refreshedJwks
|
|
5850
|
+
});
|
|
5851
|
+
}
|
|
5852
|
+
}
|
|
5853
|
+
return result;
|
|
5406
5854
|
}
|
|
5407
5855
|
|
|
5408
5856
|
// src/handler.ts
|
|
5409
5857
|
var MAX_REQUEST_BODY_BYTES = 1024 * 1024;
|
|
5858
|
+
var MCP_ALLOWED_BROWSER_ORIGIN = "https://01.software";
|
|
5410
5859
|
var METHOD_NOT_ALLOWED = JSON.stringify({
|
|
5411
5860
|
jsonrpc: "2.0",
|
|
5412
5861
|
error: {
|
|
@@ -5416,16 +5865,16 @@ var METHOD_NOT_ALLOWED = JSON.stringify({
|
|
|
5416
5865
|
id: null
|
|
5417
5866
|
});
|
|
5418
5867
|
function setCors(res) {
|
|
5419
|
-
res.setHeader("Access-Control-Allow-Origin",
|
|
5868
|
+
res.setHeader("Access-Control-Allow-Origin", MCP_ALLOWED_BROWSER_ORIGIN);
|
|
5420
5869
|
res.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS");
|
|
5421
5870
|
res.setHeader(
|
|
5422
5871
|
"Access-Control-Allow-Headers",
|
|
5423
|
-
"Content-Type,
|
|
5872
|
+
"Authorization, Content-Type, mcp-session-id"
|
|
5424
5873
|
);
|
|
5425
5874
|
res.setHeader("Access-Control-Expose-Headers", "Mcp-Session-Id, Mcp-Protocol-Version");
|
|
5426
5875
|
}
|
|
5427
|
-
function getHeaderValue(
|
|
5428
|
-
const value =
|
|
5876
|
+
function getHeaderValue(headers, name) {
|
|
5877
|
+
const value = headers[name.toLowerCase()];
|
|
5429
5878
|
if (Array.isArray(value)) return value[0];
|
|
5430
5879
|
return value;
|
|
5431
5880
|
}
|
|
@@ -5450,143 +5899,69 @@ var HOME_PAGE = `01.software MCP Server
|
|
|
5450
5899
|
======================
|
|
5451
5900
|
|
|
5452
5901
|
MCP server for AI agents to interact with the 01.software API.
|
|
5453
|
-
|
|
5902
|
+
Connect over HTTP with OAuth, or use the local CLI stdio transport for full
|
|
5903
|
+
server-key operations.
|
|
5454
5904
|
|
|
5455
5905
|
|
|
5456
5906
|
Authentication
|
|
5457
5907
|
--------------
|
|
5458
5908
|
|
|
5459
|
-
|
|
5460
|
-
|
|
5461
|
-
x-publishable-key publishable key for routing, rate limits, and quota enforcement
|
|
5462
|
-
|
|
5463
|
-
Use x-client-key as a legacy alias for x-publishable-key.
|
|
5464
|
-
|
|
5465
|
-
Accepted formats:
|
|
5466
|
-
sk01_{40hex} tenant API key (Console > Settings > API Keys)
|
|
5467
|
-
pat01_{40hex} personal access token (user-scoped local workflow)
|
|
5468
|
-
pk01_{...} publishable key
|
|
5469
|
-
|
|
5470
|
-
export SOFTWARE_PUBLISHABLE_KEY=pk01_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
|
5471
|
-
export SOFTWARE_SECRET_KEY=sk01_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
|
5472
|
-
|
|
5909
|
+
HTTP MCP uses OAuth discovery and Authorization Code + PKCE.
|
|
5910
|
+
Clients should connect to:
|
|
5473
5911
|
|
|
5474
5912
|
Connect
|
|
5475
5913
|
-------
|
|
5476
5914
|
|
|
5477
5915
|
Claude Code:
|
|
5478
5916
|
|
|
5479
|
-
claude mcp add --transport http
|
|
5480
|
-
--header "x-api-key: $SOFTWARE_SECRET_KEY" \\
|
|
5481
|
-
--header "x-publishable-key: $SOFTWARE_PUBLISHABLE_KEY" \\
|
|
5482
|
-
01software https://mcp.01.software/mcp
|
|
5917
|
+
claude mcp add --transport http 01software https://mcp.01.software/mcp
|
|
5483
5918
|
|
|
5484
|
-
Codex (.codex/config.toml
|
|
5919
|
+
Codex (.codex/config.toml):
|
|
5485
5920
|
|
|
5486
5921
|
[mcp_servers.01software]
|
|
5487
5922
|
url = "https://mcp.01.software/mcp"
|
|
5488
5923
|
|
|
5489
|
-
|
|
5490
|
-
x-api-key = "SOFTWARE_SECRET_KEY"
|
|
5491
|
-
x-publishable-key = "SOFTWARE_PUBLISHABLE_KEY"
|
|
5924
|
+
Cursor / Claude Desktop / other JSON clients:
|
|
5492
5925
|
|
|
5493
|
-
// or .mcp.json
|
|
5494
5926
|
{
|
|
5495
5927
|
"mcpServers": {
|
|
5496
5928
|
"01software": {
|
|
5497
5929
|
"type": "http",
|
|
5498
|
-
"url": "https://mcp.01.software/mcp"
|
|
5499
|
-
"headers": {
|
|
5500
|
-
"x-api-key": "\${env:SOFTWARE_SECRET_KEY}",
|
|
5501
|
-
"x-publishable-key": "\${env:SOFTWARE_PUBLISHABLE_KEY}"
|
|
5502
|
-
}
|
|
5930
|
+
"url": "https://mcp.01.software/mcp"
|
|
5503
5931
|
}
|
|
5504
5932
|
}
|
|
5505
5933
|
}
|
|
5506
5934
|
|
|
5507
|
-
|
|
5935
|
+
Windsurf (~/.codeium/windsurf/mcp_config.json):
|
|
5508
5936
|
|
|
5509
5937
|
{
|
|
5510
5938
|
"mcpServers": {
|
|
5511
5939
|
"01software": {
|
|
5512
|
-
"
|
|
5513
|
-
"headers": {
|
|
5514
|
-
"x-api-key": "\${env:SOFTWARE_SECRET_KEY}",
|
|
5515
|
-
"x-publishable-key": "\${env:SOFTWARE_PUBLISHABLE_KEY}"
|
|
5516
|
-
}
|
|
5940
|
+
"serverUrl": "https://mcp.01.software/mcp"
|
|
5517
5941
|
}
|
|
5518
5942
|
}
|
|
5519
5943
|
}
|
|
5520
5944
|
|
|
5521
|
-
|
|
5945
|
+
CLI (stdio):
|
|
5522
5946
|
|
|
5523
|
-
|
|
5524
|
-
"mcpServers": {
|
|
5525
|
-
"01software": {
|
|
5526
|
-
"serverUrl": "https://mcp.01.software/mcp",
|
|
5527
|
-
"headers": {
|
|
5528
|
-
"x-api-key": "\${env:SOFTWARE_SECRET_KEY}",
|
|
5529
|
-
"x-publishable-key": "\${env:SOFTWARE_PUBLISHABLE_KEY}"
|
|
5530
|
-
}
|
|
5531
|
-
}
|
|
5532
|
-
}
|
|
5533
|
-
}
|
|
5947
|
+
npx @01.software/cli mcp
|
|
5534
5948
|
|
|
5535
|
-
VS Code (.vscode/mcp.json):
|
|
5536
5949
|
|
|
5537
|
-
|
|
5538
|
-
|
|
5539
|
-
"01software": {
|
|
5540
|
-
"type": "http",
|
|
5541
|
-
"url": "https://mcp.01.software/mcp",
|
|
5542
|
-
"headers": {
|
|
5543
|
-
"x-api-key": "\${input:01software-api-key}",
|
|
5544
|
-
"x-publishable-key": "\${input:01software-publishable-key}"
|
|
5545
|
-
}
|
|
5546
|
-
}
|
|
5547
|
-
}
|
|
5548
|
-
}
|
|
5950
|
+
HTTP OAuth Tools
|
|
5951
|
+
----------------
|
|
5549
5952
|
|
|
5550
|
-
|
|
5953
|
+
Schema get-collection-schema
|
|
5954
|
+
Context get-tenant-context
|
|
5955
|
+
Field Config list-configurable-fields, update-field-config
|
|
5956
|
+
Guidance sdk-get-recipe, sdk-search-docs, sdk-get-auth-setup, sdk-get-collection-pattern
|
|
5551
5957
|
|
|
5552
|
-
|
|
5553
|
-
|
|
5554
|
-
"01software": {
|
|
5555
|
-
"url": "https://mcp.01.software/mcp",
|
|
5556
|
-
"headers": {
|
|
5557
|
-
"x-api-key": "\${env:SOFTWARE_SECRET_KEY}",
|
|
5558
|
-
"x-publishable-key": "\${env:SOFTWARE_PUBLISHABLE_KEY}"
|
|
5559
|
-
}
|
|
5560
|
-
}
|
|
5561
|
-
}
|
|
5562
|
-
}
|
|
5958
|
+
Full Tool Surface
|
|
5959
|
+
-----------------
|
|
5563
5960
|
|
|
5564
|
-
CLI
|
|
5961
|
+
The local CLI stdio transport exposes CRUD, commerce, cart, validation, product,
|
|
5962
|
+
schema, context, field-config, and guidance tools:
|
|
5565
5963
|
|
|
5566
5964
|
npx @01.software/cli mcp
|
|
5567
|
-
# Reads SOFTWARE_SECRET_KEY=sk01_... or pat01_...
|
|
5568
|
-
# Also reads SOFTWARE_PUBLISHABLE_KEY for CDN routing, rate limits, and quota enforcement
|
|
5569
|
-
|
|
5570
|
-
Security: never commit raw sk01_... or pat01_... tokens to repo-local MCP
|
|
5571
|
-
config files. Prefer client secret prompts, environment interpolation, OS secret
|
|
5572
|
-
managers, or ignored local files. Avoid passing real tokens directly on
|
|
5573
|
-
shared-machine command lines because shell history and process listings can
|
|
5574
|
-
expose them.
|
|
5575
|
-
|
|
5576
|
-
|
|
5577
|
-
Tools (34)
|
|
5578
|
-
----------
|
|
5579
|
-
|
|
5580
|
-
CRUD query, get, create, update, delete, delete-many, update-many
|
|
5581
|
-
Orders create-order, checkout, get-order, update-order, create-fulfillment, update-fulfillment, update-transaction
|
|
5582
|
-
Returns create-return, update-return, return-with-refund
|
|
5583
|
-
Cart add-cart-item, update-cart-item, remove-cart-item, clear-cart, apply-discount, remove-discount
|
|
5584
|
-
Validation validate-discount, calculate-shipping
|
|
5585
|
-
Products stock-check
|
|
5586
|
-
Schema get-collection-schema
|
|
5587
|
-
Context get-tenant-context
|
|
5588
|
-
Field Config list-configurable-fields, update-field-config
|
|
5589
|
-
Guidance sdk-get-recipe, sdk-search-docs, sdk-get-auth-setup, sdk-get-collection-pattern
|
|
5590
5965
|
|
|
5591
5966
|
Prompts (4): sdk-usage-guide, collection-query-help, order-flow-guide, feature-setup-guide
|
|
5592
5967
|
Resources (12): config, collections-schema, getting-started, guides, api, query-builder, react-query, server-api, customer-auth, browser-vs-server, file-upload, webhook
|
|
@@ -5600,6 +5975,19 @@ SDK https://01.software/docs/sdk/client
|
|
|
5600
5975
|
API Reference https://01.software/docs/api/rest-api
|
|
5601
5976
|
Console https://console.01.software
|
|
5602
5977
|
`;
|
|
5978
|
+
var PROTECTED_RESOURCE_METADATA = JSON.stringify({
|
|
5979
|
+
resource: MCP_RESOURCE_AUDIENCE,
|
|
5980
|
+
authorization_servers: [MCP_OAUTH_ISSUER],
|
|
5981
|
+
scopes_supported: [MCP_SCOPES.read, MCP_SCOPES.write]
|
|
5982
|
+
});
|
|
5983
|
+
var SERVICE_JWKS_PATH = "/.well-known/service-jwks.json";
|
|
5984
|
+
function writeOAuthError(res, status, error, description) {
|
|
5985
|
+
res.writeHead(status, {
|
|
5986
|
+
"Content-Type": "application/json",
|
|
5987
|
+
"WWW-Authenticate": `Bearer resource_metadata="${MCP_PROTECTED_RESOURCE_METADATA_PATH}", error="${error}", error_description="${description}"`
|
|
5988
|
+
});
|
|
5989
|
+
res.end(JSON.stringify({ error, error_description: description }));
|
|
5990
|
+
}
|
|
5603
5991
|
async function handler18(req, res) {
|
|
5604
5992
|
setCors(res);
|
|
5605
5993
|
if (req.method === "OPTIONS") {
|
|
@@ -5608,6 +5996,30 @@ async function handler18(req, res) {
|
|
|
5608
5996
|
return;
|
|
5609
5997
|
}
|
|
5610
5998
|
if (req.method === "GET") {
|
|
5999
|
+
const pathname = new URL(req.url ?? "/", MCP_RESOURCE_AUDIENCE).pathname;
|
|
6000
|
+
if (pathname === MCP_PROTECTED_RESOURCE_METADATA_PATH) {
|
|
6001
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
6002
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
6003
|
+
res.end(PROTECTED_RESOURCE_METADATA);
|
|
6004
|
+
return;
|
|
6005
|
+
}
|
|
6006
|
+
if (pathname === SERVICE_JWKS_PATH) {
|
|
6007
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
6008
|
+
try {
|
|
6009
|
+
res.writeHead(200, {
|
|
6010
|
+
"Cache-Control": "public, max-age=60",
|
|
6011
|
+
"Content-Type": "application/json"
|
|
6012
|
+
});
|
|
6013
|
+
res.end(JSON.stringify(mcpServicePublicJwks()));
|
|
6014
|
+
} catch {
|
|
6015
|
+
res.writeHead(503, {
|
|
6016
|
+
"Cache-Control": "no-store",
|
|
6017
|
+
"Content-Type": "application/json"
|
|
6018
|
+
});
|
|
6019
|
+
res.end(JSON.stringify({ keys: [] }));
|
|
6020
|
+
}
|
|
6021
|
+
return;
|
|
6022
|
+
}
|
|
5611
6023
|
res.writeHead(200, { "Content-Type": "text/plain; charset=utf-8" });
|
|
5612
6024
|
res.end(HOME_PAGE);
|
|
5613
6025
|
return;
|
|
@@ -5617,20 +6029,14 @@ async function handler18(req, res) {
|
|
|
5617
6029
|
res.end(METHOD_NOT_ALLOWED);
|
|
5618
6030
|
return;
|
|
5619
6031
|
}
|
|
5620
|
-
const
|
|
5621
|
-
|
|
6032
|
+
const auth = await validateBearerAuthorizationHeaderAsync(
|
|
6033
|
+
getHeaderValue(req.headers, "authorization")
|
|
6034
|
+
);
|
|
5622
6035
|
if (!auth.valid) {
|
|
5623
|
-
res
|
|
5624
|
-
res.end(JSON.stringify({ error: auth.error }));
|
|
5625
|
-
return;
|
|
5626
|
-
}
|
|
5627
|
-
const publishableKey = getHeaderValue(req.headers, "x-publishable-key") ?? getHeaderValue(req.headers, "x-client-key");
|
|
5628
|
-
if (!publishableKey) {
|
|
5629
|
-
res.writeHead(401, { "Content-Type": "application/json" });
|
|
5630
|
-
res.end(JSON.stringify({ error: "x-publishable-key header is required" }));
|
|
6036
|
+
writeOAuthError(res, auth.error === "insufficient_scope" ? 403 : 401, auth.error, auth.errorDescription);
|
|
5631
6037
|
return;
|
|
5632
6038
|
}
|
|
5633
|
-
const server = createServer();
|
|
6039
|
+
const server = createServer({ toolSurface: "oauth" });
|
|
5634
6040
|
const transport = new StreamableHTTPServerTransport({
|
|
5635
6041
|
sessionIdGenerator: void 0
|
|
5636
6042
|
});
|
|
@@ -5645,25 +6051,37 @@ async function handler18(req, res) {
|
|
|
5645
6051
|
void close();
|
|
5646
6052
|
});
|
|
5647
6053
|
await server.connect(transport);
|
|
5648
|
-
const
|
|
6054
|
+
const headers = new Headers();
|
|
5649
6055
|
for (const [key, value] of Object.entries(req.headers)) {
|
|
5650
|
-
if (typeof value === "string")
|
|
5651
|
-
else if (Array.isArray(value))
|
|
6056
|
+
if (typeof value === "string") headers.set(key, value);
|
|
6057
|
+
else if (Array.isArray(value)) headers.set(key, value.join(", "));
|
|
5652
6058
|
}
|
|
5653
|
-
await requestContext.run({ headers:
|
|
6059
|
+
await requestContext.run({ headers, auth: auth.context }, async () => {
|
|
5654
6060
|
try {
|
|
5655
6061
|
const body = req.body ?? JSON.parse(await readBody(req));
|
|
5656
6062
|
await transport.handleRequest(req, res, body);
|
|
5657
|
-
} catch {
|
|
5658
|
-
|
|
5659
|
-
res.writeHead(500, { "Content-Type": "application/json" });
|
|
5660
|
-
res.end(JSON.stringify({ error: "Internal server error" }));
|
|
5661
|
-
}
|
|
6063
|
+
} catch (err) {
|
|
6064
|
+
writeRequestError(res, err);
|
|
5662
6065
|
} finally {
|
|
5663
6066
|
await close();
|
|
5664
6067
|
}
|
|
5665
6068
|
});
|
|
5666
6069
|
}
|
|
6070
|
+
function writeRequestError(res, err) {
|
|
6071
|
+
if (res.headersSent) return;
|
|
6072
|
+
if (err instanceof SyntaxError) {
|
|
6073
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
6074
|
+
res.end(JSON.stringify({ error: "Invalid JSON body" }));
|
|
6075
|
+
return;
|
|
6076
|
+
}
|
|
6077
|
+
if (err instanceof Error && err.message === "Request body too large") {
|
|
6078
|
+
res.writeHead(413, { "Content-Type": "application/json" });
|
|
6079
|
+
res.end(JSON.stringify({ error: "Request body too large" }));
|
|
6080
|
+
return;
|
|
6081
|
+
}
|
|
6082
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
6083
|
+
res.end(JSON.stringify({ error: "Internal server error" }));
|
|
6084
|
+
}
|
|
5667
6085
|
export {
|
|
5668
6086
|
handler18 as default
|
|
5669
6087
|
};
|