@carrierllc/mcp 0.13.34 → 0.13.36
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
CHANGED
|
@@ -80,7 +80,7 @@ import {
|
|
|
80
80
|
verifyStorefront,
|
|
81
81
|
withOcsListSummary,
|
|
82
82
|
withTemplateResellerId
|
|
83
|
-
} from "./chunk-
|
|
83
|
+
} from "./chunk-RQZW6BQM.js";
|
|
84
84
|
import "./chunk-SHKKVIIA.js";
|
|
85
85
|
|
|
86
86
|
// src/index.ts
|
|
@@ -1304,12 +1304,19 @@ function wrapHandler(toolName, ocsMethod, requiredScope, ctx, handler, options)
|
|
|
1304
1304
|
content: [{ type: "text", text: `Error: ${message}` }]
|
|
1305
1305
|
};
|
|
1306
1306
|
}
|
|
1307
|
+
const handledOcsCode = result2.ocsStatusCode;
|
|
1308
|
+
if (handledOcsCode !== void 0) {
|
|
1309
|
+
const { ocsStatusCode: _auditOnly, ...clientResult } = result2;
|
|
1310
|
+
void _auditOnly;
|
|
1311
|
+
result2 = clientResult;
|
|
1312
|
+
}
|
|
1307
1313
|
ctx.audit({
|
|
1308
1314
|
tool_name: toolName,
|
|
1309
1315
|
ocs_method: ocsMethod,
|
|
1310
1316
|
status: result2.isError ? "error" : "ok",
|
|
1311
1317
|
dry_run: isDryRun,
|
|
1312
|
-
duration_ms: Date.now() - start
|
|
1318
|
+
duration_ms: Date.now() - start,
|
|
1319
|
+
...handledOcsCode !== void 0 ? { ocs_status_code: handledOcsCode } : {}
|
|
1313
1320
|
});
|
|
1314
1321
|
if (!result2.isError && !isDryRun) {
|
|
1315
1322
|
recordUsage(ctx.env, ctx.props.sub, ctx.props.tier);
|
|
@@ -5041,7 +5048,25 @@ function registerAllBacklogTools(server2, ctx) {
|
|
|
5041
5048
|
ctx,
|
|
5042
5049
|
async ({ voip_plan_id }, token2) => {
|
|
5043
5050
|
const client2 = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
|
|
5044
|
-
|
|
5051
|
+
let result2;
|
|
5052
|
+
try {
|
|
5053
|
+
result2 = await client2.call("listVoipTariffRule", voip_plan_id);
|
|
5054
|
+
} catch (err9) {
|
|
5055
|
+
if (err9 instanceof OcsApiError && err9.code === 11) {
|
|
5056
|
+
return {
|
|
5057
|
+
isError: true,
|
|
5058
|
+
// Returned, not thrown, so pass the code to wrapHandler's audit row.
|
|
5059
|
+
ocsStatusCode: 11,
|
|
5060
|
+
content: [
|
|
5061
|
+
{
|
|
5062
|
+
type: "text",
|
|
5063
|
+
text: `No VoIP tariff rules readable for VoIP plan ${voip_plan_id} under this reseller (OCS error 11: Reseller not found). OCS returns this when the plan is not owned by your reseller, for example the get_reseller_info chargingInfo.voipPlan id, which is the plan your parent reseller bills you on. Use a plan id from list_subscriber_voip_tariff; if that returns no rows, this reseller has no VoIP catalog configured.`
|
|
5064
|
+
}
|
|
5065
|
+
]
|
|
5066
|
+
};
|
|
5067
|
+
}
|
|
5068
|
+
throw err9;
|
|
5069
|
+
}
|
|
5045
5070
|
return {
|
|
5046
5071
|
content: [{ type: "text", text: JSON.stringify(result2, null, 2) }]
|
|
5047
5072
|
};
|
|
@@ -6900,6 +6925,9 @@ async function stripeGet(stripeKey, path, connectedAccountId) {
|
|
|
6900
6925
|
const data = await res.json();
|
|
6901
6926
|
return { ok: res.ok, status: res.status, data };
|
|
6902
6927
|
}
|
|
6928
|
+
function declineNotSupported(reviewId) {
|
|
6929
|
+
return `Not declined: Stripe has no endpoint to decline a Radar review, so nothing was sent for ${reviewId}. To turn the payment away, refund the charge (POST /v1/refunds) on the account the review belongs to (a platform review needs a platform-scoped refund; stripe_connect_refund acts as the operator's connected account) or, if it was authorized but not captured, cancel its PaymentIntent (POST /v1/payment_intents/:id/cancel). Either one closes the review. See https://docs.stripe.com/radar/reviews.`;
|
|
6930
|
+
}
|
|
6903
6931
|
async function stripePost(stripeKey, path, params, connectedAccountId, idempotencyKey) {
|
|
6904
6932
|
const headers = buildStripeHeaders(stripeKey, {
|
|
6905
6933
|
connectedAccountId,
|
|
@@ -7149,7 +7177,7 @@ function registerStripeConnectTools(server2, ctx) {
|
|
|
7149
7177
|
"stripe_connect_refund",
|
|
7150
7178
|
{
|
|
7151
7179
|
title: "Refund a Charge (moves real money)",
|
|
7152
|
-
description: "Refund money to a customer on one charge in the operator's connected Stripe account. This returns real funds and Stripe cannot reverse a refund once issued. Two-step by design: call without `confirm_token` to get a token and a summary of what would be refunded, then call again with that token to execute. The token expires in 5 minutes. Params: `charge_id` (Stripe charge id, `ch_...`), `amount_cents` (optional integer in the charge's smallest currency unit \u2014 omit for a full refund), `reason` ('duplicate' | 'fraudulent' | 'requested_by_customer', optional), `confirm_token`. Returns: the refund id and status. Requires `write` scope. Do NOT use this
|
|
7180
|
+
description: "Refund money to a customer on one charge in the operator's connected Stripe account. This returns real funds and Stripe cannot reverse a refund once issued. Two-step by design: call without `confirm_token` to get a token and a summary of what would be refunded, then call again with that token to execute. The token expires in 5 minutes. Params: `charge_id` (Stripe charge id, `ch_...`), `amount_cents` (optional integer in the charge's smallest currency unit \u2014 omit for a full refund), `reason` ('duplicate' | 'fraudulent' | 'requested_by_customer', optional), `confirm_token`. Returns: the refund id and status. Requires `write` scope. Do NOT use this on a payment that was authorized but not captured \u2014 cancel its PaymentIntent instead (Stripe POST /v1/payment_intents/:id/cancel). Do NOT use this to contest a chargeback \u2014 read the case with `stripe_connect_dispute_list` first, since refunding a disputed charge can cost the operator twice.",
|
|
7153
7181
|
inputSchema: {
|
|
7154
7182
|
charge_id: z8.string().min(1).describe("Stripe charge ID (ch_...)."),
|
|
7155
7183
|
amount_cents: z8.number().int().min(1).optional().describe("Partial refund amount in cents. Omit for full refund."),
|
|
@@ -7251,9 +7279,9 @@ Call again with confirm_token="${token2}" to execute. Token expires in 5 minutes
|
|
|
7251
7279
|
"radar_review_list",
|
|
7252
7280
|
{
|
|
7253
7281
|
title: "List Radar Fraud Reviews",
|
|
7254
|
-
description: "List the Stripe Radar fraud reviews waiting on a manual approve/decline decision, newest first. Reads only \u2014 deciding a review is a separate call. Params: `open_only` (boolean, default true
|
|
7282
|
+
description: "List the Stripe Radar fraud reviews waiting on a manual approve/decline decision, newest first. Reads only \u2014 deciding a review is a separate call. Params: `open_only` (boolean, default true; Stripe lists open reviews only, so false returns the same set), `limit` (1-50, default 10). Returns: { reviews: [{ id (`prv_...`), charge, reason, opened_reason, closed_reason, created, closed }], has_more }. Call this first to get the `review_id` that `radar_review_approve` and `radar_review_decline` require. Do NOT use this for chargebacks the customer has already raised with their bank \u2014 use `stripe_connect_dispute_list`.",
|
|
7255
7283
|
inputSchema: {
|
|
7256
|
-
open_only: z8.boolean().default(true).describe("
|
|
7284
|
+
open_only: z8.boolean().default(true).describe("Stripe lists only open (undecided) reviews; kept for compatibility."),
|
|
7257
7285
|
limit: z8.number().int().min(1).max(50).default(10)
|
|
7258
7286
|
},
|
|
7259
7287
|
annotations: annotationsFor("radar_review_list", "read")
|
|
@@ -7271,9 +7299,9 @@ Call again with confirm_token="${token2}" to execute. Token expires in 5 minutes
|
|
|
7271
7299
|
const stripeKey = env.STRIPE_ORG_SECRET_KEY ?? env.STRIPE_SECRET_KEY;
|
|
7272
7300
|
if (!stripeKey) return err2("Stripe not configured");
|
|
7273
7301
|
const params = new URLSearchParams({ limit: String(limit) });
|
|
7274
|
-
|
|
7275
|
-
const result2 = await stripeGet(stripeKey, `/v1/radar/reviews?${params.toString()}`);
|
|
7302
|
+
const result2 = await stripeGet(stripeKey, `/v1/reviews?${params.toString()}`);
|
|
7276
7303
|
if (!result2.ok) return err2(`Stripe error: ${JSON.stringify(result2.data)}`);
|
|
7304
|
+
const reviews = open_only ? result2.data.data.filter((r) => r.open !== false) : result2.data.data;
|
|
7277
7305
|
writeAudit(env, {
|
|
7278
7306
|
tool_name: "radar_review_list",
|
|
7279
7307
|
ocs_method: "stripe.radar.reviews.list",
|
|
@@ -7283,7 +7311,7 @@ Call again with confirm_token="${token2}" to execute. Token expires in 5 minutes
|
|
|
7283
7311
|
sub: props2.sub,
|
|
7284
7312
|
reseller_id: props2.reseller_id
|
|
7285
7313
|
});
|
|
7286
|
-
return ok(JSON.stringify({ reviews
|
|
7314
|
+
return ok(JSON.stringify({ reviews, has_more: result2.data.has_more }));
|
|
7287
7315
|
} catch (e) {
|
|
7288
7316
|
Sentry3.captureException(e);
|
|
7289
7317
|
return err2(`Error: ${e instanceof Error ? e.message : "unknown"}`);
|
|
@@ -7294,7 +7322,7 @@ Call again with confirm_token="${token2}" to execute. Token expires in 5 minutes
|
|
|
7294
7322
|
"radar_review_approve",
|
|
7295
7323
|
{
|
|
7296
7324
|
title: "Approve Radar Review (captures charge)",
|
|
7297
|
-
description: "Clear a Stripe Radar fraud review so the held charge is captured and the money is taken. Approving overrides Radar's fraud signal, so a genuinely fraudulent charge approved here usually returns later as a chargeback plus a fee. Two-step by design: call without `confirm_token` to get a token, then call again with it to execute. Params: `review_id` (`prv_...`, from `radar_review_list`), `confirm_token`. Requires `admin` scope. Do NOT call this to
|
|
7325
|
+
description: "Clear a Stripe Radar fraud review so the held charge is captured and the money is taken. Approving overrides Radar's fraud signal, so a genuinely fraudulent charge approved here usually returns later as a chargeback plus a fee. Two-step by design: call without `confirm_token` to get a token, then call again with it to execute. Params: `review_id` (`prv_...`, from `radar_review_list`), `confirm_token`. Requires `admin` scope. Do NOT call this to turn a suspicious charge away \u2014 Stripe has no review decline; refund the charge (`stripe_connect_refund`) or cancel an uncaptured PaymentIntent. Do NOT call this to return money on a charge that already went through \u2014 that is `stripe_connect_refund`.",
|
|
7298
7326
|
inputSchema: {
|
|
7299
7327
|
review_id: z8.string().min(1).describe("Stripe Radar review ID (prv_...)."),
|
|
7300
7328
|
confirm_token: z8.string().optional()
|
|
@@ -7326,7 +7354,8 @@ Call again with confirm_token="${token2}" to execute. Expires in 5 minutes.`
|
|
|
7326
7354
|
if (!stripeKey) return err2("Stripe not configured");
|
|
7327
7355
|
const result2 = await stripePost(
|
|
7328
7356
|
stripeKey,
|
|
7329
|
-
|
|
7357
|
+
// POST /v1/reviews/:id/approve (docs.stripe.com/api/radar/reviews/approve).
|
|
7358
|
+
`/v1/reviews/${encodeURIComponent(review_id)}/approve`,
|
|
7330
7359
|
{}
|
|
7331
7360
|
);
|
|
7332
7361
|
if (!result2.ok) return err2(`Stripe error: ${JSON.stringify(result2.data)}`);
|
|
@@ -7349,15 +7378,15 @@ Call again with confirm_token="${token2}" to execute. Expires in 5 minutes.`
|
|
|
7349
7378
|
server2.registerTool(
|
|
7350
7379
|
"radar_review_decline",
|
|
7351
7380
|
{
|
|
7352
|
-
title: "Decline Radar Review (
|
|
7353
|
-
description: "
|
|
7381
|
+
title: "Decline Radar Review (not supported by Stripe)",
|
|
7382
|
+
description: "Always refuses and calls nothing: Stripe has no endpoint to decline a Radar review (its Reviews API only lists, retrieves and approves). Payments in review have usually already been processed. To turn one away, refund the charge on Carrier's platform account in Stripe itself (Dashboard, or platform-scoped POST /v1/refunds with no Stripe-Account header): `stripe_connect_refund` always acts as the operator's connected account, so it will NOT find a platform charge from this review list. or, for a payment authorized but not captured, cancel its PaymentIntent (Stripe POST /v1/payment_intents/:id/cancel); either closes the review. Params: `review_id` (`prv_...`), `confirm_token` (ignored). Requires `admin` scope. Do NOT call this expecting a charge to be blocked; nothing happens.",
|
|
7354
7383
|
inputSchema: {
|
|
7355
7384
|
review_id: z8.string().min(1),
|
|
7356
7385
|
confirm_token: z8.string().optional()
|
|
7357
7386
|
},
|
|
7358
7387
|
annotations: annotationsFor("radar_review_decline", "admin")
|
|
7359
7388
|
},
|
|
7360
|
-
async ({ review_id
|
|
7389
|
+
async ({ review_id }) => {
|
|
7361
7390
|
const denied = denyUnlessScoped(props2, "radar_review_decline", STRIPE_CONNECT_TOOL_SCOPES);
|
|
7362
7391
|
if (denied) return denied;
|
|
7363
7392
|
if (!isPlatformOperator(env, props2.org_id)) {
|
|
@@ -7365,41 +7394,7 @@ Call again with confirm_token="${token2}" to execute. Expires in 5 minutes.`
|
|
|
7365
7394
|
"This tool acts on Carrier's platform Stripe account and is restricted to Carrier's own organization."
|
|
7366
7395
|
);
|
|
7367
7396
|
}
|
|
7368
|
-
|
|
7369
|
-
const start = Date.now();
|
|
7370
|
-
if (!confirm_token) {
|
|
7371
|
-
const token2 = await issueConfirmToken(env, props2.sub, toolName);
|
|
7372
|
-
return ok(
|
|
7373
|
-
`HARD_BLOCK: Declining review ${review_id} will close/block the charge.
|
|
7374
|
-
confirm_token: ${token2}
|
|
7375
|
-
Expires in 5 minutes.`
|
|
7376
|
-
);
|
|
7377
|
-
}
|
|
7378
|
-
const valid = await verifyConfirmToken(env, props2.sub, toolName, confirm_token);
|
|
7379
|
-
if (!valid) return err2("Invalid or expired confirm_token.");
|
|
7380
|
-
try {
|
|
7381
|
-
const stripeKey = env.STRIPE_ORG_SECRET_KEY ?? env.STRIPE_SECRET_KEY;
|
|
7382
|
-
if (!stripeKey) return err2("Stripe not configured");
|
|
7383
|
-
const result2 = await stripePost(
|
|
7384
|
-
stripeKey,
|
|
7385
|
-
`/v1/radar/reviews/${review_id}/approve`,
|
|
7386
|
-
{ reason: "fraudulent" }
|
|
7387
|
-
);
|
|
7388
|
-
if (!result2.ok) return err2(`Stripe error: ${JSON.stringify(result2.data)}`);
|
|
7389
|
-
writeAudit(env, {
|
|
7390
|
-
tool_name: toolName,
|
|
7391
|
-
ocs_method: "stripe.radar.review.decline",
|
|
7392
|
-
status: "ok",
|
|
7393
|
-
dry_run: false,
|
|
7394
|
-
duration_ms: Date.now() - start,
|
|
7395
|
-
sub: props2.sub,
|
|
7396
|
-
reseller_id: props2.reseller_id
|
|
7397
|
-
});
|
|
7398
|
-
return ok(`Review ${review_id} declined.`);
|
|
7399
|
-
} catch (e) {
|
|
7400
|
-
Sentry3.captureException(e);
|
|
7401
|
-
return err2(`Error: ${e instanceof Error ? e.message : "unknown"}`);
|
|
7402
|
-
}
|
|
7397
|
+
return err2(declineNotSupported(review_id));
|
|
7403
7398
|
}
|
|
7404
7399
|
);
|
|
7405
7400
|
server2.registerTool(
|