@carrierllc/mcp 0.10.4 → 0.10.6

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/cli.js CHANGED
@@ -39,7 +39,7 @@ import {
39
39
  verifyStorefront,
40
40
  walletScreen,
41
41
  which
42
- } from "./chunk-KC3FPQ7P.js";
42
+ } from "./chunk-DQHSDVIJ.js";
43
43
  import {
44
44
  copyTree,
45
45
  exists,
package/dist/index.js CHANGED
@@ -18,6 +18,8 @@ import {
18
18
  esimStatusPerAccountParams,
19
19
  extractDailyUsage,
20
20
  extractEsimStatusCounts,
21
+ extractResellerBalance,
22
+ extractSubscriberStatus,
21
23
  filterActiveSubscribers,
22
24
  fleetScreen,
23
25
  formatBytes,
@@ -26,17 +28,24 @@ import {
26
28
  getLimitForEndpoint,
27
29
  getRateLimitWindowCounts,
28
30
  imsiFromSubscriberRecord,
31
+ isActivePackage,
29
32
  isTargetId,
30
33
  lastNDaysPeriod,
31
34
  loadStorefrontBrand,
32
35
  locationParams,
33
36
  mergeEnvLocal,
37
+ networkEventRows,
34
38
  networkEventsOverPeriodParams,
35
39
  normalizePackageTemplate,
36
40
  normalizePackageTemplateChanges,
37
41
  ocsLocalDateTime,
38
42
  packageActivePeriodParams,
43
+ packageDataLimit,
44
+ packageDataUsed,
45
+ packageExpiry,
46
+ packageName,
39
47
  prepaidPackageLimits,
48
+ prepaidPackageRows,
40
49
  probeAll,
41
50
  provisionClerk,
42
51
  rankTargets,
@@ -48,10 +57,12 @@ import {
48
57
  storefrontClerkUrls,
49
58
  subscriberIdParams,
50
59
  subscriberRows,
60
+ subscriberSimId,
61
+ summarizeNetworkEvents,
51
62
  usageOverPeriodParams,
52
63
  verifyStorefront,
53
64
  withOcsListSummary
54
- } from "./chunk-KC3FPQ7P.js";
65
+ } from "./chunk-DQHSDVIJ.js";
55
66
  import "./chunk-SHKKVIIA.js";
56
67
 
57
68
  // src/index.ts
@@ -313,7 +324,7 @@ async function invokeModelRaw(creds, payload, opts = {}, signal) {
313
324
  }
314
325
  var PENDING_ASK_PREFIX = "manus_pending_ask:";
315
326
  var PENDING_ASK_TTL_SECONDS = 24 * 3600;
316
- var OCS_DASHBOARD_DEFAULT = "https://ocs.esimvault.cloud";
327
+ var OCS_DASHBOARD_DEFAULT = "https://portal-esimvault.cloud";
317
328
  function buildLoginPreamble(dashboardUrl) {
318
329
  return `STEP 1 \u2014 LOGIN:
319
330
  Navigate to ${dashboardUrl}/login (or the main page if no /login path).
@@ -1824,7 +1835,7 @@ function registerAllTools(server2, ctx) {
1824
1835
  "list_subscriber_packages",
1825
1836
  {
1826
1837
  title: "List Subscriber Packages",
1827
- description: "Use this to retrieve all prepaid packages currently assigned to a subscriber. Returns each package's allowance (data/voice/SMS), consumed usage, expiry date, status, and packageId. Always call this before any package modification tool (`modify_package_limits`, `modify_package_expiry`, `modify_package_status`, `delete_subscriber_package`) to confirm the correct packageId and current state. Params: `iccid` (subscriber identifier). Returns: `{ summary, prepaidPackage: [...] }` \u2014 package records with `packageId`, `name`, `status`, `dataLimit`, `dataUsed`, `expirationDate` and a `recurring` flag, behind a server-counted `summary.total` and a `summary.breakdown` over status and recurring. Answer 'how many' from `summary`, not by counting rows. Do NOT use this to browse the product catalog \u2014 use `list_package_templates` for that.",
1838
+ description: "Use this to retrieve all prepaid packages currently assigned to a subscriber. Returns each package's allowance (data/voice/SMS), consumed usage, expiry date, status, and packageId. Always call this before any package modification tool (`modify_package_limits`, `modify_package_expiry`, `modify_package_status`, `delete_subscriber_package`) to confirm the correct packageId and current state. Params: `iccid` (subscriber identifier). Returns: `{ summary, packages: [...] }` \u2014 package records with `packageId`, `name`, `status`, `dataLimit`, `dataUsed`, `expirationDate` and a `recurring` flag, behind a server-counted `summary.total` and a `summary.breakdown` over status and recurring. Answer 'how many' from `summary`, not by counting rows. Do NOT use this to browse the product catalog \u2014 use `list_package_templates` for that.",
1828
1839
  inputSchema: { iccid: z.string().describe("The subscriber ICCID") },
1829
1840
  annotations: { readOnlyHint: true }
1830
1841
  },
@@ -4061,57 +4072,44 @@ function registerIntelligenceTools(server2, ctx) {
4061
4072
  const sub = await safeCall(ctx.env, token2, "getSingleSubscriber", { iccid });
4062
4073
  if (sub.error) return result(`Failed to fetch subscriber: ${sub.error}`, true);
4063
4074
  if (!sub.data) return result("Subscriber not found", true);
4064
- const status = String(sub.data.status ?? "").toUpperCase();
4075
+ const status = (extractSubscriberStatus(sub.data) ?? "").toUpperCase();
4065
4076
  const balance = Number(sub.data.balance ?? 0);
4066
- if (status !== "ACTIVE") {
4077
+ if (status === "") {
4078
+ findings.push("OCS status could not be read from the subscriber record");
4079
+ if (severity === "healthy") severity = "info";
4080
+ } else if (status !== "ACTIVE") {
4067
4081
  findings.push(`OCS status is ${status} (not ACTIVE)`);
4068
4082
  actions.push(`Reactivate subscriber via modify_subscriber_status`);
4069
4083
  severity = "critical";
4070
4084
  }
4071
- if (balance <= 0) {
4072
- findings.push(`Balance is ${balance} \u2014 subscriber may be blocked from usage`);
4073
- actions.push(`Top up balance via modify_subscriber_balance`);
4074
- if (severity !== "critical") severity = "warning";
4075
- }
4076
- const simId = sub.data.simId ?? sub.data.sim_id ?? sub.data.id;
4077
- const sim = simId !== void 0 ? await safeCall(ctx.env, token2, "getSimProviderStatus", Number(simId)) : { data: null, error: null };
4078
- if (sim.data) {
4079
- const simStatus = String(sim.data.simStatus ?? sim.data.status ?? "").toUpperCase();
4080
- if (simStatus && !["ENABLED", "ACTIVE", "ACTIVATED"].includes(simStatus)) {
4081
- findings.push(`SIM provider status is ${simStatus} \u2014 SIM may be disabled at network level`);
4082
- actions.push(`Enable SIM via change_sim_status`);
4083
- severity = "critical";
4084
- }
4085
- }
4086
4085
  const pkgs = await safeCall(ctx.env, token2, "listSubscriberPrepaidPackages", { iccid });
4087
- if (pkgs.data && Array.isArray(pkgs.data)) {
4088
- const activePkgs = pkgs.data.filter(
4089
- (p) => String(p.status ?? "").toUpperCase() === "ACTIVE"
4090
- );
4086
+ const activePkgs = prepaidPackageRows(pkgs.data).filter(isActivePackage);
4087
+ if (!pkgs.error) {
4091
4088
  if (activePkgs.length === 0) {
4092
4089
  findings.push("No active packages \u2014 subscriber has no data/voice/SMS allowance");
4093
4090
  actions.push("Assign a package via assign_package");
4094
4091
  severity = "critical";
4095
4092
  } else {
4096
4093
  for (const pkg of activePkgs) {
4097
- const dataUsed = Number(pkg.dataUsed ?? pkg.dataConsumed ?? 0);
4098
- const dataLimit = Number(pkg.dataLimit ?? pkg.dataAllowance ?? 0);
4094
+ const label = packageName(pkg);
4095
+ const dataUsed = packageDataUsed(pkg);
4096
+ const dataLimit = packageDataLimit(pkg);
4099
4097
  if (dataLimit > 0 && dataUsed >= dataLimit) {
4100
4098
  findings.push(
4101
- `Package "${pkg.name ?? pkg.packageTemplateId}" data depleted: ${formatBytes(dataUsed)} / ${formatBytes(dataLimit)}`
4099
+ `Package "${label}" data depleted: ${formatBytes(dataUsed)} / ${formatBytes(dataLimit)}`
4102
4100
  );
4103
4101
  actions.push("Assign additional package or increase limits via modify_package_limits");
4104
4102
  if (severity !== "critical") severity = "warning";
4105
4103
  }
4106
- const expiry = String(pkg.expirationDate ?? pkg.endDate ?? "");
4104
+ const expiry = packageExpiry(pkg);
4107
4105
  if (expiry) {
4108
4106
  const days = daysUntil(expiry);
4109
4107
  if (days < 0) {
4110
- findings.push(`Package "${pkg.name ?? pkg.packageTemplateId}" expired ${Math.abs(days)} days ago`);
4108
+ findings.push(`Package "${label}" expired ${Math.abs(days)} days ago`);
4111
4109
  actions.push("Remove expired package and assign a new one");
4112
4110
  if (severity !== "critical") severity = "warning";
4113
4111
  } else if (days <= 3) {
4114
- findings.push(`Package "${pkg.name ?? pkg.packageTemplateId}" expires in ${days} day(s)`);
4112
+ findings.push(`Package "${label}" expires in ${days} day(s)`);
4115
4113
  actions.push("Consider renewing or assigning a recurring package");
4116
4114
  if (severity === "healthy") severity = "info";
4117
4115
  }
@@ -4119,23 +4117,61 @@ function registerIntelligenceTools(server2, ctx) {
4119
4117
  }
4120
4118
  }
4121
4119
  }
4120
+ if (balance <= 0 && activePkgs.length === 0) {
4121
+ findings.push(`Balance is ${balance} \u2014 subscriber may be blocked from usage`);
4122
+ actions.push(`Top up balance via modify_subscriber_balance`);
4123
+ if (severity !== "critical") severity = "warning";
4124
+ }
4125
+ const simId = subscriberSimId(sub.data);
4126
+ const sim = simId !== void 0 ? await safeCall(ctx.env, token2, "getSimProviderStatus", simId) : { data: null, error: null };
4127
+ if (sim.data) {
4128
+ const simStatus = String(sim.data.simStatus ?? sim.data.status ?? "").toUpperCase();
4129
+ if (simStatus && !["ENABLED", "ACTIVE", "ACTIVATED"].includes(simStatus)) {
4130
+ findings.push(`SIM provider status is ${simStatus} \u2014 SIM may be disabled at network level`);
4131
+ actions.push(`Enable SIM via change_sim_status`);
4132
+ severity = "critical";
4133
+ }
4134
+ }
4122
4135
  const now = /* @__PURE__ */ new Date();
4123
4136
  const eventWindow = lastNDaysPeriod(3, now);
4124
4137
  const events = await safeCall(ctx.env, token2, "subscriberNetworkEventsOverPeriod", {
4125
4138
  subscriber: { iccid },
4126
4139
  period: eventWindow
4127
4140
  });
4128
- if (events.data && Array.isArray(events.data)) {
4129
- if (events.data.length === 0) {
4130
- findings.push("No network events in last 48 hours \u2014 device may be powered off or out of coverage");
4141
+ if (!events.error) {
4142
+ const net = summarizeNetworkEvents(networkEventRows(events.data));
4143
+ if (net.total === 0) {
4144
+ findings.push("No network events in last 72 hours \u2014 device may be powered off or out of coverage");
4131
4145
  if (severity === "healthy") severity = "warning";
4132
4146
  } else {
4133
- const lastEvent = events.data[events.data.length - 1];
4134
- const lastType = String(lastEvent.eventType ?? lastEvent.type ?? "unknown");
4135
- findings.push(`Last network event: ${lastType} at ${lastEvent.timestamp ?? lastEvent.date ?? "unknown"}`);
4147
+ if (net.creditLimitReached > 0) {
4148
+ findings.push(
4149
+ `${net.creditLimitReached} data session(s) refused with CreditLimitReached \u2014 bundle is out of credit at the charging layer`
4150
+ );
4151
+ actions.push("Assign a package or raise limits via modify_package_limits");
4152
+ severity = "critical";
4153
+ }
4154
+ if (net.roamingNotAllowed > 0) {
4155
+ findings.push(
4156
+ `${net.roamingNotAllowed} attach(es) rejected 5004 (roaming not allowed) \u2014 operator not permitted for this subscriber`
4157
+ );
4158
+ actions.push("Review the steering list via list_steering_lists and modify_subscriber_steering_list");
4159
+ if (severity !== "critical") severity = "warning";
4160
+ }
4161
+ if (net.mapTimeouts > 0) {
4162
+ findings.push(`${net.mapTimeouts} MAP signalling leg(s) timed out \u2014 2G/3G attach is unreliable here`);
4163
+ if (severity === "healthy") severity = "info";
4164
+ }
4165
+ if (net.operators.length >= 3) {
4166
+ findings.push(
4167
+ `Attached across ${net.operators.length} operators (${net.operators.join(", ")}) \u2014 possible steering ping-pong, sessions may be torn down repeatedly`
4168
+ );
4169
+ if (severity === "healthy") severity = "info";
4170
+ }
4171
+ findings.push(`${net.total} network event(s), last at ${net.lastEventTime || "unknown"}`);
4136
4172
  }
4137
4173
  }
4138
- const imsiForBitrate = typeof sub.data.imsi === "string" ? sub.data.imsi : null;
4174
+ const imsiForBitrate = imsiFromSubscriberRecord(sub.data) ?? null;
4139
4175
  const bitrate = imsiForBitrate ? await safeCall(ctx.env, token2, "hlrGetBitrate", { imsi: imsiForBitrate }) : { data: null, error: null };
4140
4176
  if (bitrate.data) {
4141
4177
  const rate = Number(bitrate.data.bitrate ?? bitrate.data.maxBitrate ?? 0);
@@ -4164,7 +4200,7 @@ function registerIntelligenceTools(server2, ctx) {
4164
4200
  `## Raw Status`,
4165
4201
  `- OCS Status: ${status}`,
4166
4202
  `- Balance: ${balance}`,
4167
- `- Active Packages: ${pkgs.data && Array.isArray(pkgs.data) ? pkgs.data.filter((p) => String(p.status ?? "").toUpperCase() === "ACTIVE").length : "unknown"}`
4203
+ `- Active Packages: ${pkgs.error ? "unknown" : activePkgs.length}`
4168
4204
  ].join("\n");
4169
4205
  return result(report);
4170
4206
  });
