@carrierllc/mcp 0.9.1 → 0.9.2
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
package/dist/index.js
CHANGED
|
@@ -37,7 +37,7 @@ import {
|
|
|
37
37
|
subscriberIdParams,
|
|
38
38
|
usageOverPeriodParams,
|
|
39
39
|
verifyStorefront
|
|
40
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-4XHSOF62.js";
|
|
41
41
|
import "./chunk-SHKKVIIA.js";
|
|
42
42
|
|
|
43
43
|
// src/index.ts
|
|
@@ -234,12 +234,12 @@ function body(req) {
|
|
|
234
234
|
...req.tools ? { tools: req.tools, tool_choice: { type: "any" } } : {}
|
|
235
235
|
};
|
|
236
236
|
}
|
|
237
|
-
function headersFor(
|
|
237
|
+
function headersFor(attribution, accept) {
|
|
238
238
|
const headers = {
|
|
239
239
|
"Content-Type": "application/json",
|
|
240
240
|
Accept: accept
|
|
241
241
|
};
|
|
242
|
-
const meta =
|
|
242
|
+
const meta = attribution ? requestMetadata(attribution) : null;
|
|
243
243
|
if (meta) headers[REQUEST_METADATA_HEADER] = JSON.stringify(meta);
|
|
244
244
|
return headers;
|
|
245
245
|
}
|
|
@@ -261,27 +261,34 @@ async function fail(resp) {
|
|
|
261
261
|
throw new BedrockError(text || `Bedrock returned HTTP ${resp.status}`, resp.status);
|
|
262
262
|
}
|
|
263
263
|
async function invokeTool(creds, req, signal) {
|
|
264
|
+
const json = await invokeModelRaw(
|
|
265
|
+
creds,
|
|
266
|
+
body(req),
|
|
267
|
+
{ attribution: req.attribution, timeoutMs: req.timeoutMs },
|
|
268
|
+
signal
|
|
269
|
+
);
|
|
270
|
+
reportUsage(req, extractUsage(json));
|
|
271
|
+
const block = json.content?.find((b) => b.type === "tool_use");
|
|
272
|
+
return block?.name ? { name: block.name, input: block.input ?? {} } : null;
|
|
273
|
+
}
|
|
274
|
+
async function invokeModelRaw(creds, payload, opts = {}, signal) {
|
|
264
275
|
const { aws, region, modelId } = client(creds);
|
|
265
276
|
const controller = new AbortController();
|
|
266
|
-
const timer = setTimeout(() => controller.abort(),
|
|
277
|
+
const timer = setTimeout(() => controller.abort(), opts.timeoutMs ?? BEDROCK_TIMEOUT_MS);
|
|
267
278
|
const onAbort = () => controller.abort();
|
|
268
279
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
269
280
|
try {
|
|
270
|
-
const headers = headersFor(req, "application/json");
|
|
271
281
|
const resp = await aws.fetch(
|
|
272
282
|
`https://bedrock-runtime.${region}.amazonaws.com/model/${encodeURIComponent(modelId)}/invoke`,
|
|
273
283
|
{
|
|
274
284
|
method: "POST",
|
|
275
|
-
headers,
|
|
276
|
-
body: JSON.stringify(
|
|
285
|
+
headers: headersFor(opts.attribution, "application/json"),
|
|
286
|
+
body: JSON.stringify(payload),
|
|
277
287
|
signal: controller.signal
|
|
278
288
|
}
|
|
279
289
|
);
|
|
280
290
|
if (!resp.ok) await fail(resp);
|
|
281
|
-
|
|
282
|
-
reportUsage(req, extractUsage(json));
|
|
283
|
-
const block = json.content?.find((b) => b.type === "tool_use");
|
|
284
|
-
return block?.name ? { name: block.name, input: block.input ?? {} } : null;
|
|
291
|
+
return await resp.json();
|
|
285
292
|
} finally {
|
|
286
293
|
clearTimeout(timer);
|
|
287
294
|
signal?.removeEventListener("abort", onAbort);
|
|
@@ -5528,6 +5535,21 @@ function computeExpiresAt(askedAt) {
|
|
|
5528
5535
|
if (isNaN(asked)) return "";
|
|
5529
5536
|
return new Date(asked + PENDING_ASK_TTL_SECONDS * 1e3).toISOString();
|
|
5530
5537
|
}
|
|
5538
|
+
async function callerOwnsTask(ctx, taskId) {
|
|
5539
|
+
let raw;
|
|
5540
|
+
try {
|
|
5541
|
+
raw = await ctx.env.CARRIER_USERS.get(`steel_task:${taskId}`);
|
|
5542
|
+
} catch {
|
|
5543
|
+
return false;
|
|
5544
|
+
}
|
|
5545
|
+
if (!raw) return false;
|
|
5546
|
+
try {
|
|
5547
|
+
const task = JSON.parse(raw);
|
|
5548
|
+
return task.owner_sub !== void 0 && task.owner_sub === ctx.props.sub;
|
|
5549
|
+
} catch {
|
|
5550
|
+
return false;
|
|
5551
|
+
}
|
|
5552
|
+
}
|
|
5531
5553
|
function registerUiAgentAskTools(server2, ctx) {
|
|
5532
5554
|
server2.registerTool(
|
|
5533
5555
|
"ui_agent_reply",
|
|
@@ -5577,7 +5599,7 @@ function registerUiAgentAskTools(server2, ctx) {
|
|
|
5577
5599
|
}
|
|
5578
5600
|
const pendingKey = `${PENDING_ASK_PREFIX}${task_id}`;
|
|
5579
5601
|
const pendingRaw = await ctx.env.CARRIER_USERS.get(pendingKey);
|
|
5580
|
-
if (pendingRaw === null) {
|
|
5602
|
+
if (pendingRaw === null || !await callerOwnsTask(ctx, task_id)) {
|
|
5581
5603
|
return {
|
|
5582
5604
|
isError: true,
|
|
5583
5605
|
content: [
|
|
@@ -5719,6 +5741,8 @@ function registerUiAgentAskTools(server2, ctx) {
|
|
|
5719
5741
|
if (!raw) return null;
|
|
5720
5742
|
try {
|
|
5721
5743
|
const parsed = JSON.parse(raw);
|
|
5744
|
+
const taskId = parsed.task_id ?? name.slice(PENDING_ASK_PREFIX.length);
|
|
5745
|
+
if (!await callerOwnsTask(ctx, taskId)) return null;
|
|
5722
5746
|
return {
|
|
5723
5747
|
...parsed,
|
|
5724
5748
|
expires_at: computeExpiresAt(parsed.asked_at)
|
|
@@ -6696,6 +6720,33 @@ async function resolveBillingSub(env, orgId) {
|
|
|
6696
6720
|
return pointer ?? orgId;
|
|
6697
6721
|
}
|
|
6698
6722
|
|
|
6723
|
+
// src/scope-guard.ts
|
|
6724
|
+
function denyUnlessScoped(props2, toolName, scopes) {
|
|
6725
|
+
const required = scopes[toolName];
|
|
6726
|
+
if (required === void 0) {
|
|
6727
|
+
return {
|
|
6728
|
+
isError: true,
|
|
6729
|
+
content: [
|
|
6730
|
+
{
|
|
6731
|
+
type: "text",
|
|
6732
|
+
text: `Scope denied: tool '${toolName}' declares no scope, so it cannot be authorised. This is a server-side omission \u2014 add it to the tool's scope table.`
|
|
6733
|
+
}
|
|
6734
|
+
]
|
|
6735
|
+
};
|
|
6736
|
+
}
|
|
6737
|
+
const held = props2.scope ?? [];
|
|
6738
|
+
if (held.includes(required)) return null;
|
|
6739
|
+
return {
|
|
6740
|
+
isError: true,
|
|
6741
|
+
content: [
|
|
6742
|
+
{
|
|
6743
|
+
type: "text",
|
|
6744
|
+
text: `Scope denied: tool '${toolName}' requires '${required}' scope. Your token has: [${held.join(", ")}].`
|
|
6745
|
+
}
|
|
6746
|
+
]
|
|
6747
|
+
};
|
|
6748
|
+
}
|
|
6749
|
+
|
|
6699
6750
|
// src/wallet-tools.ts
|
|
6700
6751
|
var PACKS = [
|
|
6701
6752
|
{ id: "pack_500", eurCents: 5e4, bonusPct: 0 },
|
|
@@ -6892,6 +6943,8 @@ function registerWalletTools(server2, ctx) {
|
|
|
6892
6943
|
annotations: annotationsFor("wallet_balance", "read")
|
|
6893
6944
|
},
|
|
6894
6945
|
async () => {
|
|
6946
|
+
const denied = denyUnlessScoped(props2, "wallet_balance", WALLET_TOOL_SCOPES);
|
|
6947
|
+
if (denied) return denied;
|
|
6895
6948
|
const orgId = defaultOrgId;
|
|
6896
6949
|
const start = Date.now();
|
|
6897
6950
|
try {
|
|
@@ -6934,6 +6987,8 @@ function registerWalletTools(server2, ctx) {
|
|
|
6934
6987
|
annotations: annotationsFor("wallet_topup_checkout", "write")
|
|
6935
6988
|
},
|
|
6936
6989
|
async ({ pack }) => {
|
|
6990
|
+
const denied = denyUnlessScoped(props2, "wallet_topup_checkout", WALLET_TOOL_SCOPES);
|
|
6991
|
+
if (denied) return denied;
|
|
6937
6992
|
const orgId = defaultOrgId;
|
|
6938
6993
|
const start = Date.now();
|
|
6939
6994
|
if (!pack) {
|
|
@@ -6993,6 +7048,8 @@ function registerWalletTools(server2, ctx) {
|
|
|
6993
7048
|
annotations: annotationsFor("wallet_auto_topup", "write")
|
|
6994
7049
|
},
|
|
6995
7050
|
async ({ pack_cents }) => {
|
|
7051
|
+
const denied = denyUnlessScoped(props2, "wallet_auto_topup", WALLET_TOOL_SCOPES);
|
|
7052
|
+
if (denied) return denied;
|
|
6996
7053
|
const orgId = defaultOrgId;
|
|
6997
7054
|
const start = Date.now();
|
|
6998
7055
|
try {
|
|
@@ -7103,6 +7160,8 @@ function registerStripeConnectTools(server2, ctx) {
|
|
|
7103
7160
|
annotations: annotationsFor("stripe_connect_status", "read")
|
|
7104
7161
|
},
|
|
7105
7162
|
async ({ operator_id }) => {
|
|
7163
|
+
const denied = denyUnlessScoped(props2, "stripe_connect_status", STRIPE_CONNECT_TOOL_SCOPES);
|
|
7164
|
+
if (denied) return denied;
|
|
7106
7165
|
if (operator_id !== void 0 && operator_id !== operatorId) {
|
|
7107
7166
|
if (!isPlatformOperator(env, props2.org_id)) {
|
|
7108
7167
|
return err2(
|
|
@@ -7163,6 +7222,8 @@ function registerStripeConnectTools(server2, ctx) {
|
|
|
7163
7222
|
annotations: annotationsFor("stripe_connect_payouts", "read")
|
|
7164
7223
|
},
|
|
7165
7224
|
async ({ limit, status }) => {
|
|
7225
|
+
const denied = denyUnlessScoped(props2, "stripe_connect_payouts", STRIPE_CONNECT_TOOL_SCOPES);
|
|
7226
|
+
if (denied) return denied;
|
|
7166
7227
|
const start = Date.now();
|
|
7167
7228
|
try {
|
|
7168
7229
|
const stripeKey = env.STRIPE_SECRET_KEY;
|
|
@@ -7198,6 +7259,8 @@ function registerStripeConnectTools(server2, ctx) {
|
|
|
7198
7259
|
annotations: annotationsFor("stripe_connect_balance", "read")
|
|
7199
7260
|
},
|
|
7200
7261
|
async () => {
|
|
7262
|
+
const denied = denyUnlessScoped(props2, "stripe_connect_balance", STRIPE_CONNECT_TOOL_SCOPES);
|
|
7263
|
+
if (denied) return denied;
|
|
7201
7264
|
const start = Date.now();
|
|
7202
7265
|
try {
|
|
7203
7266
|
const stripeKey = env.STRIPE_SECRET_KEY;
|
|
@@ -7240,6 +7303,8 @@ function registerStripeConnectTools(server2, ctx) {
|
|
|
7240
7303
|
annotations: annotationsFor("stripe_connect_refund", "write")
|
|
7241
7304
|
},
|
|
7242
7305
|
async ({ charge_id, amount_cents, reason, confirm_token }) => {
|
|
7306
|
+
const denied = denyUnlessScoped(props2, "stripe_connect_refund", STRIPE_CONNECT_TOOL_SCOPES);
|
|
7307
|
+
if (denied) return denied;
|
|
7243
7308
|
const start = Date.now();
|
|
7244
7309
|
const toolName = "stripe_connect_refund";
|
|
7245
7310
|
if (!confirm_token) {
|
|
@@ -7292,6 +7357,8 @@ Call again with confirm_token="${token2}" to execute. Token expires in 5 minutes
|
|
|
7292
7357
|
annotations: annotationsFor("stripe_connect_dispute_list", "read")
|
|
7293
7358
|
},
|
|
7294
7359
|
async ({ limit, status }) => {
|
|
7360
|
+
const denied = denyUnlessScoped(props2, "stripe_connect_dispute_list", STRIPE_CONNECT_TOOL_SCOPES);
|
|
7361
|
+
if (denied) return denied;
|
|
7295
7362
|
const start = Date.now();
|
|
7296
7363
|
try {
|
|
7297
7364
|
const stripeKey = env.STRIPE_SECRET_KEY;
|
|
@@ -7330,6 +7397,13 @@ Call again with confirm_token="${token2}" to execute. Token expires in 5 minutes
|
|
|
7330
7397
|
annotations: annotationsFor("radar_review_list", "read")
|
|
7331
7398
|
},
|
|
7332
7399
|
async ({ open_only, limit }) => {
|
|
7400
|
+
const denied = denyUnlessScoped(props2, "radar_review_list", STRIPE_CONNECT_TOOL_SCOPES);
|
|
7401
|
+
if (denied) return denied;
|
|
7402
|
+
if (!isPlatformOperator(env, props2.org_id)) {
|
|
7403
|
+
return err2(
|
|
7404
|
+
"This tool acts on Carrier's platform Stripe account and is restricted to Carrier's own organization."
|
|
7405
|
+
);
|
|
7406
|
+
}
|
|
7333
7407
|
const start = Date.now();
|
|
7334
7408
|
try {
|
|
7335
7409
|
const stripeKey = env.STRIPE_SECRET_KEY;
|
|
@@ -7366,6 +7440,13 @@ Call again with confirm_token="${token2}" to execute. Token expires in 5 minutes
|
|
|
7366
7440
|
annotations: annotationsFor("radar_review_approve", "admin")
|
|
7367
7441
|
},
|
|
7368
7442
|
async ({ review_id, confirm_token }) => {
|
|
7443
|
+
const denied = denyUnlessScoped(props2, "radar_review_approve", STRIPE_CONNECT_TOOL_SCOPES);
|
|
7444
|
+
if (denied) return denied;
|
|
7445
|
+
if (!isPlatformOperator(env, props2.org_id)) {
|
|
7446
|
+
return err2(
|
|
7447
|
+
"This tool acts on Carrier's platform Stripe account and is restricted to Carrier's own organization."
|
|
7448
|
+
);
|
|
7449
|
+
}
|
|
7369
7450
|
const toolName = "radar_review_approve";
|
|
7370
7451
|
const start = Date.now();
|
|
7371
7452
|
if (!confirm_token) {
|
|
@@ -7415,6 +7496,13 @@ Call again with confirm_token="${token2}" to execute. Expires in 5 minutes.`
|
|
|
7415
7496
|
annotations: annotationsFor("radar_review_decline", "admin")
|
|
7416
7497
|
},
|
|
7417
7498
|
async ({ review_id, confirm_token }) => {
|
|
7499
|
+
const denied = denyUnlessScoped(props2, "radar_review_decline", STRIPE_CONNECT_TOOL_SCOPES);
|
|
7500
|
+
if (denied) return denied;
|
|
7501
|
+
if (!isPlatformOperator(env, props2.org_id)) {
|
|
7502
|
+
return err2(
|
|
7503
|
+
"This tool acts on Carrier's platform Stripe account and is restricted to Carrier's own organization."
|
|
7504
|
+
);
|
|
7505
|
+
}
|
|
7418
7506
|
const toolName = "radar_review_decline";
|
|
7419
7507
|
const start = Date.now();
|
|
7420
7508
|
if (!confirm_token) {
|
|
@@ -7465,6 +7553,13 @@ Expires in 5 minutes.`
|
|
|
7465
7553
|
annotations: annotationsFor("radar_value_list_add", "admin")
|
|
7466
7554
|
},
|
|
7467
7555
|
async ({ value_list_id, value, confirm_token }) => {
|
|
7556
|
+
const denied = denyUnlessScoped(props2, "radar_value_list_add", STRIPE_CONNECT_TOOL_SCOPES);
|
|
7557
|
+
if (denied) return denied;
|
|
7558
|
+
if (!isPlatformOperator(env, props2.org_id)) {
|
|
7559
|
+
return err2(
|
|
7560
|
+
"This tool acts on Carrier's platform Stripe account and is restricted to Carrier's own organization."
|
|
7561
|
+
);
|
|
7562
|
+
}
|
|
7468
7563
|
const toolName = "radar_value_list_add";
|
|
7469
7564
|
const start = Date.now();
|
|
7470
7565
|
if (!confirm_token) {
|
|
@@ -7514,6 +7609,13 @@ Expires in 5 minutes.`
|
|
|
7514
7609
|
annotations: annotationsFor("radar_rule_toggle", "admin")
|
|
7515
7610
|
},
|
|
7516
7611
|
async ({ rule_id, enabled }) => {
|
|
7612
|
+
const denied = denyUnlessScoped(props2, "radar_rule_toggle", STRIPE_CONNECT_TOOL_SCOPES);
|
|
7613
|
+
if (denied) return denied;
|
|
7614
|
+
if (!isPlatformOperator(env, props2.org_id)) {
|
|
7615
|
+
return err2(
|
|
7616
|
+
"This tool acts on Carrier's platform Stripe account and is restricted to Carrier's own organization."
|
|
7617
|
+
);
|
|
7618
|
+
}
|
|
7517
7619
|
return ok2(
|
|
7518
7620
|
`Stripe Radar does not expose rule enable/disable via the public API.
|
|
7519
7621
|
To ${enabled ? "enable" : "disable"} rule ${rule_id}:
|
|
@@ -10014,7 +10116,82 @@ function buildExamples(toolName) {
|
|
|
10014
10116
|
// src/list-recent-ocs-events.ts
|
|
10015
10117
|
import { z as z12 } from "zod";
|
|
10016
10118
|
|
|
10119
|
+
// src/ocs-scoping.ts
|
|
10120
|
+
function managedOwnAccountId(auth) {
|
|
10121
|
+
if (!auth.managed || auth.accountId === void 0) return void 0;
|
|
10122
|
+
const n = Number(auth.accountId);
|
|
10123
|
+
return Number.isFinite(n) ? n : void 0;
|
|
10124
|
+
}
|
|
10125
|
+
function subscriberAccountId(data) {
|
|
10126
|
+
if (!data || typeof data !== "object") return void 0;
|
|
10127
|
+
const root = data;
|
|
10128
|
+
const sub = root.subscriber && typeof root.subscriber === "object" ? root.subscriber : root;
|
|
10129
|
+
const raw = sub.accountId ?? sub.account_id ?? sub.account;
|
|
10130
|
+
if (raw === void 0 || raw === null) return void 0;
|
|
10131
|
+
const n = Number(raw);
|
|
10132
|
+
return Number.isFinite(n) ? n : void 0;
|
|
10133
|
+
}
|
|
10134
|
+
function isManagedSubscriberDenied(auth, subscriberData) {
|
|
10135
|
+
const ownId = managedOwnAccountId(auth);
|
|
10136
|
+
if (ownId === void 0) return false;
|
|
10137
|
+
const subAccountId = subscriberAccountId(subscriberData);
|
|
10138
|
+
if (subAccountId === void 0) return true;
|
|
10139
|
+
return subAccountId !== ownId;
|
|
10140
|
+
}
|
|
10141
|
+
async function assertManagedIccidAccess(baseUrl2, auth, iccid) {
|
|
10142
|
+
if (managedOwnAccountId(auth) === void 0) return { ok: true };
|
|
10143
|
+
try {
|
|
10144
|
+
const client2 = new OcsClient(baseUrl2, auth.token);
|
|
10145
|
+
const data = await client2.call("getSingleSubscriber", { iccid });
|
|
10146
|
+
if (isManagedSubscriberDenied(auth, data)) {
|
|
10147
|
+
return { ok: false, error: "Subscriber not found" };
|
|
10148
|
+
}
|
|
10149
|
+
return { ok: true };
|
|
10150
|
+
} catch (err7) {
|
|
10151
|
+
return {
|
|
10152
|
+
ok: false,
|
|
10153
|
+
error: err7 instanceof Error ? err7.message : String(err7)
|
|
10154
|
+
};
|
|
10155
|
+
}
|
|
10156
|
+
}
|
|
10157
|
+
|
|
10017
10158
|
// ../../packages/ocs-spec/src/ocs-event-buffer-read.ts
|
|
10159
|
+
function ocsEventRingBufferIccidFromDigitsReference(raw) {
|
|
10160
|
+
const digits = raw.replace(/\D/g, "");
|
|
10161
|
+
if (digits.length === 0) {
|
|
10162
|
+
throw new Error("reference must contain at least one digit");
|
|
10163
|
+
}
|
|
10164
|
+
if (digits.length > 20) {
|
|
10165
|
+
return digits.slice(-20);
|
|
10166
|
+
}
|
|
10167
|
+
if (digits.length >= 19) {
|
|
10168
|
+
return digits;
|
|
10169
|
+
}
|
|
10170
|
+
return digits.padStart(19, "0");
|
|
10171
|
+
}
|
|
10172
|
+
function msisdnFieldFromSubscriberPayload(data) {
|
|
10173
|
+
if (!data || typeof data !== "object") return null;
|
|
10174
|
+
const r = data;
|
|
10175
|
+
const v = r["msisdn"] ?? r["MSISDN"];
|
|
10176
|
+
if (v === void 0 || v === null) return null;
|
|
10177
|
+
if (typeof v === "string") return /\d/.test(v) ? v : null;
|
|
10178
|
+
if (typeof v === "number") return String(v);
|
|
10179
|
+
return null;
|
|
10180
|
+
}
|
|
10181
|
+
function mergeOcsEventOutputsNewestFirst(parts, limit) {
|
|
10182
|
+
const seen = /* @__PURE__ */ new Set();
|
|
10183
|
+
const out = [];
|
|
10184
|
+
const combined = [...parts].flat().sort(
|
|
10185
|
+
(x, y) => x.timestamp < y.timestamp ? 1 : x.timestamp > y.timestamp ? -1 : x.event_id.localeCompare(y.event_id)
|
|
10186
|
+
);
|
|
10187
|
+
for (const e of combined) {
|
|
10188
|
+
if (seen.has(e.event_id)) continue;
|
|
10189
|
+
seen.add(e.event_id);
|
|
10190
|
+
out.push(e);
|
|
10191
|
+
if (out.length >= limit) break;
|
|
10192
|
+
}
|
|
10193
|
+
return out;
|
|
10194
|
+
}
|
|
10018
10195
|
async function listRecentOcsEvents(iccid, limit, eventTypes, since, kv) {
|
|
10019
10196
|
const routingRaw = await kv.get(`iccid:${iccid}`, "json");
|
|
10020
10197
|
const resellerId = routingRaw?.reseller_id ?? 0;
|
|
@@ -10097,7 +10274,8 @@ var listRecentOcsEventsSchema = {
|
|
|
10097
10274
|
async function listRecentOcsEvents2(iccid, limit, eventTypes, since, kv) {
|
|
10098
10275
|
return listRecentOcsEvents(iccid, limit, eventTypes, since, kv);
|
|
10099
10276
|
}
|
|
10100
|
-
function registerListRecentOcsEventsTool(server2,
|
|
10277
|
+
function registerListRecentOcsEventsTool(server2, ctx) {
|
|
10278
|
+
const env = ctx.env;
|
|
10101
10279
|
server2.registerTool(
|
|
10102
10280
|
"list_recent_ocs_events",
|
|
10103
10281
|
{
|
|
@@ -10113,6 +10291,19 @@ function registerListRecentOcsEventsTool(server2, env) {
|
|
|
10113
10291
|
async (args) => {
|
|
10114
10292
|
const { iccid, limit, event_types, since } = args;
|
|
10115
10293
|
try {
|
|
10294
|
+
if (managedOwnAccountId(ctx.managedAuth) !== void 0) {
|
|
10295
|
+
const access = await assertManagedIccidAccess(
|
|
10296
|
+
env.CARRIER_OCS_BASE_URL,
|
|
10297
|
+
{ token: await ctx.getUserToken(ctx.props.sub), ...ctx.managedAuth },
|
|
10298
|
+
iccid
|
|
10299
|
+
);
|
|
10300
|
+
if (!access.ok) {
|
|
10301
|
+
return {
|
|
10302
|
+
isError: true,
|
|
10303
|
+
content: [{ type: "text", text: access.error }]
|
|
10304
|
+
};
|
|
10305
|
+
}
|
|
10306
|
+
}
|
|
10116
10307
|
const result2 = await listRecentOcsEvents2(
|
|
10117
10308
|
iccid,
|
|
10118
10309
|
limit,
|
|
@@ -10230,6 +10421,20 @@ function ok5(payload) {
|
|
|
10230
10421
|
function err5(message) {
|
|
10231
10422
|
return { isError: true, content: [{ type: "text", text: message }] };
|
|
10232
10423
|
}
|
|
10424
|
+
async function ownershipToken(ctx) {
|
|
10425
|
+
if (managedOwnAccountId(ctx.managedAuth) === void 0) return null;
|
|
10426
|
+
return ctx.getUserToken(ctx.props.sub);
|
|
10427
|
+
}
|
|
10428
|
+
async function ownsEvent(ctx, token2, iccid) {
|
|
10429
|
+
if (token2 === null) return true;
|
|
10430
|
+
if (!iccid) return false;
|
|
10431
|
+
const access = await assertManagedIccidAccess(
|
|
10432
|
+
ctx.env.CARRIER_OCS_BASE_URL,
|
|
10433
|
+
{ token: token2, ...ctx.managedAuth },
|
|
10434
|
+
iccid
|
|
10435
|
+
);
|
|
10436
|
+
return access.ok;
|
|
10437
|
+
}
|
|
10233
10438
|
function registerDepletionEventsTool(server2, ctx) {
|
|
10234
10439
|
server2.registerTool(
|
|
10235
10440
|
"subscriber_depletion_events",
|
|
@@ -10259,6 +10464,14 @@ function registerDepletionEventsTool(server2, ctx) {
|
|
|
10259
10464
|
);
|
|
10260
10465
|
}
|
|
10261
10466
|
const { subscriberId, since } = args;
|
|
10467
|
+
let scopeToken;
|
|
10468
|
+
try {
|
|
10469
|
+
scopeToken = await ownershipToken(ctx);
|
|
10470
|
+
} catch (e) {
|
|
10471
|
+
return err5(
|
|
10472
|
+
`Could not resolve the OCS credential needed to scope this read: ${e instanceof Error ? e.message : String(e)}`
|
|
10473
|
+
);
|
|
10474
|
+
}
|
|
10262
10475
|
if (subscriberId) {
|
|
10263
10476
|
const raw = await kv.get(`bundle-depleted:${subscriberId}`, "text");
|
|
10264
10477
|
if (!raw) {
|
|
@@ -10280,6 +10493,14 @@ function registerDepletionEventsTool(server2, ctx) {
|
|
|
10280
10493
|
note: "Stored depletion entry was invalid JSON and was ignored."
|
|
10281
10494
|
});
|
|
10282
10495
|
}
|
|
10496
|
+
if (!await ownsEvent(ctx, scopeToken, event.iccid)) {
|
|
10497
|
+
return ok5({
|
|
10498
|
+
subscriber_id: subscriberId,
|
|
10499
|
+
depleted: false,
|
|
10500
|
+
event: null,
|
|
10501
|
+
note: "No bundle depletion event found in the last 7 days."
|
|
10502
|
+
});
|
|
10503
|
+
}
|
|
10283
10504
|
if (since && event.depletedAt < since) {
|
|
10284
10505
|
return ok5({
|
|
10285
10506
|
subscriber_id: subscriberId,
|
|
@@ -10316,6 +10537,7 @@ function registerDepletionEventsTool(server2, ctx) {
|
|
|
10316
10537
|
try {
|
|
10317
10538
|
const ev = JSON.parse(raw);
|
|
10318
10539
|
if (since && ev.depletedAt < since) return;
|
|
10540
|
+
if (!await ownsEvent(ctx, scopeToken, ev.iccid)) return;
|
|
10319
10541
|
events.push({
|
|
10320
10542
|
subscriber_id: ev.subscriberId,
|
|
10321
10543
|
iccid: ev.iccid,
|
|
@@ -10353,19 +10575,46 @@ function registerCountryHistoryTool(server2, ctx) {
|
|
|
10353
10575
|
},
|
|
10354
10576
|
wrapHandler(
|
|
10355
10577
|
"subscriber_country_history",
|
|
10356
|
-
"
|
|
10578
|
+
"getSingleSubscriber",
|
|
10357
10579
|
"read",
|
|
10358
10580
|
ctx,
|
|
10359
|
-
async ({ subscriberId, limit }) => {
|
|
10581
|
+
async ({ subscriberId, limit }, token2) => {
|
|
10360
10582
|
const effectiveLimit = limit ?? 20;
|
|
10361
|
-
const
|
|
10583
|
+
const client2 = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
|
|
10584
|
+
const subscriberPayload = await client2.call("getSingleSubscriber", {
|
|
10585
|
+
iccid: subscriberId
|
|
10586
|
+
});
|
|
10587
|
+
let syntheticRingIccid = null;
|
|
10588
|
+
const msisdnRaw = msisdnFieldFromSubscriberPayload(subscriberPayload);
|
|
10589
|
+
if (msisdnRaw) {
|
|
10590
|
+
try {
|
|
10591
|
+
const k = ocsEventRingBufferIccidFromDigitsReference(msisdnRaw);
|
|
10592
|
+
if (k !== subscriberId) syntheticRingIccid = k;
|
|
10593
|
+
} catch {
|
|
10594
|
+
syntheticRingIccid = null;
|
|
10595
|
+
}
|
|
10596
|
+
}
|
|
10597
|
+
const primary = await listRecentOcsEvents(
|
|
10362
10598
|
subscriberId,
|
|
10363
10599
|
effectiveLimit,
|
|
10364
10600
|
["country.entered"],
|
|
10365
10601
|
void 0,
|
|
10366
10602
|
ctx.env.OCS_EVENT_ROUTING
|
|
10367
10603
|
);
|
|
10368
|
-
|
|
10604
|
+
let countryEvents = primary.events;
|
|
10605
|
+
if (syntheticRingIccid) {
|
|
10606
|
+
const secondary = await listRecentOcsEvents(
|
|
10607
|
+
syntheticRingIccid,
|
|
10608
|
+
effectiveLimit,
|
|
10609
|
+
["country.entered"],
|
|
10610
|
+
void 0,
|
|
10611
|
+
ctx.env.OCS_EVENT_ROUTING
|
|
10612
|
+
);
|
|
10613
|
+
countryEvents = mergeOcsEventOutputsNewestFirst(
|
|
10614
|
+
[primary.events, secondary.events],
|
|
10615
|
+
effectiveLimit
|
|
10616
|
+
);
|
|
10617
|
+
}
|
|
10369
10618
|
return {
|
|
10370
10619
|
content: [
|
|
10371
10620
|
{
|
|
@@ -10383,7 +10632,7 @@ function registerCountryHistoryTool(server2, ctx) {
|
|
|
10383
10632
|
source: e.data["source"] ?? "relay-lu"
|
|
10384
10633
|
})),
|
|
10385
10634
|
total_country_events: countryEvents.length,
|
|
10386
|
-
total_in_buffer:
|
|
10635
|
+
total_in_buffer: primary.total_in_buffer,
|
|
10387
10636
|
note: countryEvents.length === 0 ? "No cross-border events recorded in the 24h ring-buffer for this subscriber." : void 0
|
|
10388
10637
|
},
|
|
10389
10638
|
null,
|
|
@@ -11949,7 +12198,13 @@ var props = {
|
|
|
11949
12198
|
var audit = (_row) => {
|
|
11950
12199
|
};
|
|
11951
12200
|
var getUserToken = async (_sub) => token;
|
|
11952
|
-
var toolCtx = {
|
|
12201
|
+
var toolCtx = {
|
|
12202
|
+
env: stdioEnv,
|
|
12203
|
+
props,
|
|
12204
|
+
managedAuth: {},
|
|
12205
|
+
audit,
|
|
12206
|
+
getUserToken
|
|
12207
|
+
};
|
|
11953
12208
|
var server = new McpServer(
|
|
11954
12209
|
{ name: "carrier-mcp", version: CARRIER_VERSION },
|
|
11955
12210
|
{
|
|
@@ -11961,7 +12216,7 @@ registerAllTools(server, toolCtx);
|
|
|
11961
12216
|
registerIntelligenceTools(server, toolCtx);
|
|
11962
12217
|
registerAllBacklogTools(server, toolCtx);
|
|
11963
12218
|
registerAllCarrierAskTools(server, toolCtx);
|
|
11964
|
-
registerListRecentOcsEventsTool(server,
|
|
12219
|
+
registerListRecentOcsEventsTool(server, toolCtx);
|
|
11965
12220
|
registerRateLimitStatusTool(server, toolCtx);
|
|
11966
12221
|
registerCountryHistoryTool(server, toolCtx);
|
|
11967
12222
|
registerDepletionEventsTool(server, toolCtx);
|