@kaminari-ad/mcp 0.14.0 → 0.16.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 +108 -1
- package/README.md +4 -4
- package/dist/bin.js +3 -3
- package/dist/{chunk-FQTVDC5D.js → chunk-LTUO4SP6.js} +3 -3
- package/dist/{chunk-FQTVDC5D.js.map → chunk-LTUO4SP6.js.map} +1 -1
- package/dist/{chunk-CUJWJSNJ.js → chunk-YYS2HD6K.js} +126 -50
- package/dist/chunk-YYS2HD6K.js.map +1 -0
- package/dist/{http-bootstrap-AYQ47NTT.js → http-bootstrap-PDCTS4IS.js} +4 -4
- package/dist/{http-bootstrap-AYQ47NTT.js.map → http-bootstrap-PDCTS4IS.js.map} +1 -1
- package/dist/{stdio-bootstrap-XZIU2X6Z.js → stdio-bootstrap-LLCHIZ4X.js} +4 -4
- package/dist/{stdio-bootstrap-XZIU2X6Z.js.map → stdio-bootstrap-LLCHIZ4X.js.map} +1 -1
- package/package.json +1 -1
- package/dist/chunk-CUJWJSNJ.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,110 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.16.0] - 2026-08-26
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **`unpublish_policy_set` — publication is no longer a one-way door
|
|
15
|
+
(KAMIAD-167).** `request_policy_set_approval` had no inverse, so an
|
|
16
|
+
agent could put a set into the shared catalog but never take it out;
|
|
17
|
+
the only escape was asking a human to reject it, and that worked only
|
|
18
|
+
while the request was still pending. The new tool returns a set to
|
|
19
|
+
private from either state — approved or awaiting review — and is
|
|
20
|
+
idempotent on a set that is already private. It is annotated
|
|
21
|
+
`destructiveHint: true` because other organizations lose access to a
|
|
22
|
+
set they may be browsing. Campaigns already bound to the set keep
|
|
23
|
+
running against it; going private blocks new attachments instead.
|
|
24
|
+
|
|
25
|
+
Needs the API side deployed first: it wraps
|
|
26
|
+
`POST /api/v1/policy-sets/{id}/unpublish`, added in `adverif/api!378`.
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
|
|
30
|
+
- **`get_campaign_alert_overrides` validates `mode` strictly — this
|
|
31
|
+
actually shipped in 0.15.0, undocumented.** That release's regen
|
|
32
|
+
narrowed `CampaignOverridesResponse.mode` from a bare `string` to the
|
|
33
|
+
generated `CampaignOverrideMode` enum (`inherit | override |
|
|
34
|
+
silence`), and the response parser enforces it, so a fourth value
|
|
35
|
+
from the API now surfaces as an `upstream` error instead of passing
|
|
36
|
+
through. That is the intent — the api types the field, so drift
|
|
37
|
+
should fail loudly — but it is a behaviour change and 0.15.0 recorded
|
|
38
|
+
only "regenerated openapi.ts / zod-schemas.ts".
|
|
39
|
+
- `set_campaign_alert_overrides` now takes its `mode` input from that
|
|
40
|
+
same generated enum instead of a hand-written `z.enum` with identical
|
|
41
|
+
values. Behaviour is unchanged; the point is that `check-tool-enum-drift`
|
|
42
|
+
can finally catch future value changes on this field, so its
|
|
43
|
+
exemption is gone.
|
|
44
|
+
|
|
45
|
+
### Removed
|
|
46
|
+
|
|
47
|
+
- The two `/api/forms/*` entries in `check-api-coverage`'s
|
|
48
|
+
`EXEMPT_OPERATIONS`. Those routes are `include_in_schema=False` and
|
|
49
|
+
dropped out of the spec in the 0.15.0 regen, so the exemptions had
|
|
50
|
+
become dead config — exactly as their own comment predicted.
|
|
51
|
+
|
|
52
|
+
## [0.15.0] - 2026-08-24
|
|
53
|
+
|
|
54
|
+
### Added
|
|
55
|
+
|
|
56
|
+
- **`get_proxy_targeting` — the accepted proxy values, instead of
|
|
57
|
+
guesswork.** A scan's `proxy` block takes a region, city, and ISP whose
|
|
58
|
+
valid values come from our upstream network provider's catalogue, so
|
|
59
|
+
they cannot be an enum in the schema: they differ per country and per
|
|
60
|
+
connection type. Until now an agent had to guess, and a wrong guess
|
|
61
|
+
came back as a 422 with a prose message. The new tool wraps
|
|
62
|
+
`GET /api/v1/proxy/targeting` and returns the accepted regions,
|
|
63
|
+
cities, and ISPs for a country, ordered by pool size so the agent can
|
|
64
|
+
prefer values likely to yield an exit node. Anything it lists is
|
|
65
|
+
accepted by `create_scan`.
|
|
66
|
+
|
|
67
|
+
Two things the tool's description makes explicit, because both are
|
|
68
|
+
easy to get wrong: pass `proxy_type: "mobile"` when the scan is mobile
|
|
69
|
+
(the two networks are separate pools — in the US that is 1500+ ISPs
|
|
70
|
+
against roughly a dozen carriers), and take a city from the same
|
|
71
|
+
response that produced the region, since a region and a city that do
|
|
72
|
+
not belong together leave the provider nothing to route through.
|
|
73
|
+
|
|
74
|
+
- **The write tools now point at it.** A tool nobody is told about is a
|
|
75
|
+
tool nobody calls, and an agent starts from `create_scan`, not from the
|
|
76
|
+
catalogue. The `proxy` fields on `create_scan` / `create_bulk_scans`
|
|
77
|
+
and the `proxy_*` fields on `create_campaign` / `update_campaign` now
|
|
78
|
+
name `get_proxy_targeting` and carry the same two warnings. The
|
|
79
|
+
campaign `proxy_region` description previously said "free-text", which
|
|
80
|
+
told the agent to invent a value — precisely the behaviour that
|
|
81
|
+
produces the 422 this release exists to remove.
|
|
82
|
+
|
|
83
|
+
### Changed
|
|
84
|
+
|
|
85
|
+
- **Regenerated `openapi.ts` / `zod-schemas.ts`** against the API
|
|
86
|
+
release that adds `/api/v1/proxy/targeting`.
|
|
87
|
+
|
|
88
|
+
- **A rejected field value now arrives as a `detail` array.** The API
|
|
89
|
+
changed 422 responses for values checked against a runtime vocabulary
|
|
90
|
+
(`proxy.region`, `proxy.city`, `proxy.isp`, `country_code`,
|
|
91
|
+
`emulator_id`) from a prose string to the `HTTPValidationError`
|
|
92
|
+
array its OpenAPI schema always declared. No change was needed here —
|
|
93
|
+
`toApiError` has handled both shapes since the parser-drift work — and
|
|
94
|
+
the agent-visible message is now `body.proxy.region: Unsupported proxy
|
|
95
|
+
region …` instead of an undifferentiated sentence.
|
|
96
|
+
|
|
97
|
+
## [0.14.1] - 2026-08-24
|
|
98
|
+
|
|
99
|
+
### Changed
|
|
100
|
+
|
|
101
|
+
- **Three tag tools described archived tags as still reachable
|
|
102
|
+
(KAMIAD-120).** The API now retires an archived tag everywhere: it is
|
|
103
|
+
no longer assigned to scans, no longer raises alerts, and an archived
|
|
104
|
+
platform tag is gone from the catalogue entirely. `list_tags` told the
|
|
105
|
+
agent the opposite — to pass `include_archived` "when resolving a slug
|
|
106
|
+
seen on an older scan", which now returns nothing for exactly those
|
|
107
|
+
slugs. `get_tag_definition` now documents the 404, and
|
|
108
|
+
`list_scan_tags` that a scan can report fewer tags than when it ran.
|
|
109
|
+
Descriptions only; no schema or shape change, so
|
|
110
|
+
`src/shared/api/{openapi,zod-schemas}.ts` are unaffected — the two
|
|
111
|
+
stale JSDoc lines about `include_archived` are regenerated from the
|
|
112
|
+
live spec once the API side is deployed.
|
|
113
|
+
|
|
10
114
|
## [0.14.0] - 2026-08-23
|
|
11
115
|
|
|
12
116
|
Resyncs the tool surface with `/api/v1` (KAMIAD-158). The generated
|
|
@@ -1128,7 +1232,10 @@ Initial public release. The first version that ships to npm under
|
|
|
1128
1232
|
need them.
|
|
1129
1233
|
- Invoice PDF fetcher — same reason.
|
|
1130
1234
|
|
|
1131
|
-
[Unreleased]: https://github.com/kaminari-ad/mcp/compare/v0.
|
|
1235
|
+
[Unreleased]: https://github.com/kaminari-ad/mcp/compare/v0.15.0...HEAD
|
|
1236
|
+
[0.15.0]: https://github.com/kaminari-ad/mcp/compare/v0.14.1...v0.15.0
|
|
1237
|
+
[0.14.1]: https://github.com/kaminari-ad/mcp/compare/v0.14.0...v0.14.1
|
|
1238
|
+
[0.14.0]: https://github.com/kaminari-ad/mcp/compare/v0.13.0...v0.14.0
|
|
1132
1239
|
[0.13.0]: https://github.com/kaminari-ad/mcp/compare/v0.12.0...v0.13.0
|
|
1133
1240
|
[0.12.0]: https://github.com/kaminari-ad/mcp/compare/v0.11.0...v0.12.0
|
|
1134
1241
|
[0.11.0]: https://github.com/kaminari-ad/mcp/compare/v0.10.0...v0.11.0
|
package/README.md
CHANGED
|
@@ -63,7 +63,7 @@ Add to your MCP client config (Cursor: `~/.cursor/mcp.json`; Claude Desktop: `~/
|
|
|
63
63
|
}
|
|
64
64
|
```
|
|
65
65
|
|
|
66
|
-
Restart your client. You should see `kaminari-ad` in the MCP servers list with
|
|
66
|
+
Restart your client. You should see `kaminari-ad` in the MCP servers list with 107 tools exposed.
|
|
67
67
|
|
|
68
68
|
### 2b. Hosted HTTP transport (no install)
|
|
69
69
|
|
|
@@ -113,7 +113,7 @@ which decides which credential type minted it.
|
|
|
113
113
|
|
|
114
114
|
## Tools
|
|
115
115
|
|
|
116
|
-
|
|
116
|
+
107 tools covering the public `/api/v1` surface of Kaminari Ad. Every tool carries MCP behaviour annotations (`title`, `readOnlyHint`, `destructiveHint`, `idempotentHint`, `openWorldHint`) so MCP clients can warn before destructive actions. The complete list, by domain:
|
|
117
117
|
|
|
118
118
|
- **Account** (14) — `get_account`, `update_org`, `list_org_users`, `invite_user`, `update_user_role`, `remove_user`, `transfer_ownership`, `list_org_roles`, `create_custom_role`, `list_account_labels`, `update_account_labels`, `list_api_keys`, `create_api_key`, `revoke_api_key`
|
|
119
119
|
- **Scans** (13) — `list_scans`, `get_scan`, `list_scan_children`, `create_scan`, `create_bulk_scans`, `recheck_scans`, `cancel_scan`, `get_scan_screenshot`, `get_scan_creative_screenshot`, `get_scan_landing_screenshot`, `get_scan_creative_html`, `get_scan_creative_video`, `get_scan_vast_xml`
|
|
@@ -123,13 +123,13 @@ which decides which credential type minted it.
|
|
|
123
123
|
- **Tags** (5) — `list_tags`, `get_tag_definition`, `update_tag_definition`, `delete_tag_definition`, `list_scan_tags`
|
|
124
124
|
- **Custom rules** (6) — `list_custom_rules`, `get_custom_rule`, `create_custom_rule`, `update_custom_rule`, `delete_custom_rule`, `test_custom_rule`
|
|
125
125
|
- **Custom taxonomies** (7) — `list_custom_taxonomies`, `get_custom_taxonomy`, `create_custom_taxonomy`, `update_custom_taxonomy`, `delete_custom_taxonomy`, `restore_custom_taxonomy`, `parse_custom_taxonomy_text`
|
|
126
|
-
- **Policy sets** (
|
|
126
|
+
- **Policy sets** (10) — `list_policy_sets`, `get_policy_set`, `create_policy_set`, `update_policy_set`, `delete_policy_set`, `request_policy_set_approval`, `unpublish_policy_set`, `list_policy_set_campaigns`, `attach_policy_set_campaigns`, `detach_policy_set_campaigns`
|
|
127
127
|
- **Alerts** (4) — `list_alerts`, `update_alert_status`, `bulk_update_alert_status`, `get_alert_stats`
|
|
128
128
|
- **Webhooks** (11) — `list_webhooks`, `get_webhook`, `create_webhook`, `update_webhook`, `delete_webhook`, `list_webhook_event_types`, `list_webhook_deliveries`, `test_webhook`, `rotate_webhook_secret`, `replay_webhook_delivery`, `bulk_replay_webhook`
|
|
129
129
|
- **Billing** (4) — `get_billing_summary`, `list_usage`, `get_usage_summary`, `list_balance_history`
|
|
130
130
|
- **Invoicing** (2) — `list_invoices`, `get_invoice_pdf`
|
|
131
131
|
- **Alert notifications** (5) — `list_alert_destinations`, `delete_alert_destination`, `set_alert_destination_version`, `get_campaign_alert_overrides`, `set_campaign_alert_overrides`
|
|
132
|
-
- **Reference data** (
|
|
132
|
+
- **Reference data** (3) — `list_geos`, `list_emulators`, `get_proxy_targeting`
|
|
133
133
|
|
|
134
134
|
Screenshots (`get_scan_screenshot`, `get_scan_creative_screenshot`, `get_scan_landing_screenshot`) come back as inline MCP `image` blocks; `get_invoice_pdf` and `get_scan_creative_video` as inline resource blocks — no second fetch, no presigned URL. The two text artifacts (`get_scan_creative_html`, `get_scan_vast_xml`) come back as strings the model can read directly. Every artifact download is size-capped in the gateway — 256 KiB for the text artifacts, 8 MiB for the binary ones — and refused while reading rather than buffered and then rejected.
|
|
135
135
|
|
package/dist/bin.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { NAME, VERSION, err, ok } from './chunk-
|
|
2
|
+
import { NAME, VERSION, err, ok } from './chunk-LTUO4SP6.js';
|
|
3
3
|
import process from 'process';
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
|
|
@@ -160,10 +160,10 @@ async function main() {
|
|
|
160
160
|
}
|
|
161
161
|
const config = configResult.value;
|
|
162
162
|
if (config.transport === "stdio") {
|
|
163
|
-
const { bootstrapStdio } = await import('./stdio-bootstrap-
|
|
163
|
+
const { bootstrapStdio } = await import('./stdio-bootstrap-LLCHIZ4X.js');
|
|
164
164
|
return bootstrapStdio(config);
|
|
165
165
|
}
|
|
166
|
-
const { bootstrapHttp } = await import('./http-bootstrap-
|
|
166
|
+
const { bootstrapHttp } = await import('./http-bootstrap-PDCTS4IS.js');
|
|
167
167
|
return bootstrapHttp(config);
|
|
168
168
|
}
|
|
169
169
|
main().then(
|
|
@@ -3,8 +3,8 @@ export { err, ok } from 'neverthrow';
|
|
|
3
3
|
|
|
4
4
|
// src/shared/version.ts
|
|
5
5
|
var NAME = "@kaminari-ad/mcp";
|
|
6
|
-
var VERSION = "0.
|
|
6
|
+
var VERSION = "0.16.0";
|
|
7
7
|
|
|
8
8
|
export { NAME, VERSION };
|
|
9
|
-
//# sourceMappingURL=chunk-
|
|
10
|
-
//# sourceMappingURL=chunk-
|
|
9
|
+
//# sourceMappingURL=chunk-LTUO4SP6.js.map
|
|
10
|
+
//# sourceMappingURL=chunk-LTUO4SP6.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/shared/version.ts"],"names":[],"mappings":";;;;AASO,IAAM,IAAA,GAAO;AACb,IAAM,OAAA,GAAU","file":"chunk-
|
|
1
|
+
{"version":3,"sources":["../src/shared/version.ts"],"names":[],"mappings":";;;;AASO,IAAM,IAAA,GAAO;AACb,IAAM,OAAA,GAAU","file":"chunk-LTUO4SP6.js","sourcesContent":["/**\n * Package version and name. Hard-coded as constants here, asserted to\n * match `package.json` by a unit test.\n *\n * Why not import `package.json`: it would force JSON-module support at\n * runtime and tsup-bundling would inline the entire manifest. Two\n * constants + one assertion test is simpler and gives the same safety.\n */\n\nexport const NAME = \"@kaminari-ad/mcp\";\nexport const VERSION = \"0.16.0\";\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { err, ok } from './chunk-
|
|
2
|
+
import { err, ok } from './chunk-LTUO4SP6.js';
|
|
3
3
|
import { createHash, randomUUID } from 'crypto';
|
|
4
4
|
import createClient from 'openapi-fetch';
|
|
5
5
|
import { fetch } from 'undici';
|
|
@@ -471,6 +471,15 @@ var GeoResponse = z.object({
|
|
|
471
471
|
region: z.string(),
|
|
472
472
|
tier: z.string()
|
|
473
473
|
}).passthrough();
|
|
474
|
+
var ProxyTargetingResponse = z.object({
|
|
475
|
+
country_code: z.string(),
|
|
476
|
+
proxy_type: z.string(),
|
|
477
|
+
regions: z.array(z.string()),
|
|
478
|
+
cities: z.array(z.string()),
|
|
479
|
+
isps: z.array(z.string()),
|
|
480
|
+
refreshed_at: z.union([z.string(), z.null()]),
|
|
481
|
+
ttl_seconds: z.number().int()
|
|
482
|
+
}).passthrough();
|
|
474
483
|
var EmulatorResponse = z.object({
|
|
475
484
|
id: z.string(),
|
|
476
485
|
display_name: z.string(),
|
|
@@ -1093,13 +1102,14 @@ var AlertNotificationDestinationResponse = z.object({
|
|
|
1093
1102
|
updated_at: z.string().datetime({ offset: true })
|
|
1094
1103
|
}).passthrough();
|
|
1095
1104
|
z.object({ version: AlertNotificationVersion }).passthrough();
|
|
1105
|
+
var CampaignOverrideMode = z.enum(["inherit", "override", "silence"]);
|
|
1096
1106
|
var CampaignOverridesResponse = z.object({
|
|
1097
1107
|
campaign_id: z.string().uuid(),
|
|
1098
|
-
mode:
|
|
1108
|
+
mode: CampaignOverrideMode,
|
|
1099
1109
|
destination_ids: z.array(z.string().uuid())
|
|
1100
1110
|
}).passthrough();
|
|
1101
1111
|
z.object({
|
|
1102
|
-
mode:
|
|
1112
|
+
mode: CampaignOverrideMode,
|
|
1103
1113
|
destination_ids: z.array(z.string().uuid()).optional().default([])
|
|
1104
1114
|
}).passthrough();
|
|
1105
1115
|
var InvoiceType = z.enum(["proforma", "final"]);
|
|
@@ -1135,32 +1145,6 @@ z.object({
|
|
|
1135
1145
|
limit: z.number().int(),
|
|
1136
1146
|
pages: z.number().int()
|
|
1137
1147
|
}).passthrough();
|
|
1138
|
-
z.object({
|
|
1139
|
-
name: z.string().min(2).max(100),
|
|
1140
|
-
email: z.string().email(),
|
|
1141
|
-
message: z.string().min(10).max(2e3),
|
|
1142
|
-
source: z.string().max(512).optional().default("")
|
|
1143
|
-
}).passthrough();
|
|
1144
|
-
z.object({
|
|
1145
|
-
id: z.string().uuid(),
|
|
1146
|
-
received_at: z.string().datetime({ offset: true })
|
|
1147
|
-
}).passthrough();
|
|
1148
|
-
var PreferredContactChannel = z.enum(["telegram", "whatsapp", "email"]);
|
|
1149
|
-
z.object({
|
|
1150
|
-
first_name: z.string().min(2).max(60),
|
|
1151
|
-
last_name: z.string().min(2).max(60),
|
|
1152
|
-
company_email: z.string().email(),
|
|
1153
|
-
company_name: z.string().min(2).max(120),
|
|
1154
|
-
preferred_channel: PreferredContactChannel,
|
|
1155
|
-
contact_handle: z.string().max(120).optional().default(""),
|
|
1156
|
-
comment: z.string().max(2e3).optional().default(""),
|
|
1157
|
-
privacy_accepted: z.boolean(),
|
|
1158
|
-
source: z.string().max(512).optional().default("")
|
|
1159
|
-
}).passthrough();
|
|
1160
|
-
z.object({
|
|
1161
|
-
id: z.string().uuid(),
|
|
1162
|
-
received_at: z.string().datetime({ offset: true })
|
|
1163
|
-
}).passthrough();
|
|
1164
1148
|
var CustomTaxonomyListItem = z.object({
|
|
1165
1149
|
id: z.string().uuid(),
|
|
1166
1150
|
name: z.string(),
|
|
@@ -1230,6 +1214,7 @@ var schemas = {
|
|
|
1230
1214
|
ScanResponse,
|
|
1231
1215
|
ScanBriefResponse,
|
|
1232
1216
|
GeoResponse,
|
|
1217
|
+
ProxyTargetingResponse,
|
|
1233
1218
|
EmulatorResponse,
|
|
1234
1219
|
CampaignGroupResponse,
|
|
1235
1220
|
GroupActionResponse,
|
|
@@ -1261,6 +1246,7 @@ var schemas = {
|
|
|
1261
1246
|
DeliveryAttemptResponse,
|
|
1262
1247
|
BulkReplayResponse,
|
|
1263
1248
|
AlertNotificationDestinationResponse,
|
|
1249
|
+
CampaignOverrideMode,
|
|
1264
1250
|
CampaignOverridesResponse,
|
|
1265
1251
|
InvoiceResponse,
|
|
1266
1252
|
CustomTaxonomyListItem,
|
|
@@ -1779,6 +1765,18 @@ var PolicySetListItemSchema = schemas.PolicySetListItem.pick({
|
|
|
1779
1765
|
}).strip();
|
|
1780
1766
|
var parsePolicySetPage = (raw) => parsePagedWithItemSchema(PolicySetListItemSchema, raw, "policy-sets");
|
|
1781
1767
|
|
|
1768
|
+
// src/infrastructure/api/parsers/parse-proxy-targeting.ts
|
|
1769
|
+
var ProxyTargetingSchema = schemas.ProxyTargetingResponse.pick({
|
|
1770
|
+
country_code: true,
|
|
1771
|
+
proxy_type: true,
|
|
1772
|
+
regions: true,
|
|
1773
|
+
cities: true,
|
|
1774
|
+
isps: true,
|
|
1775
|
+
refreshed_at: true,
|
|
1776
|
+
ttl_seconds: true
|
|
1777
|
+
}).strip();
|
|
1778
|
+
var parseProxyTargeting = (raw) => parseWithSchema(ProxyTargetingSchema, raw, "proxy targeting");
|
|
1779
|
+
|
|
1782
1780
|
// src/infrastructure/api/parsers/parse-run.ts
|
|
1783
1781
|
var RunSchema = schemas.RunResponse.pick({
|
|
1784
1782
|
id: true,
|
|
@@ -2254,6 +2252,9 @@ function createHttpApiGateway(config) {
|
|
|
2254
2252
|
async listEmulators() {
|
|
2255
2253
|
return call("GET", "/api/v1/emulators", {}, parseEmulatorList);
|
|
2256
2254
|
},
|
|
2255
|
+
async getProxyTargeting(query) {
|
|
2256
|
+
return call("GET", "/api/v1/proxy/targeting", { params: { query } }, parseProxyTargeting);
|
|
2257
|
+
},
|
|
2257
2258
|
// ── Campaigns ─────────────────────────────────────────────────
|
|
2258
2259
|
async listCampaigns(filters) {
|
|
2259
2260
|
return call("GET", "/api/v1/campaigns", { params: { query: filters } }, parseCampaignPage);
|
|
@@ -2556,6 +2557,14 @@ function createHttpApiGateway(config) {
|
|
|
2556
2557
|
parseEmpty
|
|
2557
2558
|
);
|
|
2558
2559
|
},
|
|
2560
|
+
async unpublishPolicySet(id) {
|
|
2561
|
+
return call(
|
|
2562
|
+
"POST",
|
|
2563
|
+
"/api/v1/policy-sets/{policy_set_id}/unpublish",
|
|
2564
|
+
{ params: { path: { policy_set_id: id } } },
|
|
2565
|
+
parseEmpty
|
|
2566
|
+
);
|
|
2567
|
+
},
|
|
2559
2568
|
// ── Custom taxonomies ─────────────────────────────────────────
|
|
2560
2569
|
async listCustomTaxonomies(filters) {
|
|
2561
2570
|
return call(
|
|
@@ -3288,12 +3297,7 @@ var setAlertDestinationVersionTool = {
|
|
|
3288
3297
|
};
|
|
3289
3298
|
var SetCampaignAlertOverridesInputShape = {
|
|
3290
3299
|
campaign_id: z.string().uuid().describe("Campaign UUID."),
|
|
3291
|
-
|
|
3292
|
-
// the field as a plain string, so no generated schema constrains it.
|
|
3293
|
-
// Swap to `schemas.CampaignOverrideMode` after the api enum change
|
|
3294
|
-
// (`fix/type-override-mode-and-unlist-forms`) reaches prod and the
|
|
3295
|
-
// next `make gen-api-types` picks it up.
|
|
3296
|
-
mode: z.enum(["inherit", "override", "silence"]).describe(
|
|
3300
|
+
mode: schemas.CampaignOverrideMode.describe(
|
|
3297
3301
|
"Routing mode: `inherit` (fall back to the org-wide destinations), `override` (route ONLY to `destination_ids`), `silence` (send nothing for this campaign)."
|
|
3298
3302
|
),
|
|
3299
3303
|
destination_ids: z.array(z.string().uuid()).max(50).default([]).describe(
|
|
@@ -3920,10 +3924,18 @@ var campaignConfigFields = {
|
|
|
3920
3924
|
emulator_mode: z.enum(["random", "all"]).optional().describe(
|
|
3921
3925
|
"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."
|
|
3922
3926
|
),
|
|
3923
|
-
proxy_type: z.enum(["residential", "mobile"]).optional().describe(
|
|
3924
|
-
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
+
proxy_type: z.enum(["residential", "mobile"]).optional().describe(
|
|
3928
|
+
"Proxy network type. Default: residential. Residential and mobile are separate pools with separate catalogues, so pass the same value to `get_proxy_targeting` that you send here."
|
|
3929
|
+
),
|
|
3930
|
+
proxy_region: z.string().optional().describe(
|
|
3931
|
+
"Proxy region/state; use a value from `get_proxy_targeting` for one of this campaign's countries. Only honoured when the campaign targets a single country."
|
|
3932
|
+
),
|
|
3933
|
+
proxy_city: z.string().optional().describe(
|
|
3934
|
+
"Proxy city from `get_proxy_targeting`. If you also set `proxy_region`, take the city from a call made with that same region \u2014 a city from a different region passes validation but leaves the provider no exit node."
|
|
3935
|
+
),
|
|
3936
|
+
proxy_isp: z.string().optional().describe(
|
|
3937
|
+
"Proxy ISP, or mobile carrier when `proxy_type` is mobile. Use a value from `get_proxy_targeting`."
|
|
3938
|
+
),
|
|
3927
3939
|
...repeatRetryFields,
|
|
3928
3940
|
schedule_type: z.enum(["weekly", "interval"]).optional().describe(
|
|
3929
3941
|
"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."
|
|
@@ -5055,6 +5067,26 @@ var requestPolicySetApprovalTool = {
|
|
|
5055
5067
|
return ok({ requested: true });
|
|
5056
5068
|
}
|
|
5057
5069
|
};
|
|
5070
|
+
var UnpublishPolicySetInputShape = {
|
|
5071
|
+
policy_set_id: z.string().uuid().describe("Policy set UUID.")
|
|
5072
|
+
};
|
|
5073
|
+
var unpublishPolicySetTool = {
|
|
5074
|
+
name: "unpublish_policy_set",
|
|
5075
|
+
description: "Return one of your organization's policy sets to PRIVATE. Inverse of request_policy_set_approval: removes an approved set from the shared catalog other organizations browse, or withdraws a publication request that is still awaiting review. The set stays fully usable inside your own organization. Campaigns in other organizations that already reference the set keep their binding \u2014 going private blocks new attachments rather than breaking existing ones. Safe to call on a set that is already private.",
|
|
5076
|
+
annotations: {
|
|
5077
|
+
title: "Unpublish Policy Set",
|
|
5078
|
+
readOnlyHint: false,
|
|
5079
|
+
destructiveHint: true,
|
|
5080
|
+
idempotentHint: true,
|
|
5081
|
+
openWorldHint: false
|
|
5082
|
+
},
|
|
5083
|
+
inputSchema: z.object(UnpublishPolicySetInputShape),
|
|
5084
|
+
handler: async (input, ctx) => {
|
|
5085
|
+
const result = await ctx.api.unpublishPolicySet(input.policy_set_id);
|
|
5086
|
+
if (result.isErr()) return err(mapApiError(result.error));
|
|
5087
|
+
return ok({ unpublished: true });
|
|
5088
|
+
}
|
|
5089
|
+
};
|
|
5058
5090
|
var UpdatePolicySetInputShape = {
|
|
5059
5091
|
policy_set_id: z.string().uuid().describe("Policy set UUID."),
|
|
5060
5092
|
name: z.string().min(1).max(200).describe("New name (always required by the API on update)."),
|
|
@@ -5084,6 +5116,38 @@ var updatePolicySetTool = {
|
|
|
5084
5116
|
return ok(result.value);
|
|
5085
5117
|
}
|
|
5086
5118
|
};
|
|
5119
|
+
var GetProxyTargetingInputShape = {
|
|
5120
|
+
country_code: z.string().length(2).describe("ISO 3166-1 alpha-2 country code, e.g. 'US'. Case-insensitive."),
|
|
5121
|
+
proxy_type: z.enum(["residential", "mobile"]).optional().describe(
|
|
5122
|
+
"Which network to describe. Defaults to residential. Pass 'mobile' when the scan will use mobile: the two are separate pools with different catalogues, so a residential ISP is normally rejected for a mobile scan."
|
|
5123
|
+
),
|
|
5124
|
+
region: z.string().optional().describe(
|
|
5125
|
+
"Narrow the returned cities to one region. Pass a value from this tool's own 'regions' array. Omit it for the country-wide city list."
|
|
5126
|
+
)
|
|
5127
|
+
};
|
|
5128
|
+
var getProxyTargetingTool = {
|
|
5129
|
+
name: "get_proxy_targeting",
|
|
5130
|
+
description: "List the proxy regions, cities, and ISPs accepted for a country. Call this before setting proxy targeting on create_scan, create_bulk_scans, create_campaign, or update_campaign \u2014 the accepted values come from the upstream network provider and cannot be listed in those tools' schemas, so a guess is a 422. Anything listed here is accepted. Values are ordered by pool size, largest first; prefer values near the front. Two traps: residential and mobile are separate pools, so pass the proxy_type the scan will use; and without a region the cities are the whole country's, so if you target a region, call again with that region and take the city from that narrower list \u2014 a region and a city that do not belong together are accepted but leave the provider no exit node.",
|
|
5131
|
+
annotations: {
|
|
5132
|
+
title: "Get Proxy Targeting",
|
|
5133
|
+
readOnlyHint: true,
|
|
5134
|
+
destructiveHint: false,
|
|
5135
|
+
idempotentHint: true,
|
|
5136
|
+
openWorldHint: false
|
|
5137
|
+
},
|
|
5138
|
+
inputSchema: z.object(GetProxyTargetingInputShape),
|
|
5139
|
+
handler: async (input, ctx) => {
|
|
5140
|
+
const result = await ctx.api.getProxyTargeting({
|
|
5141
|
+
country_code: input.country_code,
|
|
5142
|
+
...input.proxy_type !== void 0 && { proxy_type: input.proxy_type },
|
|
5143
|
+
...input.region !== void 0 && { region: input.region }
|
|
5144
|
+
});
|
|
5145
|
+
if (result.isErr()) {
|
|
5146
|
+
return err(mapApiError(result.error));
|
|
5147
|
+
}
|
|
5148
|
+
return ok(result.value);
|
|
5149
|
+
}
|
|
5150
|
+
};
|
|
5087
5151
|
var CancelRunInputShape = { run_id: z.string().uuid().describe("Run UUID.") };
|
|
5088
5152
|
var cancelRunTool = {
|
|
5089
5153
|
name: "cancel_run",
|
|
@@ -5166,11 +5230,21 @@ var cancelScanTool = {
|
|
|
5166
5230
|
}
|
|
5167
5231
|
};
|
|
5168
5232
|
var scanProxyField = z.object({
|
|
5169
|
-
proxy_type: z.enum(["residential", "mobile"]).optional().describe(
|
|
5170
|
-
|
|
5171
|
-
|
|
5172
|
-
|
|
5173
|
-
|
|
5233
|
+
proxy_type: z.enum(["residential", "mobile"]).optional().describe(
|
|
5234
|
+
"Proxy network type. Default: residential. Residential and mobile are separate pools with separate catalogues, so pass the same value to `get_proxy_targeting` that you send here."
|
|
5235
|
+
),
|
|
5236
|
+
region: z.string().optional().describe(
|
|
5237
|
+
"Proxy region/state. Use a value from `get_proxy_targeting`; anything else is rejected with 422."
|
|
5238
|
+
),
|
|
5239
|
+
city: z.string().optional().describe(
|
|
5240
|
+
"Proxy city. Use a value from `get_proxy_targeting`. If you also set `region`, take the city from a `get_proxy_targeting` call made with that same region \u2014 a city from a different region passes validation but leaves the provider no exit node."
|
|
5241
|
+
),
|
|
5242
|
+
isp: z.string().optional().describe(
|
|
5243
|
+
"Proxy ISP, or mobile carrier when `proxy_type` is mobile. Use a value from `get_proxy_targeting`."
|
|
5244
|
+
)
|
|
5245
|
+
}).optional().describe(
|
|
5246
|
+
"Optional proxy geo targeting for the crawl. Omit to use the org default. Call `get_proxy_targeting` for the country first: the accepted values come from the upstream network provider and cannot be listed in this schema."
|
|
5247
|
+
);
|
|
5174
5248
|
var scanReferrerField = z.string().url().regex(/^https?:\/\//i, "Must be an http(s) URL.").max(2048).optional().describe(
|
|
5175
5249
|
"Optional http(s) page URL the check is performed from. With `ad_tag` or `vast_tag` this is the publisher page the tag is embedded in \u2014 NOT the creative and NOT its landing page; the browser commits the page document on this URL without fetching the publisher, so the creative renders as if embedded there, and its cross-origin subrequests receive the origin only (https://publisher.example/, no path). With a `url` target this is where the visitor came from, sent in full as the Referer of the page request."
|
|
5176
5250
|
);
|
|
@@ -5599,7 +5673,7 @@ var GetTagDefinitionInputShape = {
|
|
|
5599
5673
|
};
|
|
5600
5674
|
var getTagDefinitionTool = {
|
|
5601
5675
|
name: "get_tag_definition",
|
|
5602
|
-
description: "Get full definition of one tag: display name, description, severity, category, source (system vs custom), public-report visibility, usage counts, plus `linked_rules` \u2014 the custom rules currently producing this tag (id, name, active flag). Fetch a specific rule's full config via `get_custom_rule`.",
|
|
5676
|
+
description: "Get full definition of one tag: display name, description, severity, category, source (system vs custom), public-report visibility, usage counts, plus `linked_rules` \u2014 the custom rules currently producing this tag (id, name, active flag). Fetch a specific rule's full config via `get_custom_rule`. Returns 404 for a retired (archived) tag this organization does not own, including every archived system tag.",
|
|
5603
5677
|
annotations: {
|
|
5604
5678
|
title: "Get Tag Definition",
|
|
5605
5679
|
readOnlyHint: true,
|
|
@@ -5619,7 +5693,7 @@ var ListScanTagsInputShape = {
|
|
|
5619
5693
|
};
|
|
5620
5694
|
var listScanTagsTool = {
|
|
5621
5695
|
name: "list_scan_tags",
|
|
5622
|
-
description: "List every tag (system + custom) attached to one scan by the checker pipeline, with display name, category, and severity.",
|
|
5696
|
+
description: "List every tag (system + custom) attached to one scan by the checker pipeline, with display name, category, and severity. Tags whose definition has since been archived are omitted \u2014 the scan can therefore report fewer tags than when it ran.",
|
|
5623
5697
|
annotations: {
|
|
5624
5698
|
title: "List Scan Tags",
|
|
5625
5699
|
readOnlyHint: true,
|
|
@@ -5639,12 +5713,12 @@ var ListTagsInputShape = {
|
|
|
5639
5713
|
"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."
|
|
5640
5714
|
),
|
|
5641
5715
|
include_archived: z.boolean().optional().describe(
|
|
5642
|
-
"
|
|
5716
|
+
"Also return the archived tag definitions this organization owns, which are excluded by default. An archived tag is retired: it is no longer assigned to scans and no longer raises alerts, and archived platform (system) tags are never returned at all \u2014 so this flag cannot resolve a slug seen on an older scan."
|
|
5643
5717
|
)
|
|
5644
5718
|
};
|
|
5645
5719
|
var listTagsTool = {
|
|
5646
5720
|
name: "list_tags",
|
|
5647
|
-
description: "List every tag definition
|
|
5721
|
+
description: "List every tag definition in service for this organization (system tags + organization custom tags) with category, severity, visibility, and usage counters (scans + rules per tag). Optionally filter by category, and pass `include_archived` to also see the retired definitions this organization owns.",
|
|
5648
5722
|
annotations: {
|
|
5649
5723
|
title: "List Tags",
|
|
5650
5724
|
readOnlyHint: true,
|
|
@@ -5980,6 +6054,7 @@ function registerAllTools(register) {
|
|
|
5980
6054
|
register(createApiKeyTool);
|
|
5981
6055
|
register(revokeApiKeyTool);
|
|
5982
6056
|
register(listGeosTool);
|
|
6057
|
+
register(getProxyTargetingTool);
|
|
5983
6058
|
register(listEmulatorsTool);
|
|
5984
6059
|
register(getScanTool);
|
|
5985
6060
|
register(listScanChildrenTool);
|
|
@@ -6041,6 +6116,7 @@ function registerAllTools(register) {
|
|
|
6041
6116
|
register(updatePolicySetTool);
|
|
6042
6117
|
register(deletePolicySetTool);
|
|
6043
6118
|
register(requestPolicySetApprovalTool);
|
|
6119
|
+
register(unpublishPolicySetTool);
|
|
6044
6120
|
register(listPolicySetCampaignsTool);
|
|
6045
6121
|
register(attachPolicySetCampaignsTool);
|
|
6046
6122
|
register(detachPolicySetCampaignsTool);
|
|
@@ -6150,5 +6226,5 @@ function formatToolError(error) {
|
|
|
6150
6226
|
}
|
|
6151
6227
|
|
|
6152
6228
|
export { BearerToken, SERVER_INSTRUCTIONS, createHttpApiGateway, createPinoLogger, declareEmptyResourcesAndPrompts, newRequestId, wireToolsIntoMcpServer };
|
|
6153
|
-
//# sourceMappingURL=chunk-
|
|
6154
|
-
//# sourceMappingURL=chunk-
|
|
6229
|
+
//# sourceMappingURL=chunk-YYS2HD6K.js.map
|
|
6230
|
+
//# sourceMappingURL=chunk-YYS2HD6K.js.map
|