@@ -4249,9 +4285,7 @@ High suspension rate (${totalSuspended} suspended vs ${totalActive} active)`);
4249
4285
  const criticalZero = accounts.filter(
4250
4286
  (a) => a.packageOnly === false && Number(a.balance ?? 0) <= 0
4251
4287
  );
4252
- const resellerRaw = resellerInfoResult?.data ?? null;
4253
- const rawBalance = resellerRaw?.getResellerInfo?.balance;
4254
- const resellerBalance = rawBalance === void 0 || rawBalance === null ? null : Number(rawBalance);
4288
+ const resellerBalance = extractResellerBalance(resellerInfoResult?.data);
4255
4289
  const resellerOutOfCredit = resellerBalance !== null && resellerBalance <= 0;
4256
4290
  sections.push(`
4257
4291
  ## Account Summary`);
@@ -5860,6 +5894,20 @@ function registerAllUiAgentTools(server2, ctx, runtime, optIn = readPortalOptIn(
5860
5894
  };
5861
5895
  }
5862
5896
  const resellerId = args.reseller_id ?? ctx.props.reseller_id;
5897
+ if (typeof resellerId !== "number" || !Number.isFinite(resellerId)) {
5898
+ return {
5899
+ isError: true,
5900
+ content: [
5901
+ {
5902
+ type: "text",
5903
+ text: JSON.stringify({
5904
+ error: "reseller_id_unresolved",
5905
+ message: "Could not resolve a reseller id from the session. Pass reseller_id explicitly."
5906
+ })
5907
+ }
5908
+ ]
5909
+ };
5910
+ }
5863
5911
  const requested = [
5864
5912
  args.relay_gy === void 0 ? null : `Relay Gy: ${args.relay_gy ? "enable" : "disable"}`,
5865
5913
  args.relay_calls_sms === void 0 ? null : `Calls/SMS relay: ${args.relay_calls_sms ? "enable" : "disable"}`,
@@ -10390,10 +10438,14 @@ async function listRecentOcsEvents(iccid, limit, eventTypes, since, kv) {
10390
10438
  var ALLOWED_EVENT_TYPES = [
10391
10439
  "esim.activated",
10392
10440
  "esim.disabled",
10393
- "package.expiry_warning",
10441
+ "esim.enabled",
10442
+ "package.low_balance",
10443
+ "package.low_quota",
10444
+ "package.expiring",
10445
+ "package.expired",
10394
10446
  "location.changed",
10395
10447
  "country.entered",
10396
- "balance.low"
10448
+ "usage.anomaly"
10397
10449
  ];
10398
10450
  var listRecentOcsEventsSchema = {
10399
10451
  iccid: z12.string().regex(/^\d{19,20}$/).describe("ICCID, 19 or 20 digits, ITU-T E.118 format"),