@carrierllc/mcp 0.2.17 → 0.2.18

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 (28) hide show
  1. package/README.md +21 -1
  2. package/dist/cli.js +881 -80
  3. package/dist/cli.js.map +1 -1
  4. package/dist/index.js +177 -22
  5. package/dist/index.js.map +1 -1
  6. package/package.json +7 -6
  7. package/plugin/.claude-plugin/marketplace.json +2 -2
  8. package/plugin/carrier/.claude-plugin/plugin.json +1 -1
  9. package/plugin/carrier/README.md +31 -4
  10. package/plugin/carrier/agents/carrier-billing-auditor.md +1 -1
  11. package/plugin/carrier/commands/billing.md +8 -1
  12. package/plugin/carrier/commands/provision.md +18 -8
  13. package/plugin/carrier/commands/wallet.md +31 -0
  14. package/plugin/carrier/skills/carrier-operations/SKILL.md +12 -5
  15. package/templates/storefront/src/app/activate/[orderId]/ActivateClient.tsx +125 -0
  16. package/templates/storefront/src/app/activate/[orderId]/page.tsx +16 -12
  17. package/templates/storefront/src/app/api/checkout/claim/route.ts +30 -0
  18. package/templates/storefront/src/app/api/checkout/guest/route.ts +91 -0
  19. package/templates/storefront/src/app/api/profile/phone/route.ts +40 -0
  20. package/templates/storefront/src/app/checkout/[templateId]/CheckoutClient.tsx +71 -13
  21. package/templates/storefront/src/app/checkout/success/CheckoutSuccessClient.tsx +415 -0
  22. package/templates/storefront/src/app/checkout/success/page.tsx +59 -0
  23. package/templates/storefront/src/app/sign-up/[[...sign-up]]/StorefrontSignUpClient.tsx +199 -0
  24. package/templates/storefront/src/app/sign-up/[[...sign-up]]/page.tsx +18 -3
  25. package/templates/storefront/src/lib/checkout-order-claim.ts +127 -0
  26. package/templates/storefront/src/lib/complete-email-sign-up.ts +50 -0
  27. package/templates/storefront/src/lib/verify-checkout-session.ts +53 -0
  28. package/templates/storefront/src/middleware.ts +6 -0
package/dist/index.js CHANGED
@@ -8,7 +8,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
8
8
  import { z } from "zod";
9
9
  import * as Sentry from "@sentry/cloudflare";
10
10
 
