@carrierllc/mcp 0.13.35 → 0.13.37

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-EH3ZRLVZ.js";
83
+ } from "./chunk-4MQE47L6.js";
84
84
  import "./chunk-SHKKVIIA.js";
85
85
 
86
86
  // src/index.ts
@@ -6925,6 +6925,9 @@ async function stripeGet(stripeKey, path, connectedAccountId) {
6925
6925
  const data = await res.json();
6926
6926
  return { ok: res.ok, status: res.status, data };
6927
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
+ }
6928
6931
  async function stripePost(stripeKey, path, params, connectedAccountId, idempotencyKey) {
6929
6932
  const headers = buildStripeHeaders(stripeKey, {
6930
6933
  connectedAccountId,
@@ -7174,7 +7177,7 @@ function registerStripeConnectTools(server2, ctx) {
7174
7177
  "stripe_connect_refund",
7175
7178
  {
7176
7179
  title: "Refund a Charge (moves real money)",
7177
- 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 to stop a charge that has not settled yet \u2014 decline it with `radar_review_decline`. 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.",
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.",
7178
7181
  inputSchema: {
7179
7182
  charge_id: z8.string().min(1).describe("Stripe charge ID (ch_...)."),
7180
7183
  amount_cents: z8.number().int().min(1).optional().describe("Partial refund amount in cents. Omit for full refund."),
@@ -7276,9 +7279,9 @@ Call again with confirm_token="${token2}" to execute. Token expires in 5 minutes
7276
7279
  "radar_review_list",
7277
7280
  {
7278
7281
  title: "List Radar Fraud Reviews",
7279
- 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 \u2014 false also returns already-decided reviews), `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`.",
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`.",
7280
7283
  inputSchema: {
7281
- open_only: z8.boolean().default(true).describe("If true, only returns open (undecided) reviews."),
7284
+ open_only: z8.boolean().default(true).describe("Stripe lists only open (undecided) reviews; kept for compatibility."),
7282
7285
  limit: z8.number().int().min(1).max(50).default(10)
7283
7286
  },
7284
7287
  annotations: annotationsFor("radar_review_list", "read")
@@ -7296,9 +7299,9 @@ Call again with confirm_token="${token2}" to execute. Token expires in 5 minutes
7296
7299
  const stripeKey = env.STRIPE_ORG_SECRET_KEY ?? env.STRIPE_SECRET_KEY;
7297
7300
  if (!stripeKey) return err2("Stripe not configured");
7298
7301
  const params = new URLSearchParams({ limit: String(limit) });
7299
- if (open_only) params.set("open", "true");
7300
- const result2 = await stripeGet(stripeKey, `/v1/radar/reviews?${params.toString()}`);
7302
+ const result2 = await stripeGet(stripeKey, `/v1/reviews?${params.toString()}`);
7301
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;
7302
7305
  writeAudit(env, {
7303
7306
  tool_name: "radar_review_list",
7304
7307
  ocs_method: "stripe.radar.reviews.list",
@@ -7308,7 +7311,7 @@ Call again with confirm_token="${token2}" to execute. Token expires in 5 minutes
7308
7311
  sub: props2.sub,
7309
7312
  reseller_id: props2.reseller_id
7310
7313
  });
7311
- return ok(JSON.stringify({ reviews: result2.data.data, has_more: result2.data.has_more }));
7314
+ return ok(JSON.stringify({ reviews, has_more: result2.data.has_more }));
7312
7315
  } catch (e) {
7313
7316
  Sentry3.captureException(e);
7314
7317
  return err2(`Error: ${e instanceof Error ? e.message : "unknown"}`);
@@ -7319,7 +7322,7 @@ Call again with confirm_token="${token2}" to execute. Token expires in 5 minutes
7319
7322
  "radar_review_approve",
7320
7323
  {
7321
7324
  title: "Approve Radar Review (captures charge)",
7322
- 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 block a suspicious charge \u2014 that is `radar_review_decline`, the opposite outcome. Do NOT call this to return money on a charge that already went through \u2014 that is `stripe_connect_refund`.",
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`.",
7323
7326
  inputSchema: {
7324
7327
  review_id: z8.string().min(1).describe("Stripe Radar review ID (prv_...)."),
7325
7328
  confirm_token: z8.string().optional()
@@ -7351,7 +7354,8 @@ Call again with confirm_token="${token2}" to execute. Expires in 5 minutes.`
7351
7354
  if (!stripeKey) return err2("Stripe not configured");
7352
7355
  const result2 = await stripePost(
7353
7356
  stripeKey,
7354
- `/v1/radar/reviews/${review_id}/approve`,
7357
+ // POST /v1/reviews/:id/approve (docs.stripe.com/api/radar/reviews/approve).
7358
+ `/v1/reviews/${encodeURIComponent(review_id)}/approve`,
7355
7359
  {}
7356
7360
  );
7357
7361
  if (!result2.ok) return err2(`Stripe error: ${JSON.stringify(result2.data)}`);
@@ -7374,15 +7378,15 @@ Call again with confirm_token="${token2}" to execute. Expires in 5 minutes.`
7374
7378
  server2.registerTool(
7375
7379
  "radar_review_decline",
7376
7380
  {
7377
- title: "Decline Radar Review (blocks charge)",
7378
- description: "Close a Stripe Radar fraud review as fraudulent, so the held charge is blocked and the customer is never billed. The customer sees a failed payment; if they were legitimate, they have to pay again. 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 let a charge through \u2014 that is `radar_review_approve`, the opposite outcome. Do NOT call this on a charge that already succeeded; a review only exists while the charge is held, and returning settled money is `stripe_connect_refund`.",
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.",
7379
7383
  inputSchema: {
7380
7384
  review_id: z8.string().min(1),
7381
7385
  confirm_token: z8.string().optional()
7382
7386
  },
7383
7387
  annotations: annotationsFor("radar_review_decline", "admin")
7384
7388
  },
7385
- async ({ review_id, confirm_token }) => {
7389
+ async ({ review_id }) => {
7386
7390
  const denied = denyUnlessScoped(props2, "radar_review_decline", STRIPE_CONNECT_TOOL_SCOPES);
7387
7391
  if (denied) return denied;
7388
7392
  if (!isPlatformOperator(env, props2.org_id)) {
@@ -7390,41 +7394,7 @@ Call again with confirm_token="${token2}" to execute. Expires in 5 minutes.`
7390
7394
  "This tool acts on Carrier's platform Stripe account and is restricted to Carrier's own organization."
7391
7395
  );
7392
7396
  }
7393
- const toolName = "radar_review_decline";
7394
- const start = Date.now();
7395
- if (!confirm_token) {
7396
- const token2 = await issueConfirmToken(env, props2.sub, toolName);
7397
- return ok(
7398
- `HARD_BLOCK: Declining review ${review_id} will close/block the charge.
7399
- confirm_token: ${token2}
7400
- Expires in 5 minutes.`
7401
- );
7402
- }
7403
- const valid = await verifyConfirmToken(env, props2.sub, toolName, confirm_token);
7404
- if (!valid) return err2("Invalid or expired confirm_token.");
7405
- try {
7406
- const stripeKey = env.STRIPE_ORG_SECRET_KEY ?? env.STRIPE_SECRET_KEY;
7407
- if (!stripeKey) return err2("Stripe not configured");
7408
- const result2 = await stripePost(
7409
- stripeKey,
7410
- `/v1/radar/reviews/${review_id}/approve`,
7411
- { reason: "fraudulent" }
7412
- );
7413
- if (!result2.ok) return err2(`Stripe error: ${JSON.stringify(result2.data)}`);
7414
- writeAudit(env, {
7415
- tool_name: toolName,
7416
- ocs_method: "stripe.radar.review.decline",
7417
- status: "ok",
7418
- dry_run: false,
7419
- duration_ms: Date.now() - start,
7420
- sub: props2.sub,
7421
- reseller_id: props2.reseller_id
7422
- });
7423
- return ok(`Review ${review_id} declined.`);
7424
- } catch (e) {
7425
- Sentry3.captureException(e);
7426
- return err2(`Error: ${e instanceof Error ? e.message : "unknown"}`);
7427
- }
7397
+ return err2(declineNotSupported(review_id));
7428
7398
  }
7429
7399
  );
7430
7400
  server2.registerTool(