@payments-ai/mcp 1.4.3 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/main.http.js +33549 -788
  2. package/package.json +15 -12
  3. package/dist/main.js +0 -1445
package/dist/main.js DELETED
@@ -1,1445 +0,0 @@
1
- #!/usr/bin/env node
2
- var __create = Object.create;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
9
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
10
- }) : x)(function(x) {
11
- if (typeof require !== "undefined") return require.apply(this, arguments);
12
- throw Error('Dynamic require of "' + x + '" is not supported');
13
- });
14
- var __commonJS = (cb, mod) => function __require2() {
15
- try {
16
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
17
- } catch (e) {
18
- throw mod = 0, e;
19
- }
20
- };
21
- var __copyProps = (to, from, except, desc) => {
22
- if (from && typeof from === "object" || typeof from === "function") {
23
- for (let key of __getOwnPropNames(from))
24
- if (!__hasOwnProp.call(to, key) && key !== except)
25
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
26
- }
27
- return to;
28
- };
29
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
30
- // If the importer is in node compatibility mode or this is not an ESM
31
- // file that has been converted to a CommonJS file using a Babel-
32
- // compatible transform (i.e. "__esModule" has not been set), then set
33
- // "default" to the CommonJS "module.exports" for node compatibility.
34
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
35
- mod
36
- ));
37
-
38
- // ../../packages/mcp-contracts/dist/tool-names.js
39
- var require_tool_names = __commonJS({
40
- "../../packages/mcp-contracts/dist/tool-names.js"(exports) {
41
- "use strict";
42
- Object.defineProperty(exports, "__esModule", { value: true });
43
- exports.MCP_TOOL_NAMES = void 0;
44
- exports.MCP_TOOL_NAMES = {
45
- PAYMENTS_AI_HEALTH: "payments_ai_health",
46
- CREATE_MERCHANT_ACCOUNT: "create_merchant_account",
47
- GET_MERCHANT_ACTIVATION_STATUS: "get_merchant_activation_status",
48
- SEARCH_PAYMENTS_AI_DOCS: "search_payments_ai_docs",
49
- CREATE_PRODUCT: "create_product",
50
- GET_PRODUCT_IMAGE_UPLOAD_URL: "get_product_image_upload_url",
51
- CONFIRM_PRODUCT_IMAGE: "confirm_product_image",
52
- GET_CHECKOUT_CUSTOMIZATION: "get_checkout_customization",
53
- UPDATE_CHECKOUT_CUSTOMIZATION: "update_checkout_customization"
54
- };
55
- }
56
- });
57
-
58
- // ../../packages/mcp-contracts/dist/create-product.js
59
- var require_create_product = __commonJS({
60
- "../../packages/mcp-contracts/dist/create-product.js"(exports) {
61
- "use strict";
62
- Object.defineProperty(exports, "__esModule", { value: true });
63
- exports.createMcpProductOutputSchema = exports.createMcpProductInputSchema = exports.createMcpProductBodySchema = void 0;
64
- var zod_1 = __require("zod");
65
- var PLAN_TYPES = ["free-access", "one-time", "recurring"];
66
- var BILLING_PERIODS = ["day", "week", "month", "year"];
67
- var PRODUCT_STATUSES = ["draft", "active", "archived"];
68
- var createMcpPlanSchema = zod_1.z.object({
69
- name: zod_1.z.string().trim().min(1).max(30),
70
- description: zod_1.z.string().trim().max(80).optional(),
71
- richDescription: zod_1.z.string().trim().max(65535).optional(),
72
- currency: zod_1.z.string().trim().length(3).transform((v) => v.toLowerCase()),
73
- amount: zod_1.z.number().nonnegative(),
74
- type: zod_1.z.enum(PLAN_TYPES),
75
- billingPeriod: zod_1.z.enum(BILLING_PERIODS),
76
- periodLength: zod_1.z.number().int().positive(),
77
- freeTrial: zod_1.z.number().int().min(0).optional()
78
- }).superRefine((plan, ctx) => {
79
- if (plan.type === "free-access")
80
- return;
81
- if (plan.amount <= 0) {
82
- ctx.addIssue({
83
- code: "custom",
84
- message: "Amount must be greater than 0 for paid plans",
85
- path: ["amount"]
86
- });
87
- }
88
- });
89
- exports.createMcpProductBodySchema = zod_1.z.object({
90
- name: zod_1.z.string().trim().min(1).max(30),
91
- description: zod_1.z.string().trim().min(1).max(80).optional(),
92
- taxCodeId: zod_1.z.string().trim().min(1).max(255).optional(),
93
- status: zod_1.z.enum(PRODUCT_STATUSES).optional().default("draft"),
94
- discountCode: zod_1.z.string().trim().min(1).max(255).optional(),
95
- plans: zod_1.z.array(createMcpPlanSchema).min(1)
96
- }).strict();
97
- exports.createMcpProductInputSchema = exports.createMcpProductBodySchema.extend({
98
- merchantId: zod_1.z.uuid()
99
- });
100
- exports.createMcpProductOutputSchema = zod_1.z.object({
101
- id: zod_1.z.string(),
102
- planIds: zod_1.z.array(zod_1.z.string())
103
- });
104
- }
105
- });
106
-
107
- // ../../packages/mcp-contracts/dist/product-image-presigned-upload.js
108
- var require_product_image_presigned_upload = __commonJS({
109
- "../../packages/mcp-contracts/dist/product-image-presigned-upload.js"(exports) {
110
- "use strict";
111
- Object.defineProperty(exports, "__esModule", { value: true });
112
- exports.PRODUCT_IMAGE_MIME_TYPES = exports.MAX_PRODUCT_IMAGE_UPLOAD_BYTES = exports.confirmProductImageOutputSchema = exports.confirmProductImageInputSchema = exports.confirmProductImageBodySchema = exports.productImageUploadUrlOutputSchema = exports.productImageUploadUrlInputSchema = exports.productImageUploadUrlBodySchema = void 0;
113
- var zod_1 = __require("zod");
114
- var PRODUCT_IMAGE_MIME_TYPES = ["image/png", "image/jpeg", "image/jpg", "image/webp"];
115
- exports.PRODUCT_IMAGE_MIME_TYPES = PRODUCT_IMAGE_MIME_TYPES;
116
- var MAX_PRODUCT_IMAGE_UPLOAD_BYTES = 5242880;
117
- exports.MAX_PRODUCT_IMAGE_UPLOAD_BYTES = MAX_PRODUCT_IMAGE_UPLOAD_BYTES;
118
- var mimeTypeSchema = zod_1.z.enum(PRODUCT_IMAGE_MIME_TYPES, {
119
- message: "mimeType must be image/png, image/jpeg, image/jpg, or image/webp. Recovery: convert the file to a supported format."
120
- });
121
- var fileNameSchema = zod_1.z.string().trim().min(1, "fileName is required.").max(255, "fileName must be at most 255 characters.");
122
- exports.productImageUploadUrlBodySchema = zod_1.z.object({
123
- fileName: fileNameSchema,
124
- mimeType: mimeTypeSchema
125
- }).strict();
126
- exports.productImageUploadUrlInputSchema = exports.productImageUploadUrlBodySchema.extend({
127
- merchantId: zod_1.z.uuid(),
128
- productId: zod_1.z.uuid()
129
- });
130
- exports.productImageUploadUrlOutputSchema = zod_1.z.object({
131
- // S3 POST endpoint the client submits the multipart/form-data upload to.
132
- url: zod_1.z.string(),
133
- // Form fields the client must include in the multipart body (policy, signature,
134
- // key, Content-Type, ...). The `file` field must be added last per S3's spec.
135
- fields: zod_1.z.record(zod_1.z.string(), zod_1.z.string()),
136
- // Opaque storage key the client must echo back to confirmProductImage. Bound to the
137
- // merchant; confirm rejects keys outside the caller's own prefix.
138
- key: zod_1.z.string(),
139
- expiresIn: zod_1.z.number().int().positive()
140
- });
141
- exports.confirmProductImageBodySchema = zod_1.z.object({
142
- key: zod_1.z.string().trim().min(1, "key is required. Recovery: use the key returned by the upload-url step.")
143
- }).strict();
144
- exports.confirmProductImageInputSchema = exports.confirmProductImageBodySchema.extend({
145
- merchantId: zod_1.z.uuid(),
146
- productId: zod_1.z.uuid()
147
- });
148
- exports.confirmProductImageOutputSchema = zod_1.z.object({
149
- imageUrl: zod_1.z.string()
150
- });
151
- }
152
- });
153
-
154
- // ../../packages/mcp-contracts/dist/create-merchant-account.js
155
- var require_create_merchant_account = __commonJS({
156
- "../../packages/mcp-contracts/dist/create-merchant-account.js"(exports) {
157
- "use strict";
158
- Object.defineProperty(exports, "__esModule", { value: true });
159
- exports.createMerchantAccountOutputSchema = exports.createMerchantAccountInputSchema = void 0;
160
- var zod_1 = __require("zod");
161
- exports.createMerchantAccountInputSchema = zod_1.z.object({
162
- name: zod_1.z.string().trim().min(1, {
163
- message: "Provide a non-empty business or display name. Recovery: re-send the tool call with a visible label for the merchant account."
164
- }),
165
- email: zod_1.z.email({
166
- error: "Provide a valid email. Recovery: check spelling, domain, and that the value is a single RFC-style address."
167
- })
168
- });
169
- exports.createMerchantAccountOutputSchema = zod_1.z.object({
170
- merchantId: zod_1.z.uuid()
171
- });
172
- }
173
- });
174
-
175
- // ../../packages/mcp-contracts/dist/activation-status.js
176
- var require_activation_status = __commonJS({
177
- "../../packages/mcp-contracts/dist/activation-status.js"(exports) {
178
- "use strict";
179
- Object.defineProperty(exports, "__esModule", { value: true });
180
- exports.activationStatusOutputSchema = exports.activationStatusEnumSchema = exports.activationStatusInputSchema = void 0;
181
- var zod_1 = __require("zod");
182
- exports.activationStatusInputSchema = zod_1.z.object({
183
- merchantId: zod_1.z.string().trim().min(1, {
184
- message: "Provide the merchant account identifier returned from create_merchant_account. Recovery: copy the merchantId from a prior successful create_merchant_account response."
185
- })
186
- });
187
- exports.activationStatusEnumSchema = zod_1.z.enum(["pending", "not_provisioned", "active"]);
188
- exports.activationStatusOutputSchema = zod_1.z.object({
189
- status: exports.activationStatusEnumSchema
190
- });
191
- }
192
- });
193
-
194
- // ../../packages/mcp-contracts/dist/payments-ai-health.js
195
- var require_payments_ai_health = __commonJS({
196
- "../../packages/mcp-contracts/dist/payments-ai-health.js"(exports) {
197
- "use strict";
198
- Object.defineProperty(exports, "__esModule", { value: true });
199
- exports.paymentsAiHealthOutputSchema = exports.paymentsAiHealthBackendSchema = exports.paymentsAiHealthBackendProbeSchema = void 0;
200
- var zod_1 = __require("zod");
201
- exports.paymentsAiHealthBackendProbeSchema = zod_1.z.object({
202
- path: zod_1.z.string(),
203
- ok: zod_1.z.boolean(),
204
- httpStatus: zod_1.z.number().optional(),
205
- message: zod_1.z.string()
206
- });
207
- exports.paymentsAiHealthBackendSchema = zod_1.z.object({
208
- baseUrlConfigured: zod_1.z.boolean(),
209
- probe: exports.paymentsAiHealthBackendProbeSchema.optional()
210
- });
211
- exports.paymentsAiHealthOutputSchema = zod_1.z.object({
212
- serverName: zod_1.z.string(),
213
- version: zod_1.z.string(),
214
- /** Always true for this PoC slice — tool remains illustrative / non-mutating. */
215
- stub: zod_1.z.literal(true),
216
- backend: exports.paymentsAiHealthBackendSchema
217
- });
218
- }
219
- });
220
-
221
- // ../../packages/mcp-contracts/dist/search-payments-ai-docs.js
222
- var require_search_payments_ai_docs = __commonJS({
223
- "../../packages/mcp-contracts/dist/search-payments-ai-docs.js"(exports) {
224
- "use strict";
225
- Object.defineProperty(exports, "__esModule", { value: true });
226
- exports.searchPaymentsAiDocsOutputSchema = exports.searchPaymentsAiDocsResultSchema = exports.searchPaymentsAiDocsInputSchema = void 0;
227
- var zod_1 = __require("zod");
228
- exports.searchPaymentsAiDocsInputSchema = zod_1.z.object({
229
- query: zod_1.z.string().min(1).max(500).describe("Search query")
230
- });
231
- exports.searchPaymentsAiDocsResultSchema = zod_1.z.object({
232
- title: zod_1.z.string().describe("Section title"),
233
- path: zod_1.z.string().describe("Documentation path/anchor"),
234
- content: zod_1.z.string().describe("Section content")
235
- });
236
- exports.searchPaymentsAiDocsOutputSchema = zod_1.z.object({
237
- results: zod_1.z.array(exports.searchPaymentsAiDocsResultSchema).describe("Matching documentation sections with titles and links")
238
- });
239
- }
240
- });
241
-
242
- // ../../packages/mcp-contracts/dist/checkout-customization.js
243
- var require_checkout_customization = __commonJS({
244
- "../../packages/mcp-contracts/dist/checkout-customization.js"(exports) {
245
- "use strict";
246
- Object.defineProperty(exports, "__esModule", { value: true });
247
- exports.checkoutCustomizationOutputSchema = exports.updateCheckoutCustomizationInputSchema = exports.getCheckoutCustomizationInputSchema = exports.checkoutCustomizationFieldsSchema = void 0;
248
- var zod_1 = __require("zod");
249
- var HEX_COLOR_REGEX = /^#(?:[0-9a-fA-F]{6})$/;
250
- var CHECKOUT_THEME_MODES = ["light", "dark"];
251
- var CHECKOUT_FONT_FAMILIES = ["Inter", "Roboto"];
252
- var CHECKOUT_INPUT_STYLES = ["rounded", "square"];
253
- var hexColor = zod_1.z.string().regex(HEX_COLOR_REGEX, {
254
- message: 'Provide a 6-digit hex color like "#1A2B3C". Recovery: include the leading "#".'
255
- });
256
- exports.checkoutCustomizationFieldsSchema = zod_1.z.object({
257
- themeMode: zod_1.z.enum(CHECKOUT_THEME_MODES).optional(),
258
- backgroundColor: hexColor.optional(),
259
- buttonColor: hexColor.optional(),
260
- buttonTextColor: hexColor.optional(),
261
- fontColor: hexColor.optional(),
262
- fontFamily: zod_1.z.enum(CHECKOUT_FONT_FAMILIES).optional(),
263
- inputStyle: zod_1.z.enum(CHECKOUT_INPUT_STYLES).optional()
264
- }).strict();
265
- exports.getCheckoutCustomizationInputSchema = zod_1.z.object({
266
- merchantId: zod_1.z.uuid()
267
- });
268
- exports.updateCheckoutCustomizationInputSchema = zod_1.z.object({
269
- merchantId: zod_1.z.uuid(),
270
- // At least one field must be present — an empty update is a no-op that would still bump
271
- // updated_at, so reject it with a clear message rather than writing nothing meaningful.
272
- customization: exports.checkoutCustomizationFieldsSchema.refine((c) => Object.keys(c).length > 0, 'Provide at least one field to change. Recovery: include e.g. "buttonColor" or "themeMode".')
273
- });
274
- exports.checkoutCustomizationOutputSchema = exports.checkoutCustomizationFieldsSchema.extend({
275
- logoUrl: zod_1.z.string().optional()
276
- }).passthrough();
277
- }
278
- });
279
-
280
- // ../../packages/mcp-contracts/dist/index.js
281
- var require_dist = __commonJS({
282
- "../../packages/mcp-contracts/dist/index.js"(exports) {
283
- "use strict";
284
- Object.defineProperty(exports, "__esModule", { value: true });
285
- exports.checkoutCustomizationOutputSchema = exports.updateCheckoutCustomizationInputSchema = exports.getCheckoutCustomizationInputSchema = exports.checkoutCustomizationFieldsSchema = exports.searchPaymentsAiDocsOutputSchema = exports.searchPaymentsAiDocsResultSchema = exports.searchPaymentsAiDocsInputSchema = exports.paymentsAiHealthOutputSchema = exports.paymentsAiHealthBackendSchema = exports.paymentsAiHealthBackendProbeSchema = exports.activationStatusOutputSchema = exports.activationStatusEnumSchema = exports.activationStatusInputSchema = exports.createMerchantAccountOutputSchema = exports.createMerchantAccountInputSchema = exports.PRODUCT_IMAGE_MIME_TYPES = exports.MAX_PRODUCT_IMAGE_UPLOAD_BYTES = exports.confirmProductImageOutputSchema = exports.confirmProductImageInputSchema = exports.confirmProductImageBodySchema = exports.productImageUploadUrlOutputSchema = exports.productImageUploadUrlInputSchema = exports.productImageUploadUrlBodySchema = exports.createMcpProductOutputSchema = exports.createMcpProductInputSchema = exports.createMcpProductBodySchema = exports.MCP_TOOL_NAMES = void 0;
286
- var tool_names_js_1 = require_tool_names();
287
- Object.defineProperty(exports, "MCP_TOOL_NAMES", { enumerable: true, get: function() {
288
- return tool_names_js_1.MCP_TOOL_NAMES;
289
- } });
290
- var create_product_js_1 = require_create_product();
291
- Object.defineProperty(exports, "createMcpProductBodySchema", { enumerable: true, get: function() {
292
- return create_product_js_1.createMcpProductBodySchema;
293
- } });
294
- Object.defineProperty(exports, "createMcpProductInputSchema", { enumerable: true, get: function() {
295
- return create_product_js_1.createMcpProductInputSchema;
296
- } });
297
- Object.defineProperty(exports, "createMcpProductOutputSchema", { enumerable: true, get: function() {
298
- return create_product_js_1.createMcpProductOutputSchema;
299
- } });
300
- var product_image_presigned_upload_js_1 = require_product_image_presigned_upload();
301
- Object.defineProperty(exports, "productImageUploadUrlBodySchema", { enumerable: true, get: function() {
302
- return product_image_presigned_upload_js_1.productImageUploadUrlBodySchema;
303
- } });
304
- Object.defineProperty(exports, "productImageUploadUrlInputSchema", { enumerable: true, get: function() {
305
- return product_image_presigned_upload_js_1.productImageUploadUrlInputSchema;
306
- } });
307
- Object.defineProperty(exports, "productImageUploadUrlOutputSchema", { enumerable: true, get: function() {
308
- return product_image_presigned_upload_js_1.productImageUploadUrlOutputSchema;
309
- } });
310
- Object.defineProperty(exports, "confirmProductImageBodySchema", { enumerable: true, get: function() {
311
- return product_image_presigned_upload_js_1.confirmProductImageBodySchema;
312
- } });
313
- Object.defineProperty(exports, "confirmProductImageInputSchema", { enumerable: true, get: function() {
314
- return product_image_presigned_upload_js_1.confirmProductImageInputSchema;
315
- } });
316
- Object.defineProperty(exports, "confirmProductImageOutputSchema", { enumerable: true, get: function() {
317
- return product_image_presigned_upload_js_1.confirmProductImageOutputSchema;
318
- } });
319
- Object.defineProperty(exports, "MAX_PRODUCT_IMAGE_UPLOAD_BYTES", { enumerable: true, get: function() {
320
- return product_image_presigned_upload_js_1.MAX_PRODUCT_IMAGE_UPLOAD_BYTES;
321
- } });
322
- Object.defineProperty(exports, "PRODUCT_IMAGE_MIME_TYPES", { enumerable: true, get: function() {
323
- return product_image_presigned_upload_js_1.PRODUCT_IMAGE_MIME_TYPES;
324
- } });
325
- var create_merchant_account_js_1 = require_create_merchant_account();
326
- Object.defineProperty(exports, "createMerchantAccountInputSchema", { enumerable: true, get: function() {
327
- return create_merchant_account_js_1.createMerchantAccountInputSchema;
328
- } });
329
- Object.defineProperty(exports, "createMerchantAccountOutputSchema", { enumerable: true, get: function() {
330
- return create_merchant_account_js_1.createMerchantAccountOutputSchema;
331
- } });
332
- var activation_status_js_1 = require_activation_status();
333
- Object.defineProperty(exports, "activationStatusInputSchema", { enumerable: true, get: function() {
334
- return activation_status_js_1.activationStatusInputSchema;
335
- } });
336
- Object.defineProperty(exports, "activationStatusEnumSchema", { enumerable: true, get: function() {
337
- return activation_status_js_1.activationStatusEnumSchema;
338
- } });
339
- Object.defineProperty(exports, "activationStatusOutputSchema", { enumerable: true, get: function() {
340
- return activation_status_js_1.activationStatusOutputSchema;
341
- } });
342
- var payments_ai_health_js_1 = require_payments_ai_health();
343
- Object.defineProperty(exports, "paymentsAiHealthBackendProbeSchema", { enumerable: true, get: function() {
344
- return payments_ai_health_js_1.paymentsAiHealthBackendProbeSchema;
345
- } });
346
- Object.defineProperty(exports, "paymentsAiHealthBackendSchema", { enumerable: true, get: function() {
347
- return payments_ai_health_js_1.paymentsAiHealthBackendSchema;
348
- } });
349
- Object.defineProperty(exports, "paymentsAiHealthOutputSchema", { enumerable: true, get: function() {
350
- return payments_ai_health_js_1.paymentsAiHealthOutputSchema;
351
- } });
352
- var search_payments_ai_docs_js_1 = require_search_payments_ai_docs();
353
- Object.defineProperty(exports, "searchPaymentsAiDocsInputSchema", { enumerable: true, get: function() {
354
- return search_payments_ai_docs_js_1.searchPaymentsAiDocsInputSchema;
355
- } });
356
- Object.defineProperty(exports, "searchPaymentsAiDocsResultSchema", { enumerable: true, get: function() {
357
- return search_payments_ai_docs_js_1.searchPaymentsAiDocsResultSchema;
358
- } });
359
- Object.defineProperty(exports, "searchPaymentsAiDocsOutputSchema", { enumerable: true, get: function() {
360
- return search_payments_ai_docs_js_1.searchPaymentsAiDocsOutputSchema;
361
- } });
362
- var checkout_customization_js_1 = require_checkout_customization();
363
- Object.defineProperty(exports, "checkoutCustomizationFieldsSchema", { enumerable: true, get: function() {
364
- return checkout_customization_js_1.checkoutCustomizationFieldsSchema;
365
- } });
366
- Object.defineProperty(exports, "getCheckoutCustomizationInputSchema", { enumerable: true, get: function() {
367
- return checkout_customization_js_1.getCheckoutCustomizationInputSchema;
368
- } });
369
- Object.defineProperty(exports, "updateCheckoutCustomizationInputSchema", { enumerable: true, get: function() {
370
- return checkout_customization_js_1.updateCheckoutCustomizationInputSchema;
371
- } });
372
- Object.defineProperty(exports, "checkoutCustomizationOutputSchema", { enumerable: true, get: function() {
373
- return checkout_customization_js_1.checkoutCustomizationOutputSchema;
374
- } });
375
- }
376
- });
377
-
378
- // src/load-env.ts
379
- import path from "node:path";
380
- import dotenv from "dotenv";
381
- var packageRoot = path.resolve(import.meta.dirname, "..");
382
- dotenv.config({ path: path.join(packageRoot, ".env"), quiet: true });
383
- dotenv.config({ path: path.join(process.cwd(), ".env"), quiet: true });
384
-
385
- // src/observability/instrument-sentry.ts
386
- import * as Sentry from "@sentry/node";
387
-
388
- // src/config/env.ts
389
- var APP_ENV_VALUES = ["local", "development", "production", "stage", "test"];
390
- function readAppEnv(env = process.env) {
391
- const raw = env.APP_ENV?.trim();
392
- if (!raw) {
393
- return void 0;
394
- }
395
- if (!APP_ENV_VALUES.includes(raw)) {
396
- throw new Error(`APP_ENV must be one of: ${APP_ENV_VALUES.join(", ")}`);
397
- }
398
- return raw;
399
- }
400
-
401
- // src/observability/sentry.config.ts
402
- function parseTracesSampleRate(value, defaultValue) {
403
- if (!value?.trim()) {
404
- return defaultValue;
405
- }
406
- const parsed = Number(value);
407
- if (!Number.isFinite(parsed) || parsed < 0 || parsed > 1) {
408
- return defaultValue;
409
- }
410
- return parsed;
411
- }
412
- function defaultTracesSampleRateForAppEnv(appEnv) {
413
- if (appEnv === "stage" || appEnv === "production") {
414
- return 0.2;
415
- }
416
- return 1;
417
- }
418
- function readSentryDsn(env = process.env) {
419
- const dsn = env.SENTRY_DSN?.trim();
420
- return dsn || void 0;
421
- }
422
- function resolveSentryEnvironment(env = process.env) {
423
- const fromEnv = env.SENTRY_ENVIRONMENT?.trim();
424
- if (fromEnv) {
425
- return fromEnv;
426
- }
427
- return readAppEnv(env) ?? "local";
428
- }
429
- function readSentryTracesSampleRate(env = process.env) {
430
- const appEnv = readAppEnv(env);
431
- return parseTracesSampleRate(
432
- env.SENTRY_TRACES_SAMPLE_RATE,
433
- defaultTracesSampleRateForAppEnv(appEnv)
434
- );
435
- }
436
- function scrubAuthorizationHeader(headers) {
437
- if (!headers) {
438
- return headers;
439
- }
440
- const scrubbed = { ...headers };
441
- for (const key of Object.keys(scrubbed)) {
442
- if (key.toLowerCase() === "authorization") {
443
- scrubbed[key] = "[Filtered]";
444
- }
445
- }
446
- return scrubbed;
447
- }
448
- function scrubEventRequestHeaders(event) {
449
- const request = event.request;
450
- if (!request?.headers) {
451
- return event;
452
- }
453
- return {
454
- ...event,
455
- request: {
456
- ...request,
457
- headers: scrubAuthorizationHeader(request.headers)
458
- }
459
- };
460
- }
461
- function buildSentryInitOptions(env = process.env) {
462
- const dsn = readSentryDsn(env);
463
- if (!dsn) {
464
- return void 0;
465
- }
466
- return {
467
- dsn,
468
- environment: resolveSentryEnvironment(env),
469
- tracesSampleRate: readSentryTracesSampleRate(env),
470
- sendDefaultPii: false,
471
- beforeSend(event) {
472
- return scrubEventRequestHeaders(event);
473
- },
474
- beforeSendTransaction(event) {
475
- return scrubEventRequestHeaders(event);
476
- }
477
- };
478
- }
479
-
480
- // src/observability/instrument-sentry.ts
481
- var options = buildSentryInitOptions();
482
- if (options) {
483
- Sentry.init(options);
484
- }
485
-
486
- // src/main.ts
487
- import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
488
-
489
- // src/backend/backend-client.ts
490
- var BACKEND_HTTP_HEALTH_PATH = "/api/v1/health-checks/http";
491
- var BACKEND_CREATE_MERCHANT_ACCOUNT_PATH = "/api/v1/mcp/provision";
492
- function backendCreateProductPath(merchantId) {
493
- return `/api/v1/mcp/merchants/${merchantId}/products`;
494
- }
495
- function backendActivationStatusPath(merchantId) {
496
- return `/api/v1/mcp/merchants/${merchantId}/activation-status`;
497
- }
498
- function backendGetCheckoutCustomizationPath(merchantId) {
499
- return `/api/v1/mcp/merchants/${merchantId}/checkout/customization`;
500
- }
501
- function backendProductImageUploadUrlPath(merchantId, productId) {
502
- return `/api/v1/mcp/merchants/${merchantId}/products/${productId}/image/upload-url`;
503
- }
504
- function backendConfirmProductImagePath(merchantId, productId) {
505
- return `/api/v1/mcp/merchants/${merchantId}/products/${productId}/image/confirm`;
506
- }
507
- function backendUpdateCheckoutCustomizationPath(merchantId) {
508
- return `/api/v1/mcp/merchants/${merchantId}/checkout/customization`;
509
- }
510
- var DEFAULT_TIMEOUT_MS = 1e4;
511
- function normalizeBaseUrl(baseUrl) {
512
- return baseUrl.replace(/\/+$/, "");
513
- }
514
- function joinUrl(baseUrl, path2) {
515
- const p = path2.startsWith("/") ? path2 : `/${path2}`;
516
- return `${normalizeBaseUrl(baseUrl)}${p}`;
517
- }
518
- var BackendClient = class {
519
- baseUrl;
520
- timeoutMs;
521
- fetchImpl;
522
- authorizationHeader;
523
- constructor(config) {
524
- this.baseUrl = normalizeBaseUrl(config.baseUrl);
525
- this.timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;
526
- this.fetchImpl = config.fetchImpl ?? globalThis.fetch;
527
- this.authorizationHeader = config.authorizationHeader;
528
- }
529
- async get(path2) {
530
- const url = joinUrl(this.baseUrl, path2);
531
- let response;
532
- try {
533
- response = await this.fetchImpl(url, {
534
- method: "GET",
535
- headers: { Accept: "application/json", ...this.buildAuthHeader() },
536
- signal: AbortSignal.timeout(this.timeoutMs)
537
- });
538
- } catch (error) {
539
- const isAbort = error instanceof Error && error.name === "TimeoutError";
540
- return {
541
- ok: false,
542
- kind: "network",
543
- message: isAbort ? `Backend request timed out after ${this.timeoutMs}ms. Check BACKEND_BASE_URL, network reachability, and firewall rules.` : `Could not reach backend at ${this.baseUrl}. Verify BACKEND_BASE_URL and that the backend process is running. (${error instanceof Error ? error.message : String(error)})`
544
- };
545
- }
546
- const bodyText = await response.text();
547
- if (!response.ok) {
548
- return {
549
- ok: false,
550
- kind: "http_error",
551
- status: response.status,
552
- message: `Backend returned HTTP ${response.status}. ${bodyText ? `Body: ${bodyText.slice(0, 500)}` : "Empty response body."} If this persists, confirm the route exists and ingress targets the API service.`
553
- };
554
- }
555
- return { ok: true, status: response.status, bodyText };
556
- }
557
- post(path2, jsonBody) {
558
- return this.sendJson("POST", path2, jsonBody);
559
- }
560
- patch(path2, jsonBody) {
561
- return this.sendJson("PATCH", path2, jsonBody);
562
- }
563
- postNoContent(path2, jsonBody) {
564
- return this.sendJson("POST", path2, jsonBody);
565
- }
566
- async sendJson(method, path2, jsonBody) {
567
- const url = joinUrl(this.baseUrl, path2);
568
- let response;
569
- try {
570
- response = await this.fetchImpl(url, {
571
- method,
572
- headers: {
573
- Accept: "application/json",
574
- "Content-Type": "application/json",
575
- ...this.buildAuthHeader()
576
- },
577
- body: JSON.stringify(jsonBody),
578
- signal: AbortSignal.timeout(this.timeoutMs)
579
- });
580
- } catch (error) {
581
- const isAbort = error instanceof Error && error.name === "TimeoutError";
582
- return {
583
- ok: false,
584
- kind: "network",
585
- message: isAbort ? `Backend request timed out after ${this.timeoutMs}ms. Check BACKEND_BASE_URL, network reachability, and firewall rules.` : `Could not reach backend at ${this.baseUrl}. Verify BACKEND_BASE_URL and that the backend process is running. (${error instanceof Error ? error.message : String(error)})`
586
- };
587
- }
588
- const bodyText = await response.text();
589
- if (!response.ok) {
590
- return {
591
- ok: false,
592
- kind: "http_error",
593
- status: response.status,
594
- message: `Backend returned HTTP ${response.status}. ${bodyText ? `Body: ${bodyText.slice(0, 500)}` : "Empty response body."} If this persists, confirm the route exists and ingress targets the API service.`
595
- };
596
- }
597
- return { ok: true, status: response.status, bodyText };
598
- }
599
- buildAuthHeader() {
600
- return this.authorizationHeader ? { Authorization: this.authorizationHeader } : {};
601
- }
602
- };
603
- function createBackendClientFromEnv(explicitBaseUrl) {
604
- const raw = explicitBaseUrl?.trim() || process.env.BACKEND_BASE_URL?.trim();
605
- if (!raw) {
606
- console.error(
607
- "BACKEND_BASE_URL is not set; MCP server runs in stub-only mode for backend-backed probes (set it to enable HTTP checks from tools)."
608
- );
609
- return void 0;
610
- }
611
- const timeoutRaw = process.env.BACKEND_HTTP_TIMEOUT_MS?.trim();
612
- const timeoutMs = timeoutRaw ? Number(timeoutRaw) : DEFAULT_TIMEOUT_MS;
613
- const parsedTimeout = Number.isFinite(timeoutMs) && timeoutMs > 0 ? timeoutMs : DEFAULT_TIMEOUT_MS;
614
- const serviceToken = process.env.BACKEND_SERVICE_TOKEN?.trim();
615
- const authorizationHeader = serviceToken ? `Bearer ${serviceToken}` : void 0;
616
- return new BackendClient({ baseUrl: raw, timeoutMs: parsedTimeout, authorizationHeader });
617
- }
618
-
619
- // src/load-package-meta.ts
620
- import { readFileSync } from "node:fs";
621
- import { dirname, join } from "node:path";
622
- import { fileURLToPath } from "node:url";
623
- var __dirname = dirname(fileURLToPath(import.meta.url));
624
- function readMcpServerVersion() {
625
- const path2 = join(__dirname, "..", "package.json");
626
- const raw = readFileSync(path2, "utf8");
627
- const pkg = JSON.parse(raw);
628
- return pkg.version ?? "0.0.0";
629
- }
630
-
631
- // src/observability/create-instrumented-mcp-server.ts
632
- import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
633
- var MCP_SERVER_NAME = "pai-managed-mcp-server";
634
- function createInstrumentedMcpServer(options2) {
635
- const server = new McpServer({
636
- name: MCP_SERVER_NAME,
637
- version: options2.version
638
- });
639
- return Sentry.wrapMcpServerWithSentry(server, {
640
- recordInputs: false,
641
- recordOutputs: false
642
- });
643
- }
644
-
645
- // src/tools/register-tools.ts
646
- var import_mcp_contracts9 = __toESM(require_dist(), 1);
647
-
648
- // src/tools/merchant/activation-status.tool.ts
649
- var import_mcp_contracts = __toESM(require_dist(), 1);
650
-
651
- // src/shared/zod-format.ts
652
- function formatZodIssuesForTool(issues) {
653
- return issues.map((issue) => {
654
- const path2 = issue.path.length > 0 ? issue.path.join(".") : "arguments";
655
- return `[${path2}] ${issue.message}`;
656
- }).join("\n");
657
- }
658
-
659
- // src/tools/merchant/activation-status.tool.ts
660
- function stubStatusForAccount(merchantId) {
661
- return merchantId.toLowerCase().includes("pending") ? "pending" : "not_provisioned";
662
- }
663
- function buildActivationStatusStub(input) {
664
- return import_mcp_contracts.activationStatusOutputSchema.parse({
665
- status: stubStatusForAccount(input.merchantId)
666
- });
667
- }
668
- function runActivationStatusHandler(raw) {
669
- const parsed = import_mcp_contracts.activationStatusInputSchema.safeParse(raw);
670
- if (!parsed.success) {
671
- return {
672
- ok: false,
673
- errorText: `Invalid arguments for get_merchant_activation_status.
674
- ${formatZodIssuesForTool(parsed.error.issues)}`
675
- };
676
- }
677
- return { ok: true, data: buildActivationStatusStub(parsed.data) };
678
- }
679
- async function runActivationStatusHandlerWithBackend(backendClient, input) {
680
- const result = await backendClient.get(backendActivationStatusPath(input.merchantId));
681
- if (!result.ok) {
682
- return {
683
- ok: false,
684
- errorText: `Backend activation status request failed.
685
- ${result.message}
686
- Recovery: verify BACKEND_BASE_URL and that GET ${backendActivationStatusPath(input.merchantId)} is reachable from the MCP container or host.`
687
- };
688
- }
689
- let parsedJson;
690
- try {
691
- parsedJson = JSON.parse(result.bodyText);
692
- } catch {
693
- return {
694
- ok: false,
695
- errorText: "Backend returned non-JSON for get_merchant_activation_status. Recovery: confirm the API matches this MCP server version."
696
- };
697
- }
698
- const out = import_mcp_contracts.activationStatusOutputSchema.safeParse(parsedJson);
699
- if (!out.success) {
700
- return {
701
- ok: false,
702
- errorText: "Backend response did not match the expected activation status output schema. Recovery: inspect backend deployment and shared @pai-managed/mcp-contracts version."
703
- };
704
- }
705
- return { ok: true, data: out.data };
706
- }
707
-
708
- // src/tools/product/create-product.tool.ts
709
- var import_mcp_contracts2 = __toESM(require_dist(), 1);
710
- async function runCreateProductHandler(backendClient, input) {
711
- const { merchantId, ...body } = input;
712
- const result = await backendClient.post(backendCreateProductPath(merchantId), body);
713
- if (!result.ok) {
714
- return {
715
- ok: false,
716
- errorText: `Backend create product request failed.
717
- ${result.message}
718
- Recovery: verify BACKEND_BASE_URL and that POST /api/v1/mcp/merchants/:merchantId/products is reachable.`
719
- };
720
- }
721
- let parsedJson;
722
- try {
723
- parsedJson = JSON.parse(result.bodyText);
724
- } catch {
725
- return {
726
- ok: false,
727
- errorText: "Backend returned non-JSON for create product. Recovery: confirm the API matches this MCP server version."
728
- };
729
- }
730
- const out = import_mcp_contracts2.createMcpProductOutputSchema.safeParse(parsedJson);
731
- if (!out.success) {
732
- return {
733
- ok: false,
734
- errorText: "Backend response did not match expected create product output schema. Recovery: inspect backend deployment and shared @pai-managed/mcp-contracts version."
735
- };
736
- }
737
- return { ok: true, data: out.data };
738
- }
739
- function runCreateProductHandlerValidation(raw) {
740
- const parsed = import_mcp_contracts2.createMcpProductInputSchema.safeParse(raw);
741
- if (!parsed.success) {
742
- return {
743
- ok: false,
744
- errorText: `Invalid arguments for create_product.
745
- ${formatZodIssuesForTool(parsed.error.issues)}`
746
- };
747
- }
748
- return { ok: true, data: parsed.data };
749
- }
750
-
751
- // src/tools/product/get-product-image-upload-url.tool.ts
752
- var import_mcp_contracts3 = __toESM(require_dist(), 1);
753
- function runGetProductImageUploadUrlValidation(raw) {
754
- const parsed = import_mcp_contracts3.productImageUploadUrlInputSchema.safeParse(raw);
755
- if (!parsed.success) {
756
- return {
757
- ok: false,
758
- errorText: `Invalid arguments for get_product_image_upload_url.
759
- ${formatZodIssuesForTool(parsed.error.issues)}`
760
- };
761
- }
762
- return { ok: true, data: parsed.data };
763
- }
764
- function mapHttpError(status, message) {
765
- if (status === 404) {
766
- return `Product not found for this merchant.
767
- ${message}
768
- Recovery: call create_product first and pass the returned id as productId.`;
769
- }
770
- if (status === 422) {
771
- return `Cannot upload an image for this product.
772
- ${message}
773
- Recovery: archived products cannot receive images.`;
774
- }
775
- return `Backend get product image upload URL request failed.
776
- ${message}
777
- Recovery: verify BACKEND_BASE_URL and that POST /api/v1/mcp/merchants/:merchantId/products/:productId/image/upload-url is reachable.`;
778
- }
779
- async function runGetProductImageUploadUrlHandler(backendClient, input) {
780
- const { merchantId, productId, fileName, mimeType } = input;
781
- const result = await backendClient.post(backendProductImageUploadUrlPath(merchantId, productId), {
782
- fileName,
783
- mimeType
784
- });
785
- if (!result.ok) {
786
- return { ok: false, errorText: mapHttpError(result.status, result.message) };
787
- }
788
- let parsedJson;
789
- try {
790
- parsedJson = JSON.parse(result.bodyText);
791
- } catch {
792
- return {
793
- ok: false,
794
- errorText: "Backend returned non-JSON for get product image upload URL. Recovery: confirm the API matches this MCP server version."
795
- };
796
- }
797
- const out = import_mcp_contracts3.productImageUploadUrlOutputSchema.safeParse(parsedJson);
798
- if (!out.success) {
799
- return {
800
- ok: false,
801
- errorText: "Backend response did not match expected upload URL output schema. Recovery: inspect backend deployment and shared @pai-managed/mcp-contracts version."
802
- };
803
- }
804
- return { ok: true, data: out.data };
805
- }
806
-
807
- // src/tools/product/confirm-product-image.tool.ts
808
- var import_mcp_contracts4 = __toESM(require_dist(), 1);
809
- function runConfirmProductImageValidation(raw) {
810
- const parsed = import_mcp_contracts4.confirmProductImageInputSchema.safeParse(raw);
811
- if (!parsed.success) {
812
- return {
813
- ok: false,
814
- errorText: `Invalid arguments for confirm_product_image.
815
- ${formatZodIssuesForTool(parsed.error.issues)}`
816
- };
817
- }
818
- return { ok: true, data: parsed.data };
819
- }
820
- function mapHttpError2(status, message) {
821
- if (status === 404) {
822
- return `Product not found for this merchant.
823
- ${message}
824
- Recovery: pass the same productId used with get_product_image_upload_url.`;
825
- }
826
- if (status === 422) {
827
- return `Cannot upload an image for this product.
828
- ${message}
829
- Recovery: archived products cannot receive images.`;
830
- }
831
- if (status === 400) {
832
- return `Uploaded image rejected by the backend.
833
- ${message}
834
- Recovery: POST the bytes (multipart/form-data with all returned fields, then the file field last) to the upload URL first, use PNG/JPEG/WebP under 5 MB, and pass the exact key returned by get_product_image_upload_url.`;
835
- }
836
- return `Backend confirm product image request failed.
837
- ${message}
838
- Recovery: verify BACKEND_BASE_URL and that POST /api/v1/mcp/merchants/:merchantId/products/:productId/image/confirm is reachable.`;
839
- }
840
- async function runConfirmProductImageHandler(backendClient, input) {
841
- const { merchantId, productId, key } = input;
842
- const result = await backendClient.post(backendConfirmProductImagePath(merchantId, productId), {
843
- key
844
- });
845
- if (!result.ok) {
846
- return { ok: false, errorText: mapHttpError2(result.status, result.message) };
847
- }
848
- let parsedJson;
849
- try {
850
- parsedJson = JSON.parse(result.bodyText);
851
- } catch {
852
- return {
853
- ok: false,
854
- errorText: "Backend returned non-JSON for confirm product image. Recovery: confirm the API matches this MCP server version."
855
- };
856
- }
857
- const out = import_mcp_contracts4.confirmProductImageOutputSchema.safeParse(parsedJson);
858
- if (!out.success) {
859
- return {
860
- ok: false,
861
- errorText: "Backend response did not match expected confirm product image output schema. Recovery: inspect backend deployment and shared @pai-managed/mcp-contracts version."
862
- };
863
- }
864
- return { ok: true, data: out.data };
865
- }
866
-
867
- // src/tools/docs/knowledge/products-plans.ts
868
- var DOC_SECTIONS = [
869
- {
870
- title: "Navigation \u2014 Products & Plans",
871
- path: "/docs/products-plans#navigation",
872
- content: `To access Products & Plans, find **Products** in the left sidebar under the "Product" group (Package icon). Click **Products** to navigate to /products.`
873
- },
874
- {
875
- title: "Create a Product",
876
- path: "/docs/products-plans#create-a-product",
877
- content: `1. Call **create_product** with merchantId, name, and at least one plan.
878
- 2. Optionally attach an image via the presigned upload flow: call **get_product_image_upload_url** with the returned product id, POST the raw bytes (multipart/form-data with the returned fields + file last) to the returned URL, then call **confirm_product_image** with the returned key.
879
- 3. Use a returned planId to build a checkout URL: {checkout-base-url}/payment/{planId}`
880
- },
881
- {
882
- title: "Upload a Product Image (MCP)",
883
- path: "/docs/products-plans#upload-product-image-mcp",
884
- content: `After create_product returns an id:
885
- 1. Call **get_product_image_upload_url** with merchantId, productId, fileName, and mimeType. It returns { url, fields, key, expiresIn }.
886
- 2. HTTP POST the raw file bytes to \`url\` as \`multipart/form-data\`: add every entry from \`fields\` as a form field FIRST, then add the \`file\` field last (S3 requires the file field last). Example: \`curl -X POST -F "key=<fields.key>" -F "Content-Type=<mimeType>" -F "policy=<fields.policy>" -F "x-amz-signature=<fields['x-amz-signature']>" ... -F "file=@./logo.png" "<url>"\`.
887
- 3. Call **confirm_product_image** with merchantId, productId, and the returned key to validate and attach the image.
888
- 4. Supported formats: PNG, JPEG, WebP. Maximum size: 5 MB (enforced by S3 at upload time via a \`content-length-range\` policy condition \u2014 oversized bodies return a 403 from S3, before the backend ever sees them).
889
- 5. If confirm fails, retry get_product_image_upload_url + POST + confirm_product_image with the same productId \u2014 the product row is kept; the previous rejected upload was cleaned up by the backend.`
890
- },
891
- {
892
- title: "Plan Fields",
893
- path: "/docs/products-plans#plan-fields",
894
- content: `Each plan has the following fields:
895
- - **Name** \u2014 display name for the plan (max 30 characters)
896
- - **Amount** \u2014 price in USD as a decimal dollar amount (e.g. 9.99 = $9.99)
897
- - **Type** \u2014 one of: \`one-time\`, \`recurring\`, \`free-access\`
898
- - **Billing Period** \u2014 one of: \`day\`, \`week\`, \`month\`, \`year\`
899
- - **Period Length** \u2014 number of billing periods per cycle
900
- - **Free Trial** \u2014 number of free trial days (optional)`
901
- },
902
- {
903
- title: "Edit a Product",
904
- path: "/docs/products-plans#edit-a-product",
905
- content: `1. Go to **Products** in the left sidebar.
906
- 2. Click on the product row you want to edit.
907
- 3. Click **Edit** to modify name, description, status, or plans.`
908
- },
909
- {
910
- title: "Checkout URL",
911
- path: "/docs/products-plans#checkout-url",
912
- content: `Each plan has a unique checkout URL. The format is:
913
- {checkout-base-url}/payment/{planId}
914
-
915
- Embed it as: \`<a href="{checkout-base-url}/payment/{planId}">Pay Now!</a>\`
916
-
917
- Customers land on the payment page when they click the link. The \`planId\` is returned when you create a product via the \`create_product\` MCP tool.`
918
- }
919
- ];
920
-
921
- // src/tools/docs/knowledge/checkout-customization.ts
922
- var CHECKOUT_CUSTOMIZATION_DOC_SECTIONS = [
923
- {
924
- title: "Checkout Customization \u2014 Overview",
925
- path: "/docs/checkout-customization#overview",
926
- content: `Checkout customization controls the branding of a merchant's hosted checkout (the customer-facing payment page at /payment/{planId}). Configurable fields:
927
- - **themeMode** \u2014 \`light\` or \`dark\`
928
- - **backgroundColor**, **buttonColor**, **buttonTextColor**, **fontColor** \u2014 6-digit hex like \`#1A2B3C\`
929
- - **fontFamily** \u2014 \`Inter\` or \`Roboto\`
930
- - **inputStyle** \u2014 \`rounded\` or \`square\`
931
- - **logo** \u2014 set via the dashboard (not yet settable over MCP)
932
-
933
- Read with the \`get_checkout_customization\` MCP tool; change with \`update_checkout_customization\`.`
934
- },
935
- {
936
- title: "Checkout Customization \u2014 Updating branding via MCP",
937
- path: "/docs/checkout-customization#update",
938
- content: `The \`update_checkout_customization\` tool MERGES the fields you send: only the fields in the call are changed, and any field you omit keeps its current value. So you can send just \`{ "buttonColor": "#0A84FF" }\` to recolor the button without touching the rest of the branding.
939
-
940
- To remove or reset a field back to default, use the dashboard \u2014 clearing a field is not supported over MCP. Colors must be 6-digit hex (include the leading \`#\`). The tool returns the full customization after the merge, including the current \`logoUrl\` if a logo was set via the dashboard.`
941
- },
942
- {
943
- title: "Checkout Customization \u2014 Logo",
944
- path: "/docs/checkout-customization#logo",
945
- content: `The checkout logo is currently set through the PAI Managed dashboard (Checkout settings). It is returned as a read-only \`logoUrl\` by \`get_checkout_customization\`. Setting the logo directly over MCP is planned but not yet available.`
946
- }
947
- ];
948
-
949
- // src/tools/docs/search-payments-ai-docs.tool.ts
950
- var ALL_DOC_SECTIONS = [...DOC_SECTIONS, ...CHECKOUT_CUSTOMIZATION_DOC_SECTIONS];
951
- function runSearchPaymentsAiDocsHandler(query) {
952
- const terms = query.toLowerCase().split(/\s+/).filter((t) => t.length > 1);
953
- if (terms.length === 0) {
954
- return { results: ALL_DOC_SECTIONS };
955
- }
956
- const scored = ALL_DOC_SECTIONS.map((section) => {
957
- const haystack = `${section.title} ${section.content}`.toLowerCase();
958
- const hits = terms.filter((t) => haystack.includes(t)).length;
959
- return { section, hits };
960
- });
961
- const matches = scored.filter((s) => s.hits > 0).sort((a, b) => b.hits - a.hits);
962
- return {
963
- results: matches.length > 0 ? matches.map((s) => s.section) : ALL_DOC_SECTIONS
964
- };
965
- }
966
-
967
- // src/tools/health/payments-ai-health.tool.ts
968
- var import_mcp_contracts5 = __toESM(require_dist(), 1);
969
- async function buildPaymentsAiHealthOutput(backendClient) {
970
- const base = {
971
- serverName: "pai-managed-mcp-server",
972
- version: readMcpServerVersion(),
973
- stub: true,
974
- backend: { baseUrlConfigured: false }
975
- };
976
- if (!backendClient) {
977
- return import_mcp_contracts5.paymentsAiHealthOutputSchema.parse(base);
978
- }
979
- const result = await backendClient.get(BACKEND_HTTP_HEALTH_PATH);
980
- if (!result.ok) {
981
- return import_mcp_contracts5.paymentsAiHealthOutputSchema.parse({
982
- ...base,
983
- backend: {
984
- baseUrlConfigured: true,
985
- probe: {
986
- path: BACKEND_HTTP_HEALTH_PATH,
987
- ok: false,
988
- httpStatus: result.status,
989
- message: result.message
990
- }
991
- }
992
- });
993
- }
994
- let message = "Backend responded successfully.";
995
- try {
996
- const json = JSON.parse(result.bodyText);
997
- if (typeof json.message === "string" && json.message.length > 0) {
998
- message = json.message;
999
- }
1000
- } catch {
1001
- message = result.bodyText.slice(0, 500) || message;
1002
- }
1003
- return import_mcp_contracts5.paymentsAiHealthOutputSchema.parse({
1004
- ...base,
1005
- backend: {
1006
- baseUrlConfigured: true,
1007
- probe: {
1008
- path: BACKEND_HTTP_HEALTH_PATH,
1009
- ok: true,
1010
- httpStatus: result.status,
1011
- message
1012
- }
1013
- }
1014
- });
1015
- }
1016
-
1017
- // src/tools/merchant/create-merchant-account.tool.ts
1018
- var import_mcp_contracts6 = __toESM(require_dist(), 1);
1019
- var STUB_MERCHANT = {
1020
- merchantId: "01930000-0000-7000-8000-000000000001"
1021
- };
1022
- function buildCreateMerchantAccountStub(_input) {
1023
- return import_mcp_contracts6.createMerchantAccountOutputSchema.parse(STUB_MERCHANT);
1024
- }
1025
- function runCreateMerchantAccountHandler(raw) {
1026
- const parsed = import_mcp_contracts6.createMerchantAccountInputSchema.safeParse(raw);
1027
- if (!parsed.success) {
1028
- return {
1029
- ok: false,
1030
- errorText: `Invalid arguments for create_merchant_account.
1031
- ${formatZodIssuesForTool(parsed.error.issues)}`
1032
- };
1033
- }
1034
- return { ok: true, data: buildCreateMerchantAccountStub(parsed.data) };
1035
- }
1036
- async function runCreateMerchantAccountHandlerWithBackend(backendClient, input, userId) {
1037
- const result = await backendClient.post(BACKEND_CREATE_MERCHANT_ACCOUNT_PATH, {
1038
- name: input.name,
1039
- email: input.email,
1040
- userId
1041
- });
1042
- if (!result.ok) {
1043
- return {
1044
- ok: false,
1045
- errorText: `Backend create merchant account request failed.
1046
- ${result.message}
1047
- Recovery: verify BACKEND_BASE_URL and that POST ${BACKEND_CREATE_MERCHANT_ACCOUNT_PATH} is reachable from the MCP container or host.`
1048
- };
1049
- }
1050
- let parsedJson;
1051
- try {
1052
- parsedJson = JSON.parse(result.bodyText);
1053
- } catch {
1054
- return {
1055
- ok: false,
1056
- errorText: "Backend returned non-JSON for create_merchant_account. Recovery: confirm the API matches this MCP server version."
1057
- };
1058
- }
1059
- const out = import_mcp_contracts6.createMerchantAccountOutputSchema.safeParse(parsedJson);
1060
- if (!out.success) {
1061
- return {
1062
- ok: false,
1063
- errorText: "Backend response did not match the expected merchant account output schema. Recovery: inspect backend deployment and shared @pai-managed/mcp-contracts version."
1064
- };
1065
- }
1066
- return { ok: true, data: out.data };
1067
- }
1068
-
1069
- // src/tools/checkout/get-checkout-customization.tool.ts
1070
- var import_mcp_contracts7 = __toESM(require_dist(), 1);
1071
- function runGetCheckoutCustomizationValidation(raw) {
1072
- const parsed = import_mcp_contracts7.getCheckoutCustomizationInputSchema.safeParse(raw);
1073
- if (!parsed.success) {
1074
- return {
1075
- ok: false,
1076
- errorText: `Invalid arguments for get_checkout_customization.
1077
- ${formatZodIssuesForTool(parsed.error.issues)}`
1078
- };
1079
- }
1080
- return { ok: true, data: parsed.data };
1081
- }
1082
- async function runGetCheckoutCustomizationHandler(backendClient, input) {
1083
- const result = await backendClient.get(backendGetCheckoutCustomizationPath(input.merchantId));
1084
- if (!result.ok) {
1085
- return {
1086
- ok: false,
1087
- errorText: `Backend get checkout customization request failed.
1088
- ${result.message}
1089
- Recovery: verify BACKEND_BASE_URL and that GET /api/v1/mcp/merchants/:merchantId/checkout/customization is reachable.`
1090
- };
1091
- }
1092
- let parsedJson;
1093
- try {
1094
- parsedJson = JSON.parse(result.bodyText);
1095
- } catch {
1096
- return {
1097
- ok: false,
1098
- errorText: "Backend returned non-JSON for get checkout customization. Recovery: confirm the API matches this MCP server version."
1099
- };
1100
- }
1101
- const customization = parsedJson?.customization;
1102
- const out = import_mcp_contracts7.checkoutCustomizationOutputSchema.safeParse(customization);
1103
- if (!out.success) {
1104
- return {
1105
- ok: false,
1106
- errorText: "Backend response did not match expected checkout customization output schema. Recovery: inspect backend deployment and shared @pai-managed/mcp-contracts version."
1107
- };
1108
- }
1109
- return { ok: true, data: out.data };
1110
- }
1111
-
1112
- // src/tools/checkout/update-checkout-customization.tool.ts
1113
- var import_mcp_contracts8 = __toESM(require_dist(), 1);
1114
- function runUpdateCheckoutCustomizationValidation(raw) {
1115
- const parsed = import_mcp_contracts8.updateCheckoutCustomizationInputSchema.safeParse(raw);
1116
- if (!parsed.success) {
1117
- return {
1118
- ok: false,
1119
- errorText: `Invalid arguments for update_checkout_customization.
1120
- ${formatZodIssuesForTool(parsed.error.issues)}`
1121
- };
1122
- }
1123
- return { ok: true, data: parsed.data };
1124
- }
1125
- async function runUpdateCheckoutCustomizationHandler(backendClient, input) {
1126
- const { merchantId, customization } = input;
1127
- const result = await backendClient.patch(backendUpdateCheckoutCustomizationPath(merchantId), {
1128
- customization
1129
- });
1130
- if (!result.ok) {
1131
- return {
1132
- ok: false,
1133
- errorText: `Backend update checkout customization request failed.
1134
- ${result.message}
1135
- Recovery: verify BACKEND_BASE_URL and that PATCH /api/v1/mcp/merchants/:merchantId/checkout/customization is reachable.`
1136
- };
1137
- }
1138
- let parsedJson;
1139
- try {
1140
- parsedJson = JSON.parse(result.bodyText);
1141
- } catch {
1142
- return {
1143
- ok: false,
1144
- errorText: "Backend returned non-JSON for update checkout customization. Recovery: confirm the API matches this MCP server version."
1145
- };
1146
- }
1147
- const updated = parsedJson?.customization;
1148
- const out = import_mcp_contracts8.checkoutCustomizationOutputSchema.safeParse(updated);
1149
- if (!out.success) {
1150
- return {
1151
- ok: false,
1152
- errorText: "Backend response did not match expected checkout customization output schema. Recovery: inspect backend deployment and shared @pai-managed/mcp-contracts version."
1153
- };
1154
- }
1155
- return { ok: true, data: out.data };
1156
- }
1157
-
1158
- // src/tools/register-tools.ts
1159
- function toolError(text) {
1160
- return {
1161
- isError: true,
1162
- content: [{ type: "text", text }]
1163
- };
1164
- }
1165
- function isMerchantAllowed(merchantId, payload) {
1166
- return !payload || payload.merchantIds.includes(merchantId);
1167
- }
1168
- function isScopeAllowed(required, payload) {
1169
- if (!payload) return true;
1170
- if (payload.scopes === null) return true;
1171
- return payload.scopes.includes(required);
1172
- }
1173
- function registerTools(server, options2) {
1174
- const backendClient = options2?.backendClient ?? createBackendClientFromEnv();
1175
- const mcpTokenPayload = options2?.mcpTokenPayload;
1176
- server.registerTool(
1177
- import_mcp_contracts9.MCP_TOOL_NAMES.PAYMENTS_AI_HEALTH,
1178
- {
1179
- description: "Check whether the PAI Managed MCP server is healthy. Returns server version and connectivity status.",
1180
- outputSchema: import_mcp_contracts9.paymentsAiHealthOutputSchema
1181
- },
1182
- async () => {
1183
- if (!isScopeAllowed("health:read", mcpTokenPayload)) {
1184
- return toolError("Insufficient scope.");
1185
- }
1186
- const structuredContent = await buildPaymentsAiHealthOutput(backendClient);
1187
- return {
1188
- content: [{ type: "text", text: JSON.stringify(structuredContent) }],
1189
- structuredContent
1190
- };
1191
- }
1192
- );
1193
- server.registerTool(
1194
- import_mcp_contracts9.MCP_TOOL_NAMES.CREATE_MERCHANT_ACCOUNT,
1195
- {
1196
- description: "Create a merchant account on PAI Managed. Provide a business name and email; returns a merchant ID you can use with other tools such as create_product.",
1197
- inputSchema: import_mcp_contracts9.createMerchantAccountInputSchema,
1198
- outputSchema: import_mcp_contracts9.createMerchantAccountOutputSchema
1199
- },
1200
- async (args) => {
1201
- if (!isScopeAllowed("merchant:create", mcpTokenPayload)) {
1202
- return toolError("Insufficient scope.");
1203
- }
1204
- const result = backendClient ? await runCreateMerchantAccountHandlerWithBackend(
1205
- backendClient,
1206
- args,
1207
- mcpTokenPayload?.userId
1208
- ) : runCreateMerchantAccountHandler(args);
1209
- if (!result.ok) {
1210
- return toolError(result.errorText);
1211
- }
1212
- return {
1213
- content: [{ type: "text", text: JSON.stringify(result.data) }],
1214
- structuredContent: result.data
1215
- };
1216
- }
1217
- );
1218
- server.registerTool(
1219
- import_mcp_contracts9.MCP_TOOL_NAMES.GET_MERCHANT_ACTIVATION_STATUS,
1220
- {
1221
- description: 'Get the production activation status of a merchant account on PAI Managed. Returns "pending" (account exists, activation in progress) or "not_provisioned" (not yet set up).',
1222
- inputSchema: import_mcp_contracts9.activationStatusInputSchema,
1223
- outputSchema: import_mcp_contracts9.activationStatusOutputSchema
1224
- },
1225
- async (args) => {
1226
- if (!isScopeAllowed("merchant:read", mcpTokenPayload)) {
1227
- return toolError("Insufficient scope.");
1228
- }
1229
- if (!isMerchantAllowed(args.merchantId, mcpTokenPayload)) {
1230
- return toolError("Merchant not authorized for this MCP key.");
1231
- }
1232
- const result = backendClient ? await runActivationStatusHandlerWithBackend(backendClient, args) : runActivationStatusHandler(args);
1233
- if (!result.ok) {
1234
- return toolError(result.errorText);
1235
- }
1236
- return {
1237
- content: [{ type: "text", text: JSON.stringify(result.data) }],
1238
- structuredContent: result.data
1239
- };
1240
- }
1241
- );
1242
- server.registerTool(
1243
- import_mcp_contracts9.MCP_TOOL_NAMES.SEARCH_PAYMENTS_AI_DOCS,
1244
- {
1245
- description: "Search the PAI Managed documentation knowledge base to find guides, API references, UI walkthroughs, and feature explanations. Returns matching sections with titles and direct documentation links. Use this tool to understand how PAI Managed works, find step-by-step instructions for dashboard tasks, or locate specific features such as creating products, configuring plans, or generating checkout links.",
1246
- inputSchema: import_mcp_contracts9.searchPaymentsAiDocsInputSchema,
1247
- outputSchema: import_mcp_contracts9.searchPaymentsAiDocsOutputSchema
1248
- },
1249
- async (args) => {
1250
- if (!isScopeAllowed("docs:read", mcpTokenPayload)) {
1251
- return toolError("Insufficient scope.");
1252
- }
1253
- const structuredContent = runSearchPaymentsAiDocsHandler(args.query);
1254
- return {
1255
- content: [{ type: "text", text: JSON.stringify(structuredContent) }],
1256
- structuredContent
1257
- };
1258
- }
1259
- );
1260
- server.registerTool(
1261
- import_mcp_contracts9.MCP_TOOL_NAMES.CREATE_PRODUCT,
1262
- {
1263
- description: "Create a product with one or more pricing plans for a merchant on the PAI Managed platform. Products represent digital offerings (software, subscriptions, services) that customers can purchase via a checkout link. Each plan defines the price (in USD cents), billing type (one-time, recurring, or free-access), and billing period. Returns the product ID and the plan IDs; use a plan ID to build a checkout URL for your customers. Product images are not supported on create \u2014 after success, call get_product_image_upload_url with the returned id as productId, POST the file bytes (multipart/form-data) to the returned URL, then call confirm_product_image with the returned key.",
1264
- inputSchema: import_mcp_contracts9.createMcpProductInputSchema,
1265
- outputSchema: import_mcp_contracts9.createMcpProductOutputSchema
1266
- },
1267
- async (args) => {
1268
- if (!isScopeAllowed("product:create", mcpTokenPayload)) {
1269
- return toolError("Insufficient scope.");
1270
- }
1271
- const validation = runCreateProductHandlerValidation(args);
1272
- if (!validation.ok) {
1273
- return toolError(validation.errorText);
1274
- }
1275
- if (!isMerchantAllowed(validation.data.merchantId, mcpTokenPayload)) {
1276
- return toolError("Merchant not authorized for this MCP key.");
1277
- }
1278
- if (!backendClient) {
1279
- return toolError(
1280
- "The PAI Managed backend is not reachable. Contact your platform administrator to configure backend connectivity."
1281
- );
1282
- }
1283
- const result = await runCreateProductHandler(backendClient, validation.data);
1284
- if (!result.ok) {
1285
- return toolError(result.errorText);
1286
- }
1287
- return {
1288
- content: [{ type: "text", text: JSON.stringify(result.data) }],
1289
- structuredContent: result.data
1290
- };
1291
- }
1292
- );
1293
- server.registerTool(
1294
- import_mcp_contracts9.MCP_TOOL_NAMES.GET_PRODUCT_IMAGE_UPLOAD_URL,
1295
- {
1296
- description: 'Get a presigned POST policy to upload a product image directly to storage \u2014 the image bytes never pass through the tool call, and S3 enforces the 5 MB cap at upload time via `content-length-range` (oversized bodies get a 403 from S3, not the backend). Use this on any surface that can issue an HTTP multipart/form-data POST (CLI, agent, dashboard). The product must already exist (call create_product first). Provide merchantId, productId, fileName, and mimeType (image/png, image/jpeg, image/jpg, or image/webp). Returns { url, fields, key, expiresIn }: issue an HTTP POST to `url` with Content-Type: multipart/form-data. Add every entry from `fields` as a form field FIRST, then add the `file` field last (S3 requires the file field last), e.g. `curl -X POST <all -F fields...> -F "file=@./logo.png" "<url>"`. Then call confirm_product_image with the returned key to validate and attach the image.',
1297
- inputSchema: import_mcp_contracts9.productImageUploadUrlInputSchema,
1298
- outputSchema: import_mcp_contracts9.productImageUploadUrlOutputSchema
1299
- },
1300
- async (args) => {
1301
- if (!isScopeAllowed("product:create", mcpTokenPayload)) {
1302
- return toolError("Insufficient scope.");
1303
- }
1304
- const validation = runGetProductImageUploadUrlValidation(args);
1305
- if (!validation.ok) {
1306
- return toolError(validation.errorText);
1307
- }
1308
- if (!isMerchantAllowed(validation.data.merchantId, mcpTokenPayload)) {
1309
- return toolError("Merchant not authorized for this MCP key.");
1310
- }
1311
- if (!backendClient) {
1312
- return toolError(
1313
- "The PAI Managed backend is not reachable. Contact your platform administrator to configure backend connectivity."
1314
- );
1315
- }
1316
- const result = await runGetProductImageUploadUrlHandler(backendClient, validation.data);
1317
- if (!result.ok) {
1318
- return toolError(result.errorText);
1319
- }
1320
- return {
1321
- content: [{ type: "text", text: JSON.stringify(result.data) }],
1322
- structuredContent: result.data
1323
- };
1324
- }
1325
- );
1326
- server.registerTool(
1327
- import_mcp_contracts9.MCP_TOOL_NAMES.CONFIRM_PRODUCT_IMAGE,
1328
- {
1329
- description: "Confirm a product image uploaded via a presigned POST policy from get_product_image_upload_url. Call this after the multipart/form-data POST succeeds. Provide merchantId, productId, and the key returned by get_product_image_upload_url. The backend validates the stored object (format, size, magic bytes) and attaches it to the product. Returns { imageUrl } for verification. Replaces any existing product image.",
1330
- inputSchema: import_mcp_contracts9.confirmProductImageInputSchema,
1331
- outputSchema: import_mcp_contracts9.confirmProductImageOutputSchema
1332
- },
1333
- async (args) => {
1334
- if (!isScopeAllowed("product:create", mcpTokenPayload)) {
1335
- return toolError("Insufficient scope.");
1336
- }
1337
- const validation = runConfirmProductImageValidation(args);
1338
- if (!validation.ok) {
1339
- return toolError(validation.errorText);
1340
- }
1341
- if (!isMerchantAllowed(validation.data.merchantId, mcpTokenPayload)) {
1342
- return toolError("Merchant not authorized for this MCP key.");
1343
- }
1344
- if (!backendClient) {
1345
- return toolError(
1346
- "The PAI Managed backend is not reachable. Contact your platform administrator to configure backend connectivity."
1347
- );
1348
- }
1349
- const result = await runConfirmProductImageHandler(backendClient, validation.data);
1350
- if (!result.ok) {
1351
- return toolError(result.errorText);
1352
- }
1353
- return {
1354
- content: [{ type: "text", text: JSON.stringify(result.data) }],
1355
- structuredContent: result.data
1356
- };
1357
- }
1358
- );
1359
- server.registerTool(
1360
- import_mcp_contracts9.MCP_TOOL_NAMES.GET_CHECKOUT_CUSTOMIZATION,
1361
- {
1362
- description: "Get a merchant's checkout customization on PAI Managed \u2014 theme mode, colors (background, button, button text, font), font family, input style, and the current logo URL (read-only). Use this to inspect current branding before changing it.",
1363
- inputSchema: import_mcp_contracts9.getCheckoutCustomizationInputSchema,
1364
- outputSchema: import_mcp_contracts9.checkoutCustomizationOutputSchema
1365
- },
1366
- async (args) => {
1367
- if (!isScopeAllowed("checkout:read", mcpTokenPayload)) {
1368
- return toolError("Insufficient scope.");
1369
- }
1370
- const validation = runGetCheckoutCustomizationValidation(args);
1371
- if (!validation.ok) {
1372
- return toolError(validation.errorText);
1373
- }
1374
- if (!isMerchantAllowed(validation.data.merchantId, mcpTokenPayload)) {
1375
- return toolError("Merchant not authorized for this MCP key.");
1376
- }
1377
- if (!backendClient) {
1378
- return toolError(
1379
- "The PAI Managed backend is not reachable. Contact your platform administrator to configure backend connectivity."
1380
- );
1381
- }
1382
- const result = await runGetCheckoutCustomizationHandler(backendClient, validation.data);
1383
- if (!result.ok) {
1384
- return toolError(result.errorText);
1385
- }
1386
- return {
1387
- content: [{ type: "text", text: JSON.stringify(result.data) }],
1388
- structuredContent: result.data
1389
- };
1390
- }
1391
- );
1392
- server.registerTool(
1393
- import_mcp_contracts9.MCP_TOOL_NAMES.UPDATE_CHECKOUT_CUSTOMIZATION,
1394
- {
1395
- description: "Update a merchant's checkout customization on PAI Managed. Fields are MERGED: send only the fields you want to change \u2014 any field you omit is left unchanged. To remove/reset a field, use the dashboard (clearing is not supported over MCP). Colors are 6-digit hex like '#1A2B3C'; fontFamily is 'Inter' or 'Roboto'; themeMode is 'light' or 'dark'; inputStyle is 'rounded' or 'square'. The logo is set via the dashboard. Returns the full customization after the merge.",
1396
- inputSchema: import_mcp_contracts9.updateCheckoutCustomizationInputSchema,
1397
- outputSchema: import_mcp_contracts9.checkoutCustomizationOutputSchema
1398
- },
1399
- async (args) => {
1400
- if (!isScopeAllowed("checkout:write", mcpTokenPayload)) {
1401
- return toolError("Insufficient scope.");
1402
- }
1403
- const validation = runUpdateCheckoutCustomizationValidation(args);
1404
- if (!validation.ok) {
1405
- return toolError(validation.errorText);
1406
- }
1407
- if (!isMerchantAllowed(validation.data.merchantId, mcpTokenPayload)) {
1408
- return toolError("Merchant not authorized for this MCP key.");
1409
- }
1410
- if (!backendClient) {
1411
- return toolError(
1412
- "The PAI Managed backend is not reachable. Contact your platform administrator to configure backend connectivity."
1413
- );
1414
- }
1415
- const result = await runUpdateCheckoutCustomizationHandler(backendClient, validation.data);
1416
- if (!result.ok) {
1417
- return toolError(result.errorText);
1418
- }
1419
- return {
1420
- content: [{ type: "text", text: JSON.stringify(result.data) }],
1421
- structuredContent: result.data
1422
- };
1423
- }
1424
- );
1425
- }
1426
-
1427
- // src/main.ts
1428
- async function main() {
1429
- const version = readMcpServerVersion();
1430
- const server = createInstrumentedMcpServer({ version });
1431
- const backendClient = createBackendClientFromEnv();
1432
- registerTools(server, { backendClient });
1433
- const transport = new StdioServerTransport();
1434
- await server.connect(transport);
1435
- console.error(`pai-managed MCP server ready (v${version}).`);
1436
- console.error(
1437
- "Transport: stdio (JSON-RPC on process stdin/stdout). No host or TCP port \u2014 the MCP client must spawn this process."
1438
- );
1439
- }
1440
- main().catch(async (error) => {
1441
- Sentry.captureException(error);
1442
- console.error("Fatal error in MCP server:", error);
1443
- await Sentry.flush(2e3);
1444
- process.exit(1);
1445
- });