@kaminari-ad/mcp 0.2.2 → 0.3.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 +95 -0
- package/dist/bin.js +3 -3
- package/dist/{chunk-BAZQPU6T.js → chunk-KTQBHJUB.js} +3 -3
- package/dist/{chunk-BAZQPU6T.js.map → chunk-KTQBHJUB.js.map} +1 -1
- package/dist/{chunk-4MNLSWSZ.js → chunk-W7TPFRJB.js} +1031 -69
- package/dist/chunk-W7TPFRJB.js.map +1 -0
- package/dist/{http-bootstrap-PW4K2NDQ.js → http-bootstrap-FGGCFLRU.js} +4 -4
- package/dist/{http-bootstrap-PW4K2NDQ.js.map → http-bootstrap-FGGCFLRU.js.map} +1 -1
- package/dist/{stdio-bootstrap-PSX3TI3I.js → stdio-bootstrap-RBANZT6F.js} +4 -4
- package/dist/{stdio-bootstrap-PSX3TI3I.js.map → stdio-bootstrap-RBANZT6F.js.map} +1 -1
- package/package.json +1 -1
- package/dist/chunk-4MNLSWSZ.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-KTQBHJUB.js';
|
|
3
3
|
import { createHash, randomUUID } from 'crypto';
|
|
4
4
|
import createClient from 'openapi-fetch';
|
|
5
5
|
import { fetch } from 'undici';
|
|
@@ -148,12 +148,20 @@ function toApiError(status2, parsed, retryAfterHeader) {
|
|
|
148
148
|
}
|
|
149
149
|
return { kind: "upstream", detail: message, status: status2 };
|
|
150
150
|
}
|
|
151
|
+
var OrganizationStatus = z.enum([
|
|
152
|
+
"pending_email_verification",
|
|
153
|
+
"pending_admin_approval",
|
|
154
|
+
"active",
|
|
155
|
+
"suspended",
|
|
156
|
+
"rejected"
|
|
157
|
+
]);
|
|
151
158
|
var OrgResponse = z.object({
|
|
152
159
|
id: z.string().uuid(),
|
|
153
160
|
name: z.string(),
|
|
154
161
|
owner_id: z.string().uuid(),
|
|
155
|
-
|
|
156
|
-
created_at: z.string().datetime({ offset: true })
|
|
162
|
+
status: OrganizationStatus,
|
|
163
|
+
created_at: z.string().datetime({ offset: true }),
|
|
164
|
+
is_active: z.boolean()
|
|
157
165
|
}).passthrough();
|
|
158
166
|
z.object({ name: z.union([z.string(), z.null()]) }).partial().passthrough();
|
|
159
167
|
var ValidationError = z.object({
|
|
@@ -164,7 +172,7 @@ var ValidationError = z.object({
|
|
|
164
172
|
ctx: z.object({}).partial().passthrough().optional()
|
|
165
173
|
}).passthrough();
|
|
166
174
|
z.object({ detail: z.array(ValidationError) }).partial().passthrough();
|
|
167
|
-
z.object({
|
|
175
|
+
var LabelDefinitionResponse = z.object({
|
|
168
176
|
key: z.string(),
|
|
169
177
|
display_name: z.string(),
|
|
170
178
|
position: z.number().int(),
|
|
@@ -180,7 +188,10 @@ var UserResponse = z.object({
|
|
|
180
188
|
id: z.string().uuid(),
|
|
181
189
|
email: z.string(),
|
|
182
190
|
name: z.string(),
|
|
191
|
+
role_id: z.string().uuid(),
|
|
183
192
|
role_name: z.string(),
|
|
193
|
+
organization_id: z.string().uuid(),
|
|
194
|
+
organization_name: z.string(),
|
|
184
195
|
is_active: z.boolean(),
|
|
185
196
|
created_at: z.string().datetime({ offset: true })
|
|
186
197
|
}).passthrough();
|
|
@@ -271,16 +282,35 @@ var ProxyTargetResponse = z.object({
|
|
|
271
282
|
city: z.string().optional().default(""),
|
|
272
283
|
isp: z.string().optional().default("")
|
|
273
284
|
}).passthrough();
|
|
274
|
-
var
|
|
285
|
+
var AiCategoryResponse = z.object({
|
|
275
286
|
tier1: z.string(),
|
|
276
287
|
tier2: z.union([z.string(), z.null()]).optional(),
|
|
277
288
|
tier3: z.union([z.string(), z.null()]).optional(),
|
|
278
289
|
tier4: z.union([z.string(), z.null()]).optional()
|
|
279
290
|
}).passthrough();
|
|
291
|
+
var IabV3CategoryResponse = z.object({
|
|
292
|
+
tier1: z.string(),
|
|
293
|
+
tier2: z.union([z.string(), z.null()]).optional(),
|
|
294
|
+
tier3: z.union([z.string(), z.null()]).optional(),
|
|
295
|
+
tier4: z.union([z.string(), z.null()]).optional()
|
|
296
|
+
}).passthrough();
|
|
297
|
+
var ScanTaxonomyClassificationResponse = z.object({
|
|
298
|
+
taxonomy_id: z.string().uuid(),
|
|
299
|
+
taxonomy_name: z.string(),
|
|
300
|
+
taxonomy_slug: z.string(),
|
|
301
|
+
taxonomy_version: z.number().int(),
|
|
302
|
+
leaf_node_id: z.union([z.string(), z.null()]),
|
|
303
|
+
tier1: z.union([z.string(), z.null()]),
|
|
304
|
+
tier2: z.union([z.string(), z.null()]).optional(),
|
|
305
|
+
tier3: z.union([z.string(), z.null()]).optional(),
|
|
306
|
+
tier4: z.union([z.string(), z.null()]).optional(),
|
|
307
|
+
used_default: z.boolean().optional().default(false)
|
|
308
|
+
}).passthrough();
|
|
280
309
|
var ScanClassificationResponse = z.object({
|
|
281
310
|
brand: z.union([z.string(), z.null()]),
|
|
282
|
-
|
|
283
|
-
iab_v3: z.union([
|
|
311
|
+
ai_category: z.union([AiCategoryResponse, z.null()]),
|
|
312
|
+
iab_v3: z.union([IabV3CategoryResponse, z.null()]),
|
|
313
|
+
custom_taxonomies: z.array(ScanTaxonomyClassificationResponse).default([])
|
|
284
314
|
}).partial().passthrough();
|
|
285
315
|
var LandingResponse = z.object({
|
|
286
316
|
ord: z.number().int(),
|
|
@@ -532,7 +562,7 @@ var TagDefinitionWithStatsResponse = z.object({
|
|
|
532
562
|
description: z.string(),
|
|
533
563
|
is_system: z.boolean(),
|
|
534
564
|
organization_id: z.union([z.string(), z.null()]),
|
|
535
|
-
|
|
565
|
+
visibility: z.string(),
|
|
536
566
|
severity: z.string(),
|
|
537
567
|
scans_count: z.number().int(),
|
|
538
568
|
rules_count: z.number().int()
|
|
@@ -552,17 +582,18 @@ var TagDefinitionDetailResponse = z.object({
|
|
|
552
582
|
description: z.string(),
|
|
553
583
|
is_system: z.boolean(),
|
|
554
584
|
organization_id: z.union([z.string(), z.null()]),
|
|
555
|
-
|
|
585
|
+
visibility: z.string(),
|
|
556
586
|
severity: z.string(),
|
|
557
587
|
scans_count: z.number().int(),
|
|
558
588
|
rules_count: z.number().int(),
|
|
559
589
|
linked_rules: z.array(LinkedRuleResponse).optional()
|
|
560
590
|
}).passthrough();
|
|
591
|
+
var TagVisibility = z.enum(["hidden", "internal", "public"]);
|
|
561
592
|
var TagSeverity = z.enum(["high", "medium", "low"]);
|
|
562
593
|
z.object({
|
|
563
594
|
display_name: z.union([z.string(), z.null()]),
|
|
564
595
|
description: z.union([z.string(), z.null()]),
|
|
565
|
-
|
|
596
|
+
visibility: z.union([TagVisibility, z.null()]),
|
|
566
597
|
severity: z.union([TagSeverity, z.null()])
|
|
567
598
|
}).partial().passthrough();
|
|
568
599
|
z.object({
|
|
@@ -613,18 +644,66 @@ var RuleTestResponse = z.object({
|
|
|
613
644
|
llm_prompt_url: z.string().optional().default(""),
|
|
614
645
|
llm_response_url: z.string().optional().default("")
|
|
615
646
|
}).passthrough();
|
|
616
|
-
var
|
|
617
|
-
|
|
618
|
-
|
|
647
|
+
var IabV3PolicyCategoryRequest = z.object({
|
|
648
|
+
tier1: z.string().min(1).max(200),
|
|
649
|
+
tier2: z.union([z.string(), z.null()]).optional(),
|
|
650
|
+
tier3: z.union([z.string(), z.null()]).optional(),
|
|
651
|
+
tier4: z.union([z.string(), z.null()]).optional()
|
|
652
|
+
}).passthrough();
|
|
653
|
+
var AiCategoryRequest = z.object({
|
|
654
|
+
tier1: z.string().min(1).max(200),
|
|
655
|
+
tier2: z.union([z.string(), z.null()]).optional(),
|
|
656
|
+
tier3: z.union([z.string(), z.null()]).optional(),
|
|
657
|
+
tier4: z.union([z.string(), z.null()]).optional()
|
|
658
|
+
}).passthrough();
|
|
659
|
+
var CustomTaxonomyRefRequest = z.object({
|
|
660
|
+
taxonomy_id: z.string().uuid(),
|
|
661
|
+
tier1: z.string().min(1).max(200),
|
|
662
|
+
tier2: z.union([z.string(), z.null()]).optional(),
|
|
663
|
+
tier3: z.union([z.string(), z.null()]).optional(),
|
|
664
|
+
tier4: z.union([z.string(), z.null()]).optional()
|
|
619
665
|
}).passthrough();
|
|
666
|
+
var PolicyEntryRequest = z.object({
|
|
667
|
+
rule_type: z.enum(["tag", "iab_v3", "brand", "ai_category", "custom_taxonomy"]).default("tag"),
|
|
668
|
+
tag_slug: z.union([z.string(), z.null()]),
|
|
669
|
+
iab_v3: z.union([IabV3PolicyCategoryRequest, z.null()]),
|
|
670
|
+
brand: z.union([z.string(), z.null()]),
|
|
671
|
+
ai_category: z.union([AiCategoryRequest, z.null()]),
|
|
672
|
+
custom_taxonomy: z.union([CustomTaxonomyRefRequest, z.null()]),
|
|
673
|
+
country_codes: z.array(z.string()).max(50)
|
|
674
|
+
}).partial().passthrough();
|
|
620
675
|
z.object({
|
|
621
676
|
name: z.string().min(1).max(200),
|
|
622
677
|
description: z.string().max(2e3).optional().default(""),
|
|
623
678
|
entries: z.array(PolicyEntryRequest).min(1).max(500)
|
|
624
679
|
}).passthrough();
|
|
680
|
+
var PolicyEntryIabV3Response = z.object({
|
|
681
|
+
tier1: z.string(),
|
|
682
|
+
tier2: z.union([z.string(), z.null()]).optional(),
|
|
683
|
+
tier3: z.union([z.string(), z.null()]).optional(),
|
|
684
|
+
tier4: z.union([z.string(), z.null()]).optional()
|
|
685
|
+
}).passthrough();
|
|
686
|
+
var PolicyEntryAiCategoryResponse = z.object({
|
|
687
|
+
tier1: z.string(),
|
|
688
|
+
tier2: z.union([z.string(), z.null()]).optional(),
|
|
689
|
+
tier3: z.union([z.string(), z.null()]).optional(),
|
|
690
|
+
tier4: z.union([z.string(), z.null()]).optional()
|
|
691
|
+
}).passthrough();
|
|
692
|
+
var PolicyEntryCustomTaxonomyResponse = z.object({
|
|
693
|
+
taxonomy_id: z.string().uuid(),
|
|
694
|
+
tier1: z.string(),
|
|
695
|
+
tier2: z.union([z.string(), z.null()]).optional(),
|
|
696
|
+
tier3: z.union([z.string(), z.null()]).optional(),
|
|
697
|
+
tier4: z.union([z.string(), z.null()]).optional()
|
|
698
|
+
}).passthrough();
|
|
625
699
|
var PolicyEntryResponse = z.object({
|
|
626
700
|
id: z.string().uuid(),
|
|
627
|
-
|
|
701
|
+
rule_type: z.string(),
|
|
702
|
+
tag_slug: z.union([z.string(), z.null()]).optional(),
|
|
703
|
+
iab_v3: z.union([PolicyEntryIabV3Response, z.null()]).optional(),
|
|
704
|
+
brand: z.union([z.string(), z.null()]).optional(),
|
|
705
|
+
ai_category: z.union([PolicyEntryAiCategoryResponse, z.null()]).optional(),
|
|
706
|
+
custom_taxonomy: z.union([PolicyEntryCustomTaxonomyResponse, z.null()]).optional(),
|
|
628
707
|
country_codes: z.array(z.string())
|
|
629
708
|
}).passthrough();
|
|
630
709
|
var PolicySetResponse = z.object({
|
|
@@ -677,7 +756,9 @@ var AlertResponse = z.object({
|
|
|
677
756
|
updated_at: z.union([z.string(), z.null()]),
|
|
678
757
|
scan_url: z.string(),
|
|
679
758
|
offer_url: z.string(),
|
|
680
|
-
tag_display_name: z.string()
|
|
759
|
+
tag_display_name: z.string(),
|
|
760
|
+
rule_type: z.string().optional().default("tag"),
|
|
761
|
+
matched_value: z.union([z.string(), z.null()]).optional()
|
|
681
762
|
}).passthrough();
|
|
682
763
|
z.object({
|
|
683
764
|
items: z.array(AlertResponse),
|
|
@@ -932,8 +1013,67 @@ z.object({
|
|
|
932
1013
|
id: z.string().uuid(),
|
|
933
1014
|
received_at: z.string().datetime({ offset: true })
|
|
934
1015
|
}).passthrough();
|
|
1016
|
+
var CustomTaxonomyListItem = z.object({
|
|
1017
|
+
id: z.string().uuid(),
|
|
1018
|
+
name: z.string(),
|
|
1019
|
+
slug: z.string(),
|
|
1020
|
+
description: z.string(),
|
|
1021
|
+
is_active: z.boolean(),
|
|
1022
|
+
version: z.number().int(),
|
|
1023
|
+
node_count: z.number().int(),
|
|
1024
|
+
created_at: z.string().datetime({ offset: true }),
|
|
1025
|
+
updated_at: z.string().datetime({ offset: true })
|
|
1026
|
+
}).passthrough();
|
|
1027
|
+
var TaxonomyNodeRequest = z.object({
|
|
1028
|
+
client_id: z.string().min(1).max(100),
|
|
1029
|
+
parent_client_id: z.union([z.string(), z.null()]).optional(),
|
|
1030
|
+
name: z.string().min(1).max(100),
|
|
1031
|
+
description: z.string().max(200).optional().default(""),
|
|
1032
|
+
is_default: z.boolean().optional().default(false)
|
|
1033
|
+
});
|
|
1034
|
+
z.object({
|
|
1035
|
+
name: z.string().min(1).max(100),
|
|
1036
|
+
description: z.string().max(500).optional().default(""),
|
|
1037
|
+
nodes: z.array(TaxonomyNodeRequest).optional().default([])
|
|
1038
|
+
});
|
|
1039
|
+
var TaxonomyNodeResponse = z.object({
|
|
1040
|
+
id: z.string().uuid(),
|
|
1041
|
+
parent_id: z.union([z.string(), z.null()]),
|
|
1042
|
+
level: z.number().int(),
|
|
1043
|
+
position: z.number().int(),
|
|
1044
|
+
name: z.string(),
|
|
1045
|
+
description: z.string(),
|
|
1046
|
+
is_default: z.boolean()
|
|
1047
|
+
}).passthrough();
|
|
1048
|
+
var CustomTaxonomyResponse = z.object({
|
|
1049
|
+
id: z.string().uuid(),
|
|
1050
|
+
organization_id: z.string().uuid(),
|
|
1051
|
+
name: z.string(),
|
|
1052
|
+
slug: z.string(),
|
|
1053
|
+
description: z.string(),
|
|
1054
|
+
is_active: z.boolean(),
|
|
1055
|
+
version: z.number().int(),
|
|
1056
|
+
nodes: z.array(TaxonomyNodeResponse),
|
|
1057
|
+
created_at: z.string().datetime({ offset: true }),
|
|
1058
|
+
updated_at: z.string().datetime({ offset: true })
|
|
1059
|
+
}).passthrough();
|
|
1060
|
+
z.object({
|
|
1061
|
+
text: z.string().min(1).max(5e4)
|
|
1062
|
+
});
|
|
1063
|
+
var ParsedTaxonomyNode = z.object({
|
|
1064
|
+
level: z.number().int(),
|
|
1065
|
+
name: z.string(),
|
|
1066
|
+
description: z.string()
|
|
1067
|
+
}).passthrough();
|
|
1068
|
+
var ParseTaxonomyTextResponse = z.object({ nodes: z.array(ParsedTaxonomyNode), warnings: z.array(z.string()) }).passthrough();
|
|
1069
|
+
z.object({
|
|
1070
|
+
name: z.string().min(1).max(100),
|
|
1071
|
+
description: z.string().max(500).optional().default(""),
|
|
1072
|
+
nodes: z.array(TaxonomyNodeRequest).optional().default([])
|
|
1073
|
+
});
|
|
935
1074
|
var schemas = {
|
|
936
1075
|
OrgResponse,
|
|
1076
|
+
LabelDefinitionResponse,
|
|
937
1077
|
UserResponse,
|
|
938
1078
|
ApiKeyResponse,
|
|
939
1079
|
ApiKeyCreatedResponse,
|
|
@@ -970,7 +1110,12 @@ var schemas = {
|
|
|
970
1110
|
BulkReplayResponse,
|
|
971
1111
|
AlertNotificationDestinationResponse,
|
|
972
1112
|
CampaignOverridesResponse,
|
|
973
|
-
InvoiceResponse
|
|
1113
|
+
InvoiceResponse,
|
|
1114
|
+
CustomTaxonomyListItem,
|
|
1115
|
+
TaxonomyNodeResponse,
|
|
1116
|
+
CustomTaxonomyResponse,
|
|
1117
|
+
ParsedTaxonomyNode,
|
|
1118
|
+
ParseTaxonomyTextResponse};
|
|
974
1119
|
function parseWithSchema(schema, raw, label) {
|
|
975
1120
|
const parsed = schema.safeParse(raw);
|
|
976
1121
|
if (parsed.success) return ok(stripUndefinedKeys(parsed.data));
|
|
@@ -1020,6 +1165,8 @@ var AlertSchema = schemas.AlertResponse.pick({
|
|
|
1020
1165
|
campaign_id: true,
|
|
1021
1166
|
policy_set_id: true,
|
|
1022
1167
|
violation_rule_id: true,
|
|
1168
|
+
rule_type: true,
|
|
1169
|
+
matched_value: true,
|
|
1023
1170
|
tag_slug: true,
|
|
1024
1171
|
tag_display_name: true,
|
|
1025
1172
|
country_code: true,
|
|
@@ -1143,6 +1290,49 @@ var CustomRuleSchema2 = schemas.CustomRuleResponse.pick({
|
|
|
1143
1290
|
created_at: true
|
|
1144
1291
|
}).strip();
|
|
1145
1292
|
var parseCustomRulePage = (raw) => parsePagedWithItemSchema(CustomRuleSchema2, raw, "custom-rules");
|
|
1293
|
+
var CustomTaxonomyListItemSchema = schemas.CustomTaxonomyListItem.pick({
|
|
1294
|
+
id: true,
|
|
1295
|
+
name: true,
|
|
1296
|
+
slug: true,
|
|
1297
|
+
description: true,
|
|
1298
|
+
is_active: true,
|
|
1299
|
+
version: true,
|
|
1300
|
+
node_count: true,
|
|
1301
|
+
created_at: true,
|
|
1302
|
+
updated_at: true
|
|
1303
|
+
}).strip();
|
|
1304
|
+
var CustomTaxonomyListSchema = z.array(CustomTaxonomyListItemSchema);
|
|
1305
|
+
var TaxonomyNodeSchema = schemas.TaxonomyNodeResponse.pick({
|
|
1306
|
+
id: true,
|
|
1307
|
+
parent_id: true,
|
|
1308
|
+
level: true,
|
|
1309
|
+
position: true,
|
|
1310
|
+
name: true,
|
|
1311
|
+
description: true,
|
|
1312
|
+
is_default: true
|
|
1313
|
+
}).strip();
|
|
1314
|
+
var CustomTaxonomySchema = schemas.CustomTaxonomyResponse.pick({
|
|
1315
|
+
id: true,
|
|
1316
|
+
organization_id: true,
|
|
1317
|
+
name: true,
|
|
1318
|
+
slug: true,
|
|
1319
|
+
description: true,
|
|
1320
|
+
is_active: true,
|
|
1321
|
+
version: true,
|
|
1322
|
+
created_at: true,
|
|
1323
|
+
updated_at: true
|
|
1324
|
+
}).extend({ nodes: z.array(TaxonomyNodeSchema) }).strip();
|
|
1325
|
+
var ParsedTaxonomyNodeSchema = schemas.ParsedTaxonomyNode.pick({
|
|
1326
|
+
level: true,
|
|
1327
|
+
name: true,
|
|
1328
|
+
description: true
|
|
1329
|
+
}).strip();
|
|
1330
|
+
var ParseTaxonomyTextResponseSchema = schemas.ParseTaxonomyTextResponse.pick({
|
|
1331
|
+
warnings: true
|
|
1332
|
+
}).extend({ nodes: z.array(ParsedTaxonomyNodeSchema) }).strip();
|
|
1333
|
+
var parseCustomTaxonomyList = (raw) => parseWithSchema(CustomTaxonomyListSchema, raw, "custom-taxonomies");
|
|
1334
|
+
var parseCustomTaxonomy = (raw) => parseWithSchema(CustomTaxonomySchema, raw, "custom-taxonomy");
|
|
1335
|
+
var parseTaxonomyTextPreview = (raw) => parseWithSchema(ParseTaxonomyTextResponseSchema, raw, "custom-taxonomy-parse-text");
|
|
1146
1336
|
|
|
1147
1337
|
// src/infrastructure/api/parsers/parse-empty.ts
|
|
1148
1338
|
function parseEmpty(_raw) {
|
|
@@ -1213,6 +1403,13 @@ var RoleSchema = schemas.RoleResponse.pick({
|
|
|
1213
1403
|
permissions: true
|
|
1214
1404
|
}).strip();
|
|
1215
1405
|
var parseRole = (raw) => parseWithSchema(RoleSchema, raw, "role");
|
|
1406
|
+
var LabelDefinitionSchema = schemas.LabelDefinitionResponse.pick({
|
|
1407
|
+
key: true,
|
|
1408
|
+
display_name: true,
|
|
1409
|
+
position: true,
|
|
1410
|
+
auto_extract: true
|
|
1411
|
+
}).strip();
|
|
1412
|
+
var parseLabelDefinition = (raw) => parseWithSchema(LabelDefinitionSchema, raw, "label-definition");
|
|
1216
1413
|
var ApiKeyCreatedSchema = schemas.ApiKeyCreatedResponse.pick({
|
|
1217
1414
|
id: true,
|
|
1218
1415
|
key_prefix: true,
|
|
@@ -1354,7 +1551,12 @@ var GroupActionSchema = schemas.GroupActionResponse.pick({
|
|
|
1354
1551
|
var parseGroupAction = (raw) => parseWithSchema(GroupActionSchema, raw, "group-action");
|
|
1355
1552
|
schemas.PolicyEntryResponse.pick({
|
|
1356
1553
|
id: true,
|
|
1554
|
+
rule_type: true,
|
|
1357
1555
|
tag_slug: true,
|
|
1556
|
+
iab_v3: true,
|
|
1557
|
+
brand: true,
|
|
1558
|
+
ai_category: true,
|
|
1559
|
+
custom_taxonomy: true,
|
|
1358
1560
|
country_codes: true
|
|
1359
1561
|
}).strip();
|
|
1360
1562
|
var GeoSchema = schemas.GeoResponse.pick({
|
|
@@ -1465,7 +1667,7 @@ var TagDefinitionSchema = schemas.TagDefinitionWithStatsResponse.pick({
|
|
|
1465
1667
|
severity: true,
|
|
1466
1668
|
is_system: true,
|
|
1467
1669
|
organization_id: true,
|
|
1468
|
-
|
|
1670
|
+
visibility: true,
|
|
1469
1671
|
scans_count: true,
|
|
1470
1672
|
rules_count: true
|
|
1471
1673
|
}).strip();
|
|
@@ -1484,7 +1686,7 @@ var TagDetailSchema = schemas.TagDefinitionDetailResponse.pick({
|
|
|
1484
1686
|
severity: true,
|
|
1485
1687
|
is_system: true,
|
|
1486
1688
|
organization_id: true,
|
|
1487
|
-
|
|
1689
|
+
visibility: true,
|
|
1488
1690
|
scans_count: true,
|
|
1489
1691
|
rules_count: true
|
|
1490
1692
|
}).extend({ linked_rules: z.array(LinkedRuleSchema).optional() }).strip();
|
|
@@ -1592,6 +1794,56 @@ function createHttpApiGateway(config) {
|
|
|
1592
1794
|
}
|
|
1593
1795
|
return err(toApiError(status2, error ?? data, response.headers.get("retry-after") ?? void 0));
|
|
1594
1796
|
}
|
|
1797
|
+
async function binaryGet(path, query) {
|
|
1798
|
+
const startedAtMs = Date.now();
|
|
1799
|
+
const qs = query && Object.keys(query).length > 0 ? `?${new URLSearchParams(
|
|
1800
|
+
Object.fromEntries(Object.entries(query).map(([k, v]) => [k, String(v)]))
|
|
1801
|
+
).toString()}` : "";
|
|
1802
|
+
const url = `${baseUrl}${path}${qs}`;
|
|
1803
|
+
let response;
|
|
1804
|
+
try {
|
|
1805
|
+
const init = {
|
|
1806
|
+
method: "GET",
|
|
1807
|
+
// Header allowlist: see binaryGet docstring above. Keep this
|
|
1808
|
+
// map minimal; any future addition needs a CONTRIBUTING.md
|
|
1809
|
+
// update + a tenant-isolation review.
|
|
1810
|
+
headers: {
|
|
1811
|
+
authorization: bearer.toAuthorizationHeader(),
|
|
1812
|
+
accept: "image/*, application/pdf, application/octet-stream",
|
|
1813
|
+
"user-agent": "kaminari-ad-mcp",
|
|
1814
|
+
"x-request-id": requestId
|
|
1815
|
+
}
|
|
1816
|
+
};
|
|
1817
|
+
if (dispatcher !== void 0) init["dispatcher"] = dispatcher;
|
|
1818
|
+
response = await fetch(
|
|
1819
|
+
url,
|
|
1820
|
+
init
|
|
1821
|
+
);
|
|
1822
|
+
} catch (cause) {
|
|
1823
|
+
logger.warn({ api_path: path, elapsed_ms: Date.now() - startedAtMs }, "api.network_error");
|
|
1824
|
+
const inner = cause instanceof Error && cause.cause instanceof Error ? cause.cause : cause instanceof Error ? cause : null;
|
|
1825
|
+
return err({ kind: "upstream", detail: inner !== null ? inner.message : "network error" });
|
|
1826
|
+
}
|
|
1827
|
+
const status2 = response.status;
|
|
1828
|
+
logger.info(
|
|
1829
|
+
{ api_path: path, api_status: status2, elapsed_ms: Date.now() - startedAtMs },
|
|
1830
|
+
"api.done"
|
|
1831
|
+
);
|
|
1832
|
+
if (status2 >= 200 && status2 < 300) {
|
|
1833
|
+
const buf = await response.arrayBuffer();
|
|
1834
|
+
return ok({
|
|
1835
|
+
bytes: new Uint8Array(buf),
|
|
1836
|
+
contentType: response.headers.get("content-type") ?? "application/octet-stream"
|
|
1837
|
+
});
|
|
1838
|
+
}
|
|
1839
|
+
let errBody;
|
|
1840
|
+
try {
|
|
1841
|
+
errBody = await response.json();
|
|
1842
|
+
} catch {
|
|
1843
|
+
errBody = void 0;
|
|
1844
|
+
}
|
|
1845
|
+
return err(toApiError(status2, errBody, response.headers.get("retry-after") ?? void 0));
|
|
1846
|
+
}
|
|
1595
1847
|
return {
|
|
1596
1848
|
// ── Account ───────────────────────────────────────────────────
|
|
1597
1849
|
async getAccount() {
|
|
@@ -1633,6 +1885,33 @@ function createHttpApiGateway(config) {
|
|
|
1633
1885
|
async listOrgRoles() {
|
|
1634
1886
|
return call("GET", "/api/v1/account/roles", {}, parseArrayOf(parseRole));
|
|
1635
1887
|
},
|
|
1888
|
+
async createCustomRole(body) {
|
|
1889
|
+
return call("POST", "/api/v1/account/roles", { body }, parseRole);
|
|
1890
|
+
},
|
|
1891
|
+
async listAccountLabels() {
|
|
1892
|
+
return call("GET", "/api/v1/account/labels", {}, parseArrayOf(parseLabelDefinition));
|
|
1893
|
+
},
|
|
1894
|
+
async updateAccountLabels(body) {
|
|
1895
|
+
return call("PUT", "/api/v1/account/labels", { body }, parseArrayOf(parseLabelDefinition));
|
|
1896
|
+
},
|
|
1897
|
+
async getScanScreenshot(scanId, w2) {
|
|
1898
|
+
return binaryGet(`/api/v1/scans/${scanId}/screenshot`, w2 !== void 0 ? { w: w2 } : void 0);
|
|
1899
|
+
},
|
|
1900
|
+
async getScanCreativeScreenshot(scanId, w2) {
|
|
1901
|
+
return binaryGet(
|
|
1902
|
+
`/api/v1/scans/${scanId}/creative-screenshot`,
|
|
1903
|
+
w2 !== void 0 ? { w: w2 } : void 0
|
|
1904
|
+
);
|
|
1905
|
+
},
|
|
1906
|
+
async getScanLandingScreenshot(scanId, landingOrd, w2) {
|
|
1907
|
+
return binaryGet(
|
|
1908
|
+
`/api/v1/scans/${scanId}/landings/${String(landingOrd)}/screenshot`,
|
|
1909
|
+
w2 !== void 0 ? { w: w2 } : void 0
|
|
1910
|
+
);
|
|
1911
|
+
},
|
|
1912
|
+
async getInvoicePdf(invoiceId) {
|
|
1913
|
+
return binaryGet(`/api/v1/invoices/${invoiceId}/pdf`);
|
|
1914
|
+
},
|
|
1636
1915
|
async listApiKeys() {
|
|
1637
1916
|
return call("GET", "/api/v1/account/api-keys", {}, parseApiKeyList);
|
|
1638
1917
|
},
|
|
@@ -1759,8 +2038,13 @@ function createHttpApiGateway(config) {
|
|
|
1759
2038
|
parsePageOf(parseRun)
|
|
1760
2039
|
);
|
|
1761
2040
|
},
|
|
1762
|
-
async listCampaignsPicker() {
|
|
1763
|
-
return call(
|
|
2041
|
+
async listCampaignsPicker(filters) {
|
|
2042
|
+
return call(
|
|
2043
|
+
"GET",
|
|
2044
|
+
"/api/v1/campaigns/picker",
|
|
2045
|
+
filters ? { params: { query: filters } } : {},
|
|
2046
|
+
parseCampaignPickerArray
|
|
2047
|
+
);
|
|
1764
2048
|
},
|
|
1765
2049
|
// ── Runs ──────────────────────────────────────────────────────
|
|
1766
2050
|
async getRun(id) {
|
|
@@ -1859,8 +2143,13 @@ function createHttpApiGateway(config) {
|
|
|
1859
2143
|
);
|
|
1860
2144
|
},
|
|
1861
2145
|
// ── Tag definitions ───────────────────────────────────────────
|
|
1862
|
-
async listTags() {
|
|
1863
|
-
return call(
|
|
2146
|
+
async listTags(filters) {
|
|
2147
|
+
return call(
|
|
2148
|
+
"GET",
|
|
2149
|
+
"/api/v1/tag-definitions",
|
|
2150
|
+
filters ? { params: { query: filters } } : {},
|
|
2151
|
+
parseTagDefinitionArray
|
|
2152
|
+
);
|
|
1864
2153
|
},
|
|
1865
2154
|
async getTagDefinition(slug) {
|
|
1866
2155
|
return call(
|
|
@@ -1964,6 +2253,53 @@ function createHttpApiGateway(config) {
|
|
|
1964
2253
|
parseEmpty
|
|
1965
2254
|
);
|
|
1966
2255
|
},
|
|
2256
|
+
// ── Custom taxonomies ─────────────────────────────────────────
|
|
2257
|
+
async listCustomTaxonomies() {
|
|
2258
|
+
return call("GET", "/api/v1/custom-taxonomies", {}, parseCustomTaxonomyList);
|
|
2259
|
+
},
|
|
2260
|
+
async getCustomTaxonomy(id) {
|
|
2261
|
+
return call(
|
|
2262
|
+
"GET",
|
|
2263
|
+
"/api/v1/custom-taxonomies/{taxonomy_id}",
|
|
2264
|
+
{ params: { path: { taxonomy_id: id } } },
|
|
2265
|
+
parseCustomTaxonomy
|
|
2266
|
+
);
|
|
2267
|
+
},
|
|
2268
|
+
async createCustomTaxonomy(body) {
|
|
2269
|
+
return call("POST", "/api/v1/custom-taxonomies", { body }, parseCustomTaxonomy);
|
|
2270
|
+
},
|
|
2271
|
+
async updateCustomTaxonomy(id, body) {
|
|
2272
|
+
return call(
|
|
2273
|
+
"PUT",
|
|
2274
|
+
"/api/v1/custom-taxonomies/{taxonomy_id}",
|
|
2275
|
+
{ params: { path: { taxonomy_id: id } }, body },
|
|
2276
|
+
parseCustomTaxonomy
|
|
2277
|
+
);
|
|
2278
|
+
},
|
|
2279
|
+
async deleteCustomTaxonomy(id) {
|
|
2280
|
+
return call(
|
|
2281
|
+
"DELETE",
|
|
2282
|
+
"/api/v1/custom-taxonomies/{taxonomy_id}",
|
|
2283
|
+
{ params: { path: { taxonomy_id: id } } },
|
|
2284
|
+
parseEmpty
|
|
2285
|
+
);
|
|
2286
|
+
},
|
|
2287
|
+
async restoreCustomTaxonomy(id) {
|
|
2288
|
+
return call(
|
|
2289
|
+
"POST",
|
|
2290
|
+
"/api/v1/custom-taxonomies/{taxonomy_id}/restore",
|
|
2291
|
+
{ params: { path: { taxonomy_id: id } } },
|
|
2292
|
+
parseCustomTaxonomy
|
|
2293
|
+
);
|
|
2294
|
+
},
|
|
2295
|
+
async parseCustomTaxonomyText(body) {
|
|
2296
|
+
return call(
|
|
2297
|
+
"POST",
|
|
2298
|
+
"/api/v1/custom-taxonomies/parse-text",
|
|
2299
|
+
{ body },
|
|
2300
|
+
parseTaxonomyTextPreview
|
|
2301
|
+
);
|
|
2302
|
+
},
|
|
1967
2303
|
// ── Alerts ────────────────────────────────────────────────────
|
|
1968
2304
|
async listAlerts(filters) {
|
|
1969
2305
|
return call("GET", "/api/v1/alerts", { params: { query: filters } }, parseAlertPage);
|
|
@@ -2254,6 +2590,32 @@ var createApiKeyTool = {
|
|
|
2254
2590
|
return ok(result.value);
|
|
2255
2591
|
}
|
|
2256
2592
|
};
|
|
2593
|
+
var CreateCustomRoleInputShape = {
|
|
2594
|
+
name: z.string().min(1).max(100).describe("Display name for the role."),
|
|
2595
|
+
permissions: z.array(z.string().min(1).max(100)).min(1).max(200).describe(
|
|
2596
|
+
"Permission slugs the role grants (e.g. 'scans.read', 'campaigns.write'). Use `list_org_roles` to see permissions on existing system roles."
|
|
2597
|
+
)
|
|
2598
|
+
};
|
|
2599
|
+
var createCustomRoleTool = {
|
|
2600
|
+
name: "create_custom_role",
|
|
2601
|
+
description: "Create a custom organization role with the supplied permission set. Returns the persisted role; assign it to users via `update_user_role`.",
|
|
2602
|
+
annotations: {
|
|
2603
|
+
title: "Create Custom Role",
|
|
2604
|
+
readOnlyHint: false,
|
|
2605
|
+
destructiveHint: false,
|
|
2606
|
+
idempotentHint: false,
|
|
2607
|
+
openWorldHint: false
|
|
2608
|
+
},
|
|
2609
|
+
inputSchema: z.object(CreateCustomRoleInputShape),
|
|
2610
|
+
handler: async (input, ctx) => {
|
|
2611
|
+
const result = await ctx.api.createCustomRole({
|
|
2612
|
+
name: input.name,
|
|
2613
|
+
permissions: [...input.permissions]
|
|
2614
|
+
});
|
|
2615
|
+
if (result.isErr()) return err(mapApiError(result.error));
|
|
2616
|
+
return ok(result.value);
|
|
2617
|
+
}
|
|
2618
|
+
};
|
|
2257
2619
|
var GetAccountInputShape = {};
|
|
2258
2620
|
var getAccountTool = {
|
|
2259
2621
|
name: "get_account",
|
|
@@ -2299,6 +2661,24 @@ var inviteUserTool = {
|
|
|
2299
2661
|
return ok(result.value);
|
|
2300
2662
|
}
|
|
2301
2663
|
};
|
|
2664
|
+
var ListAccountLabelsInputShape = {};
|
|
2665
|
+
var listAccountLabelsTool = {
|
|
2666
|
+
name: "list_account_labels",
|
|
2667
|
+
description: "List the organization's custom label definitions (key, display_name, position, auto_extract). Labels enrich scans and can be used as filters in `list_scans`.",
|
|
2668
|
+
annotations: {
|
|
2669
|
+
title: "List Account Labels",
|
|
2670
|
+
readOnlyHint: true,
|
|
2671
|
+
destructiveHint: false,
|
|
2672
|
+
idempotentHint: true,
|
|
2673
|
+
openWorldHint: false
|
|
2674
|
+
},
|
|
2675
|
+
inputSchema: z.object(ListAccountLabelsInputShape),
|
|
2676
|
+
handler: async (_input, ctx) => {
|
|
2677
|
+
const result = await ctx.api.listAccountLabels();
|
|
2678
|
+
if (result.isErr()) return err(mapApiError(result.error));
|
|
2679
|
+
return ok({ items: result.value });
|
|
2680
|
+
}
|
|
2681
|
+
};
|
|
2302
2682
|
var ListApiKeysInputShape = {};
|
|
2303
2683
|
var listApiKeysTool = {
|
|
2304
2684
|
name: "list_api_keys",
|
|
@@ -2413,6 +2793,45 @@ var transferOwnershipTool = {
|
|
|
2413
2793
|
return ok({ transferred: true });
|
|
2414
2794
|
}
|
|
2415
2795
|
};
|
|
2796
|
+
var LabelItem = z.object({
|
|
2797
|
+
key: z.string().min(1).max(100).regex(/^[a-z0-9_]+$/, "key must be snake_case ([a-z0-9_]+)").describe("Stable snake_case identifier used in scan filters."),
|
|
2798
|
+
display_name: z.string().min(1).max(200).describe("Human-readable name shown in the UI."),
|
|
2799
|
+
auto_extract: z.boolean().optional().describe(
|
|
2800
|
+
"When true, the LLM auto-populates this label's value during scan classification. Defaults to false."
|
|
2801
|
+
)
|
|
2802
|
+
});
|
|
2803
|
+
var UpdateAccountLabelsInputShape = {
|
|
2804
|
+
labels: z.array(LabelItem).max(20).describe(
|
|
2805
|
+
"REPLACEMENT list of all labels \u2014 pass every label you want to keep. Order in the array becomes `position`. Empty array removes all labels."
|
|
2806
|
+
)
|
|
2807
|
+
};
|
|
2808
|
+
var updateAccountLabelsTool = {
|
|
2809
|
+
name: "update_account_labels",
|
|
2810
|
+
description: "REPLACE the organization's full set of custom label definitions. The API replaces the list (no merge); read the current list with `list_account_labels` first. Returns the persisted list with allocated positions.",
|
|
2811
|
+
annotations: {
|
|
2812
|
+
title: "Update Account Labels",
|
|
2813
|
+
readOnlyHint: false,
|
|
2814
|
+
// REPLACE semantics: passing `labels: []` wipes every label and
|
|
2815
|
+
// detaches the value on every scan that referenced one. Hint as
|
|
2816
|
+
// destructive so MCP clients that gate dangerous tools warn the
|
|
2817
|
+
// user before this call runs.
|
|
2818
|
+
destructiveHint: true,
|
|
2819
|
+
idempotentHint: true,
|
|
2820
|
+
openWorldHint: false
|
|
2821
|
+
},
|
|
2822
|
+
inputSchema: z.object(UpdateAccountLabelsInputShape),
|
|
2823
|
+
handler: async (input, ctx) => {
|
|
2824
|
+
const result = await ctx.api.updateAccountLabels({
|
|
2825
|
+
labels: input.labels.map((l) => ({
|
|
2826
|
+
key: l.key,
|
|
2827
|
+
display_name: l.display_name,
|
|
2828
|
+
auto_extract: l.auto_extract ?? false
|
|
2829
|
+
}))
|
|
2830
|
+
});
|
|
2831
|
+
if (result.isErr()) return err(mapApiError(result.error));
|
|
2832
|
+
return ok({ items: result.value });
|
|
2833
|
+
}
|
|
2834
|
+
};
|
|
2416
2835
|
var UpdateOrgInputShape = {
|
|
2417
2836
|
name: z.string().min(1).max(200).optional().describe("New organization display name."),
|
|
2418
2837
|
settings: z.record(z.unknown()).optional().describe("Replacement settings object. Fields not supplied are left unchanged.")
|
|
@@ -2574,7 +2993,7 @@ var setCampaignAlertOverridesTool = {
|
|
|
2574
2993
|
var GetAlertStatsInputShape = {};
|
|
2575
2994
|
var getAlertStatsTool = {
|
|
2576
2995
|
name: "get_alert_stats",
|
|
2577
|
-
description: "Get alert counts grouped by status: open,
|
|
2996
|
+
description: "Get alert counts grouped by status: open, acknowledged, resolved, dismissed (total is implicit in the sum). Status names match the canonical AlertStatus enum used by `list_alerts` and `update_alert_status`.",
|
|
2578
2997
|
annotations: {
|
|
2579
2998
|
title: "Get Alert Stats",
|
|
2580
2999
|
readOnlyHint: true,
|
|
@@ -2591,13 +3010,15 @@ var getAlertStatsTool = {
|
|
|
2591
3010
|
};
|
|
2592
3011
|
var ListAlertsInputShape = {
|
|
2593
3012
|
campaign_id: z.string().uuid().optional().describe("Filter to one campaign's alerts."),
|
|
2594
|
-
status: z.enum(["open", "
|
|
3013
|
+
status: z.enum(["open", "acknowledged", "resolved", "dismissed"]).optional().describe(
|
|
3014
|
+
"Filter by alert status. Open = unhandled; acknowledged = seen by an operator; resolved = closed; dismissed = closed without action."
|
|
3015
|
+
),
|
|
2595
3016
|
page: z.number().int().min(1).max(500).default(1).describe("1-indexed page number."),
|
|
2596
3017
|
limit: z.number().int().min(1).max(200).default(50).describe("Page size.")
|
|
2597
3018
|
};
|
|
2598
3019
|
var listAlertsTool = {
|
|
2599
3020
|
name: "list_alerts",
|
|
2600
|
-
description: "List violation alerts (one per scan + violating
|
|
3021
|
+
description: "List violation alerts (one per scan + violating rule combo) with offer URL, country, status, scan back-reference, and the kind-aware fields `rule_type` (tag / iab_v3 / brand / ai_category / custom_taxonomy) + `matched_value` (the canonical text the scan matched against).",
|
|
2601
3022
|
annotations: {
|
|
2602
3023
|
title: "List Alerts",
|
|
2603
3024
|
readOnlyHint: true,
|
|
@@ -2675,15 +3096,29 @@ var getUsageSummaryTool = {
|
|
|
2675
3096
|
return ok(result.value);
|
|
2676
3097
|
}
|
|
2677
3098
|
};
|
|
3099
|
+
var TransactionTypeEnum = z.enum([
|
|
3100
|
+
"initial_balance",
|
|
3101
|
+
"top_up_manual",
|
|
3102
|
+
"usage_charge",
|
|
3103
|
+
"subscription_renewal",
|
|
3104
|
+
"subscription_upgrade",
|
|
3105
|
+
"admin_adjustment",
|
|
3106
|
+
"refund",
|
|
3107
|
+
"invoice_settlement",
|
|
3108
|
+
"crypto_top_up"
|
|
3109
|
+
]);
|
|
2678
3110
|
var ListBalanceHistoryInputShape = {
|
|
2679
3111
|
date_from: z.string().date().optional().describe("ISO date, inclusive."),
|
|
2680
3112
|
date_to: z.string().date().optional().describe("ISO date, inclusive."),
|
|
3113
|
+
type: z.array(TransactionTypeEnum).max(9).optional().describe(
|
|
3114
|
+
"Filter by transaction kind. Pass several values to OR them (e.g. ['top_up_manual','crypto_top_up'] for credits-only)."
|
|
3115
|
+
),
|
|
2681
3116
|
page: z.number().int().min(1).max(500).default(1).describe("1-indexed page."),
|
|
2682
3117
|
limit: z.number().int().min(1).max(200).default(50).describe("Page size.")
|
|
2683
3118
|
};
|
|
2684
3119
|
var listBalanceHistoryTool = {
|
|
2685
3120
|
name: "list_balance_history",
|
|
2686
|
-
description: "List ledger transactions (charges, refunds, top-ups, invoice settlements) on the organization's balance. Each row: type, amount in micros, description, timestamp.",
|
|
3121
|
+
description: "List ledger transactions (charges, refunds, top-ups, invoice settlements) on the organization's balance. Each row: type, amount in micros, description, timestamp. Filter by `type` (multi-select) and / or date range.",
|
|
2687
3122
|
annotations: {
|
|
2688
3123
|
title: "List Balance History",
|
|
2689
3124
|
readOnlyHint: true,
|
|
@@ -2697,7 +3132,8 @@ var listBalanceHistoryTool = {
|
|
|
2697
3132
|
page: input.page,
|
|
2698
3133
|
limit: input.limit,
|
|
2699
3134
|
...input.date_from !== void 0 ? { date_from: input.date_from } : {},
|
|
2700
|
-
...input.date_to !== void 0 ? { date_to: input.date_to } : {}
|
|
3135
|
+
...input.date_to !== void 0 ? { date_to: input.date_to } : {},
|
|
3136
|
+
...input.type !== void 0 ? { type: input.type } : {}
|
|
2701
3137
|
};
|
|
2702
3138
|
const result = await ctx.api.listBalanceHistory(filters);
|
|
2703
3139
|
if (result.isErr()) return err(mapApiError(result.error));
|
|
@@ -2705,8 +3141,10 @@ var listBalanceHistoryTool = {
|
|
|
2705
3141
|
}
|
|
2706
3142
|
};
|
|
2707
3143
|
var ListUsageInputShape = {
|
|
2708
|
-
date_from: z.string().
|
|
2709
|
-
|
|
3144
|
+
date_from: z.string().datetime({ offset: true }).optional().describe(
|
|
3145
|
+
"ISO 8601 datetime (with timezone offset), inclusive lower bound on the usage timestamp. Plain dates also work \u2014 the API normalises to UTC midnight."
|
|
3146
|
+
),
|
|
3147
|
+
date_to: z.string().datetime({ offset: true }).optional().describe("ISO 8601 datetime (with offset), inclusive upper bound."),
|
|
2710
3148
|
scan_id: z.string().uuid().optional().describe("Filter to one scan's cost rows."),
|
|
2711
3149
|
page: z.number().int().min(1).max(500).default(1).describe("1-indexed page."),
|
|
2712
3150
|
limit: z.number().int().min(1).max(200).default(50).describe("Page size.")
|
|
@@ -3070,12 +3508,16 @@ var listCampaignRunsTool = {
|
|
|
3070
3508
|
};
|
|
3071
3509
|
var ListCampaignsInputShape = {
|
|
3072
3510
|
group_id: z.string().uuid().optional().describe("Optional campaign-group UUID to filter by."),
|
|
3511
|
+
archived: z.boolean().optional().describe(
|
|
3512
|
+
"When omitted, the API returns active campaigns only. Pass `true` to see archived campaigns, `false` for active-only (explicit)."
|
|
3513
|
+
),
|
|
3514
|
+
q: z.string().min(1).max(200).optional().describe("Substring search against campaign name (case-insensitive)."),
|
|
3073
3515
|
page: z.number().int().min(1).max(500).default(1).describe("1-indexed page number."),
|
|
3074
3516
|
limit: z.number().int().min(1).max(200).default(50).describe("Page size (1-200).")
|
|
3075
3517
|
};
|
|
3076
3518
|
var listCampaignsTool = {
|
|
3077
3519
|
name: "list_campaigns",
|
|
3078
|
-
description: "List campaigns for the caller's organization, optionally filtered by group,
|
|
3520
|
+
description: "List campaigns for the caller's organization, optionally filtered by group, archived flag, or name substring. Paginated.",
|
|
3079
3521
|
annotations: {
|
|
3080
3522
|
title: "List Campaigns",
|
|
3081
3523
|
readOnlyHint: true,
|
|
@@ -3088,14 +3530,21 @@ var listCampaignsTool = {
|
|
|
3088
3530
|
const filters = {
|
|
3089
3531
|
page: input.page,
|
|
3090
3532
|
limit: input.limit,
|
|
3091
|
-
...input.group_id !== void 0 ? { group_id: input.group_id } : {}
|
|
3533
|
+
...input.group_id !== void 0 ? { group_id: input.group_id } : {},
|
|
3534
|
+
...input.archived !== void 0 ? { archived: input.archived } : {},
|
|
3535
|
+
...input.q !== void 0 ? { q: input.q } : {}
|
|
3092
3536
|
};
|
|
3093
3537
|
const result = await ctx.api.listCampaigns(filters);
|
|
3094
3538
|
if (result.isErr()) return err(mapApiError(result.error));
|
|
3095
3539
|
return ok(result.value);
|
|
3096
3540
|
}
|
|
3097
3541
|
};
|
|
3098
|
-
var ListCampaignsPickerInputShape = {
|
|
3542
|
+
var ListCampaignsPickerInputShape = {
|
|
3543
|
+
archived: z.boolean().optional().describe("Pass true to include archived campaigns. Defaults to active-only."),
|
|
3544
|
+
group_id: z.string().uuid().optional().describe("Filter to one campaign group."),
|
|
3545
|
+
q: z.string().min(1).max(200).optional().describe("Substring search against campaign name (case-insensitive)."),
|
|
3546
|
+
limit: z.number().int().min(1).max(500).optional().describe("Maximum rows to return (default per API, typically 200).")
|
|
3547
|
+
};
|
|
3099
3548
|
var listCampaignsPickerTool = {
|
|
3100
3549
|
name: "list_campaigns_picker",
|
|
3101
3550
|
description: "Slim per-row campaign list for selection UIs \u2014 id, name, group_id, is_archived. Cheaper than `list_campaigns` for orgs with thousands of campaigns. Use `get_campaign(id)` after a selection to fetch full details.",
|
|
@@ -3107,8 +3556,16 @@ var listCampaignsPickerTool = {
|
|
|
3107
3556
|
openWorldHint: false
|
|
3108
3557
|
},
|
|
3109
3558
|
inputSchema: z.object(ListCampaignsPickerInputShape),
|
|
3110
|
-
handler: async (
|
|
3111
|
-
const
|
|
3559
|
+
handler: async (input, ctx) => {
|
|
3560
|
+
const filters = {
|
|
3561
|
+
...input.archived !== void 0 ? { archived: input.archived } : {},
|
|
3562
|
+
...input.group_id !== void 0 ? { group_id: input.group_id } : {},
|
|
3563
|
+
...input.q !== void 0 ? { q: input.q } : {},
|
|
3564
|
+
...input.limit !== void 0 ? { limit: input.limit } : {}
|
|
3565
|
+
};
|
|
3566
|
+
const result = await ctx.api.listCampaignsPicker(
|
|
3567
|
+
Object.keys(filters).length > 0 ? filters : void 0
|
|
3568
|
+
);
|
|
3112
3569
|
if (result.isErr()) return err(mapApiError(result.error));
|
|
3113
3570
|
return ok(result.value);
|
|
3114
3571
|
}
|
|
@@ -3340,6 +3797,196 @@ var updateCustomRuleTool = {
|
|
|
3340
3797
|
return ok(result.value);
|
|
3341
3798
|
}
|
|
3342
3799
|
};
|
|
3800
|
+
var TaxonomyNodeShape = z.object({
|
|
3801
|
+
client_id: z.string().min(1).max(100).describe(
|
|
3802
|
+
"Caller-chosen string id used to wire parent/child links inside this request only. The API allocates real UUIDs on response."
|
|
3803
|
+
),
|
|
3804
|
+
parent_client_id: z.string().min(1).max(100).nullable().optional().describe("client_id of this node's parent. null/omitted = top-level node."),
|
|
3805
|
+
name: z.string().min(1).max(100).describe("Display name of the node."),
|
|
3806
|
+
description: z.string().max(200).optional().describe(
|
|
3807
|
+
"Free-form description shown to the LLM during classification \u2014 keep it concrete (one sentence)."
|
|
3808
|
+
),
|
|
3809
|
+
is_default: z.boolean().optional().describe(
|
|
3810
|
+
"Mark this node as the fallback bucket. Exactly ONE node per taxonomy must be is_default=true."
|
|
3811
|
+
)
|
|
3812
|
+
});
|
|
3813
|
+
|
|
3814
|
+
// src/application/tools/custom-taxonomies/create-custom-taxonomy.tool.ts
|
|
3815
|
+
var CreateCustomTaxonomyInputShape = {
|
|
3816
|
+
name: z.string().min(1).max(100).describe("Display name (1-100 chars)."),
|
|
3817
|
+
description: z.string().max(500).optional().describe("Free-form description (defaults to empty string)."),
|
|
3818
|
+
nodes: z.array(TaxonomyNodeShape).max(2e3).optional().describe(
|
|
3819
|
+
"Initial tree as a flat array (parents before children, linked via client_id / parent_client_id). Empty / omitted = empty taxonomy."
|
|
3820
|
+
)
|
|
3821
|
+
};
|
|
3822
|
+
var createCustomTaxonomyTool = {
|
|
3823
|
+
name: "create_custom_taxonomy",
|
|
3824
|
+
description: "Create a custom classification taxonomy with its initial tree. Exactly one node should have is_default=true (fallback for scans the LLM cannot classify confidently). Returns the persisted taxonomy with allocated node UUIDs and version=1.",
|
|
3825
|
+
annotations: {
|
|
3826
|
+
title: "Create Custom Taxonomy",
|
|
3827
|
+
readOnlyHint: false,
|
|
3828
|
+
destructiveHint: false,
|
|
3829
|
+
idempotentHint: false,
|
|
3830
|
+
openWorldHint: false
|
|
3831
|
+
},
|
|
3832
|
+
inputSchema: z.object(CreateCustomTaxonomyInputShape),
|
|
3833
|
+
handler: async (input, ctx) => {
|
|
3834
|
+
const result = await ctx.api.createCustomTaxonomy({
|
|
3835
|
+
name: input.name,
|
|
3836
|
+
description: input.description ?? "",
|
|
3837
|
+
nodes: (input.nodes ?? []).map(toRequestNode)
|
|
3838
|
+
});
|
|
3839
|
+
if (result.isErr()) return err(mapApiError(result.error));
|
|
3840
|
+
return ok(result.value);
|
|
3841
|
+
}
|
|
3842
|
+
};
|
|
3843
|
+
function toRequestNode(n) {
|
|
3844
|
+
return {
|
|
3845
|
+
client_id: n.client_id,
|
|
3846
|
+
parent_client_id: n.parent_client_id ?? null,
|
|
3847
|
+
name: n.name,
|
|
3848
|
+
description: n.description ?? "",
|
|
3849
|
+
is_default: n.is_default ?? false
|
|
3850
|
+
};
|
|
3851
|
+
}
|
|
3852
|
+
var DeleteCustomTaxonomyInputShape = {
|
|
3853
|
+
taxonomy_id: z.string().uuid().describe("Custom taxonomy UUID.")
|
|
3854
|
+
};
|
|
3855
|
+
var deleteCustomTaxonomyTool = {
|
|
3856
|
+
name: "delete_custom_taxonomy",
|
|
3857
|
+
description: "Soft-delete a custom taxonomy (sets is_active=false). Historical scan classifications keep referencing the id; new scans skip this taxonomy. Use `restore_custom_taxonomy` to undo.",
|
|
3858
|
+
annotations: {
|
|
3859
|
+
title: "Delete Custom Taxonomy",
|
|
3860
|
+
readOnlyHint: false,
|
|
3861
|
+
destructiveHint: true,
|
|
3862
|
+
// Soft-delete: a second call returns 404 for the same id but
|
|
3863
|
+
// does not change observable state — same convention used by
|
|
3864
|
+
// `delete_policy_set` and `delete_tag_definition`.
|
|
3865
|
+
idempotentHint: true,
|
|
3866
|
+
openWorldHint: false
|
|
3867
|
+
},
|
|
3868
|
+
inputSchema: z.object(DeleteCustomTaxonomyInputShape),
|
|
3869
|
+
handler: async (input, ctx) => {
|
|
3870
|
+
const result = await ctx.api.deleteCustomTaxonomy(input.taxonomy_id);
|
|
3871
|
+
if (result.isErr()) return err(mapApiError(result.error));
|
|
3872
|
+
return ok({ deleted: true });
|
|
3873
|
+
}
|
|
3874
|
+
};
|
|
3875
|
+
var GetCustomTaxonomyInputShape = {
|
|
3876
|
+
taxonomy_id: z.string().uuid().describe("Custom taxonomy UUID.")
|
|
3877
|
+
};
|
|
3878
|
+
var getCustomTaxonomyTool = {
|
|
3879
|
+
name: "get_custom_taxonomy",
|
|
3880
|
+
description: "Get one custom taxonomy by UUID with its full node tree (each node has id, parent_id, level, position, name, description, is_default).",
|
|
3881
|
+
annotations: {
|
|
3882
|
+
title: "Get Custom Taxonomy",
|
|
3883
|
+
readOnlyHint: true,
|
|
3884
|
+
destructiveHint: false,
|
|
3885
|
+
idempotentHint: true,
|
|
3886
|
+
openWorldHint: false
|
|
3887
|
+
},
|
|
3888
|
+
inputSchema: z.object(GetCustomTaxonomyInputShape),
|
|
3889
|
+
handler: async (input, ctx) => {
|
|
3890
|
+
const result = await ctx.api.getCustomTaxonomy(input.taxonomy_id);
|
|
3891
|
+
if (result.isErr()) return err(mapApiError(result.error));
|
|
3892
|
+
return ok(result.value);
|
|
3893
|
+
}
|
|
3894
|
+
};
|
|
3895
|
+
var ListCustomTaxonomiesInputShape = {};
|
|
3896
|
+
var listCustomTaxonomiesTool = {
|
|
3897
|
+
name: "list_custom_taxonomies",
|
|
3898
|
+
description: "List the calling org's custom classification taxonomies. Returns slim summaries (id, name, slug, version, node_count, is_active). Soft-deleted taxonomies are included with `is_active=false`. Fetch the full tree via `get_custom_taxonomy`.",
|
|
3899
|
+
annotations: {
|
|
3900
|
+
title: "List Custom Taxonomies",
|
|
3901
|
+
readOnlyHint: true,
|
|
3902
|
+
destructiveHint: false,
|
|
3903
|
+
idempotentHint: true,
|
|
3904
|
+
openWorldHint: false
|
|
3905
|
+
},
|
|
3906
|
+
inputSchema: z.object(ListCustomTaxonomiesInputShape),
|
|
3907
|
+
handler: async (_input, ctx) => {
|
|
3908
|
+
const result = await ctx.api.listCustomTaxonomies();
|
|
3909
|
+
if (result.isErr()) return err(mapApiError(result.error));
|
|
3910
|
+
return ok({ items: result.value });
|
|
3911
|
+
}
|
|
3912
|
+
};
|
|
3913
|
+
var ParseCustomTaxonomyTextInputShape = {
|
|
3914
|
+
text: z.string().min(1).max(5e4).describe(
|
|
3915
|
+
"Free-form text describing the tree (one node per line; indentation expresses depth). Up to 50 000 chars."
|
|
3916
|
+
)
|
|
3917
|
+
};
|
|
3918
|
+
var parseCustomTaxonomyTextTool = {
|
|
3919
|
+
name: "parse_custom_taxonomy_text",
|
|
3920
|
+
description: "Preview-parse pasted free-form text into a taxonomy tree (NOT persisted). Returns `nodes: [{level, name, description}]` + `warnings: string[]`. After review, persist via `create_custom_taxonomy` (remember to flag exactly one node as is_default).",
|
|
3921
|
+
annotations: {
|
|
3922
|
+
title: "Parse Custom Taxonomy Text",
|
|
3923
|
+
readOnlyHint: true,
|
|
3924
|
+
destructiveHint: false,
|
|
3925
|
+
idempotentHint: true,
|
|
3926
|
+
openWorldHint: false
|
|
3927
|
+
},
|
|
3928
|
+
inputSchema: z.object(ParseCustomTaxonomyTextInputShape),
|
|
3929
|
+
handler: async (input, ctx) => {
|
|
3930
|
+
const result = await ctx.api.parseCustomTaxonomyText({ text: input.text });
|
|
3931
|
+
if (result.isErr()) return err(mapApiError(result.error));
|
|
3932
|
+
return ok(result.value);
|
|
3933
|
+
}
|
|
3934
|
+
};
|
|
3935
|
+
var RestoreCustomTaxonomyInputShape = {
|
|
3936
|
+
taxonomy_id: z.string().uuid().describe("Custom taxonomy UUID (must currently be is_active=false).")
|
|
3937
|
+
};
|
|
3938
|
+
var restoreCustomTaxonomyTool = {
|
|
3939
|
+
name: "restore_custom_taxonomy",
|
|
3940
|
+
description: "Re-activate a previously soft-deleted custom taxonomy. Returns the restored taxonomy with its full tree (is_active=true).",
|
|
3941
|
+
annotations: {
|
|
3942
|
+
title: "Restore Custom Taxonomy",
|
|
3943
|
+
readOnlyHint: false,
|
|
3944
|
+
destructiveHint: false,
|
|
3945
|
+
idempotentHint: true,
|
|
3946
|
+
openWorldHint: false
|
|
3947
|
+
},
|
|
3948
|
+
inputSchema: z.object(RestoreCustomTaxonomyInputShape),
|
|
3949
|
+
handler: async (input, ctx) => {
|
|
3950
|
+
const result = await ctx.api.restoreCustomTaxonomy(input.taxonomy_id);
|
|
3951
|
+
if (result.isErr()) return err(mapApiError(result.error));
|
|
3952
|
+
return ok(result.value);
|
|
3953
|
+
}
|
|
3954
|
+
};
|
|
3955
|
+
var UpdateCustomTaxonomyInputShape = {
|
|
3956
|
+
taxonomy_id: z.string().uuid().describe("Custom taxonomy UUID."),
|
|
3957
|
+
name: z.string().min(1).max(100).describe("New display name."),
|
|
3958
|
+
description: z.string().max(500).optional().describe("New description (defaults to empty string)."),
|
|
3959
|
+
nodes: z.array(TaxonomyNodeShape).max(2e3).optional().describe(
|
|
3960
|
+
"REPLACEMENT tree as a flat array (REPLACES the existing tree, not a merge). Read the current tree via `get_custom_taxonomy` first if you only want to tweak one node."
|
|
3961
|
+
)
|
|
3962
|
+
};
|
|
3963
|
+
var updateCustomTaxonomyTool = {
|
|
3964
|
+
name: "update_custom_taxonomy",
|
|
3965
|
+
description: "REPLACE a custom taxonomy's name, description, and full tree atomically. The API bumps `version` on every successful update; ongoing scan classifications continue with the previous tree until they finish, so updates are safe but not retroactive.",
|
|
3966
|
+
annotations: {
|
|
3967
|
+
title: "Update Custom Taxonomy",
|
|
3968
|
+
readOnlyHint: false,
|
|
3969
|
+
destructiveHint: false,
|
|
3970
|
+
idempotentHint: true,
|
|
3971
|
+
openWorldHint: false
|
|
3972
|
+
},
|
|
3973
|
+
inputSchema: z.object(UpdateCustomTaxonomyInputShape),
|
|
3974
|
+
handler: async (input, ctx) => {
|
|
3975
|
+
const result = await ctx.api.updateCustomTaxonomy(input.taxonomy_id, {
|
|
3976
|
+
name: input.name,
|
|
3977
|
+
description: input.description ?? "",
|
|
3978
|
+
nodes: (input.nodes ?? []).map((n) => ({
|
|
3979
|
+
client_id: n.client_id,
|
|
3980
|
+
parent_client_id: n.parent_client_id ?? null,
|
|
3981
|
+
name: n.name,
|
|
3982
|
+
description: n.description ?? "",
|
|
3983
|
+
is_default: n.is_default ?? false
|
|
3984
|
+
}))
|
|
3985
|
+
});
|
|
3986
|
+
if (result.isErr()) return err(mapApiError(result.error));
|
|
3987
|
+
return ok(result.value);
|
|
3988
|
+
}
|
|
3989
|
+
};
|
|
3343
3990
|
var ListEmulatorsInputShape = {};
|
|
3344
3991
|
var listEmulatorsTool = {
|
|
3345
3992
|
name: "list_emulators",
|
|
@@ -3378,13 +4025,72 @@ var listGeosTool = {
|
|
|
3378
4025
|
return ok({ items: result.value, total: result.value.length });
|
|
3379
4026
|
}
|
|
3380
4027
|
};
|
|
4028
|
+
|
|
4029
|
+
// src/application/tools/_shared/binary-content.ts
|
|
4030
|
+
function imageBlock(bytes, mimeType) {
|
|
4031
|
+
return {
|
|
4032
|
+
content: [
|
|
4033
|
+
{
|
|
4034
|
+
type: "image",
|
|
4035
|
+
data: Buffer.from(bytes).toString("base64"),
|
|
4036
|
+
mimeType
|
|
4037
|
+
}
|
|
4038
|
+
]
|
|
4039
|
+
};
|
|
4040
|
+
}
|
|
4041
|
+
function resourceBlock(bytes, mimeType, uri) {
|
|
4042
|
+
return {
|
|
4043
|
+
content: [
|
|
4044
|
+
{
|
|
4045
|
+
type: "resource",
|
|
4046
|
+
resource: {
|
|
4047
|
+
uri,
|
|
4048
|
+
mimeType,
|
|
4049
|
+
blob: Buffer.from(bytes).toString("base64")
|
|
4050
|
+
}
|
|
4051
|
+
}
|
|
4052
|
+
]
|
|
4053
|
+
};
|
|
4054
|
+
}
|
|
4055
|
+
|
|
4056
|
+
// src/application/tools/invoicing/get-invoice-pdf.tool.ts
|
|
4057
|
+
var GetInvoicePdfInputShape = {
|
|
4058
|
+
invoice_id: z.string().uuid().describe("Invoice UUID \u2014 see `list_invoices`.")
|
|
4059
|
+
};
|
|
4060
|
+
var getInvoicePdfTool = {
|
|
4061
|
+
name: "get_invoice_pdf",
|
|
4062
|
+
description: "Download one invoice as an inline PDF (base64-encoded). Returned as a single MCP resource content block \u2014 agents can save / forward it without a second API call.",
|
|
4063
|
+
annotations: {
|
|
4064
|
+
title: "Get Invoice PDF",
|
|
4065
|
+
readOnlyHint: true,
|
|
4066
|
+
destructiveHint: false,
|
|
4067
|
+
idempotentHint: true,
|
|
4068
|
+
openWorldHint: false
|
|
4069
|
+
},
|
|
4070
|
+
inputSchema: z.object(GetInvoicePdfInputShape),
|
|
4071
|
+
handler: async (input, ctx) => {
|
|
4072
|
+
const result = await ctx.api.getInvoicePdf(input.invoice_id);
|
|
4073
|
+
if (result.isErr()) return err(mapApiError(result.error));
|
|
4074
|
+
return ok(
|
|
4075
|
+
resourceBlock(
|
|
4076
|
+
result.value.bytes,
|
|
4077
|
+
result.value.contentType,
|
|
4078
|
+
`kaminari-ad://invoices/${input.invoice_id}.pdf`
|
|
4079
|
+
)
|
|
4080
|
+
);
|
|
4081
|
+
}
|
|
4082
|
+
};
|
|
3381
4083
|
var ListInvoicesInputShape = {
|
|
4084
|
+
type: z.enum(["proforma", "final"]).optional().describe(
|
|
4085
|
+
"Filter by invoice kind: proforma (advance bill) or final (issued after the period)."
|
|
4086
|
+
),
|
|
4087
|
+
status: z.enum(["draft", "issued", "paid", "voided", "overdue"]).optional().describe("Filter by lifecycle status."),
|
|
3382
4088
|
page: z.number().int().min(1).max(500).default(1).describe("1-indexed page."),
|
|
3383
4089
|
limit: z.number().int().min(1).max(200).default(50).describe("Page size.")
|
|
3384
4090
|
};
|
|
3385
4091
|
var listInvoicesTool = {
|
|
3386
4092
|
name: "list_invoices",
|
|
3387
|
-
description: "List invoices issued to the organization with number, status, total in micros, currency, due/paid dates.
|
|
4093
|
+
description: "List invoices issued to the organization with number, type, status, total in micros, currency, due/paid dates. Filter by `type` and / or `status`. Use `get_invoice_pdf` to download the PDF for a specific invoice.",
|
|
3388
4094
|
annotations: {
|
|
3389
4095
|
title: "List Invoices",
|
|
3390
4096
|
readOnlyHint: true,
|
|
@@ -3394,23 +4100,123 @@ var listInvoicesTool = {
|
|
|
3394
4100
|
},
|
|
3395
4101
|
inputSchema: z.object(ListInvoicesInputShape),
|
|
3396
4102
|
handler: async (input, ctx) => {
|
|
3397
|
-
const
|
|
4103
|
+
const filters = {
|
|
4104
|
+
page: input.page,
|
|
4105
|
+
limit: input.limit,
|
|
4106
|
+
...input.type !== void 0 ? { type: input.type } : {},
|
|
4107
|
+
...input.status !== void 0 ? { status: input.status } : {}
|
|
4108
|
+
};
|
|
4109
|
+
const result = await ctx.api.listInvoices(filters);
|
|
3398
4110
|
if (result.isErr()) return err(mapApiError(result.error));
|
|
3399
4111
|
return ok(result.value);
|
|
3400
4112
|
}
|
|
3401
4113
|
};
|
|
3402
|
-
var
|
|
3403
|
-
|
|
3404
|
-
|
|
4114
|
+
var TIER1 = z.string().min(1).max(200);
|
|
4115
|
+
var TIER_OPT = z.string().max(200).nullable().optional();
|
|
4116
|
+
var IabV3Block = z.object({
|
|
4117
|
+
tier1: TIER1.describe("Top-level IAB Content Taxonomy V3 category (e.g. 'Sensitive Topics')."),
|
|
4118
|
+
tier2: TIER_OPT.describe("Sub-category (optional). Empty/null = subtree match."),
|
|
4119
|
+
tier3: TIER_OPT.describe("Sub-sub-category (optional)."),
|
|
4120
|
+
tier4: TIER_OPT.describe(
|
|
4121
|
+
"Leaf-level category (optional). When all 4 tiers set, leaf-only match."
|
|
4122
|
+
)
|
|
4123
|
+
});
|
|
4124
|
+
var AiCategoryBlock = z.object({
|
|
4125
|
+
tier1: TIER1.describe("Top-level freeform AI-generated category (e.g. 'Gambling')."),
|
|
4126
|
+
tier2: TIER_OPT.describe("Sub-category (optional)."),
|
|
4127
|
+
tier3: TIER_OPT.describe("Sub-sub-category (optional)."),
|
|
4128
|
+
tier4: TIER_OPT.describe("Leaf-level category (optional).")
|
|
4129
|
+
});
|
|
4130
|
+
var CustomTaxonomyBlock = z.object({
|
|
4131
|
+
taxonomy_id: z.string().uuid().describe("ID of the per-org custom taxonomy (see `list_custom_taxonomies`)."),
|
|
4132
|
+
tier1: TIER1.describe("Top-level node name in the taxonomy."),
|
|
4133
|
+
tier2: TIER_OPT.describe("Tier 2 node name (optional)."),
|
|
4134
|
+
tier3: TIER_OPT.describe("Tier 3 node name (optional)."),
|
|
4135
|
+
tier4: TIER_OPT.describe("Leaf node name (optional).")
|
|
3405
4136
|
});
|
|
4137
|
+
var COUNTRY_CODES = z.array(z.string().min(2).max(3)).max(50).describe("Restrict the rule to these countries (ISO 3166-1 alpha-2 / alpha-3). Empty = all.");
|
|
4138
|
+
var PolicyEntryInput = z.discriminatedUnion("rule_type", [
|
|
4139
|
+
z.object({
|
|
4140
|
+
rule_type: z.literal("tag").describe("Match a specific tag slug emitted by the scan pipeline."),
|
|
4141
|
+
tag_slug: z.string().min(1).max(100).describe("Tag slug (see `list_tags` for the catalogue)."),
|
|
4142
|
+
country_codes: COUNTRY_CODES
|
|
4143
|
+
}),
|
|
4144
|
+
z.object({
|
|
4145
|
+
rule_type: z.literal("iab_v3").describe("Match the scan's canonical IAB V3 category prefix."),
|
|
4146
|
+
iab_v3: IabV3Block,
|
|
4147
|
+
country_codes: COUNTRY_CODES
|
|
4148
|
+
}),
|
|
4149
|
+
z.object({
|
|
4150
|
+
rule_type: z.literal("brand").describe("Match the scan's advertiser brand (case-insensitive)."),
|
|
4151
|
+
brand: z.string().min(1).max(200).describe("Brand string."),
|
|
4152
|
+
country_codes: COUNTRY_CODES
|
|
4153
|
+
}),
|
|
4154
|
+
z.object({
|
|
4155
|
+
rule_type: z.literal("ai_category").describe("Match the freeform LLM-generated category prefix on the scan."),
|
|
4156
|
+
ai_category: AiCategoryBlock,
|
|
4157
|
+
country_codes: COUNTRY_CODES
|
|
4158
|
+
}),
|
|
4159
|
+
z.object({
|
|
4160
|
+
rule_type: z.literal("custom_taxonomy").describe("Match a per-org custom taxonomy node prefix on the scan."),
|
|
4161
|
+
custom_taxonomy: CustomTaxonomyBlock,
|
|
4162
|
+
country_codes: COUNTRY_CODES
|
|
4163
|
+
})
|
|
4164
|
+
]).describe(
|
|
4165
|
+
"One policy rule. Discriminated by `rule_type`; populate the matching value-block (tag_slug / iab_v3 / brand / ai_category / custom_taxonomy)."
|
|
4166
|
+
);
|
|
4167
|
+
function policyEntryToRequest(entry) {
|
|
4168
|
+
const base = {
|
|
4169
|
+
rule_type: entry.rule_type,
|
|
4170
|
+
tag_slug: null,
|
|
4171
|
+
iab_v3: null,
|
|
4172
|
+
brand: null,
|
|
4173
|
+
ai_category: null,
|
|
4174
|
+
custom_taxonomy: null,
|
|
4175
|
+
country_codes: [...entry.country_codes]
|
|
4176
|
+
};
|
|
4177
|
+
if (entry.rule_type === "tag") {
|
|
4178
|
+
return { ...base, tag_slug: entry.tag_slug };
|
|
4179
|
+
}
|
|
4180
|
+
if (entry.rule_type === "iab_v3") {
|
|
4181
|
+
return { ...base, iab_v3: normaliseTiers(entry.iab_v3) };
|
|
4182
|
+
}
|
|
4183
|
+
if (entry.rule_type === "brand") {
|
|
4184
|
+
return { ...base, brand: entry.brand };
|
|
4185
|
+
}
|
|
4186
|
+
if (entry.rule_type === "ai_category") {
|
|
4187
|
+
return { ...base, ai_category: normaliseTiers(entry.ai_category) };
|
|
4188
|
+
}
|
|
4189
|
+
return { ...base, custom_taxonomy: normaliseCustomTaxonomy(entry.custom_taxonomy) };
|
|
4190
|
+
}
|
|
4191
|
+
function normaliseTiers(t) {
|
|
4192
|
+
return {
|
|
4193
|
+
tier1: t.tier1,
|
|
4194
|
+
tier2: t.tier2 ?? null,
|
|
4195
|
+
tier3: t.tier3 ?? null,
|
|
4196
|
+
tier4: t.tier4 ?? null
|
|
4197
|
+
};
|
|
4198
|
+
}
|
|
4199
|
+
function normaliseCustomTaxonomy(t) {
|
|
4200
|
+
return {
|
|
4201
|
+
taxonomy_id: t.taxonomy_id,
|
|
4202
|
+
tier1: t.tier1,
|
|
4203
|
+
tier2: t.tier2 ?? null,
|
|
4204
|
+
tier3: t.tier3 ?? null,
|
|
4205
|
+
tier4: t.tier4 ?? null
|
|
4206
|
+
};
|
|
4207
|
+
}
|
|
4208
|
+
|
|
4209
|
+
// src/application/tools/policy-sets/create-policy-set.tool.ts
|
|
3406
4210
|
var CreatePolicySetInputShape = {
|
|
3407
4211
|
name: z.string().min(1).max(200).describe("Display name."),
|
|
3408
4212
|
description: z.string().max(2e3).describe("Free-form description (use empty string for none)."),
|
|
3409
|
-
entries: z.array(
|
|
4213
|
+
entries: z.array(PolicyEntryInput).min(1).max(500).describe(
|
|
4214
|
+
"At least one entry. Each entry is a discriminated union over five rule kinds: tag / iab_v3 / brand / ai_category / custom_taxonomy."
|
|
4215
|
+
)
|
|
3410
4216
|
};
|
|
3411
4217
|
var createPolicySetTool = {
|
|
3412
4218
|
name: "create_policy_set",
|
|
3413
|
-
description: "Create a new policy set (named collection of tag
|
|
4219
|
+
description: "Create a new policy set (named collection of violation rules). Each rule is one of: tag slug, IAB V3 category prefix, advertiser brand, freeform AI category, or per-org custom-taxonomy node. Bind campaigns to the set via `update_campaign`.",
|
|
3414
4220
|
annotations: {
|
|
3415
4221
|
title: "Create Policy Set",
|
|
3416
4222
|
readOnlyHint: false,
|
|
@@ -3423,7 +4229,7 @@ var createPolicySetTool = {
|
|
|
3423
4229
|
const result = await ctx.api.createPolicySet({
|
|
3424
4230
|
name: input.name,
|
|
3425
4231
|
description: input.description,
|
|
3426
|
-
entries: input.entries.map(
|
|
4232
|
+
entries: input.entries.map(policyEntryToRequest)
|
|
3427
4233
|
});
|
|
3428
4234
|
if (result.isErr()) return err(mapApiError(result.error));
|
|
3429
4235
|
return ok(result.value);
|
|
@@ -3454,7 +4260,7 @@ var GetPolicySetInputShape = {
|
|
|
3454
4260
|
};
|
|
3455
4261
|
var getPolicySetTool = {
|
|
3456
4262
|
name: "get_policy_set",
|
|
3457
|
-
description: "Get one policy set by UUID with its complete list of entries (tag
|
|
4263
|
+
description: "Get one policy set by UUID with its complete list of entries (each entry is one of five rule kinds \u2014 tag / iab_v3 / brand / ai_category / custom_taxonomy \u2014 plus applicable country codes).",
|
|
3458
4264
|
annotations: {
|
|
3459
4265
|
title: "Get Policy Set",
|
|
3460
4266
|
readOnlyHint: true,
|
|
@@ -3471,11 +4277,14 @@ var getPolicySetTool = {
|
|
|
3471
4277
|
};
|
|
3472
4278
|
var ListPolicySetsInputShape = {
|
|
3473
4279
|
page: z.number().int().min(1).max(500).default(1).describe("1-indexed page number."),
|
|
3474
|
-
limit: z.number().int().min(1).max(200).default(50).describe("Page size.")
|
|
4280
|
+
limit: z.number().int().min(1).max(200).default(50).describe("Page size."),
|
|
4281
|
+
visibility: z.enum(["private", "public"]).optional().describe(
|
|
4282
|
+
"Narrow to one scope. `private` = org-owned only, `public` = Kaminari Ad-curated sets visible to every org. Omit the filter to see BOTH combined."
|
|
4283
|
+
)
|
|
3475
4284
|
};
|
|
3476
4285
|
var listPolicySetsTool = {
|
|
3477
4286
|
name: "list_policy_sets",
|
|
3478
|
-
description: "Paginated list of policy sets: named collections of (tag
|
|
4287
|
+
description: "Paginated list of policy sets: named collections of violation rules (tag / IAB V3 / brand / AI category / custom-taxonomy entries) that define what counts as a violation. Campaigns bind to one policy set. Returns `{items, total, page, limit}`. List items omit `entries` for payload size \u2014 fetch a single set via `get_policy_set` when you need them. Use `visibility=public` to discover Kaminari Ad-curated sets.",
|
|
3479
4288
|
annotations: {
|
|
3480
4289
|
title: "List Policy Sets",
|
|
3481
4290
|
readOnlyHint: true,
|
|
@@ -3485,7 +4294,11 @@ var listPolicySetsTool = {
|
|
|
3485
4294
|
},
|
|
3486
4295
|
inputSchema: z.object(ListPolicySetsInputShape),
|
|
3487
4296
|
handler: async (input, ctx) => {
|
|
3488
|
-
const result = await ctx.api.listPolicySets({
|
|
4297
|
+
const result = await ctx.api.listPolicySets({
|
|
4298
|
+
page: input.page,
|
|
4299
|
+
limit: input.limit,
|
|
4300
|
+
...input.visibility !== void 0 ? { visibility: input.visibility } : {}
|
|
4301
|
+
});
|
|
3489
4302
|
if (result.isErr()) return err(mapApiError(result.error));
|
|
3490
4303
|
return ok(result.value);
|
|
3491
4304
|
}
|
|
@@ -3510,19 +4323,17 @@ var requestPolicySetApprovalTool = {
|
|
|
3510
4323
|
return ok({ requested: true });
|
|
3511
4324
|
}
|
|
3512
4325
|
};
|
|
3513
|
-
var PolicyEntryShape2 = z.object({
|
|
3514
|
-
tag_slug: z.string().min(1).max(100),
|
|
3515
|
-
country_codes: z.array(z.string().length(2)).max(50)
|
|
3516
|
-
});
|
|
3517
4326
|
var UpdatePolicySetInputShape = {
|
|
3518
4327
|
policy_set_id: z.string().uuid().describe("Policy set UUID."),
|
|
3519
4328
|
name: z.string().min(1).max(200).describe("New name (always required by the API on update)."),
|
|
3520
4329
|
description: z.string().max(2e3).describe("New description (empty string allowed)."),
|
|
3521
|
-
entries: z.array(
|
|
4330
|
+
entries: z.array(PolicyEntryInput).min(1).max(500).describe(
|
|
4331
|
+
"REPLACEMENT entries list \u2014 REPLACES the current list, not a merge. Each entry is a discriminated union over five rule kinds (tag / iab_v3 / brand / ai_category / custom_taxonomy)."
|
|
4332
|
+
)
|
|
3522
4333
|
};
|
|
3523
4334
|
var updatePolicySetTool = {
|
|
3524
4335
|
name: "update_policy_set",
|
|
3525
|
-
description: "REPLACE a policy set's name, description, and entry list. The API requires all three fields on every update \u2014 read the current set with `get_policy_set` first if you only want to change one thing.",
|
|
4336
|
+
description: "REPLACE a policy set's name, description, and entry list. The API requires all three fields on every update \u2014 read the current set with `get_policy_set` first if you only want to change one thing. Supports all five rule kinds (tag / iab_v3 / brand / ai_category / custom_taxonomy).",
|
|
3526
4337
|
annotations: {
|
|
3527
4338
|
title: "Update Policy Set",
|
|
3528
4339
|
readOnlyHint: false,
|
|
@@ -3535,7 +4346,7 @@ var updatePolicySetTool = {
|
|
|
3535
4346
|
const result = await ctx.api.updatePolicySet(input.policy_set_id, {
|
|
3536
4347
|
name: input.name,
|
|
3537
4348
|
description: input.description,
|
|
3538
|
-
entries: input.entries.map(
|
|
4349
|
+
entries: input.entries.map(policyEntryToRequest)
|
|
3539
4350
|
});
|
|
3540
4351
|
if (result.isErr()) return err(mapApiError(result.error));
|
|
3541
4352
|
return ok(result.value);
|
|
@@ -3708,22 +4519,110 @@ var getScanTool = {
|
|
|
3708
4519
|
return ok(result.value);
|
|
3709
4520
|
}
|
|
3710
4521
|
};
|
|
4522
|
+
var GetScanCreativeScreenshotInputShape = {
|
|
4523
|
+
scan_id: z.string().uuid().describe("Scan UUID \u2014 must be an ad-tag scan (is_ad_tag=true)."),
|
|
4524
|
+
width: z.number().int().min(50).max(2e3).optional().describe("Optional resize width in pixels.")
|
|
4525
|
+
};
|
|
4526
|
+
var getScanCreativeScreenshotTool = {
|
|
4527
|
+
name: "get_scan_creative_screenshot",
|
|
4528
|
+
description: "Fetch the creative screenshot for an ad-tag scan as an inline image (base64-encoded PNG). Returns 404 if the scan is not an ad-tag scan or has no creative captured yet.",
|
|
4529
|
+
annotations: {
|
|
4530
|
+
title: "Get Scan Creative Screenshot",
|
|
4531
|
+
readOnlyHint: true,
|
|
4532
|
+
destructiveHint: false,
|
|
4533
|
+
idempotentHint: true,
|
|
4534
|
+
openWorldHint: false
|
|
4535
|
+
},
|
|
4536
|
+
inputSchema: z.object(GetScanCreativeScreenshotInputShape),
|
|
4537
|
+
handler: async (input, ctx) => {
|
|
4538
|
+
const result = await ctx.api.getScanCreativeScreenshot(input.scan_id, input.width);
|
|
4539
|
+
if (result.isErr()) return err(mapApiError(result.error));
|
|
4540
|
+
return ok(imageBlock(result.value.bytes, result.value.contentType));
|
|
4541
|
+
}
|
|
4542
|
+
};
|
|
4543
|
+
var GetScanLandingScreenshotInputShape = {
|
|
4544
|
+
scan_id: z.string().uuid().describe("Scan UUID (ad-tag scan)."),
|
|
4545
|
+
landing_ord: z.number().int().min(0).max(50).describe("0-indexed landing slot (see `get_scan(...).landings[*].ord`)."),
|
|
4546
|
+
width: z.number().int().min(50).max(2e3).optional().describe("Optional resize width in pixels.")
|
|
4547
|
+
};
|
|
4548
|
+
var getScanLandingScreenshotTool = {
|
|
4549
|
+
name: "get_scan_landing_screenshot",
|
|
4550
|
+
description: "Fetch the screenshot of one landing tab on an ad-tag scan as an inline image. Use `get_scan` first to discover available `landings[*].ord` values.",
|
|
4551
|
+
annotations: {
|
|
4552
|
+
title: "Get Scan Landing Screenshot",
|
|
4553
|
+
readOnlyHint: true,
|
|
4554
|
+
destructiveHint: false,
|
|
4555
|
+
idempotentHint: true,
|
|
4556
|
+
openWorldHint: false
|
|
4557
|
+
},
|
|
4558
|
+
inputSchema: z.object(GetScanLandingScreenshotInputShape),
|
|
4559
|
+
handler: async (input, ctx) => {
|
|
4560
|
+
const result = await ctx.api.getScanLandingScreenshot(
|
|
4561
|
+
input.scan_id,
|
|
4562
|
+
input.landing_ord,
|
|
4563
|
+
input.width
|
|
4564
|
+
);
|
|
4565
|
+
if (result.isErr()) return err(mapApiError(result.error));
|
|
4566
|
+
return ok(imageBlock(result.value.bytes, result.value.contentType));
|
|
4567
|
+
}
|
|
4568
|
+
};
|
|
4569
|
+
var GetScanScreenshotInputShape = {
|
|
4570
|
+
scan_id: z.string().uuid().describe("Scan UUID."),
|
|
4571
|
+
width: z.number().int().min(50).max(2e3).optional().describe(
|
|
4572
|
+
"Optional resize width in pixels. The API resizes server-side to keep the image small for the agent's context window."
|
|
4573
|
+
)
|
|
4574
|
+
};
|
|
4575
|
+
var getScanScreenshotTool = {
|
|
4576
|
+
name: "get_scan_screenshot",
|
|
4577
|
+
description: "Fetch the primary screenshot for a scan as an inline image (base64-encoded PNG). Pass `width` to request a resized version (50-2000 px). Returns one MCP image content block.",
|
|
4578
|
+
annotations: {
|
|
4579
|
+
title: "Get Scan Screenshot",
|
|
4580
|
+
readOnlyHint: true,
|
|
4581
|
+
destructiveHint: false,
|
|
4582
|
+
idempotentHint: true,
|
|
4583
|
+
openWorldHint: false
|
|
4584
|
+
},
|
|
4585
|
+
inputSchema: z.object(GetScanScreenshotInputShape),
|
|
4586
|
+
handler: async (input, ctx) => {
|
|
4587
|
+
const result = await ctx.api.getScanScreenshot(input.scan_id, input.width);
|
|
4588
|
+
if (result.isErr()) return err(mapApiError(result.error));
|
|
4589
|
+
return ok(imageBlock(result.value.bytes, result.value.contentType));
|
|
4590
|
+
}
|
|
4591
|
+
};
|
|
3711
4592
|
var ListScansInputShape = {
|
|
3712
4593
|
status: z.string().optional().describe(
|
|
3713
|
-
"Comma-separated statuses to filter by.
|
|
4594
|
+
"Comma-separated statuses to filter by. Lifecycle values: pending, running, crawled, checking, checking_async, completed, partial, failed, cancelled."
|
|
3714
4595
|
),
|
|
3715
4596
|
country_code: z.string().optional().describe("Comma-separated ISO 3166-1 alpha-2 country codes, e.g. US,DE,JP."),
|
|
3716
4597
|
url: z.string().optional().describe("Substring match against the scanned URL."),
|
|
3717
4598
|
scan_id: z.string().optional().describe("Comma-separated scan UUIDs to fetch a specific set."),
|
|
3718
4599
|
date_from: z.string().date().optional().describe("ISO date (YYYY-MM-DD), inclusive lower bound on scan creation."),
|
|
3719
4600
|
date_to: z.string().date().optional().describe("ISO date (YYYY-MM-DD), inclusive upper bound on scan creation."),
|
|
4601
|
+
timezone: z.string().optional().describe(
|
|
4602
|
+
"IANA timezone (e.g. 'Europe/Berlin') applied to date_from / date_to. Defaults to UTC."
|
|
4603
|
+
),
|
|
4604
|
+
run_id: z.string().uuid().optional().describe("Filter to scans of one run."),
|
|
4605
|
+
campaign_id: z.string().uuid().optional().describe("Filter to scans of one campaign."),
|
|
4606
|
+
group_id: z.string().uuid().optional().describe("Filter to scans of one campaign group."),
|
|
3720
4607
|
tag: z.string().optional().describe("Comma-separated tag slugs to filter by."),
|
|
4608
|
+
ai_category: z.string().optional().describe(
|
|
4609
|
+
"Filter by the freeform LLM-generated category prefix on the scan (slash-separated tier path, e.g. 'Gambling/Online Casinos')."
|
|
4610
|
+
),
|
|
4611
|
+
iab_v3_category: z.string().optional().describe("Filter by canonical IAB Content Taxonomy V3 prefix (slash-separated tier path)."),
|
|
4612
|
+
iab_category: z.string().optional().describe("Filter by legacy IAB V2.2 category (only present on pre-P3 scans)."),
|
|
4613
|
+
brand: z.string().optional().describe("Filter by detected advertiser brand (case-insensitive)."),
|
|
4614
|
+
labels: z.record(
|
|
4615
|
+
z.string().min(1).max(100).regex(/^[a-z0-9_]+$/, "label keys must be snake_case ([a-z0-9_]+)"),
|
|
4616
|
+
z.string().min(1).max(200)
|
|
4617
|
+
).optional().describe(
|
|
4618
|
+
"Dynamic label filters as a flat object: { brand_safety: 'high', vertical: 'gambling' }. Keys are snake_case and must exist in the org's label catalogue. Each key becomes a `label_<key>=<value>` query param. See `list_account_labels`."
|
|
4619
|
+
),
|
|
3721
4620
|
page: z.number().int().min(1).max(500).default(1).describe("1-indexed page number."),
|
|
3722
4621
|
limit: z.number().int().min(1).max(200).default(50).describe("Page size (1-200). Default 50.")
|
|
3723
4622
|
};
|
|
3724
4623
|
var listScansTool = {
|
|
3725
4624
|
name: "list_scans",
|
|
3726
|
-
description: "List scans for the caller's organization with optional filters (status, country, URL substring, date range,
|
|
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.",
|
|
3727
4626
|
annotations: {
|
|
3728
4627
|
title: "List Scans",
|
|
3729
4628
|
readOnlyHint: true,
|
|
@@ -3733,6 +4632,12 @@ var listScansTool = {
|
|
|
3733
4632
|
},
|
|
3734
4633
|
inputSchema: z.object(ListScansInputShape),
|
|
3735
4634
|
handler: async (input, ctx) => {
|
|
4635
|
+
const labelFilters = {};
|
|
4636
|
+
if (input.labels !== void 0) {
|
|
4637
|
+
for (const [k, v] of Object.entries(input.labels)) {
|
|
4638
|
+
labelFilters[`label_${k}`] = v;
|
|
4639
|
+
}
|
|
4640
|
+
}
|
|
3736
4641
|
const filters = {
|
|
3737
4642
|
page: input.page,
|
|
3738
4643
|
limit: input.limit,
|
|
@@ -3742,7 +4647,16 @@ var listScansTool = {
|
|
|
3742
4647
|
...input.scan_id !== void 0 ? { scan_id: input.scan_id } : {},
|
|
3743
4648
|
...input.date_from !== void 0 ? { date_from: input.date_from } : {},
|
|
3744
4649
|
...input.date_to !== void 0 ? { date_to: input.date_to } : {},
|
|
3745
|
-
...input.
|
|
4650
|
+
...input.timezone !== void 0 ? { timezone: input.timezone } : {},
|
|
4651
|
+
...input.run_id !== void 0 ? { run_id: input.run_id } : {},
|
|
4652
|
+
...input.campaign_id !== void 0 ? { campaign_id: input.campaign_id } : {},
|
|
4653
|
+
...input.group_id !== void 0 ? { group_id: input.group_id } : {},
|
|
4654
|
+
...input.tag !== void 0 ? { tag: input.tag } : {},
|
|
4655
|
+
...input.ai_category !== void 0 ? { ai_category: input.ai_category } : {},
|
|
4656
|
+
...input.iab_v3_category !== void 0 ? { iab_v3_category: input.iab_v3_category } : {},
|
|
4657
|
+
...input.iab_category !== void 0 ? { iab_category: input.iab_category } : {},
|
|
4658
|
+
...input.brand !== void 0 ? { brand: input.brand } : {},
|
|
4659
|
+
...labelFilters
|
|
3746
4660
|
};
|
|
3747
4661
|
const result = await ctx.api.listScans(filters);
|
|
3748
4662
|
if (result.isErr()) {
|
|
@@ -3839,10 +4753,14 @@ var listScanTagsTool = {
|
|
|
3839
4753
|
return ok({ items: result.value, total: result.value.length });
|
|
3840
4754
|
}
|
|
3841
4755
|
};
|
|
3842
|
-
var ListTagsInputShape = {
|
|
4756
|
+
var ListTagsInputShape = {
|
|
4757
|
+
category: z.string().min(1).max(100).optional().describe(
|
|
4758
|
+
"Filter to tags in one category slug (e.g. 'security', 'malware', 'compliance'). Use the slug exactly as it appears in `category` of an existing tag."
|
|
4759
|
+
)
|
|
4760
|
+
};
|
|
3843
4761
|
var listTagsTool = {
|
|
3844
4762
|
name: "list_tags",
|
|
3845
|
-
description: "List every tag definition the platform knows (system tags + organization custom tags) with category, severity, and usage counters (scans + rules per tag).",
|
|
4763
|
+
description: "List every tag definition the platform knows (system tags + organization custom tags) with category, severity, visibility, and usage counters (scans + rules per tag). Optionally filter by category.",
|
|
3846
4764
|
annotations: {
|
|
3847
4765
|
title: "List Tags",
|
|
3848
4766
|
readOnlyHint: true,
|
|
@@ -3851,8 +4769,9 @@ var listTagsTool = {
|
|
|
3851
4769
|
openWorldHint: false
|
|
3852
4770
|
},
|
|
3853
4771
|
inputSchema: z.object(ListTagsInputShape),
|
|
3854
|
-
handler: async (
|
|
3855
|
-
const
|
|
4772
|
+
handler: async (input, ctx) => {
|
|
4773
|
+
const filters = input.category !== void 0 ? { category: input.category } : void 0;
|
|
4774
|
+
const result = await ctx.api.listTags(filters);
|
|
3856
4775
|
if (result.isErr()) return err(mapApiError(result.error));
|
|
3857
4776
|
return ok({ items: result.value, total: result.value.length });
|
|
3858
4777
|
}
|
|
@@ -3862,7 +4781,9 @@ var UpdateTagDefinitionInputShape = {
|
|
|
3862
4781
|
display_name: z.string().min(1).max(200).optional().describe("New human-readable name."),
|
|
3863
4782
|
description: z.string().max(2e3).optional().describe("New description."),
|
|
3864
4783
|
severity: z.enum(["high", "medium", "low"]).optional().describe("New severity level."),
|
|
3865
|
-
|
|
4784
|
+
visibility: z.enum(["hidden", "internal", "public"]).optional().describe(
|
|
4785
|
+
"Tag visibility on the scan report: hidden = not surfaced; internal = visible to org members; public = appears in the public scan-share view."
|
|
4786
|
+
)
|
|
3866
4787
|
};
|
|
3867
4788
|
var updateTagDefinitionTool = {
|
|
3868
4789
|
name: "update_tag_definition",
|
|
@@ -3880,8 +4801,12 @@ var updateTagDefinitionTool = {
|
|
|
3880
4801
|
if (input.display_name !== void 0) body.display_name = input.display_name;
|
|
3881
4802
|
if (input.description !== void 0) body.description = input.description;
|
|
3882
4803
|
if (input.severity !== void 0) body.severity = input.severity;
|
|
3883
|
-
if (input.
|
|
3884
|
-
|
|
4804
|
+
if (input.visibility !== void 0) body.visibility = input.visibility;
|
|
4805
|
+
if (Object.keys(body).length === 0) {
|
|
4806
|
+
return err({
|
|
4807
|
+
kind: "invalid-input",
|
|
4808
|
+
message: "update_tag_definition requires at least one field to change (display_name, description, severity, or visibility)."
|
|
4809
|
+
});
|
|
3885
4810
|
}
|
|
3886
4811
|
const result = await ctx.api.updateTagDefinition(input.slug, body);
|
|
3887
4812
|
if (result.isErr()) return err(mapApiError(result.error));
|
|
@@ -3985,12 +4910,15 @@ var getWebhookTool = {
|
|
|
3985
4910
|
};
|
|
3986
4911
|
var ListWebhookDeliveriesInputShape = {
|
|
3987
4912
|
webhook_id: z.string().uuid().describe("Webhook endpoint UUID."),
|
|
4913
|
+
success: z.boolean().optional().describe("Filter to delivered (true) or failed (false) attempts only."),
|
|
4914
|
+
from_ts: z.string().datetime({ offset: true }).optional().describe("ISO 8601 datetime (with offset), inclusive lower bound on attempt time."),
|
|
4915
|
+
to_ts: z.string().datetime({ offset: true }).optional().describe("ISO 8601 datetime (with offset), inclusive upper bound."),
|
|
3988
4916
|
page: z.number().int().min(1).max(500).default(1).describe("1-indexed page."),
|
|
3989
4917
|
limit: z.number().int().min(1).max(200).default(50).describe("Page size.")
|
|
3990
4918
|
};
|
|
3991
4919
|
var listWebhookDeliveriesTool = {
|
|
3992
4920
|
name: "list_webhook_deliveries",
|
|
3993
|
-
description: "List delivery attempts for one webhook endpoint with event type, status (pending / delivered / failed), HTTP response status if any, and attempt timestamp. Paginated.",
|
|
4921
|
+
description: "List delivery attempts for one webhook endpoint with event type, status (pending / delivered / failed), HTTP response status if any, and attempt timestamp. Filter by `success` and / or a `from_ts` / `to_ts` range. Paginated.",
|
|
3994
4922
|
annotations: {
|
|
3995
4923
|
title: "List Webhook Deliveries",
|
|
3996
4924
|
readOnlyHint: true,
|
|
@@ -4000,10 +4928,14 @@ var listWebhookDeliveriesTool = {
|
|
|
4000
4928
|
},
|
|
4001
4929
|
inputSchema: z.object(ListWebhookDeliveriesInputShape),
|
|
4002
4930
|
handler: async (input, ctx) => {
|
|
4003
|
-
const
|
|
4931
|
+
const filters = {
|
|
4004
4932
|
page: input.page,
|
|
4005
|
-
limit: input.limit
|
|
4006
|
-
|
|
4933
|
+
limit: input.limit,
|
|
4934
|
+
...input.success !== void 0 ? { success: input.success } : {},
|
|
4935
|
+
...input.from_ts !== void 0 ? { from_ts: input.from_ts } : {},
|
|
4936
|
+
...input.to_ts !== void 0 ? { to_ts: input.to_ts } : {}
|
|
4937
|
+
};
|
|
4938
|
+
const result = await ctx.api.listWebhookDeliveries(input.webhook_id, filters);
|
|
4007
4939
|
if (result.isErr()) return err(mapApiError(result.error));
|
|
4008
4940
|
return ok(result.value);
|
|
4009
4941
|
}
|
|
@@ -4146,6 +5078,9 @@ function registerAllTools(register) {
|
|
|
4146
5078
|
register(removeUserTool);
|
|
4147
5079
|
register(transferOwnershipTool);
|
|
4148
5080
|
register(listOrgRolesTool);
|
|
5081
|
+
register(createCustomRoleTool);
|
|
5082
|
+
register(listAccountLabelsTool);
|
|
5083
|
+
register(updateAccountLabelsTool);
|
|
4149
5084
|
register(listApiKeysTool);
|
|
4150
5085
|
register(createApiKeyTool);
|
|
4151
5086
|
register(revokeApiKeyTool);
|
|
@@ -4157,6 +5092,9 @@ function registerAllTools(register) {
|
|
|
4157
5092
|
register(createBulkScansTool);
|
|
4158
5093
|
register(createScanTool);
|
|
4159
5094
|
register(recheckScansTool);
|
|
5095
|
+
register(getScanScreenshotTool);
|
|
5096
|
+
register(getScanCreativeScreenshotTool);
|
|
5097
|
+
register(getScanLandingScreenshotTool);
|
|
4160
5098
|
register(getCampaignTool);
|
|
4161
5099
|
register(listCampaignsTool);
|
|
4162
5100
|
register(archiveCampaignTool);
|
|
@@ -4191,6 +5129,13 @@ function registerAllTools(register) {
|
|
|
4191
5129
|
register(updateCustomRuleTool);
|
|
4192
5130
|
register(deleteCustomRuleTool);
|
|
4193
5131
|
register(testCustomRuleTool);
|
|
5132
|
+
register(listCustomTaxonomiesTool);
|
|
5133
|
+
register(getCustomTaxonomyTool);
|
|
5134
|
+
register(createCustomTaxonomyTool);
|
|
5135
|
+
register(updateCustomTaxonomyTool);
|
|
5136
|
+
register(deleteCustomTaxonomyTool);
|
|
5137
|
+
register(restoreCustomTaxonomyTool);
|
|
5138
|
+
register(parseCustomTaxonomyTextTool);
|
|
4194
5139
|
register(listPolicySetsTool);
|
|
4195
5140
|
register(getPolicySetTool);
|
|
4196
5141
|
register(createPolicySetTool);
|
|
@@ -4216,6 +5161,7 @@ function registerAllTools(register) {
|
|
|
4216
5161
|
register(getUsageSummaryTool);
|
|
4217
5162
|
register(listBalanceHistoryTool);
|
|
4218
5163
|
register(listInvoicesTool);
|
|
5164
|
+
register(getInvoicePdfTool);
|
|
4219
5165
|
register(listAlertDestinationsTool);
|
|
4220
5166
|
register(deleteAlertDestinationTool);
|
|
4221
5167
|
register(setAlertDestinationVersionTool);
|
|
@@ -4253,12 +5199,28 @@ function wireToolsIntoMcpServer(server, ctxProvider) {
|
|
|
4253
5199
|
});
|
|
4254
5200
|
}
|
|
4255
5201
|
function toolOkToMcpResult(value) {
|
|
5202
|
+
if (isMcpContentEnvelope(value)) {
|
|
5203
|
+
return value;
|
|
5204
|
+
}
|
|
4256
5205
|
const isPlainObject = value !== null && typeof value === "object" && !Array.isArray(value);
|
|
4257
5206
|
return {
|
|
4258
5207
|
content: [{ type: "text", text: JSON.stringify(value, null, 2) }],
|
|
4259
5208
|
...isPlainObject ? { structuredContent: value } : {}
|
|
4260
5209
|
};
|
|
4261
5210
|
}
|
|
5211
|
+
function isBinaryBlockType(type2) {
|
|
5212
|
+
return type2 === "image" || type2 === "audio" || type2 === "resource";
|
|
5213
|
+
}
|
|
5214
|
+
function isMcpContentEnvelope(value) {
|
|
5215
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
|
|
5216
|
+
const v = value;
|
|
5217
|
+
if (!Array.isArray(v.content) || v.content.length === 0) return false;
|
|
5218
|
+
return v.content.every((block) => {
|
|
5219
|
+
if (block === null || typeof block !== "object") return false;
|
|
5220
|
+
const type2 = block.type;
|
|
5221
|
+
return typeof type2 === "string" && isBinaryBlockType(type2);
|
|
5222
|
+
});
|
|
5223
|
+
}
|
|
4262
5224
|
function toolErrorToMcpResult(error) {
|
|
4263
5225
|
return {
|
|
4264
5226
|
isError: true,
|
|
@@ -4285,5 +5247,5 @@ function formatToolError(error) {
|
|
|
4285
5247
|
}
|
|
4286
5248
|
|
|
4287
5249
|
export { BearerToken, createHttpApiGateway, createPinoLogger, declareEmptyResourcesAndPrompts, newRequestId, wireToolsIntoMcpServer };
|
|
4288
|
-
//# sourceMappingURL=chunk-
|
|
4289
|
-
//# sourceMappingURL=chunk-
|
|
5250
|
+
//# sourceMappingURL=chunk-W7TPFRJB.js.map
|
|
5251
|
+
//# sourceMappingURL=chunk-W7TPFRJB.js.map
|