@kaminari-ad/mcp 0.17.1 → 0.19.1

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 CHANGED
@@ -7,6 +7,77 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.19.1] - 2026-09-10
11
+
12
+ > Requires the API-side KAMIAD-104 deploy. Until it lands, production
13
+ > rejects `invoice_payment_adjustment` as an unknown query enum (422,
14
+ > surfaced as an `invalid_input` tool error), so do not tag this release
15
+ > ahead of the API.
16
+
17
+ ### Fixed
18
+
19
+ - **`list_balance_history` can filter on `invoice_payment_adjustment`.**
20
+ The API gained this `BalanceTransactionType` upstream (KAMIAD-104):
21
+ correcting an already-settled invoice appends a signed correction row
22
+ rather than editing the original `invoice_settlement`. Once the API
23
+ ships, an unfiltered call will return such rows without a parser change
24
+ — the response schema holds `type` as a plain string — but the filter
25
+ enum rejected the value, so an agent could neither select nor exclude
26
+ corrections. Same class of gap as `card_top_up` in 0.13.0, hence a
27
+ patch. No tool signature changed.
28
+
29
+ The two generated schemas were hand-edited rather than regenerated,
30
+ because `gen:api-types` defaults to the production spec and would drag
31
+ in unrelated drift that is not on this branch. Each hunk was verified
32
+ byte-equivalent to what a regen against the branch spec produces.
33
+
34
+ ### Security
35
+
36
+ - Cleared the three advisory clusters that `audit:deps` flagged, taking
37
+ `npm audit` from 9 findings (5 high, 4 moderate) to zero. `vitest` and
38
+ its `@vitest/*` siblings 4.1.6 → 4.1.11 (GHSA-82fw-gwwq-j7x9) and the
39
+ `js-yaml` override 4.3.1 → 4.3.2 (GHSA-2883-xcg3-v3hh) are both
40
+ dev-only. The new `hono` override (`^4.13.7`, three advisories) is
41
+ **not**: `hono` reaches the runtime tree through
42
+ `@modelcontextprotocol/sdk`, on the streamable-HTTP transport's request
43
+ path, so this changes what the HTTP deployment resolves. The published
44
+ bundle is unaffected — the SDK stays external — and npm `overrides` do
45
+ not propagate to consumers, so a consumer pinning a vulnerable `hono`
46
+ needs its own bump.
47
+
48
+ ## [0.19.0] - 2026-09-08
49
+
50
+ ### Changed
51
+
52
+ - **`network` on a discovered ad is now the ad network's NAME, and its
53
+ domain moved to `network_host`.** The API used to put whichever ad host
54
+ matched first into `network`, so an agent reading it got
55
+ `cdn.tsyndicate.com` where a name belongs — and sometimes
56
+ `www.googletagmanager.com`, which is not an ad network at all. Upstream
57
+ (KAMIAD-133) `network` became a display name resolved from a domain
58
+ catalog and is **empty when the ad server is not recognised**, while the
59
+ observed domain travels in the new `network_host`.
60
+
61
+ Both fields are exposed on every tool that returns a scan shape:
62
+ `get_scan`, `list_scans`, `list_scan_children`, `create_scan` and
63
+ `create_bulk_scans`. (`list_run_scans` returns the slim run tile, which
64
+ carries no network fields at all.) An
65
+ agent that identified networks by `network` should read `network_host`
66
+ when `network` is empty; one that treated `network` as a hostname needs
67
+ to stop. Scans created before the upstream release keep a hostname in
68
+ `network` and have an empty `network_host`, so a network breakdown is
69
+ only sound over scans created after it.
70
+
71
+ Ads served from infrastructure (tag managers, analytics, measurement,
72
+ DMPs) and from a publisher's own creative CDN are still found, scanned
73
+ and billed exactly as before — they simply no longer claim a network
74
+ name.
75
+
76
+ `network_host` is declared on the port rather than picked from the
77
+ generated types, the same escape hatch `max_discovered_ads` uses: the
78
+ generated files are regenerated off the DEPLOYED spec, and this field
79
+ ships in the release it describes. The next regen absorbs it.
80
+
10
81
  ## [0.17.1] - 2026-09-03
