@kaminari-ad/mcp 0.24.0 → 0.24.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,34 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.24.2] - 2026-10-03
11
+
12
+ ### Added
13
+
14
+ - **Listed in the official MCP Registry.** Every release tag now publishes
15
+ `server.json` to `registry.modelcontextprotocol.io` as
16
+ `io.github.kaminari-ad/mcp`, with both the npm package and the hosted
17
+ `https://mcp.kaminari.ad/mcp` endpoint. `package.json` carries the matching
18
+ `mcpName` the registry uses to verify package ownership.
19
+
20
+ ### Fixed
21
+
22
+ - **README privacy link.** It pointed at `kaminari.ad/legal/privacy`, which
23
+ returns 404; it now points at `kaminari.ad/privacy`.
24
+ - **npm homepage** now points at `https://kaminari.ad/mcp` instead of the
25
+ GitHub repository.
26
+
27
+ ## [0.24.1] - 2026-10-02
28
+
29
+ ### Fixed
30
+
31
+ - **`GET /` on the hosted HTTP endpoint redirects to the landing page.** The
32
+ bare `mcp.kaminari.ad` used to answer `404 Not found`, a dead end for people
33
+ and crawlers arriving from MCP directories. It now returns `301` to
34
+ `https://kaminari.ad/mcp` (override with `KAMINARI_AD_MCP_LANDING_URL`). No
35
+ auth, no API call; `/mcp`, `/healthz` and the OAuth discovery document are
36
+ unchanged.
37
+
10
38
  ## [0.24.0] - 2026-09-30
11
39
 
12
40
  > Requires the API release with campaign `notifications` and label routing.
