@kaminari-ad/mcp 0.3.0 → 0.5.0
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/CHANGELOG.md +73 -0
- package/README.md +27 -0
- package/dist/bin.js +48 -5
- package/dist/bin.js.map +1 -1
- package/dist/{chunk-W7TPFRJB.js → chunk-6FT6HKOB.js} +165 -36
- package/dist/chunk-6FT6HKOB.js.map +1 -0
- package/dist/{chunk-KTQBHJUB.js → chunk-PG5IDZWQ.js} +3 -3
- package/dist/{chunk-KTQBHJUB.js.map → chunk-PG5IDZWQ.js.map} +1 -1
- package/dist/{http-bootstrap-FGGCFLRU.js → http-bootstrap-N64P6LER.js} +45 -6
- package/dist/http-bootstrap-N64P6LER.js.map +1 -0
- package/dist/{stdio-bootstrap-RBANZT6F.js → stdio-bootstrap-IJKGS6IL.js} +8 -5
- package/dist/stdio-bootstrap-IJKGS6IL.js.map +1 -0
- package/package.json +5 -1
- package/dist/chunk-W7TPFRJB.js.map +0 -1
- package/dist/http-bootstrap-FGGCFLRU.js.map +0 -1
- package/dist/stdio-bootstrap-RBANZT6F.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { err, ok } from './chunk-
|
|
2
|
+
import { err, ok } from './chunk-PG5IDZWQ.js';
|
|
3
3
|
import { createHash, randomUUID } from 'crypto';
|
|
4
4
|
import createClient from 'openapi-fetch';
|
|
5
5
|
import { fetch } from 'undici';
|
|
@@ -332,6 +332,8 @@ var ScanResponse = z.object({
|
|
|
332
332
|
offer_url: z.string(),
|
|
333
333
|
redirect_chain: z.array(RedirectHopResponse),
|
|
334
334
|
screenshot_url: z.string().optional().default(""),
|
|
335
|
+
report_url: z.string().optional().default(""),
|
|
336
|
+
public_report_url: z.string().optional().default(""),
|
|
335
337
|
ad_tag: z.union([z.string(), z.null()]).optional(),
|
|
336
338
|
creative_screenshot_url: z.string().optional().default(""),
|
|
337
339
|
creative_width: z.number().int().optional().default(0),
|
|
@@ -357,6 +359,8 @@ var ScanBriefResponse = z.object({
|
|
|
357
359
|
status: ScanStatus,
|
|
358
360
|
offer_url: z.string(),
|
|
359
361
|
screenshot_url: z.string().optional().default(""),
|
|
362
|
+
report_url: z.string().optional().default(""),
|
|
363
|
+
public_report_url: z.string().optional().default(""),
|
|
360
364
|
labels: z.record(z.string()).optional(),
|
|
361
365
|
classification: z.union([ScanClassificationResponse, z.null()]).optional(),
|
|
362
366
|
elapsed_ms: z.number().int(),
|
|
@@ -533,6 +537,8 @@ var ScanTileResponse = z.object({
|
|
|
533
537
|
status: z.string(),
|
|
534
538
|
offer_url: z.string().optional().default(""),
|
|
535
539
|
screenshot_url: z.string().optional().default(""),
|
|
540
|
+
report_url: z.string().optional().default(""),
|
|
541
|
+
public_report_url: z.string().optional().default(""),
|
|
536
542
|
elapsed_ms: z.number().int().optional().default(0),
|
|
537
543
|
error: z.string().optional().default("")
|
|
538
544
|
}).passthrough();
|
|
@@ -1201,7 +1207,13 @@ var BillingSummarySchema = schemas.BillingSummaryResponse.pick({
|
|
|
1201
1207
|
is_suspended: true,
|
|
1202
1208
|
can_create_scan: true,
|
|
1203
1209
|
billing_mode: true,
|
|
1204
|
-
block_reason: true
|
|
1210
|
+
block_reason: true,
|
|
1211
|
+
current_plan_is_custom: true,
|
|
1212
|
+
credit_limit_micros: true,
|
|
1213
|
+
effective_minimum_balance_micros: true,
|
|
1214
|
+
scheduled_next_plan_id: true,
|
|
1215
|
+
scheduled_next_plan_name: true,
|
|
1216
|
+
scheduled_effective_at: true
|
|
1205
1217
|
}).strip();
|
|
1206
1218
|
var parseBillingSummary = (raw) => parseWithSchema(BillingSummarySchema, raw, "billing-summary");
|
|
1207
1219
|
|
|
@@ -1214,10 +1226,18 @@ var CampaignSchema = schemas.CampaignResponse.pick({
|
|
|
1214
1226
|
ad_tag: true,
|
|
1215
1227
|
country_codes: true,
|
|
1216
1228
|
group_id: true,
|
|
1229
|
+
emulator_selection: true,
|
|
1230
|
+
proxy_type: true,
|
|
1231
|
+
proxy_region: true,
|
|
1232
|
+
proxy_city: true,
|
|
1233
|
+
proxy_isp: true,
|
|
1217
1234
|
labels: true,
|
|
1218
1235
|
policy_set_id: true,
|
|
1219
1236
|
schedule_enabled: true,
|
|
1220
1237
|
schedule_type: true,
|
|
1238
|
+
schedule_weekly: true,
|
|
1239
|
+
schedule_interval_seconds: true,
|
|
1240
|
+
schedule_timezone: true,
|
|
1221
1241
|
is_archived: true,
|
|
1222
1242
|
created_at: true,
|
|
1223
1243
|
last_run_at: true
|
|
@@ -1390,6 +1410,7 @@ var UserSchema = schemas.UserResponse.pick({
|
|
|
1390
1410
|
id: true,
|
|
1391
1411
|
email: true,
|
|
1392
1412
|
name: true,
|
|
1413
|
+
role_id: true,
|
|
1393
1414
|
role_name: true,
|
|
1394
1415
|
is_active: true,
|
|
1395
1416
|
created_at: true
|
|
@@ -1615,6 +1636,8 @@ var ScanTileSchema = schemas.ScanTileResponse.pick({
|
|
|
1615
1636
|
status: true,
|
|
1616
1637
|
offer_url: true,
|
|
1617
1638
|
screenshot_url: true,
|
|
1639
|
+
report_url: true,
|
|
1640
|
+
public_report_url: true,
|
|
1618
1641
|
elapsed_ms: true,
|
|
1619
1642
|
error: true
|
|
1620
1643
|
}).strip();
|
|
@@ -1627,6 +1650,8 @@ var ScanSchema = schemas.ScanResponse.pick({
|
|
|
1627
1650
|
status: true,
|
|
1628
1651
|
offer_url: true,
|
|
1629
1652
|
screenshot_url: true,
|
|
1653
|
+
report_url: true,
|
|
1654
|
+
public_report_url: true,
|
|
1630
1655
|
ad_tag: true,
|
|
1631
1656
|
creative_screenshot_url: true,
|
|
1632
1657
|
page_title: true,
|
|
@@ -1650,6 +1675,8 @@ var ScanBriefSchema = schemas.ScanBriefResponse.pick({
|
|
|
1650
1675
|
status: true,
|
|
1651
1676
|
offer_url: true,
|
|
1652
1677
|
screenshot_url: true,
|
|
1678
|
+
report_url: true,
|
|
1679
|
+
public_report_url: true,
|
|
1653
1680
|
labels: true,
|
|
1654
1681
|
elapsed_ms: true,
|
|
1655
1682
|
campaign_id: true,
|
|
@@ -2519,6 +2546,18 @@ function wrap(impl) {
|
|
|
2519
2546
|
}
|
|
2520
2547
|
};
|
|
2521
2548
|
}
|
|
2549
|
+
|
|
2550
|
+
// src/shared/server-instructions.ts
|
|
2551
|
+
var SERVER_INSTRUCTIONS = [
|
|
2552
|
+
"Kaminari Ad \u2014 ad-verification API (malvertising, scams, policy violations).",
|
|
2553
|
+
"",
|
|
2554
|
+
"Linking to a scan: use the URL fields the tools return \u2014 never build or guess them.",
|
|
2555
|
+
"- `report_url`: authenticated dashboard report (requires login).",
|
|
2556
|
+
"- `public_report_url`: shareable report (no login).",
|
|
2557
|
+
"- `screenshot_url` / `creative_screenshot_url`: absolute, directly followable.",
|
|
2558
|
+
"These come from `get_scan`, `list_scans`, and `list_run_scans`. Do NOT assemble",
|
|
2559
|
+
"scan/app URLs from a base host yourself \u2014 the apex domain does not serve scan pages."
|
|
2560
|
+
].join("\n");
|
|
2522
2561
|
function declareEmptyResourcesAndPrompts(server) {
|
|
2523
2562
|
server.server.registerCapabilities({ resources: {}, prompts: {} });
|
|
2524
2563
|
server.server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
@@ -2637,7 +2676,8 @@ var getAccountTool = {
|
|
|
2637
2676
|
var InviteUserInputShape = {
|
|
2638
2677
|
email: z.string().email().describe("Email of the person to invite. They get a signup link."),
|
|
2639
2678
|
role_id: z.string().uuid().describe("UUID of the role to assign on accept. Get UUIDs from `list_org_roles`."),
|
|
2640
|
-
name: z.string().min(1).optional().describe("Optional display name for the invitee.")
|
|
2679
|
+
name: z.string().min(1).optional().describe("Optional display name for the invitee."),
|
|
2680
|
+
timezone: z.string().optional().describe("Optional IANA timezone for the invitee, e.g. 'Europe/Berlin'. Default: UTC.")
|
|
2641
2681
|
};
|
|
2642
2682
|
var inviteUserTool = {
|
|
2643
2683
|
name: "invite_user",
|
|
@@ -2656,6 +2696,7 @@ var inviteUserTool = {
|
|
|
2656
2696
|
role_id: input.role_id
|
|
2657
2697
|
};
|
|
2658
2698
|
if (input.name !== void 0) body.name = input.name;
|
|
2699
|
+
if (input.timezone !== void 0) body.timezone = input.timezone;
|
|
2659
2700
|
const result = await ctx.api.inviteUser(body);
|
|
2660
2701
|
if (result.isErr()) return err(mapApiError(result.error));
|
|
2661
2702
|
return ok(result.value);
|
|
@@ -2833,12 +2874,11 @@ var updateAccountLabelsTool = {
|
|
|
2833
2874
|
}
|
|
2834
2875
|
};
|
|
2835
2876
|
var UpdateOrgInputShape = {
|
|
2836
|
-
name: z.string().min(1).max(200).optional().describe("New organization display name.")
|
|
2837
|
-
settings: z.record(z.unknown()).optional().describe("Replacement settings object. Fields not supplied are left unchanged.")
|
|
2877
|
+
name: z.string().min(1).max(200).optional().describe("New organization display name.")
|
|
2838
2878
|
};
|
|
2839
2879
|
var updateOrgTool = {
|
|
2840
2880
|
name: "update_org",
|
|
2841
|
-
description: "Update the caller's organization
|
|
2881
|
+
description: "Update the caller's organization display name.",
|
|
2842
2882
|
annotations: {
|
|
2843
2883
|
title: "Update Organization",
|
|
2844
2884
|
readOnlyHint: false,
|
|
@@ -2849,8 +2889,7 @@ var updateOrgTool = {
|
|
|
2849
2889
|
inputSchema: z.object(UpdateOrgInputShape),
|
|
2850
2890
|
handler: async (input, ctx) => {
|
|
2851
2891
|
const body = {
|
|
2852
|
-
...input.name !== void 0 ? { name: input.name } : {}
|
|
2853
|
-
...input.settings !== void 0 ? { settings: input.settings } : {}
|
|
2892
|
+
...input.name !== void 0 ? { name: input.name } : {}
|
|
2854
2893
|
};
|
|
2855
2894
|
const result = await ctx.api.updateOrg(body);
|
|
2856
2895
|
if (result.isErr()) return err(mapApiError(result.error));
|
|
@@ -3356,12 +3395,11 @@ var unarchiveCampaignGroupTool = {
|
|
|
3356
3395
|
};
|
|
3357
3396
|
var UpdateCampaignGroupInputShape = {
|
|
3358
3397
|
group_id: z.string().uuid().describe("Group UUID to update."),
|
|
3359
|
-
name: z.string().min(1).max(200).optional().describe("New display name.")
|
|
3360
|
-
schedule_paused: z.boolean().optional().describe("Pause/resume the scheduler for every campaign in this group.")
|
|
3398
|
+
name: z.string().min(1).max(200).optional().describe("New display name.")
|
|
3361
3399
|
};
|
|
3362
3400
|
var updateCampaignGroupTool = {
|
|
3363
3401
|
name: "update_campaign_group",
|
|
3364
|
-
description: "
|
|
3402
|
+
description: "Rename a campaign group. To pause/resume its scheduler, use `pause_campaign_group_schedule` / `resume_campaign_group_schedule` instead.",
|
|
3365
3403
|
annotations: {
|
|
3366
3404
|
title: "Update Campaign Group",
|
|
3367
3405
|
readOnlyHint: false,
|
|
@@ -3372,8 +3410,7 @@ var updateCampaignGroupTool = {
|
|
|
3372
3410
|
inputSchema: z.object(UpdateCampaignGroupInputShape),
|
|
3373
3411
|
handler: async (input, ctx) => {
|
|
3374
3412
|
const body = {
|
|
3375
|
-
...input.name !== void 0 ? { name: input.name } : {}
|
|
3376
|
-
...input.schedule_paused !== void 0 ? { schedule_paused: input.schedule_paused } : {}
|
|
3413
|
+
...input.name !== void 0 ? { name: input.name } : {}
|
|
3377
3414
|
};
|
|
3378
3415
|
const result = await ctx.api.updateCampaignGroup(input.group_id, body);
|
|
3379
3416
|
if (result.isErr()) return err(mapApiError(result.error));
|
|
@@ -3420,6 +3457,52 @@ var cancelCampaignTool = {
|
|
|
3420
3457
|
return ok(result.value);
|
|
3421
3458
|
}
|
|
3422
3459
|
};
|
|
3460
|
+
var campaignConfigFields = {
|
|
3461
|
+
emulator_categories: z.array(z.string()).optional().describe(
|
|
3462
|
+
"Device categories to rotate through, e.g. ['android_phone']. Valid: android_phone, android_tablet, iphone, ipad, windows_desktop, macos_desktop. On create, omitting this defaults to ['android_phone']; pass [] together with emulator_specific_ids to target ONLY specific devices."
|
|
3463
|
+
),
|
|
3464
|
+
emulator_specific_ids: z.array(z.string()).optional().describe(
|
|
3465
|
+
"Pin exact device profile slugs from `list_emulators` (the `id` field), e.g. ['samsung_galaxy_s23_ultra_android16']. Always scanned regardless of emulator_mode."
|
|
3466
|
+
),
|
|
3467
|
+
emulator_mode: z.enum(["random", "all"]).optional().describe(
|
|
3468
|
+
"How selected categories expand per run: 'random' = one random device per category (the UI's 'Random (1 per group)'), 'all' = every device in each category ('All checked'). Does not affect emulator_specific_ids. Default: random."
|
|
3469
|
+
),
|
|
3470
|
+
proxy_type: z.enum(["residential", "mobile"]).optional().describe("Proxy network type. Default: residential."),
|
|
3471
|
+
proxy_region: z.string().optional().describe("Proxy region/state targeting (free-text; only honoured for a single country)."),
|
|
3472
|
+
proxy_city: z.string().optional().describe("Proxy city targeting."),
|
|
3473
|
+
proxy_isp: z.string().optional().describe("Proxy ISP targeting."),
|
|
3474
|
+
schedule_type: z.enum(["weekly", "interval"]).optional().describe(
|
|
3475
|
+
"Scheduling mode: 'weekly' (run on a weekday/hour grid via schedule_weekly) or 'interval' (run every schedule_interval_seconds). Omit for a manual (run-on-demand) campaign."
|
|
3476
|
+
),
|
|
3477
|
+
schedule_weekly: z.record(z.array(z.number().int().min(0).max(23))).optional().describe(
|
|
3478
|
+
"Weekly run grid for schedule_type='weekly'. Keys are weekdays '0'-'6' (Mon-Sun); values are hours 0-23 in schedule_timezone, e.g. { '0': [9, 17], '4': [12] }."
|
|
3479
|
+
),
|
|
3480
|
+
schedule_interval_seconds: z.number().int().optional().describe(
|
|
3481
|
+
"Run interval for schedule_type='interval'. Allowed presets (seconds): 60, 120, 300, 600, 900, 1800, 2700, 3600, 7200, 14400, 28800, 86400."
|
|
3482
|
+
),
|
|
3483
|
+
schedule_timezone: z.string().optional().describe("IANA timezone for the weekly grid, e.g. 'Europe/Berlin'. Default: UTC.")
|
|
3484
|
+
};
|
|
3485
|
+
function pickCampaignConfigBody(input) {
|
|
3486
|
+
const body = {};
|
|
3487
|
+
if (input.emulator_categories !== void 0) body.emulator_categories = input.emulator_categories;
|
|
3488
|
+
if (input.emulator_specific_ids !== void 0) {
|
|
3489
|
+
body.emulator_specific_ids = input.emulator_specific_ids;
|
|
3490
|
+
}
|
|
3491
|
+
if (input.emulator_mode !== void 0) body.emulator_mode = input.emulator_mode;
|
|
3492
|
+
if (input.proxy_type !== void 0) body.proxy_type = input.proxy_type;
|
|
3493
|
+
if (input.proxy_region !== void 0) body.proxy_region = input.proxy_region;
|
|
3494
|
+
if (input.proxy_city !== void 0) body.proxy_city = input.proxy_city;
|
|
3495
|
+
if (input.proxy_isp !== void 0) body.proxy_isp = input.proxy_isp;
|
|
3496
|
+
if (input.schedule_type !== void 0) body.schedule_type = input.schedule_type;
|
|
3497
|
+
if (input.schedule_weekly !== void 0) body.schedule_weekly = input.schedule_weekly;
|
|
3498
|
+
if (input.schedule_interval_seconds !== void 0) {
|
|
3499
|
+
body.schedule_interval_seconds = input.schedule_interval_seconds;
|
|
3500
|
+
}
|
|
3501
|
+
if (input.schedule_timezone !== void 0) body.schedule_timezone = input.schedule_timezone;
|
|
3502
|
+
return body;
|
|
3503
|
+
}
|
|
3504
|
+
|
|
3505
|
+
// src/application/tools/campaigns/create-campaign.tool.ts
|
|
3423
3506
|
var CreateCampaignInputShape = {
|
|
3424
3507
|
name: z.string().min(1).max(200).describe("Display name (1-200 chars)."),
|
|
3425
3508
|
campaign_type: z.enum(["url", "ad_tag"]).describe("`url` or `ad_tag` \u2014 must match the target field below."),
|
|
@@ -3427,7 +3510,7 @@ var CreateCampaignInputShape = {
|
|
|
3427
3510
|
ad_tag: z.string().optional().describe("Ad-tag HTML/JS (required if campaign_type=ad_tag)."),
|
|
3428
3511
|
country_codes: z.array(z.string().length(2)).min(1).describe("ISO 3166-1 alpha-2 codes \u2014 one scan per country per run."),
|
|
3429
3512
|
group_id: z.string().uuid().optional().describe("Parent group UUID; defaults to the org's default group."),
|
|
3430
|
-
|
|
3513
|
+
...campaignConfigFields,
|
|
3431
3514
|
labels: z.record(z.string()).optional().describe("Arbitrary metadata applied to every queued scan."),
|
|
3432
3515
|
policy_set_id: z.string().uuid().optional().describe("Policy set to evaluate every scan against."),
|
|
3433
3516
|
schedule_enabled: z.boolean().optional().describe("If true, the scheduler runs immediately. Default: false (manual run).")
|
|
@@ -3451,10 +3534,10 @@ var createCampaignTool = {
|
|
|
3451
3534
|
...input.url !== void 0 ? { url: input.url } : {},
|
|
3452
3535
|
...input.ad_tag !== void 0 ? { ad_tag: input.ad_tag } : {},
|
|
3453
3536
|
...input.group_id !== void 0 ? { group_id: input.group_id } : {},
|
|
3454
|
-
...input.emulator_categories !== void 0 ? { emulator_categories: input.emulator_categories } : {},
|
|
3455
3537
|
...input.labels !== void 0 ? { labels: input.labels } : {},
|
|
3456
3538
|
...input.policy_set_id !== void 0 ? { policy_set_id: input.policy_set_id } : {},
|
|
3457
|
-
...input.schedule_enabled !== void 0 ? { schedule_enabled: input.schedule_enabled } : {}
|
|
3539
|
+
...input.schedule_enabled !== void 0 ? { schedule_enabled: input.schedule_enabled } : {},
|
|
3540
|
+
...pickCampaignConfigBody(input)
|
|
3458
3541
|
};
|
|
3459
3542
|
const result = await ctx.api.createCampaign(body);
|
|
3460
3543
|
if (result.isErr()) return err(mapApiError(result.error));
|
|
@@ -3613,7 +3696,11 @@ var unarchiveCampaignTool = {
|
|
|
3613
3696
|
var UpdateCampaignInputShape = {
|
|
3614
3697
|
campaign_id: z.string().uuid().describe("Campaign UUID to update."),
|
|
3615
3698
|
name: z.string().min(1).max(200).optional().describe("New display name."),
|
|
3699
|
+
url: z.string().url().optional().describe("New target URL (url-type campaigns)."),
|
|
3700
|
+
ad_tag: z.string().optional().describe("New ad-tag HTML/JS (ad_tag-type campaigns)."),
|
|
3616
3701
|
country_codes: z.array(z.string().length(2)).optional().describe("Replace the country list."),
|
|
3702
|
+
group_id: z.string().uuid().optional().describe("Move the campaign to another group."),
|
|
3703
|
+
...campaignConfigFields,
|
|
3617
3704
|
labels: z.record(z.string()).optional().describe("Replace the label map."),
|
|
3618
3705
|
policy_set_id: z.string().uuid().nullable().optional().describe("New policy set UUID; pass null to clear."),
|
|
3619
3706
|
schedule_enabled: z.boolean().optional().describe("Pause / resume the scheduler.")
|
|
@@ -3632,10 +3719,14 @@ var updateCampaignTool = {
|
|
|
3632
3719
|
handler: async (input, ctx) => {
|
|
3633
3720
|
const body = {
|
|
3634
3721
|
...input.name !== void 0 ? { name: input.name } : {},
|
|
3722
|
+
...input.url !== void 0 ? { url: input.url } : {},
|
|
3723
|
+
...input.ad_tag !== void 0 ? { ad_tag: input.ad_tag } : {},
|
|
3635
3724
|
...input.country_codes !== void 0 ? { country_codes: input.country_codes } : {},
|
|
3725
|
+
...input.group_id !== void 0 ? { group_id: input.group_id } : {},
|
|
3636
3726
|
...input.labels !== void 0 ? { labels: input.labels } : {},
|
|
3637
3727
|
...input.policy_set_id !== void 0 ? { policy_set_id: input.policy_set_id } : {},
|
|
3638
|
-
...input.schedule_enabled !== void 0 ? { schedule_enabled: input.schedule_enabled } : {}
|
|
3728
|
+
...input.schedule_enabled !== void 0 ? { schedule_enabled: input.schedule_enabled } : {},
|
|
3729
|
+
...pickCampaignConfigBody(input)
|
|
3639
3730
|
};
|
|
3640
3731
|
const result = await ctx.api.updateCampaign(input.campaign_id, body);
|
|
3641
3732
|
if (result.isErr()) return err(mapApiError(result.error));
|
|
@@ -3643,17 +3734,25 @@ var updateCampaignTool = {
|
|
|
3643
3734
|
}
|
|
3644
3735
|
};
|
|
3645
3736
|
var CreateCustomRuleInputShape = {
|
|
3646
|
-
name: z.string().min(1).max(200).describe(
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3737
|
+
name: z.string().min(1).max(200).describe(
|
|
3738
|
+
"Display name. For non-LLM rules this also becomes the `display_name` of the auto-registered tag definition (see `tag_slug`)."
|
|
3739
|
+
),
|
|
3740
|
+
tag_slug: z.string().max(100).optional().describe(
|
|
3741
|
+
"Tag slug to assign on match. Empty = create-only (advanced). The API auto-registers a custom tag definition for this slug with `display_name = name`. **MUST NOT collide with a built-in system tag slug** (see `list_tags` where `is_system=true`); colliding requests return 422 with code `checking.system_slug_reserved`. For `rule_type='llm'` use `config.tags` keys instead and leave `tag_slug` empty."
|
|
3742
|
+
),
|
|
3743
|
+
rule_type: z.string().max(50).describe(
|
|
3744
|
+
"Rule engine. One of: `stopword_content`, `stopword_url`, `regexp_content`, `regexp_url`, `blacklist_domain`, `combo`, `llm`. The API validates."
|
|
3745
|
+
),
|
|
3746
|
+
config: z.record(z.unknown()).describe(
|
|
3747
|
+
"Rule-type-specific configuration object. Shape depends on `rule_type`. For `rule_type='llm'` the shape is `{ prompt: string, tags: { <tag_slug>: <description>, ... } }`; each key in `config.tags` is auto-registered as a custom tag definition AND must not collide with a system slug (same 422 contract as `tag_slug`)."
|
|
3748
|
+
),
|
|
3650
3749
|
target: z.string().max(30).optional().describe(
|
|
3651
3750
|
"Where to apply the rule (e.g. 'page' for landing HTML). Default: page. See API docs for the full set of valid values."
|
|
3652
3751
|
)
|
|
3653
3752
|
};
|
|
3654
3753
|
var createCustomRuleTool = {
|
|
3655
3754
|
name: "create_custom_rule",
|
|
3656
|
-
description: "Define a custom tag-detection rule (
|
|
3755
|
+
description: "Define a custom tag-detection rule. The API auto-registers a tag definition for each slug the rule emits (`tag_slug` for non-LLM rules; `config.tags` keys for `rule_type='llm'`); slugs that collide with a built-in system tag are rejected with HTTP 422 / code `checking.system_slug_reserved`. Matches tag every future scan; existing scans are untouched until you call `recheck_scans`.",
|
|
3657
3756
|
annotations: {
|
|
3658
3757
|
title: "Create Custom Rule",
|
|
3659
3758
|
readOnlyHint: false,
|
|
@@ -3735,8 +3834,12 @@ var listCustomRulesTool = {
|
|
|
3735
3834
|
}
|
|
3736
3835
|
};
|
|
3737
3836
|
var TestCustomRuleInputShape = {
|
|
3738
|
-
rule_type: z.string().max(50).describe(
|
|
3739
|
-
|
|
3837
|
+
rule_type: z.string().max(50).describe(
|
|
3838
|
+
"Rule engine type. One of: `stopword_content`, `stopword_url`, `regexp_content`, `regexp_url`, `blacklist_domain`, `combo`, `llm`."
|
|
3839
|
+
),
|
|
3840
|
+
config: z.record(z.unknown()).describe(
|
|
3841
|
+
"Rule-type-specific config to test. Same shape as `create_custom_rule`'s `config`. NOTE: `test_custom_rule` evaluates the rule against a scan WITHOUT persisting it, so slug-collision validation does NOT run here \u2014 verify slugs against `list_tags` (`is_system=true`) before promoting to `create_custom_rule`."
|
|
3842
|
+
),
|
|
3740
3843
|
target: z.string().max(30).describe(
|
|
3741
3844
|
"Where to apply the rule (e.g. 'page' for landing HTML). See API docs for the full set of valid values."
|
|
3742
3845
|
),
|
|
@@ -3744,7 +3847,7 @@ var TestCustomRuleInputShape = {
|
|
|
3744
3847
|
};
|
|
3745
3848
|
var testCustomRuleTool = {
|
|
3746
3849
|
name: "test_custom_rule",
|
|
3747
|
-
description: "Preview-test a rule definition against an existing scan WITHOUT persisting the rule. Returns `matched: bool`, evaluation time, and per-tag-slug details. Use to validate config before `create_custom_rule`.",
|
|
3850
|
+
description: "Preview-test a rule definition against an existing scan WITHOUT persisting the rule. Returns `matched: bool`, evaluation time, and per-tag-slug details. Use to validate config before `create_custom_rule`. NOTE: slug-collision validation does NOT run in preview mode \u2014 verify any `tag_slug` (or LLM `config.tags` keys) against `list_tags` (`is_system=true`) before promoting to `create_custom_rule`, which would otherwise reject the same payload with HTTP 422 / code `checking.system_slug_reserved`.",
|
|
3748
3851
|
annotations: {
|
|
3749
3852
|
title: "Test Custom Rule",
|
|
3750
3853
|
readOnlyHint: true,
|
|
@@ -3766,9 +3869,15 @@ var testCustomRuleTool = {
|
|
|
3766
3869
|
};
|
|
3767
3870
|
var UpdateCustomRuleInputShape = {
|
|
3768
3871
|
rule_id: z.string().uuid().describe("Rule UUID to update."),
|
|
3769
|
-
name: z.string().min(1).max(200).optional().describe(
|
|
3770
|
-
|
|
3771
|
-
|
|
3872
|
+
name: z.string().min(1).max(200).optional().describe(
|
|
3873
|
+
"New display name. For non-LLM rules this also becomes the new `display_name` of the auto-registered tag definition."
|
|
3874
|
+
),
|
|
3875
|
+
tag_slug: z.string().max(100).optional().describe(
|
|
3876
|
+
"New tag slug to assign on match. **MUST NOT collide with a built-in system tag slug** (see `list_tags` where `is_system=true`); colliding requests return 422 with code `checking.system_slug_reserved`. Re-registering an existing custom slug refreshes its tag definition's `display_name` / `description`."
|
|
3877
|
+
),
|
|
3878
|
+
config: z.record(z.unknown()).optional().describe(
|
|
3879
|
+
"New rule-type-specific config object. For `rule_type='llm'` the keys of `config.tags` are auto-registered as tag definitions; any key that collides with a system slug returns the same 422 contract."
|
|
3880
|
+
),
|
|
3772
3881
|
target: z.string().max(30).optional().describe(
|
|
3773
3882
|
"Where to apply the rule (e.g. 'page' for landing HTML). See API docs for the full set of valid values."
|
|
3774
3883
|
),
|
|
@@ -3776,7 +3885,7 @@ var UpdateCustomRuleInputShape = {
|
|
|
3776
3885
|
};
|
|
3777
3886
|
var updateCustomRuleTool = {
|
|
3778
3887
|
name: "update_custom_rule",
|
|
3779
|
-
description: "Update a custom tag-detection rule. Only supplied fields are sent. To toggle activation, pass `is_active`. Existing tagged scans are NOT re-evaluated \u2014 call `recheck_scans` for that. (Rule engine `rule_type` cannot be changed after creation; create a new rule instead.)",
|
|
3888
|
+
description: "Update a custom tag-detection rule. Only supplied fields are sent. Changing `tag_slug` (or `config.tags` keys for `rule_type='llm'`) onto a built-in system slug returns HTTP 422 / code `checking.system_slug_reserved`. To toggle activation, pass `is_active`. Existing tagged scans are NOT re-evaluated \u2014 call `recheck_scans` for that. (Rule engine `rule_type` cannot be changed after creation; create a new rule instead.)",
|
|
3780
3889
|
annotations: {
|
|
3781
3890
|
title: "Update Custom Rule",
|
|
3782
3891
|
readOnlyHint: false,
|
|
@@ -3990,7 +4099,7 @@ var updateCustomTaxonomyTool = {
|
|
|
3990
4099
|
var ListEmulatorsInputShape = {};
|
|
3991
4100
|
var listEmulatorsTool = {
|
|
3992
4101
|
name: "list_emulators",
|
|
3993
|
-
description: "List every device/OS emulator profile available for scans (id, display name, category, browser).
|
|
4102
|
+
description: "List every device/OS emulator profile available for scans (id, display name, category, browser). For `create_scan`, use the `id` as `emulator_id`. For `create_campaign` / `update_campaign`, use the `category` in `emulator_categories` or the `id` in `emulator_specific_ids`.",
|
|
3994
4103
|
annotations: {
|
|
3995
4104
|
title: "List Emulators",
|
|
3996
4105
|
readOnlyHint: true,
|
|
@@ -4395,7 +4504,7 @@ var ListRunScansInputShape = {
|
|
|
4395
4504
|
};
|
|
4396
4505
|
var listRunScansTool = {
|
|
4397
4506
|
name: "list_run_scans",
|
|
4398
|
-
description: "List the tile-scan items produced by one run (status, country, offer URL, screenshot, elapsed ms, error). For full scan details (input URL, labels, classification, redirect chain) fetch a specific scan via `get_scan`.",
|
|
4507
|
+
description: "List the tile-scan items produced by one run (status, country, offer URL, absolute screenshot URL, report_url + public_report_url deep-links, elapsed ms, error). Link users to a scan with the returned `report_url` (auth dashboard) or `public_report_url` (shareable) \u2014 never hand-build URLs. For full scan details (input URL, labels, classification, redirect chain) fetch a specific scan via `get_scan`.",
|
|
4399
4508
|
annotations: {
|
|
4400
4509
|
title: "List Run Scans",
|
|
4401
4510
|
readOnlyHint: true,
|
|
@@ -4433,11 +4542,20 @@ var cancelScanTool = {
|
|
|
4433
4542
|
return ok(result.value);
|
|
4434
4543
|
}
|
|
4435
4544
|
};
|
|
4545
|
+
var scanProxyField = z.object({
|
|
4546
|
+
proxy_type: z.enum(["residential", "mobile"]).optional().describe("Proxy network type. Default: residential."),
|
|
4547
|
+
region: z.string().optional().describe("Proxy region/state targeting."),
|
|
4548
|
+
city: z.string().optional().describe("Proxy city targeting."),
|
|
4549
|
+
isp: z.string().optional().describe("Proxy ISP targeting.")
|
|
4550
|
+
}).optional().describe("Optional proxy geo targeting for the crawl. Omit to use the org default.");
|
|
4551
|
+
|
|
4552
|
+
// src/application/tools/scans/create-bulk-scans.tool.ts
|
|
4436
4553
|
var CreateBulkScansInputShape = {
|
|
4437
4554
|
url: z.string().url().optional().describe("Direct URL. EITHER `url` OR `ad_tag` is required."),
|
|
4438
4555
|
ad_tag: z.string().optional().describe("Raw ad-tag HTML/JS. EITHER `url` OR `ad_tag` is required."),
|
|
4439
4556
|
country_codes: z.array(z.string().length(2)).min(1).max(50).describe("List of ISO 3166-1 alpha-2 country codes; one scan per country is created."),
|
|
4440
4557
|
emulator_id: z.string().min(1).max(100).describe("Device/OS profile slug; same for every country in the batch."),
|
|
4558
|
+
proxy: scanProxyField,
|
|
4441
4559
|
labels: z.record(z.string()).optional().describe("Arbitrary metadata copied onto every created scan.")
|
|
4442
4560
|
};
|
|
4443
4561
|
var createBulkScansTool = {
|
|
@@ -4457,6 +4575,7 @@ var createBulkScansTool = {
|
|
|
4457
4575
|
emulator_id: input.emulator_id,
|
|
4458
4576
|
...input.url !== void 0 ? { url: input.url } : {},
|
|
4459
4577
|
...input.ad_tag !== void 0 ? { ad_tag: input.ad_tag } : {},
|
|
4578
|
+
...input.proxy !== void 0 ? { proxy: input.proxy } : {},
|
|
4460
4579
|
...input.labels !== void 0 ? { labels: input.labels } : {}
|
|
4461
4580
|
};
|
|
4462
4581
|
const result = await ctx.api.createBulkScans(body);
|
|
@@ -4469,6 +4588,7 @@ var CreateScanInputShape = {
|
|
|
4469
4588
|
ad_tag: z.string().optional().describe("Raw HTML/JS ad tag (script, iframe, image). EITHER `url` OR `ad_tag` is required."),
|
|
4470
4589
|
country_code: z.string().length(2).describe("ISO 3166-1 alpha-2 country code, e.g. US, DE, JP. Determines proxy geo."),
|
|
4471
4590
|
emulator_id: z.string().min(1).max(100).describe("Device/OS profile slug; use `list_emulators` to discover valid values."),
|
|
4591
|
+
proxy: scanProxyField,
|
|
4472
4592
|
labels: z.record(z.string()).optional().describe("Arbitrary string -> string metadata attached to the scan."),
|
|
4473
4593
|
campaign_id: z.string().uuid().optional().describe("Optional campaign UUID to attribute the scan to."),
|
|
4474
4594
|
run_id: z.string().uuid().optional().describe("Optional run UUID inside the campaign.")
|
|
@@ -4490,6 +4610,7 @@ var createScanTool = {
|
|
|
4490
4610
|
emulator_id: input.emulator_id,
|
|
4491
4611
|
...input.url !== void 0 ? { url: input.url } : {},
|
|
4492
4612
|
...input.ad_tag !== void 0 ? { ad_tag: input.ad_tag } : {},
|
|
4613
|
+
...input.proxy !== void 0 ? { proxy: input.proxy } : {},
|
|
4493
4614
|
...input.labels !== void 0 ? { labels: input.labels } : {},
|
|
4494
4615
|
...input.campaign_id !== void 0 ? { campaign_id: input.campaign_id } : {},
|
|
4495
4616
|
...input.run_id !== void 0 ? { run_id: input.run_id } : {}
|
|
@@ -4504,7 +4625,7 @@ var GetScanInputShape = {
|
|
|
4504
4625
|
};
|
|
4505
4626
|
var getScanTool = {
|
|
4506
4627
|
name: "get_scan",
|
|
4507
|
-
description: "Get full detail for one scan by UUID: status, offer URL, screenshot URL, timing, labels, and the parent campaign if any.",
|
|
4628
|
+
description: "Get full detail for one scan by UUID: status, offer URL, absolute screenshot URL, report_url + public_report_url deep-links, timing, labels, and the parent campaign if any. Link users with the returned `report_url` / `public_report_url` \u2014 never construct URLs yourself.",
|
|
4508
4629
|
annotations: {
|
|
4509
4630
|
title: "Get Scan",
|
|
4510
4631
|
readOnlyHint: true,
|
|
@@ -4622,7 +4743,7 @@ var ListScansInputShape = {
|
|
|
4622
4743
|
};
|
|
4623
4744
|
var listScansTool = {
|
|
4624
4745
|
name: "list_scans",
|
|
4625
|
-
description: "List scans for the caller's organization with optional filters (status, country, URL substring, date range, run/campaign/group, tag, AI/IAB/brand category, dynamic labels). Returns a paginated envelope.",
|
|
4746
|
+
description: "List scans for the caller's organization with optional filters (status, country, URL substring, date range, run/campaign/group, tag, AI/IAB/brand category, dynamic labels). Returns a paginated envelope; each scan carries an absolute screenshot URL plus report_url (auth dashboard) and public_report_url (shareable) deep-links \u2014 link users with those, never hand-build URLs.",
|
|
4626
4747
|
annotations: {
|
|
4627
4748
|
title: "List Scans",
|
|
4628
4749
|
readOnlyHint: true,
|
|
@@ -5042,7 +5163,12 @@ var testWebhookTool = {
|
|
|
5042
5163
|
var UpdateWebhookInputShape = {
|
|
5043
5164
|
webhook_id: z.string().uuid().describe("Webhook UUID."),
|
|
5044
5165
|
url: z.string().url().optional().describe("New endpoint URL."),
|
|
5166
|
+
description: z.string().max(256).optional().describe("New human-readable label."),
|
|
5045
5167
|
event_types: z.array(z.string()).max(50).optional().describe("Replace the subscribed-event-types list."),
|
|
5168
|
+
campaign_ids: z.array(z.string().uuid()).optional().describe("Restrict deliveries to these campaign UUIDs (replaces the current set)."),
|
|
5169
|
+
clear_campaign_ids: z.boolean().optional().describe(
|
|
5170
|
+
"Set true to remove the campaign restriction so the webhook fires for all campaigns."
|
|
5171
|
+
),
|
|
5046
5172
|
is_active: z.boolean().optional().describe("Enable / disable delivery.")
|
|
5047
5173
|
};
|
|
5048
5174
|
var updateWebhookTool = {
|
|
@@ -5059,7 +5185,10 @@ var updateWebhookTool = {
|
|
|
5059
5185
|
handler: async (input, ctx) => {
|
|
5060
5186
|
const body = {
|
|
5061
5187
|
...input.url !== void 0 ? { url: input.url } : {},
|
|
5188
|
+
...input.description !== void 0 ? { description: input.description } : {},
|
|
5062
5189
|
...input.event_types !== void 0 ? { event_types: input.event_types } : {},
|
|
5190
|
+
...input.campaign_ids !== void 0 ? { campaign_ids: input.campaign_ids } : {},
|
|
5191
|
+
...input.clear_campaign_ids !== void 0 ? { clear_campaign_ids: input.clear_campaign_ids } : {},
|
|
5063
5192
|
...input.is_active !== void 0 ? { is_active: input.is_active } : {}
|
|
5064
5193
|
};
|
|
5065
5194
|
const result = await ctx.api.updateWebhook(input.webhook_id, body);
|
|
@@ -5246,6 +5375,6 @@ function formatToolError(error) {
|
|
|
5246
5375
|
}
|
|
5247
5376
|
}
|
|
5248
5377
|
|
|
5249
|
-
export { BearerToken, createHttpApiGateway, createPinoLogger, declareEmptyResourcesAndPrompts, newRequestId, wireToolsIntoMcpServer };
|
|
5250
|
-
//# sourceMappingURL=chunk-
|
|
5251
|
-
//# sourceMappingURL=chunk-
|
|
5378
|
+
export { BearerToken, SERVER_INSTRUCTIONS, createHttpApiGateway, createPinoLogger, declareEmptyResourcesAndPrompts, newRequestId, wireToolsIntoMcpServer };
|
|
5379
|
+
//# sourceMappingURL=chunk-6FT6HKOB.js.map
|
|
5380
|
+
//# sourceMappingURL=chunk-6FT6HKOB.js.map
|