11
82
 
12
83
  ### Fixed
package/dist/bin.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { NAME, VERSION, err, ok } from './chunk-HZDWYWEN.js';
2
+ import { NAME, VERSION, err, ok } from './chunk-MKBTS4IH.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-UYBS3TK4.js');
163
+ const { bootstrapStdio } = await import('./stdio-bootstrap-4PXPX6BD.js');
164
164
  return bootstrapStdio(config);
165
165
  }
166
- const { bootstrapHttp } = await import('./http-bootstrap-MEVOCFTE.js');
166
+ const { bootstrapHttp } = await import('./http-bootstrap-FN4DOOJT.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.17.1";
6
+ var VERSION = "0.19.1";
7
7
 
8
8
  export { NAME, VERSION };
9
- //# sourceMappingURL=chunk-HZDWYWEN.js.map
10
- //# sourceMappingURL=chunk-HZDWYWEN.js.map
9
+ //# sourceMappingURL=chunk-MKBTS4IH.js.map
10
+ //# sourceMappingURL=chunk-MKBTS4IH.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/shared/version.ts"],"names":[],"mappings":";;;;AASO,IAAM,IAAA,GAAO;AACb,IAAM,OAAA,GAAU","file":"chunk-HZDWYWEN.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.17.1\";\n"]}
1
+ {"version":3,"sources":["../src/shared/version.ts"],"names":[],"mappings":";;;;AASO,IAAM,IAAA,GAAO;AACb,IAAM,OAAA,GAAU","file":"chunk-MKBTS4IH.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.19.1\";\n"]}
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { err, ok } from './chunk-HZDWYWEN.js';
2
+ import { err, ok } from './chunk-MKBTS4IH.js';
3
3
  import { createHash, randomUUID } from 'crypto';
4
4
  import createClient from 'openapi-fetch';
5
5
  import { fetch } from 'undici';
@@ -978,6 +978,7 @@ var BalanceTransactionType = z.enum([
978
978
  "admin_adjustment",
979
979
  "refund",
980
980
  "invoice_settlement",
981
+ "invoice_payment_adjustment",
981
982
  "crypto_top_up",
982
983
  "card_top_up"
983
984
  ]);
@@ -1348,8 +1349,6 @@ var BillingSummarySchema = schemas.BillingSummaryResponse.pick({
1348
1349
  scheduled_effective_at: true
1349
1350
  }).strip();
1350
1351
  var parseBillingSummary = (raw) => parseWithSchema(BillingSummarySchema, raw, "billing-summary");
1351
-
1352
- // src/infrastructure/api/parsers/parse-campaign.ts
1353
1352
  var CampaignSchema = schemas.CampaignResponse.pick({
1354
1353
  id: true,
1355
1354
  name: true,
@@ -1378,7 +1377,7 @@ var CampaignSchema = schemas.CampaignResponse.pick({
1378
1377
  is_archived: true,
1379
1378
  created_at: true,
1380
1379
  last_run_at: true
1381
- }).extend({ repeat_mode: schemas.RepeatMode.default("isolated") }).strip();
1380
+ }).extend({ repeat_mode: schemas.RepeatMode.default("isolated") }).extend({ max_discovered_ads: z.number().int().nullable().optional() }).strip();
1382
1381
  var parseCampaign = (raw) => parseWithSchema(CampaignSchema, raw, "campaign");
1383
1382
  var parseCampaignPage = (raw) => parsePagedWithItemSchema(CampaignSchema, raw, "campaigns");
1384
1383
 
@@ -1840,12 +1839,10 @@ var ScanSchema = schemas.ScanResponse.pick({
1840
1839
  repeat_scan_ids: true,
1841
1840
  retry_attempt: true,
1842
1841
  retry_max_attempts: true
1843
- }).extend({ creative_kind: z.string().default("banner") }).strip();
1842
+ }).extend({ creative_kind: z.string().default("banner") }).extend({ max_discovered_ads: z.number().int().nullable().optional() }).extend({ network_host: z.string().optional() }).strip();
1844
1843
  var ScanArraySchema = z.array(ScanSchema);