11
- // ../../packages/ocs-client/dist/chunk-67QO5NVD.js
11
+ // ../../packages/ocs-client/dist/chunk-PMFMORPK.js
12
12
  var ENDPOINT_LIMITS_PER_MIN = {
13
13
  // Global sentinel (keyed as "__global__")
14
14
  __global__: 600,
@@ -20,7 +20,7 @@ var ENDPOINT_LIMITS_PER_MIN = {
20
20
  listLocationZoneElement: 150,
21
21
  sendMtSms: 150,
22
22
  // 300/min (explicit; also the fallback default)
23
- affectPlanToSubscriber: 300,
23
+ modifySubscriberMobilePlan: 300,
24
24
  affectRecurringPackageToSubscriber: 300,
25
25
  affectSubscriberFakePhoneNumber: 300,
26
26
  affectSubscriberRealPhoneNumber: 300,
@@ -389,7 +389,9 @@ var DESTRUCTIVE_TOOLS = /* @__PURE__ */ new Set([
389
389
  "modify_subscriber_package_active_period",
390
390
  "modify_subscriber_voip_plan",
391
391
  "push_steering_to_subscriber",
392
- "reset_subscriber_gz_counter"
392
+ "reset_subscriber_gz_counter",
393
+ // S6 live-smoke gap fill (CAR-105)
394
+ "change_network_profile_of_location_zone"
393
395
  ]);
394
396
  function wrapHandler(toolName, ocsMethod, requiredScope, ctx, handler) {
395
397
  return async (args) => {
@@ -567,9 +569,7 @@ function registerAllTools(server2, ctx) {
567
569
  TOOL_SCOPES["modify_account_balance"],
568
570
  ctx,
569
571
  async ({ accountId, amount, mode }, token2) => {
570
- const params = { accountId };
571
- if (mode === "adapt") params.adaptBalance = amount;
572
- else params.setBalance = amount;
572
+ const params = { accountId, amount, mode };
573
573
  return ocsCall(ctx.env, token2, "modifyAccountBalance", params);
574
574
  }
575
575
  )
@@ -2395,12 +2395,27 @@ var ocs_methods_default = {
2395
2395
  name: "high_cost_subscribers",
2396
2396
  category: "intelligence",
2397
2397
  scope: "read",
2398
+ http_method: "POST",
2399
+ url_path: "/v1/intelligence/high-cost-subscribers",
2398
2400
  description: "Identify highest-cost subscribers for cost optimization",
2399
2401
  wraps: ["listSubscriber", "subscriberUsageOverPeriod", "getCustomerTariff"],
2400
2402
  params: {
2401
- startDate: { type: "string(YYYY-MM-DD)", required: true },
2402
- endDate: { type: "string(YYYY-MM-DD)", required: true },
2403
- accountId: { type: "number", required: false }
2403
+ start: { type: "string(YYYY-MM-DD)", required: false, default: "first day of current month" },
2404
+ end: { type: "string(YYYY-MM-DD)", required: false, default: "today" },
2405
+ limit: { type: "number", required: false, default: 20, max: 200 }
2406
+ },
2407
+ verified_against_server: true,
2408
+ verified_against_live_docs: false
2409
+ },
2410
+ {
2411
+ name: "detect_country_entry",
2412
+ category: "intelligence",
2413
+ scope: "read",
2414
+ description: "Detect subscriber country entry via getSingleSubscriber networkInfo.lastMcc (one OCS call). Resolves MCC to ISO 3166-1 alpha-2 and optionally diffs against expectedCountry.",
2415
+ wraps: ["getSingleSubscriber"],
2416
+ params: {
2417
+ subscriber: { type: "object(subscriberId|imsi|iccid|msisdn|multiImsi|activationCode)", required: true },
2418
+ expectedCountry: { type: "string(ISO3166-1 alpha-2)", required: false }
2404
2419
  },
2405
2420
  verified_against_server: true,
2406
2421
  verified_against_live_docs: false
@@ -2539,10 +2554,10 @@ var ocs_methods_default = {
2539
2554
  ocs_method: "getSubscriberLocationByCellId",
2540
2555
  category: "subscriber",
2541
2556
  scope: "read",
2542
- status: "stubbed",
2557
+ status: "obsolete",
2543
2558
  audit_pr: "feat/ocs-feature-audit",
2544
2559
  audit_stub_id: "S-03",
2545
- description: "Resolve a raw cell tower tuple (radioType + MCC + MNC + LAC + optional cellId) to lat/lon via Bridge4IP GeoSense. Does NOT require a subscriber identifier \u2014 caller supplies cell params directly. Lower-level primitive than get_subscriber_location_by_cell_id. Needed for Relay LU webhook consumer.",
2560
+ description: "OBSOLETE \u2014 duplicate of implemented get_subscriber_location_by_cell_id (same OCS method + cell tuple). Do not register. Use get_subscriber_location_by_cell_id for GeoSense cell-tower resolution.",
2546
2561
  params: {
2547
2562
  radio_type: { type: "enum[2G,3G,4G,5G,NB-IoT]", required: true },
2548
2563
  mcc: { type: "integer", required: true },
@@ -2557,7 +2572,7 @@ var ocs_methods_default = {
2557
2572
  accuracy: { type: "integer", notes: "median error in meters at 50% confidence" }
2558
2573
  },
2559
2574
  annotations: "readOnlyHint",
2560
- blocked_by: "confirm Relay LU payload shape with Bridge4IP NOC",
2575
+ superseded_by: "get_subscriber_location_by_cell_id",
2561
2576
  verified_against_server: false,
2562
2577
  verified_against_live_docs: true
2563
2578
  },
@@ -2566,7 +2581,7 @@ var ocs_methods_default = {
2566
2581
  ocs_method: "getResellerInfo",
2567
2582
  category: "reseller",
2568
2583
  scope: "read",
2569
- status: "stubbed",
2584
+ status: "implemented",
2570
2585
  audit_pr: "feat/ocs-feature-audit",
2571
2586
  audit_stub_id: "S-04",
2572
2587
  description: "Read-only view of Bridge4IP webhook and relay flag state from getResellerInfo.trafficInfo. Surfaces relayLU, relayGy, relayCallSms, relayVoIP booleans + notification webhook types. Relay LU is the key flag for event-driven country-change detection (vs polling). Relay endpoint config is OCS portal UI-only.",
@@ -2581,8 +2596,57 @@ var ocs_methods_default = {
2581
2596
  notification_webhooks: { type: "array", notes: "Active notification types: prepaid_usage, low_credit, esim_status, recurring_packages" }
2582
2597
  },
2583
2598
  annotations: "readOnlyHint",
2584
- verified_against_server: false,
2599
+ verified_against_server: true,
2585
2600
  verified_against_live_docs: true
2601
+ },
2602
+ {
2603
+ name: "list_subscriber_voip_tariff",
2604
+ ocs_method: "listSubscriberVoipTariff",
2605
+ category: "tariff",
2606
+ scope: "read",
2607
+ status: "implemented",
2608
+ description: "List VoIP tariff definitions available to a reseller (smoke-verified OCS method; not on public docs SPA). Optional resellerId filter; omit for token owner's default catalog. Companion to list_voip_tariff_rule for rule detail.",
2609
+ params: {
2610
+ reseller_id: { type: "number", required: false }
2611
+ },
2612
+ annotations: "readOnlyHint",
2613
+ verified_against_server: true,
2614
+ verified_against_live_docs: false,
2615
+ verified_against_live_smoke: true,
2616
+ notes: "Live probe 2026-07-10: only known request property is resellerId (object). Empty object accepted (code 0)."
2617
+ },
2618
+ {
2619
+ name: "list_voip_tariff_rule",
2620
+ ocs_method: "listVoipTariffRule",
2621
+ category: "tariff",
2622
+ scope: "read",
2623
+ status: "implemented",
2624
+ description: "List rate rules for a VoIP plan/tariff by bare integer id (smoke-verified; not on public docs SPA). OCS expects a primitive integer body (same pattern as getCustomerTariff), not an object. Use plan ids from get_reseller_info chargingInfo.voipPlan or list_subscriber_voip_tariff.",
2625
+ params: {
2626
+ voip_plan_id: { type: "number", required: true }
2627
+ },
2628
+ annotations: "readOnlyHint",
2629
+ verified_against_server: true,
2630
+ verified_against_live_docs: false,
2631
+ verified_against_live_smoke: true,
2632
+ notes: "Live probe 2026-07-10: object body rejected (expects java.lang.Integer); unknown id \u2192 OCS 6 No VoIP plan found."
2633
+ },
2634
+ {
2635
+ name: "change_network_profile_of_location_zone",
2636
+ ocs_method: "changeNetworkProfileOfLocationZone",
2637
+ category: "network",
2638
+ scope: "write",
2639
+ status: "implemented",
2640
+ description: "Attach or change the network profile on an existing location zone (smoke-verified; not on public docs SPA). Required fields: locationZoneId + networkProfileId. Use list_network_profiles and list_detailed_location_zones to resolve ids.",
2641
+ params: {
2642
+ location_zone_id: { type: "number", required: true },
2643
+ network_profile_id: { type: "number", required: true }
2644
+ },
2645
+ annotations: "destructiveHint",
2646
+ verified_against_server: true,
2647
+ verified_against_live_docs: false,
2648
+ verified_against_live_smoke: true,
2649
+ notes: "Live probe 2026-07-10: known properties locationZoneId, networkProfileId; missing networkProfileId \u2192 code 2 Missing 'networkProfileId'."
2586
2650
  }
2587
2651
  ],
2588
2652
  v1_app_methods: [
@@ -4142,8 +4206,11 @@ var VALID_RADIO_TYPES = /* @__PURE__ */ new Set(["2G", "3G", "4G", "5G", "NB-IoT
4142
4206
  var BACKLOG_TOOL_SCOPES = {
4143
4207
  affect_subscriber_phone_number: "write",
4144
4208
  carrier_webhook_config: "read",
4209
+ change_network_profile_of_location_zone: "write",
4145
4210
  get_subscriber_location_by_cell_id: "read",
4146
4211
  list_destination_lists: "read",
4212
+ list_subscriber_voip_tariff: "read",
4213
+ list_voip_tariff_rule: "read",
4147
4214
  modify_subscriber_mobile_plan: "write",
4148
4215
  modify_subscriber_package_active_period: "write",
4149
4216
  modify_subscriber_voip_plan: "write",
@@ -4445,6 +4512,92 @@ function registerAllBacklogTools(server2, ctx) {
4445
4512
  }
4446
4513
  )
4447
4514
  );
4515
+ server2.registerTool(
4516
+ "list_subscriber_voip_tariff",
4517
+ {
4518
+ title: "List VoIP Tariffs",
4519
+ description: "Use this to list VoIP tariff definitions available to a reseller. Despite the OCS method name (listSubscriberVoipTariff), this is a reseller-level catalog listing \u2014 not a per-ICCID lookup. Use results (or get_reseller_info chargingInfo.voipPlan.id) to feed `list_voip_tariff_rule` for rate detail. Params: `reseller_id` (integer, optional \u2014 omit to use the token owner's reseller). Returns: OCS VoIP tariff records (may be empty when no VoIP catalog is configured). Do NOT use this for mobile wholesale rates \u2014 use `get_tariff` (getCustomerTariff). Do NOT use this to assign a VoIP plan \u2014 use `modify_subscriber_voip_plan`.",
4520
+ inputSchema: {
4521
+ reseller_id: z3.number().int().positive().optional().describe("Reseller ID (omit to list tariffs for the token owner's reseller)")
4522
+ },
4523
+ annotations: { readOnlyHint: true }
4524
+ },
4525
+ wrapHandler(
4526
+ "list_subscriber_voip_tariff",
4527
+ "listSubscriberVoipTariff",
4528
+ BACKLOG_TOOL_SCOPES["list_subscriber_voip_tariff"],
4529
+ ctx,
4530
+ async ({ reseller_id }, token2) => {
4531
+ const client = new OcsClient2(ctx.env.CARRIER_OCS_BASE_URL, token2);
4532
+ const params = {};
4533
+ if (reseller_id !== void 0) {
4534
+ params.resellerId = reseller_id;
4535
+ }
4536
+ const result2 = await client.call("listSubscriberVoipTariff", params);
4537
+ return {
4538
+ content: [{ type: "text", text: JSON.stringify(result2, null, 2) }]
4539
+ };
4540
+ }
4541
+ )
4542
+ );
4543
+ server2.registerTool(
4544
+ "list_voip_tariff_rule",
4545
+ {
4546
+ title: "List VoIP Tariff Rules",
4547
+ description: "Use this to list the rate rules (costs) for a specific VoIP plan/tariff. OCS expects a bare integer plan id in the request body (not an object). Obtain plan ids from `get_reseller_info` \u2192 chargingInfo.voipPlan.id, or from `list_subscriber_voip_tariff`. Params: `voip_plan_id` (integer, required \u2014 VoIP plan/tariff id). Returns: VoIP tariff rule rows for that plan, or an OCS error when the id is unknown. Do NOT use this for mobile (non-VoIP) wholesale rates \u2014 use `get_tariff`. Do NOT use this to change a subscriber's VoIP plan \u2014 use `modify_subscriber_voip_plan`.",
4548
+ inputSchema: {
4549
+ voip_plan_id: z3.number().int().positive().describe(
4550
+ "VoIP plan/tariff ID (bare integer to OCS listVoipTariffRule; from get_reseller_info chargingInfo.voipPlan.id or list_subscriber_voip_tariff)"
4551
+ )
4552
+ },
4553
+ annotations: { readOnlyHint: true }
4554
+ },
4555
+ wrapHandler(
4556
+ "list_voip_tariff_rule",
4557
+ "listVoipTariffRule",
4558
+ BACKLOG_TOOL_SCOPES["list_voip_tariff_rule"],
4559
+ ctx,
4560
+ async ({ voip_plan_id }, token2) => {
4561
+ const client = new OcsClient2(ctx.env.CARRIER_OCS_BASE_URL, token2);
4562
+ const result2 = await client.call("listVoipTariffRule", voip_plan_id);
4563
+ return {
4564
+ content: [{ type: "text", text: JSON.stringify(result2, null, 2) }]
4565
+ };
4566
+ }
4567
+ )
4568
+ );
4569
+ server2.registerTool(
4570
+ "change_network_profile_of_location_zone",
4571
+ {
4572
+ title: "Change Network Profile of Location Zone",
4573
+ description: "Use this to attach or change the network profile on an existing location zone. A network profile defines sponsor/roaming configuration used when the zone is referenced by package templates. Params: `location_zone_id` (integer from list_detailed_location_zones), `network_profile_id` (integer from list_network_profiles). Returns: OCS confirmation of the updated zone/profile binding. Do NOT use this to create a new location zone \u2014 use `create_location_zone` (which requires networkProfileId at creation time). Do NOT use this for edit/delete of zone TADIG lists \u2014 those remain UI-agent-only (G-19).",
4574
+ inputSchema: {
4575
+ location_zone_id: z3.number().int().positive().describe("Location zone ID (locationZoneId / zoneId from list_detailed_location_zones)"),
4576
+ network_profile_id: z3.number().int().positive().describe("Network profile ID (from list_network_profiles)"),
4577
+ ...DRY_RUN_FIELD2
4578
+ },
4579
+ annotations: { destructiveHint: true }
4580
+ },
4581
+ wrapHandler(
4582
+ "change_network_profile_of_location_zone",
4583
+ "changeNetworkProfileOfLocationZone",
4584
+ BACKLOG_TOOL_SCOPES["change_network_profile_of_location_zone"],
4585
+ ctx,
4586
+ async ({
4587
+ location_zone_id,
4588
+ network_profile_id
4589
+ }, token2) => {
4590
+ const client = new OcsClient2(ctx.env.CARRIER_OCS_BASE_URL, token2);
4591
+ const result2 = await client.call("changeNetworkProfileOfLocationZone", {
4592
+ locationZoneId: location_zone_id,
4593
+ networkProfileId: network_profile_id
4594
+ });
4595
+ return {
4596
+ content: [{ type: "text", text: JSON.stringify(result2, null, 2) }]
4597
+ };
4598
+ }
4599
+ )
4600
+ );
4448
4601
  }
4449
4602
 
4450
4603
  // src/tools-carrier-ask.ts
@@ -5478,7 +5631,7 @@ var MONITORED_ENDPOINTS = [
5478
5631
  // 150/min
5479
5632
  "sendMtSms",
5480
5633
  // 150/min
5481
- "affectPlanToSubscriber",
5634
+ "modifySubscriberMobilePlan",
5482
5635
  // 300/min
5483
5636
  "affectRecurringPackageToSubscriber",
5484
5637
  // 300/min
@@ -6397,8 +6550,10 @@ function registerBalanceTopupApp(server2, ctx) {
6397
6550
  const execResult = await safeCallWithToken3(
6398
6551
  client,
6399
6552
  token2,
6400
- "modifyAccountBalance",
6401
- { subscriber: iccid, adaptBalance: delta }
6553
+ // CAR-78: subscriber top-up uses modifySubscriberBalance with { subscriber, amount }
6554
+ // (delta). modifyAccountBalance is account-level and expects { accountId, amount, mode }.
6555
+ "modifySubscriberBalance",
6556
+ { subscriber: iccid, amount: delta }
6402
6557
  );
6403
6558
  if (execResult.error) {
6404
6559
  return {
@@ -7350,7 +7505,7 @@ var CARRIER_SERVICE_CATALOG = [
7350
7505
  id: "mcp",
7351
7506
  name: "Carrier MCP",
7352
7507
  category: "connectivity",
7353
- description: "Model Context Protocol server \u2014 103 natural-language tools for MVNO/eSIM fleet management",
7508
+ description: "Model Context Protocol server \u2014 113 natural-language tools for MVNO/eSIM fleet management",
7354
7509
  tier_required: "free",
7355
7510
  scopes_required: ["read"],
7356
7511
  endpoints: ["https://mcp.carrier.llc/mcp"],
@@ -7424,7 +7579,7 @@ var CARRIER_SERVICE_CATALOG = [
7424
7579
  tier_required: "free",
7425
7580
  scopes_required: ["read"],
7426
7581
  endpoints: ["https://app.carrier.llc"],
7427
- docs_url: "https://app.carrier.llc/docs"
7582
+ docs_url: "https://carrier.llc/docs"
7428
7583
  }
7429
7584
  ];
7430
7585
  var PROJECTS_TOOLS = [
@@ -7657,7 +7812,7 @@ var PROJECTS_TOOLS = [
7657
7812
  auth_method: props2.auth_method ?? "oauth"
7658
7813
  },
7659
7814
  capabilities: {
7660
- total_tools: 103,
7815
+ total_tools: 113,
7661
7816
  // full tool count
7662
7817
  read_tools: 35,
7663
7818
  write_tools: 20,
@@ -7781,7 +7936,7 @@ function generateCredentialRecommendations(hasToken, tokenAgeDays) {
7781
7936
  const recommendations = [];
7782
7937
  if (!hasToken) {
7783
7938
  recommendations.push(
7784
- "No eSIMVault token configured. Complete setup at https://app.carrier.llc/setup"
7939
+ "No eSIMVault token configured. Complete setup at https://app.carrier.llc/onboarding"
7785
7940
  );
7786
7941
  }
7787
7942
  if (tokenAgeDays !== null && tokenAgeDays > 90) {
@@ -10568,7 +10723,7 @@ var audit = (_row) => {
10568
10723
  var getUserToken = async (_sub) => token;
10569
10724
  var toolCtx = { env: stdioEnv, props, audit, getUserToken };
10570
10725
  var server = new McpServer(
10571
- { name: "carrier-mcp", version: "0.2.4" },
10726
+ { name: "carrier-mcp", version: "0.2.18" },
10572
10727
  {
10573
10728
  instructions: "Carrier MCP \u2014 single-user stdio mode. Full tool registry (mirrors the deployed Worker)."
10574
10729
  }