@carrierllc/mcp 0.2.4 → 0.2.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/index.js CHANGED
@@ -530,13 +530,22 @@ function registerAllTools(server2, ctx) {
530
530
  "list_subscribers",
531
531
  {
532
532
  title: "List Subscribers",
533
- description: "Use this to list subscribers with optional filters and pagination. Good for fleet enumeration, bulk status checks, and finding subscribers by account or status. Params: `accountId` (integer, filter by account), `status` (string, e.g. 'ACTIVE'/'SUSPENDED'), `offset` (integer, for pagination \u2014 default 0), `limit` (integer, max results \u2014 always set to avoid unbounded fetches; recommended max 100 per call). Returns: array of subscriber summary records with ICCID, status, and account. Do NOT use this to fetch full details for a specific subscriber \u2014 use `get_subscriber` for that.",
534
- inputSchema: {
533
+ description: "Use this to list subscribers with optional filters and pagination. Good for fleet enumeration, bulk status checks, and finding subscribers by account or status. OCS REQUIRES at least one search key \u2014 provide exactly one of: `imsi`, `iccid`, `activationCode`, `accountId`, or `msisdn`. Calling with no key will be rejected before reaching OCS. Params: `imsi` (string), `iccid` (string), `activationCode` (string), `accountId` (integer), `msisdn` (string), `status` (string, e.g. 'ACTIVE'/'SUSPENDED'), `offset` (integer, pagination \u2014 default 0), `limit` (integer, max results \u2014 always set to avoid unbounded fetches; recommended max 100 per call). Returns: array of subscriber summary records with ICCID, status, and account. Do NOT use this to fetch full details for a specific subscriber \u2014 use `get_subscriber` for that.",
534
+ inputSchema: z.object({
535
+ imsi: z.string().optional().describe("Filter by IMSI"),
536
+ iccid: z.string().optional().describe("Filter by ICCID"),
537
+ activationCode: z.string().optional().describe("Filter by activation code"),
535
538
  accountId: z.number().optional().describe("Filter by account ID"),
539
+ msisdn: z.string().optional().describe("Filter by MSISDN"),
536
540
  status: z.string().optional().describe("Filter by status"),
537
541
  offset: z.number().optional().describe("Pagination offset"),
538
542
  limit: z.number().optional().describe("Max results to return")
539
- },
543
+ }).refine(
544
+ (d) => d.imsi !== void 0 || d.iccid !== void 0 || d.activationCode !== void 0 || d.accountId !== void 0 || d.msisdn !== void 0,
545
+ {
546
+ message: "Provide at least one of: imsi, iccid, activationCode, accountId, msisdn"
547
+ }
548
+ ),
540
549
  annotations: { readOnlyHint: true }
541
550
  },
542
551
  wrapHandler(
@@ -546,7 +555,11 @@ function registerAllTools(server2, ctx) {
546
555
  ctx,
547
556
  async (args, token2) => {
548
557
  const params = {};
558
+ if (args.imsi) params.imsi = args.imsi;
559
+ if (args.iccid) params.iccid = args.iccid;
560
+ if (args.activationCode) params.activationCode = args.activationCode;
549
561
  if (args.accountId !== void 0) params.accountId = args.accountId;
562
+ if (args.msisdn) params.msisdn = args.msisdn;
550
563
  if (args.status) params.status = args.status;
551
564
  if (args.offset !== void 0) params.offset = args.offset;
552
565
  const client = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
@@ -3120,9 +3133,11 @@ function registerIntelligenceTools(server2, ctx) {
3120
3133
  safeCall(ctx.env, token2, "listResellerAccount", {})
3121
3134
  ]);
3122
3135
  const sections = ["# Fleet Health Dashboard\n"];
3123
- if (statusResult.data && Array.isArray(statusResult.data)) {
3124
- let totalActive = 0, totalSuspended = 0, totalInventory = 0, totalOther = 0;
3125
- for (const account of statusResult.data) {
3136
+ let totalActive = 0, totalSuspended = 0, totalInventory = 0, totalOther = 0;
3137
+ const statusOk = statusResult.data && Array.isArray(statusResult.data);
3138
+ const statusAccounts = statusOk ? statusResult.data : [];
3139
+ if (statusOk) {
3140
+ for (const account of statusAccounts) {
3126
3141
  totalActive += Number(account.active ?? 0);
3127
3142
  totalSuspended += Number(account.suspended ?? 0);
3128
3143
  totalInventory += Number(account.inventory ?? account.notActivated ?? 0);
@@ -3131,37 +3146,79 @@ function registerIntelligenceTools(server2, ctx) {
3131
3146
  const total = totalActive + totalSuspended + totalInventory + totalOther;
3132
3147
  const utilization = total > 0 ? (totalActive / total * 100).toFixed(1) : "0";
3133
3148
  sections.push(`## eSIM Fleet Status`);
3134
- sections.push(`| Metric | Count | % |`);
3135
- sections.push(`|--------|-------|---|`);
3136
- sections.push(`| Active | ${totalActive} | ${total > 0 ? (totalActive / total * 100).toFixed(1) : 0}% |`);
3137
- sections.push(`| Suspended | ${totalSuspended} | ${total > 0 ? (totalSuspended / total * 100).toFixed(1) : 0}% |`);
3138
- sections.push(`| Inventory | ${totalInventory} | ${total > 0 ? (totalInventory / total * 100).toFixed(1) : 0}% |`);
3139
- sections.push(`| Other | ${totalOther} | ${total > 0 ? (totalOther / total * 100).toFixed(1) : 0}% |`);
3140
- sections.push(`| **Total** | **${total}** | |`);
3141
- sections.push(`
3142
- **Fleet Utilization: ${utilization}%**`);
3143
- if (totalSuspended > totalActive * 0.1) {
3149
+ if (total === 0) {
3150
+ sections.push(`No eSIMs provisioned across ${statusAccounts.length} account(s).`);
3151
+ } else {
3152
+ sections.push(`| Metric | Count | % |`);
3153
+ sections.push(`|--------|-------|---|`);
3154
+ sections.push(`| Active | ${totalActive} | ${(totalActive / total * 100).toFixed(1)}% |`);
3155
+ sections.push(`| Suspended | ${totalSuspended} | ${(totalSuspended / total * 100).toFixed(1)}% |`);
3156
+ sections.push(`| Inventory | ${totalInventory} | ${(totalInventory / total * 100).toFixed(1)}% |`);
3157
+ sections.push(`| Other | ${totalOther} | ${(totalOther / total * 100).toFixed(1)}% |`);
3158
+ sections.push(`| **Total** | **${total}** | |`);
3144
3159
  sections.push(`
3145
- \u26A0 High suspension rate (${totalSuspended} suspended vs ${totalActive} active)`);
3160
+ **Fleet Utilization: ${utilization}%**`);
3161
+ if (totalSuspended > totalActive * 0.1) {
3162
+ sections.push(`
3163
+ High suspension rate (${totalSuspended} suspended vs ${totalActive} active)`);
3164
+ }
3146
3165
  }
3166
+ } else {
3167
+ sections.push(`## eSIM Fleet Status`);
3168
+ sections.push(`Unavailable: ${statusResult.error ?? "esimStatusPerAccount returned no data"}`);
3147
3169
  }
3148
- if (accountsResult.data && Array.isArray(accountsResult.data)) {
3149
- const lowBalance = accountsResult.data.filter(
3170
+ const accountsOk = accountsResult.data && Array.isArray(accountsResult.data);
3171
+ const accounts = accountsOk ? accountsResult.data : [];
3172
+ if (accountsOk) {
3173
+ const lowBalance = accounts.filter(
3150
3174
  (a) => Number(a.balance ?? 0) < 10
3151
3175
  );
3176
+ const packageOnlyZero = accounts.filter(
3177
+ (a) => Boolean(a.packageOnly) && Number(a.balance ?? 0) <= 0
3178
+ );
3179
+ sections.push(`
3180
+ ## Account Summary`);
3181
+ sections.push(`- Total accounts: ${accounts.length}`);
3182
+ sections.push(`- Low balance (< 10): ${lowBalance.length}`);
3183
+ sections.push(`- Package-only with 0 balance: ${packageOnlyZero.length}`);
3152
3184
  if (lowBalance.length > 0) {
3153
3185
  sections.push(`
3154
- ## Low Balance Accounts (< 10)`);
3155
- sections.push(`| Account | Balance |`);
3156
- sections.push(`|---------|---------|`);
3186
+ ### Low Balance Accounts (< 10)`);
3187
+ sections.push(`| Account | Balance | packageOnly |`);
3188
+ sections.push(`|---------|---------|-------------|`);
3157
3189
  for (const a of lowBalance) {
3158
- sections.push(`| ${a.name ?? a.accountId ?? "?"} | ${Number(a.balance ?? 0).toFixed(2)} |`);
3190
+ sections.push(`| ${a.name ?? a.accountId ?? "?"} | ${Number(a.balance ?? 0).toFixed(2)} | ${a.packageOnly ? "yes" : "no"} |`);
3159
3191
  }
3160
3192
  }
3193
+ const critical = packageOnlyZero.length;
3194
+ const warning = lowBalance.length - critical;
3195
+ const healthy = accounts.length - lowBalance.length;
3196
+ sections.push(`
3197
+ ## Fleet Health Verdict`);
3198
+ sections.push(`- Healthy: ${healthy}`);
3199
+ sections.push(`- Warning (low balance, not package-only-zero): ${Math.max(warning, 0)}`);
3200
+ sections.push(`- Critical (package-only and 0 balance): ${critical}`);
3201
+ if (accounts.length === 0) {
3202
+ sections.push(`
3203
+ No accounts found under this reseller.`);
3204
+ } else if (critical > 0) {
3205
+ sections.push(`
3206
+ Action: top up package-only accounts at 0 balance to keep packages assignable.`);
3207
+ } else if (lowBalance.length === 0) {
3208
+ sections.push(`
3209
+ All accounts healthy.`);
3210
+ }
3211
+ } else {
3161
3212
  sections.push(`
3162
3213
  ## Account Summary`);
3163
- sections.push(`- Total accounts: ${accountsResult.data.length}`);
3164
- sections.push(`- Low balance (< 10): ${lowBalance.length}`);
3214
+ sections.push(`Unavailable: ${accountsResult.error ?? "listResellerAccount returned no data"}`);
3215
+ }
3216
+ if (!statusOk && !accountsOk) {
3217
+ sections.push(`
3218
+ ## Errors`);
3219
+ if (statusResult.error) sections.push(`- esimStatusPerAccount: ${statusResult.error}`);
3220
+ if (accountsResult.error) sections.push(`- listResellerAccount: ${accountsResult.error}`);
3221
+ return result(sections.join("\n"), true);
3165
3222
  }
3166
3223
  return result(sections.join("\n"));
3167
3224
  });