1845
1844
  var parseScan = (raw) => parseWithSchema(ScanSchema, raw, "scan");
1846
1845
  var parseScanArray = (raw) => parseWithSchema(ScanArraySchema, raw, "scans");
1847
-
1848
- // src/infrastructure/api/parsers/parse-scan-page.ts
1849
1846
  var ScanBriefSchema = schemas.ScanBriefResponse.pick({
1850
1847
  id: true,
1851
1848
  url: true,
@@ -1872,7 +1869,7 @@ var ScanBriefSchema = schemas.ScanBriefResponse.pick({
1872
1869
  repeat_session_id: true,
1873
1870
  retry_attempt: true,
1874
1871
  retry_max_attempts: true
1875
- }).strip();
1872
+ }).extend({ network_host: z.string().optional() }).strip();
1876
1873
  var parseScanPage = (raw) => parsePagedWithItemSchema(ScanBriefSchema, raw, "scans");
1877
1874
  var TagDefinitionSchema = schemas.TagDefinitionWithStatsResponse.pick({
1878
1875
  slug: true,
@@ -3552,6 +3549,7 @@ var TransactionTypeEnum = z.enum([
3552
3549
  "admin_adjustment",
3553
3550
  "refund",
3554
3551
  "invoice_settlement",
3552
+ "invoice_payment_adjustment",
3555
3553
  "crypto_top_up",
3556
3554
  "card_top_up"
3557
3555
  ]);
@@ -3559,14 +3557,14 @@ var ListBalanceHistoryInputShape = {
3559
3557
  date_from: z.string().date().optional().describe("ISO date, inclusive."),
3560
3558
  date_to: z.string().date().optional().describe("ISO date, inclusive."),
3561
3559
  type: z.array(TransactionTypeEnum).max(TransactionTypeEnum.options.length).optional().describe(
3562
- "Filter by transaction kind. Pass several values to OR them (e.g. ['top_up_manual','crypto_top_up','card_top_up'] for credits-only)."
3560
+ "Filter by transaction kind. Pass several values to OR them (e.g. ['top_up_manual','crypto_top_up','card_top_up','invoice_settlement'] for every way a balance is funded). Note `invoice_payment_adjustment` is signed: a correction to an already-settled invoice can be either a credit or a debit."
3563
3561
  ),
3564
3562
  page: z.number().int().min(1).max(500).default(1).describe("1-indexed page."),
3565
3563
  limit: z.number().int().min(1).max(200).default(50).describe("Page size.")
3566
3564
  };
3567
3565
  var listBalanceHistoryTool = {
3568
3566
  name: "list_balance_history",
3569
- 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.",
3567
+ description: "List ledger transactions (charges, refunds, top-ups, invoice settlements and their corrections) on the organization's balance. Each row: type, amount in micros, description, timestamp. Filter by `type` (multi-select) and / or date range.",
3570
3568
  annotations: {
3571
3569
  title: "List Balance History",
3572
3570
  readOnlyHint: true,
@@ -3892,6 +3890,15 @@ var cancelCampaignTool = {
3892
3890
  return ok(result.value);
3893
3891
  }
3894
3892
  };
3893
+ var MAX_DISCOVERED_ADS_DESCRIPTION = 'How many ad blocks to look for on each publisher page before stopping (1-25). Every ad found becomes its own scan with its own report and is BILLED AS A SEPARATE CHECK, so this multiplies the cost: a page scanned at 25 can cost 26 checks \u2014 one parent plus its children. Only valid on an ad-discovery target \u2014 `ad_discovery: true` on a scan, or `campaign_type: "ad_discovery"` on a campaign \u2014 and rejected with 422 anywhere else.';
3894
+ var PLATFORM_DEFAULT_NOTE = "The platform default is 12 unless an operator retuned it.";
3895
+ var maxDiscoveredAds = z.number().int().min(1).max(25);
3896
+ var maxDiscoveredAdsField = maxDiscoveredAds.optional().describe(
3897
+ `${MAX_DISCOVERED_ADS_DESCRIPTION} Omit it to use the platform default. ` + PLATFORM_DEFAULT_NOTE
3898
+ );
3899
+ var maxDiscoveredAdsUpdateField = maxDiscoveredAds.nullable().optional().describe(
3900
+ `${MAX_DISCOVERED_ADS_DESCRIPTION} Omitting the field leaves the campaign's current setting unchanged; pass null to drop its own number and go back to the platform default. ${PLATFORM_DEFAULT_NOTE}`
3901
+ );
3895
3902
  var repeatRetryFields = {
3896
3903
  repeat_count: z.number().int().min(1).max(20).optional().describe(
3897
3904
  "How many times to repeat every scan this call already produces (1-20). It is a multiplier on top of the tool's own fan-out \u2014 see that tool's description for the exact formula \u2014 and each resulting repeat is a full scan with its own report and its own billing. 1-20 is the API's default ceiling; an operator can lower it during an incident, and then a value accepted here still comes back as a 422 from the API. Default: 1."
@@ -3986,6 +3993,7 @@ var CreateCampaignInputShape = {
3986
3993
  "VAST video ad tag: an http(s) URL of a VAST endpoint OR raw VAST XML (required if campaign_type=vast)."
3987
3994
  ),
3988
3995
  referrer: campaignReferrerField,
3996
+ max_discovered_ads: maxDiscoveredAdsField,
3989
3997
  country_codes: z.array(z.string().length(2)).min(1).describe("ISO 3166-1 alpha-2 codes \u2014 one scan per country per run."),
3990
3998
  group_id: z.string().uuid().optional().describe("Parent group UUID; defaults to the org's default group."),
3991
3999
  ...campaignConfigFields,
@@ -4013,6 +4021,7 @@ var createCampaignTool = {
4013
4021
  ...input.ad_tag !== void 0 ? { ad_tag: input.ad_tag } : {},
4014
4022
  ...input.vast_tag !== void 0 ? { vast_tag: input.vast_tag } : {},
4015
4023
  ...input.referrer !== void 0 ? { referrer: input.referrer } : {},
4024
+ ...input.max_discovered_ads !== void 0 ? { max_discovered_ads: input.max_discovered_ads } : {},
4016
4025
  ...input.group_id !== void 0 ? { group_id: input.group_id } : {},
4017
4026
  ...input.labels !== void 0 ? { labels: input.labels } : {},
4018
4027
  ...input.policy_set_id !== void 0 ? { policy_set_id: input.policy_set_id } : {},
@@ -4186,6 +4195,7 @@ var UpdateCampaignInputShape = {
4186
4195
  "New VAST video ad tag: an http(s) URL of a VAST endpoint OR raw VAST XML (vast-type campaigns)."
4187
4196
  ),
4188
4197
  referrer: campaignReferrerUpdateField,
4198
+ max_discovered_ads: maxDiscoveredAdsUpdateField,
4189
4199
  country_codes: z.array(z.string().length(2)).optional().describe("Replace the country list."),
4190
4200
  group_id: z.string().uuid().optional().describe("Move the campaign to another group."),
4191
4201
  ...campaignConfigFields,
@@ -4195,7 +4205,7 @@ var UpdateCampaignInputShape = {
4195
4205
  };
4196
4206
  var updateCampaignTool = {
4197
4207
  name: "update_campaign",
4198
- description: "Update one or more fields of a campaign. Fields not supplied are left unchanged. `policy_set_id` accepts null to clear the binding, and `referrer` accepts null to clear the publisher page scans are checked from.",
4208
+ description: "Update one or more fields of a campaign. Fields not supplied are left unchanged. `policy_set_id` accepts null to clear the binding, `referrer` accepts null to clear the publisher page scans are checked from, and `max_discovered_ads` accepts null to go back to the platform ad cap.",
4199
4209
  annotations: {
4200
4210
  title: "Update Campaign",
4201
4211
  readOnlyHint: false,
@@ -4211,6 +4221,7 @@ var updateCampaignTool = {
4211
4221
  ...input.ad_tag !== void 0 ? { ad_tag: input.ad_tag } : {},
4212
4222
  ...input.vast_tag !== void 0 ? { vast_tag: input.vast_tag } : {},
4213
4223
  ...input.referrer !== void 0 ? { referrer: input.referrer } : {},
4224
+ ...input.max_discovered_ads !== void 0 ? { max_discovered_ads: input.max_discovered_ads } : {},
4214
4225
  ...input.country_codes !== void 0 ? { country_codes: input.country_codes } : {},
4215
4226
  ...input.group_id !== void 0 ? { group_id: input.group_id } : {},
4216
4227
  ...input.labels !== void 0 ? { labels: input.labels } : {},
@@ -5314,6 +5325,7 @@ var CreateScanInputShape = {
5314
5325
  ad_discovery: z.boolean().optional().describe(
5315
5326
  "Publisher ad discovery: detect ad blocks on the page and spawn one child scan per detected ad (banner/pop). Only valid with `url`. Each child is a separate billed scan; list them with `list_scan_children`."
5316
5327
  ),
5328
+ max_discovered_ads: maxDiscoveredAdsField,
5317
5329
  ...repeatRetryFields
5318
5330
  };
5319
5331
  var createScanTool = {
@@ -5340,6 +5352,7 @@ var createScanTool = {
5340
5352
  ...input.campaign_id !== void 0 ? { campaign_id: input.campaign_id } : {},
5341
5353
  ...input.run_id !== void 0 ? { run_id: input.run_id } : {},
5342
5354
  ...input.ad_discovery !== void 0 ? { ad_discovery: input.ad_discovery } : {},
5355
+ ...input.max_discovered_ads !== void 0 ? { max_discovered_ads: input.max_discovered_ads } : {},
5343
5356
  ...pickRepeatRetryBody(input)
5344
5357
  };
5345
5358
  const result = await ctx.api.createScan(body);
@@ -5519,7 +5532,7 @@ var ListScanChildrenInputShape = {
5519
5532
  };
5520
5533
  var listScanChildrenTool = {
5521
5534
  name: "list_scan_children",
5522
- description: "List the discovered-ad child scans of a publisher ad-discovery scan \u2014 one per detected ad block on the page. Each child brief carries ad_kind (banner|pop), the attributed ad network, and slot_index. The repeat / retry fields are present but never meaningful here: a child is always its own group of one (`repeat_index` 0, `repeat_total` 1, `repeat_session_id` null) and is never re-crawled, because repeats and retries apply to the publisher scan \u2014 repeating an ad-discovery scan gives you several parents, each with its own children. Returns a paginated envelope with screenshot + report deep-links; link users with those, never hand-build URLs.",
5535
+ description: "List the discovered-ad child scans of a publisher ad-discovery scan \u2014 one per detected ad block on the page. Each child brief carries ad_kind (banner|pop), slot_index, and the ad's attribution split in two: network is the ad network's NAME and is empty when the ad server is unrecognised, network_host is the domain observed \u2014 so read network first and fall back to network_host. Both are empty when the ad came from infrastructure that is not an ad network (tag manager, analytics) or from the publisher's own creative CDN; a pop carries a network but no host, because pop networks rotate their serving domains. The repeat / retry fields are present but never meaningful here: a child is always its own group of one (`repeat_index` 0, `repeat_total` 1, `repeat_session_id` null) and is never re-crawled, because repeats and retries apply to the publisher scan \u2014 repeating an ad-discovery scan gives you several parents, each with its own children. Returns a paginated envelope with screenshot + report deep-links; link users with those, never hand-build URLs.",
5523
5536
  annotations: {
5524
5537
  title: "List Scan Children",
5525
5538
  readOnlyHint: true,
@@ -6227,5 +6240,5 @@ function formatToolError(error) {
6227
6240
  }
6228
6241
 
6229
6242
  export { BearerToken, SERVER_INSTRUCTIONS, createHttpApiGateway, createPinoLogger, declareEmptyResourcesAndPrompts, newRequestId, wireToolsIntoMcpServer };
6230
- //# sourceMappingURL=chunk-WOYPDCIR.js.map
6231
- //# sourceMappingURL=chunk-WOYPDCIR.js.map
6243
+ //# sourceMappingURL=chunk-NPSDASQE.js.map
6244
+ //# sourceMappingURL=chunk-NPSDASQE.js.map