package/README.md CHANGED
@@ -10,7 +10,7 @@ Lets AI agents (Cursor, Claude Desktop, Cline, and any MCP-compatible client) la
10
10
  [![node](https://img.shields.io/node/v/@kaminari-ad/mcp)](https://nodejs.org)
11
11
  [![CI](https://github.com/kaminari-ad/mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/kaminari-ad/mcp/actions/workflows/ci.yml)
12
12
  [![Provenance](https://img.shields.io/npm/v/@kaminari-ad/mcp?label=provenance&logo=github)](https://www.npmjs.com/package/@kaminari-ad/mcp)
13
- [![MCP Registry](https://img.shields.io/badge/MCP_Registry-listed-blue)](https://registry.modelcontextprotocol.io)
13
+ [![MCP Registry](https://img.shields.io/badge/MCP_Registry-listed-blue)](https://registry.modelcontextprotocol.io/v0/servers?search=io.github.kaminari-ad/mcp)
14
14
 
15
15
  ## Install (one click)
16
16
 
@@ -18,6 +18,8 @@ Lets AI agents (Cursor, Claude Desktop, Cline, and any MCP-compatible client) la
18
18
 
19
19
  <a href="https://kaminari.ad/mcp/install"><img alt="Install in Cursor" src="https://cursor.com/deeplink/mcp-install-dark.png" height="32" /></a>
20
20
 
21
+ What the server can do and how to connect any client: [Kaminari Ad MCP overview](https://kaminari.ad/mcp).
22
+
21
23
  ### Claude Desktop
22
24
 
23
25
  [**Download `kaminari-ad-mcp.mcpb`**](https://github.com/kaminari-ad/mcp/releases/latest/download/kaminari-ad-mcp.mcpb) → double-click to install. Claude Desktop shows a config form for your API key.
@@ -182,7 +184,7 @@ npm run lint && npm run typecheck && npm test
182
184
 
183
185
  See [CONTRIBUTING.md](CONTRIBUTING.md) for the development workflow and how to add a tool.
184
186
 
185
- > The maintainers run the full development gate (integration tests, deploy automation, prod smoke) on a private GitLab instance and mirror the repo to GitHub. The public CI on GitHub Actions ([`.github/workflows/ci.yml`](.github/workflows/ci.yml)) runs lint + typecheck + unit tests + build + bundle-size check on every community PR, so contributors get fast green/red feedback without needing access to the internal infra. Tag pushes (`v*.*.*`) trigger [`.github/workflows/release.yml`](.github/workflows/release.yml), which publishes the package to npm with OIDC provenance and creates the GitHub Release.
187
+ > The maintainers run the full development gate (integration tests, deploy automation, prod smoke) on a private GitLab instance and mirror the repo to GitHub. The public CI on GitHub Actions ([`.github/workflows/ci.yml`](.github/workflows/ci.yml)) runs lint + typecheck + unit tests + build + bundle-size check on every community PR, so contributors get fast green/red feedback without needing access to the internal infra. Tag pushes (`v*.*.*`) trigger [`.github/workflows/release.yml`](.github/workflows/release.yml), which publishes the package to npm with OIDC provenance, creates the GitHub Release and publishes [`server.json`](server.json) to the official MCP Registry.
186
188
 
187
189
  ---
188
190
 
@@ -202,12 +204,20 @@ We follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html) for the two
202
204
  ## Privacy
203
205
 
204
206
  - **Data collected by the MCP server itself:** none beyond the `Authorization` header it forwards. The HTTP transport is stateless — no sessions are persisted; each request is authenticated independently by its own Bearer. The only in-memory state is the leaky-bucket rate limiter keyed by `sha256(bearer)`.
205
- - **Data forwarded to Kaminari Ad:** every tool call is a thin pass-through to `/api/v1` over HTTPS. The Kaminari Ad privacy policy applies: [https://kaminari.ad/legal/privacy](https://kaminari.ad/legal/privacy).
207
+ - **Data forwarded to Kaminari Ad:** every tool call is a thin pass-through to `/api/v1` over HTTPS. The Kaminari Ad privacy policy applies: [https://kaminari.ad/privacy](https://kaminari.ad/privacy).
206
208
  - **Logs:** structured pino output, JSON in HTTP mode. The full Bearer token is redacted; only `bearer_hash = sha256(token).slice(0,8)` makes it into a log line, alongside `request_id`, `tool_name`, `api_status`, `elapsed_ms`. Tool inputs (which may contain customer scan IDs / URLs) are NOT logged.
207
209
  - **Telemetry:** none. The OSS build ships a `NoopErrorReporter`. We do not bundle Sentry, OpenTelemetry exporters, or PostHog.
208
210
 
209
211
  To report a security or privacy issue, see [SECURITY.md](SECURITY.md).
210
212
 
213
+ ## Learn more
214
+
215
+ - [Kaminari Ad MCP overview](https://kaminari.ad/mcp) — what agents can do with the server, with setup for every client.
216
+ - [MCP server developer docs](https://kaminari.ad/docs/developers/mcp-server) — transports, authentication and OAuth connected apps.
217
+ - [REST API quickstart](https://kaminari.ad/docs/developers/rest-quickstart) — the `/api/v1` surface every tool calls.
218
+ - [Malvertising, auto-redirect and cloaking detections](https://kaminari.ad/detections) — what a scan verdict can flag.
219
+ - [DarkSword in the ad stack: an iOS exploit chain](https://kaminari.ad/blog/darksword-ios-exploit-chain-in-ad-traffic) — research from the Kaminari Ad team.
220
+
211
221
  ## License
212
222
 
213
223
  MIT — see [LICENSE](LICENSE).
package/dist/bin.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { NAME, VERSION, err, ok } from './chunk-JTJY73XX.js';
2
+ import { NAME, VERSION, err, ok } from './chunk-4P6CNASK.js';
3
3
  import process from 'process';
4
4
  import { z } from 'zod';
5
5
 
@@ -79,7 +79,8 @@ var RawSchema = z.object({
79
79
  KAMINARI_AD_OAUTH_AUTHORIZATION_SERVER_URL: z.string().url().default("https://app.kaminari.ad"),
80
80
  // Space-separated scope list. We split on /\s+/ post-parse and drop
81
81
  // empty tokens so accidental double-spaces don't corrupt the array.
82
- KAMINARI_AD_OAUTH_SCOPES: z.string().optional()
82
+ KAMINARI_AD_OAUTH_SCOPES: z.string().optional(),
83
+ KAMINARI_AD_MCP_LANDING_URL: z.string().url().default("https://kaminari.ad/mcp")
83
84
  });
84
85
  function loadConfig(env) {
85
86
  const parsed = RawSchema.safeParse(env);
@@ -102,7 +103,8 @@ function loadConfig(env) {
102
103
  oauthProtectedResource: raw.KAMINARI_AD_OAUTH_PROTECTED_RESOURCE,
103
104
  oauthProtectedResourceMetadataUrl: raw.KAMINARI_AD_OAUTH_PROTECTED_RESOURCE_METADATA_URL,
104
105
  oauthAuthorizationServerUrl: raw.KAMINARI_AD_OAUTH_AUTHORIZATION_SERVER_URL,
105
- oauthScopes
106
+ oauthScopes,
107
+ landingUrl: raw.KAMINARI_AD_MCP_LANDING_URL
106
108
  });
107
109
  }
108
110
 
@@ -160,10 +162,10 @@ async function main() {
160
162
  }
161
163
  const config = configResult.value;
162
164
  if (config.transport === "stdio") {
163
- const { bootstrapStdio } = await import('./stdio-bootstrap-HDLBAPCW.js');
165
+ const { bootstrapStdio } = await import('./stdio-bootstrap-M4TOIBTL.js');
164
166
  return bootstrapStdio(config);
165
167
  }
166
- const { bootstrapHttp } = await import('./http-bootstrap-URSEZ7YN.js');
168
+ const { bootstrapHttp } = await import('./http-bootstrap-KBFALUIO.js');
167
169
  return bootstrapHttp(config);
168
170
  }
169
171
  main().then(
package/dist/bin.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/shared/check-node-version.ts","../src/shared/oauth-scope-catalogue.ts","../src/shared/config.ts","../src/bin.ts"],"names":[],"mappings":"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","file":"bin.js","sourcesContent":["/**\n * Pure Node-version preflight, extracted from {@link bin.ts} so it\n * can be unit-tested without `process.exit` side effects.\n *\n * Why this exists: `undici@8.x` removed feature probes in v8.0.3 and\n * imports `markAsUncloneable` from `node:worker_threads`\n * unconditionally — that symbol only exists on Node 22.19+. Older\n * Node versions crash at import time with the cryptic message\n * `webidl.util.markAsUncloneable is not a function`. We surface a\n * clean upgrade message instead, BEFORE any dynamic import pulls\n * undici.\n *\n * Keep {@link REQUIRED_NODE_MAJOR} / {@link REQUIRED_NODE_MINOR} in\n * sync with `engines.node` in `package.json` (currently\n * `>=22.19.0`).\n */\n\nimport { err, ok, type Result } from \"./result.js\";\nimport { NAME } from \"./version.js\";\n\nexport const REQUIRED_NODE_MAJOR = 22;\nexport const REQUIRED_NODE_MINOR = 19;\n\n/**\n * Check whether `nodeVersion` (e.g. `\"22.19.0\"`, the value of\n * `process.versions.node`) satisfies the package's runtime floor.\n *\n * Returns `Ok(undefined)` on pass, `Err(message)` with a multi-line\n * upgrade message on fail. The message is plain text ready to be\n * written to stderr verbatim.\n */\nexport function checkNodeVersion(nodeVersion: string): Result<undefined, string> {\n const parts = nodeVersion.split(\".\");\n const major = Number(parts[0]);\n const minor = Number(parts[1]);\n if (\n Number.isNaN(major) ||\n Number.isNaN(minor) ||\n major < REQUIRED_NODE_MAJOR ||\n (major === REQUIRED_NODE_MAJOR && minor < REQUIRED_NODE_MINOR)\n ) {\n const required = `>=${String(REQUIRED_NODE_MAJOR)}.${String(REQUIRED_NODE_MINOR)}.0`;\n return err(\n [\n `${NAME} requires Node.js ${required} (you have v${nodeVersion}).`,\n \"\",\n \"The underlying undici 8.x HTTP client uses markAsUncloneable\",\n \"from node:worker_threads, available only on Node 22.19+.\",\n \"Older Node crashes at import time with the cryptic message\",\n \"`webidl.util.markAsUncloneable is not a function`.\",\n \"\",\n \"Please upgrade Node and re-run: https://nodejs.org/en/download\",\n ].join(\"\\n\")\n );\n }\n return ok(undefined);\n}\n","/**\n * Canonical catalogue of OAuth 2.0 scopes the Kaminari Ad MCP server\n * advertises in its protected-resource metadata (RFC 9728) and\n * `WWW-Authenticate: Bearer scope=\"...\"` challenge.\n *\n * The catalogue is intentionally static and lives in `shared/` because\n * (a) it has no runtime behaviour — it is data — and (b) it is read by\n * both the `protected-resource-metadata-handler` and the\n * `www-authenticate` builder. If a new scope is added on the\n * Authorization Server side, mirror it here in the same release so the\n * Resource Server (this process) advertises it.\n *\n * `offline_access` is part of the catalogue per RFC 6749 §6 because\n * the Authorization Server issues refresh tokens only when the client\n * requests this scope. Anthropic's Claude clients append it\n * automatically when the server advertises it in\n * `scopes_supported`/the `WWW-Authenticate` `scope=` parameter.\n */\n\n/**\n * Default scope catalogue, frozen at build time.\n *\n * MUST stay byte-identical to the Authorization Server's advertised\n * catalogue (`app.oauth_authorization.domain.entities.scope.advertised_scopes()`\n * — i.e. `sorted(KNOWN_SCOPES)`). The order is lexicographic, which\n * happens to yield the desired semantics for free: `:read` sorts before\n * `:write` within a resource, and `offline_access` sorts after every\n * `mcp:` scope.\n *\n * Read scopes grant the resource's view permission; write scopes grant\n * read + the resource's mutating permissions. billing/invoicing/account\n * are read-only over OAuth by design (money-spend / privilege-escalation\n * tools stay API-key only). When the AS catalogue changes, mirror it\n * here in the same release — `tests/unit/shared/oauth-scope-catalogue.test.ts`\n * pins the exact list so drift fails CI.\n */\nexport const DEFAULT_OAUTH_SCOPES: readonly string[] = Object.freeze([\n \"mcp:account:read\",\n \"mcp:alert_notifications:read\",\n \"mcp:alert_notifications:write\",\n \"mcp:alerts:read\",\n \"mcp:alerts:write\",\n \"mcp:billing:read\",\n \"mcp:campaigns:read\",\n \"mcp:campaigns:write\",\n \"mcp:custom_rules:read\",\n \"mcp:custom_rules:write\",\n \"mcp:invoicing:read\",\n \"mcp:policies:read\",\n \"mcp:policies:write\",\n \"mcp:scans:read\",\n \"mcp:scans:write\",\n \"mcp:tags:read\",\n \"mcp:tags:write\",\n \"mcp:taxonomies:read\",\n \"mcp:taxonomies:write\",\n \"mcp:webhooks:read\",\n \"mcp:webhooks:write\",\n \"offline_access\",\n]);\n","/**\n * Runtime configuration for `@kaminari-ad/mcp`.\n *\n * The single source of truth for all env-var reads. `process.env.X`\n * outside this file is a code-review blocker — every config value flows\n * through the zod-parsed {@link Config} object.\n */\n\nimport { z } from \"zod\";\n\nimport { DEFAULT_OAUTH_SCOPES } from \"./oauth-scope-catalogue.js\";\nimport { err, ok, type Result } from \"./result.js\";\n\n/**\n * MCP transport. `stdio` is for local install (one process per user);\n * `http` is for the hosted multi-tenant endpoint.\n */\nexport const TransportSchema = z.enum([\"stdio\", \"http\"]);\nexport type Transport = z.infer<typeof TransportSchema>;\n\n/**\n * pino log level.\n */\nexport const LogLevelSchema = z.enum([\"trace\", \"debug\", \"info\", \"warn\", \"error\", \"fatal\"]);\nexport type LogLevel = z.infer<typeof LogLevelSchema>;\n\n/**\n * pino log output format.\n *\n * - `pretty` — colorised single-line ANSI output for terminals. Default\n * in stdio mode (operator reads stderr in their shell).\n * - `json` — newline-delimited JSON, one record per line. Default in\n * HTTP mode (Docker/k8s log aggregators expect JSON). MCP hosts that\n * capture stderr from the stdio process (Cursor, Claude Desktop)\n * parse much better with `json` — flip this when the operator is a\n * machine, not a human.\n */\nexport const LogFormatSchema = z.enum([\"pretty\", \"json\"]);\nexport type LogFormat = z.infer<typeof LogFormatSchema>;\n\n/**\n * Parsed configuration. All fields are `readonly` — mutation post-load\n * is a bug.\n */\nexport interface Config {\n readonly transport: Transport;\n readonly apiBaseUrl: string;\n readonly logLevel: LogLevel;\n readonly logFormat: LogFormat;\n readonly httpPort: number;\n readonly rateLimitRpm: number;\n /**\n * Set only in stdio mode. In HTTP mode the bootstrap MUST assert\n * this is `undefined` (see CONTRIBUTING.md \"Tenant isolation\" §5).\n */\n readonly stdioApiKey: string | undefined;\n /**\n * Canonical MCP endpoint URL advertised as the `resource` field of\n * the RFC 9728 protected-resource metadata document. Anthropic's\n * Claude clients require this to match the URL the user enters in\n * Claude exactly (including the path component).\n */\n readonly oauthProtectedResource: string;\n /**\n * Absolute URL where this server serves the protected-resource\n * metadata JSON. Advertised back to clients via\n * `WWW-Authenticate: Bearer resource_metadata=\"…\"` on 401.\n */\n readonly oauthProtectedResourceMetadataUrl: string;\n /**\n * Issuer URL of the Authorization Server that mints access tokens\n * accepted by this Resource Server. Advertised as the first (and\n * only) entry of the metadata's `authorization_servers` array.\n */\n readonly oauthAuthorizationServerUrl: string;\n /**\n * Scopes the Resource Server advertises in both the metadata's\n * `scopes_supported` field and the 401 `WWW-Authenticate scope=…`\n * parameter. Defaults to {@link DEFAULT_OAUTH_SCOPES}; operators\n * may override via `KAMINARI_AD_OAUTH_SCOPES` (space-separated).\n */\n readonly oauthScopes: readonly string[];\n}\n\n/**\n * Every env var carries the `KAMINARI_AD_` namespace prefix.\n *\n * Why: this process inherits the host's full environment (Cursor /\n * Claude Desktop / Docker compose / k8s pod), where `API_BASE_URL` /\n * `LOG_LEVEL` / `HTTP_PORT` are common generic names. Without a\n * namespace, another tool in the same shell trivially poisons our\n * config — e.g. `LOG_LEVEL=debug` set for some app library suddenly\n * makes the MCP server log every secret-redacted-but-still-noisy\n * request to stderr, and the user has no idea why. With the prefix\n * the boundary is explicit and `env | grep KAMINARI_AD_` enumerates\n * exactly what we read.\n */\nconst RawSchema = z.object({\n KAMINARI_AD_TRANSPORT: TransportSchema.default(\"stdio\"),\n // `app.kaminari.ad` is the API host; `kaminari.ad` (no subdomain)\n // is the marketing landing page and does NOT serve /api/v1/*.\n // Setting this wrong (e.g. the root domain) makes every tool call\n // fail with HTTP 404 — the symptom that surfaced this default bug\n // in v0.2.0.\n KAMINARI_AD_API_URL: z.string().url().default(\"https://app.kaminari.ad\"),\n KAMINARI_AD_LOG_LEVEL: LogLevelSchema.default(\"info\"),\n KAMINARI_AD_LOG_FORMAT: LogFormatSchema.optional(),\n KAMINARI_AD_HTTP_PORT: z.coerce.number().int().min(0).max(65535).default(8080),\n KAMINARI_AD_RATE_LIMIT_RPM: z.coerce.number().int().min(1).max(10_000).default(120),\n KAMINARI_AD_API_KEY: z.string().min(8).optional(),\n // OAuth discovery (RFC 9728 protected-resource + RFC 8414 AS\n // metadata). All three URLs default to the production deployment;\n // local/staging operators override per-environment.\n KAMINARI_AD_OAUTH_PROTECTED_RESOURCE: z.string().url().default(\"https://mcp.kaminari.ad/mcp\"),\n KAMINARI_AD_OAUTH_PROTECTED_RESOURCE_METADATA_URL: z\n .string()\n .url()\n .default(\"https://mcp.kaminari.ad/.well-known/oauth-protected-resource\"),\n KAMINARI_AD_OAUTH_AUTHORIZATION_SERVER_URL: z.string().url().default(\"https://app.kaminari.ad\"),\n // Space-separated scope list. We split on /\\s+/ post-parse and drop\n // empty tokens so accidental double-spaces don't corrupt the array.\n KAMINARI_AD_OAUTH_SCOPES: z.string().optional(),\n});\n\n/**\n * Parse and validate environment variables into a {@link Config}.\n *\n * Returns `Err<ConfigError>` on validation failure. Caller (typically\n * `bin.ts`) prints the error and exits non-zero.\n *\n * `KAMINARI_AD_LOG_FORMAT` defaults are transport-dependent: `pretty`\n * for stdio (terminal-facing) and `json` for http (aggregator-facing).\n * If the user sets the env var explicitly, that wins.\n */\nexport function loadConfig(env: NodeJS.ProcessEnv): Result<Config, ConfigError> {\n const parsed = RawSchema.safeParse(env);\n if (!parsed.success) {\n return err({ kind: \"invalid\", issues: parsed.error.flatten().fieldErrors });\n }\n const raw = parsed.data;\n const transport = raw.KAMINARI_AD_TRANSPORT;\n const logFormat = raw.KAMINARI_AD_LOG_FORMAT ?? (transport === \"stdio\" ? \"pretty\" : \"json\");\n const oauthScopesRaw = raw.KAMINARI_AD_OAUTH_SCOPES;\n const oauthScopes: readonly string[] =\n oauthScopesRaw === undefined\n ? DEFAULT_OAUTH_SCOPES\n : Object.freeze(oauthScopesRaw.split(/\\s+/).filter((s) => s.length > 0));\n return ok({\n transport,\n apiBaseUrl: raw.KAMINARI_AD_API_URL,\n logLevel: raw.KAMINARI_AD_LOG_LEVEL,\n logFormat,\n httpPort: raw.KAMINARI_AD_HTTP_PORT,\n rateLimitRpm: raw.KAMINARI_AD_RATE_LIMIT_RPM,\n stdioApiKey: raw.KAMINARI_AD_API_KEY,\n oauthProtectedResource: raw.KAMINARI_AD_OAUTH_PROTECTED_RESOURCE,\n oauthProtectedResourceMetadataUrl: raw.KAMINARI_AD_OAUTH_PROTECTED_RESOURCE_METADATA_URL,\n oauthAuthorizationServerUrl: raw.KAMINARI_AD_OAUTH_AUTHORIZATION_SERVER_URL,\n oauthScopes,\n });\n}\n\n/**\n * Errors from {@link loadConfig}.\n */\nexport interface ConfigError {\n readonly kind: \"invalid\";\n readonly issues: Readonly<Record<string, readonly string[] | undefined>>;\n}\n","/**\n * CLI entrypoint for `@kaminari-ad/mcp`.\n *\n * Dispatches to a transport-specific composition root (stdio or HTTP)\n * based on the `--transport` flag (or `TRANSPORT` env var, with stdio\n * as the default).\n *\n * Wire-up is intentionally minimal — every dependency is constructed\n * inside the chosen bootstrap, never here. This file just parses argv\n * and config, then hands off.\n *\n * Imports policy: the STATIC imports below MUST stay free of any\n * runtime dependency that requires Node >= 22.19 (undici, MCP SDK,\n * pino). Otherwise the Node-version preflight in `main()` runs too\n * late — those modules crash at import time on older Node. The\n * transport bootstraps pull undici / MCP SDK / pino via dynamic\n * `await import()` so the preflight gets to fire first.\n */\n\nimport process from \"node:process\";\n\nimport { checkNodeVersion } from \"./shared/check-node-version.js\";\nimport { loadConfig, type Transport } from \"./shared/config.js\";\nimport { NAME, VERSION } from \"./shared/version.js\";\n\nfunction parseTransportFlag(argv: readonly string[]): Transport | undefined {\n for (const arg of argv) {\n if (arg === \"--transport=stdio\" || arg === \"--transport=http\") {\n return arg === \"--transport=stdio\" ? \"stdio\" : \"http\";\n }\n if (arg.startsWith(\"--transport=\")) {\n const value = arg.slice(\"--transport=\".length);\n if (value === \"stdio\" || value === \"http\") return value;\n }\n }\n return undefined;\n}\n\nasync function main(): Promise<number> {\n const argv = process.argv.slice(2);\n\n // Informational flags handled BEFORE the Node preflight so users on\n // any Node can confirm the binary resolves and discover the help\n // text — the only paths that touch zero runtime deps.\n if (argv.includes(\"--version\") || argv.includes(\"-v\")) {\n process.stdout.write(`${NAME} ${VERSION}\\n`);\n return 0;\n }\n if (argv.includes(\"--help\") || argv.includes(\"-h\")) {\n process.stdout.write(\n [\n `${NAME} ${VERSION}`,\n ``,\n `Usage:`,\n ` kaminari-ad-mcp [--transport=stdio|http]`,\n ``,\n `Transports:`,\n ` stdio (default) Local install — auth via KAMINARI_AD_API_KEY env var.`,\n ` http Hosted multi-tenant server — auth via incoming Authorization header.`,\n ``,\n `Configuration is documented in .env.example.`,\n ``,\n ].join(\"\\n\")\n );\n return 0;\n }\n\n // Preflight: bail with a clean upgrade message BEFORE any dynamic\n // import pulls undici / MCP SDK / pino — all three require\n // Node 22.19+ and crash at import time on older Node. Without this\n // gate users see undici's cryptic\n // `webidl.util.markAsUncloneable is not a function` instead.\n const check = checkNodeVersion(process.versions.node);\n if (check.isErr()) {\n process.stderr.write(`${check.error}\\n`);\n return 2;\n }\n\n const cliTransport = parseTransportFlag(argv);\n const env: NodeJS.ProcessEnv = cliTransport\n ? { ...process.env, KAMINARI_AD_TRANSPORT: cliTransport }\n : process.env;\n\n const configResult = loadConfig(env);\n if (configResult.isErr()) {\n process.stderr.write(`Invalid configuration: ${JSON.stringify(configResult.error.issues)}\\n`);\n return 2;\n }\n const config = configResult.value;\n\n if (config.transport === \"stdio\") {\n const { bootstrapStdio } = await import(\"./presentation/stdio/stdio-bootstrap.js\");\n return bootstrapStdio(config);\n }\n const { bootstrapHttp } = await import(\"./presentation/http/http-bootstrap.js\");\n return bootstrapHttp(config);\n}\n\nmain().then(\n (code) => {\n process.exit(code);\n },\n (error: unknown) => {\n process.stderr.write(`Fatal: ${error instanceof Error ? error.message : String(error)}\\n`);\n process.exit(1);\n }\n);\n"]}
1
+ {"version":3,"sources":["../src/shared/check-node-version.ts","../src/shared/oauth-scope-catalogue.ts","../src/shared/config.ts","../src/bin.ts"],"names":[],"mappings":"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","file":"bin.js","sourcesContent":["/**\n * Pure Node-version preflight, extracted from {@link bin.ts} so it\n * can be unit-tested without `process.exit` side effects.\n *\n * Why this exists: `undici@8.x` removed feature probes in v8.0.3 and\n * imports `markAsUncloneable` from `node:worker_threads`\n * unconditionally — that symbol only exists on Node 22.19+. Older\n * Node versions crash at import time with the cryptic message\n * `webidl.util.markAsUncloneable is not a function`. We surface a\n * clean upgrade message instead, BEFORE any dynamic import pulls\n * undici.\n *\n * Keep {@link REQUIRED_NODE_MAJOR} / {@link REQUIRED_NODE_MINOR} in\n * sync with `engines.node` in `package.json` (currently\n * `>=22.19.0`).\n */\n\nimport { err, ok, type Result } from \"./result.js\";\nimport { NAME } from \"./version.js\";\n\nexport const REQUIRED_NODE_MAJOR = 22;\nexport const REQUIRED_NODE_MINOR = 19;\n\n/**\n * Check whether `nodeVersion` (e.g. `\"22.19.0\"`, the value of\n * `process.versions.node`) satisfies the package's runtime floor.\n *\n * Returns `Ok(undefined)` on pass, `Err(message)` with a multi-line\n * upgrade message on fail. The message is plain text ready to be\n * written to stderr verbatim.\n */\nexport function checkNodeVersion(nodeVersion: string): Result<undefined, string> {\n const parts = nodeVersion.split(\".\");\n const major = Number(parts[0]);\n const minor = Number(parts[1]);\n if (\n Number.isNaN(major) ||\n Number.isNaN(minor) ||\n major < REQUIRED_NODE_MAJOR ||\n (major === REQUIRED_NODE_MAJOR && minor < REQUIRED_NODE_MINOR)\n ) {\n const required = `>=${String(REQUIRED_NODE_MAJOR)}.${String(REQUIRED_NODE_MINOR)}.0`;\n return err(\n [\n `${NAME} requires Node.js ${required} (you have v${nodeVersion}).`,\n \"\",\n \"The underlying undici 8.x HTTP client uses markAsUncloneable\",\n \"from node:worker_threads, available only on Node 22.19+.\",\n \"Older Node crashes at import time with the cryptic message\",\n \"`webidl.util.markAsUncloneable is not a function`.\",\n \"\",\n \"Please upgrade Node and re-run: https://nodejs.org/en/download\",\n ].join(\"\\n\")\n );\n }\n return ok(undefined);\n}\n","/**\n * Canonical catalogue of OAuth 2.0 scopes the Kaminari Ad MCP server\n * advertises in its protected-resource metadata (RFC 9728) and\n * `WWW-Authenticate: Bearer scope=\"...\"` challenge.\n *\n * The catalogue is intentionally static and lives in `shared/` because\n * (a) it has no runtime behaviour — it is data — and (b) it is read by\n * both the `protected-resource-metadata-handler` and the\n * `www-authenticate` builder. If a new scope is added on the\n * Authorization Server side, mirror it here in the same release so the\n * Resource Server (this process) advertises it.\n *\n * `offline_access` is part of the catalogue per RFC 6749 §6 because\n * the Authorization Server issues refresh tokens only when the client\n * requests this scope. Anthropic's Claude clients append it\n * automatically when the server advertises it in\n * `scopes_supported`/the `WWW-Authenticate` `scope=` parameter.\n */\n\n/**\n * Default scope catalogue, frozen at build time.\n *\n * MUST stay byte-identical to the Authorization Server's advertised\n * catalogue (`app.oauth_authorization.domain.entities.scope.advertised_scopes()`\n * — i.e. `sorted(KNOWN_SCOPES)`). The order is lexicographic, which\n * happens to yield the desired semantics for free: `:read` sorts before\n * `:write` within a resource, and `offline_access` sorts after every\n * `mcp:` scope.\n *\n * Read scopes grant the resource's view permission; write scopes grant\n * read + the resource's mutating permissions. billing/invoicing/account\n * are read-only over OAuth by design (money-spend / privilege-escalation\n * tools stay API-key only). When the AS catalogue changes, mirror it\n * here in the same release — `tests/unit/shared/oauth-scope-catalogue.test.ts`\n * pins the exact list so drift fails CI.\n */\nexport const DEFAULT_OAUTH_SCOPES: readonly string[] = Object.freeze([\n \"mcp:account:read\",\n \"mcp:alert_notifications:read\",\n \"mcp:alert_notifications:write\",\n \"mcp:alerts:read\",\n \"mcp:alerts:write\",\n \"mcp:billing:read\",\n \"mcp:campaigns:read\",\n \"mcp:campaigns:write\",\n \"mcp:custom_rules:read\",\n \"mcp:custom_rules:write\",\n \"mcp:invoicing:read\",\n \"mcp:policies:read\",\n \"mcp:policies:write\",\n \"mcp:scans:read\",\n \"mcp:scans:write\",\n \"mcp:tags:read\",\n \"mcp:tags:write\",\n \"mcp:taxonomies:read\",\n \"mcp:taxonomies:write\",\n \"mcp:webhooks:read\",\n \"mcp:webhooks:write\",\n \"offline_access\",\n]);\n","/**\n * Runtime configuration for `@kaminari-ad/mcp`.\n *\n * The single source of truth for all env-var reads. `process.env.X`\n * outside this file is a code-review blocker — every config value flows\n * through the zod-parsed {@link Config} object.\n */\n\nimport { z } from \"zod\";\n\nimport { DEFAULT_OAUTH_SCOPES } from \"./oauth-scope-catalogue.js\";\nimport { err, ok, type Result } from \"./result.js\";\n\n/**\n * MCP transport. `stdio` is for local install (one process per user);\n * `http` is for the hosted multi-tenant endpoint.\n */\nexport const TransportSchema = z.enum([\"stdio\", \"http\"]);\nexport type Transport = z.infer<typeof TransportSchema>;\n\n/**\n * pino log level.\n */\nexport const LogLevelSchema = z.enum([\"trace\", \"debug\", \"info\", \"warn\", \"error\", \"fatal\"]);\nexport type LogLevel = z.infer<typeof LogLevelSchema>;\n\n/**\n * pino log output format.\n *\n * - `pretty` — colorised single-line ANSI output for terminals. Default\n * in stdio mode (operator reads stderr in their shell).\n * - `json` — newline-delimited JSON, one record per line. Default in\n * HTTP mode (Docker/k8s log aggregators expect JSON). MCP hosts that\n * capture stderr from the stdio process (Cursor, Claude Desktop)\n * parse much better with `json` — flip this when the operator is a\n * machine, not a human.\n */\nexport const LogFormatSchema = z.enum([\"pretty\", \"json\"]);\nexport type LogFormat = z.infer<typeof LogFormatSchema>;\n\n/**\n * Parsed configuration. All fields are `readonly` — mutation post-load\n * is a bug.\n */\nexport interface Config {\n readonly transport: Transport;\n readonly apiBaseUrl: string;\n readonly logLevel: LogLevel;\n readonly logFormat: LogFormat;\n readonly httpPort: number;\n readonly rateLimitRpm: number;\n /**\n * Set only in stdio mode. In HTTP mode the bootstrap MUST assert\n * this is `undefined` (see CONTRIBUTING.md \"Tenant isolation\" §5).\n */\n readonly stdioApiKey: string | undefined;\n /**\n * Canonical MCP endpoint URL advertised as the `resource` field of\n * the RFC 9728 protected-resource metadata document. Anthropic's\n * Claude clients require this to match the URL the user enters in\n * Claude exactly (including the path component).\n */\n readonly oauthProtectedResource: string;\n /**\n * Absolute URL where this server serves the protected-resource\n * metadata JSON. Advertised back to clients via\n * `WWW-Authenticate: Bearer resource_metadata=\"…\"` on 401.\n */\n readonly oauthProtectedResourceMetadataUrl: string;\n /**\n * Issuer URL of the Authorization Server that mints access tokens\n * accepted by this Resource Server. Advertised as the first (and\n * only) entry of the metadata's `authorization_servers` array.\n */\n readonly oauthAuthorizationServerUrl: string;\n /**\n * Scopes the Resource Server advertises in both the metadata's\n * `scopes_supported` field and the 401 `WWW-Authenticate scope=…`\n * parameter. Defaults to {@link DEFAULT_OAUTH_SCOPES}; operators\n * may override via `KAMINARI_AD_OAUTH_SCOPES` (space-separated).\n */\n readonly oauthScopes: readonly string[];\n /**\n * Public landing page for the MCP server. `GET /` on the hosted\n * endpoint permanently redirects here so the bare subdomain is not a\n * dead end for people and crawlers.\n */\n readonly landingUrl: string;\n}\n\n/**\n * Every env var carries the `KAMINARI_AD_` namespace prefix.\n *\n * Why: this process inherits the host's full environment (Cursor /\n * Claude Desktop / Docker compose / k8s pod), where `API_BASE_URL` /\n * `LOG_LEVEL` / `HTTP_PORT` are common generic names. Without a\n * namespace, another tool in the same shell trivially poisons our\n * config — e.g. `LOG_LEVEL=debug` set for some app library suddenly\n * makes the MCP server log every secret-redacted-but-still-noisy\n * request to stderr, and the user has no idea why. With the prefix\n * the boundary is explicit and `env | grep KAMINARI_AD_` enumerates\n * exactly what we read.\n */\nconst RawSchema = z.object({\n KAMINARI_AD_TRANSPORT: TransportSchema.default(\"stdio\"),\n // `app.kaminari.ad` is the API host; `kaminari.ad` (no subdomain)\n // is the marketing landing page and does NOT serve /api/v1/*.\n // Setting this wrong (e.g. the root domain) makes every tool call\n // fail with HTTP 404 — the symptom that surfaced this default bug\n // in v0.2.0.\n KAMINARI_AD_API_URL: z.string().url().default(\"https://app.kaminari.ad\"),\n KAMINARI_AD_LOG_LEVEL: LogLevelSchema.default(\"info\"),\n KAMINARI_AD_LOG_FORMAT: LogFormatSchema.optional(),\n KAMINARI_AD_HTTP_PORT: z.coerce.number().int().min(0).max(65535).default(8080),\n KAMINARI_AD_RATE_LIMIT_RPM: z.coerce.number().int().min(1).max(10_000).default(120),\n KAMINARI_AD_API_KEY: z.string().min(8).optional(),\n // OAuth discovery (RFC 9728 protected-resource + RFC 8414 AS\n // metadata). All three URLs default to the production deployment;\n // local/staging operators override per-environment.\n KAMINARI_AD_OAUTH_PROTECTED_RESOURCE: z.string().url().default(\"https://mcp.kaminari.ad/mcp\"),\n KAMINARI_AD_OAUTH_PROTECTED_RESOURCE_METADATA_URL: z\n .string()\n .url()\n .default(\"https://mcp.kaminari.ad/.well-known/oauth-protected-resource\"),\n KAMINARI_AD_OAUTH_AUTHORIZATION_SERVER_URL: z.string().url().default(\"https://app.kaminari.ad\"),\n // Space-separated scope list. We split on /\\s+/ post-parse and drop\n // empty tokens so accidental double-spaces don't corrupt the array.\n KAMINARI_AD_OAUTH_SCOPES: z.string().optional(),\n KAMINARI_AD_MCP_LANDING_URL: z.string().url().default(\"https://kaminari.ad/mcp\"),\n});\n\n/**\n * Parse and validate environment variables into a {@link Config}.\n *\n * Returns `Err<ConfigError>` on validation failure. Caller (typically\n * `bin.ts`) prints the error and exits non-zero.\n *\n * `KAMINARI_AD_LOG_FORMAT` defaults are transport-dependent: `pretty`\n * for stdio (terminal-facing) and `json` for http (aggregator-facing).\n * If the user sets the env var explicitly, that wins.\n */\nexport function loadConfig(env: NodeJS.ProcessEnv): Result<Config, ConfigError> {\n const parsed = RawSchema.safeParse(env);\n if (!parsed.success) {\n return err({ kind: \"invalid\", issues: parsed.error.flatten().fieldErrors });\n }\n const raw = parsed.data;\n const transport = raw.KAMINARI_AD_TRANSPORT;\n const logFormat = raw.KAMINARI_AD_LOG_FORMAT ?? (transport === \"stdio\" ? \"pretty\" : \"json\");\n const oauthScopesRaw = raw.KAMINARI_AD_OAUTH_SCOPES;\n const oauthScopes: readonly string[] =\n oauthScopesRaw === undefined\n ? DEFAULT_OAUTH_SCOPES\n : Object.freeze(oauthScopesRaw.split(/\\s+/).filter((s) => s.length > 0));\n return ok({\n transport,\n apiBaseUrl: raw.KAMINARI_AD_API_URL,\n logLevel: raw.KAMINARI_AD_LOG_LEVEL,\n logFormat,\n httpPort: raw.KAMINARI_AD_HTTP_PORT,\n rateLimitRpm: raw.KAMINARI_AD_RATE_LIMIT_RPM,\n stdioApiKey: raw.KAMINARI_AD_API_KEY,\n oauthProtectedResource: raw.KAMINARI_AD_OAUTH_PROTECTED_RESOURCE,\n oauthProtectedResourceMetadataUrl: raw.KAMINARI_AD_OAUTH_PROTECTED_RESOURCE_METADATA_URL,\n oauthAuthorizationServerUrl: raw.KAMINARI_AD_OAUTH_AUTHORIZATION_SERVER_URL,\n oauthScopes,\n landingUrl: raw.KAMINARI_AD_MCP_LANDING_URL,\n });\n}\n\n/**\n * Errors from {@link loadConfig}.\n */\nexport interface ConfigError {\n readonly kind: \"invalid\";\n readonly issues: Readonly<Record<string, readonly string[] | undefined>>;\n}\n","/**\n * CLI entrypoint for `@kaminari-ad/mcp`.\n *\n * Dispatches to a transport-specific composition root (stdio or HTTP)\n * based on the `--transport` flag (or `TRANSPORT` env var, with stdio\n * as the default).\n *\n * Wire-up is intentionally minimal — every dependency is constructed\n * inside the chosen bootstrap, never here. This file just parses argv\n * and config, then hands off.\n *\n * Imports policy: the STATIC imports below MUST stay free of any\n * runtime dependency that requires Node >= 22.19 (undici, MCP SDK,\n * pino). Otherwise the Node-version preflight in `main()` runs too\n * late — those modules crash at import time on older Node. The\n * transport bootstraps pull undici / MCP SDK / pino via dynamic\n * `await import()` so the preflight gets to fire first.\n */\n\nimport process from \"node:process\";\n\nimport { checkNodeVersion } from \"./shared/check-node-version.js\";\nimport { loadConfig, type Transport } from \"./shared/config.js\";\nimport { NAME, VERSION } from \"./shared/version.js\";\n\nfunction parseTransportFlag(argv: readonly string[]): Transport | undefined {\n for (const arg of argv) {\n if (arg === \"--transport=stdio\" || arg === \"--transport=http\") {\n return arg === \"--transport=stdio\" ? \"stdio\" : \"http\";\n }\n if (arg.startsWith(\"--transport=\")) {\n const value = arg.slice(\"--transport=\".length);\n if (value === \"stdio\" || value === \"http\") return value;\n }\n }\n return undefined;\n}\n\nasync function main(): Promise<number> {\n const argv = process.argv.slice(2);\n\n // Informational flags handled BEFORE the Node preflight so users on\n // any Node can confirm the binary resolves and discover the help\n // text — the only paths that touch zero runtime deps.\n if (argv.includes(\"--version\") || argv.includes(\"-v\")) {\n process.stdout.write(`${NAME} ${VERSION}\\n`);\n return 0;\n }\n if (argv.includes(\"--help\") || argv.includes(\"-h\")) {\n process.stdout.write(\n [\n `${NAME} ${VERSION}`,\n ``,\n `Usage:`,\n ` kaminari-ad-mcp [--transport=stdio|http]`,\n ``,\n `Transports:`,\n ` stdio (default) Local install — auth via KAMINARI_AD_API_KEY env var.`,\n ` http Hosted multi-tenant server — auth via incoming Authorization header.`,\n ``,\n `Configuration is documented in .env.example.`,\n ``,\n ].join(\"\\n\")\n );\n return 0;\n }\n\n // Preflight: bail with a clean upgrade message BEFORE any dynamic\n // import pulls undici / MCP SDK / pino — all three require\n // Node 22.19+ and crash at import time on older Node. Without this\n // gate users see undici's cryptic\n // `webidl.util.markAsUncloneable is not a function` instead.\n const check = checkNodeVersion(process.versions.node);\n if (check.isErr()) {\n process.stderr.write(`${check.error}\\n`);\n return 2;\n }\n\n const cliTransport = parseTransportFlag(argv);\n const env: NodeJS.ProcessEnv = cliTransport\n ? { ...process.env, KAMINARI_AD_TRANSPORT: cliTransport }\n : process.env;\n\n const configResult = loadConfig(env);\n if (configResult.isErr()) {\n process.stderr.write(`Invalid configuration: ${JSON.stringify(configResult.error.issues)}\\n`);\n return 2;\n }\n const config = configResult.value;\n\n if (config.transport === \"stdio\") {\n const { bootstrapStdio } = await import(\"./presentation/stdio/stdio-bootstrap.js\");\n return bootstrapStdio(config);\n }\n const { bootstrapHttp } = await import(\"./presentation/http/http-bootstrap.js\");\n return bootstrapHttp(config);\n}\n\nmain().then(\n (code) => {\n process.exit(code);\n },\n (error: unknown) => {\n process.stderr.write(`Fatal: ${error instanceof Error ? error.message : String(error)}\\n`);\n process.exit(1);\n }\n);\n"]}
@@ -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.24.0";
6
+ var VERSION = "0.24.2";
7
7
 
8
8
  export { NAME, VERSION };
9
- //# sourceMappingURL=chunk-JTJY73XX.js.map
10
- //# sourceMappingURL=chunk-JTJY73XX.js.map
9
+ //# sourceMappingURL=chunk-4P6CNASK.js.map
10
+ //# sourceMappingURL=chunk-4P6CNASK.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/shared/version.ts"],"names":[],"mappings":";;;;AASO,IAAM,IAAA,GAAO;AACb,IAAM,OAAA,GAAU","file":"chunk-JTJY73XX.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.24.0\";\n"]}
1
+ {"version":3,"sources":["../src/shared/version.ts"],"names":[],"mappings":";;;;AASO,IAAM,IAAA,GAAO;AACb,IAAM,OAAA,GAAU","file":"chunk-4P6CNASK.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.24.2\";\n"]}
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { err, ok } from './chunk-JTJY73XX.js';
2
+ import { err, ok } from './chunk-4P6CNASK.js';
3
3
  import { createHash, randomUUID } from 'crypto';
4
4
  import createClient from 'openapi-fetch';
5
5
  import { fetch } from 'undici';
@@ -6387,5 +6387,5 @@ function formatToolError(error) {
6387
6387
  }
6388
6388
 
6389
6389
  export { BearerToken, SERVER_INSTRUCTIONS, createHttpApiGateway, createPinoLogger, declareEmptyResourcesAndPrompts, newRequestId, wireToolsIntoMcpServer };
6390
- //# sourceMappingURL=chunk-VLIIUTPH.js.map
6391
- //# sourceMappingURL=chunk-VLIIUTPH.js.map
6390
+ //# sourceMappingURL=chunk-GPJ6BQNP.js.map
6391
+ //# sourceMappingURL=chunk-GPJ6BQNP.js.map