Skip to main content
Glama
kaminari-ad

@kaminari-ad/mcp

Official
by kaminari-ad

@kaminari-ad/mcp

Official Model Context Protocol (MCP) server for Kaminari Ad — the ad verification platform from the team behind Kaminari Click.

Lets AI agents (Cursor, Claude Desktop, Cline, and any MCP-compatible client) launch scans, inspect results, manage campaigns and policies, and read alerts directly against your Kaminari Ad workspace via your API key.

npm version npm downloads License: MIT node CI Provenance MCP Registry

Install (one click)

Cursor

Claude Desktop

Download kaminari-ad-mcp.mcpb → double-click to install. Claude Desktop shows a config form for your API key.

Claude Code (CLI)

claude mcp add kaminari-ad -- npx -y @kaminari-ad/mcp
export KAMINARI_AD_API_KEY=your-key

Full installation docs — see Quick start below.


Related MCP server: Caido MCP Server

Quick start

1. Sign up & get an API key

  1. Sign up at https://app.kaminari.ad/signup (free tier, no card required).

  2. Once signed in, go to Settings → API Keys and generate a new key, OR have an existing AI assistant (with a temporary login) call the create_api_key tool — both paths produce the same result.

  3. The key is shown once. Copy it. The full key is hashed server-side immediately.

Keys are opaque random strings — no required prefix or fixed length. Treat the whole value as a raw secret and paste it verbatim into your client config.

Tip for evaluators / Anthropic Software Directory reviewers: ask the team at hello@kaminari.ad for a sandboxed test account with seeded sample scans, campaigns, and alerts.

2a. Local install (stdio transport)

Add to your MCP client config (Cursor: ~/.cursor/mcp.json; Claude Desktop: ~/Library/Application Support/Claude/claude_desktop_config.json):

{
  "mcpServers": {
    "kaminari-ad": {
      "command": "npx",
      "args": ["-y", "@kaminari-ad/mcp"],
      "env": {
        "KAMINARI_AD_API_KEY": "<your-kaminari-ad-api-key>",
      },
    },
  },
}

Restart your client. You should see kaminari-ad in the MCP servers list with 108 tools exposed.

2b. Hosted HTTP transport (no install)

For cloud agents or clients without a local Node runtime, point at the hosted endpoint:

{
  "mcpServers": {
    "kaminari-ad": {
      "url": "https://mcp.kaminari.ad/mcp",
      "headers": {
        "Authorization": "Bearer <your-kaminari-ad-api-key>",
      },
    },
  },
}

2c. OAuth 2.0 (Claude directory, third-party agents)

The hosted server publishes RFC 9728 protected-resource metadata at https://mcp.kaminari.ad/.well-known/oauth-protected-resource and points at the Kaminari Ad Authorization Server (https://app.kaminari.ad). Any unauthenticated request to /mcp returns a WWW-Authenticate: Bearer resource_metadata="…" header so spec-compliant MCP clients (Claude.ai, Claude Code, third-party agents) can complete an OAuth 2.0 authorization-code flow with PKCE S256 + Dynamic Client Registration (RFC 7591).

# Discovery — works without any credential
curl -sk https://mcp.kaminari.ad/.well-known/oauth-protected-resource

# Triggering the WWW-Authenticate hint
curl -isk https://mcp.kaminari.ad/mcp -X POST \
  -H 'content-type: application/json' \
  -d '{"jsonrpc":"2.0","method":"tools/list","id":1}'

API keys remain the recommended path for CLIs and one-off scripting — OAuth is only for interactive agents that want per-app consent and per-app revocation. Both Bearer flavours hit the same /mcp endpoint; the server forwards the token verbatim to the API, which decides which credential type minted it.


Tools

108 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:

  • 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

  • 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

  • Campaigns (10) — list_campaigns, list_campaigns_picker, get_campaign, create_campaign, update_campaign, archive_campaign, unarchive_campaign, cancel_campaign, run_campaign, list_campaign_runs

  • Campaign groups (10) — list/get/create/update/run/cancel/archive/unarchive + pause_campaign_group_schedule, resume_campaign_group_schedule

  • Runs (3) — get_run, list_run_scans, cancel_run (use list_campaign_runs to enumerate runs of a campaign — the API has no standalone /runs index)

  • Tags (5) — list_tags, get_tag_definition, update_tag_definition, delete_tag_definition, list_scan_tags

  • Custom rules (6) — list_custom_rules, get_custom_rule, create_custom_rule, update_custom_rule, delete_custom_rule, test_custom_rule

  • 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

  • Policy sets (11) — list_policy_sets, get_policy_set, create_policy_set, update_policy_set, delete_policy_set, request_policy_set_approval, unpublish_policy_set, set_default_policy_set, list_policy_set_campaigns, attach_policy_set_campaigns, detach_policy_set_campaigns

  • Alerts (4) — list_alerts, update_alert_status, bulk_update_alert_status, get_alert_stats

  • 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

  • Billing (4) — get_billing_summary, list_usage, get_usage_summary, list_balance_history

  • Invoicing (2) — list_invoices, get_invoice_pdf

  • Alert notifications (5) — list_alert_destinations, delete_alert_destination, set_alert_destination_version, get_campaign_alert_overrides, set_campaign_alert_overrides

  • Reference data (3) — list_geos, list_emulators, get_proxy_targeting

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.

Not exposed (intentionally): the public marketing forms, which are anonymous intake for kaminari.ad itself rather than an agent capability.

Example agent prompts

These three prompts each exercise a different cross-section of tools and demonstrate the typical agent workflow:

  1. "Scan https://news.example.com/article-promo across US, UK, DE on mobile profiles, flag anything that redirects to a paywall." Touches list_emulatorscreate_bulk_scans → wait → list_scans (status=completed) → get_scanlist_scan_tags.

  2. "Create a campaign that re-checks the homepage of brand-x.com every hour from JP and US; alert me on Slack if it ever shows a malware tag." Touches list_emulatorslist_policy_sets (find one with malware) → create_campaign (schedule_enabled=true) → attach_policy_set_campaignslist_alert_destinationsset_campaign_alert_overrides (mode: "override" with the Slack destination).

  3. "What did I spend on ad verification last month, and which campaigns drove the cost?" Touches get_usage_summarylist_usage (with date_from/date_to) → group by scan_idget_scanget_campaign for attribution.

Full machine-readable tool listing is exposed by the server itself — connect with any MCP client and call tools/list.


Security & tenant isolation

The hosted HTTP endpoint serves many organizations from a single process. We take cross-tenant isolation very seriously:

  • The MCP server is a strict, stateless, per-request pass-through. It forwards your Authorization header to the Kaminari Ad API verbatim and stores no per-tenant state between requests.

  • No caches, no in-memory data indexed by anything tenant-related.

  • KAMINARI_AD_API_KEY env var is rejected on startup in HTTP mode (stdio only) — no default fallback token exists.

  • Session IDs are bound to the SHA-256 of the Bearer that initialized them; reuse with a different Bearer is rejected.

  • Bearers are never logged. Only their 8-character hash prefix is recorded for correlation.

  • See tests/isolation/ for the regression suite that enforces every rule above on each CI run.

To report a security issue, see SECURITY.md.


Development

The Docker path (no local Node required for the build, but see CONTRIBUTING for the host-side commit hooks):

make check           # lint + format-check + typecheck + arch-gates + test-cov
make test            # full test suite
make test-unit       # unit only
make test-isolation  # tenant-isolation suite

Or directly with npm if you have Node >=22.19.0 on the host (matches engines.node; .nvmrc pins the minor for dev parity with CI). The package gates strictly at 22.19.0 because undici@8.x requires markAsUncloneable from node:worker_threads (Node 22.19+).

npm ci --legacy-peer-deps
npm run lint && npm run typecheck && npm test

See CONTRIBUTING.md for the development workflow and how to add a tool.

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) 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, which publishes the package to npm with OIDC provenance and creates the GitHub Release.


Stability

The public surface of this package is:

  1. The CLI binary kaminari-ad-mcp and its --transport stdio|http flag, the env vars documented in .env.example, and the exit codes (0 / 1 fatal / 2 invalid config).

  2. The MCP wire protocol as implemented by every registered tool (tool names, input schemas, output shapes, annotations). Tools deprecated in a future major version will keep working for at least one minor version with a console warning.

Everything else — the TypeScript types exported from dist/bin.d.ts, deep imports, internal class shapes — is not part of the public contract and may change in any release. Treat this package as a CLI, not a library.

We follow Semantic Versioning for the two items above. See CHANGELOG.md for the per-release record.


Privacy

  • 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).

  • 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.

  • 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.

  • Telemetry: none. The OSS build ships a NoopErrorReporter. We do not bundle Sentry, OpenTelemetry exporters, or PostHog.

To report a security or privacy issue, see SECURITY.md.

License

MIT — see LICENSE.

Available Tools

108 tools
archive_campaignArchive CampaignA
Idempotent

Soft-delete (archive) a campaign. Removes it from default lists and stops the scheduler; previously-collected scans are preserved.

ParametersJSON Schema
NameRequiredDescriptionDefault
campaign_idYesCampaign UUID to archive.

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Description adds valuable behavioral details beyond annotations: soft-delete nature, preservation of scans, removal from lists, and scheduler stoppage. Aligns with annotations (idempotentHint=true, destructiveHint=false) without contradiction.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences that are front-loaded with the key action and effect. No redundant or unnecessary information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple tool with one parameter and no output schema, the description covers the core behavior well. Could mention reversibility via unarchive briefly, but that is implied by the sibling tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Input schema has one parameter with full description coverage (100%). The description does not add additional meaning beyond what the schema provides, so baseline score of 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description clearly states the action ('soft-delete/archive') and the resource ('campaign'), with specific effects (removes from lists, stops scheduler, preserves scans). Distinguishes from sibling tools like 'archive_campaign_group' and 'unarchive_campaign'.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Description provides clear context on what happens when archiving, implying when to use (e.g., to soft-delete). Does not explicitly state when not to use or compare with alternatives like cancel_campaign, but the context is sufficient.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

archive_campaign_groupArchive Campaign GroupA
Idempotent

Soft-delete the group AND every campaign in it. The default group cannot be archived; ask the user to move campaigns out first.

ParametersJSON Schema
NameRequiredDescriptionDefault
group_idYesCampaign group UUID.

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description discloses the cascade behavior (group and campaigns) and the restriction on default groups. Annotations already provide idempotentHint and destructiveHint, and the description's 'soft-delete' aligns with destructiveHint false. No contradiction.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, no fluff. The key information (what it does, exception) is front-loaded. Every part earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given 1 parameter and no output schema, the description adequately covers the tool's main behavior and an important exception. Siblings like archive_campaign and unarchive_campaign_group provide context. A small gap is not mentioning any side effects beyond soft-delete, but annotations fill that role.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The single parameter (group_id) already has a full schema description ('Campaign group UUID.'), so the tool description adds no extra meaning beyond the context of archiving. Baseline of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action ('soft-delete') and the resources affected ('the group AND every campaign in it'). This distinguishes it from sibling tools like archive_campaign (single campaign) and cancel_campaign_group (different action).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states when not to use (default group) and what to do instead ('ask the user to move campaigns out first'). Could be improved by mentioning archive_campaign as an alternative for individual campaigns, but the guidance is clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

attach_policy_set_campaignsAttach Policy Set CampaignsA
DestructiveIdempotent

Bind campaigns to a policy set. This and detach_policy_set_campaigns are the only way to change membership — update_policy_set edits the set's name, description and rules, never its campaigns. Membership changes here are incremental: this set's other members are left alone. IMPORTANT: a campaign can belong to only one policy set, so naming a campaign currently on a DIFFERENT set MOVES it here — it stops being evaluated against its old set's rules, and no warning is returned. Check list_campaigns (policy_set_id) first when the campaign may already be bound elsewhere. Split lists longer than 500 across calls; verify with list_policy_set_campaigns.

ParametersJSON Schema
NameRequiredDescriptionDefault
campaign_idsYesCampaign UUIDs to bind, at most 500 per call. A campaign already on THIS set is a no-op; a campaign on a DIFFERENT set is moved to this one.
policy_set_idYesPolicy set UUID.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond annotations (destructiveHint, idempotentHint), the description reveals the critical side effect: naming a campaign on a different set MOVES it here and silently stops evaluation against the old set. It also states membership changes are incremental (other members unaffected). This is exactly the kind of behavior an agent must know and is not disclosed by the schema or annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is five sentences, all relevant and front‑loaded with the primary action, then the distinctions and warnings. It could be slightly tightened (e.g., the last two sentences could merge), but every sentence earns its place given the side‑effect complexity. No fluff.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a destructive mutation tool with no output schema, the description covers the essential context: the exclusive membership mechanism, incremental behavior, the moving hazard, the 500‑item cap, and verification steps. Nothing an agent needs to call it safely is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and both parameters already have detailed descriptions, including the 500‑per‑call limit and the move behavior for `campaign_ids`. The description adds a practical instruction to split lists over 500, but it largely repeats schema info rather than adding new semantic depth. Baseline of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with 'Bind campaigns to a policy set' — a specific verb and resource — and immediately distinguishes itself from `detach_policy_set_campaigns` and `update_policy_set`. This makes the tool's role unambiguous even without reading the schema or sibling names.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly states this and `detach_policy_set_campaigns` are the only ways to change membership, notes `update_policy_set` never affects campaigns, and gives concrete pre‑call guidance (check `list_campaigns` for existing bindings, split lists over 500, verify with `list_policy_set_campaigns`). This fully orients the agent on when and how to use it.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

bulk_replay_webhookBulk Replay WebhookA

Replay every delivery attempt for this webhook endpoint that landed in [from_ts, to_ts). Returns { replayed, skipped } counts. Use to recover after a downstream outage — every event in the window is re-fired.

ParametersJSON Schema
NameRequiredDescriptionDefault
to_tsYesISO-8601 upper bound (exclusive) of the time window to replay.
from_tsYesISO-8601 lower bound (inclusive) of the time window to replay.
webhook_idYesWebhook endpoint UUID.

TDQS

A4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description adds behavioral context beyond annotations: it returns replayed/skipped counts and re-fires events. Annotations already indicate readOnlyHint=false and destructiveHint=false, which align with this mutation. However, it does not disclose idempotency, potential duplicates, or whether replaying is safe to rerun.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences that are front-loaded with the essential action and return type, followed by the use case. No extraneous information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description adequately covers the tool's purpose, use case, and return format. It does not explain what 'replayed' vs 'skipped' means or mention rate limits, but for a simple 3-parameter tool with clear schema, it is sufficiently complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so each parameter has a description. The description reinforces the time window interval notation ([from_ts, to_ts)) which adds a slight nuance about inclusivity/exclusivity, but overall the schema provides adequate meaning.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's action: replay every delivery attempt for a webhook endpoint within a time window. It specifies the resource (webhook endpoint), the scope (every delivery in [from_ts, to_ts)), and the output (replayed/skipped counts). The use case 'recover after a downstream outage' further clarifies purpose and distinguishes it from sibling tools like replay_webhook_delivery.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit context for when to use this tool: 'Use to recover after a downstream outage'. While it does not explicitly mention when not to use it or list alternative tools, the single use case is clear and actionable.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

bulk_update_alert_statusBulk Update Alert StatusA
Idempotent

Change the status of many alerts at once. Select EITHER an explicit ids list (max 1000) OR all_matching: true with the filter_* fields, which mirror list_alerts. Alerts already in a state the transition cannot leave are skipped rather than failing the call, so the response reports updated and skipped counts — compare updated + skipped against the selection size to see how many were no-ops. Prefer update_alert_status for a single alert.

ParametersJSON Schema
NameRequiredDescriptionDefault
idsNoExplicit alert UUIDs, at most 1000 per call. Mutually exclusive with `all_matching`.
statusYesStatus to move the selected alerts to.
all_matchingNoApply to every alert matching the `filter_*` fields instead of an id list. With no filters this means EVERY alert in the organization, so filter first and confirm the scope with `get_alert_stats` using the same filters.
filter_statusNoOnly with `all_matching`: restrict to alerts currently in this status.
filter_date_toNoOnly with `all_matching`: inclusive upper bound (YYYY-MM-DD) on alert creation.
filter_timezoneNoIANA timezone for the filter date bounds. REQUIRED by the API whenever either date is set.
filter_date_fromNoOnly with `all_matching`: inclusive lower bound (YYYY-MM-DD) on alert creation.
filter_tag_slugsNoOnly with `all_matching`: restrict to alerts carrying any of these tag slugs.
filter_campaign_idNoOnly with `all_matching`: restrict to one campaign.
filter_country_codesNoOnly with `all_matching`: restrict to these ISO 3166-1 alpha-2 countries.
filter_policy_set_idsNoOnly with `all_matching`: restrict to alerts raised by any of these policy sets.

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description discloses behavior beyond annotations: alerts that cannot transition are skipped rather than failing, and the response reports `updated` and `skipped` counts. Annotations already indicate idempotency and non-destructiveness, so the description adds meaningful context about the operation's effect, though it does not cover every possible failure mode.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three concise sentences with zero fluff. The core purpose is front-loaded, and the selection modes and behavior are explained efficiently. Every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For an 11-parameter bulk operation with no output schema, the description explains the two selection strategies, the response format (`updated` and `skipped` counts), and points to the single-alert alternative. It relies on the schema for the full filter list, which is acceptable given 100% schema coverage, and it advises checking scope via `get_alert_stats` indirectly through the schema's `all_matching` comment.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema fully documents each parameter. The description adds value by clarifying the mutually exclusive selection modes (ids vs all_matching), the maximum id count, and that filters mirror `list_alerts`, which helps an agent understand parameter relationships without deep schema inspection.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a clear verb+resource ('Change the status of many alerts at once') and explicitly differentiates itself from the single-alert sibling by recommending `update_alert_status` for one alert. This tells an agent exactly what the tool does and how it is distinct.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It provides explicit usage guidance: select either an `ids` list or `all_matching` with filters, and it routes to `update_alert_status` for single alerts. It also explains the skip behavior and how to interpret the response counts, which helps an agent decide when to use this tool and how to validate the result.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

cancel_campaignCancel CampaignA
Idempotent

Cancel every pending scan across all unfinished runs of a campaign. Running scans complete normally; pending scans are marked cancelled and credits refunded. Returns count of cancelled scans.

ParametersJSON Schema
NameRequiredDescriptionDefault
campaign_idYesCampaign UUID.

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description discloses that credits are refunded and returns count of cancelled scans, adding value beyond annotations which include idempotentHint=true and destructiveHint=false.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with the main action, every sentence adds value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-parameter tool with no output schema, the description adequately explains behavior and return value.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 100% schema coverage, the description adds no extra detail beyond the schema's 'Campaign UUID' for campaign_id, so baseline score of 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states it cancels pending scans across all unfinished runs of a campaign, distinguishing it from siblings like cancel_run and cancel_scan.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explains that running scans complete normally and pending scans are cancelled with credit refund, providing context for when to call it, though it doesn't explicitly contrast with alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

cancel_campaign_groupCancel Campaign GroupA
Idempotent

Cancel every pending scan across every campaign in the group. Refunds credits for cancelled scans. Returns the total cancelled count.

ParametersJSON Schema
NameRequiredDescriptionDefault
group_idYesCampaign group UUID.

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description adds behavioral details beyond annotations: it refunds credits and returns a count. The annotations already indicate idempotent and non-destructive (destructiveHint=false), and the description aligns with these traits.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single concise sentence that conveys the action, side effect, and output with no redundant information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple cancellation tool with one parameter and no output schema, the description adequately covers the action, refund behavior, and return value. It does not mention permissions or edge cases, but the context is sufficient for basic use.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The sole parameter (group_id) is fully described in the schema (format: uuid, description: 'Campaign group UUID.'). The tool description does not add extra parameter meaning, so a baseline score of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action (cancel pending scans across all campaigns in the group), side effects (refunds credits), and output (total cancelled count). It distinguishes well from sibling tools like cancel_campaign and cancel_scan.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explains what the tool does but does not provide explicit guidance on when to use it versus alternatives (e.g., cancel_campaign or cancel_scan). Usage context is only implied.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

cancel_runCancel RunA
Idempotent

Cancel every pending scan within one run. Running scans complete; pending ones get refunded. Returns the count of cancelled scans.

ParametersJSON Schema
NameRequiredDescriptionDefault
run_idYesRun UUID.

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description discloses that running scans complete and pending scans get refunded, adding behavioral context beyond the idempotentHint annotation. It also states the return value (count of cancelled scans). While annotations exist, the description provides useful nuance.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two sentences long, front-loaded with the core action, and every sentence adds value. No redundant or filler content.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the simple operation (cancel pending scans in a run) and the presence of output description (returns count), the description is complete. No output schema is needed as the return value is stated.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema already fully describes the single parameter (run_id) with 100% coverage. The description does not add further parameter-level details, so it meets the baseline for high coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states that the tool cancels pending scans within a run, differentiating it from sibling tools like cancel_scan (single scan) and cancel_campaign (campaign-level). It uses specific verbs and resources: 'Cancel every pending scan within one run.'

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage for run-level cancellation but does not explicitly state when to use this tool versus alternatives like cancel_scan or cancel_campaign. There are no exclusion criteria or direct comparisons.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

cancel_scanCancel ScanA
Idempotent

Cancel one pending scan by UUID. Already-running or completed scans are no-ops. Cancellation refunds the scan credit.

ParametersJSON Schema
NameRequiredDescriptionDefault
scan_idYesUUID of the pending scan to cancel.

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations show idempotentHint=true and destructiveHint=false. The description adds the key behavioral detail that cancellation refunds the scan credit, which is beyond what annotations provide. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is three short sentences with no wasted words. Every sentence adds value: action, boundary conditions, and side effect. Front-loaded with the core action.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple tool with one parameter, no output schema, and clear annotations, the description covers all essential aspects: what it does, when it works, and what side effects occur. No additional information is needed.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

There is only one parameter (scan_id) with 100% schema coverage and a clear description in the schema. The tool description does not add additional semantic value beyond stating it is a UUID, so a baseline score of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states 'Cancel one pending scan by UUID', specifying the action, resource, and unique identifier. It distinguishes from similar tools like cancel_campaign and cancel_run by focusing on scans and the 'pending' state condition.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly notes that already-running or completed scans are no-ops, guiding when the tool is applicable. It also mentions the refund effect, but does not explicitly compare with sibling tools like cancel_campaign.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

create_api_keyCreate API KeyA

Mint a new API key for the caller's organization. The full secret is returned in full_key THIS ONE TIME ONLY — show it to the user and instruct them to store it; the server keeps only a hash and cannot reveal it again.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYesHuman-readable label (e.g. `ci-pipeline`, `claude-mcp`).
expires_atNoOptional ISO-8601 expiry timestamp. Omit or send `null` for a non-expiring key (operator can revoke any time).

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description goes beyond annotations by disclosing that the full key is returned once, the server stores only a hash, and the user must store the key. This is critical behavioral detail not inferable from annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences with no filler. Front-loaded with the action and immediately followed by the most important behavioral note. Highly efficient.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite lacking an output schema, the description explains the return behavior (full_key one-time). All parameters are fully documented in the schema. No additional context is needed for this simple tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and both parameter descriptions are already in the schema. The description adds no additional semantic value beyond the schema, so baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a clear verb ('Mint') and resource ('API key'), and uniquely highlights the one-time return of the secret. This distinguishes it from sibling tools like revoke_api_key or list_api_keys.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description clarifies the scope ('caller's organization') and the critical one-time display. However, it does not explicitly state when not to use or suggest alternatives, though the context is inherently clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

create_bulk_scansCreate Bulk ScansA

Queue one new scan per country in a single call (e.g. test the same URL, ad-tag, or VAST video tag from US + DE + JP). COSTS N CREDITS where N = number of countries times repeat_count. Returns one entry per country; each entry's repeat_scan_ids lists that country's extra repeats.

ParametersJSON Schema
NameRequiredDescriptionDefault
urlNoDirect URL. Provide exactly one of `url`, `ad_tag`, or `vast_tag`.
proxyNoOptional 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.
ad_tagNoRaw ad-tag HTML/JS OR an http(s) URL of a page with the creative already rendered. Provide exactly one of `url`, `ad_tag`, or `vast_tag`.
labelsNoArbitrary metadata copied onto every created scan.
referrerNoOptional 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 — 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.
vast_tagNoVAST video ad tag: an http(s) URL of a VAST endpoint OR raw VAST XML. Provide exactly one of `url`, `ad_tag`, or `vast_tag`.
emulator_idYesDevice/OS profile slug; same for every country in the batch.
repeat_modeNoHow the repeats of one combination relate to each other. 'isolated' gives every repeat a fresh browser and a new IP, so the repeats are statistically independent. 'shared' runs all repeats of one combination in a single browser behind one IP, carrying cookies and localStorage from one repeat to the next — use it to reproduce a cloaker or a frequency cap that only misbehaves on the second or third visit. 'shared' is rejected with 422 on an ad-discovery target: when creating, that is `ad_discovery: true` on a scan or `campaign_type: "ad_discovery"` on a campaign; when updating a campaign, it is a campaign whose existing type is already ad_discovery, since campaign_type itself cannot be changed. Default: isolated.
repeat_countNoHow 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 — see that tool's description for the exact formula — 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.
country_codesYesList of ISO 3166-1 alpha-2 country codes; one scan per country is created.
retry_max_attemptsNoExtra crawl attempts when a scan fails for a technical reason — dead proxy, navigation timeout, browser crash (0-5). Permanent failures are never retried. The same scan is reused and only a completed scan is billed, so a retry never double-charges. 0-5 is the API's default ceiling; an operator can lower it, and then a value accepted here still comes back as a 422 from the API. Default: 0.
ignore_first_n_domainsNoHow many leading domains of the redirect chain to exclude from detection and tagging (0-5). Use it when the check enters through the caller's OWN click or tracking domains: without it a reputation hit on one of those tags the material and raises an alert about the caller's infrastructure rather than about the offer. Counting starts at the entry point and follows chain order; domains fold to their registrable form, so www.example.com and example.com consume one slot between them, and any other request to one of those domains is excluded too. A skipped domain is checked by NOTHING, so never set this higher than the number of domains the caller actually owns at the head of the chain — ask rather than guess. The full redirect chain is still captured and returned either way. Omit it to skip nothing (0). A scan created directly does NOT inherit this from the campaign named in `campaign_id` — only scans queued by a campaign run do — so send it explicitly on every direct submission that needs it.

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations are minimal (no readOnly, no destructive, no idempotent), so the description carries the behavioral disclosure burden. It discloses the cost formula (N credits), the fact that it creates scans, and the return shape (one entry per country with repeat_scan_ids). It does not state idempotency or auth requirements, but those are not essential given the operation is clearly a creation. It adds meaningful context beyond the sparse annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise and front-loaded: the first sentence states purpose and example, the second gives the cost formula, the third explains the return structure. No filler. It is slightly longer than necessary but every sentence adds information relevant to using the tool correctly.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with 12 parameters and no output schema, the description covers the core behavior, cost, and return shape. It does not enumerate all parameters (the schema does), but it explains the key cross-parameter interactions (cost, repeat multiplier) and gives a clear example. It lacks detail on error handling or edge cases, but those are partially in the schema descriptions. Overall, adequate for a complex tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so baseline is 3. The description adds value by explaining the cost formula tying country_codes and repeat_count together, and clarifying that repeat_count is a multiplier on the tool's own fan-out. It also clarifies the output's repeat_scan_ids semantics. This goes beyond what the schema states, justifying a 4.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('Queue'), resource ('one new scan per country'), and a concrete use case (testing the same URL across multiple countries). It clearly distinguishes from sibling tools like create_scan, which is for a single scan, by emphasizing the per-country fan-out.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It provides clear context for when to use this tool: when you need to run the same check across multiple countries in one call. It does not explicitly name create_scan as the single-country alternative, but the sibling list includes it and the purpose is evident. A more explicit 'use create_scan for a single country' would raise this to 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

create_campaignCreate CampaignA

Create a recurring scan campaign (template). The schedule produces N scans per run where N = number of countries times number of device profiles times repeat_count. Scans cost credits when they run, not when the campaign is created, so a high repeat_count multiplies the bill on every run. The returned campaign echoes repeat_count, repeat_mode, and retry_max_attempts, so read it back to confirm what the campaign will do.

ParametersJSON Schema
NameRequiredDescriptionDefault
urlNoTarget URL (required if campaign_type=url or ad_discovery).
nameYesDisplay name (1-200 chars).
ad_tagNoAd-tag HTML/JS or an http(s) URL of a page with the rendered creative (required if campaign_type=ad_tag).
labelsNoArbitrary metadata applied to every queued scan.
group_idNoParent group UUID; defaults to the org's default group.
referrerNoOptional http(s) page URL every scan of this campaign is checked from. For `ad_tag` and `vast` campaigns this is the publisher page the tag is embedded in — 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). For `url` and `ad_discovery` campaigns this is where the visitor came from, sent in full as the Referer of the page request.
vast_tagNoVAST video ad tag: an http(s) URL of a VAST endpoint OR raw VAST XML (required if campaign_type=vast).
proxy_ispNoProxy ISP, or mobile carrier when `proxy_type` is mobile. Use a value from `get_proxy_targeting`.
proxy_cityNoProxy city from `get_proxy_targeting`. If you also set `proxy_region`, take the city from a call made with that same region — a city from a different region passes validation but leaves the provider no exit node.
proxy_typeNoProxy 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.
repeat_modeNoHow the repeats of one combination relate to each other. 'isolated' gives every repeat a fresh browser and a new IP, so the repeats are statistically independent. 'shared' runs all repeats of one combination in a single browser behind one IP, carrying cookies and localStorage from one repeat to the next — use it to reproduce a cloaker or a frequency cap that only misbehaves on the second or third visit. 'shared' is rejected with 422 on an ad-discovery target: when creating, that is `ad_discovery: true` on a scan or `campaign_type: "ad_discovery"` on a campaign; when updating a campaign, it is a campaign whose existing type is already ad_discovery, since campaign_type itself cannot be changed. Default: isolated.
proxy_regionNoProxy 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.
repeat_countNoHow 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 — see that tool's description for the exact formula — 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.
campaign_typeYes`url`, `ad_tag`, `vast`, or `ad_discovery` — must match the target field below. `ad_discovery` is a publisher-page scan: set `url`; each run detects the page's ad blocks and opens a child scan per detected ad.
country_codesYesISO 3166-1 alpha-2 codes — one scan per country per run.
emulator_modeNoHow 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.
policy_set_idNoPolicy set to evaluate every scan against. Omit to bind the organization's default (if any). Pass null for no policy set and no policy alerts.
schedule_typeNoScheduling 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.
schedule_weeklyNoWeekly run grid for schedule_type='weekly'. Keys are weekdays '0'-'6' (Mon-Sun); values are hours 0-23 in schedule_timezone, e.g. { '0': [9, 17], '4': [12] }.
schedule_enabledNoIf true, the scheduler runs immediately. Default: false (manual run).
schedule_timezoneNoIANA timezone for the weekly grid, e.g. 'Europe/Berlin'. Default: UTC.
max_discovered_adsNoHow 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 — one parent plus its children. Only valid on an ad-discovery target — `ad_discovery: true` on a scan, or `campaign_type: "ad_discovery"` on a campaign — and rejected with 422 anywhere else. Omit it to use the platform default. The platform default is 12 unless an operator retuned it.
retry_max_attemptsNoExtra crawl attempts when a scan fails for a technical reason — dead proxy, navigation timeout, browser crash (0-5). Permanent failures are never retried. The same scan is reused and only a completed scan is billed, so a retry never double-charges. 0-5 is the API's default ceiling; an operator can lower it, and then a value accepted here still comes back as a 422 from the API. Default: 0.
emulator_categoriesNoDevice categories to rotate through, e.g. ['android_phone']. Valid: android_phone, android_tablet, iphone, ipad, windows_desktop, macos_desktop. On create, omitting this defaults to ['android_phone']; pass [] together with emulator_specific_ids to target ONLY specific devices.
emulator_specific_idsNoPin exact device profile slugs from `list_emulators` (the `id` field), e.g. ['samsung_galaxy_s23_ultra_android16']. Always scanned regardless of emulator_mode.
ignore_first_n_domainsNoHow many leading domains of the redirect chain to exclude from detection and tagging (0-5). Use it when the check enters through the caller's OWN click or tracking domains: without it a reputation hit on one of those tags the material and raises an alert about the caller's infrastructure rather than about the offer. Counting starts at the entry point and follows chain order; domains fold to their registrable form, so www.example.com and example.com consume one slot between them, and any other request to one of those domains is excluded too. A skipped domain is checked by NOTHING, so never set this higher than the number of domains the caller actually owns at the head of the chain — ask rather than guess. The full redirect chain is still captured and returned either way. Omit it to skip nothing (0).
schedule_interval_secondsNoRun interval for schedule_type='interval'. Allowed presets (seconds): 60, 120, 300, 600, 900, 1800, 2700, 3600, 7200, 14400, 28800, 86400.

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already indicate readOnlyHint=false, destructiveHint=false, and idempotentHint=false. The description adds valuable behavioral context: credits are charged at run time, repeat_count multiplies the bill, and the returned campaign echoes specific fields for verification. It also warns about 422 rejections for shared mode on ad-discovery targets. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise and front-loaded, stating the core purpose first. Every sentence adds value: the cost warning, the formula, and the read-back instruction. There is no filler or repetition of schema content. It is efficient for the number of parameters involved.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With 27 parameters and full schema coverage, the description is not exhaustive but covers the non-obvious interactions (billing, fan-out, constraints). It also tells the agent what to read back from the response, which is useful given there is no output schema. It could mention error handling or cancellation, but those are covered by sibling tools. It is complete enough for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema documents each parameter. The description adds meaning beyond the schema: the fan-out formula (countries × device profiles × repeat_count), the credit billing implication, and the cross-reference to get_proxy_targeting for proxy parameters. It also clarifies referrer semantics and the repeat_mode rejection case, which are not in the schema. This is a strong addition on top of a complete schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: 'Create a recurring scan campaign (template).' It clearly distinguishes from siblings like create_scan (one-off vs recurring) and update_campaign (create vs update). The phrase 'recurring scan campaign' and the mention of schedule types make the purpose unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage by contrasting with one-off scans and noting that scans cost credits only when they run. It references get_proxy_targeting and list_emulators for valid parameter values, which is a clear guideline. It doesn't explicitly state when not to use it or name alternatives, but the distinction from create_scan is implicit and sufficient for an agent to select correctly.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

create_campaign_groupCreate Campaign GroupA

Create a new campaign group (folder). Free operation, no scans queued.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYesDisplay name (1-200 chars).

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations provide readOnlyHint=false, destructiveHint=false. The description adds 'Free operation, no scans queued', which provides useful behavioral context beyond annotations. No contradiction.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Extremely concise - two clear phrases. Front-loaded with purpose. Every word is meaningful with no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple 1-parameter tool with no output schema, the description is sufficient. It covers purpose and key behavioral traits. Could mention that a campaign group is a folder, but that is implied by the title.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Only one parameter 'name' with a description in the schema covering 100%. The tool description adds no extra parameter-specific information, so the schema already handles it.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states 'Create a new campaign group (folder)' which specifies the action and resource. It distinguishes from sibling tools like get_campaign_group, archive_campaign_group, update_campaign_group, etc.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No explicit guidance on when to use this tool vs alternatives. The description implies usage by stating 'Free operation, no scans queued' but lacks when-not or alternative tool references.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

create_custom_roleCreate Custom RoleA

Create a custom organization role with the supplied permission set. Returns the persisted role; assign it to users via update_user_role.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYesDisplay name for the role.
permissionsYesPermission slugs the role grants (e.g. 'scans.read', 'campaigns.write'). Use `list_org_roles` to see permissions on existing system roles.

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already indicate this is a mutation (readOnlyHint=false) and non-destructive (destructiveHint=false). The description adds value by stating the action 'Create' and the return of the persisted role, and suggests assignment behavior. No contradictions. Additional context like permissions or side effects would be helpful but not mandatory given annotation coverage.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is extremely concise, using two sentences with no redundant information. It is front-loaded with the main action and includes a clear follow-up instruction. Every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple create tool with two parameters and no output schema, the description is largely complete. It covers the return value, next steps, and references a related tool. Minor gaps (e.g., activation timing, limits) exist but are not critical given the tool's simplicity and annotation coverage.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% for both parameters, so the description does not need to add much. The description mentions the 'supplied permission set' and references 'list_org_roles' for examples, which is helpful but not essential. Baseline 3 is appropriate as the description adds marginal value over the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action ('Create'), the resource ('custom organization role'), and the key input ('supplied permission set'). It also mentions the return value and next step, distinguishing it from siblings like 'update_user_role' and 'list_org_roles'.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides context for usage by noting that the created role should be assigned via 'update_user_role'. It implicitly tells the agent when to use this tool (when a new custom role is needed) but does not explicitly state when not to use it or list alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

create_custom_ruleCreate Custom RuleA

Define a custom tag-detection rule. Use rule_type='regexp_request_url' to match captured network and subresource URLs; fresh scans carry up to 5,000 URLs, while later tests/rechecks use a reduced persisted request tree and are best-effort. Use rule_type='regexp_request_body' to match the CONTENTS of those sub-resources instead — the right choice when the code you want to catch keeps changing its filename; those contents are kept for one day. rule_type='regexp_url' remains redirect-chain-only. The API auto-registers a tag definition for each emitted slug and rejects built-in system-slug collisions with HTTP 422 / checking.system_slug_reserved. Matches tag future scans; existing scans are untouched until recheck_scans.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYesDisplay name. For non-LLM rules this also becomes the `display_name` of the auto-registered tag definition (see `tag_slug`).
configYesRule-type-specific configuration object. Shape depends on `rule_type`. For `rule_type='regexp_request_url'` and `rule_type='regexp_request_body'`, `config` must be exactly `{ pattern: string, flags?: '' | 'i' }`: pattern is non-empty and at most 4,096 characters; omit flags or use `''` for case-sensitive matching, or `'i'` for case-insensitive matching. `target` may be `'page'` (the landing tab), `'creative'` (the ad-tag creative's own traffic) or `'creative_and_page'` (both, reported separately) — a script inside a banner's iframe is on no landing's request list, so a page-only rule cannot see it. Default `page`. `regexp_request_url` inspects up to 5,000 captured request URLs on a fresh scan; tests and rechecks of stored scans reconstruct main-frame hops plus up to 200 persisted subrequests with selected resource types omitted, so historical matching is best-effort. `regexp_request_body` inspects the CONTENTS of the page's scripts, fetch/XHR responses and iframe documents — never images, video, fonts or stylesheets — capped at 400 resources, 128 KB each and 8 MB per scan. Those contents are kept for ONE DAY, so a test or recheck against an older scan reports no match because there is nothing left to read. `regexp_url` remains redirect-chain-only. For `rule_type='llm'` the shape is `{ prompt: string, tags: { <tag_slug>: <description>, ... } }`; each key in `config.tags` is auto-registered as a custom tag definition AND must not collide with a system slug (same 422 contract as `tag_slug`). For `rule_type='combo'` the optional rule-level key `match_scope` decides where conditions are counted. `"scan"` (the default, and the behaviour when the key is absent) checks them against the union of all tags on the scan. With `"url"`, every condition must be satisfied by tags on the same link, and the tag is assigned to that link — so a rule built only from link-less tags (AI verdicts, crawler behaviour) has no link to attach to and will never match; keep those on the whole scan. Mixing the two kinds does not help either: AI verdicts and per-link detections reach the engine in different scan parts and are not evaluated together today, so such a combo fires under neither scope. Give a `"url"` rule at least one positive condition (`all_of` / `any_of` / `tag_category` + `count_gte`) — a config carrying only `none_of` matches every link that merely lacks those tags, and the API does not reject that on this path. Thresholds stay "N or more" (`count_gte` / `any_of_min`) in both scopes; no other `match_scope` value is accepted.
targetNoWhere to apply the rule (e.g. 'page' for landing HTML). `regexp_request_url` and `regexp_request_body` also accept `'creative'` (the ad-tag creative's own traffic) and `'creative_and_page'` (both, reported separately). Default: page. See API docs for the full set of valid values.
tag_slugNoTag slug to assign on match. Empty = create-only (advanced). The API auto-registers a custom tag definition for this slug with `display_name = name`. **MUST NOT collide with a built-in system tag slug** (see `list_tags` where `scope=system`); colliding requests return 422 with code `checking.system_slug_reserved`. For `rule_type='llm'` use `config.tags` keys instead and leave `tag_slug` empty.
rule_typeYesRule engine. One of: `stopword_content`, `stopword_url`, `regexp_content`, `regexp_url`, `regexp_request_url`, `regexp_request_body`, `blacklist_domain`, `combo`, `llm`. `regexp_url` checks redirect-chain URLs only; `regexp_request_url` checks captured network and subresource URLs; `regexp_request_body` checks what those sub-resources contained. The API validates.

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description richly discloses behaviors beyond the annotations: the API auto-registers tag definitions for emitted slugs, built-in system-slug collisions return HTTP 422 with checking.system_slug_reserved, matches only future scans, and existing scans stay untouched until recheck_scans. It also explains best-effort historical matching, one-day request body retention, and resource/URL limits.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but dense and purpose-driven; nearly every sentence conveys actionable constraints or trade-offs. Some information is repeated between the main description and the schema property descriptions, but the structure is clear enough and the detail-earning content justifies the length.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex create tool with no output schema and many rule types, the description covers most of the high-risk behavior: future vs existing scans, retention, request body limits, target semantics, and collision errors. It falls just short of complete because a few rule types like stopword_content, stopword_url, regexp_content, and blacklist_domain are only named and not behaviorally explained, and the response shape is not described.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is a 3, but the description adds meaningful semantic context on top of the schema: it explains what config shapes do, the side effects of tag_slug and config.tags auto-registration, target semantics, and match_scope behavior for combo rules. This helps an agent reason about valid parameter combinations more reliably than the schema alone.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence is specific: 'Define a custom tag-detection rule' names the verb, the resource, and the operation, and the rest of the description clarifies what kind of rules exist and which rule types match what. It also implicitly distinguishes itself from siblings like update_custom_rule, delete_custom_rule, and test_custom_rule by focusing on the initial creation semantics.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit when-to-use guidance for the main rule types: use regexp_request_url for captured URLs, use regexp_request_body when filenames keep changing, and regexp_url is described as redirect-chain-only. It also gives direct advice on pitfalls, such as page-only rules missing iframe traffic and llm rules using config.tags keys instead of tag_slug.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

create_custom_taxonomyCreate Custom TaxonomyA

Create a custom classification taxonomy with its initial tree. Exactly one node should have is_default=true (fallback for scans the LLM cannot classify confidently). Returns the persisted taxonomy with allocated node UUIDs and version=1.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYesDisplay name (1-100 chars).
nodesNoInitial tree as a flat array (parents before children, linked via client_id / parent_client_id). Empty / omitted = empty taxonomy.
descriptionNoFree-form description (defaults to empty string).

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations (readOnlyHint=false, destructiveHint=false) already indicate it's a non-destructive mutation. The description adds important context: the taxonomy is persisted, returned with allocated UUIDs and version=1, and the default node constraint. No contradictions with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is three sentences long, each with a distinct purpose: purpose statement, constraint/guideline, and return value. No unnecessary words, well-structured, and front-loaded with the main action.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the absence of an output schema, the description compensates by stating the return includes the taxonomy with UUIDs and version=1. It covers the creation logic, default node requirement, and tree structure. It could mention error conditions or rate limits, but for a creation tool with three parameters, it is sufficiently complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has 100% coverage with descriptions for all properties. The description, however, adds value by explaining the tree structure and client_id/parent_client_id linking mechanism, which is not fully detailed in the schema. It also reiterates the is_default constraint in context.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states 'Create a custom classification taxonomy with its initial tree,' specifying the verb (create), resource (taxonomy), and the concept of an initial tree. This distinguishes it from siblings like update_custom_taxonomy or delete_custom_taxonomy. The mention of a default node further clarifies the unique behavior.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear context on when to use the tool (to create a taxonomy) and includes a critical constraint ('Exactly one node should have is_default=true'). It explains the purpose of the default node (fallback for classification). However, it does not explicitly state when not to use it or mention alternatives like parse_custom_taxonomy_text, but the sibling list implies differentiation.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

create_policy_setCreate Policy SetA

Create a new policy set (named collection of violation rules). Each rule is one of: tag slug, IAB V3 category prefix, advertiser brand, freeform AI category, or per-org custom-taxonomy node. Bind campaigns to the set via update_campaign.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYesDisplay name.
entriesYesAt least one entry. Each entry is a discriminated union over five rule kinds: tag / iab_v3 / brand / ai_category / custom_taxonomy.
descriptionYesFree-form description (use empty string for none).

TDQS

A4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations declare readOnlyHint false, destructiveHint false, and idempotentHint false. The description does not contradict annotations but adds minimal behavioral context beyond listing rule types. It does not disclose any side effects, auth requirements, or return behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences efficiently cover the core purpose and a key nuance (binding campaigns). No unnecessary words. Every sentence adds value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a creation tool with no output schema, the description adequately covers the input parameters and a post-creation step. It lacks return type details (likely the created policy set), which is common but could be improved. Overall, it is sufficiently complete given the tool's complexity.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, with detailed parameter descriptions. The description adds a concise summary of rule kinds, complementing the schema without redundancy. It provides a helpful overview but does not introduce entirely new information.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool creates a new policy set (a named collection of violation rules), listing the five rule kinds. It distinguishes from sibling tools like update_policy_set and delete_policy_set by its unique action.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description mentions binding campaigns via update_campaign after creation, which provides context. However, it does not explicitly state when to use or avoid this tool, nor compare it to alternatives like update_policy_set. The guidance is implied but not comprehensive.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

create_scanCreate ScanA

Queue a single new scan for a URL, ad-tag, or VAST video tag against one country. Takes one target and one country — there is no multi-URL form; call it once per URL. COSTS CREDITS and bills the caller's organization: this call creates exactly repeat_count scans (default 1) and bills every one of them. Returns the newly-created scan record; when repeat_count > 1 the response's repeat_scan_ids lists the sibling scans this call also created.

ParametersJSON Schema
NameRequiredDescriptionDefault
urlNoDirect URL of the ad / landing page. Provide exactly one of `url`, `ad_tag`, or `vast_tag`.
proxyNoOptional 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.
ad_tagNoRaw HTML/JS ad tag (script, iframe, image) OR an http(s) URL of a page with the creative already rendered. Provide exactly one of `url`, `ad_tag`, or `vast_tag`.
labelsNoArbitrary string -> string metadata attached to the scan.
run_idNoOptional run UUID inside the campaign.
referrerNoOptional 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 — 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.
vast_tagNoVAST video ad tag: an http(s) URL of a VAST endpoint OR raw VAST XML (a document containing a <VAST> element). Fetched and played in a real browser. Provide exactly one of `url`, `ad_tag`, or `vast_tag`.
campaign_idNoOptional campaign UUID to attribute the scan to.
emulator_idYesDevice/OS profile slug; use `list_emulators` to discover valid values.
repeat_modeNoHow the repeats of one combination relate to each other. 'isolated' gives every repeat a fresh browser and a new IP, so the repeats are statistically independent. 'shared' runs all repeats of one combination in a single browser behind one IP, carrying cookies and localStorage from one repeat to the next — use it to reproduce a cloaker or a frequency cap that only misbehaves on the second or third visit. 'shared' is rejected with 422 on an ad-discovery target: when creating, that is `ad_discovery: true` on a scan or `campaign_type: "ad_discovery"` on a campaign; when updating a campaign, it is a campaign whose existing type is already ad_discovery, since campaign_type itself cannot be changed. Default: isolated.
ad_discoveryNoPublisher 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`.
country_codeYesISO 3166-1 alpha-2 country code, e.g. US, DE, JP. Determines proxy geo.
repeat_countNoHow 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 — see that tool's description for the exact formula — 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.
max_discovered_adsNoHow 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 — one parent plus its children. Only valid on an ad-discovery target — `ad_discovery: true` on a scan, or `campaign_type: "ad_discovery"` on a campaign — and rejected with 422 anywhere else. Omit it to use the platform default. The platform default is 12 unless an operator retuned it.
retry_max_attemptsNoExtra crawl attempts when a scan fails for a technical reason — dead proxy, navigation timeout, browser crash (0-5). Permanent failures are never retried. The same scan is reused and only a completed scan is billed, so a retry never double-charges. 0-5 is the API's default ceiling; an operator can lower it, and then a value accepted here still comes back as a 422 from the API. Default: 0.
ignore_first_n_domainsNoHow many leading domains of the redirect chain to exclude from detection and tagging (0-5). Use it when the check enters through the caller's OWN click or tracking domains: without it a reputation hit on one of those tags the material and raises an alert about the caller's infrastructure rather than about the offer. Counting starts at the entry point and follows chain order; domains fold to their registrable form, so www.example.com and example.com consume one slot between them, and any other request to one of those domains is excluded too. A skipped domain is checked by NOTHING, so never set this higher than the number of domains the caller actually owns at the head of the chain — ask rather than guess. The full redirect chain is still captured and returned either way. Omit it to skip nothing (0). A scan created directly does NOT inherit this from the campaign named in `campaign_id` — only scans queued by a campaign run do — so send it explicitly on every direct submission that needs it.

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the annotations by disclosing the critical side effect: this call costs credits and bills the caller's organization for every scan created. It also explains the repeat_count fan-out and the repeat_scan_ids response field, making the operation's real-world impact transparent.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tight, front-loaded sentences: scope first, then cost/billing behavior, then return value shape. Every sentence earns its place and there is no repetition of schema details.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex 16-parameter tool with no output schema, the description covers the essential usage constraint, cost/fan-out behavior, and return-value shape. The fully described schema supplies the remaining per-parameter and cross-tool context, so an agent has enough to select and invoke the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has 100% parameter description coverage, with detailed explanations for every property including cross-tool references. The description's summary of 'one target and one country' adds no per-parameter meaning beyond what the schema already provides, so the baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific action — 'Queue a single new scan' — for a concrete resource (a URL, ad-tag, or VAST tag) and explicitly narrows it to one target and one country. It also rules out a multi-URL form, which distinguishes it from bulk scan creation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says this tool takes one target and one country, with no multi-URL form, and directs callers to invoke it once per URL. It does not name the bulk alternative (create_bulk_scans), but the usage condition is clear enough.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

create_webhookCreate WebhookA

Register a webhook endpoint for the chosen event types. Response is a { webhook, secret } envelope — the HMAC-SHA256 SIGNING SECRET is returned once and the caller MUST store it to verify event signatures.

ParametersJSON Schema
NameRequiredDescriptionDefault
urlYesHTTPS endpoint URL.
descriptionNoFree-form label shown in the dashboard.
event_typesNoEvent-type slugs to subscribe to (see `list_webhook_event_types`). Empty array = subscribe to ALL events.
campaign_idsNoRestrict to events from these campaigns. Empty array = events from every campaign.

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description discloses that the HMAC-SHA256 signing secret is returned only once and must be stored by the caller. This is a crucial behavioral trait beyond what annotations provide (readOnlyHint=false, destructiveHint=false). It does not discuss rate limits or other behaviors, but the information given is highly relevant.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two sentences long, front-loaded with the core action, and every word adds value. The first sentence specifies the action and scope, the second explains the critical response detail. No fluff or redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Although there is no output schema, the description explains the response format (webhook and secret envelope) and the caller's obligation to store the secret. This covers the main output. It does not mention error handling or edge cases, but for a creation tool with four parameters, it is reasonably complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the description does not need to add parameter details. The description mentions 'chosen event types' and the response envelope, which aligns with the schema. However, it does not add new meaning beyond the schema's existing descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool registers a webhook endpoint for chosen event types, which matches the name 'Create Webhook'. It distinguishes from sibling tools like update_webhook and delete_webhook by focusing on creation and the unique response envelope.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies when to use (to set up a webhook) but provides no explicit guidance on when not to use or alternatives like update_webhook or rotate_webhook_secret. The context signals show many webhook-related siblings, so more guidance would help.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

delete_alert_destinationDelete Alert DestinationA
DestructiveIdempotent

Remove an alert-notification destination. The org stops receiving pings on this channel immediately; campaign-level overrides referencing it are pruned.

ParametersJSON Schema
NameRequiredDescriptionDefault
destination_idYesDestination UUID.

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description goes beyond annotations by specifying that removal is immediate and that campaign-level overrides referencing the destination are pruned. This adds concrete behavioral detail to the destructiveHint and idempotentHint annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two sentences long, with the first sentence stating the core action and the second detailing effects. It is front-loaded and contains no unnecessary words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple delete tool with no output schema, the description fully explains the outcome (stops pings, prunes overrides) and side effects. No additional information is needed.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% with a single parameter description ('Destination UUID.'). The tool description does not add further parameter information, but given the simplicity and full schema coverage, a baseline score of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action ('Remove an alert-notification destination') and immediately specifies the consequences ('stops receiving pings', 'overrides pruned'). This distinguishes it from siblings that list or update alert destinations.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description indicates when to use the tool (to remove an alert destination) and explains immediate effects and side effects (pruning overrides). However, it does not explicitly mention when not to use it or compare to alternatives, but the sibling list contains no other delete-alert-destination tool.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

delete_custom_ruleDelete Custom RuleA
DestructiveIdempotent

Permanently delete a custom rule. Already-applied tags on past scans are preserved; the rule simply stops running on future scans.

ParametersJSON Schema
NameRequiredDescriptionDefault
rule_idYesRule UUID to delete.

TDQS

A4.3/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description adds important behavioral context beyond annotations: it notes that deletion is permanent, but already-applied tags on past scans are preserved and only future scans are affected. This aligns with the destructiveHint annotation and provides helpful detail.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences, 18 words total. The first sentence states the action, the second adds behavioral transparency. No wasted words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool has only one required parameter and no output schema, the description covers the action, permanence, and effect on tags/scans. It is complete for the tool's complexity.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema already has 100% coverage with a description for the only parameter, rule_id. The tool description does not add any further meaning or context about the parameter beyond what the schema provides. Baseline score of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action 'Permanently delete a custom rule', with a specific verb and resource. It distinguishes itself from sibling tools like create_custom_rule or update_custom_rule.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description does not explicitly state when to use this tool versus alternatives or when not to use it. Usage is implied by the action, but no guidance on context or exclusion is provided.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

delete_custom_taxonomyDelete Custom TaxonomyA
DestructiveIdempotent

Soft-delete a custom taxonomy (sets is_active=false). Historical scan classifications keep referencing the id; new scans skip this taxonomy. Use restore_custom_taxonomy to undo.

ParametersJSON Schema
NameRequiredDescriptionDefault
taxonomy_idYesCustom taxonomy UUID.

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description reveals soft-delete behavior and consequences: 'Historical scan classifications keep referencing the id; new scans skip this taxonomy.' This adds significant context beyond the annotations (destructiveHint, idempotentHint) by clarifying the non-permanent effect and impact on scans.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise: two sentences conveying the action, effect, and reversion. No unnecessary words, well-structured.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple tool with one parameter and no output schema, the description fully explains the behavior, consequences, and undo option. It is complete and self-sufficient.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The sole parameter 'taxonomy_id' is described in the schema as 'Custom taxonomy UUID.' The description does not add further details about the parameter. With 100% schema coverage, baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action: 'Soft-delete a custom taxonomy (sets is_active=false).' It is specific about what happens and distinguishes from siblings like 'delete_custom_rule' and 'restore_custom_taxonomy'.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly mentions the undo operation: 'Use `restore_custom_taxonomy` to undo.' It implies when to use this tool (to soft-delete) but does not explicitly state when not to use it or alternative scenarios. Overall, it provides adequate guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

delete_policy_setDelete Policy SetA
DestructiveIdempotent

Permanently delete a policy set. IMPORTANT: API returns HTTP 400 if any active campaign is still bound to this set. To unbind first, call list_campaigns with a policy_set_id filter (when available) or scan your campaigns for matches, then update_campaign for each match setting policy_set_id=null, then retry delete. Alerts created under this set persist (their policy_set_id becomes null).

ParametersJSON Schema
NameRequiredDescriptionDefault
policy_set_idYesPolicy set UUID.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Adds important context beyond annotations: permanence, error condition, side effect on alerts (their policy_set_id becomes null). No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Each sentence adds value; front-loaded with purpose. Slightly wordy but well-structured.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Covers purpose, preconditions, error handling, workaround, and side effects – comprehensive for a delete tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description covers the parameter ('Policy set UUID.'). The tool description adds no further semantic detail.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Starts with 'Permanently delete a policy set' – a specific verb+resource. Clarifies it's permanent and distinct from siblings like archive or cancel.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly warns about HTTP 400 when campaigns are bound, provides a step-by-step unbinding workaround using list_campaigns and update_campaign.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

delete_tag_definitionDelete Tag DefinitionA
DestructiveIdempotent

Delete a CUSTOM tag definition. Historical tag assignments are preserved; future scans will not receive this tag. System tags cannot be deleted.

ParametersJSON Schema
NameRequiredDescriptionDefault
slugYesCustom tag slug to delete.

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond annotations (destructiveHint=true, idempotentHint=true), the description reveals that historical tag assignments are preserved and future scans will not receive the tag, adding valuable behavioral context.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two concise sentences: the first states the action and restriction, the second explains consequences. No superfluous words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-parameter delete tool without output schema, the description fully covers purpose, constraints, and effects, leaving no gaps for agent decision-making.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The single parameter 'slug' has 100% schema coverage with a clear description. The tool description adds little beyond emphasizing 'CUSTOM,' so the schema already carries the semantic load.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action 'Delete a CUSTOM tag definition' and explicitly distinguishes custom from system tags, which differentiates it from sibling tools like delete_custom_rule or archive_campaign.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly says 'System tags cannot be deleted,' providing a clear when-not-to-use condition. However, it does not mention any alternative tools for handling system tags.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

delete_webhookDelete WebhookA
DestructiveIdempotent

Unregister a webhook endpoint. No further events are delivered; in-flight retries are dropped. Past delivery history is preserved.

ParametersJSON Schema
NameRequiredDescriptionDefault
webhook_idYesWebhook endpoint UUID to remove.

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations indicate destructive and non-readonly behavior. The description adds value by specifying that no further events are delivered, in-flight retries are dropped, and past delivery history is preserved. This goes beyond the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is exceptionally concise with two sentences that each add unique value without any redundancy or filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple deletion tool with one parameter and no output schema, the description covers the essential effects (event delivery, retries, history preservation). It is complete enough for an agent to understand the tool's impact.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% with a clear parameter description. The tool description does not add additional meaning beyond what the schema already provides, so a baseline score of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action 'Unregister a webhook endpoint' with a specific verb and resource. It also provides behavioral details about event delivery and history preservation, distinguishing it from other webhook tools like create or update.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description lacks explicit guidance on when to use this tool versus alternatives such as updating a webhook to disable it. No when-to-use or when-not-to-use context is provided.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

detach_policy_set_campaignsDetach Policy Set CampaignsA
DestructiveIdempotent

Unbind campaigns from a policy set INCREMENTALLY — the bindings you don't name survive. Pass campaign_ids for specific campaigns or detach_all: true to clear the whole membership. This and attach_policy_set_campaigns are the only way to change membership; update_policy_set edits the set's name, description and rules, never its campaigns. Detaching leaves the policy set and its rules intact, and alerts already raised under it are kept.

ParametersJSON Schema
NameRequiredDescriptionDefault
detach_allNoUnbind EVERY campaign from this policy set. Check the current membership with `list_policy_set_campaigns` first — the campaigns stop being evaluated against these rules, so alerts they would have raised simply stop.
campaign_idsNoCampaign UUIDs to unbind, at most 500 per call. Omit when using `detach_all`.
policy_set_idYesPolicy set UUID.

TDQS

A5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark it destructive (destructiveHint: true), but the description adds crucial detail: detaching is incremental (unnamed bindings survive), the policy set and rules remain intact, and existing alerts are kept. It further explains that detached campaigns stop being evaluated, so new alerts simply stop. This goes well beyond the annotation flags.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact yet information-dense. It opens with the core behavior, then gives parameter options and contrasts with siblings, and closes with side effects. Every sentence earns its place; no fluff.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a mutation tool with no output schema, the description covers all essential aspects: what it does, incremental semantics, alternatives, and consequences for alerts. It even includes a practical tip for checking membership first. Nothing needed for correct invocation is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, but the description adds meaning beyond the schema: it clarifies the mutual exclusivity of campaign_ids and detach_all, caps campaign_ids at 500, and advises checking current membership via list_policy_set_campaigns before using detach_all. This enriches the agent's understanding of parameter usage and side effects.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('Unbind campaigns') and resource ('policy set'), and explicitly differentiates from siblings: it names attach_policy_set_campaigns as the complementary operation and clarifies that update_policy_set does not touch campaigns. This makes the tool's role unmistakable even without reading schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It provides explicit when-to-use guidance: pass campaign_ids for specific campaigns or detach_all: true for full clearance, and warns to check membership first via list_policy_set_campaigns. It also contrasts with update_policy_set and attach_policy_set_campaigns, covering both when to use and when not to use this tool.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_accountGet AccountA
Read-onlyIdempotent

Get the organization owning the current API key (id, name, owner_id, is_active, created_at). Use this to confirm authentication and capture the org context for follow-up tool calls.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false. The description adds value by specifying the returned fields and the purpose of confirming authentication and capturing org context, going beyond what annotations provide.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description spans two sentences with no extraneous information. It front-loads the core functionality and follows with a usage note, achieving maximum conciseness.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool has no parameters and no output schema, the description is fully complete: it explains what the tool does, what fields are returned, and when to use it. No additional information is needed.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

There are zero parameters, and schema description coverage is 100%. Per guidelines, this earns a baseline of 4. The description does not need to add parameter information, but it successfully clarifies the output and usage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool retrieves the organization owning the current API key and lists the returned fields (id, name, owner_id, is_active, created_at). It distinguishes itself from sibling tools by being the only tool for reading account info, as siblings focus on creating, updating, or deleting entities.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly says 'Use this to confirm authentication and capture the org context for follow-up tool calls,' providing clear guidance on when to invoke this tool. The read-only, non-destructive nature is further supported by annotations, making it safe to call anytime.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_alert_statsGet Alert StatsA
Read-onlyIdempotent

Get alert counts grouped by status: open, escalated, resolved, dismissed. Accepts every filter list_alerts does except status — the response buckets BY status — so passing the same filters to both makes the four counts sum to the total that list_alerts reports. Unfiltered, the counts cover the whole organization over all time. Use this to size a selection before calling bulk_update_alert_status with all_matching.

ParametersJSON Schema
NameRequiredDescriptionDefault
tagNoComma-separated tag slugs. Matches alerts carrying any of them; see `list_tags`.
date_toNoISO date (YYYY-MM-DD), inclusive upper bound on alert creation.
timezoneNoIANA timezone (e.g. 'Europe/Berlin') the date bounds are read in. Defaults to UTC. Omitting both dates spans all time.
date_fromNoISO date (YYYY-MM-DD), inclusive lower bound on alert creation.
campaign_idNoFilter to one campaign's alerts.
country_codeNoComma-separated ISO 3166-1 alpha-2 country codes, e.g. US,DE,JP.
policy_set_idNoComma-separated policy-set UUIDs. Matches alerts raised by any of them; see `list_policy_sets`.

TDQS

A4.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the safety profile is covered. The description adds valuable behavior: the scope of unfiltered counts ('cover the whole organization over all time') and the fact that the response buckets by status, which is not implied by the annotations. It does not describe pagination or response format, but given the annotation coverage, this is acceptable.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two sentences long, with the primary purpose front-loaded. It packs a lot of context (status grouping, filter compatibility, scope, and usage guidance) into a minimal length. Every sentence adds value, and there is no redundant or filler text.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (7 filters, no output schema), the description is remarkably complete. It explains what the tool returns (counts by status), how filters behave (same as list_alerts except status), the default scope (whole org all time), and a concrete use case (sizing before bulk_update_alert_status). Nothing critical is missing for an agent to decide to call it and understand the results.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so all 7 parameters are individually documented. The description adds a crucial semantic above the schema: it explicitly notes that the tool accepts every filter list_alerts does except status, explaining the absence of a status parameter and why (because the response is grouped by status). This extra clarity about parameter constraints is helpful and goes beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description immediately states the specific function: 'Get alert counts grouped by status: open, escalated, resolved, dismissed.' It names the resource (alerts) and the output format (counts by status). It also distinguishes itself from list_alerts and references bulk_update_alert_status, making it clear what this tool is versus what it is not.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly tells the agent when to use this tool: 'Use this to size a selection before calling bulk_update_alert_status with all_matching.' It also explains the relationship with list_alerts, noting that the same filters can be used and that counts sum to the total from list_alerts, thereby guiding the agent on when this provides value versus simply listing alerts.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_billing_summaryGet Billing SummaryA
Read-onlyIdempotent

Get the organization's billing snapshot: balance (in micros), current plan, period usage counters, suspension state, and whether new scans are accepted right now.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already indicate readOnlyHint=true, idempotentHint=true, destructiveHint=false. The description adds value by enumerating the specific fields returned (balance in micros, plan, counters, etc.), providing context beyond the annotations. No contradictions.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single sentence that efficiently conveys the tool's purpose and key return fields without any unnecessary words or repetition.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the absence of output schema and parameters, the description provides sufficient context: it identifies the tool as a read operation, lists return fields, and implies organizational scope. No critical information is missing for an agent to invoke it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

There are zero parameters; schema coverage is 100% by default. The description adds meaning by explaining what the returned data includes, meeting the baseline for a parameterless tool as per guidelines.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states it retrieves a billing snapshot with specific fields (balance, plan, counters, suspension, scan acceptance). The verb 'get' and resource 'billing summary' are specific and distinguishable from sibling tools like 'get_usage_summary' or 'list_balance_history'.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description does not provide any guidance on when to use this tool versus alternatives. It lacks instructions on when not to use it or comparisons to siblings.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_campaignGet CampaignA
Read-onlyIdempotent

Get one campaign by UUID: name, type (url|ad_tag|vast|ad_discovery), target URL / ad-tag / VAST tag (vast_tag), countries, emulator selection, proxy targeting, schedule status, archive status, parent group. Also echoes the repeat / retry settings — repeat_count, repeat_mode, retry_max_attempts — so this is how you confirm what create_campaign or update_campaign actually saved, and how many scans a run will produce (countries x device profiles x repeat_count). ad_discovery campaigns store the publisher page in the URL field.

ParametersJSON Schema
NameRequiredDescriptionDefault
campaign_idYesCampaign UUID.

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and idempotentHint=true. Description adds value by detailing exact return fields, including repeat/retry settings and ad_discovery behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Description is a single paragraph, front-loaded with purpose, and each sentence adds value. Slightly long but appropriate for detail.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read tool with one parameter and no output schema, the description covers all return fields, explains the scan count formula, and handles edge cases like ad_discovery. Fully complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and describes campaign_id as UUID. Description doesn't add new semantic info beyond what the schema already provides for the parameter.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states it retrieves one campaign by UUID, lists the fields returned, and distinguishes from list_campaigns. It uses specific verbs and resources.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says this confirms what create_campaign or update_campaign saved, providing clear context for when to use. Doesn't mention when not to use but differentiation from siblings is clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_campaign_alert_overridesGet Campaign Alert OverridesA
Read-onlyIdempotent

Get the per-campaign override of which alert destinations receive its alerts. mode is one of inherit (no override — the campaign follows the org-wide destinations), override (alerts go ONLY to the returned destination_ids), or silence (the campaign sends nothing).

ParametersJSON Schema
NameRequiredDescriptionDefault
campaign_idYesCampaign UUID.

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint and idempotentHint, so the description adds value by explaining the three modes ('inherit', 'override', 'silence') and their behavioral consequences (e.g., 'override' means alerts go ONLY to returned destination_ids). This goes beyond what annotations provide, though it stops short of detailing response structure.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two sentences with zero fluff. It fronts the main purpose and then explains the mode semantics, which are essential for interpreting the response. Every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description partially compensates by describing the mode values and referencing 'destination_ids'. For a simple one-parameter read operation with annotations covering safety, this is fairly complete, though a bit more detail on response structure would be ideal.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the only parameter (campaign_id) is fully described in the schema as a UUID. The description adds nothing about the parameter itself, but since the schema already handles it, the baseline of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('Get') and resource ('per-campaign override of which alert destinations receive its alerts'), making the tool's purpose immediately clear. It also distinguishes from the sibling 'set_campaign_alert_overrides' by explicitly covering the semantics of 'mode', which clarifies what the getter returns.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage (when you need to read the override) but doesn't explicitly say when to use this versus alternatives like 'list_alert_destinations' or the setter. There are no exclusions or alternative pointers, so guidance is only implied.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_campaign_groupGet Campaign GroupA
Read-onlyIdempotent

Get one campaign group by UUID with default/archive/pause flags and campaign count.

ParametersJSON Schema
NameRequiredDescriptionDefault
group_idYesCampaign group UUID.

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description adds context beyond annotations by specifying the returned fields (flags and campaign count). Annotations already indicate readOnlyHint=true and destructiveHint=false, so the tool is safe. No contradictions.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, front-loaded sentence that conveys essential information without any redundant or unnecessary words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description adequately explains the tool's purpose and return data for a simple get operation. No output schema is present, but the description covers what the agent needs to know.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has 100% coverage: one parameter (group_id) with a description. The description adds no further meaning beyond the schema, meeting the baseline for high schema coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action ('Get'), the resource ('campaign group'), the identifier ('by UUID'), and the specific data returned ('default/archive/pause flags and campaign count'). This fully distinguishes it from sibling tools like list_campaign_groups.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description does not explicitly state when to use this tool versus alternatives, nor does it provide exclusions or prerequisites. However, the verb 'Get' and the resource 'campaign group by UUID' imply usage when a specific UUID is known. No explicit when-not-to guidance is given.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_custom_ruleGet Custom RuleA
Read-onlyIdempotent

Get one custom rule by UUID with name, tag-slug, type, config object, target, active flag. For rule_type='combo' the returned config may carry the rule-level key match_scope ("scan" = count conditions across the whole scan, "url" = every condition must be satisfied by tags on the same link). Resend it verbatim when updating: update_custom_rule replaces config wholesale, so dropping the key reverts the rule to whole-scan matching.

ParametersJSON Schema
NameRequiredDescriptionDefault
rule_idYesRule UUID.

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, and destructiveHint. The description adds transparency about the config object's behavior for combo rules, specifically the match_scope key and its effect on updates, which is beyond the annotation metadata.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four sentences with no fluff. The first sentence states the core purpose, and subsequent sentences provide critical behavioral details and update guidance. Perfectly front-loaded and efficient.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's simplicity (1 parameter, no output schema, no nested objects), the description fully covers the returned fields and special behavior for combo rules. It also links to the update tool, making it contextually complete for an agent.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% with a single parameter rule_id that has a clear description and format. The description does not add additional semantic meaning beyond the schema, so baseline score of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description explicitly states 'Get one custom rule by UUID' with the specific fields returned, clearly distinguishing it from siblings like list_custom_rules and update_custom_rule.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides explicit guidance on using the returned config object when updating via update_custom_rule, warning about the match_scope key. Does not explicitly state when not to use, but the purpose is clear and usage context is well-covered.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_custom_taxonomyGet Custom TaxonomyA
Read-onlyIdempotent

Get one custom taxonomy by UUID with its full node tree (each node has id, parent_id, level, position, name, description, is_default).

ParametersJSON Schema
NameRequiredDescriptionDefault
taxonomy_idYesCustom taxonomy UUID.

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Adds context beyond annotations by specifying the return structure (full node tree with fields like id, parent_id, level, etc.). Annotations already indicate read-only and idempotent behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Single sentence, front-loaded with key information, no redundant text.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple retrieval tool with one parameter and no output schema, the description adequately describes the purpose and return structure.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Only one parameter with schema coverage 100%. The description adds no extra meaning beyond the schema's description, but baseline is 3.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Clearly states the verb 'Get' and the resource 'custom taxonomy by UUID', and distinguishes from siblings like 'list_custom_taxonomies' and 'create_custom_taxonomy'.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Implies usage when needing a single taxonomy by UUID, but lacks explicit guidance on when to use vs alternatives or when not to use.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_invoice_pdfGet Invoice PDFA
Read-onlyIdempotent

Download one invoice as an inline PDF (base64-encoded). Returned as a single MCP resource content block — agents can save / forward it without a second API call.

ParametersJSON Schema
NameRequiredDescriptionDefault
invoice_idYesInvoice UUID — see `list_invoices`.

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations provide readOnlyHint, idempotentHint; description adds that return is base64-encoded and as single MCP resource content block, beyond annotation scope.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two efficient sentences, no fluff, front-loaded with action and output format.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Although no output schema, description explains return format adequately for a simple download tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Invoice_id description in schema references list_invoices. Description does not add new semantics but schema coverage is 100%, so baseline applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Clearly states the verb 'download' and specific resource 'one invoice as an inline PDF'. Distinct from siblings like list_invoices which provide metadata.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Mentions agents can save/forward without a second API call, implying convenience. Does not explicitly exclude alternatives, but purpose is clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_policy_setGet Policy SetA
Read-onlyIdempotent

Get one policy set by UUID with its complete list of entries (each entry is one of five rule kinds — tag / iab_v3 / brand / ai_category / custom_taxonomy — plus applicable country codes). is_default is true when this owned set is the organization's default for new campaigns.

ParametersJSON Schema
NameRequiredDescriptionDefault
policy_set_idYesPolicy set UUID.

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so safety is covered. The description adds valuable behavioral context by detailing what the response contains (entries, rule kinds, country codes, is_default semantics), which goes beyond annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with the primary action, then concise elaboration on return structure. No redundant words or padding; every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple get-by-id tool with one parameter, the description covers the key return details (entries, rule kinds, country codes, is_default). It omits other metadata like name or description, but those are likely secondary. Acceptable completeness for typical use.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% with the parameter described as 'Policy set UUID.' The description does not add further meaning about the parameter (e.g., format constraints or default behavior). Baseline 3 applies given high schema coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool retrieves a single policy set by UUID and specifies the return structure: complete list of entries with five rule kinds and country codes, plus the is_default flag. This distinguishes it from list_policy_sets (retrieves many) and create/update/delete siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied (use when you need a specific policy set by ID) but there is no explicit guidance contrasting it with list_policy_sets or set_default_policy_set. No exclusions or alternative selection criteria are mentioned.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_proxy_targetingGet Proxy TargetingA
Read-onlyIdempotent

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 — 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 — a region and a city that do not belong together are accepted but leave the provider no exit node.

ParametersJSON Schema
NameRequiredDescriptionDefault
regionNoNarrow the returned cities to one region. Pass a value from this tool's own 'regions' array. Omit it for the country-wide city list.
proxy_typeNoWhich 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.
country_codeYesISO 3166-1 alpha-2 country code, e.g. 'US'. Case-insensitive.

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, idempotentHint=true, destructiveHint=false, so safety is covered. The description adds rich behavior beyond that: values are dynamically sourced from the upstream provider, ordered by pool size with a 'prefer front' heuristic, residential/mobile pool separation, the country-wide default for cities when a region is omitted, and the subtle warning that mismatched region/city pairs are accepted but leave no exit node. No annotation is contradicted.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Five sentences, each carrying distinct operational information: purpose, when-to-call, acceptance guarantee, ordering preference, and the two traps. The purpose is front-loaded, and the structure flows logically from what → when → how → gotchas. Nothing is repeated from the schema verbatim, and the length is justified given the real complexity of the tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Behavioral guidance is exhaustive: sourcing, ordering, pool semantics, validation behavior, and downstream consumer tools are all covered. The only gap is the exact output shape: there is no output schema, and while the schema's reference to 'this tool's own regions array' anchors one field name, the precise structure for cities and ISPs (field names, nesting) is left implicit. For a tool with three flat parameters and strong annotations, this is a minor omission.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and each parameter already has a strong description (ISO format, case-insensitivity, enum with defaults, pool separation, regions-array sourcing), so the baseline is 3. The description adds genuine meaning beyond the schema: the ordering heuristic ('prefer values near the front'), the acceptance guarantee ('Anything listed here is accepted'), the two-call workflow ('if you target a region, call again with that region and take the city from that narrower list'), and the 422 consequence — all of which shape how the agent chooses values.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence 'List the proxy regions, cities, and ISPs accepted for a country' states a specific verb, resource, and scope. The description further distinguishes this from the many sibling read tools (list_geos, list_emulators, get_scan) by naming the four consumer tools (create_scan, create_bulk_scans, create_campaign, update_campaign) that this lookup feeds, making its role unmistakable.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit when-to-call guidance: 'Call this before setting proxy targeting on create_scan, create_bulk_scans, create_campaign, or update_campaign'. It explains why this is mandatory (values come from the upstream network provider and cannot be listed in those tools' schemas) and the failure mode of the alternative ('a guess is a 422'), effectively stating the when-not-to: never guess or hardcode values.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_runGet RunA
Read-onlyIdempotent

Get one run by UUID with totals (queued, completed, failed, partial, cancelled), parent campaign, label, source.

ParametersJSON Schema
NameRequiredDescriptionDefault
run_idYesRun UUID.

TDQS

A3.8/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint and idempotentHint, covering safety. The description adds return field context but doesn't disclose additional traits like auth requirements or rate limits. With annotations, this is satisfactory.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single sentence, front-loaded with the action and then details. Every word adds value, with no fluff.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With one required parameter, no output schema, and clear annotations, the description provides sufficient context. It lists the return fields, which is valuable without an output schema. Slightly more detail on the structure could improve it, but it's mostly complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% with description for run_id (UUI). The tool description adds no extra meaning beyond what the schema provides, so baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool gets a single run by UUID and enumerates the fields returned (totals with statuses, parent campaign, label, source). This is specific and distinguishes it from sibling tools that retrieve other entities.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies when to use—when needing a run by UUID—but provides no explicit guidance on when not to use it or alternatives. For a simple retrieval tool, this is adequate but leaves room for ambiguity.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_scanGet ScanA
Read-onlyIdempotent

Get full detail for one scan by UUID: status, offer URL, absolute screenshot URL, report_url + public_report_url deep-links, timing, labels, and the parent campaign if any. VAST video scans also carry vast_tag, creative_kind (banner or video today; treat it as an open string), and a video block (duration, media-file URL, the creative's click_through destination, VAST version, ad system, VPAID flag, wrapper depth). Repeats and retries: repeat_index / repeat_total place this scan inside its repeat group (0-based, so 2 of 5 reads as repeat_index 1), a non-null repeat_session_id means the group ran in shared mode (same browser, same IP, cookies carried over) and is the key to correlate its members — a shared group of one has nothing to carry over, so it stays null — repeat_scan_ids is filled only on the create response, and retry_attempt / retry_max_attempts show how many technical re-crawls this scan already consumed. Link users with the returned report_url / public_report_url — never construct URLs yourself.

ParametersJSON Schema
NameRequiredDescriptionDefault
scan_idYesThe scan's UUID (returned by `list_scans` or `create_scan`).

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations mark it as read-only, idempotent, and non-destructive. The description adds value by explaining repeat/retry semantics, shared mode, and VAST video details. It warns against constructing URLs manually, providing behavioral context beyond annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the main purpose but becomes lengthy explaining VAST and repeat/retry details. Every sentence adds value given the complexity, but could be slightly more concise.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema exists, so the description must cover return fields completely. It does so, listing status, URLs, timing, labels, campaign, VAST specifics, and repeat/retry fields with detailed explanations. The description is comprehensive for the tool's complexity.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema fully describes the single parameter (scan_id as UUID, sourced from list_scans or create_scan). The description does not add new constraints or format details; it only repeats the purpose. With 100% schema coverage, this is a baseline score.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states it retrieves full detail for a single scan by UUID, listing specific fields like status, URLs, timing, labels, and parent campaign. It distinguishes from sibling tools like list_scans (which returns a list) and get_scan_screenshot (which gets a screenshot).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies use when full detail of a specific scan is needed, but does not explicitly state when to use this tool over alternatives or provide exclusion criteria. The note about linking users with report URLs is a usage hint but not about tool selection.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_scan_creative_htmlGet Scan Creative HTMLA
Read-onlyIdempotent

Fetch the generated creative markup for an ad-tag scan as text — the HTML the ad tag produced, with the scripts, iframes and click-through URLs it embedded. Use it to explain WHY a creative was tagged when a screenshot cannot show it (obfuscated redirectors, hidden trackers, injected handlers). Only ad-tag scans have this artifact; a URL or VAST scan returns not-found. The markup is returned inert as text and is never executed. Markup over 256 KiB is refused — open the report URL from get_scan for those.

ParametersJSON Schema
NameRequiredDescriptionDefault
scan_idYesScan UUID.

TDQS

A4.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, idempotentHint=true, destructiveHint=false, so the agent knows it's safe. The description adds two critical behaviors beyond annotations: 'The markup is returned inert as text and is never executed' and 'Markup over 256 KiB is refused.' These are valuable operational details that affect caller behavior (e.g., not treating output as executable) and handling of large payloads. No contradiction with annotations exists.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the main action and then efficiently covers why to use it, limitations, and behavior. Every sentence earns its place: the first states the purpose, the second gives the use case, the third differentiates scan types, the fourth clarifies safety, and the fifth notes the size limit. No filler or repetition. It is concise despite being multi-sentence because each sentence contributes unique, actionable information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-parameter tool with no output schema, the description covers all essential aspects: what is returned (HTML markup with embedded elements), why to use it (explain tagging not visible in screenshots), scope (only ad-tag scans), behavior (inert text, never executed), and a critical limitation (256 KiB limit with fallback). The agent has everything needed to decide when to call, what to expect, and how to handle edge cases, making it contextually complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the parameter scan_id is already described as 'Scan UUID.' The description adds meaning beyond that by clarifying that the scan must be an ad-tag scan, not a URL or VAST scan, since only ad-tag scans have this artifact. It also implies the UUID must refer to an existing scan. This is a subtle but important constraint that helps the agent pass a valid scan_id, going beyond the schema's generic description.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Fetch the generated creative markup for an ad-tag scan as text.' It clearly states what the tool returns (scripts, iframes, click-through URLs) and differentiates from siblings by specifying that only ad-tag scans have this artifact, URL/VAST scans return not-found. This immediately distinguishes it from related tools like get_scan_screenshot or get_scan_vast_xml.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly gives when to use the tool: 'Use it to explain WHY a creative was tagged when a screenshot cannot show it (obfuscated redirectors, hidden trackers, injected handlers).' It also gives a clear exclusion: 'Only ad-tag scans have this artifact; a URL or VAST scan returns not-found.' Additionally, it provides a fallback for large markup: 'open the report URL from get_scan.' This is concrete, actionable guidance that tells the agent exactly when to invoke this vs. alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_scan_creative_screenshotGet Scan Creative ScreenshotA
Read-onlyIdempotent

Fetch the creative screenshot for an ad-tag scan as an inline image (base64-encoded WebP — the API stores and serves every screenshot as WebP, so the client must be able to decode it). Returns 404 if the scan is not an ad-tag scan or has no creative captured yet.

ParametersJSON Schema
NameRequiredDescriptionDefault
widthNoOptional resize width in pixels.
scan_idYesScan UUID — must be an ad-tag scan (is_ad_tag=true).

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description goes well beyond the readOnly/idempotent annotations by revealing the return encoding (base64 WebP), the client-side decode requirement, and the specific 404 behavior when no creative exists. This is valuable behavioral context an agent cannot infer from the schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact and well-structured: it leads with the action and resource, then gives the encoding detail, then the error condition. Every sentence adds useful information without padding.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only fetch tool with no output schema, the description sufficiently covers the return format, decode expectations, and failure conditions. The schema covers parameters, and the annotations cover safety, so nothing critical is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so scan_id and width are already documented. The description adds the ad-tag-scan context already present in the schema's scan_id description, but does not add meaningful new parameter-level semantics.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb-resource pair: 'Fetch the creative screenshot for an ad-tag scan.' It also clarifies the output form (inline base64 WebP image) and the ad-tag-scan prerequisite, which separates it from related screenshot tools like get_scan_screenshot and get_scan_landing_screenshot.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description clearly indicates when the tool is appropriate: for ad-tag scans with a captured creative, and it explicitly describes when it will not work via the 404 condition. However, it does not name alternatives such as get_scan_creative_html or get_scan_screenshot for non-ad-tag scans.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_scan_creative_videoGet Scan Creative VideoA
Read-onlyIdempotent

Fetch the MP4 MediaFile a VAST scan downloaded, as one inline resource block. Only VAST scans have it; others return not-found. Prefer get_scan_creative_screenshot for a still frame and get_scan_vast_xml for the declared metadata — both are far cheaper. Reach for the video itself only when the moving image is the evidence. Files over 8 MiB are refused rather than inlined; fall back to get_scan_creative_screenshot or the report URL from get_scan for those.

ParametersJSON Schema
NameRequiredDescriptionDefault
scan_idYesScan UUID.

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the safety profile is covered. The description adds valuable behavioral detail: only VAST scans contain the video (others return not-found), files over 8 MiB are refused rather than inlined, and it explicitly notes fallback options. This goes beyond the annotations to disclose edge cases and limitations that could affect successful invocation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is three sentences, no fluff, and information is front-loaded: the main action is stated first, then the constraint (only VAST), then alternatives and size limit. Every sentence earns its place with actionable guidance. There is no redundant phrasing or over-explanation.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-parameter read-only tool with no output schema, the description covers all essential context: what the tool returns, when it succeeds (VAST only), when it fails (non-VAST, large files), and what to use instead. The presence of sibling alternatives and fallback options makes it fully self-contained for an agent to decide when to call it.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema covers the single parameter (scan_id) with a clear description 'Scan UUID' at 100% coverage. The description does not add further semantic detail about the parameter itself, but it does implicitly tie it to VAST scans. Since schema coverage is complete, a baseline of 3 is appropriate; the description adds no extra meaning beyond what the schema provides.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the specific action ('Fetch'), the resource ('MP4 MediaFile a VAST scan downloaded'), and the output format ('one inline resource block'). It distinguishes this tool from siblings by explicitly noting that only VAST scans have the video and that others return not-found. The purpose is unmistakable and well-differentiated from similar tools like get_scan_creative_screenshot and get_scan_vast_xml.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit guidance on when to use this tool versus alternatives: it recommends preferring get_scan_creative_screenshot for still frames and get_scan_vast_xml for metadata, calling them 'far cheaper,' and reserves video usage for 'when the moving image is the evidence.' It also gives a clear fallback for large files, stating that files over 8 MiB are refused and directing users to use get_scan_creative_screenshot or the report URL from get_scan. This is complete usage routing.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_scan_landing_screenshotGet Scan Landing ScreenshotA
Read-onlyIdempotent

Fetch the screenshot of one landing tab on an ad-tag scan as an inline image (base64-encoded WebP — the API stores and serves every screenshot as WebP, so the client must be able to decode it). Use get_scan first to discover available landings[*].ord values.

ParametersJSON Schema
NameRequiredDescriptionDefault
widthNoOptional resize width in pixels. The API top-crops a resized landing screenshot whose height exceeds 2.5x its width, so a long landing page comes back as its top region only — never conclude that something is absent from the page from a resized capture. Fetch without `width` when you need the whole page.
scan_idYesScan UUID (ad-tag scan).
landing_ordYes0-indexed landing slot (see `get_scan(...).landings[*].ord`).

TDQS

A5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description discloses that the API always serves WebP and that resized screenshots are top-cropped when height exceeds 2.5x width. It warns against concluding content is absent from resized captures, which is critical behavioral context beyond the idempotent and read-only annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact but information-dense. The key action and format are front-loaded, followed by necessary warnings and a clear procedural pointer. Every sentence adds value, with no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's simplicity (3 params, no output schema), the description covers the necessary pre-requisite, the return format, the resizing caveat, and how to get the full page. Nothing essential is missing for an agent to call it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

While schema coverage is 100%, the description adds crucial meaning to the `width` parameter by explaining the cropping behavior and advising to omit it for full-page captures. It also reinforces how `landing_ord` relates to `get_scan` output, going beyond the raw schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool fetches a screenshot of one landing tab on an ad-tag scan as a base64-encoded inline image. It specifies the format (WebP) and distinguishes from sibling tools like get_scan_screenshot and get_scan_creative_screenshot by mentioning "landing tab on an ad-tag scan."

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly instructs to call `get_scan` first to discover available `landings[*].ord` values, giving a clear before/after sequence. It also explains when to omit the `width` parameter to get the whole page, which is actionable usage guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_scan_screenshotGet Scan ScreenshotA
Read-onlyIdempotent

Fetch the primary screenshot for a scan as an inline image (base64-encoded WebP — the API stores and serves every screenshot as WebP, so the client must be able to decode it). Pass width to request a resized version (50-2000 px). Returns one MCP image content block.

ParametersJSON Schema
NameRequiredDescriptionDefault
widthNoOptional resize width in pixels. The API resizes server-side to keep the image small for the agent's context window. It also top-crops a resized page screenshot whose height exceeds 2.5x its width, so a long page comes back as its top region only — never conclude that something is absent from the page from a resized capture. Fetch without `width` when you need the whole page.
scan_idYesScan UUID.

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations, the description discloses the exact return format (one MCP image content block, base64 WebP) and the server-side resize/top-crop behavior. It even flags a practical caveat about long pages being top-cropped. This strongly helps an agent predict tool behavior and is consistent with the readOnlyHint and idempotentHint annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise and front-loaded: purpose, output format, and primary usage tip appear in two efficient sentences. The additional width caveat lives in the schema where it belongs, keeping the main description readable without losing critical details.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only, two-parameter tool, the definition is complete: required input, optional behavior, return format, and an important interpretation caveat are all covered. The lack of an output schema is mitigated by explicitly stating the one MCP image content block. The only minor omission is an explicit routing note about sibling screenshot tools, but the primary/creative/landing naming makes that clear enough.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema already documents both parameters thoroughly, including the width range and crop behavior. The main description adds limited parameter-specific meaning beyond the schema, mostly repeating the width intent. With 100% schema description coverage, a baseline of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: 'Fetch the primary screenshot for a scan'. It also identifies the output format, an inline base64-encoded WebP image, making the tool's purpose concrete. The word 'primary' differentiates it from sibling screenshot tools like get_scan_creative_screenshot and get_scan_landing_screenshot.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear guidance on when to use optional width: pass it for a smaller server-resized image, and omit it when the whole page is needed. It also warns against concluding content is absent from a resized capture. However, it does not explicitly contrast this tool with screenshot siblings such as creative or landing screenshot tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_scan_vast_xmlGet Scan VAST XMLA
Read-onlyIdempotent

Fetch the VAST document for a VAST scan as text, with wrappers already resolved so the whole chain is visible in one payload. Use it to inspect the tracking pixels, verification vendors, companion ads and click-through targets a video ad declared — the parsed summary on get_scan (video block) covers duration, media file and ad system, but not the full element tree. Only VAST scans have this artifact; others return not-found. Documents over 256 KiB are refused.

ParametersJSON Schema
NameRequiredDescriptionDefault
scan_idYesScan UUID.

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, and destructiveHint, so safety is covered. The description adds valuable behaviors beyond that: wrappers are resolved, documents over 256 KiB are refused, and non-VAST scans return not-found. This gives the agent realistic expectations about content and failure modes without contradicting annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Every sentence earns its place: the primary action, the usage rationale, the alternative, the applicability restriction, and the size limit. It is front-loaded with the main purpose and avoids any fluff. The length is justified by the rich content.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With a single parameter, no output schema, and a text return value, the description sufficiently covers what is returned (VAST document as text), the resolution of wrappers, the size cap, and the not-found case. It also directs the agent to get_scan for a summary, covering the relationship between tools. Nothing essential is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema already documents scan_id as 'Scan UUID.' The description does not add any syntax, format, or constraint details beyond that. It mentions 'VAST scan' as context but this is not parameter-specific semantics. Baseline 3 is appropriate since the schema carries the full burden.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('Fetch'), a precise resource ('the VAST document for a VAST scan as text'), and a key differentiator ('wrappers already resolved so the whole chain is visible in one payload'). It distinguishes itself from siblings like get_scan by explicitly contrasting its full element tree with get_scan's parsed summary. No ambiguity about what it does.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states when to use it: to inspect tracking pixels, verification vendors, companion ads, and click-through targets. It names the alternative (get_scan) and exactly what that alternative covers (duration, media file, ad system), making the choice unambiguous. It also notes that only VAST scans have this artifact, guiding the agent on applicability.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_tag_definitionGet Tag DefinitionA
Read-onlyIdempotent

Get full definition of one tag: display name, description, severity, category, source (system vs custom), public-report visibility, usage counts, plus linked_rules — 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.

ParametersJSON Schema
NameRequiredDescriptionDefault
slugYesTag slug (e.g. `malware`, `redirect_chain_too_long`).

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, and destructiveHint, so safety profile is covered. The description adds useful edge-case behavior: returns 404 for archived tags the org does not own, including every archived system tag. This goes beyond structured annotations without contradicting them.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, information-dense paragraph with no filler. Each part earns its place: field enumeration, cross-reference, and a 404 edge case. It is slightly long but still front-loaded and readable.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description compensates by enumerating the return fields and the linked_rules shape. It also covers an important error case and a relevant sibling route. For a one-parameter read-only tool, this is complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the slug parameter already has a clear description with examples. The tool description adds no further parameter-level detail, so baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb and resource, 'Get full definition of one tag,' and enumerates the exact fields returned. It distinguishes itself from siblings by being tag-level rather than rule-level and explicitly points to get_custom_rule for rule config.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It clearly implies when to use this tool (full tag definition) and explicitly directs rule-config needs to get_custom_rule. It does not mention list_tags, but the single-tag scope and alternative reference provide adequate usage context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_usage_summaryGet Usage SummaryA
Read-onlyIdempotent

Get a one-liner aggregate of usage for the current billing period: total cost (micros), check count, period start/end.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.1/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare the tool as read-only, idempotent, and non-destructive. The description adds context that the output is a one-liner aggregate, but does not disclose any behavioral traits beyond what annotations provide (e.g., no mention of handling empty usage or error conditions). It adds some value but not rich behavioral context.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single sentence that immediately states the purpose and lists the return fields. Every word adds value, and there is no extraneous information. It is ideally concise and front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's simplicity (zero parameters, no output schema), the description is fully complete. It explicitly states what data is returned, and no additional context (e.g., error behavior) is necessary for a read-only aggregate query. The annotations further assure the agent of safe usage.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has no parameters, so the description does not need to explain them. Schema coverage is 100%, and the description correctly implies no inputs are required. This exceeds the baseline for zero-parameter tools.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly specifies the action ('Get'), the resource ('usage summary'), and the scope ('current billing period'), along with the exact fields returned (total cost in micros, check count, period start/end). This fully distinguishes it from siblings like 'get_billing_summary' or 'list_usage'.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies it is for a quick aggregate view via the phrase 'one-liner aggregate', but it does not explicitly state when to use this tool versus alternatives like 'list_usage' or 'get_billing_summary'. No exclusions or alternative suggestions are provided.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_webhookGet WebhookA
Read-onlyIdempotent

Get one webhook endpoint by UUID with URL, subscribed event types, active flag.

ParametersJSON Schema
NameRequiredDescriptionDefault
webhook_idYesWebhook endpoint UUID.

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already provide readOnlyHint=true and idempotentHint=true; description adds return field details (URL, event types, active flag) beyond annotations. No contradictions.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

One sentence of 12 words, front-loaded with verb and resource, no wasted words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Simple read tool with full annotation coverage; description adequately explains what is returned, compensating for lack of output schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and parameter description is clear; description adds little beyond schema for the webhook_id parameter, only reiterating 'by UUID'.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description clearly states verb 'Get one webhook endpoint by UUID' and specifies returned fields (URL, subscribed event types, active flag), distinguishing it from sibling tools like list_webhooks.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Description implies usage for retrieving a single webhook by UUID, but does not explicitly contrast with alternatives like list_webhooks or provide when-not guidance. Context makes it clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

invite_userInvite UserA

Send an invitation email so a new person can join the caller's organization with a chosen role. Returns the pending member record.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameNoOptional display name for the invitee.
emailYesEmail of the person to invite. They get a signup link.
role_idYesUUID of the role to assign on accept. Get UUIDs from `list_org_roles`.
timezoneNoOptional IANA timezone for the invitee, e.g. 'Europe/Berlin'. Default: UTC.

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations indicate non-read-only, non-destructive, and non-idempotent. Description adds that it sends an email and returns a pending member record, which is useful beyond annotations. Could mention idempotency or rate limits.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, no fluff, front-loaded with the action. Every sentence adds value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description explains the return value (pending member record) since there is no output schema. Covers the tool's purpose and parameters adequately for its complexity.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

All four parameters are described in the input schema (100% coverage). The description adds helpful hints: 'They get a signup link' for email and 'Get UUIDs from list_org_roles' for role_id, enhancing understanding.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Clearly states the action (send invitation email), the target resource (new person joining organization), and the return value (pending member record). Distinguishes from siblings like 'remove_user' and 'update_user_role'.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Implies usage for inviting a new user to the organization, but does not provide explicit when-to-use or when-not-to-use guidance compared to alternatives. No mention of prerequisites or conditions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_account_labelsList Account LabelsA
Read-onlyIdempotent

List the organization's custom label definitions (key, display_name, position, auto_extract). Labels enrich scans and can be used as filters in list_scans.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.3/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly, idempotent, and non-destructive behavior. The description adds that it returns custom label definitions at the organization level, which is useful context but does not reveal any surprising behaviors beyond what annotations imply.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two concise sentences with front-loaded verb phrase. Every sentence adds value: first states the action and output fields, second explains the purpose and connection to list_scans. No wasted words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-parameter tool with no output schema and clear annotations, the description is complete. It explains what is listed, the fields, and how labels are used, providing sufficient context for an agent to invoke correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Tool has no parameters (schema coverage 100%), so description does not need to add parameter info. The description lists the fields returned, which provides meaning beyond the empty schema. Baseline for 0 params is 4.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description clearly states the tool lists organization's custom label definitions and enumerates the fields (key, display_name, position, auto_extract). It differentiates from siblings like update_account_labels and list_scans by specifying the listing behavior and the use of labels as filters.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explains that labels enrich scans and can be used as filters in list_scans, providing context for when to use this tool. It does not explicitly state when not to use alternatives, but the purpose is clear enough for a simple list operation.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_alert_destinationsList Alert DestinationsA
Read-onlyIdempotent

List configured alert-notification destinations (channels): Slack workspaces, Telegram chats, email lists, generic webhooks. Each entry has id, kind, display name, version, and creation timestamp.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.1/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, idempotentHint=true, destructiveHint=false. The description adds content information (return fields) but no further behavioral traits such as pagination, limits, or authentication requirements. With annotations covering safety, the description is adequate but adds little beyond what is evident.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences: first states purpose and scope, second details output fields. No filler, every sentence adds value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple list tool with no parameters and no output schema, the description fully covers what is returned and the nature of the resource. No missing information.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters and 100% schema coverage (none). Baseline is 4 per guidelines. Description adds value by describing the return fields, which helps the agent understand the output.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description specifies exactly what the tool does: list configured alert-notification destinations (channels) with explicit types (Slack, Telegram, etc.) and field details. Clearly distinguishes from sibling tools like delete_alert_destination or set_alert_destination_version.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies when to use (to view destinations) but does not explicitly contrast with alternatives or state when not to use it. Since the tool is simple and has no parameters, the lack of explicit guidance is acceptable but not optimal.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_alertsList AlertsA
Read-onlyIdempotent

List violation alerts (one per scan + violating rule combo) with offer URL, country, status, scan back-reference, and the kind-aware fields rule_type (tag / iab_v3 / brand / ai_category / custom_taxonomy) + matched_value (the canonical text the scan matched against). Filter by campaign, status, policy set, tag, country and creation-date range; policy_set_id, tag and country_code take comma-separated values and match any of them. Pass the same filters to get_alert_stats to get counts that agree with this list.

ParametersJSON Schema
NameRequiredDescriptionDefault
tagNoComma-separated tag slugs. Matches alerts carrying any of them; see `list_tags`.
pageNo1-indexed page number.
limitNoPage size.
statusNoFilter by alert status. Open = unhandled; escalated = flagged for attention; resolved = closed; dismissed = closed without action.
date_toNoISO date (YYYY-MM-DD), inclusive upper bound on alert creation.
timezoneNoIANA timezone (e.g. 'Europe/Berlin') the date bounds are read in. Defaults to UTC. Omitting both dates spans all time.
date_fromNoISO date (YYYY-MM-DD), inclusive lower bound on alert creation.
campaign_idNoFilter to one campaign's alerts.
country_codeNoComma-separated ISO 3166-1 alpha-2 country codes, e.g. US,DE,JP.
policy_set_idNoComma-separated policy-set UUIDs. Matches alerts raised by any of them; see `list_policy_sets`.

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already carry the safety profile (readOnlyHint=true, idempotentHint=true, destructiveHint=false), which aligns with the non-mutating 'List' verb. The description adds value beyond annotations by disclosing the dedup rule, the kind-aware rule_type values, and the filter behavior. No contradiction; annotation_contradiction=false.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

One information-dense sentence delivers the return fields, dedup rule, filter list, OR-match semantics, and the stats relationship with no filler. It is front-loaded with the return semantics. It is dense enough that a line break or two would aid readability, but nothing is wasted.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description correctly carries the return-value burden by enumerating the fields (offer URL, country, status, scan back-reference, rule_type, matched_value) and the dedup semantics. Filters and pagination are covered by a fully-documented schema. Together they give an agent everything needed to call it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3 because the schema already documents all 10 parameters with defaults and enum meanings. The description earns a 4 by adding semantics beyond the schema: the dedup definition, the kind-aware field context, and the OR-match behavior for comma-separated values. It also points out the cross-tool filter relationship with get_alert_stats.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a precise verb+resource ('List violation alerts') and enriches it with the dedup semantics ('one per scan + violating rule combo') and the exact returned fields (offer URL, country, status, scan back-reference, rule_type, matched_value). This distinguishes it clearly from the sibling get_alert_stats, which is about aggregates rather than the alert list itself.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear actionable context: it explains that the same filters passed to get_alert_stats yield agreeing counts, which routes the agent between list vs. stats tools. It also explains the OR-match semantics of comma-separated filters. It stops short of an explicit 'use X instead when…' exclusion, which keeps it from a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_api_keysList Api KeysA
Read-onlyIdempotent

List the organization's API keys: id, key prefix (first 8 chars of the secret), display name, expiry, created_at. The full secret is NEVER returned by this endpoint — only the prefix.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, idempotentHint=true, destructiveHint=false, establishing safety. The description adds crucial context that 'The full secret is NEVER returned' – an important behavioral constraint beyond annotations. No contradictions.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences: first sentence clearly states what the tool lists, second sentence adds a critical behavioral warning. No wasted words, front-loaded with purpose.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite no output schema, the description lists the fields returned. For a simple parameterless list tool, this is complete. All necessary context is provided.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Input schema has 0 parameters, so schema description coverage is 100%. Baseline for zero parameters is 4. Description does not need to explain parameters.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description clearly states 'List the organization's API keys' and enumerates returned fields (id, key prefix, display name, etc.). Verb 'List' and resource 'API keys' are specific, and sibling tools (create_api_key, revoke_api_key) differentiate this as a read-only operation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No explicit when-to-use or when-not-to-use guidance is provided. The description implies this tool is for listing keys and notes that the full secret is not available, but does not mention alternatives such as create_api_key for creation or revoke_api_key for revocation.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_balance_historyList Balance HistoryA
Read-onlyIdempotent

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
pageNo1-indexed page.
typeNoFilter 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.
limitNoPage size.
date_toNoISO date, inclusive.
date_fromNoISO date, inclusive.

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover the safety profile (readOnly, idempotent, non-destructive, closed-world), so the bar is lower. The description adds real behavioral content beyond them: the shape of each returned row (type, amount, description, timestamp) and the crucial unit detail that amounts are in micros. Pagination ordering and default sort are not disclosed, keeping it short of a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with the resource identified first and the filters second. No filler, no restatement of the title.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema present, the description compensates by describing the returned row fields and the micros unit, which is exactly what an agent needs to interpret results. Filtering is fully covered by the schema. Ordering/pagination behavior is the only material omission.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the schema itself documents page/limit bounds, ISO date inclusivity and the enum semantics including OR-ing and the signed adjustment caveat. The description's mention of multi-select type and date range merely restates the schema, adding nothing new.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb ('List') and resource ('ledger transactions ... on the organization's balance') and enumerates the transaction kinds covered. It does not explicitly contrast itself with nearby siblings such as list_invoices or get_billing_summary, so an agent must infer the boundary, but the resource is named precisely enough to be usable.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description tells how to narrow results ('Filter by `type` (multi-select) and / or date range') but never says when this tool is preferred over list_invoices, list_usage or get_billing_summary. Usage is implied by the resource rather than stated as a decision rule.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_campaign_groupsList Campaign GroupsA
Read-onlyIdempotent

List campaign groups — folders that group related campaigns — with per-group campaign count and last_run_at. Filter by archived flag, name substring, or creation / last-run date range; a group's last run is the newest run across its campaigns. Not paginated; the org-scoped list is typically small (a few dozen groups max).

ParametersJSON Schema
NameRequiredDescriptionDefault
qNoSubstring search against group name (case-insensitive).
archivedNoIf true, list ONLY archived groups. Default: only active groups.
timezoneNoIANA timezone (e.g. 'Europe/Berlin') the date bounds are read in. Defaults to UTC.
created_toNoISO date (YYYY-MM-DD), inclusive upper bound on the creation day.
last_run_toNoISO date (YYYY-MM-DD), inclusive upper bound on the most recent run.
created_fromNoISO date (YYYY-MM-DD), inclusive lower bound on the creation day.
last_run_fromNoISO date (YYYY-MM-DD), inclusive lower bound on the most recent run. Setting either last-run bound excludes anything that has never run.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark it read-only, idempotent, and non-destructive. The description adds meaningful behavior: the list is not paginated (all groups returned at once) and the org-scoped list is small. It also explains the semantics of last_run_at (newest run across its campaigns), which is not derivable from annotations. This gives the agent a solid mental model of the tool's behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two sentences. The first sentence states the action and key returned fields. The second covers filters, the special meaning of last run, and the non-pagination/size note. Every sentence earns its place, and the most important info is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, so the description must convey the return shape. It does state per-group campaign count and last_run_at, which is a useful sketch. It also addresses potential concerns like pagination and list size. It doesn't mention sorting or other fields, but for a read-only list tool that is typically small, this is adequate. Slightly more detail on return fields would push it to a 5.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% so baseline is 3, but the description adds value beyond the schema by explaining what 'last run' means in the context of last_run_from/last_run_to filters. It also summarizes the filter groups (archived flag, name substring, date ranges) in one concise phrase. This extra semantic context justifies a 4.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states the verb 'List' and the resource 'campaign groups', then defines what a campaign group is ('folders that group related campaigns') and what it returns (per-group campaign count and last_run_at). This clearly distinguishes it from listing campaigns or getting a single group, so the purpose is unambiguous and well-scoped.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear usage context: what it lists, the available filters, and the note that the list is not paginated and typically small. However, it does not explicitly contrast with siblings like get_campaign_group (for a single group) or list_campaigns (for campaigns). Since the tool name and description make the resource type clear, it earns a 4 for context without explicit exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_campaign_runsList Campaign RunsA
Read-onlyIdempotent

List every run (scheduled execution) of one campaign, paginated, with per-run counters.

ParametersJSON Schema
NameRequiredDescriptionDefault
pageNo1-indexed page.
limitNoPage size.
campaign_idYesCampaign UUID.

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, destructiveHint. Description adds 'per-run counters' and 'paginated', providing context beyond annotations without contradiction.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Single sentence, front-loaded, with no unnecessary words. Efficiently conveys purpose and key characteristics.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Adequate for a simple list tool with 3 parameters and full annotations. Missing details like return format, but counters imply some data shape. Sufficient for agent to select and invoke correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so parameters are well-documented. Description adds 'paginated' and 'per-run counters' but does not enhance parameter meaning beyond schema defaults.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Clearly states 'List every run...of one campaign, paginated, with per-run counters.' Specifies verb, resource, and additional details that distinguish from sibling tools like 'list_run_scans'.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Implies usage for retrieving a paginated list of runs for a specific campaign. Does not explicitly state when not to use or provide alternatives, but context is clear enough from the description and sibling tool names.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_campaignsList CampaignsB
Read-onlyIdempotent

List campaigns for the caller's organization, optionally filtered by group, archived flag, name substring, or creation / last-run date range. Paginated. Each row carries the same fields as get_campaign, including the repeat / retry settings (repeat_count, repeat_mode, retry_max_attempts) — use them to spot the campaigns that multiply their per-run scan count.

ParametersJSON Schema
NameRequiredDescriptionDefault
qNoSubstring search against campaign name (case-insensitive).
pageNo1-indexed page number.
limitNoPage size (1-200).
archivedNoWhen omitted, the API returns active campaigns only. Pass `true` to see archived campaigns, `false` for active-only (explicit).
group_idNoOptional campaign-group UUID to filter by.
timezoneNoIANA timezone (e.g. 'Europe/Berlin') the date bounds are read in. Defaults to UTC.
created_toNoISO date (YYYY-MM-DD), inclusive upper bound on the creation day.
last_run_toNoISO date (YYYY-MM-DD), inclusive upper bound on the most recent run.
created_fromNoISO date (YYYY-MM-DD), inclusive lower bound on the creation day.
last_run_fromNoISO date (YYYY-MM-DD), inclusive lower bound on the most recent run. Setting either last-run bound excludes anything that has never run.

TDQS

B3.2/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already establish the read-only, idempotent, non-destructive profile (readOnlyHint=true, idempotentHint=true, destructiveHint=false), so no credit is needed for safety disclosure. The description adds useful beyond-annotation behavior: the 'Paginated' note and the return-format promise that each row 'carries the same fields as get_campaign', pointing the agent to that sibling for full field definitions. This is meaningful context, though it does not fully characterize pagination semantics or empty-result behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, front-loaded with the core action and scope before the filter list. The final sentence on spotting scan-multiplying campaigns is the least purely-functional part, but it earns its place by flagging a concrete use case for the repeat/retry fields. Minimal waste overall.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only list tool with zero required parameters and fully documented schema (including the subtle archived-omitted default and the never-run exclusion on last-run bounds), the description covers the essentials: purpose, scope, filter axes, pagination, and return format via the get_campaign reference. It is complete enough for an agent to call it correctly; only the absent output schema (no explicit field list) keeps it from a 5.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% with detailed per-parameter text (e.g., the archived flag explains omitted-vs-true-vs-false, and last_run_from notes the never-run exclusion). The description adds only a high-level grouping of those filters (group, archived, name substring, date ranges), which maps cleanly to the schema but does not deepen meaning beyond it. This is the expected baseline-3 case where the schema carries the load.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a specific action ('List campaigns'), a bounded scope ('for the caller's organization'), and enumerates the filter axes (group, archived flag, name substring, creation/last-run date range). It is clear and specific. It stops short of a 5 because it does not explicitly differentiate from the near-named sibling `list_campaigns_picker`, relying on name inference and the 'same fields as get_campaign' note instead of an explicit distinction.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no guidance on when to choose this tool over alternatives such as `get_campaign` or the sibling `list_campaigns_picker`, and no exclusionary guidance ('do not use when...'). The only usage hint—'use them to spot the campaigns that multiply their per-run scan count'—concerns interpreting returned fields after the call, not tool selection. With a picker sibling present, the absence of when/why-routing is a real gap.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_campaigns_pickerList Campaigns (Picker)A
Read-onlyIdempotent

Slim per-row campaign list for selection UIs — id, name, group_id, is_archived. Cheaper than list_campaigns for orgs with thousands of campaigns. Use get_campaign(id) after a selection to fetch full details.

ParametersJSON Schema
NameRequiredDescriptionDefault
qNoSubstring search against campaign name (case-insensitive).
limitNoMaximum rows to return (default per API, typically 200).
archivedNoPass true to include archived campaigns. Defaults to active-only.
group_idNoFilter to one campaign group.

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and destructiveHint=false, so the safety profile is known. The description adds value by stating the fields returned ('id, name, group_id, is_archived') and performance characteristic ('cheaper'), which are beyond annotation scope. No contradictions.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three concise sentences: purpose+fields, comparison to sibling, and follow-up action. No wasted words, perfectly front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple read-only filtered list tool with well-described parameters and rich annotations, the description fully covers what the agent needs: purpose, fields returned, performance, and next steps. No gaps.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, with all parameters having clear descriptions (q, limit, archived, group_id). The description does not add extra meaning beyond the schema, so baseline score of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description explicitly states the verb ('list'), resource ('campaigns'), and specificity ('slim per-row campaign list for selection UIs'). It distinguishes from sibling `list_campaigns` by highlighting it's cheaper for large orgs, making the purpose unmistakable.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides clear context on when to use ('for selection UIs', 'Cheaper than list_campaigns for orgs with thousands of campaigns') and what to do after ('Use get_campaign(id) after a selection to fetch full details'), giving explicit usage guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_custom_rulesList Custom RulesA
Read-onlyIdempotent

Paginated list of the organization's custom tag-detection rules (regex / heuristics) with their config, target, and active flag. Returns {items, total, page, limit}. To iterate: there is a next page iff page * limit < total (or equivalently items.length === limit until the last page). page is 1-indexed. For rule_type='combo' the returned config may carry the rule-level key match_scope ("scan" = count conditions across the whole scan, "url" = every condition must be satisfied by tags on the same link). Resend it verbatim when updating: update_custom_rule replaces config wholesale, so dropping the key reverts the rule to whole-scan matching.

ParametersJSON Schema
NameRequiredDescriptionDefault
pageNo1-indexed page number.
limitNoPage size.

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already provide readOnlyHint, idempotentHint, destructiveHint. The description adds valuable context about pagination behavior (1-indexed page, limit default) and config field semantics for combo rules (match_scope). No contradiction.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences with no wasted words. Information is front-loaded: first sentence states purpose and return shape; second explains pagination and config nuance. Highly efficient.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite no output schema, the description mentions the return structure '{items, total, page, limit}'. It covers pagination, parameter defaults, and special behavior for combo rules. Given the simplicity of the tool and good annotations, this is fully complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so baseline is 3. The description doesn't repeat parameter details but adds contextual usage (page 1-indexed, limit default 50). This is adequate given the coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states 'Paginated list of the organization's custom tag-detection rules (regex / heuristics) with their config, target, and active flag.' This specific verb and resource, along with the inclusion of content, distinguishes it from sibling tools like get_custom_rule (single) and create/update/delete.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit pagination iteration logic ('there is a next page iff page * limit < total') and explains how to handle config for combo rules when updating. While it doesn't explicitly list when not to use this tool, the context is clear and helpful.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_custom_taxonomiesList Custom TaxonomiesA
Read-onlyIdempotent

List the calling org's custom classification taxonomies. Returns slim summaries (id, name, slug, version, node_count, is_active). Only active taxonomies are listed unless you pass include_inactive: true; soft-deleted ones then appear with is_active=false. Fetch the full tree via get_custom_taxonomy.

ParametersJSON Schema
NameRequiredDescriptionDefault
include_inactiveNoInclude soft-deleted taxonomies, which are excluded by default. Pass `true` to find one to `restore_custom_taxonomy`, or to resolve a taxonomy id seen on an older scan.

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover safety (readOnlyHint, idempotentHint, destructiveHint), so the description adds value by explaining filtering behavior (default active only, soft-deleted shown with `is_active=false`) and the slim summary format. It does not contradict annotations and provides useful context beyond what is structured.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three concise sentences with no fluff. The primary purpose is front-loaded, followed by return format and parameter behavior, all in a logical order. Every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description fully addresses the tool's simple purpose: it explains the return summaries, default filtering, the use of include_inactive, and points to the sibling for deeper data. Minor omissions like pagination or rate limits are negligible given the tool's simplicity and the annotations covering safety.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% since `include_inactive` has a descriptive schema entry explaining its effect. The description reinforces the parameter's purpose but does not add substantially new information beyond the schema, so the baseline of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action ('List') and the resource ('the calling org's custom classification taxonomies'), with specific details about what is returned. It distinguishes itself from sibling tool `get_custom_taxonomy` by noting that the full tree is fetched there, avoiding ambiguity.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides explicit guidance on when to use the tool and when to use the include_inactive parameter: to find soft-deleted taxonomies for restoration or to resolve IDs from older scans. It also instructs, 'Fetch the full tree via get_custom_taxonomy,' clearly routing agents to the appropriate alternative.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_emulatorsList EmulatorsA
Read-onlyIdempotent

List every device/OS emulator profile available for scans (id, display name, category, browser). For create_scan, use the id as emulator_id. For create_campaign / update_campaign, use the category in emulator_categories or the id in emulator_specific_ids.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.5/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, destructiveHint=false, idempotentHint=true. The description adds that it lists profiles 'available for scans' but doesn't disclose additional behavioral traits like caching, rate limits, or pagination. Adequate but no extra value beyond annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences: first states purpose, second gives usage guidance. No redundancy, no fluff. Efficiently structured.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a parameterless list tool with no output schema, the description fully covers what the tool does, what it returns, and how to use the results. No gaps.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Input schema has zero parameters with 100% coverage, so description doesn't need to explain params. It instead adds value by listing the fields returned (id, display name, category, browser), which helps agents understand the output structure.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description explicitly states it lists every device/OS emulator profile available for scans, with details on returned fields (id, display name, category, browser). This clearly distinguishes it from sibling tools like list_geos or list_scans.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides explicit guidance on how to use the output for other tools: 'For create_scan, use the id as emulator_id. For create_campaign / update_campaign, use the category in emulator_categories or the id in emulator_specific_ids.' This is exceptional context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_geosList GeosA
Read-onlyIdempotent

List every country the Kaminari Ad platform can scan ads from, with ISO 3166-1 alpha-2 code, name, continent, and emoji.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.1/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, destructiveHint. Description adds the specific fields returned but no additional behavioral traits (e.g., rate limits, pagination). Beyond annotations it provides useful context.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Single sentence under 20 words, front-loaded with action and scope. No unnecessary words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a no-parameter listing tool with no output schema, the description fully informs the agent of what to expect. Complete enough for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

No parameters; schema coverage 100%. Description adds value by specifying output fields (ISO code, name, continent, emoji), which is beyond the empty schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Clearly states it lists every country the platform can scan ads from, with specific fields (ISO code, name, continent, emoji). Differentiates from sibling tools as no other tool lists geos.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Does not explicitly state when to use vs alternatives, but implied usage is clear: when needing available geos for campaign targeting. No exclusions or alternatives given.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_invoicesList InvoicesA
Read-onlyIdempotent

List invoices issued to the organization with number, type, status, total in micros, currency, due/paid dates. Filter by type and / or status. Use get_invoice_pdf to download the PDF for a specific invoice.

ParametersJSON Schema
NameRequiredDescriptionDefault
pageNo1-indexed page.
typeNoFilter by invoice kind: proforma (advance bill) or final (issued after the period).
limitNoPage size.
statusNoFilter by lifecycle status.

TDQS

A4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, idempotentHint=true, destructiveHint=false, so the description does not need to restate safety. The description adds context about the returned fields and filtering, but no additional behavioral traits beyond annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences: first lists returned fields, second explains filtering and points to a related tool. Every sentence is necessary and concise with no fluff.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers the main purpose, filtering, and links to a related tool. No output schema is provided, but the description lists the fields returned. Lacks details on pagination or sorting, but these are implicit from the parameters.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and each parameter has a description. The description only mentions filtering by type and status, which is already covered in the schema. No additional semantics added beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states it lists invoices with specific fields (number, type, status, etc.), and mentions filtering by type and status. It distinguishes itself from the sibling get_invoice_pdf by directing users to that tool for PDF download.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly says to filter by type and/or status, and provides an alternative tool (get_invoice_pdf) for downloading PDFs. It does not specify when not to use, but provides clear context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_org_rolesList Organization RolesA
Read-onlyIdempotent

List the roles defined for the organization — built-in (owner, admin, member) plus any custom roles, with each role's permission set.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, and destructiveHint. The description adds that each role's permission set is returned, providing useful context beyond annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single, concise sentence that efficiently communicates the tool's function without extraneous information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite no output schema, the description explains what is returned (roles with permission sets). It is sufficiently complete given the tool's simplicity and the annotations covering safety.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has no parameters, so the description does not need to add parameter info. Schema coverage is 100%, and baseline is 4.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool lists organization roles (both built-in and custom) with their permission sets, distinguishing it from sibling tools like list_org_users or create_custom_role.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No explicit guidance on when to use this tool vs alternatives is provided. However, the description is straightforward and implies this is the tool for listing roles.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_org_usersList Organization MembersA
Read-onlyIdempotent

List every member of the caller's organization with their role, ownership flag, and join date.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already indicate read-only, idempotent, and non-destructive behavior. The description adds value by specifying the exact fields returned (role, ownership flag, join date), providing additional context beyond annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single concise sentence with no wasted words, directly conveying the tool's purpose and output fields.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple list tool with no parameters and no output schema, the description fully explains what the tool returns and its scope. No additional details are necessary for correct usage.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has no parameters, and the schema coverage is 100%. The description does not need to add parameter info, meeting the baseline of 4 for zero-parameter tools.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool lists every organization member with specific details (role, ownership flag, join date). It distinguishes itself from sibling tools like invite_user or remove_user by explicitly describing its scope and output.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage for retrieving full member lists but does not provide explicit guidance on when to use this tool versus alternatives like list_org_roles. However, it is clear enough for the intended use case.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_policy_set_campaignsList Policy Set CampaignsA
Read-onlyIdempotent

List the campaigns bound to a policy set, paginated, each with id, name and is_archived. get_policy_set returns only the first page of bindings plus a campaigns_total, so use this tool when a set has more campaigns than that page holds, or to search them by name. Read the membership here before detach_policy_set_campaigns — and before delete_policy_set, which the API refuses while any active campaign is still bound.

ParametersJSON Schema
NameRequiredDescriptionDefault
qNoSubstring search against campaign name (case-insensitive).
pageNo1-indexed page number.
limitNoPage size (1-200).
policy_set_idYesPolicy set UUID.

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the description does not need to repeat safety traits. It adds the pagination behavior and the output fields (id, name, is_archived). It also discloses a useful boundary: get_policy_set only returns the first page, which sets expectations for pagination. While it doesn't mention rate limits or performance, the pagination detail and the deletion constraint fill the transparency gap beyond annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, zero waste. The core function is front-loaded, followed by the pagination limitation and two crucial ordering hints (read before detach/delete). Every clause earns its place, and the structure is immediately scannable.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

As a list tool with no output schema, the description explains what is returned (id, name, is_archived) and that it is paginated. It also covers the gap in get_policy_set and warns about delete_policy_set, which is essential for an agent making safe decisions. There are no missing details needed to call this tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and each parameter has a clear description (e.g., q for substring search, page/limit for pagination). The description's mention of 'search them by name' essentially repeats what the q parameter schema already says, adding no new meaning. With full schema coverage, the baseline is 3; the description does not lower or raise it.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States exactly what it does: 'List the campaigns bound to a policy set, paginated, each with id, name and is_archived.' The verb ('List') and resource ('campaigns bound to a policy set') are specific, and it explicitly differentiates itself from get_policy_set by noting that the latter returns only the first page. An agent can immediately know what this tool provides and how it differs from siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides explicit when-to-use guidance: 'use this tool when a set has more campaigns than that page holds, or to search them by name.' It also advises to read the membership here before detach_policy_set_campaigns and delete_policy_set, which is actionable and prevents failed operations. This leaves no ambiguity about when to choose this tool over alternatives like get_policy_set.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_policy_setsList Policy SetsA
Read-onlyIdempotent

Paginated list of policy sets: named collections of violation rules (tag / IAB V3 / brand / AI category / custom-taxonomy entries) that define what counts as a violation. Campaigns bind to one policy set. Returns {items, total, page, limit}. List items omit entries for payload size — fetch a single set via get_policy_set when you need them. is_default is true on the owned set that new campaigns bind when policy_set_id is omitted. Use visibility=public to discover Kaminari Ad-curated sets.

ParametersJSON Schema
NameRequiredDescriptionDefault
pageNo1-indexed page number.
limitNoPage size.
visibilityNoNarrow to one scope. `private` = org-owned only, `public` = Kaminari Ad-curated sets visible to every org. Omit the filter to see BOTH combined.

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, and destructiveHint, so safety is covered; the description adds behavior beyond those hints. It discloses pagination behavior, the exact return shape (`{items, total, page, limit}`), the payload-size omission of `entries`, and the semantics of `is_default`. This gives the agent a clear model of what the call returns and how to interpret results.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact and front-loaded with the core purpose, then efficiently adds the most decision-relevant behavior: return shape, omitted entries, default-set behavior, and public visibility use. Every sentence provides useful information without redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given no output schema, the description compensates well by stating the return shape and the key behavioral caveat (`entries` omitted). It also provides enough context for the tool's role in the policy-set lifecycle and covers the practical use of the `visibility` filter. The tool is a simple paginated list, and the description fully covers the information an agent needs to invoke and interpret it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so page, limit, and visibility are already documented. The description adds value by explaining that `visibility=public` is specifically for discovering Kaminari Ad-curated sets, which goes beyond the raw enum. Page and limit are adequately covered by the schema, so the description doesn't need to restate them.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource ('Paginated list of policy sets') and provides a clear definition of what a policy set is. It distinguishes itself from the sibling `get_policy_set` by noting that list items omit `entries` and that individual sets should be fetched separately when details are needed.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives actionable guidance: use `get_policy_set` when entries are needed, and use `visibility=public` to discover curated sets. It also explains the meaning of `is_default` and its relationship to campaign binding, helping agents decide when to use this tool over related policy set operations.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_run_scansList Run ScansA
Read-onlyIdempotent

List the tile-scan items produced by one run (status, country, offer URL, absolute screenshot URL, report_url + public_report_url deep-links, elapsed ms, error). Link users to a scan with the returned report_url (auth dashboard) or public_report_url (shareable) — never hand-build URLs. For full scan details (input URL, labels, classification, redirect chain) fetch a specific scan via get_scan.

ParametersJSON Schema
NameRequiredDescriptionDefault
pageNo1-indexed page.
limitNoPage size.
run_idYesRun UUID.

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description aligns with annotations (readOnlyHint, destructiveHint, idempotentHint) and adds behavioral context about the returned data fields, including how to use report_url vs public_report_url. No contradictions.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two concise sentences that front-load the core purpose. Every sentence adds value: first lists what the tool returns, second provides usage guidance and references a sibling tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a list tool with no output schema, the description adequately details the returned fields and provides enough context for an agent to select and invoke the tool correctly, including references to deeper functionality via get_scan.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% (all parameters described in schema). The description adds value beyond schema by explaining the output fields and their purpose, which indirectly clarifies the parameters' role, but the schema already covers parameter details adequately.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb ('list') and resource ('tile-scan items produced by one run'), and distinguishes from siblings like get_scan and list_scans by specifying the scope ('produced by one run').

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly tells when to use this tool (to list scans for a run) and provides a clear alternative for detailed scan information ('fetch a specific scan via get_scan'). It also gives guidance on using returned URLs ('never hand-build URLs').

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_scan_childrenList Scan ChildrenA
Read-onlyIdempotent

List the discovered-ad child scans of a publisher ad-discovery scan — 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 — 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 — 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.

ParametersJSON Schema
NameRequiredDescriptionDefault
pageNo1-indexed page number.
limitNoPage size (1-200). Default 50.
scan_idYesThe publisher scan's UUID (an ad-discovery scan created with ad_discovery=true).

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark the operation as read-only and idempotent, and the description goes well beyond that by explaining the meaning of child briefs, the attribution split, when fields are empty, and why repeat/retry fields are always meaningless at the child level. It also discloses the paginated envelope and warns against constructing URLs manually — valuable operational behavior not encoded anywhere else.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is lengthy but every sentence carries meaning: purpose, field semantics, edge-case behavior, repeat-field caveats, and return-envelope guidance. It is front-loaded with the core purpose and structured so related details are grouped logically. No filler or redundant restatement of the title.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description shoulders the burden of explaining what the response contains, and it does so thoroughly: child brief fields, the network fallback rule, empty-value cases, repeat/retry semantics, pagination, and deep-link usage. For a read-only list endpoint with a fully documented input schema, nothing essential is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema already documents all three parameters, including the meaning of scan_id as the publisher ad-discovery scan's UUID. The description reinforces the scan_id context but does not add new parameter-level detail beyond what the schema provides. With 100% schema coverage, baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb and resource: 'List the discovered-ad child scans of a publisher ad-discovery scan.' It immediately clarifies the unit of output ('one per detected ad block on the page') and distinguishes this from publisher-level scans, so an agent understands exactly what the tool returns.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear context: this is for the children of an ad-discovery scan, one per ad block, and explains how the data is scoped. It also provides actionable guidance like reading network before network_host and using returned deep-links instead of hand-building URLs. It stops short of explicitly naming sibling alternatives or saying when not to use this tool, but the context is unambiguous.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_scansList ScansA
Read-onlyIdempotent

List scans for the caller's organization with optional filters (status, country, URL substring, date range, run/campaign/group, tag, AI/IAB/brand category, dynamic labels). Returns a paginated envelope; each brief carries is_ad_tag and is_vast flags, an absolute screenshot URL plus report_url (auth dashboard) and public_report_url (shareable) deep-links — link users with those, never hand-build URLs. Repeated scans look like near-duplicate rows: repeat_index / repeat_total place each one inside its repeat group (0-based) and a non-null repeat_session_id means the group ran in shared mode (one browser, one IP, cookies carried across repeats) — group by it to compare the repeats of one combination. retry_attempt / retry_max_attempts count technical re-crawls of that same scan, not extra scans. repeat_scan_ids is not part of this response; use get_scan for a single scan's full detail.

ParametersJSON Schema
NameRequiredDescriptionDefault
tagNoComma-separated tag slugs to filter by.
urlNoSubstring match against the scanned URL.
pageNo1-indexed page number.
brandNoFilter by detected advertiser brand (case-insensitive).
limitNoPage size (1-200). Default 50.
labelsNoDynamic label filters as a flat object: { brand_safety: 'high', vertical: 'gambling' }. Keys are snake_case and must exist in the org's label catalogue. Each key becomes a `label_<key>=<value>` query param. See `list_account_labels`.
run_idNoFilter to scans of one run.
statusNoComma-separated statuses to filter by. Lifecycle values: pending, running, crawled, checking, checking_async, rechecking, completed, partial, failed, cancelled.
date_toNoISO date (YYYY-MM-DD), inclusive upper bound on scan creation.
scan_idNoComma-separated scan UUIDs to fetch a specific set.
group_idNoFilter to scans of one campaign group.
timezoneNoIANA timezone (e.g. 'Europe/Berlin') applied to date_from / date_to. Defaults to UTC.
date_fromNoISO date (YYYY-MM-DD), inclusive lower bound on scan creation.
tag_matchNoHow multiple `tag` slugs combine: `any` (default) returns scans carrying at least one, `all` requires every one of them.
ai_categoryNoFilter by the freeform LLM-generated category prefix on the scan (slash-separated tier path, e.g. 'Gambling/Online Casinos').
campaign_idNoFilter to scans of one campaign.
country_codeNoComma-separated ISO 3166-1 alpha-2 country codes, e.g. US,DE,JP.
iab_categoryNoFilter by legacy IAB V2.2 category (only present on pre-P3 scans).
parent_scan_idNoFilter to the ad-discovery child scans of one parent scan. Setting this lifts the default 7-day window, so old children stay reachable. `list_scan_children` is the paginated equivalent.
iab_v3_categoryNoFilter by canonical IAB Content Taxonomy V3 prefix (slash-separated tier path).

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, and destructiveHint, but the description goes far beyond that. It reveals the paginated envelope, the `is_ad_tag`/`is_vast` flags, the different URL types (screenshot, report_url, public_report_url) and instructs to use those links rather than build URLs. It also explains the nuance of repeated scans (`repeat_index`, `repeat_total`, `repeat_session_id`) and retries (`retry_attempt`, `retry_max_attempts`), which are non-obvious behaviors that would otherwise be hidden. This is rich context that materially helps the agent interpret results.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but every sentence carries load-bearing information. It fronts the purpose and filters, then moves to response structure and edge cases, and closes with pointers to siblings. There is no filler or redundancy; the structure is logical and the density is justified by the tool's complexity (20 params, no output schema).

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with 20 parameters, no output schema, and significant response nuances, the description covers everything an agent needs to call it correctly and interpret results: pagination, flags, URLs, repeat/retry logic, and links to sibling tools. It also flags what is NOT included (repeat_scan_ids) to prevent assumptions. Nothing essential is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so each parameter already has a description. The description adds meaningful semantics beyond that: it explains how `labels` object maps to query params, how `tag_match` controls tag combination, and that `parent_scan_id` lifts the 7-day window. It also clarifies that `repeat_scan_ids` is not in this response and points to `get_scan` for that. This goes beyond a baseline of 3 by clarifying interactions and scope of filters.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('List') with a clear resource ('scans for the caller's organization') and enumerates the optional filters. It explicitly distinguishes itself from sibling tools by pointing to `get_scan` for single-scan detail and `list_scan_children` as a paginated equivalent, so an agent can immediately tell them apart.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implicitly defines when to use this tool (listing scans with filters) and explicitly routes to alternatives: 'use `get_scan` for a single scan's full detail' and notes `list_scan_children` as the paginated equivalent for child scans. It also clarifies the parent_scan_id behavior and the default 7-day window, giving concrete guidance on when to switch.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_scan_tagsList Scan TagsA
Read-onlyIdempotent

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 — the scan can therefore report fewer tags than when it ran.

ParametersJSON Schema
NameRequiredDescriptionDefault
scan_idYesScan UUID.

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already provide readOnly, idempotent, and non-destructive hints. The description adds valuable non-obvious behavior: archived tag definitions are omitted, so the current tag list may differ from what was reported at scan time. This goes beyond the annotations and helps set expectations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two tightly written sentences earn their place. The primary purpose is front-loaded, and the archival caveat is succinctly appended without redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a low-complexity tool with a single parameter, no output schema, and informative annotations, the description is complete. It states what is returned (tags, display name, category, severity) and the important omissive behavior, leaving no significant gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%: scan_id is documented as 'Scan UUID.' The description does not add further parameter detail, but the schema already carries the semantic weight. Baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('List') and resource ('tag (system + custom) attached to one scan'), and clarifies scope ('every tag', 'by the checker pipeline'). It clearly distinguishes from sibling tools like list_tags by focusing on tags attached to a particular scan.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Clear context is given: this tool lists tags for a single scan. While it doesn't explicitly name alternatives or exclusion cases, the phrase 'one scan' makes the intended use unambiguous, and the sibling list_tags is implicitly differentiated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_tagsList TagsA
Read-onlyIdempotent

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
categoryNoFilter to tags in one category slug (e.g. 'security', 'malware', 'compliance'). Use the slug exactly as it appears in `category` of an existing tag.
include_archivedNoAlso 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 — so this flag cannot resolve a slug seen on an older scan.

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark the call read-only, idempotent, and non-destructive. The description adds valuable behavioral detail: archived tags are retired (no longer assigned/alerts), archived platform system tags are never returned, and include_archived cannot resolve old scan slugs. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences with no filler. The main operation and output scope are front-loaded, followed by the optional parameters and the key archived-behavior caveat. Every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only list operation with no output schema, the description covers what is returned, the organization scope, optional filters, and the non-obvious archived-tag semantics. An agent has enough information to invoke it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%; both parameters already have rich descriptions. The description only restates the intended filter behavior without adding new semantic detail beyond the schema, so baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('List'), a concrete resource ('every tag definition in service for this organization'), and the contents (system + organization custom tags). It is clearly distinct from sibling get_tag_definition/list_scan_tags by promising the full set rather than a single tag or per-scan association.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives clear usage context: optional category filtering and include_archived to include retired org-owned definitions, with a caveat about archived system tags. It does not explicitly name alternatives or say when not to use this tool, but the 'every' scope and optional filters make the intended use clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_usageList UsageA
Read-onlyIdempotent

List per-scan usage rows (cost in micros, kind, scan id, timestamp). Use to attribute cost to specific scans or campaigns.

ParametersJSON Schema
NameRequiredDescriptionDefault
pageNo1-indexed page.
limitNoPage size.
date_toNoISO 8601 datetime (with offset), inclusive upper bound.
scan_idNoFilter to one scan's cost rows.
date_fromNoISO 8601 datetime (with timezone offset), inclusive lower bound on the usage timestamp. Plain dates also work — the API normalises to UTC midnight.

TDQS

A4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already indicate read-only, idempotent, non-destructive behavior. Description adds return field names but not significant behavioral context beyond that.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two concise sentences: first states function, second states purpose. No redundancy or fluff.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Lists returned fields in lie of an output schema, providing clarity. Lacks explicit mention of pagination, but pagination is implied by parameters. Adequate for the tool's simplicity.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema covers all 5 parameters with descriptions (100% coverage). Description does not add parameter meaning beyond the schema, so baseline score applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Clearly states the tool lists per-scan usage rows with specific fields (cost, kind, scan id, timestamp) and links it to cost attribution. Differentiates from sibling get_usage_summary by granularity.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states use case for attributing cost to scans or campaigns. While it does not list alternatives, the presence of get_usage_summary among siblings implies the distinction, providing adequate implicit guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_webhook_deliveriesList Webhook DeliveriesA
Read-onlyIdempotent

List delivery attempts for one webhook endpoint with event type, status (pending / delivered / failed), HTTP response status if any, and attempt timestamp. Filter by success and / or a from_ts / to_ts range. Paginated.

ParametersJSON Schema
NameRequiredDescriptionDefault
pageNo1-indexed page.
limitNoPage size.
to_tsNoISO 8601 datetime (with offset), inclusive upper bound.
from_tsNoISO 8601 datetime (with offset), inclusive lower bound on attempt time.
successNoFilter to delivered (true) or failed (false) attempts only.
webhook_idYesWebhook endpoint UUID.

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark it as readOnlyHint and idempotentHint. The description adds that results include event type, status, HTTP response, and timestamp, and shows filtering and pagination behavior. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences with no redundancy: first sentence states what is listed, second covers filters and pagination. Every part earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Covers main purpose, returned fields, filters, and pagination. Lacks details on pagination mechanism and sorting, but given no output schema and simple parameters, it is adequate.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the description does not add new parameter meaning beyond what the schema provides. It reiterates filters and pagination but does not expand on format or constraints.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states 'List delivery attempts for one webhook endpoint' and enumerates fields returned (event type, status, HTTP response, timestamp). Among siblings like list_webhooks and list_webhook_event_types, this tool is distinct.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description mentions filtering by success and date range, and pagination, which implies typical listing usage. It does not explicitly state when not to use or alternatives, but is clear enough for a list tool.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_webhook_event_typesList Webhook Event TypesA
Read-onlyIdempotent

List the catalog of event types a webhook can subscribe to (e.g. scan.done, alert.opened, campaign.run.completed) with each event's description and a sample payload.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already indicate readOnlyHint=true and destructiveHint=false. The description adds useful context about what the tool returns (event types, descriptions, sample payload) beyond the annotation hints.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single sentence that includes examples and specifies the output contents, with no wasted words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given no output schema, the description adequately explains the return value (event types with descriptions and sample payload). For a simple list tool with zero parameters, this is complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

There are no parameters, and schema coverage is 100%. The description does not need to add parameter meaning; the baseline for zero parameters is 4.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states it lists the catalog of event types a webhook can subscribe to, with concrete examples like `scan.done` and mentions each event's description and sample payload. This distinguishes it from sibling tools that manage webhooks or other entities.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies the tool is for discovering event types before creating a webhook, but does not explicitly state when to use it versus alternatives or provide exclusion criteria.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_webhooksList WebhooksA
Read-onlyIdempotent

List the organization's registered webhook endpoints with their URL, subscribed event types, and active flag.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations provide readOnlyHint=true, idempotentHint=true, destructiveHint=false, which already indicate safety. The description adds context about the specific fields returned, and there is no contradiction.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Single sentence, front-loaded with action and resource, concise and efficient.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple list-all tool with no output schema, the description fully informs about what is returned, making it complete for agent selection.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Input schema has zero parameters, so schema coverage is 100% trivially. Description adds no parameter info, but baseline for 0 params is 4 as per calibration.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action (list), the resource (webhook endpoints), and specifies the returned fields (URL, event types, active flag). It distinguishes well from sibling tools like create_webhook, delete_webhook, get_webhook, and list_webhook_event_types.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description does not provide any guidance on when to use this tool versus alternatives like get_webhook for a specific endpoint, nor does it mention exclusions or context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

parse_custom_taxonomy_textParse Custom Taxonomy TextA
Read-onlyIdempotent

Preview-parse pasted free-form text into a taxonomy tree (NOT persisted). Returns nodes: [{level, name, description}] + warnings: string[]. After review, persist via create_custom_taxonomy (remember to flag exactly one node as is_default).

ParametersJSON Schema
NameRequiredDescriptionDefault
textYesFree-form text describing the tree (one node per line; indentation expresses depth). Up to 50 000 chars.

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description aligns with annotations (readOnlyHint: true, destructiveHint: false) and adds that the parsing is not persisted, returning nodes and warnings. This gives full behavioral context beyond annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences cover purpose, behavior, return type, and follow-up action. No redundant information; every sentence adds value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite no output schema, the description specifies the return format (nodes with level/name/description, warnings). Combined with annotations and simple one-parameter schema, the description is complete and actionable.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% with a detailed description of the 'text' parameter (format, constraints). The description adds no additional parameter semantics, so the baseline score of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action ('Preview-parse'), the resource ('pasted free-form text'), and the result ('into a taxonomy tree'). It explicitly notes that the result is NOT persisted, distinguishing it from the sibling 'create_custom_taxonomy' tool.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit usage guidance: use this tool for previewing, then persist via 'create_custom_taxonomy' with a reminder to set one node as is_default. This clearly separates when to use this tool versus alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

pause_campaign_group_schedulePause Group ScheduleA
Idempotent

Pause the scheduler for EVERY campaign in the group. Already-pending scans complete; no new scheduled runs are produced until you resume_campaign_group_schedule.

ParametersJSON Schema
NameRequiredDescriptionDefault
group_idYesCampaign group UUID.

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Adds value beyond annotations: explains that pending scans complete and no new runs are produced until resume. Annotations already indicate idempotentHint=true and destructiveHint=false, which the description aligns with.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, both essential and front-loaded. The first sentence clearly states the action, and the second adds important behavioral context. No unnecessary words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Completely covers the tool's behavior for a single-parameter, no-output-schema tool. Includes side effects (pending scans complete, no new runs until resume) and does not miss any critical information given the available annotations.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the schema already describes the parameter as 'Campaign group UUID.' The description does not add additional meaning or context for the parameter beyond what is in the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Explicitly states the action: 'Pause the scheduler for EVERY campaign in the group.' Clearly distinguishes from siblings by specifying scope (every campaign in the group) and complementary action (resume).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides clear context for when to use (to pause scheduling) and explicitly mentions the complementary tool `resume_campaign_group_schedule`. Does not explicitly list when not to use, but the distinction from cancel/archive is implied by the behavior described.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

recheck_scansRecheck ScansA

Re-run the checker pipeline against recent COMPLETED scans (e.g. after updating policies or custom rules). Returns the number of scans queued for re-evaluation. No new crawl fee — only the checker cost.

ParametersJSON Schema
NameRequiredDescriptionDefault
scope_typeYesSelection mode. `last_n` = most recent N scans; `hours` = scans from the past N hours.
scope_valueYesNumber of scans (`last_n`, max 5000) OR number of hours (`hours`, max 72). API enforces tighter caps per mode.

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations are sparse but description adds: no new crawl fee, only checker cost; returns count of queued scans. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two efficient sentences, first explains function, second adds cost detail. No superfluous text.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given simple parameters and no output schema, description adequately explains return value (count) and scope (completed scans). Sufficient for agent usage.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema covers parameters fully (100%). Description adds important constraint that only completed scans are eligible, which is not in schema. Also clarifies cost context.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description clearly states the tool re-runs the checker pipeline on completed scans, which is distinct from creating new scans. It gives specific use cases like after policy updates, and mentions cost implications.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says when to use (after updating policies or custom rules). Does not explicitly mention when not to use, but context implies it's for re-evaluation only, not new scans.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

remove_userRemove UserA
DestructiveIdempotent

Revoke a member's access to the organization. The user is signed out and any active API keys they created remain unless revoked separately. CANNOT remove the owner — use transfer_ownership first.

ParametersJSON Schema
NameRequiredDescriptionDefault
user_idYesUUID of the member to remove.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description adds significant behavioral context beyond annotations, such as that the user is signed out, active API keys remain, and the owner cannot be removed. This complements the annotations (destructiveHint=true, idempotentHint=true) without contradiction.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise, consisting of two sentences that immediately convey the primary function key constraints. Every sentence adds necessary information, and the structure is front-loaded with the core action.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the absence of an output schema, the description covers the main effects (sign out, key retention, owner restriction). However, it does not specify what the return value indicates or error handling for invalid user IDs. For a simple one-parameter destructive tool, this is nearly complete but lacks success/failure clarification.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 100% schema coverage, the description does not add substantial meaning beyond the parameter's schema description ('UUID of the member to remove'). The tool description implies the user_id is the member, but no additional format or usage details are provided beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool revokes a member's access ('Revoke a member's access to the organization'), uses a specific verb and resource, and distinguishes itself from siblings by noting that it cannot remove the owner (directing to transfer_ownership) and mentioning API key handling (differentiating from revoke_api_key).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit guidance on when to use the tool (to revoke member access), when not to use it (cannot remove owner), and an alternative action (use transfer_ownership first). It also notes that API keys persist unless separately revoked, aiding in decision-making.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

replay_webhook_deliveryReplay Webhook DeliveryA

Queue a re-attempt for one specific webhook-delivery attempt by id. Useful when an endpoint was temporarily down. Result of the replay shows up as a new entry in list_webhook_deliveries.

ParametersJSON Schema
NameRequiredDescriptionDefault
attempt_idYesDelivery-attempt UUID (from `list_webhook_deliveries`).

TDQS

A4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations indicate mutation (readOnlyHint=false) but not destructive or idempotent. The description adds the outcome (new entry in list), but does not disclose whether the operation is synchronous or asynchronous, or any required permissions. With annotations covering basic safety, this is adequate but minimal.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two efficient sentences: first states action, second gives use case, third explains outcome. No redundant words or fluff. Information is front-loaded and well-structured.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple tool with one parameter and no output schema, the description covers purpose, use case, and outcome. It does not mention possible errors, rate limits, or async behavior, but these are not critical for basic selection and invocation given annotations.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% for the single parameter attempt_id. The description adds 'from list_webhook_deliveries' which provides source context beyond the schema's UUID format. This is helpful but not substantial.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action (Queue a re-attempt) and the resource (one specific webhook-delivery attempt by id). It distinguishes from siblings like bulk_replay_webhook by specifying 'one specific.' The output behavior is explained (result appears as new entry in list_webhook_deliveries).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives a clear use case ('when an endpoint was temporarily down') but does not explicitly state when not to use or compare to alternatives like bulk_replay_webhook. The context is sufficient for an agent to decide in common scenarios.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

request_policy_set_approvalRequest Policy Set ApprovalA

Submit a private policy set for Kaminari Ad team review so it can be marked PUBLIC and used by other organizations. The set must be complete and well-formed. Returns immediately; approval status is reflected on the policy set entity once the review completes.

ParametersJSON Schema
NameRequiredDescriptionDefault
policy_set_idYesPolicy set UUID.

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description discloses that the tool returns immediately and that the approval status is reflected asynchronously on the policy set entity. This adds behavioral context beyond the annotations, which only indicate non-read-only, non-destructive, non-idempotent behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is extremely concise with two sentences covering purpose, precondition, and behavior. Every sentence adds value, and the most critical information is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the single parameter and no output schema, the description sufficiently explains the tool's purpose, the prerequisite, and the asynchronous behavior. It provides all necessary context for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 100% schema description coverage, the schema already documents the policy_set_id parameter as a UUID. The description adds no additional meaning or context for this parameter, so it does not exceed the baseline of 3.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action ('submit'), the resource ('private policy set'), and the purpose ('...so it can be marked PUBLIC and used by other organizations'). It effectively distinguishes itself from sibling tools like create_policy_set and update_policy_set by specifying the review process.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides a clear precondition ('the set must be complete and well-formed') and implies the tool is for making a policy set public. However, it does not explicitly state when not to use it or list alternative tools, which would have earned a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

restore_custom_taxonomyRestore Custom TaxonomyA
Idempotent

Re-activate a previously soft-deleted custom taxonomy. Returns the restored taxonomy with its full tree (is_active=true).

ParametersJSON Schema
NameRequiredDescriptionDefault
taxonomy_idYesCustom taxonomy UUID (must currently be is_active=false).

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Discloses that the restored taxonomy includes its full tree and becomes active (is_active=true). Annotations already declare idempotent and non-destructive; description adds return context without contradiction.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Single sentence that is front-loaded with action and result, no redundant words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Covers the essential action and return value. Lacks mention of error cases (e.g., taxonomy not found or already active), but sufficient for a simple one-parameter operation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% with a clear description of taxonomy_id requiring is_active=false. Description adds no extra semantic information beyond what the schema already provides.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Clearly states 're-activate' a soft-deleted custom taxonomy, distinguishing it from sibling tools like delete_custom_taxonomy and update_custom_taxonomy.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Implies use when a taxonomy is soft-deleted (is_active=false), but does not explicitly state when not to use or mention alternatives like update_custom_taxonomy.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

resume_campaign_group_scheduleResume Group ScheduleA
Idempotent

Re-enable the scheduler for every campaign in the group. Inverse of pause_campaign_group_schedule.

ParametersJSON Schema
NameRequiredDescriptionDefault
group_idYesCampaign group UUID.

TDQS

A4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare idempotentHint=true (safe to call multiple times), readOnlyHint=false, destructiveHint=false. Description adds that it affects every campaign in the group, which is useful but doesn't add significant behavioral detail beyond annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Single sentence with clear action and inverse reference. No unnecessary words, front-loaded with the core purpose.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple toggle tool with one parameter and no output schema, the description covers the essential purpose and scope. Lacks error conditions or side effects, but is sufficient given the low complexity.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Only one parameter (group_id) with schema description 'Campaign group UUID.'. Description does not add extra semantics beyond what the input schema provides, so baseline score of 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Clearly states the action 're-enable the scheduler' and scope 'for every campaign in the group'. Also explicitly references the inverse tool 'pause_campaign_group_schedule', differentiating it from siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Indicates it is the inverse of pause_campaign_group_schedule, implying it should be used after a pause. Does not explicitly state when not to use it, but the context is straightforward for a toggle action.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

revoke_api_keyRevoke API KeyA
DestructiveIdempotent

Permanently invalidate an API key. Any subsequent request using it returns 401. Cannot be undone — the user would have to create_api_key again.

ParametersJSON Schema
NameRequiredDescriptionDefault
key_idYesUUID of the key to revoke (from `list_api_keys`).

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond annotations (destructiveHint=true), the description adds that subsequent requests return 401 and that the action cannot be undone, providing critical behavioral context.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two concise sentences with front-loaded action and effect; every word contributes to understanding.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple 1-parameter destructive tool with no output schema, the description covers the operation, irreversibility, and consequence fully.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, with a clear description for key_id. The description does not add parameter semantics beyond the schema, meeting the baseline.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb ('revoke') and clearly states it permanently invalidates an API key, distinguishing it from sibling tools like create_api_key.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly states the permanent nature and points to create_api_key as an alternative for regeneration, though it lacks explicit 'when not to use' guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

rotate_webhook_secretRotate Webhook SecretA
Destructive

Generate a new signing secret for a webhook. The new secret is returned IN FULL once — tell the user to store it. Subsequent deliveries are signed with the new secret; the old one stops working immediately.

ParametersJSON Schema
NameRequiredDescriptionDefault
webhook_idYesWebhook endpoint UUID.

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description adds critical behavioral details beyond annotations: the new secret is returned in full only once, and the old secret stops working immediately. While annotations already set destructiveHint=true, the description provides the specific consequences.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is three sentences, front-loaded with the core action, followed by critical warnings. Every sentence adds value with no redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool has one parameter, no output schema, and annotations provide safety hints, the description fully covers the purpose, the one-time secret retrieval, and the immediate invalidation of the old secret. It is complete for an agent to understand behavior and consequences.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% with the parameter 'webhook_id' fully described as 'Webhook endpoint UUID'. The description does not add any additional meaning or usage guidance for this parameter, so baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb 'Generate' and explicitly states the resource 'signing secret for a webhook'. It distinguishes itself from sibling tools like 'update_webhook' or 'test_webhook' by focusing on secret rotation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies when to use (to rotate a secret) but does not explicitly state when not to use or provide alternatives. The warning to store the secret provides some guidance, but exclusions are missing.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

run_campaignRun Campaign NowA

Trigger an immediate, ad-hoc run of a campaign. Costs N credits where N = number of countries × number of emulators in the campaign config. Returns the new run with progress counters (total / completed / failed / partial / cancelled); track further progress via get_run.

ParametersJSON Schema
NameRequiredDescriptionDefault
campaign_idYesCampaign UUID to run now.

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description adds cost calculation detail and return format beyond annotations. Annotations already indicate non-readOnly and non-destructive; description clarifies the action's effects and cost. No contradictions.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two sentences, front-loading purpose and then providing key behavioral details. Every sentence adds value with no redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite lacking an output schema, the description explicitly states what the tool returns (progress counters) and suggests how to track further progress. It also covers cost, making it complete for a simple tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 100% schema coverage for the single parameter (campaign_id), the description does not add additional meaning beyond the schema's description. Baseline score of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action ('Trigger an immediate, ad-hoc run') and the resource ('a campaign'). It distinguishes from siblings like 'run_campaign_group' and 'cancel_run' by specifying it's for a single campaign and ad-hoc.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides cost implications and how to track progress via 'get_run'. It hints at the use case (ad-hoc) but does not explicitly state when not to use or compare with alternatives like schedule-based runs.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

run_campaign_groupRun Campaign GroupA

Fire an immediate run of every active (non-archived, non-paused) campaign in the group. Returns aggregate stats: how many campaigns triggered, the per-campaign run UUIDs, and any per-campaign failures.

ParametersJSON Schema
NameRequiredDescriptionDefault
group_idYesCampaign group UUID.

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations are sparse (readOnlyHint=false, destructiveHint=false). The description adds value by stating it triggers a run and returns aggregate stats including failures. However, it does not disclose potential side effects like rate limits, idempotency, or behavior when campaigns are already running.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two sentences, front-loads the core action, and provides return value details without unnecessary words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple tool with one parameter and no output schema, the description covers the key aspects: what triggers, scope ('active campaigns'), and return type (aggregate stats). It lacks error condition details but is sufficient for the complexity.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The only parameter, group_id, is fully described in the schema as 'Campaign group UUID.' The description does not add further meaning beyond the schema. With 100% schema coverage, baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action 'Fire an immediate run' and specifies the resource 'every active campaign in the group'. It distinguishes from sibling tools like run_campaign (single campaign) and cancel_campaign_group (cancellation).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies when to use (to run all active campaigns in a group immediately) but does not explicitly mention when not to use or provide alternatives. The context of siblings like run_campaign suggests a comparison, but no direct guidance is given.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

set_alert_destination_versionSet Destination VersionA
Idempotent

Switch a destination to a specific versioned config — used after re-authorizing a Slack workspace, rotating a Telegram bot token, etc. The new version must already exist in the destination's history. The API returns no body on success; this tool reports { updated: true }. Use list_alert_destinations to read the new state if needed.

ParametersJSON Schema
NameRequiredDescriptionDefault
versionYesWhich version of the scan-report link to embed in alert messages: `public` (anonymous, no auth) or `internal` (requires UI login).
destination_idYesDestination UUID.

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations indicate idempotent and non-destructive. The description adds that the API returns no body and the tool reports { updated: true }, and that the new version must exist. This provides useful behavioral details beyond annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences efficiently convey purpose, prerequisites, and return behavior. No redundant information, and key points are front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a two-parameter mutation tool with good annotations and no output schema, the description covers behavior, preconditions, return value, and suggests reading state. It is fully adequate.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema covers 100% of parameters with descriptions. The description adds the critical constraint that the version must already exist in the destination's history, which is not in the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool switches a destination to a versioned config, with specific examples (Slack re-authorization, Telegram token rotation). It distinguishes from siblings by focusing on version switching, which is not covered by other tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explains when to use the tool (after reauthorizing or rotating tokens) and notes the prerequisite that the version must exist. It doesn't explicitly exclude other scenarios or name alternatives, but the context signals are clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

set_campaign_alert_overridesSet Campaign Alert OverridesA
Idempotent

REPLACE the per-campaign alert-routing override. mode=inherit drops the override so the campaign follows the org-wide destinations; mode=override routes its alerts ONLY to destination_ids; mode=silence sends nothing for the campaign. There is no 'route everywhere except these' mode — to exclude one destination, pass override with the destinations you DO want (see list_alert_destinations). To read the new state, follow up with get_campaign_alert_overrides.

ParametersJSON Schema
NameRequiredDescriptionDefault
modeYesRouting mode: `inherit` (fall back to the org-wide destinations), `override` (route ONLY to `destination_ids`), `silence` (send nothing for this campaign).
campaign_idYesCampaign UUID.
destination_idsNoDestination UUIDs to route to. Accepted ONLY with `mode: override` — the API rejects it for `inherit`/`silence`. An empty list with `override` routes nowhere, which is the same outcome as `silence`.

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark the tool as idempotent (idempotentHint=true) and not read-only (readOnlyHint=false). The description adds substantial behavioral detail beyond annotations: it defines what each mode does (e.g., `inherit` drops the override, `silence` sends nothing), clarifies that `destination_ids` is only accepted with `override`, and notes the edge case where an empty list with `override` routes nowhere (same as `silence`). This level of behavioral disclosure exceeds what annotations supply and prevents misuse.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact yet information-dense. It front-loads the core action ('REPLACE'), then organizes the three modes in a logical sequence, and concludes with a caveat and a read-back instruction. Every sentence serves a purpose, and there is no redundancy or filler. The structure (action, modes, exclusions, follow-up) aids comprehension.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite having no output schema, the description tells the agent how to verify the result (call get_campaign_alert_overrides). It also covers the full semantic space of the tool's behavior, including what happens with each mode and the interaction of parameters. For a simple mutation tool with three parameters and no nested objects, this is complete enough for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so each parameter already has a description. The description adds value by clarifying the interaction between parameters: `destination_ids` is accepted ONLY with `mode: override`, and an empty list with `override` is equivalent to `silence`. It also explains the default behavior for `inherit` and `silence`, which is not fully evident from the schema alone. This is beyond baseline but not exhaustive for all edge cases, hence a 4.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with 'REPLACE the per-campaign alert-routing override,' which is a specific verb and resource. It then differentiates the three modes (inherit, override, silence) and explicitly calls out that there is no 'route everywhere except these' mode, distinguishing it from a potential sibling behavior and from list_alert_destinations. This makes the tool's purpose unambiguous and distinct from related tools like get_campaign_alert_overrides.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit guidance on when to use each mode, including the condition for using `override` to exclude a single destination (pass the destinations you DO want) and a pointer to list_alert_destinations for discovering valid destinations. It also tells the agent to follow up with get_campaign_alert_overrides to read the new state, effectively covering both selection and post-action verification.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

set_default_policy_setSet Default Policy SetA
Idempotent

Mark or clear one of your organization's policy sets as the default for new campaigns. At most one owned set may be default. Creating a campaign without policy_set_id then binds this set (or stays unbound if none is set). Pass policy_set_id: null on create_campaign to opt out of the default. Foreign public sets cannot be made default. The API returns 204; this tool echoes is_default.

ParametersJSON Schema
NameRequiredDescriptionDefault
is_defaultYesTrue makes this the organization's default for new campaigns (clearing any previous default). False clears the flag on this set and leaves the org without a default.
policy_set_idYesOwned policy set UUID.

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare mutation (readOnlyHint=false), idempotency (idempotentHint=true), and non-destructiveness. The description adds the API return code (204), the echo of is_default, and the side-effect of clearing a previous default when setting a new one, plus the interaction with create_campaign. This goes beyond the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is four sentences, front-loaded with the primary purpose, and each sentence adds value (purpose, constraint, interaction, response format). No filler or redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a two-parameter tool with no output schema, the description covers the main behavior, the effect on new campaigns, the opt-out, and the return code. It does not mention error cases or permission requirements, but these are not critical for correct invocation given the schema and annotations.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema already provides full descriptions for both parameters (100% coverage). The description adds a small extra constraint (owned set requirement) but otherwise does not materially extend the schema's meaning. Baseline of 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific action (mark or clear) on a specific resource (policy set) and clarifies the effect on new campaigns. It clearly distinguishes itself from sibling tools like create_policy_set (creation) and update_policy_set (property updates) by focusing on the default flag.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explains when to use this tool (to set or clear the default) and provides critical context about how it interacts with create_campaign, including the opt-out via policy_set_id:null. It also states a constraint (foreign public sets cannot be made default). However, it does not explicitly name alternatives or give when-not-to-use conditions beyond the ownership constraint.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

test_custom_ruleTest Custom RuleA
Read-onlyIdempotent

Preview-test a rule definition against a stored scan without persisting it. For regexp_request_url, the historical snapshot contains main-frame hops plus at most 200 persisted subrequests with selected resource types omitted, so a no-match does not prove the original fresh scan lacked the request. For regexp_request_body, the captured contents live for ONE DAY — pick a scan from the last 24 hours, because an older one reports no match with nothing left to read. Returns match state, elapsed time, and per-tag detail; the preview response does not expose the matched request URL separately. Slug-collision validation does not run in preview mode.

ParametersJSON Schema
NameRequiredDescriptionDefault
configYesRule-type-specific config to test. Same shape as `create_custom_rule`'s `config`. For `rule_type='regexp_request_url'` and `rule_type='regexp_request_body'`, `config` must be exactly `{ pattern: string, flags?: '' | 'i' }`: pattern is non-empty and at most 4,096 characters; omit flags or use `''` for case-sensitive matching, or `'i'` for case-insensitive matching. `target` may be `'page'` (the landing tab), `'creative'` (the ad-tag creative's own traffic) or `'creative_and_page'` (both, reported separately) — a script inside a banner's iframe is on no landing's request list, so a page-only rule cannot see it. Default `page`. `regexp_request_url` inspects up to 5,000 captured request URLs on a fresh scan; tests and rechecks of stored scans reconstruct main-frame hops plus up to 200 persisted subrequests with selected resource types omitted, so historical matching is best-effort. `regexp_request_body` inspects the CONTENTS of the page's scripts, fetch/XHR responses and iframe documents — never images, video, fonts or stylesheets — capped at 400 resources, 128 KB each and 8 MB per scan. Those contents are kept for ONE DAY, so a test or recheck against an older scan reports no match because there is nothing left to read. `regexp_url` remains redirect-chain-only. NOTE: `test_custom_rule` evaluates the rule against a scan WITHOUT persisting it, so slug-collision validation does NOT run here — verify slugs against `list_tags` (`scope=system`) before promoting to `create_custom_rule`. For `rule_type='combo'` the optional rule-level key `match_scope` decides where conditions are counted. `"scan"` (the default, and the behaviour when the key is absent) checks them against the union of all tags on the scan. With `"url"`, every condition must be satisfied by tags on the same link, and the tag is assigned to that link — so a rule built only from link-less tags (AI verdicts, crawler behaviour) has no link to attach to and will never match; keep those on the whole scan. Mixing the two kinds does not help either: AI verdicts and per-link detections reach the engine in different scan parts and are not evaluated together today, so such a combo fires under neither scope. Give a `"url"` rule at least one positive condition (`all_of` / `any_of` / `tag_category` + `count_gte`) — a config carrying only `none_of` matches every link that merely lacks those tags, and the API does not reject that on this path. Thresholds stay "N or more" (`count_gte` / `any_of_min`) in both scopes; no other `match_scope` value is accepted.
targetYesWhere to apply the rule (e.g. 'page' for landing HTML). `regexp_request_url` and `regexp_request_body` also accept `'creative'` and `'creative_and_page'`. See API docs for the full set of valid values.
scan_idYesExisting scan UUID to evaluate the rule against.
rule_typeYesRule engine type. One of: `stopword_content`, `stopword_url`, `regexp_content`, `regexp_url`, `regexp_request_url`, `regexp_request_body`, `blacklist_domain`, `combo`, `llm`. `regexp_url` checks redirect-chain URLs only; `regexp_request_url` checks captured network and subresource URLs; `regexp_request_body` checks what those sub-resources contained.

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already signal read-only, idempotent, non-destructive behavior, and the description adds substantial caveats: nothing is persisted, slug-collision validation is absent, historical snapshots omit subrequests, and request-body contents expire after one day. It also discloses what the response does and does not contain. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The first sentence is an excellent front-loaded summary, and every paragraph carries high-value caveats. However, some content is repeated between the main description and the config property description, and the overall block is long; it earns its length through complexity but could be tightened.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Even without an output schema, the description tells the caller what is returned (match state, elapsed time, per-tag detail), what is not returned (matched URL), and what subtle constraints apply. It covers data retention, validation omissions, rule types, and target semantics, so an agent has enough to invoke it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, but the description meaningfully extends it with per-parameter behavior: scan_id freshness matters for regexp_request_body, rule_type determines what is inspected, target explains creative vs page scope, and config details combo match_scope pitfalls. This exceeds what the schema alone provides.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence names the specific action ('Preview-test'), the object ('a rule definition'), the context ('against a stored scan'), and the key distinction ('without persisting it'). This clearly separates it from create_custom_rule and similar persistence-oriented siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly frames this as a pre-promotion check ('before promoting to create_custom_rule'), gives the retention-based usage constraint for regexp_request_body ('pick a scan from the last 24 hours'), and warns that slug-collision validation is skipped. It tells the agent when to use this tool and what to verify before using the alternative.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

test_webhookTest WebhookA

Dispatch a synthetic event with the sample payload for the given event_type to the webhook endpoint and return the receiver's response synchronously. Includes HTTP status, elapsed time, and a snippet of the response body so the operator can diagnose receiver bugs.

ParametersJSON Schema
NameRequiredDescriptionDefault
event_typeYesEvent type slug whose sample payload to send (see `list_webhook_event_types` for the catalog).
webhook_idYesWebhook endpoint UUID.

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations indicate non-readOnly, non-destructive, non-idempotent. Description adds that it dispatches a synthetic event synchronously and returns a response, which goes beyond annotations. It does not disclose potential side effects on the webhook endpoint or rate limits, but overall provides adequate transparency.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with purpose, no extraneous words. Efficiently communicates the tool's action and output.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite no output schema, the description explains the response contents (HTTP status, elapsed time, snippet of response body). For a simple two-parameter tool, the description is complete and sufficient for an agent to understand the tool's functionality and expected return.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema provides 100% coverage with descriptions for both parameters (event_type references sample payload catalog, webhook_id is UUID). The description does not add additional parameter information beyond the schema, meeting baseline but not exceeding it.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description clearly states the tool dispatches a synthetic event with a sample payload for a given event_type to the webhook endpoint and returns the receiver's response synchronously. It specifies the return details (HTTP status, elapsed time, snippet of response body), distinguishing it from sibling tools like replay_webhook_delivery.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage for diagnosing receiver bugs via synthetic payloads. It doesn't explicitly exclude alternatives like replay_webhook_delivery for actual deliveries, but the context is clear. A slight improvement would be adding a note about when not to use this tool.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

transfer_ownershipTransfer Organization OwnershipA
Destructive

Hand the organization owner role to another existing member. ONE-WAY: the previous owner becomes a regular member afterwards. Require explicit confirmation from the user.

ParametersJSON Schema
NameRequiredDescriptionDefault
user_idYesUUID of the existing member to become the new owner.

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description adds behavioral context beyond annotations: it specifies that the transfer is one-way and makes the previous owner a regular member. Annotations already indicate destructiveHint=true, and the description confirms and elaborates, with no contradiction.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is three short sentences, front-loading the action and then adding critical behavioral details. Every sentence is necessary with no redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers the core functionality and side effects. However, it lacks details about return values or error handling (e.g., invalid user ID). The tool is simple, so the information is sufficient but not exhaustive.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

There is only one parameter (user_id) with 100% schema description coverage. The description does not add new information beyond the schema's description ('UUID of the existing member to become the new owner'), so baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action ('transfer ownership') and the resource ('organization owner role to another existing member'). It distinguishes from sibling tools like update_user_role or remove_user by specifying the exact ownership transfer semantics.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description mentions 'Require explicit confirmation from the user,' which provides a usage condition. However, it does not explicitly state when not to use this tool or compare it to alternatives like update_org or create_custom_role.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

unarchive_campaignUnarchive CampaignA
Idempotent

Restore an archived campaign. Inverse of archive_campaign. The campaign re-appears in default lists; if schedule_enabled was true, the scheduler resumes producing runs.

ParametersJSON Schema
NameRequiredDescriptionDefault
campaign_idYesCampaign UUID.

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description adds behavioral context beyond annotations: it explains the inverse relationship and the resumption of scheduled runs. Annotations already indicate idempotent and non-destructive, and the description complements this well.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences efficiently convey the purpose and key behavior. No redundant information, and the most critical points are front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple tool with one parameter and no output schema, the description covers all necessary aspects: purpose, relationship to archive, and consequences of restoration.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 100% schema coverage, the description does not add extra meaning beyond the schema's 'Campaign UUID.' It adequately covers the single parameter but provides no further enrichment.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states 'Restore an archived campaign' and identifies it as the inverse of 'archive_campaign', making the verb and resource explicit. It distinguishes itself from the sibling tool 'archive_campaign'.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explains the effect (re-appears in lists, scheduler resumes) which guides when to use. However, it does not explicitly state conditions when not to use, such as if the campaign is already active.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

unarchive_campaign_groupUnarchive Campaign GroupA
Idempotent

Restore an archived campaign group and re-expose its campaigns in default lists.

ParametersJSON Schema
NameRequiredDescriptionDefault
group_idYesCampaign group UUID.

TDQS

A3.9/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already indicate idempotent, non-destructive mutation. Description adds context about re-exposing campaigns but does not elaborate on side effects or system behavior beyond what annotations provide.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Single sentence that front-loads the action and object, with no wasted words. Perfectly concise for a simple operation.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with one parameter and no output schema, the description fully explains the purpose and effect, leaving no obvious gaps.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema covers 100% of parameters with clear descriptions. The tool description adds nothing beyond the schema, meeting the baseline for high coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states it restores an archived campaign group and re-exposes its campaigns, which distinguishes it from similar tools like unarchive_campaign and archive_campaign_group.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage to reverse an archive but lacks explicit guidance on when not to use or mention of alternatives. For a simple operation, this is adequate but not exemplary.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

unpublish_policy_setUnpublish Policy SetA
DestructiveIdempotent

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 — going private blocks new attachments rather than breaking existing ones. Safe to call on a set that is already private.

ParametersJSON Schema
NameRequiredDescriptionDefault
policy_set_idYesPolicy set UUID.

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark this as non-readonly, destructive, and idempotent, so the description goes beyond them by clarifying the exact scope of destruction: it removes public availability but does not delete the set internally and does not break existing campaign bindings. It also explains the difference between blocking new attachments and breaking existing ones. This is rich, non-obvious behavioral context that annotations alone could not convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact but information-dense, with each sentence adding a distinct and valuable piece of behavior: the primary action, the inverse relationship, internal usability, external campaign behavior, and idempotent safety. The main action is front-loaded, and there is no redundant filler or repetition of the tool name.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given a single obvious parameter, no output schema, and comprehensive annotations, the description covers all essential context: what the operation does, what happens to pending vs. approved requests, internal impact, external impact, and edge-case safety. An agent has everything needed to invoke this tool correctly and predict its effects.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema already fully documents the only parameter, policy_set_id, as a UUID, giving 100% coverage. The description does not add parameter-specific semantics beyond identifying the resource as one of the organization's policy sets. With full schema coverage, a baseline score of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Return one of your organization's policy sets to PRIVATE.' It clearly distinguishes itself from the sibling request_policy_set_approval by describing itself as the inverse, and it also contrasts with delete_policy_set by noting the set stays usable internally. An agent can immediately understand what operation this performs.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly frames when to use the tool: it removes an approved set from the shared catalog or withdraws a pending publication request. It names the alternative request_policy_set_approval and explains the inverse relationship, and it adds a practical safety note that calling it on an already-private set is harmless. This gives clear decision guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

update_account_labelsUpdate Account LabelsA
DestructiveIdempotent

REPLACE the organization's full set of custom label definitions. The API replaces the list (no merge); read the current list with list_account_labels first. Returns the persisted list with allocated positions.

ParametersJSON Schema
NameRequiredDescriptionDefault
labelsYesREPLACEMENT list of all labels — pass every label you want to keep. Order in the array becomes `position`. Empty array removes all labels.

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description explains that the API replaces the list (no merge) and returns the persisted list with positions, going beyond annotations (destructiveHint=true, idempotentHint=true). No contradictions with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three succinct sentences: first states core action, second adds replacement semantics with pre-read advice, third describes return value. No redundancy. Front-loaded and efficient.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given good annotations and full schema coverage, the description covers the essential semantics (replacement, position, removal). Could mention error conditions or permissions, but the return value and destructive nature are explained.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

For the single 'labels' parameter, schema coverage is 100%. The description adds significant context: 'REPLACEMENT list of all labels — pass every label you want to keep. Order in the array becomes position. Empty array removes all labels.' This clarifies replacement behavior and array semantics beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states 'REPLACE the organization's full set of custom label definitions,' specifying the verb (replace) and resource (label definitions). It distinguishes from sibling 'list_account_labels' by noting to read first, and the replacement semantics differentiate it from merge operations.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description advises reading the current list with 'list_account_labels' first, providing clear context for when to use this tool. It does not explicitly mention when not to use it or list alternatives, but the note about reading first serves as a guideline.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

update_alert_statusUpdate Alert StatusA
Idempotent

Update an alert's status in its lifecycle: open → escalated → resolved | dismissed. The API enforces valid transitions; an invalid one returns 422.

ParametersJSON Schema
NameRequiredDescriptionDefault
statusYesNew status: open | escalated | resolved | dismissed.
alert_idYesAlert UUID.

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already provide idempotentHint=true and destructiveHint=false. The description adds that the API enforces valid transitions (open→escalated→resolved|dismissed) and returns 422 for invalid ones, which is useful behavioral context beyond annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Single sentence, front-loaded with action and resource, then critical constraints. No extraneous words. Every part adds value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple tool with two required parameters and no output schema, the description is fully self-contained: it explains purpose, valid transitions, and error behavior. No additional context needed.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% with descriptions for both parameters. The description adds meaning by specifying the valid order of transitions and the 422 error for invalid statuses, which the schema alone does not convey.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb ('Update') and resource ('alert's status') and clearly defines the scope via the lifecycle transitions. It distinguishes from siblings like list_alerts or get_alert_stats which are read-only.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implicitly indicates when to use (to transition alert status) and mentions that invalid transitions return 422, guiding proper usage. However, it does not explicitly state when not to use or suggest alternatives, though no sibling serves the same purpose.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

update_campaignUpdate CampaignA
Idempotent

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. ignore_first_n_domains is the exception: it is not nullable, so pass 0 to go back to skipping nothing.

ParametersJSON Schema
NameRequiredDescriptionDefault
urlNoNew target URL (url-type and ad_discovery campaigns).
nameNoNew display name.
ad_tagNoNew ad-tag HTML/JS or an http(s) URL of a page with the rendered creative (ad_tag-type campaigns).
labelsNoReplace the label map.
group_idNoMove the campaign to another group.
referrerNoOptional http(s) page URL every scan of this campaign is checked from. For `ad_tag` and `vast` campaigns this is the publisher page the tag is embedded in — 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). For `url` and `ad_discovery` campaigns this is where the visitor came from, sent in full as the Referer of the page request. Pass null to clear it.
vast_tagNoNew VAST video ad tag: an http(s) URL of a VAST endpoint OR raw VAST XML (vast-type campaigns).
proxy_ispNoProxy ISP, or mobile carrier when `proxy_type` is mobile. Use a value from `get_proxy_targeting`.
proxy_cityNoProxy city from `get_proxy_targeting`. If you also set `proxy_region`, take the city from a call made with that same region — a city from a different region passes validation but leaves the provider no exit node.
proxy_typeNoProxy 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.
campaign_idYesCampaign UUID to update.
repeat_modeNoHow the repeats of one combination relate to each other. 'isolated' gives every repeat a fresh browser and a new IP, so the repeats are statistically independent. 'shared' runs all repeats of one combination in a single browser behind one IP, carrying cookies and localStorage from one repeat to the next — use it to reproduce a cloaker or a frequency cap that only misbehaves on the second or third visit. 'shared' is rejected with 422 on an ad-discovery target: when creating, that is `ad_discovery: true` on a scan or `campaign_type: "ad_discovery"` on a campaign; when updating a campaign, it is a campaign whose existing type is already ad_discovery, since campaign_type itself cannot be changed. Default: isolated.
proxy_regionNoProxy 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.
repeat_countNoHow 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 — see that tool's description for the exact formula — 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.
country_codesNoReplace the country list.
emulator_modeNoHow 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.
policy_set_idNoNew policy set UUID; pass null to clear.
schedule_typeNoScheduling 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.
schedule_weeklyNoWeekly run grid for schedule_type='weekly'. Keys are weekdays '0'-'6' (Mon-Sun); values are hours 0-23 in schedule_timezone, e.g. { '0': [9, 17], '4': [12] }.
schedule_enabledNoPause / resume the scheduler.
schedule_timezoneNoIANA timezone for the weekly grid, e.g. 'Europe/Berlin'. Default: UTC.
max_discovered_adsNoHow 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 — one parent plus its children. Only valid on an ad-discovery target — `ad_discovery: true` on a scan, or `campaign_type: "ad_discovery"` on a campaign — and rejected with 422 anywhere else. Omitting the field leaves the campaign's current setting unchanged; pass null to drop its own number and go back to the platform default. The platform default is 12 unless an operator retuned it.
retry_max_attemptsNoExtra crawl attempts when a scan fails for a technical reason — dead proxy, navigation timeout, browser crash (0-5). Permanent failures are never retried. The same scan is reused and only a completed scan is billed, so a retry never double-charges. 0-5 is the API's default ceiling; an operator can lower it, and then a value accepted here still comes back as a 422 from the API. Default: 0.
emulator_categoriesNoDevice categories to rotate through, e.g. ['android_phone']. Valid: android_phone, android_tablet, iphone, ipad, windows_desktop, macos_desktop. On create, omitting this defaults to ['android_phone']; pass [] together with emulator_specific_ids to target ONLY specific devices.
emulator_specific_idsNoPin exact device profile slugs from `list_emulators` (the `id` field), e.g. ['samsung_galaxy_s23_ultra_android16']. Always scanned regardless of emulator_mode.
ignore_first_n_domainsNoHow many leading domains of the redirect chain to exclude from detection and tagging (0-5). Use it when the check enters through the caller's OWN click or tracking domains: without it a reputation hit on one of those tags the material and raises an alert about the caller's infrastructure rather than about the offer. Counting starts at the entry point and follows chain order; domains fold to their registrable form, so www.example.com and example.com consume one slot between them, and any other request to one of those domains is excluded too. A skipped domain is checked by NOTHING, so never set this higher than the number of domains the caller actually owns at the head of the chain — ask rather than guess. The full redirect chain is still captured and returned either way. Omitting the field leaves the campaign's current setting unchanged; pass 0 to go back to skipping nothing. Not nullable — null is rejected with 422.
schedule_interval_secondsNoRun interval for schedule_type='interval'. Allowed presets (seconds): 60, 120, 300, 600, 900, 1800, 2700, 3600, 7200, 14400, 28800, 86400.

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations provide idempotentHint=true and destructiveHint=false, and the description adds useful behavior beyond that: fields not supplied are left unchanged, and null clears policy_set_id/referrer/max_discovered_ads, with ignore_first_n_domains explicitly non-nullable. This gives operational guidance that prevents mistakes.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, front-loaded with the core action

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given 27 parameters and the schema covering them all, the description focuses on cross-cutting behavior (partial update, null handling) and the one exception. It omits return-value information, but with no output schema and an update operation, that is a minor gap. The key behavioral rules are covered.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so every parameter is already documented in the input schema. The tool-level description repeats a few nullability notes (e.g., 'policy_set_id accepts null') that are already in the parameter descriptions, thus adding minimal value over the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with 'Update one or more fields of a campaign', a specific verb and resource that immediately distinguishes this from create_campaign and archive_campaign. It also clarifies the partial-update semantics, making the tool's job unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies use on existing campaigns ('update') but never explicitly contrasts with create_campaign or other alternatives. There is no 'when not to use' or naming of sibling tools, so an agent must infer the boundary from context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

update_campaign_groupUpdate Campaign GroupA
Idempotent

Rename a campaign group. To pause/resume its scheduler, use pause_campaign_group_schedule / resume_campaign_group_schedule instead.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameNoNew display name.
group_idYesGroup UUID to update.

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already indicate idempotent and non-destructive behavior. The description adds the specific scope of renaming, which is sufficient. No additional behavioral traits beyond annotations are needed, but the clarity is good.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences that are concise and front-loaded. Every sentence adds value: the first states the core action, the second provides usage guidance. No waste.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple update operation with full schema annotation coverage and clear sibling differentiation, the description is complete. It tells the agent everything needed to use the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% with clear descriptions for both parameters (group_id and name). The description does not add extra semantic details beyond the schema, so baseline score of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states 'Rename a campaign group', which is a specific verb and resource. It distinguishes from sibling tools like pause/resume by explicitly referring to them, making the purpose unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit when-to-use (renaming) and when-not-to-use (scheduler management, directing to pause/resume tools). This is excellent guidance for an agent.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

update_custom_ruleUpdate Custom RuleA
Idempotent

Update a custom tag-detection rule. Only supplied fields are sent, but config replaces the stored object wholesale; read the rule first and resend every required key. regexp_request_url and regexp_request_body need a non-empty pattern (max 4,096), flags ''/'i', and a target of 'page', 'creative' or 'creative_and_page'. Same-slug GLOBAL rule edits preserve separately managed tag metadata; use update_tag_definition to change it. Existing scans are not re-evaluated until recheck_scans.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameNoNew rule display name. For PERSONAL non-LLM rules this refreshes the auto-registered tag's display name. A same-slug GLOBAL rule keeps its separately managed tag metadata unchanged; use `update_tag_definition` for that tag.
configNoNew rule-type-specific config object. Replaces the stored config wholesale — resend every key you want to keep, including a combo rule's `match_scope`. For `rule_type='llm'` the keys of `config.tags` are auto-registered as tag definitions; any key that collides with a system slug returns the same 422 contract. For `rule_type='regexp_request_url'` and `rule_type='regexp_request_body'`, `config` must be exactly `{ pattern: string, flags?: '' | 'i' }`: pattern is non-empty and at most 4,096 characters; omit flags or use `''` for case-sensitive matching, or `'i'` for case-insensitive matching. `target` may be `'page'` (the landing tab), `'creative'` (the ad-tag creative's own traffic) or `'creative_and_page'` (both, reported separately) — a script inside a banner's iframe is on no landing's request list, so a page-only rule cannot see it. Default `page`. `regexp_request_url` inspects up to 5,000 captured request URLs on a fresh scan; tests and rechecks of stored scans reconstruct main-frame hops plus up to 200 persisted subrequests with selected resource types omitted, so historical matching is best-effort. `regexp_request_body` inspects the CONTENTS of the page's scripts, fetch/XHR responses and iframe documents — never images, video, fonts or stylesheets — capped at 400 resources, 128 KB each and 8 MB per scan. Those contents are kept for ONE DAY, so a test or recheck against an older scan reports no match because there is nothing left to read. Read the rule first because `rule_type` is immutable and is not repeated in this update input. For `rule_type='combo'` the optional rule-level key `match_scope` decides where conditions are counted. `"scan"` (the default, and the behaviour when the key is absent) checks them against the union of all tags on the scan. With `"url"`, every condition must be satisfied by tags on the same link, and the tag is assigned to that link — so a rule built only from link-less tags (AI verdicts, crawler behaviour) has no link to attach to and will never match; keep those on the whole scan. Mixing the two kinds does not help either: AI verdicts and per-link detections reach the engine in different scan parts and are not evaluated together today, so such a combo fires under neither scope. Give a `"url"` rule at least one positive condition (`all_of` / `any_of` / `tag_category` + `count_gte`) — a config carrying only `none_of` matches every link that merely lacks those tags, and the API does not reject that on this path. Thresholds stay "N or more" (`count_gte` / `any_of_min`) in both scopes; no other `match_scope` value is accepted.
targetNoWhere to apply the rule. `regexp_request_url` and `regexp_request_body` accept `'page'`, `'creative'` or `'creative_and_page'`. See API docs for the valid targets of other rule types.
rule_idYesRule UUID to update.
tag_slugNoNew tag slug to assign on match. **MUST NOT collide with a built-in system tag slug** (see `list_tags` where `scope=system`); colliding requests return 422 with code `checking.system_slug_reserved`. Leaving a GLOBAL rule on the same slug preserves its admin-managed tag metadata.
is_activeNoEnable/disable the rule.

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations declare readOnlyHint=false, destructiveHint=false, idempotentHint=true, openWorldHint=false. The description adds substantial behavioral context beyond those: config replaces the stored object wholesale, rule_type is immutable, existing scans are not re-evaluated until recheck_scans, regexp_request_body contents are kept for only ONE DAY, and historical matching is best-effort. It also discloses that colliding system slugs return 422. No contradiction with annotations; the description enriches them.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long, but every sentence earns its place given the complexity of the tool. It front-loads the most critical warning (config replaces wholesale, read first) and then proceeds logically through rule types, targets, and combo scopes. It is dense but not redundant; the only minor deduction is that some sentences could be tightened, but the length is justified by the parameter complexity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 6-parameter update tool with no output schema, the description covers all the essential context: partial update semantics, immutable fields, rule-type-specific constraints, target semantics, combo match_scope pitfalls, tag slug collision behavior, and recheck behavior. It also names the sibling tool (update_tag_definition) for the adjacent concern. Nothing an agent needs to call this correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3, but the description goes far beyond the schema. It explains the wholesale replacement semantics of config, the exact shape required for regexp rule types, the meaning of target values with a concrete iframe example, the match_scope behavior for combo rules, and the 422 contract for system slug collisions. It also warns that rule_type is immutable and not repeated in the input, which is not in the schema. This is exemplary parameter-level guidance.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Update a custom tag-detection rule.' It clearly distinguishes this from siblings like create_custom_rule, delete_custom_rule, test_custom_rule, and update_tag_definition by naming the latter explicitly and explaining the boundary. The title and description align, and the scope is unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit when-to-use guidance: read the rule first because rule_type is immutable and not repeated in the update input; use update_tag_definition for same-slug GLOBAL rule tag metadata; and notes that existing scans are not re-evaluated until recheck_scans. It also explains when a combo rule with match_scope='url' will never match, which is critical usage guidance. This is far beyond a generic 'use this to update' statement.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

update_custom_taxonomyUpdate Custom TaxonomyA
Idempotent

REPLACE a custom taxonomy's name, description, and full tree atomically. The API bumps version on every successful update; ongoing scan classifications continue with the previous tree until they finish, so updates are safe but not retroactive.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYesNew display name.
nodesNoREPLACEMENT tree as a flat array (REPLACES the existing tree, not a merge). Read the current tree via `get_custom_taxonomy` first if you only want to tweak one node.
descriptionNoNew description (defaults to empty string).
taxonomy_idYesCustom taxonomy UUID.

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond annotations (idempotentHint=true, destructiveHint=false), the description adds key behaviors: atomic replacement, version bump, and that ongoing scans continue with the previous tree. No contradictions.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two succinct sentences: first states purpose and atomicity, second explains safety behavior. No unnecessary words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with no output schema, the description provides necessary context about the replacement semantics and safety during ongoing scans. Minor gap: no mention of error conditions, but overall complete enough.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the schema itself provides detailed descriptions, including that nodes are a replacement tree. The description adds little beyond naming the parameters (name, description, full tree). Baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool replaces a custom taxonomy's name, description, and full tree atomically. It uses the verb REPLACE, distinguishing it from siblings like create, delete, get, and restore custom taxonomy.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage for atomic replacement and notes that for tweaking one node, one should read the current tree first via get_custom_taxonomy. However, it does not explicitly state when not to use this tool or provide direct alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

update_orgUpdate OrganizationB
Idempotent

Update the caller's organization display name.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameNoNew organization display name.

TDQS

B3.2/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already indicate idempotentHint=true and destructiveHint=false, so the description's statement 'update' adds no new behavioral context. It does not disclose whether the update is instantaneous, if it affects other properties, or any side effects. The description carries minimal additional transparency beyond the structured annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, direct sentence with no unnecessary words. It is efficiently front-loaded and earns its place without redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple update tool with one parameter and no output schema, the description is mostly adequate. However, it does not clarify whether the 'name' parameter is required (schema shows required: false, but minLength: 1 implies a value should be provided), nor does it mention that the update applies to the 'caller's organization' explicitly. The description is otherwise sufficient given the tool's simplicity and the richness of annotations.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema provides full coverage for the single parameter 'name' with a clear description. The tool description does not add additional meaning beyond the schema, so a baseline score of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb 'Update' and the resource 'organization display name', specifying the exact property being modified. However, it does not distinguish this tool from sibling update tools like update_campaign or update_custom_rule, as the context of 'caller's organization' is implied but not explicitly stated.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance is provided on when to use this tool versus alternatives, such as transfer_ownership for broader organization changes. There is no mention of prerequisites, scope limitations (e.g., only the caller's org), or conditions under which the update can be performed.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

update_policy_setUpdate Policy SetA
Idempotent

REPLACE a policy set's name, description, and entry list. The API requires all three fields on every update — read the current set with get_policy_set first if you only want to change one thing. Supports all five rule kinds (tag / iab_v3 / brand / ai_category / custom_taxonomy).

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYesNew name (always required by the API on update).
entriesYesREPLACEMENT entries list — REPLACES the current list, not a merge. Each entry is a discriminated union over five rule kinds (tag / iab_v3 / brand / ai_category / custom_taxonomy).
descriptionYesNew description (empty string allowed).
policy_set_idYesPolicy set UUID.

TDQS

A4.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare non-readOnly, idempotent, and non-destructive. The description adds behavioral context: the API requires all three fields on every update, and the entries list is replaced (not merged). This goes beyond annotations without contradicting them.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, no filler. The first sentence states the core action and constraint; the second adds a key detail. Every word earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite the complexity of the entries array with discriminated unions, the description covers the essential behavior (replace, required fields, rule kinds) and the usage pattern. No output schema exists, so missing return info is acceptable. The tool is fully specified for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% with detailed field descriptions. The description adds significant value by clarifying the replace semantics for the 'entries' parameter and the fact that all five rule kinds are supported, which is not fully captured in the schema alone.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description explicitly states 'REPLACE a policy set's name, description, and entry list', using a specific verb and resource. It clearly distinguishes from siblings like 'create_policy_set', 'get_policy_set', and 'delete_policy_set' by emphasizing the replace semantics.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit guidance: 'The API requires all three fields on every update — read the current set with `get_policy_set` first if you only want to change one thing.' It also notes support for all five rule kinds, helping the agent know when this tool is appropriate.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

update_tag_definitionUpdate Tag DefinitionA
Idempotent

Update display fields of a CUSTOM tag (system tags are read-only). Only supplied fields are touched. To read the updated definition, follow up with get_tag_definition.

ParametersJSON Schema
NameRequiredDescriptionDefault
slugYesTag slug.
severityNoNew severity level.
visibilityNoTag visibility on the scan report: hidden = not surfaced; internal = visible to org members; public = appears in the public scan-share view.
descriptionNoNew description.
display_nameNoNew human-readable name.

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already indicate idempotentHint=true and destructiveHint=false. The description adds that only supplied fields are touched (partial update behavior) and that system tags are read-only, which aligns with annotations. No contradictions.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences with no unnecessary words. The main purpose is front-loaded, and additional guidance is provided concisely.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given 5 parameters, 100% schema coverage, no output schema, and provided annotations, the description covers key aspects (custom vs system, partial update, follow-up). It lacks explicit permission requirements or error handling but is sufficient for a mutation tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% with clear descriptions for all 5 parameters. The description adds minimal value beyond the schema, only reinforcing the partial update concept. Baseline of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool updates display fields of custom tags, distinguishes from system tags (read-only), and uses the imperative verb 'update' with a specific resource. It differentiates from sibling tools like delete_tag_definition and get_tag_definition.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear context: use only for custom tags, partial updates (only supplied fields touched), and suggests a follow-up read with get_tag_definition. However, it does not explicitly exclude other use cases or compare with alternatives beyond mentioning system tags.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

update_user_roleUpdate User RoleA
Idempotent

Change an organization member's role. The owner role can only be transferred via transfer_ownership. Returns {updated: true} on success; refetch with list_org_users if you need the new role echoed.

ParametersJSON Schema
NameRequiredDescriptionDefault
role_idYesUUID of the new role (see `list_org_roles`).
user_idYesUUID of the member to update.

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond annotations, describes the return object and suggests refetching. Annotations already indicate idempotent and non-destructive, so description adds useful behavioral context without contradiction.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with purpose, then constraints and return info. No wasted words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given simple tool with 2 required params, schema descriptions, and clear annotations, the description covers purpose, alternatives, return value, and post-action step. Complete for effective use.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema descriptions already cover both parameters with UUID types and cross-reference. Tool description adds minimal extra meaning beyond noting 'list_org_roles' for role_id, which is helpful but not essential.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description clearly states the tool changes an organization member's role, distinguishing it from the 'transfer_ownership' sibling for owner role changes.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says to use 'transfer_ownership' for owner role and to refetch with 'list_org_users' to see the change, providing clear when-to-use and when-not-to-use guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

update_webhookUpdate WebhookA
Idempotent

Update a webhook endpoint's URL, event-type subscriptions, and/or active flag. Signing secret is NOT rotated by this call — use rotate_webhook_secret for that.

ParametersJSON Schema
NameRequiredDescriptionDefault
urlNoNew endpoint URL.
is_activeNoEnable / disable delivery.
webhook_idYesWebhook UUID.
descriptionNoNew human-readable label.
event_typesNoReplace the subscribed-event-types list.
campaign_idsNoRestrict deliveries to these campaign UUIDs (replaces the current set).
clear_campaign_idsNoSet true to remove the campaign restriction so the webhook fires for all campaigns.

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already provide readOnlyHint=false, destructiveHint=false, idempotentHint=true. Description adds behavioral context that signing secret is not rotated. However, it does not mention partial update behavior or idempotency implications, which would further aid transparency.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences that front-load the core purpose and immediately clarify a common misconception (secret not rotated). No wasted words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema, but the description does not mention return value or response structure. For an update tool, this is often acceptable. It does cover the key behavioral nuance about secret rotation, making it fairly complete for the given context.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so description need not add much. It lists URL, event-type subscriptions, and active flag but omits campaign_ids, clear_campaign_ids, and description parameters. This provides a helpful high-level summary but is incomplete.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description clearly states the tool updates a webhook endpoint's URL, event-type subscriptions, and/or active flag, using specific verbs and resource. It distinguishes from the sibling tool rotate_webhook_secret by explicitly mentioning that the signing secret is not rotated here.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states what fields can be updated and provides a clear alternative for rotating the secret (rotate_webhook_secret). This tells the agent when to use this tool vs. another.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 8 tool updatesv0.22.0
    • Changedcreate_bulk_scans1 field changed
      • addedInput schema / properties / ignore_first_n_domains
        Added value: +{
        +  "description": "How many leading domains of the redirect chain to exclude from detection and tagging (0-5). Use it when the check enters through the caller's OWN click or tracking domains: without it a reputation hit on one of those tags the material and raises an alert about the caller's infrastructure rather than about the offer. Counting starts at the entry point and follows chain order; domains fold to their registrable form, so www.example.com and example.com consume one slot between them, and any other request to one of those domains is excluded too. A skipped domain is checked by NOTHING, so never set this higher than the number of domains the caller actually owns at the head of the chain — ask rather than guess. The full redirect chain is still captured and returned either way. Omit it to skip nothing (0). A scan created directly does NOT inherit this from the campaign named in `campaign_id` — only scans queued by a campaign run do — so send it explicitly on every direct submission that needs it.",
        +  "maximum": 5,
        +  "minimum": 0,
        +  "type": "integer"
        +}
    • Changedcreate_campaign5 fields changed
      • addedInput schema / properties / ignore_first_n_domains
        Added value: +{
        +  "description": "How many leading domains of the redirect chain to exclude from detection and tagging (0-5). Use it when the check enters through the caller's OWN click or tracking domains: without it a reputation hit on one of those tags the material and raises an alert about the caller's infrastructure rather than about the offer. Counting starts at the entry point and follows chain order; domains fold to their registrable form, so www.example.com and example.com consume one slot between them, and any other request to one of those domains is excluded too. A skipped domain is checked by NOTHING, so never set this higher than the number of domains the caller actually owns at the head of the chain — ask rather than guess. The full redirect chain is still captured and returned either way. Omit it to skip nothing (0).",
        +  "maximum": 5,
        +  "minimum": 0,
        +  "type": "integer"
        +}
      • addedInput schema / properties / policy_set_id / anyOf
        Added value: +[
        +  {
        +    "format": "uuid",
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedInput schema / properties / policy_set_id / description
        Previous value: -"Policy set to evaluate every scan against."New value: +"Policy set to evaluate every scan against. Omit to bind the organization's default (if any). Pass null for no policy set and no policy alerts."
      • removedInput schema / properties / policy_set_id / format
        Removed value: -"uuid"
      • removedInput schema / properties / policy_set_id / type
        Removed value: -"string"
    • Changedcreate_custom_rule2 fields changed
      • changedInput schema / properties / config / description
        Previous value: -"Rule-type-specific configuration object. Shape depends on `rule_type`. For `rule_type='regexp_request_url'` and `rule_type='regexp_request_body'`, `config` must be exactly `{ pattern: string, flags?: '' | 'i' }`: pattern is non-empty and at most 4,096 characters; omit flags or use `''` for case-sensitive matching, or `'i'` for case-insensitive matching. `target` must be `'page'` for both. `regexp_request_url` inspects up to 5,000 captured request URLs on a fresh scan; tests and rechecks of stored scans reconstruct main-frame hops plus up to 200 persisted subrequests with selected resource types omitted, so historical matching is best-effort. `regexp_request_body` inspects the CONTENTS of the page's scripts, fetch/XHR responses and iframe documents — never images, video, fonts or stylesheets — capped at 400 resources, 128 KB each and 8 MB per scan. Those contents are kept for ONE DAY, so a test or recheck against an older scan reports no match because there is nothing left to read. `regexp_url` remains redirect-chain-only. For `rule_type='llm'` the shape is `{ prompt: string, tags: { <tag_slug>: <description>, ... } }`; each key in `config.tags` is auto-registered as a custom tag definition AND must not collide with a system slug (same 422 contract as `tag_slug`). For `rule_type='combo'` the optional rule-level key `match_scope` decides where conditions are counted. `\"scan\"` (the default, and the behaviour when the key is absent) checks them against the union of all tags on the scan. With `\"url\"`, every condition must be satisfied by tags on the same link, and the tag is assigned to that link — so a rule built only from link-less tags (AI verdicts, crawler behaviour) has no link to attach to and will never match; keep those on the whole scan. Mixing the two kinds does not help either: AI verdicts and per-link detections reach the engine in different scan parts and are not evaluated together today, so such a combo fires under neither scope. Give a `\"url\"` rule at least one positive condition (`all_of` / `any_of` / `tag_category` + `count_gte`) — a config carrying only `none_of` matches every link that merely lacks those tags, and the API does not reject that on this path. Thresholds stay \"N or more\" (`count_gte` / `any_of_min`) in both scopes; no other `match_scope` value is accepted."New value: +"Rule-type-specific configuration object. Shape depends on `rule_type`. For `rule_type='regexp_request_url'` and `rule_type='regexp_request_body'`, `config` must be exactly `{ pattern: string, flags?: '' | 'i' }`: pattern is non-empty and at most 4,096 characters; omit flags or use `''` for case-sensitive matching, or `'i'` for case-insensitive matching. `target` may be `'page'` (the landing tab), `'creative'` (the ad-tag creative's own traffic) or `'creative_and_page'` (both, reported separately) — a script inside a banner's iframe is on no landing's request list, so a page-only rule cannot see it. Default `page`. `regexp_request_url` inspects up to 5,000 captured request URLs on a fresh scan; tests and rechecks of stored scans reconstruct main-frame hops plus up to 200 persisted subrequests with selected resource types omitted, so historical matching is best-effort. `regexp_request_body` inspects the CONTENTS of the page's scripts, fetch/XHR responses and iframe documents — never images, video, fonts or stylesheets — capped at 400 resources, 128 KB each and 8 MB per scan. Those contents are kept for ONE DAY, so a test or recheck against an older scan reports no match because there is nothing left to read. `regexp_url` remains redirect-chain-only. For `rule_type='llm'` the shape is `{ prompt: string, tags: { <tag_slug>: <description>, ... } }`; each key in `config.tags` is auto-registered as a custom tag definition AND must not collide with a system slug (same 422 contract as `tag_slug`). For `rule_type='combo'` the optional rule-level key `match_scope` decides where conditions are counted. `\"scan\"` (the default, and the behaviour when the key is absent) checks them against the union of all tags on the scan. With `\"url\"`, every condition must be satisfied by tags on the same link, and the tag is assigned to that link — so a rule built only from link-less tags (AI verdicts, crawler behaviour) has no link to attach to and will never match; keep those on the whole scan. Mixing the two kinds does not help either: AI verdicts and per-link detections reach the engine in different scan parts and are not evaluated together today, so such a combo fires under neither scope. Give a `\"url\"` rule at least one positive condition (`all_of` / `any_of` / `tag_category` + `count_gte`) — a config carrying only `none_of` matches every link that merely lacks those tags, and the API does not reject that on this path. Thresholds stay \"N or more\" (`count_gte` / `any_of_min`) in both scopes; no other `match_scope` value is accepted."
      • changedInput schema / properties / target / description
        Previous value: -"Where to apply the rule (e.g. 'page' for landing HTML). `regexp_request_url` and `regexp_request_body` require `target='page'`. Default: page. See API docs for the full set of valid values."New value: +"Where to apply the rule (e.g. 'page' for landing HTML). `regexp_request_url` and `regexp_request_body` also accept `'creative'` (the ad-tag creative's own traffic) and `'creative_and_page'` (both, reported separately). Default: page. See API docs for the full set of valid values."
    • Changedcreate_scan1 field changed
      • addedInput schema / properties / ignore_first_n_domains
        Added value: +{
        +  "description": "How many leading domains of the redirect chain to exclude from detection and tagging (0-5). Use it when the check enters through the caller's OWN click or tracking domains: without it a reputation hit on one of those tags the material and raises an alert about the caller's infrastructure rather than about the offer. Counting starts at the entry point and follows chain order; domains fold to their registrable form, so www.example.com and example.com consume one slot between them, and any other request to one of those domains is excluded too. A skipped domain is checked by NOTHING, so never set this higher than the number of domains the caller actually owns at the head of the chain — ask rather than guess. The full redirect chain is still captured and returned either way. Omit it to skip nothing (0). A scan created directly does NOT inherit this from the campaign named in `campaign_id` — only scans queued by a campaign run do — so send it explicitly on every direct submission that needs it.",
        +  "maximum": 5,
        +  "minimum": 0,
        +  "type": "integer"
        +}
    • Addedset_default_policy_set
    • Changedtest_custom_rule2 fields changed
      • changedInput schema / properties / config / description
        Previous value: -"Rule-type-specific config to test. Same shape as `create_custom_rule`'s `config`. For `rule_type='regexp_request_url'` and `rule_type='regexp_request_body'`, `config` must be exactly `{ pattern: string, flags?: '' | 'i' }`: pattern is non-empty and at most 4,096 characters; omit flags or use `''` for case-sensitive matching, or `'i'` for case-insensitive matching. `target` must be `'page'` for both. `regexp_request_url` inspects up to 5,000 captured request URLs on a fresh scan; tests and rechecks of stored scans reconstruct main-frame hops plus up to 200 persisted subrequests with selected resource types omitted, so historical matching is best-effort. `regexp_request_body` inspects the CONTENTS of the page's scripts, fetch/XHR responses and iframe documents — never images, video, fonts or stylesheets — capped at 400 resources, 128 KB each and 8 MB per scan. Those contents are kept for ONE DAY, so a test or recheck against an older scan reports no match because there is nothing left to read. `regexp_url` remains redirect-chain-only. NOTE: `test_custom_rule` evaluates the rule against a scan WITHOUT persisting it, so slug-collision validation does NOT run here — verify slugs against `list_tags` (`scope=system`) before promoting to `create_custom_rule`. For `rule_type='combo'` the optional rule-level key `match_scope` decides where conditions are counted. `\"scan\"` (the default, and the behaviour when the key is absent) checks them against the union of all tags on the scan. With `\"url\"`, every condition must be satisfied by tags on the same link, and the tag is assigned to that link — so a rule built only from link-less tags (AI verdicts, crawler behaviour) has no link to attach to and will never match; keep those on the whole scan. Mixing the two kinds does not help either: AI verdicts and per-link detections reach the engine in different scan parts and are not evaluated together today, so such a combo fires under neither scope. Give a `\"url\"` rule at least one positive condition (`all_of` / `any_of` / `tag_category` + `count_gte`) — a config carrying only `none_of` matches every link that merely lacks those tags, and the API does not reject that on this path. Thresholds stay \"N or more\" (`count_gte` / `any_of_min`) in both scopes; no other `match_scope` value is accepted."New value: +"Rule-type-specific config to test. Same shape as `create_custom_rule`'s `config`. For `rule_type='regexp_request_url'` and `rule_type='regexp_request_body'`, `config` must be exactly `{ pattern: string, flags?: '' | 'i' }`: pattern is non-empty and at most 4,096 characters; omit flags or use `''` for case-sensitive matching, or `'i'` for case-insensitive matching. `target` may be `'page'` (the landing tab), `'creative'` (the ad-tag creative's own traffic) or `'creative_and_page'` (both, reported separately) — a script inside a banner's iframe is on no landing's request list, so a page-only rule cannot see it. Default `page`. `regexp_request_url` inspects up to 5,000 captured request URLs on a fresh scan; tests and rechecks of stored scans reconstruct main-frame hops plus up to 200 persisted subrequests with selected resource types omitted, so historical matching is best-effort. `regexp_request_body` inspects the CONTENTS of the page's scripts, fetch/XHR responses and iframe documents — never images, video, fonts or stylesheets — capped at 400 resources, 128 KB each and 8 MB per scan. Those contents are kept for ONE DAY, so a test or recheck against an older scan reports no match because there is nothing left to read. `regexp_url` remains redirect-chain-only. NOTE: `test_custom_rule` evaluates the rule against a scan WITHOUT persisting it, so slug-collision validation does NOT run here — verify slugs against `list_tags` (`scope=system`) before promoting to `create_custom_rule`. For `rule_type='combo'` the optional rule-level key `match_scope` decides where conditions are counted. `\"scan\"` (the default, and the behaviour when the key is absent) checks them against the union of all tags on the scan. With `\"url\"`, every condition must be satisfied by tags on the same link, and the tag is assigned to that link — so a rule built only from link-less tags (AI verdicts, crawler behaviour) has no link to attach to and will never match; keep those on the whole scan. Mixing the two kinds does not help either: AI verdicts and per-link detections reach the engine in different scan parts and are not evaluated together today, so such a combo fires under neither scope. Give a `\"url\"` rule at least one positive condition (`all_of` / `any_of` / `tag_category` + `count_gte`) — a config carrying only `none_of` matches every link that merely lacks those tags, and the API does not reject that on this path. Thresholds stay \"N or more\" (`count_gte` / `any_of_min`) in both scopes; no other `match_scope` value is accepted."
      • changedInput schema / properties / target / description
        Previous value: -"Where to apply the rule (e.g. 'page' for landing HTML). `regexp_request_url` and `regexp_request_body` require `target='page'`. See API docs for the full set of valid values."New value: +"Where to apply the rule (e.g. 'page' for landing HTML). `regexp_request_url` and `regexp_request_body` also accept `'creative'` and `'creative_and_page'`. See API docs for the full set of valid values."
    • Changedupdate_campaign1 field changed
      • addedInput schema / properties / ignore_first_n_domains
        Added value: +{
        +  "description": "How many leading domains of the redirect chain to exclude from detection and tagging (0-5). Use it when the check enters through the caller's OWN click or tracking domains: without it a reputation hit on one of those tags the material and raises an alert about the caller's infrastructure rather than about the offer. Counting starts at the entry point and follows chain order; domains fold to their registrable form, so www.example.com and example.com consume one slot between them, and any other request to one of those domains is excluded too. A skipped domain is checked by NOTHING, so never set this higher than the number of domains the caller actually owns at the head of the chain — ask rather than guess. The full redirect chain is still captured and returned either way. Omitting the field leaves the campaign's current setting unchanged; pass 0 to go back to skipping nothing. Not nullable — null is rejected with 422.",
        +  "maximum": 5,
        +  "minimum": 0,
        +  "type": "integer"
        +}
    • Changedupdate_custom_rule2 fields changed
      • changedInput schema / properties / config / description
        Previous value: -"New rule-type-specific config object. Replaces the stored config wholesale — resend every key you want to keep, including a combo rule's `match_scope`. For `rule_type='llm'` the keys of `config.tags` are auto-registered as tag definitions; any key that collides with a system slug returns the same 422 contract. For `rule_type='regexp_request_url'` and `rule_type='regexp_request_body'`, `config` must be exactly `{ pattern: string, flags?: '' | 'i' }`: pattern is non-empty and at most 4,096 characters; omit flags or use `''` for case-sensitive matching, or `'i'` for case-insensitive matching. `target` must be `'page'` for both. `regexp_request_url` inspects up to 5,000 captured request URLs on a fresh scan; tests and rechecks of stored scans reconstruct main-frame hops plus up to 200 persisted subrequests with selected resource types omitted, so historical matching is best-effort. `regexp_request_body` inspects the CONTENTS of the page's scripts, fetch/XHR responses and iframe documents — never images, video, fonts or stylesheets — capped at 400 resources, 128 KB each and 8 MB per scan. Those contents are kept for ONE DAY, so a test or recheck against an older scan reports no match because there is nothing left to read. Read the rule first because `rule_type` is immutable and is not repeated in this update input. For `rule_type='combo'` the optional rule-level key `match_scope` decides where conditions are counted. `\"scan\"` (the default, and the behaviour when the key is absent) checks them against the union of all tags on the scan. With `\"url\"`, every condition must be satisfied by tags on the same link, and the tag is assigned to that link — so a rule built only from link-less tags (AI verdicts, crawler behaviour) has no link to attach to and will never match; keep those on the whole scan. Mixing the two kinds does not help either: AI verdicts and per-link detections reach the engine in different scan parts and are not evaluated together today, so such a combo fires under neither scope. Give a `\"url\"` rule at least one positive condition (`all_of` / `any_of` / `tag_category` + `count_gte`) — a config carrying only `none_of` matches every link that merely lacks those tags, and the API does not reject that on this path. Thresholds stay \"N or more\" (`count_gte` / `any_of_min`) in both scopes; no other `match_scope` value is accepted."New value: +"New rule-type-specific config object. Replaces the stored config wholesale — resend every key you want to keep, including a combo rule's `match_scope`. For `rule_type='llm'` the keys of `config.tags` are auto-registered as tag definitions; any key that collides with a system slug returns the same 422 contract. For `rule_type='regexp_request_url'` and `rule_type='regexp_request_body'`, `config` must be exactly `{ pattern: string, flags?: '' | 'i' }`: pattern is non-empty and at most 4,096 characters; omit flags or use `''` for case-sensitive matching, or `'i'` for case-insensitive matching. `target` may be `'page'` (the landing tab), `'creative'` (the ad-tag creative's own traffic) or `'creative_and_page'` (both, reported separately) — a script inside a banner's iframe is on no landing's request list, so a page-only rule cannot see it. Default `page`. `regexp_request_url` inspects up to 5,000 captured request URLs on a fresh scan; tests and rechecks of stored scans reconstruct main-frame hops plus up to 200 persisted subrequests with selected resource types omitted, so historical matching is best-effort. `regexp_request_body` inspects the CONTENTS of the page's scripts, fetch/XHR responses and iframe documents — never images, video, fonts or stylesheets — capped at 400 resources, 128 KB each and 8 MB per scan. Those contents are kept for ONE DAY, so a test or recheck against an older scan reports no match because there is nothing left to read. Read the rule first because `rule_type` is immutable and is not repeated in this update input. For `rule_type='combo'` the optional rule-level key `match_scope` decides where conditions are counted. `\"scan\"` (the default, and the behaviour when the key is absent) checks them against the union of all tags on the scan. With `\"url\"`, every condition must be satisfied by tags on the same link, and the tag is assigned to that link — so a rule built only from link-less tags (AI verdicts, crawler behaviour) has no link to attach to and will never match; keep those on the whole scan. Mixing the two kinds does not help either: AI verdicts and per-link detections reach the engine in different scan parts and are not evaluated together today, so such a combo fires under neither scope. Give a `\"url\"` rule at least one positive condition (`all_of` / `any_of` / `tag_category` + `count_gte`) — a config carrying only `none_of` matches every link that merely lacks those tags, and the API does not reject that on this path. Thresholds stay \"N or more\" (`count_gte` / `any_of_min`) in both scopes; no other `match_scope` value is accepted."
      • changedInput schema / properties / target / description
        Previous value: -"Where to apply the rule. `regexp_request_url` and `regexp_request_body` are fixed to `page`; do not change it. See API docs for the valid targets of other rule types."New value: +"Where to apply the rule. `regexp_request_url` and `regexp_request_body` accept `'page'`, `'creative'` or `'creative_and_page'`. See API docs for the valid targets of other rule types."
  2. 1 tool updatev0.19.1
    • Changedlist_balance_history3 fields changed
      • changedInput schema / properties / type / description
        Previous value: -"Filter by transaction kind. Pass several values to OR them (e.g. ['top_up_manual','crypto_top_up','card_top_up'] for credits-only)."New value: +"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."
      • changedInput schema / properties / type / items / enum
        Previous value: -[
        -  "initial_balance",
        -  "top_up_manual",
        -  "usage_charge",
        -  "subscription_renewal",
        -  "subscription_upgrade",
        -  "admin_adjustment",
        -  "refund",
        -  "invoice_settlement",
        -  "crypto_top_up",
        -  "card_top_up"
        -]New value: +[
        +  "initial_balance",
        +  "top_up_manual",
        +  "usage_charge",
        +  "subscription_renewal",
        +  "subscription_upgrade",
        +  "admin_adjustment",
        +  "refund",
        +  "invoice_settlement",
        +  "invoice_payment_adjustment",
        +  "crypto_top_up",
        +  "card_top_up"
        +]
      • changedInput schema / properties / type / maxItems
        Previous value: -10New value: +11
  3. 6 tool updatesv0.18.0
    • Changedcreate_campaign1 field changed
      • addedInput schema / properties / max_discovered_ads
        Added value: +{
        +  "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 — one parent plus its children. Only valid on an ad-discovery target — `ad_discovery: true` on a scan, or `campaign_type: \"ad_discovery\"` on a campaign — and rejected with 422 anywhere else. Omit it to use the platform default. The platform default is 12 unless an operator retuned it.",
        +  "maximum": 25,
        +  "minimum": 1,
        +  "type": "integer"
        +}
    • Changedcreate_custom_rule4 fields changed
      • changedInput schema / properties / config / anyOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "flags": {
        -        "description": "Omit or use '' for case-sensitive matching; use 'i' to ignore case.",
        -        "enum": [
        -          "",
        -          "i"
        -        ],
        -        "type": "string"
        -      },
        -      "pattern": {
        -        "description": "Non-empty request-URL regular expression, at most 4,096 characters.",
        -        "maxLength": 4096,
        -        "minLength": 1,
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "pattern"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": {},
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "flags": {
        +        "description": "Omit or use '' for case-sensitive matching; use 'i' to ignore case.",
        +        "enum": [
        +          "",
        +          "i"
        +        ],
        +        "type": "string"
        +      },
        +      "pattern": {
        +        "description": "Non-empty regular expression, at most 4,096 characters.",
        +        "maxLength": 4096,
        +        "minLength": 1,
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "pattern"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": {},
        +    "type": "object"
        +  }
        +]
      • changedInput schema / properties / config / description
        Previous value: -"Rule-type-specific configuration object. Shape depends on `rule_type`. For `rule_type='regexp_request_url'`, `config` must be exactly `{ pattern: string, flags?: '' | 'i' }`: pattern is non-empty and at most 4,096 characters; omit flags or use `''` for case-sensitive matching, or `'i'` for case-insensitive matching. `target` must be `'page'`. Fresh scans inspect up to 5,000 captured request URLs. Tests and rechecks of stored scans reconstruct main-frame hops plus up to 200 persisted subrequests with selected resource types omitted, so historical matching is best-effort. `regexp_url` remains redirect-chain-only. For `rule_type='llm'` the shape is `{ prompt: string, tags: { <tag_slug>: <description>, ... } }`; each key in `config.tags` is auto-registered as a custom tag definition AND must not collide with a system slug (same 422 contract as `tag_slug`). For `rule_type='combo'` the optional rule-level key `match_scope` decides where conditions are counted. `\"scan\"` (the default, and the behaviour when the key is absent) checks them against the union of all tags on the scan. With `\"url\"`, every condition must be satisfied by tags on the same link, and the tag is assigned to that link — so a rule built only from link-less tags (AI verdicts, crawler behaviour) has no link to attach to and will never match; keep those on the whole scan. Mixing the two kinds does not help either: AI verdicts and per-link detections reach the engine in different scan parts and are not evaluated together today, so such a combo fires under neither scope. Give a `\"url\"` rule at least one positive condition (`all_of` / `any_of` / `tag_category` + `count_gte`) — a config carrying only `none_of` matches every link that merely lacks those tags, and the API does not reject that on this path. Thresholds stay \"N or more\" (`count_gte` / `any_of_min`) in both scopes; no other `match_scope` value is accepted."New value: +"Rule-type-specific configuration object. Shape depends on `rule_type`. For `rule_type='regexp_request_url'` and `rule_type='regexp_request_body'`, `config` must be exactly `{ pattern: string, flags?: '' | 'i' }`: pattern is non-empty and at most 4,096 characters; omit flags or use `''` for case-sensitive matching, or `'i'` for case-insensitive matching. `target` must be `'page'` for both. `regexp_request_url` inspects up to 5,000 captured request URLs on a fresh scan; tests and rechecks of stored scans reconstruct main-frame hops plus up to 200 persisted subrequests with selected resource types omitted, so historical matching is best-effort. `regexp_request_body` inspects the CONTENTS of the page's scripts, fetch/XHR responses and iframe documents — never images, video, fonts or stylesheets — capped at 400 resources, 128 KB each and 8 MB per scan. Those contents are kept for ONE DAY, so a test or recheck against an older scan reports no match because there is nothing left to read. `regexp_url` remains redirect-chain-only. For `rule_type='llm'` the shape is `{ prompt: string, tags: { <tag_slug>: <description>, ... } }`; each key in `config.tags` is auto-registered as a custom tag definition AND must not collide with a system slug (same 422 contract as `tag_slug`). For `rule_type='combo'` the optional rule-level key `match_scope` decides where conditions are counted. `\"scan\"` (the default, and the behaviour when the key is absent) checks them against the union of all tags on the scan. With `\"url\"`, every condition must be satisfied by tags on the same link, and the tag is assigned to that link — so a rule built only from link-less tags (AI verdicts, crawler behaviour) has no link to attach to and will never match; keep those on the whole scan. Mixing the two kinds does not help either: AI verdicts and per-link detections reach the engine in different scan parts and are not evaluated together today, so such a combo fires under neither scope. Give a `\"url\"` rule at least one positive condition (`all_of` / `any_of` / `tag_category` + `count_gte`) — a config carrying only `none_of` matches every link that merely lacks those tags, and the API does not reject that on this path. Thresholds stay \"N or more\" (`count_gte` / `any_of_min`) in both scopes; no other `match_scope` value is accepted."
      • changedInput schema / properties / rule_type / description
        Previous value: -"Rule engine. One of: `stopword_content`, `stopword_url`, `regexp_content`, `regexp_url`, `regexp_request_url`, `blacklist_domain`, `combo`, `llm`. `regexp_url` checks redirect-chain URLs only; `regexp_request_url` checks captured network and subresource URLs. The API validates."New value: +"Rule engine. One of: `stopword_content`, `stopword_url`, `regexp_content`, `regexp_url`, `regexp_request_url`, `regexp_request_body`, `blacklist_domain`, `combo`, `llm`. `regexp_url` checks redirect-chain URLs only; `regexp_request_url` checks captured network and subresource URLs; `regexp_request_body` checks what those sub-resources contained. The API validates."
      • changedInput schema / properties / target / description
        Previous value: -"Where to apply the rule (e.g. 'page' for landing HTML). `regexp_request_url` requires `target='page'`. Default: page. See API docs for the full set of valid values."New value: +"Where to apply the rule (e.g. 'page' for landing HTML). `regexp_request_url` and `regexp_request_body` require `target='page'`. Default: page. See API docs for the full set of valid values."
    • Changedcreate_scan1 field changed
      • addedInput schema / properties / max_discovered_ads
        Added value: +{
        +  "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 — one parent plus its children. Only valid on an ad-discovery target — `ad_discovery: true` on a scan, or `campaign_type: \"ad_discovery\"` on a campaign — and rejected with 422 anywhere else. Omit it to use the platform default. The platform default is 12 unless an operator retuned it.",
        +  "maximum": 25,
        +  "minimum": 1,
        +  "type": "integer"
        +}
    • Changedtest_custom_rule4 fields changed
      • changedInput schema / properties / config / anyOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "flags": {
        -        "description": "Omit or use '' for case-sensitive matching; use 'i' to ignore case.",
        -        "enum": [
        -          "",
        -          "i"
        -        ],
        -        "type": "string"
        -      },
        -      "pattern": {
        -        "description": "Non-empty request-URL regular expression, at most 4,096 characters.",
        -        "maxLength": 4096,
        -        "minLength": 1,
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "pattern"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": {},
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "flags": {
        +        "description": "Omit or use '' for case-sensitive matching; use 'i' to ignore case.",
        +        "enum": [
        +          "",
        +          "i"
        +        ],
        +        "type": "string"
        +      },
        +      "pattern": {
        +        "description": "Non-empty regular expression, at most 4,096 characters.",
        +        "maxLength": 4096,
        +        "minLength": 1,
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "pattern"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": {},
        +    "type": "object"
        +  }
        +]
      • changedInput schema / properties / config / description
        Previous value: -"Rule-type-specific config to test. Same shape as `create_custom_rule`'s `config`. For `rule_type='regexp_request_url'`, `config` must be exactly `{ pattern: string, flags?: '' | 'i' }`: pattern is non-empty and at most 4,096 characters; omit flags or use `''` for case-sensitive matching, or `'i'` for case-insensitive matching. `target` must be `'page'`. Fresh scans inspect up to 5,000 captured request URLs. Tests and rechecks of stored scans reconstruct main-frame hops plus up to 200 persisted subrequests with selected resource types omitted, so historical matching is best-effort. `regexp_url` remains redirect-chain-only. NOTE: `test_custom_rule` evaluates the rule against a scan WITHOUT persisting it, so slug-collision validation does NOT run here — verify slugs against `list_tags` (`scope=system`) before promoting to `create_custom_rule`. For `rule_type='combo'` the optional rule-level key `match_scope` decides where conditions are counted. `\"scan\"` (the default, and the behaviour when the key is absent) checks them against the union of all tags on the scan. With `\"url\"`, every condition must be satisfied by tags on the same link, and the tag is assigned to that link — so a rule built only from link-less tags (AI verdicts, crawler behaviour) has no link to attach to and will never match; keep those on the whole scan. Mixing the two kinds does not help either: AI verdicts and per-link detections reach the engine in different scan parts and are not evaluated together today, so such a combo fires under neither scope. Give a `\"url\"` rule at least one positive condition (`all_of` / `any_of` / `tag_category` + `count_gte`) — a config carrying only `none_of` matches every link that merely lacks those tags, and the API does not reject that on this path. Thresholds stay \"N or more\" (`count_gte` / `any_of_min`) in both scopes; no other `match_scope` value is accepted."New value: +"Rule-type-specific config to test. Same shape as `create_custom_rule`'s `config`. For `rule_type='regexp_request_url'` and `rule_type='regexp_request_body'`, `config` must be exactly `{ pattern: string, flags?: '' | 'i' }`: pattern is non-empty and at most 4,096 characters; omit flags or use `''` for case-sensitive matching, or `'i'` for case-insensitive matching. `target` must be `'page'` for both. `regexp_request_url` inspects up to 5,000 captured request URLs on a fresh scan; tests and rechecks of stored scans reconstruct main-frame hops plus up to 200 persisted subrequests with selected resource types omitted, so historical matching is best-effort. `regexp_request_body` inspects the CONTENTS of the page's scripts, fetch/XHR responses and iframe documents — never images, video, fonts or stylesheets — capped at 400 resources, 128 KB each and 8 MB per scan. Those contents are kept for ONE DAY, so a test or recheck against an older scan reports no match because there is nothing left to read. `regexp_url` remains redirect-chain-only. NOTE: `test_custom_rule` evaluates the rule against a scan WITHOUT persisting it, so slug-collision validation does NOT run here — verify slugs against `list_tags` (`scope=system`) before promoting to `create_custom_rule`. For `rule_type='combo'` the optional rule-level key `match_scope` decides where conditions are counted. `\"scan\"` (the default, and the behaviour when the key is absent) checks them against the union of all tags on the scan. With `\"url\"`, every condition must be satisfied by tags on the same link, and the tag is assigned to that link — so a rule built only from link-less tags (AI verdicts, crawler behaviour) has no link to attach to and will never match; keep those on the whole scan. Mixing the two kinds does not help either: AI verdicts and per-link detections reach the engine in different scan parts and are not evaluated together today, so such a combo fires under neither scope. Give a `\"url\"` rule at least one positive condition (`all_of` / `any_of` / `tag_category` + `count_gte`) — a config carrying only `none_of` matches every link that merely lacks those tags, and the API does not reject that on this path. Thresholds stay \"N or more\" (`count_gte` / `any_of_min`) in both scopes; no other `match_scope` value is accepted."
      • changedInput schema / properties / rule_type / description
        Previous value: -"Rule engine type. One of: `stopword_content`, `stopword_url`, `regexp_content`, `regexp_url`, `regexp_request_url`, `blacklist_domain`, `combo`, `llm`. `regexp_url` checks redirect-chain URLs only; `regexp_request_url` checks captured network and subresource URLs."New value: +"Rule engine type. One of: `stopword_content`, `stopword_url`, `regexp_content`, `regexp_url`, `regexp_request_url`, `regexp_request_body`, `blacklist_domain`, `combo`, `llm`. `regexp_url` checks redirect-chain URLs only; `regexp_request_url` checks captured network and subresource URLs; `regexp_request_body` checks what those sub-resources contained."
      • changedInput schema / properties / target / description
        Previous value: -"Where to apply the rule (e.g. 'page' for landing HTML). `regexp_request_url` requires `target='page'`. See API docs for the full set of valid values."New value: +"Where to apply the rule (e.g. 'page' for landing HTML). `regexp_request_url` and `regexp_request_body` require `target='page'`. See API docs for the full set of valid values."
    • Changedupdate_campaign1 field changed
      • addedInput schema / properties / max_discovered_ads
        Added value: +{
        +  "anyOf": [
        +    {
        +      "maximum": 25,
        +      "minimum": 1,
        +      "type": "integer"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "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 — one parent plus its children. Only valid on an ad-discovery target — `ad_discovery: true` on a scan, or `campaign_type: \"ad_discovery\"` on a campaign — and rejected with 422 anywhere else. Omitting the field leaves the campaign's current setting unchanged; pass null to drop its own number and go back to the platform default. The platform default is 12 unless an operator retuned it."
        +}
    • Changedupdate_custom_rule3 fields changed
      • changedInput schema / properties / config / anyOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "flags": {
        -        "description": "Omit or use '' for case-sensitive matching; use 'i' to ignore case.",
        -        "enum": [
        -          "",
        -          "i"
        -        ],
        -        "type": "string"
        -      },
        -      "pattern": {
        -        "description": "Non-empty request-URL regular expression, at most 4,096 characters.",
        -        "maxLength": 4096,
        -        "minLength": 1,
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "pattern"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": {},
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "flags": {
        +        "description": "Omit or use '' for case-sensitive matching; use 'i' to ignore case.",
        +        "enum": [
        +          "",
        +          "i"
        +        ],
        +        "type": "string"
        +      },
        +      "pattern": {
        +        "description": "Non-empty regular expression, at most 4,096 characters.",
        +        "maxLength": 4096,
        +        "minLength": 1,
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "pattern"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": {},
        +    "type": "object"
        +  }
        +]
      • changedInput schema / properties / config / description
        Previous value: -"New rule-type-specific config object. Replaces the stored config wholesale — resend every key you want to keep, including a combo rule's `match_scope`. For `rule_type='llm'` the keys of `config.tags` are auto-registered as tag definitions; any key that collides with a system slug returns the same 422 contract. For `rule_type='regexp_request_url'`, `config` must be exactly `{ pattern: string, flags?: '' | 'i' }`: pattern is non-empty and at most 4,096 characters; omit flags or use `''` for case-sensitive matching, or `'i'` for case-insensitive matching. `target` must be `'page'`. Fresh scans inspect up to 5,000 captured request URLs. Tests and rechecks of stored scans reconstruct main-frame hops plus up to 200 persisted subrequests with selected resource types omitted, so historical matching is best-effort. Read the rule first because `rule_type` is immutable and is not repeated in this update input. For `rule_type='combo'` the optional rule-level key `match_scope` decides where conditions are counted. `\"scan\"` (the default, and the behaviour when the key is absent) checks them against the union of all tags on the scan. With `\"url\"`, every condition must be satisfied by tags on the same link, and the tag is assigned to that link — so a rule built only from link-less tags (AI verdicts, crawler behaviour) has no link to attach to and will never match; keep those on the whole scan. Mixing the two kinds does not help either: AI verdicts and per-link detections reach the engine in different scan parts and are not evaluated together today, so such a combo fires under neither scope. Give a `\"url\"` rule at least one positive condition (`all_of` / `any_of` / `tag_category` + `count_gte`) — a config carrying only `none_of` matches every link that merely lacks those tags, and the API does not reject that on this path. Thresholds stay \"N or more\" (`count_gte` / `any_of_min`) in both scopes; no other `match_scope` value is accepted."New value: +"New rule-type-specific config object. Replaces the stored config wholesale — resend every key you want to keep, including a combo rule's `match_scope`. For `rule_type='llm'` the keys of `config.tags` are auto-registered as tag definitions; any key that collides with a system slug returns the same 422 contract. For `rule_type='regexp_request_url'` and `rule_type='regexp_request_body'`, `config` must be exactly `{ pattern: string, flags?: '' | 'i' }`: pattern is non-empty and at most 4,096 characters; omit flags or use `''` for case-sensitive matching, or `'i'` for case-insensitive matching. `target` must be `'page'` for both. `regexp_request_url` inspects up to 5,000 captured request URLs on a fresh scan; tests and rechecks of stored scans reconstruct main-frame hops plus up to 200 persisted subrequests with selected resource types omitted, so historical matching is best-effort. `regexp_request_body` inspects the CONTENTS of the page's scripts, fetch/XHR responses and iframe documents — never images, video, fonts or stylesheets — capped at 400 resources, 128 KB each and 8 MB per scan. Those contents are kept for ONE DAY, so a test or recheck against an older scan reports no match because there is nothing left to read. Read the rule first because `rule_type` is immutable and is not repeated in this update input. For `rule_type='combo'` the optional rule-level key `match_scope` decides where conditions are counted. `\"scan\"` (the default, and the behaviour when the key is absent) checks them against the union of all tags on the scan. With `\"url\"`, every condition must be satisfied by tags on the same link, and the tag is assigned to that link — so a rule built only from link-less tags (AI verdicts, crawler behaviour) has no link to attach to and will never match; keep those on the whole scan. Mixing the two kinds does not help either: AI verdicts and per-link detections reach the engine in different scan parts and are not evaluated together today, so such a combo fires under neither scope. Give a `\"url\"` rule at least one positive condition (`all_of` / `any_of` / `tag_category` + `count_gte`) — a config carrying only `none_of` matches every link that merely lacks those tags, and the API does not reject that on this path. Thresholds stay \"N or more\" (`count_gte` / `any_of_min`) in both scopes; no other `match_scope` value is accepted."
      • changedInput schema / properties / target / description
        Previous value: -"Where to apply the rule. `regexp_request_url` is fixed to `page`; do not change it. See API docs for the valid targets of other rule types."New value: +"Where to apply the rule. `regexp_request_url` and `regexp_request_body` are fixed to `page`; do not change it. See API docs for the valid targets of other rule types."
  4. 7 tool updatesv0.16.0
    • Changedcreate_bulk_scans5 fields changed
      • changedInput schema / properties / proxy / description
        Previous value: -"Optional proxy geo targeting for the crawl. Omit to use the org default."New value: +"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."
      • changedInput schema / properties / proxy / properties / city / description
        Previous value: -"Proxy city targeting."New value: +"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 — a city from a different region passes validation but leaves the provider no exit node."
      • changedInput schema / properties / proxy / properties / isp / description
        Previous value: -"Proxy ISP targeting."New value: +"Proxy ISP, or mobile carrier when `proxy_type` is mobile. Use a value from `get_proxy_targeting`."
      • changedInput schema / properties / proxy / properties / proxy_type / description
        Previous value: -"Proxy network type. Default: residential."New value: +"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."
      • changedInput schema / properties / proxy / properties / region / description
        Previous value: -"Proxy region/state targeting."New value: +"Proxy region/state. Use a value from `get_proxy_targeting`; anything else is rejected with 422."
    • Changedcreate_campaign4 fields changed
      • changedInput schema / properties / proxy_city / description
        Previous value: -"Proxy city targeting."New value: +"Proxy city from `get_proxy_targeting`. If you also set `proxy_region`, take the city from a call made with that same region — a city from a different region passes validation but leaves the provider no exit node."
      • changedInput schema / properties / proxy_isp / description
        Previous value: -"Proxy ISP targeting."New value: +"Proxy ISP, or mobile carrier when `proxy_type` is mobile. Use a value from `get_proxy_targeting`."
      • changedInput schema / properties / proxy_region / description
        Previous value: -"Proxy region/state targeting (free-text; only honoured for a single country)."New value: +"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."
      • changedInput schema / properties / proxy_type / description
        Previous value: -"Proxy network type. Default: residential."New value: +"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."
    • Changedcreate_scan5 fields changed
      • changedInput schema / properties / proxy / description
        Previous value: -"Optional proxy geo targeting for the crawl. Omit to use the org default."New value: +"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."
      • changedInput schema / properties / proxy / properties / city / description
        Previous value: -"Proxy city targeting."New value: +"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 — a city from a different region passes validation but leaves the provider no exit node."
      • changedInput schema / properties / proxy / properties / isp / description
        Previous value: -"Proxy ISP targeting."New value: +"Proxy ISP, or mobile carrier when `proxy_type` is mobile. Use a value from `get_proxy_targeting`."
      • changedInput schema / properties / proxy / properties / proxy_type / description
        Previous value: -"Proxy network type. Default: residential."New value: +"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."
      • changedInput schema / properties / proxy / properties / region / description
        Previous value: -"Proxy region/state targeting."New value: +"Proxy region/state. Use a value from `get_proxy_targeting`; anything else is rejected with 422."
    • Addedget_proxy_targeting
    • Changedlist_tags1 field changed
      • changedInput schema / properties / include_archived / description
        Previous value: -"Include archived tag definitions, which are excluded by default. Archived tags still appear on the scans that carry them, so pass `true` when resolving a slug seen on an older scan."New value: +"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 — so this flag cannot resolve a slug seen on an older scan."
    • Addedunpublish_policy_set
    • Changedupdate_campaign4 fields changed
      • changedInput schema / properties / proxy_city / description
        Previous value: -"Proxy city targeting."New value: +"Proxy city from `get_proxy_targeting`. If you also set `proxy_region`, take the city from a call made with that same region — a city from a different region passes validation but leaves the provider no exit node."
      • changedInput schema / properties / proxy_isp / description
        Previous value: -"Proxy ISP targeting."New value: +"Proxy ISP, or mobile carrier when `proxy_type` is mobile. Use a value from `get_proxy_targeting`."
      • changedInput schema / properties / proxy_region / description
        Previous value: -"Proxy region/state targeting (free-text; only honoured for a single country)."New value: +"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."
      • changedInput schema / properties / proxy_type / description
        Previous value: -"Proxy network type. Default: residential."New value: +"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."
  5. 15 tool updatesv0.14.0
    • Addedattach_policy_set_campaigns
    • Addedbulk_update_alert_status
    • Addeddetach_policy_set_campaigns
    • Changedget_alert_stats7 fields changed
      • addedInput schema / properties / campaign_id
        Added value: +{
        +  "description": "Filter to one campaign's alerts.",
        +  "format": "uuid",
        +  "type": "string"
        +}
      • addedInput schema / properties / country_code
        Added value: +{
        +  "description": "Comma-separated ISO 3166-1 alpha-2 country codes, e.g. US,DE,JP.",
        +  "type": "string"
        +}
      • addedInput schema / properties / date_from
        Added value: +{
        +  "description": "ISO date (YYYY-MM-DD), inclusive lower bound on alert creation.",
        +  "format": "date",
        +  "type": "string"
        +}
      • addedInput schema / properties / date_to
        Added value: +{
        +  "description": "ISO date (YYYY-MM-DD), inclusive upper bound on alert creation.",
        +  "format": "date",
        +  "type": "string"
        +}
      • addedInput schema / properties / policy_set_id
        Added value: +{
        +  "description": "Comma-separated policy-set UUIDs. Matches alerts raised by any of them; see `list_policy_sets`.",
        +  "type": "string"
        +}
      • addedInput schema / properties / tag
        Added value: +{
        +  "description": "Comma-separated tag slugs. Matches alerts carrying any of them; see `list_tags`.",
        +  "type": "string"
        +}
      • addedInput schema / properties / timezone
        Added value: +{
        +  "description": "IANA timezone (e.g. 'Europe/Berlin') the date bounds are read in. Defaults to UTC. Omitting both dates spans all time.",
        +  "type": "string"
        +}
    • Addedget_scan_creative_html
    • Addedget_scan_creative_video
    • Addedget_scan_vast_xml
    • Changedlist_alerts6 fields changed
      • addedInput schema / properties / country_code
        Added value: +{
        +  "description": "Comma-separated ISO 3166-1 alpha-2 country codes, e.g. US,DE,JP.",
        +  "type": "string"
        +}
      • addedInput schema / properties / date_from
        Added value: +{
        +  "description": "ISO date (YYYY-MM-DD), inclusive lower bound on alert creation.",
        +  "format": "date",
        +  "type": "string"
        +}
      • addedInput schema / properties / date_to
        Added value: +{
        +  "description": "ISO date (YYYY-MM-DD), inclusive upper bound on alert creation.",
        +  "format": "date",
        +  "type": "string"
        +}
      • addedInput schema / properties / policy_set_id
        Added value: +{
        +  "description": "Comma-separated policy-set UUIDs. Matches alerts raised by any of them; see `list_policy_sets`.",
        +  "type": "string"
        +}
      • addedInput schema / properties / tag
        Added value: +{
        +  "description": "Comma-separated tag slugs. Matches alerts carrying any of them; see `list_tags`.",
        +  "type": "string"
        +}
      • addedInput schema / properties / timezone
        Added value: +{
        +  "description": "IANA timezone (e.g. 'Europe/Berlin') the date bounds are read in. Defaults to UTC. Omitting both dates spans all time.",
        +  "type": "string"
        +}
    • Changedlist_campaign_groups6 fields changed
      • addedInput schema / properties / created_from
        Added value: +{
        +  "description": "ISO date (YYYY-MM-DD), inclusive lower bound on the creation day.",
        +  "format": "date",
        +  "type": "string"
        +}
      • addedInput schema / properties / created_to
        Added value: +{
        +  "description": "ISO date (YYYY-MM-DD), inclusive upper bound on the creation day.",
        +  "format": "date",
        +  "type": "string"
        +}
      • addedInput schema / properties / last_run_from
        Added value: +{
        +  "description": "ISO date (YYYY-MM-DD), inclusive lower bound on the most recent run. Setting either last-run bound excludes anything that has never run.",
        +  "format": "date",
        +  "type": "string"
        +}
      • addedInput schema / properties / last_run_to
        Added value: +{
        +  "description": "ISO date (YYYY-MM-DD), inclusive upper bound on the most recent run.",
        +  "format": "date",
        +  "type": "string"
        +}
      • addedInput schema / properties / q
        Added value: +{
        +  "description": "Substring search against group name (case-insensitive).",
        +  "maxLength": 200,
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / timezone
        Added value: +{
        +  "description": "IANA timezone (e.g. 'Europe/Berlin') the date bounds are read in. Defaults to UTC.",
        +  "type": "string"
        +}
    • Changedlist_campaigns5 fields changed
      • addedInput schema / properties / created_from
        Added value: +{
        +  "description": "ISO date (YYYY-MM-DD), inclusive lower bound on the creation day.",
        +  "format": "date",
        +  "type": "string"
        +}
      • addedInput schema / properties / created_to
        Added value: +{
        +  "description": "ISO date (YYYY-MM-DD), inclusive upper bound on the creation day.",
        +  "format": "date",
        +  "type": "string"
        +}
      • addedInput schema / properties / last_run_from
        Added value: +{
        +  "description": "ISO date (YYYY-MM-DD), inclusive lower bound on the most recent run. Setting either last-run bound excludes anything that has never run.",
        +  "format": "date",
        +  "type": "string"
        +}
      • addedInput schema / properties / last_run_to
        Added value: +{
        +  "description": "ISO date (YYYY-MM-DD), inclusive upper bound on the most recent run.",
        +  "format": "date",
        +  "type": "string"
        +}
      • addedInput schema / properties / timezone
        Added value: +{
        +  "description": "IANA timezone (e.g. 'Europe/Berlin') the date bounds are read in. Defaults to UTC.",
        +  "type": "string"
        +}
    • Changedlist_custom_taxonomies1 field changed
      • addedInput schema / properties / include_inactive
        Added value: +{
        +  "description": "Include soft-deleted taxonomies, which are excluded by default. Pass `true` to find one to `restore_custom_taxonomy`, or to resolve a taxonomy id seen on an older scan.",
        +  "type": "boolean"
        +}
    • Addedlist_policy_set_campaigns
    • Changedlist_scans3 fields changed
      • addedInput schema / properties / parent_scan_id
        Added value: +{
        +  "description": "Filter to the ad-discovery child scans of one parent scan. Setting this lifts the default 7-day window, so old children stay reachable. `list_scan_children` is the paginated equivalent.",
        +  "format": "uuid",
        +  "type": "string"
        +}
      • changedInput schema / properties / status / description
        Previous value: -"Comma-separated statuses to filter by. Lifecycle values: pending, running, crawled, checking, checking_async, completed, partial, failed, cancelled."New value: +"Comma-separated statuses to filter by. Lifecycle values: pending, running, crawled, checking, checking_async, rechecking, completed, partial, failed, cancelled."
      • addedInput schema / properties / tag_match
        Added value: +{
        +  "description": "How multiple `tag` slugs combine: `any` (default) returns scans carrying at least one, `all` requires every one of them.",
        +  "enum": [
        +    "any",
        +    "all"
        +  ],
        +  "type": "string"
        +}
    • Changedlist_tags1 field changed
      • addedInput schema / properties / include_archived
        Added value: +{
        +  "description": "Include archived tag definitions, which are excluded by default. Archived tags still appear on the scans that carry them, so pass `true` when resolving a slug seen on an older scan.",
        +  "type": "boolean"
        +}
    • Changedset_campaign_alert_overrides3 fields changed
      • changedInput schema / properties / destination_ids / description
        Previous value: -"Destination UUIDs the mode acts on. Required for `include`/`exclude`; ignored for `inherit`."New value: +"Destination UUIDs to route to. Accepted ONLY with `mode: override` — the API rejects it for `inherit`/`silence`. An empty list with `override` routes nowhere, which is the same outcome as `silence`."
      • changedInput schema / properties / mode / description
        Previous value: -"Routing mode: `inherit` (use org defaults), `include` (route ONLY to listed destinations), `exclude` (route everywhere EXCEPT listed)."New value: +"Routing mode: `inherit` (fall back to the org-wide destinations), `override` (route ONLY to `destination_ids`), `silence` (send nothing for this campaign)."
      • changedInput schema / properties / mode / enum
        Previous value: -[
        -  "inherit",
        -  "include",
        -  "exclude"
        -]New value: +[
        +  "inherit",
        +  "override",
        +  "silence"
        +]
  6. 3 tool updatesv0.13.0
    • Changedcreate_custom_rule6 fields changed
      • removedInput schema / properties / config / additionalProperties
        Removed value: -{}
      • addedInput schema / properties / config / anyOf
        Added value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "flags": {
        +        "description": "Omit or use '' for case-sensitive matching; use 'i' to ignore case.",
        +        "enum": [
        +          "",
        +          "i"
        +        ],
        +        "type": "string"
        +      },
        +      "pattern": {
        +        "description": "Non-empty request-URL regular expression, at most 4,096 characters.",
        +        "maxLength": 4096,
        +        "minLength": 1,
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "pattern"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": {},
        +    "type": "object"
        +  }
        +]
      • changedInput schema / properties / config / description
        Previous value: -"Rule-type-specific configuration object. Shape depends on `rule_type`. For `rule_type='llm'` the shape is `{ prompt: string, tags: { <tag_slug>: <description>, ... } }`; each key in `config.tags` is auto-registered as a custom tag definition AND must not collide with a system slug (same 422 contract as `tag_slug`). For `rule_type='combo'` the optional rule-level key `match_scope` decides where conditions are counted. `\"scan\"` (the default, and the behaviour when the key is absent) checks them against the union of all tags on the scan. With `\"url\"`, every condition must be satisfied by tags on the same link, and the tag is assigned to that link — so a rule built only from link-less tags (AI verdicts, crawler behaviour) has no link to attach to and will never match; keep those on the whole scan. Mixing the two kinds does not help either: AI verdicts and per-link detections reach the engine in different scan parts and are not evaluated together today, so such a combo fires under neither scope. Give a `\"url\"` rule at least one positive condition (`all_of` / `any_of` / `tag_category` + `count_gte`) — a config carrying only `none_of` matches every link that merely lacks those tags, and the API does not reject that on this path. Thresholds stay \"N or more\" (`count_gte` / `any_of_min`) in both scopes; no other `match_scope` value is accepted."New value: +"Rule-type-specific configuration object. Shape depends on `rule_type`. For `rule_type='regexp_request_url'`, `config` must be exactly `{ pattern: string, flags?: '' | 'i' }`: pattern is non-empty and at most 4,096 characters; omit flags or use `''` for case-sensitive matching, or `'i'` for case-insensitive matching. `target` must be `'page'`. Fresh scans inspect up to 5,000 captured request URLs. Tests and rechecks of stored scans reconstruct main-frame hops plus up to 200 persisted subrequests with selected resource types omitted, so historical matching is best-effort. `regexp_url` remains redirect-chain-only. For `rule_type='llm'` the shape is `{ prompt: string, tags: { <tag_slug>: <description>, ... } }`; each key in `config.tags` is auto-registered as a custom tag definition AND must not collide with a system slug (same 422 contract as `tag_slug`). For `rule_type='combo'` the optional rule-level key `match_scope` decides where conditions are counted. `\"scan\"` (the default, and the behaviour when the key is absent) checks them against the union of all tags on the scan. With `\"url\"`, every condition must be satisfied by tags on the same link, and the tag is assigned to that link — so a rule built only from link-less tags (AI verdicts, crawler behaviour) has no link to attach to and will never match; keep those on the whole scan. Mixing the two kinds does not help either: AI verdicts and per-link detections reach the engine in different scan parts and are not evaluated together today, so such a combo fires under neither scope. Give a `\"url\"` rule at least one positive condition (`all_of` / `any_of` / `tag_category` + `count_gte`) — a config carrying only `none_of` matches every link that merely lacks those tags, and the API does not reject that on this path. Thresholds stay \"N or more\" (`count_gte` / `any_of_min`) in both scopes; no other `match_scope` value is accepted."
      • removedInput schema / properties / config / type
        Removed value: -"object"
      • changedInput schema / properties / rule_type / description
        Previous value: -"Rule engine. One of: `stopword_content`, `stopword_url`, `regexp_content`, `regexp_url`, `blacklist_domain`, `combo`, `llm`. The API validates."New value: +"Rule engine. One of: `stopword_content`, `stopword_url`, `regexp_content`, `regexp_url`, `regexp_request_url`, `blacklist_domain`, `combo`, `llm`. `regexp_url` checks redirect-chain URLs only; `regexp_request_url` checks captured network and subresource URLs. The API validates."
      • changedInput schema / properties / target / description
        Previous value: -"Where to apply the rule (e.g. 'page' for landing HTML). Default: page. See API docs for the full set of valid values."New value: +"Where to apply the rule (e.g. 'page' for landing HTML). `regexp_request_url` requires `target='page'`. Default: page. See API docs for the full set of valid values."
    • Changedtest_custom_rule6 fields changed
      • removedInput schema / properties / config / additionalProperties
        Removed value: -{}
      • addedInput schema / properties / config / anyOf
        Added value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "flags": {
        +        "description": "Omit or use '' for case-sensitive matching; use 'i' to ignore case.",
        +        "enum": [
        +          "",
        +          "i"
        +        ],
        +        "type": "string"
        +      },
        +      "pattern": {
        +        "description": "Non-empty request-URL regular expression, at most 4,096 characters.",
        +        "maxLength": 4096,
        +        "minLength": 1,
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "pattern"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": {},
        +    "type": "object"
        +  }
        +]
      • changedInput schema / properties / config / description
        Previous value: -"Rule-type-specific config to test. Same shape as `create_custom_rule`'s `config`. NOTE: `test_custom_rule` evaluates the rule against a scan WITHOUT persisting it, so slug-collision validation does NOT run here — verify slugs against `list_tags` (`scope=system`) before promoting to `create_custom_rule`. For `rule_type='combo'` the optional rule-level key `match_scope` decides where conditions are counted. `\"scan\"` (the default, and the behaviour when the key is absent) checks them against the union of all tags on the scan. With `\"url\"`, every condition must be satisfied by tags on the same link, and the tag is assigned to that link — so a rule built only from link-less tags (AI verdicts, crawler behaviour) has no link to attach to and will never match; keep those on the whole scan. Mixing the two kinds does not help either: AI verdicts and per-link detections reach the engine in different scan parts and are not evaluated together today, so such a combo fires under neither scope. Give a `\"url\"` rule at least one positive condition (`all_of` / `any_of` / `tag_category` + `count_gte`) — a config carrying only `none_of` matches every link that merely lacks those tags, and the API does not reject that on this path. Thresholds stay \"N or more\" (`count_gte` / `any_of_min`) in both scopes; no other `match_scope` value is accepted."New value: +"Rule-type-specific config to test. Same shape as `create_custom_rule`'s `config`. For `rule_type='regexp_request_url'`, `config` must be exactly `{ pattern: string, flags?: '' | 'i' }`: pattern is non-empty and at most 4,096 characters; omit flags or use `''` for case-sensitive matching, or `'i'` for case-insensitive matching. `target` must be `'page'`. Fresh scans inspect up to 5,000 captured request URLs. Tests and rechecks of stored scans reconstruct main-frame hops plus up to 200 persisted subrequests with selected resource types omitted, so historical matching is best-effort. `regexp_url` remains redirect-chain-only. NOTE: `test_custom_rule` evaluates the rule against a scan WITHOUT persisting it, so slug-collision validation does NOT run here — verify slugs against `list_tags` (`scope=system`) before promoting to `create_custom_rule`. For `rule_type='combo'` the optional rule-level key `match_scope` decides where conditions are counted. `\"scan\"` (the default, and the behaviour when the key is absent) checks them against the union of all tags on the scan. With `\"url\"`, every condition must be satisfied by tags on the same link, and the tag is assigned to that link — so a rule built only from link-less tags (AI verdicts, crawler behaviour) has no link to attach to and will never match; keep those on the whole scan. Mixing the two kinds does not help either: AI verdicts and per-link detections reach the engine in different scan parts and are not evaluated together today, so such a combo fires under neither scope. Give a `\"url\"` rule at least one positive condition (`all_of` / `any_of` / `tag_category` + `count_gte`) — a config carrying only `none_of` matches every link that merely lacks those tags, and the API does not reject that on this path. Thresholds stay \"N or more\" (`count_gte` / `any_of_min`) in both scopes; no other `match_scope` value is accepted."
      • removedInput schema / properties / config / type
        Removed value: -"object"
      • changedInput schema / properties / rule_type / description
        Previous value: -"Rule engine type. One of: `stopword_content`, `stopword_url`, `regexp_content`, `regexp_url`, `blacklist_domain`, `combo`, `llm`."New value: +"Rule engine type. One of: `stopword_content`, `stopword_url`, `regexp_content`, `regexp_url`, `regexp_request_url`, `blacklist_domain`, `combo`, `llm`. `regexp_url` checks redirect-chain URLs only; `regexp_request_url` checks captured network and subresource URLs."
      • changedInput schema / properties / target / description
        Previous value: -"Where to apply the rule (e.g. 'page' for landing HTML). See API docs for the full set of valid values."New value: +"Where to apply the rule (e.g. 'page' for landing HTML). `regexp_request_url` requires `target='page'`. See API docs for the full set of valid values."
    • Changedupdate_custom_rule7 fields changed
      • removedInput schema / properties / config / additionalProperties
        Removed value: -{}
      • addedInput schema / properties / config / anyOf
        Added value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "flags": {
        +        "description": "Omit or use '' for case-sensitive matching; use 'i' to ignore case.",
        +        "enum": [
        +          "",
        +          "i"
        +        ],
        +        "type": "string"
        +      },
        +      "pattern": {
        +        "description": "Non-empty request-URL regular expression, at most 4,096 characters.",
        +        "maxLength": 4096,
        +        "minLength": 1,
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "pattern"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": {},
        +    "type": "object"
        +  }
        +]
      • changedInput schema / properties / config / description
        Previous value: -"New rule-type-specific config object. Replaces the stored config wholesale — resend every key you want to keep, including a combo rule's `match_scope`. For `rule_type='llm'` the keys of `config.tags` are auto-registered as tag definitions; any key that collides with a system slug returns the same 422 contract. For `rule_type='combo'` the optional rule-level key `match_scope` decides where conditions are counted. `\"scan\"` (the default, and the behaviour when the key is absent) checks them against the union of all tags on the scan. With `\"url\"`, every condition must be satisfied by tags on the same link, and the tag is assigned to that link — so a rule built only from link-less tags (AI verdicts, crawler behaviour) has no link to attach to and will never match; keep those on the whole scan. Mixing the two kinds does not help either: AI verdicts and per-link detections reach the engine in different scan parts and are not evaluated together today, so such a combo fires under neither scope. Give a `\"url\"` rule at least one positive condition (`all_of` / `any_of` / `tag_category` + `count_gte`) — a config carrying only `none_of` matches every link that merely lacks those tags, and the API does not reject that on this path. Thresholds stay \"N or more\" (`count_gte` / `any_of_min`) in both scopes; no other `match_scope` value is accepted."New value: +"New rule-type-specific config object. Replaces the stored config wholesale — resend every key you want to keep, including a combo rule's `match_scope`. For `rule_type='llm'` the keys of `config.tags` are auto-registered as tag definitions; any key that collides with a system slug returns the same 422 contract. For `rule_type='regexp_request_url'`, `config` must be exactly `{ pattern: string, flags?: '' | 'i' }`: pattern is non-empty and at most 4,096 characters; omit flags or use `''` for case-sensitive matching, or `'i'` for case-insensitive matching. `target` must be `'page'`. Fresh scans inspect up to 5,000 captured request URLs. Tests and rechecks of stored scans reconstruct main-frame hops plus up to 200 persisted subrequests with selected resource types omitted, so historical matching is best-effort. Read the rule first because `rule_type` is immutable and is not repeated in this update input. For `rule_type='combo'` the optional rule-level key `match_scope` decides where conditions are counted. `\"scan\"` (the default, and the behaviour when the key is absent) checks them against the union of all tags on the scan. With `\"url\"`, every condition must be satisfied by tags on the same link, and the tag is assigned to that link — so a rule built only from link-less tags (AI verdicts, crawler behaviour) has no link to attach to and will never match; keep those on the whole scan. Mixing the two kinds does not help either: AI verdicts and per-link detections reach the engine in different scan parts and are not evaluated together today, so such a combo fires under neither scope. Give a `\"url\"` rule at least one positive condition (`all_of` / `any_of` / `tag_category` + `count_gte`) — a config carrying only `none_of` matches every link that merely lacks those tags, and the API does not reject that on this path. Thresholds stay \"N or more\" (`count_gte` / `any_of_min`) in both scopes; no other `match_scope` value is accepted."
      • removedInput schema / properties / config / type
        Removed value: -"object"
      • changedInput schema / properties / name / description
        Previous value: -"New display name. For non-LLM rules this also becomes the new `display_name` of the auto-registered tag definition."New value: +"New rule display name. For PERSONAL non-LLM rules this refreshes the auto-registered tag's display name. A same-slug GLOBAL rule keeps its separately managed tag metadata unchanged; use `update_tag_definition` for that tag."
      • changedInput schema / properties / tag_slug / description
        Previous value: -"New tag slug to assign on match. **MUST NOT collide with a built-in system tag slug** (see `list_tags` where `scope=system`); colliding requests return 422 with code `checking.system_slug_reserved`. Re-registering an existing custom slug refreshes its tag definition's `display_name` / `description`."New value: +"New tag slug to assign on match. **MUST NOT collide with a built-in system tag slug** (see `list_tags` where `scope=system`); colliding requests return 422 with code `checking.system_slug_reserved`. Leaving a GLOBAL rule on the same slug preserves its admin-managed tag metadata."
      • changedInput schema / properties / target / description
        Previous value: -"Where to apply the rule (e.g. 'page' for landing HTML). See API docs for the full set of valid values."New value: +"Where to apply the rule. `regexp_request_url` is fixed to `page`; do not change it. See API docs for the valid targets of other rule types."
  7. 11 tool updatesv0.11.0
    • Changedcreate_bulk_scans4 fields changed
      • addedInput schema / properties / referrer
        Added value: +{
        +  "description": "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 — 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.",
        +  "format": "uri",
        +  "maxLength": 2048,
        +  "pattern": "^https?:\\/\\/",
        +  "type": "string"
        +}
      • addedInput schema / properties / repeat_count
        Added value: +{
        +  "description": "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 — see that tool's description for the exact formula — 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.",
        +  "maximum": 20,
        +  "minimum": 1,
        +  "type": "integer"
        +}
      • addedInput schema / properties / repeat_mode
        Added value: +{
        +  "description": "How the repeats of one combination relate to each other. 'isolated' gives every repeat a fresh browser and a new IP, so the repeats are statistically independent. 'shared' runs all repeats of one combination in a single browser behind one IP, carrying cookies and localStorage from one repeat to the next — use it to reproduce a cloaker or a frequency cap that only misbehaves on the second or third visit. 'shared' is rejected with 422 on an ad-discovery target: when creating, that is `ad_discovery: true` on a scan or `campaign_type: \"ad_discovery\"` on a campaign; when updating a campaign, it is a campaign whose existing type is already ad_discovery, since campaign_type itself cannot be changed. Default: isolated.",
        +  "enum": [
        +    "isolated",
        +    "shared"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / retry_max_attempts
        Added value: +{
        +  "description": "Extra crawl attempts when a scan fails for a technical reason — dead proxy, navigation timeout, browser crash (0-5). Permanent failures are never retried. The same scan is reused and only a completed scan is billed, so a retry never double-charges. 0-5 is the API's default ceiling; an operator can lower it, and then a value accepted here still comes back as a 422 from the API. Default: 0.",
        +  "maximum": 5,
        +  "minimum": 0,
        +  "type": "integer"
        +}
    • Changedcreate_campaign7 fields changed
      • changedInput schema / properties / campaign_type / description
        Previous value: -"`url`, `ad_tag`, or `vast` — must match the target field below."New value: +"`url`, `ad_tag`, `vast`, or `ad_discovery` — must match the target field below. `ad_discovery` is a publisher-page scan: set `url`; each run detects the page's ad blocks and opens a child scan per detected ad."
      • changedInput schema / properties / campaign_type / enum
        Previous value: -[
        -  "url",
        -  "ad_tag",
        -  "vast"
        -]New value: +[
        +  "url",
        +  "ad_tag",
        +  "vast",
        +  "ad_discovery"
        +]
      • addedInput schema / properties / referrer
        Added value: +{
        +  "description": "Optional http(s) page URL every scan of this campaign is checked from. For `ad_tag` and `vast` campaigns this is the publisher page the tag is embedded in — 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). For `url` and `ad_discovery` campaigns this is where the visitor came from, sent in full as the Referer of the page request.",
        +  "format": "uri",
        +  "maxLength": 2048,
        +  "pattern": "^https?:\\/\\/",
        +  "type": "string"
        +}
      • addedInput schema / properties / repeat_count
        Added value: +{
        +  "description": "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 — see that tool's description for the exact formula — 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.",
        +  "maximum": 20,
        +  "minimum": 1,
        +  "type": "integer"
        +}
      • addedInput schema / properties / repeat_mode
        Added value: +{
        +  "description": "How the repeats of one combination relate to each other. 'isolated' gives every repeat a fresh browser and a new IP, so the repeats are statistically independent. 'shared' runs all repeats of one combination in a single browser behind one IP, carrying cookies and localStorage from one repeat to the next — use it to reproduce a cloaker or a frequency cap that only misbehaves on the second or third visit. 'shared' is rejected with 422 on an ad-discovery target: when creating, that is `ad_discovery: true` on a scan or `campaign_type: \"ad_discovery\"` on a campaign; when updating a campaign, it is a campaign whose existing type is already ad_discovery, since campaign_type itself cannot be changed. Default: isolated.",
        +  "enum": [
        +    "isolated",
        +    "shared"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / retry_max_attempts
        Added value: +{
        +  "description": "Extra crawl attempts when a scan fails for a technical reason — dead proxy, navigation timeout, browser crash (0-5). Permanent failures are never retried. The same scan is reused and only a completed scan is billed, so a retry never double-charges. 0-5 is the API's default ceiling; an operator can lower it, and then a value accepted here still comes back as a 422 from the API. Default: 0.",
        +  "maximum": 5,
        +  "minimum": 0,
        +  "type": "integer"
        +}
      • changedInput schema / properties / url / description
        Previous value: -"Target URL (required if campaign_type=url)."New value: +"Target URL (required if campaign_type=url or ad_discovery)."
    • Changedcreate_custom_rule1 field changed
      • changedInput schema / properties / config / description
        Previous value: -"Rule-type-specific configuration object. Shape depends on `rule_type`. For `rule_type='llm'` the shape is `{ prompt: string, tags: { <tag_slug>: <description>, ... } }`; each key in `config.tags` is auto-registered as a custom tag definition AND must not collide with a system slug (same 422 contract as `tag_slug`)."New value: +"Rule-type-specific configuration object. Shape depends on `rule_type`. For `rule_type='llm'` the shape is `{ prompt: string, tags: { <tag_slug>: <description>, ... } }`; each key in `config.tags` is auto-registered as a custom tag definition AND must not collide with a system slug (same 422 contract as `tag_slug`). For `rule_type='combo'` the optional rule-level key `match_scope` decides where conditions are counted. `\"scan\"` (the default, and the behaviour when the key is absent) checks them against the union of all tags on the scan. With `\"url\"`, every condition must be satisfied by tags on the same link, and the tag is assigned to that link — so a rule built only from link-less tags (AI verdicts, crawler behaviour) has no link to attach to and will never match; keep those on the whole scan. Mixing the two kinds does not help either: AI verdicts and per-link detections reach the engine in different scan parts and are not evaluated together today, so such a combo fires under neither scope. Give a `\"url\"` rule at least one positive condition (`all_of` / `any_of` / `tag_category` + `count_gte`) — a config carrying only `none_of` matches every link that merely lacks those tags, and the API does not reject that on this path. Thresholds stay \"N or more\" (`count_gte` / `any_of_min`) in both scopes; no other `match_scope` value is accepted."
    • Changedcreate_scan5 fields changed
      • addedInput schema / properties / ad_discovery
        Added value: +{
        +  "description": "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`.",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / referrer
        Added value: +{
        +  "description": "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 — 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.",
        +  "format": "uri",
        +  "maxLength": 2048,
        +  "pattern": "^https?:\\/\\/",
        +  "type": "string"
        +}
      • addedInput schema / properties / repeat_count
        Added value: +{
        +  "description": "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 — see that tool's description for the exact formula — 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.",
        +  "maximum": 20,
        +  "minimum": 1,
        +  "type": "integer"
        +}
      • addedInput schema / properties / repeat_mode
        Added value: +{
        +  "description": "How the repeats of one combination relate to each other. 'isolated' gives every repeat a fresh browser and a new IP, so the repeats are statistically independent. 'shared' runs all repeats of one combination in a single browser behind one IP, carrying cookies and localStorage from one repeat to the next — use it to reproduce a cloaker or a frequency cap that only misbehaves on the second or third visit. 'shared' is rejected with 422 on an ad-discovery target: when creating, that is `ad_discovery: true` on a scan or `campaign_type: \"ad_discovery\"` on a campaign; when updating a campaign, it is a campaign whose existing type is already ad_discovery, since campaign_type itself cannot be changed. Default: isolated.",
        +  "enum": [
        +    "isolated",
        +    "shared"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / retry_max_attempts
        Added value: +{
        +  "description": "Extra crawl attempts when a scan fails for a technical reason — dead proxy, navigation timeout, browser crash (0-5). Permanent failures are never retried. The same scan is reused and only a completed scan is billed, so a retry never double-charges. 0-5 is the API's default ceiling; an operator can lower it, and then a value accepted here still comes back as a 422 from the API. Default: 0.",
        +  "maximum": 5,
        +  "minimum": 0,
        +  "type": "integer"
        +}
    • Changedget_scan_landing_screenshot1 field changed
      • changedInput schema / properties / width / description
        Previous value: -"Optional resize width in pixels."New value: +"Optional resize width in pixels. The API top-crops a resized landing screenshot whose height exceeds 2.5x its width, so a long landing page comes back as its top region only — never conclude that something is absent from the page from a resized capture. Fetch without `width` when you need the whole page."
    • Changedget_scan_screenshot1 field changed
      • changedInput schema / properties / width / description
        Previous value: -"Optional resize width in pixels. The API resizes server-side to keep the image small for the agent's context window."New value: +"Optional resize width in pixels. The API resizes server-side to keep the image small for the agent's context window. It also top-crops a resized page screenshot whose height exceeds 2.5x its width, so a long page comes back as its top region only — never conclude that something is absent from the page from a resized capture. Fetch without `width` when you need the whole page."
    • Changedlist_balance_history3 fields changed
      • changedInput schema / properties / type / description
        Previous value: -"Filter by transaction kind. Pass several values to OR them (e.g. ['top_up_manual','crypto_top_up'] for credits-only)."New value: +"Filter by transaction kind. Pass several values to OR them (e.g. ['top_up_manual','crypto_top_up','card_top_up'] for credits-only)."
      • changedInput schema / properties / type / items / enum
        Previous value: -[
        -  "initial_balance",
        -  "top_up_manual",
        -  "usage_charge",
        -  "subscription_renewal",
        -  "subscription_upgrade",
        -  "admin_adjustment",
        -  "refund",
        -  "invoice_settlement",
        -  "crypto_top_up"
        -]New value: +[
        +  "initial_balance",
        +  "top_up_manual",
        +  "usage_charge",
        +  "subscription_renewal",
        +  "subscription_upgrade",
        +  "admin_adjustment",
        +  "refund",
        +  "invoice_settlement",
        +  "crypto_top_up",
        +  "card_top_up"
        +]
      • changedInput schema / properties / type / maxItems
        Previous value: -9New value: +10
    • Addedlist_scan_children
    • Changedtest_custom_rule1 field changed
      • changedInput schema / properties / config / description
        Previous value: -"Rule-type-specific config to test. Same shape as `create_custom_rule`'s `config`. NOTE: `test_custom_rule` evaluates the rule against a scan WITHOUT persisting it, so slug-collision validation does NOT run here — verify slugs against `list_tags` (`scope=system`) before promoting to `create_custom_rule`."New value: +"Rule-type-specific config to test. Same shape as `create_custom_rule`'s `config`. NOTE: `test_custom_rule` evaluates the rule against a scan WITHOUT persisting it, so slug-collision validation does NOT run here — verify slugs against `list_tags` (`scope=system`) before promoting to `create_custom_rule`. For `rule_type='combo'` the optional rule-level key `match_scope` decides where conditions are counted. `\"scan\"` (the default, and the behaviour when the key is absent) checks them against the union of all tags on the scan. With `\"url\"`, every condition must be satisfied by tags on the same link, and the tag is assigned to that link — so a rule built only from link-less tags (AI verdicts, crawler behaviour) has no link to attach to and will never match; keep those on the whole scan. Mixing the two kinds does not help either: AI verdicts and per-link detections reach the engine in different scan parts and are not evaluated together today, so such a combo fires under neither scope. Give a `\"url\"` rule at least one positive condition (`all_of` / `any_of` / `tag_category` + `count_gte`) — a config carrying only `none_of` matches every link that merely lacks those tags, and the API does not reject that on this path. Thresholds stay \"N or more\" (`count_gte` / `any_of_min`) in both scopes; no other `match_scope` value is accepted."
    • Changedupdate_campaign5 fields changed
      • addedInput schema / properties / referrer
        Added value: +{
        +  "anyOf": [
        +    {
        +      "format": "uri",
        +      "maxLength": 2048,
        +      "pattern": "^https?:\\/\\/",
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "Optional http(s) page URL every scan of this campaign is checked from. For `ad_tag` and `vast` campaigns this is the publisher page the tag is embedded in — 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). For `url` and `ad_discovery` campaigns this is where the visitor came from, sent in full as the Referer of the page request. Pass null to clear it."
        +}
      • addedInput schema / properties / repeat_count
        Added value: +{
        +  "description": "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 — see that tool's description for the exact formula — 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.",
        +  "maximum": 20,
        +  "minimum": 1,
        +  "type": "integer"
        +}
      • addedInput schema / properties / repeat_mode
        Added value: +{
        +  "description": "How the repeats of one combination relate to each other. 'isolated' gives every repeat a fresh browser and a new IP, so the repeats are statistically independent. 'shared' runs all repeats of one combination in a single browser behind one IP, carrying cookies and localStorage from one repeat to the next — use it to reproduce a cloaker or a frequency cap that only misbehaves on the second or third visit. 'shared' is rejected with 422 on an ad-discovery target: when creating, that is `ad_discovery: true` on a scan or `campaign_type: \"ad_discovery\"` on a campaign; when updating a campaign, it is a campaign whose existing type is already ad_discovery, since campaign_type itself cannot be changed. Default: isolated.",
        +  "enum": [
        +    "isolated",
        +    "shared"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / retry_max_attempts
        Added value: +{
        +  "description": "Extra crawl attempts when a scan fails for a technical reason — dead proxy, navigation timeout, browser crash (0-5). Permanent failures are never retried. The same scan is reused and only a completed scan is billed, so a retry never double-charges. 0-5 is the API's default ceiling; an operator can lower it, and then a value accepted here still comes back as a 422 from the API. Default: 0.",
        +  "maximum": 5,
        +  "minimum": 0,
        +  "type": "integer"
        +}
      • changedInput schema / properties / url / description
        Previous value: -"New target URL (url-type campaigns)."New value: +"New target URL (url-type and ad_discovery campaigns)."
    • Changedupdate_custom_rule1 field changed
      • changedInput schema / properties / config / description
        Previous value: -"New rule-type-specific config object. For `rule_type='llm'` the keys of `config.tags` are auto-registered as tag definitions; any key that collides with a system slug returns the same 422 contract."New value: +"New rule-type-specific config object. Replaces the stored config wholesale — resend every key you want to keep, including a combo rule's `match_scope`. For `rule_type='llm'` the keys of `config.tags` are auto-registered as tag definitions; any key that collides with a system slug returns the same 422 contract. For `rule_type='combo'` the optional rule-level key `match_scope` decides where conditions are counted. `\"scan\"` (the default, and the behaviour when the key is absent) checks them against the union of all tags on the scan. With `\"url\"`, every condition must be satisfied by tags on the same link, and the tag is assigned to that link — so a rule built only from link-less tags (AI verdicts, crawler behaviour) has no link to attach to and will never match; keep those on the whole scan. Mixing the two kinds does not help either: AI verdicts and per-link detections reach the engine in different scan parts and are not evaluated together today, so such a combo fires under neither scope. Give a `\"url\"` rule at least one positive condition (`all_of` / `any_of` / `tag_category` + `count_gte`) — a config carrying only `none_of` matches every link that merely lacks those tags, and the API does not reject that on this path. Thresholds stay \"N or more\" (`count_gte` / `any_of_min`) in both scopes; no other `match_scope` value is accepted."
  8. 7 tool updatesv0.8.0
    • Changedcreate_bulk_scans3 fields changed
      • changedInput schema / properties / ad_tag / description
        Previous value: -"Raw ad-tag HTML/JS. EITHER `url` OR `ad_tag` is required."New value: +"Raw ad-tag HTML/JS OR an http(s) URL of a page with the creative already rendered. Provide exactly one of `url`, `ad_tag`, or `vast_tag`."
      • changedInput schema / properties / url / description
        Previous value: -"Direct URL. EITHER `url` OR `ad_tag` is required."New value: +"Direct URL. Provide exactly one of `url`, `ad_tag`, or `vast_tag`."
      • addedInput schema / properties / vast_tag
        Added value: +{
        +  "description": "VAST video ad tag: an http(s) URL of a VAST endpoint OR raw VAST XML. Provide exactly one of `url`, `ad_tag`, or `vast_tag`.",
        +  "type": "string"
        +}
    • Changedcreate_campaign4 fields changed
      • changedInput schema / properties / ad_tag / description
        Previous value: -"Ad-tag HTML/JS (required if campaign_type=ad_tag)."New value: +"Ad-tag HTML/JS or an http(s) URL of a page with the rendered creative (required if campaign_type=ad_tag)."
      • changedInput schema / properties / campaign_type / description
        Previous value: -"`url` or `ad_tag` — must match the target field below."New value: +"`url`, `ad_tag`, or `vast` — must match the target field below."
      • changedInput schema / properties / campaign_type / enum
        Previous value: -[
        -  "url",
        -  "ad_tag"
        -]New value: +[
        +  "url",
        +  "ad_tag",
        +  "vast"
        +]
      • addedInput schema / properties / vast_tag
        Added value: +{
        +  "description": "VAST video ad tag: an http(s) URL of a VAST endpoint OR raw VAST XML (required if campaign_type=vast).",
        +  "type": "string"
        +}
    • Changedcreate_custom_rule1 field changed
      • changedInput schema / properties / tag_slug / description
        Previous value: -"Tag slug to assign on match. Empty = create-only (advanced). The API auto-registers a custom tag definition for this slug with `display_name = name`. **MUST NOT collide with a built-in system tag slug** (see `list_tags` where `is_system=true`); colliding requests return 422 with code `checking.system_slug_reserved`. For `rule_type='llm'` use `config.tags` keys instead and leave `tag_slug` empty."New value: +"Tag slug to assign on match. Empty = create-only (advanced). The API auto-registers a custom tag definition for this slug with `display_name = name`. **MUST NOT collide with a built-in system tag slug** (see `list_tags` where `scope=system`); colliding requests return 422 with code `checking.system_slug_reserved`. For `rule_type='llm'` use `config.tags` keys instead and leave `tag_slug` empty."
    • Changedcreate_scan3 fields changed
      • changedInput schema / properties / ad_tag / description
        Previous value: -"Raw HTML/JS ad tag (script, iframe, image). EITHER `url` OR `ad_tag` is required."New value: +"Raw HTML/JS ad tag (script, iframe, image) OR an http(s) URL of a page with the creative already rendered. Provide exactly one of `url`, `ad_tag`, or `vast_tag`."
      • changedInput schema / properties / url / description
        Previous value: -"Direct URL of the ad / landing page. EITHER `url` OR `ad_tag` is required."New value: +"Direct URL of the ad / landing page. Provide exactly one of `url`, `ad_tag`, or `vast_tag`."
      • addedInput schema / properties / vast_tag
        Added value: +{
        +  "description": "VAST video ad tag: an http(s) URL of a VAST endpoint OR raw VAST XML (a document containing a <VAST> element). Fetched and played in a real browser. Provide exactly one of `url`, `ad_tag`, or `vast_tag`.",
        +  "type": "string"
        +}
    • Changedtest_custom_rule1 field changed
      • changedInput schema / properties / config / description
        Previous value: -"Rule-type-specific config to test. Same shape as `create_custom_rule`'s `config`. NOTE: `test_custom_rule` evaluates the rule against a scan WITHOUT persisting it, so slug-collision validation does NOT run here — verify slugs against `list_tags` (`is_system=true`) before promoting to `create_custom_rule`."New value: +"Rule-type-specific config to test. Same shape as `create_custom_rule`'s `config`. NOTE: `test_custom_rule` evaluates the rule against a scan WITHOUT persisting it, so slug-collision validation does NOT run here — verify slugs against `list_tags` (`scope=system`) before promoting to `create_custom_rule`."
    • Changedupdate_campaign2 fields changed
      • changedInput schema / properties / ad_tag / description
        Previous value: -"New ad-tag HTML/JS (ad_tag-type campaigns)."New value: +"New ad-tag HTML/JS or an http(s) URL of a page with the rendered creative (ad_tag-type campaigns)."
      • addedInput schema / properties / vast_tag
        Added value: +{
        +  "description": "New VAST video ad tag: an http(s) URL of a VAST endpoint OR raw VAST XML (vast-type campaigns).",
        +  "type": "string"
        +}
    • Changedupdate_custom_rule1 field changed
      • changedInput schema / properties / tag_slug / description
        Previous value: -"New tag slug to assign on match. **MUST NOT collide with a built-in system tag slug** (see `list_tags` where `is_system=true`); colliding requests return 422 with code `checking.system_slug_reserved`. Re-registering an existing custom slug refreshes its tag definition's `display_name` / `description`."New value: +"New tag slug to assign on match. **MUST NOT collide with a built-in system tag slug** (see `list_tags` where `scope=system`); colliding requests return 422 with code `checking.system_slug_reserved`. Re-registering an existing custom slug refreshes its tag definition's `display_name` / `description`."
  9. 2 tool updatesv0.5.1
    • Changedlist_alerts2 fields changed
      • changedInput schema / properties / status / description
        Previous value: -"Filter by alert status. Open = unhandled; acknowledged = seen by an operator; resolved = closed; dismissed = closed without action."New value: +"Filter by alert status. Open = unhandled; escalated = flagged for attention; resolved = closed; dismissed = closed without action."
      • changedInput schema / properties / status / enum
        Previous value: -[
        -  "open",
        -  "acknowledged",
        -  "resolved",
        -  "dismissed"
        -]New value: +[
        +  "open",
        +  "escalated",
        +  "resolved",
        +  "dismissed"
        +]
    • Changedupdate_alert_status2 fields changed
      • changedInput schema / properties / status / description
        Previous value: -"New status: open | acknowledged | resolved | dismissed."New value: +"New status: open | escalated | resolved | dismissed."
      • changedInput schema / properties / status / enum
        Previous value: -[
        -  "open",
        -  "acknowledged",
        -  "resolved",
        -  "dismissed"
        -]New value: +[
        +  "open",
        +  "escalated",
        +  "resolved",
        +  "dismissed"
        +]
  10. 11 tool updatesv0.4.0
    • Changedcreate_bulk_scans1 field changed
      • addedInput schema / properties / proxy
        Added value: +{
        +  "additionalProperties": false,
        +  "description": "Optional proxy geo targeting for the crawl. Omit to use the org default.",
        +  "properties": {
        +    "city": {
        +      "description": "Proxy city targeting.",
        +      "type": "string"
        +    },
        +    "isp": {
        +      "description": "Proxy ISP targeting.",
        +      "type": "string"
        +    },
        +    "proxy_type": {
        +      "description": "Proxy network type. Default: residential.",
        +      "enum": [
        +        "residential",
        +        "mobile"
        +      ],
        +      "type": "string"
        +    },
        +    "region": {
        +      "description": "Proxy region/state targeting.",
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
    • Changedcreate_campaign11 fields changed
      • changedInput schema / properties / emulator_categories / description
        Previous value: -"Categories of device profiles to rotate through. Default: all available."New value: +"Device categories to rotate through, e.g. ['android_phone']. Valid: android_phone, android_tablet, iphone, ipad, windows_desktop, macos_desktop. On create, omitting this defaults to ['android_phone']; pass [] together with emulator_specific_ids to target ONLY specific devices."
      • addedInput schema / properties / emulator_mode
        Added value: +{
        +  "description": "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.",
        +  "enum": [
        +    "random",
        +    "all"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / emulator_specific_ids
        Added value: +{
        +  "description": "Pin exact device profile slugs from `list_emulators` (the `id` field), e.g. ['samsung_galaxy_s23_ultra_android16']. Always scanned regardless of emulator_mode.",
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / proxy_city
        Added value: +{
        +  "description": "Proxy city targeting.",
        +  "type": "string"
        +}
      • addedInput schema / properties / proxy_isp
        Added value: +{
        +  "description": "Proxy ISP targeting.",
        +  "type": "string"
        +}
      • addedInput schema / properties / proxy_region
        Added value: +{
        +  "description": "Proxy region/state targeting (free-text; only honoured for a single country).",
        +  "type": "string"
        +}
      • addedInput schema / properties / proxy_type
        Added value: +{
        +  "description": "Proxy network type. Default: residential.",
        +  "enum": [
        +    "residential",
        +    "mobile"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / schedule_interval_seconds
        Added value: +{
        +  "description": "Run interval for schedule_type='interval'. Allowed presets (seconds): 60, 120, 300, 600, 900, 1800, 2700, 3600, 7200, 14400, 28800, 86400.",
        +  "type": "integer"
        +}
      • addedInput schema / properties / schedule_timezone
        Added value: +{
        +  "description": "IANA timezone for the weekly grid, e.g. 'Europe/Berlin'. Default: UTC.",
        +  "type": "string"
        +}
      • addedInput schema / properties / schedule_type
        Added value: +{
        +  "description": "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.",
        +  "enum": [
        +    "weekly",
        +    "interval"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / schedule_weekly
        Added value: +{
        +  "additionalProperties": {
        +    "items": {
        +      "maximum": 23,
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "type": "array"
        +  },
        +  "description": "Weekly run grid for schedule_type='weekly'. Keys are weekdays '0'-'6' (Mon-Sun); values are hours 0-23 in schedule_timezone, e.g. { '0': [9, 17], '4': [12] }.",
        +  "type": "object"
        +}
    • Changedcreate_custom_rule4 fields changed
      • changedInput schema / properties / config / description
        Previous value: -"Rule-type-specific configuration object. Shape depends on rule_type."New value: +"Rule-type-specific configuration object. Shape depends on `rule_type`. For `rule_type='llm'` the shape is `{ prompt: string, tags: { <tag_slug>: <description>, ... } }`; each key in `config.tags` is auto-registered as a custom tag definition AND must not collide with a system slug (same 422 contract as `tag_slug`)."
      • changedInput schema / properties / name / description
        Previous value: -"Display name."New value: +"Display name. For non-LLM rules this also becomes the `display_name` of the auto-registered tag definition (see `tag_slug`)."
      • changedInput schema / properties / rule_type / description
        Previous value: -"Rule engine: regex | substring | iab_category | etc. (API validates)."New value: +"Rule engine. One of: `stopword_content`, `stopword_url`, `regexp_content`, `regexp_url`, `blacklist_domain`, `combo`, `llm`. The API validates."
      • changedInput schema / properties / tag_slug / description
        Previous value: -"Tag slug to assign on match. Empty = create-only (advanced)."New value: +"Tag slug to assign on match. Empty = create-only (advanced). The API auto-registers a custom tag definition for this slug with `display_name = name`. **MUST NOT collide with a built-in system tag slug** (see `list_tags` where `is_system=true`); colliding requests return 422 with code `checking.system_slug_reserved`. For `rule_type='llm'` use `config.tags` keys instead and leave `tag_slug` empty."
    • Changedcreate_scan1 field changed
      • addedInput schema / properties / proxy
        Added value: +{
        +  "additionalProperties": false,
        +  "description": "Optional proxy geo targeting for the crawl. Omit to use the org default.",
        +  "properties": {
        +    "city": {
        +      "description": "Proxy city targeting.",
        +      "type": "string"
        +    },
        +    "isp": {
        +      "description": "Proxy ISP targeting.",
        +      "type": "string"
        +    },
        +    "proxy_type": {
        +      "description": "Proxy network type. Default: residential.",
        +      "enum": [
        +        "residential",
        +        "mobile"
        +      ],
        +      "type": "string"
        +    },
        +    "region": {
        +      "description": "Proxy region/state targeting.",
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
    • Changedinvite_user1 field changed
      • addedInput schema / properties / timezone
        Added value: +{
        +  "description": "Optional IANA timezone for the invitee, e.g. 'Europe/Berlin'. Default: UTC.",
        +  "type": "string"
        +}
    • Changedtest_custom_rule2 fields changed
      • changedInput schema / properties / config / description
        Previous value: -"Rule-type-specific config to test."New value: +"Rule-type-specific config to test. Same shape as `create_custom_rule`'s `config`. NOTE: `test_custom_rule` evaluates the rule against a scan WITHOUT persisting it, so slug-collision validation does NOT run here — verify slugs against `list_tags` (`is_system=true`) before promoting to `create_custom_rule`."
      • changedInput schema / properties / rule_type / description
        Previous value: -"Rule engine type (regex, substring, ...)."New value: +"Rule engine type. One of: `stopword_content`, `stopword_url`, `regexp_content`, `regexp_url`, `blacklist_domain`, `combo`, `llm`."
    • Changedupdate_campaign14 fields changed
      • addedInput schema / properties / ad_tag
        Added value: +{
        +  "description": "New ad-tag HTML/JS (ad_tag-type campaigns).",
        +  "type": "string"
        +}
      • addedInput schema / properties / emulator_categories
        Added value: +{
        +  "description": "Device categories to rotate through, e.g. ['android_phone']. Valid: android_phone, android_tablet, iphone, ipad, windows_desktop, macos_desktop. On create, omitting this defaults to ['android_phone']; pass [] together with emulator_specific_ids to target ONLY specific devices.",
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / emulator_mode
        Added value: +{
        +  "description": "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.",
        +  "enum": [
        +    "random",
        +    "all"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / emulator_specific_ids
        Added value: +{
        +  "description": "Pin exact device profile slugs from `list_emulators` (the `id` field), e.g. ['samsung_galaxy_s23_ultra_android16']. Always scanned regardless of emulator_mode.",
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / group_id
        Added value: +{
        +  "description": "Move the campaign to another group.",
        +  "format": "uuid",
        +  "type": "string"
        +}
      • addedInput schema / properties / proxy_city
        Added value: +{
        +  "description": "Proxy city targeting.",
        +  "type": "string"
        +}
      • addedInput schema / properties / proxy_isp
        Added value: +{
        +  "description": "Proxy ISP targeting.",
        +  "type": "string"
        +}
      • addedInput schema / properties / proxy_region
        Added value: +{
        +  "description": "Proxy region/state targeting (free-text; only honoured for a single country).",
        +  "type": "string"
        +}
      • addedInput schema / properties / proxy_type
        Added value: +{
        +  "description": "Proxy network type. Default: residential.",
        +  "enum": [
        +    "residential",
        +    "mobile"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / schedule_interval_seconds
        Added value: +{
        +  "description": "Run interval for schedule_type='interval'. Allowed presets (seconds): 60, 120, 300, 600, 900, 1800, 2700, 3600, 7200, 14400, 28800, 86400.",
        +  "type": "integer"
        +}
      • addedInput schema / properties / schedule_timezone
        Added value: +{
        +  "description": "IANA timezone for the weekly grid, e.g. 'Europe/Berlin'. Default: UTC.",
        +  "type": "string"
        +}
      • addedInput schema / properties / schedule_type
        Added value: +{
        +  "description": "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.",
        +  "enum": [
        +    "weekly",
        +    "interval"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / schedule_weekly
        Added value: +{
        +  "additionalProperties": {
        +    "items": {
        +      "maximum": 23,
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "type": "array"
        +  },
        +  "description": "Weekly run grid for schedule_type='weekly'. Keys are weekdays '0'-'6' (Mon-Sun); values are hours 0-23 in schedule_timezone, e.g. { '0': [9, 17], '4': [12] }.",
        +  "type": "object"
        +}
      • addedInput schema / properties / url
        Added value: +{
        +  "description": "New target URL (url-type campaigns).",
        +  "format": "uri",
        +  "type": "string"
        +}
    • Changedupdate_campaign_group1 field changed
      • removedInput schema / properties / schedule_paused
        Removed value: -{
        -  "description": "Pause/resume the scheduler for every campaign in this group.",
        -  "type": "boolean"
        -}
    • Changedupdate_custom_rule3 fields changed
      • changedInput schema / properties / config / description
        Previous value: -"New rule-type-specific config object."New value: +"New rule-type-specific config object. For `rule_type='llm'` the keys of `config.tags` are auto-registered as tag definitions; any key that collides with a system slug returns the same 422 contract."
      • changedInput schema / properties / name / description
        Previous value: -"New display name."New value: +"New display name. For non-LLM rules this also becomes the new `display_name` of the auto-registered tag definition."
      • changedInput schema / properties / tag_slug / description
        Previous value: -"New tag slug to assign on match."New value: +"New tag slug to assign on match. **MUST NOT collide with a built-in system tag slug** (see `list_tags` where `is_system=true`); colliding requests return 422 with code `checking.system_slug_reserved`. Re-registering an existing custom slug refreshes its tag definition's `display_name` / `description`."
    • Changedupdate_org1 field changed
      • removedInput schema / properties / settings
        Removed value: -{
        -  "additionalProperties": {},
        -  "description": "Replacement settings object. Fields not supplied are left unchanged.",
        -  "type": "object"
        -}
    • Changedupdate_webhook3 fields changed
      • addedInput schema / properties / campaign_ids
        Added value: +{
        +  "description": "Restrict deliveries to these campaign UUIDs (replaces the current set).",
        +  "items": {
        +    "format": "uuid",
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / clear_campaign_ids
        Added value: +{
        +  "description": "Set true to remove the campaign restriction so the webhook fires for all campaigns.",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / description
        Added value: +{
        +  "description": "New human-readable label.",
        +  "maxLength": 256,
        +  "type": "string"
        +}
  11. 27 tool updatesv0.3.0
    • Addedcreate_custom_role
    • Addedcreate_custom_taxonomy
    • Changedcreate_policy_set7 fields changed
      • changedInput schema / properties / entries / description
        Previous value: -"At least one entry. Each entry pairs a tag-slug with country codes."New value: +"At least one entry. Each entry is a discriminated union over five rule kinds: tag / iab_v3 / brand / ai_category / custom_taxonomy."
      • removedInput schema / properties / entries / items / additionalProperties
        Removed value: -false
      • addedInput schema / properties / entries / items / anyOf
        Added value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "country_codes": {
        +        "description": "Restrict the rule to these countries (ISO 3166-1 alpha-2 / alpha-3). Empty = all.",
        +        "items": {
        +          "maxLength": 3,
        +          "minLength": 2,
        +          "type": "string"
        +        },
        +        "maxItems": 50,
        +        "type": "array"
        +      },
        +      "rule_type": {
        +        "const": "tag",
        +        "description": "Match a specific tag slug emitted by the scan pipeline.",
        +        "type": "string"
        +      },
        +      "tag_slug": {
        +        "description": "Tag slug (see `list_tags` for the catalogue).",
        +        "maxLength": 100,
        +        "minLength": 1,
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "rule_type",
        +      "tag_slug",
        +      "country_codes"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "country_codes": {
        +        "$ref": "#/properties/entries/items/anyOf/0/properties/country_codes"
        +      },
        +      "iab_v3": {
        +        "additionalProperties": false,
        +        "properties": {
        +          "tier1": {
        +            "description": "Top-level IAB Content Taxonomy V3 category (e.g. 'Sensitive Topics').",
        +            "maxLength": 200,
        +            "minLength": 1,
        +            "type": "string"
        +          },
        +          "tier2": {
        +            "anyOf": [
        +              {
        +                "maxLength": 200,
        +                "type": "string"
        +              },
        +              {
        +                "type": "null"
        +              }
        +            ],
        +            "description": "Sub-category (optional). Empty/null = subtree match."
        +          },
        +          "tier3": {
        +            "$ref": "#/properties/entries/items/anyOf/1/properties/iab_v3/properties/tier2",
        +            "description": "Sub-sub-category (optional)."
        +          },
        +          "tier4": {
        +            "$ref": "#/properties/entries/items/anyOf/1/properties/iab_v3/properties/tier2",
        +            "description": "Leaf-level category (optional). When all 4 tiers set, leaf-only match."
        +          }
        +        },
        +        "required": [
        +          "tier1"
        +        ],
        +        "type": "object"
        +      },
        +      "rule_type": {
        +        "const": "iab_v3",
        +        "description": "Match the scan's canonical IAB V3 category prefix.",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "rule_type",
        +      "iab_v3",
        +      "country_codes"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "brand": {
        +        "description": "Brand string.",
        +        "maxLength": 200,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "country_codes": {
        +        "$ref": "#/properties/entries/items/anyOf/0/properties/country_codes"
        +      },
        +      "rule_type": {
        +        "const": "brand",
        +        "description": "Match the scan's advertiser brand (case-insensitive).",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "rule_type",
        +      "brand",
        +      "country_codes"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "ai_category": {
        +        "additionalProperties": false,
        +        "properties": {
        +          "tier1": {
        +            "description": "Top-level freeform AI-generated category (e.g. 'Gambling').",
        +            "maxLength": 200,
        +            "minLength": 1,
        +            "type": "string"
        +          },
        +          "tier2": {
        +            "$ref": "#/properties/entries/items/anyOf/1/properties/iab_v3/properties/tier2",
        +            "description": "Sub-category (optional)."
        +          },
        +          "tier3": {
        +            "$ref": "#/properties/entries/items/anyOf/1/properties/iab_v3/properties/tier2",
        +            "description": "Sub-sub-category (optional)."
        +          },
        +          "tier4": {
        +            "$ref": "#/properties/entries/items/anyOf/1/properties/iab_v3/properties/tier2",
        +            "description": "Leaf-level category (optional)."
        +          }
        +        },
        +        "required": [
        +          "tier1"
        +        ],
        +        "type": "object"
        +      },
        +      "country_codes": {
        +        "$ref": "#/properties/entries/items/anyOf/0/properties/country_codes"
        +      },
        +      "rule_type": {
        +        "const": "ai_category",
        +        "description": "Match the freeform LLM-generated category prefix on the scan.",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "rule_type",
        +      "ai_category",
        +      "country_codes"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "country_codes": {
        +        "$ref": "#/properties/entries/items/anyOf/0/properties/country_codes"
        +      },
        +      "custom_taxonomy": {
        +        "additionalProperties": false,
        +        "properties": {
        +          "taxonomy_id": {
        +            "description": "ID of the per-org custom taxonomy (see `list_custom_taxonomies`).",
        +            "format": "uuid",
        +            "type": "string"
        +          },
        +          "tier1": {
        +            "description": "Top-level node name in the taxonomy.",
        +            "maxLength": 200,
        +            "minLength": 1,
        +            "type": "string"
        +          },
        +          "tier2": {
        +            "$ref": "#/properties/entries/items/anyOf/1/properties/iab_v3/properties/tier2",
        +            "description": "Tier 2 node name (optional)."
        +          },
        +          "tier3": {
        +            "$ref": "#/properties/entries/items/anyOf/1/properties/iab_v3/properties/tier2",
        +            "description": "Tier 3 node name (optional)."
        +          },
        +          "tier4": {
        +            "$ref": "#/properties/entries/items/anyOf/1/properties/iab_v3/properties/tier2",
        +            "description": "Leaf node name (optional)."
        +          }
        +        },
        +        "required": [
        +          "taxonomy_id",
        +          "tier1"
        +        ],
        +        "type": "object"
        +      },
        +      "rule_type": {
        +        "const": "custom_taxonomy",
        +        "description": "Match a per-org custom taxonomy node prefix on the scan.",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "rule_type",
        +      "custom_taxonomy",
        +      "country_codes"
        +    ],
        +    "type": "object"
        +  }
        +]
      • addedInput schema / properties / entries / items / description
        Added value: +"One policy rule. Discriminated by `rule_type`; populate the matching value-block (tag_slug / iab_v3 / brand / ai_category / custom_taxonomy)."
      • removedInput schema / properties / entries / items / properties
        Removed value: -{
        -  "country_codes": {
        -    "description": "Restrict the violation to these countries. Empty array = all countries.",
        -    "items": {
        -      "maxLength": 2,
        -      "minLength": 2,
        -      "type": "string"
        -    },
        -    "maxItems": 50,
        -    "type": "array"
        -  },
        -  "tag_slug": {
        -    "description": "Tag slug that triggers a violation.",
        -    "maxLength": 100,
        -    "minLength": 1,
        -    "type": "string"
        -  }
        -}
      • removedInput schema / properties / entries / items / required
        Removed value: -[
        -  "tag_slug",
        -  "country_codes"
        -]
      • removedInput schema / properties / entries / items / type
        Removed value: -"object"
    • Addeddelete_custom_taxonomy
    • Addedget_custom_taxonomy
    • Addedget_invoice_pdf
    • Addedget_scan_creative_screenshot
    • Addedget_scan_landing_screenshot
    • Addedget_scan_screenshot
    • Addedlist_account_labels
    • Changedlist_alerts2 fields changed
      • changedInput schema / properties / status / description
        Previous value: -"Filter by alert status."New value: +"Filter by alert status. Open = unhandled; acknowledged = seen by an operator; resolved = closed; dismissed = closed without action."
      • changedInput schema / properties / status / enum
        Previous value: -[
        -  "open",
        -  "ack",
        -  "resolved",
        -  "ignored"
        -]New value: +[
        +  "open",
        +  "acknowledged",
        +  "resolved",
        +  "dismissed"
        +]
    • Changedlist_balance_history1 field changed
      • addedInput schema / properties / type
        Added value: +{
        +  "description": "Filter by transaction kind. Pass several values to OR them (e.g. ['top_up_manual','crypto_top_up'] for credits-only).",
        +  "items": {
        +    "enum": [
        +      "initial_balance",
        +      "top_up_manual",
        +      "usage_charge",
        +      "subscription_renewal",
        +      "subscription_upgrade",
        +      "admin_adjustment",
        +      "refund",
        +      "invoice_settlement",
        +      "crypto_top_up"
        +    ],
        +    "type": "string"
        +  },
        +  "maxItems": 9,
        +  "type": "array"
        +}
    • Changedlist_campaigns2 fields changed
      • addedInput schema / properties / archived
        Added value: +{
        +  "description": "When omitted, the API returns active campaigns only. Pass `true` to see archived campaigns, `false` for active-only (explicit).",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / q
        Added value: +{
        +  "description": "Substring search against campaign name (case-insensitive).",
        +  "maxLength": 200,
        +  "minLength": 1,
        +  "type": "string"
        +}
    • Changedlist_campaigns_picker4 fields changed
      • addedInput schema / properties / archived
        Added value: +{
        +  "description": "Pass true to include archived campaigns. Defaults to active-only.",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / group_id
        Added value: +{
        +  "description": "Filter to one campaign group.",
        +  "format": "uuid",
        +  "type": "string"
        +}
      • addedInput schema / properties / limit
        Added value: +{
        +  "description": "Maximum rows to return (default per API, typically 200).",
        +  "maximum": 500,
        +  "minimum": 1,
        +  "type": "integer"
        +}
      • addedInput schema / properties / q
        Added value: +{
        +  "description": "Substring search against campaign name (case-insensitive).",
        +  "maxLength": 200,
        +  "minLength": 1,
        +  "type": "string"
        +}
    • Addedlist_custom_taxonomies
    • Changedlist_invoices2 fields changed
      • addedInput schema / properties / status
        Added value: +{
        +  "description": "Filter by lifecycle status.",
        +  "enum": [
        +    "draft",
        +    "issued",
        +    "paid",
        +    "voided",
        +    "overdue"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / type
        Added value: +{
        +  "description": "Filter by invoice kind: proforma (advance bill) or final (issued after the period).",
        +  "enum": [
        +    "proforma",
        +    "final"
        +  ],
        +  "type": "string"
        +}
    • Changedlist_policy_sets1 field changed
      • addedInput schema / properties / visibility
        Added value: +{
        +  "description": "Narrow to one scope. `private` = org-owned only, `public` = Kaminari Ad-curated sets visible to every org. Omit the filter to see BOTH combined.",
        +  "enum": [
        +    "private",
        +    "public"
        +  ],
        +  "type": "string"
        +}
    • Changedlist_scans10 fields changed
      • addedInput schema / properties / ai_category
        Added value: +{
        +  "description": "Filter by the freeform LLM-generated category prefix on the scan (slash-separated tier path, e.g. 'Gambling/Online Casinos').",
        +  "type": "string"
        +}
      • addedInput schema / properties / brand
        Added value: +{
        +  "description": "Filter by detected advertiser brand (case-insensitive).",
        +  "type": "string"
        +}
      • addedInput schema / properties / campaign_id
        Added value: +{
        +  "description": "Filter to scans of one campaign.",
        +  "format": "uuid",
        +  "type": "string"
        +}
      • addedInput schema / properties / group_id
        Added value: +{
        +  "description": "Filter to scans of one campaign group.",
        +  "format": "uuid",
        +  "type": "string"
        +}
      • addedInput schema / properties / iab_category
        Added value: +{
        +  "description": "Filter by legacy IAB V2.2 category (only present on pre-P3 scans).",
        +  "type": "string"
        +}
      • addedInput schema / properties / iab_v3_category
        Added value: +{
        +  "description": "Filter by canonical IAB Content Taxonomy V3 prefix (slash-separated tier path).",
        +  "type": "string"
        +}
      • addedInput schema / properties / labels
        Added value: +{
        +  "additionalProperties": {
        +    "maxLength": 200,
        +    "minLength": 1,
        +    "type": "string"
        +  },
        +  "description": "Dynamic label filters as a flat object: { brand_safety: 'high', vertical: 'gambling' }. Keys are snake_case and must exist in the org's label catalogue. Each key becomes a `label_<key>=<value>` query param. See `list_account_labels`.",
        +  "propertyNames": {
        +    "maxLength": 100,
        +    "minLength": 1,
        +    "pattern": "^[a-z0-9_]+$"
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / run_id
        Added value: +{
        +  "description": "Filter to scans of one run.",
        +  "format": "uuid",
        +  "type": "string"
        +}
      • changedInput schema / properties / status / description
        Previous value: -"Comma-separated statuses to filter by. One of: pending, running, done, failed, cancelled."New value: +"Comma-separated statuses to filter by. Lifecycle values: pending, running, crawled, checking, checking_async, completed, partial, failed, cancelled."
      • addedInput schema / properties / timezone
        Added value: +{
        +  "description": "IANA timezone (e.g. 'Europe/Berlin') applied to date_from / date_to. Defaults to UTC.",
        +  "type": "string"
        +}
    • Changedlist_tags1 field changed
      • addedInput schema / properties / category
        Added value: +{
        +  "description": "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.",
        +  "maxLength": 100,
        +  "minLength": 1,
        +  "type": "string"
        +}
    • Changedlist_usage4 fields changed
      • changedInput schema / properties / date_from / description
        Previous value: -"ISO date (YYYY-MM-DD), inclusive."New value: +"ISO 8601 datetime (with timezone offset), inclusive lower bound on the usage timestamp. Plain dates also work — the API normalises to UTC midnight."
      • changedInput schema / properties / date_from / format
        Previous value: -"date"New value: +"date-time"
      • changedInput schema / properties / date_to / description
        Previous value: -"ISO date (YYYY-MM-DD), inclusive."New value: +"ISO 8601 datetime (with offset), inclusive upper bound."
      • changedInput schema / properties / date_to / format
        Previous value: -"date"New value: +"date-time"
    • Changedlist_webhook_deliveries3 fields changed
      • addedInput schema / properties / from_ts
        Added value: +{
        +  "description": "ISO 8601 datetime (with offset), inclusive lower bound on attempt time.",
        +  "format": "date-time",
        +  "type": "string"
        +}
      • addedInput schema / properties / success
        Added value: +{
        +  "description": "Filter to delivered (true) or failed (false) attempts only.",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / to_ts
        Added value: +{
        +  "description": "ISO 8601 datetime (with offset), inclusive upper bound.",
        +  "format": "date-time",
        +  "type": "string"
        +}
    • Addedparse_custom_taxonomy_text
    • Addedrestore_custom_taxonomy
    • Addedupdate_account_labels
    • Addedupdate_custom_taxonomy
    • Changedupdate_policy_set7 fields changed
      • changedInput schema / properties / entries / description
        Previous value: -"REPLACEMENT entries list — REPLACES the current list, not a merge."New value: +"REPLACEMENT entries list — REPLACES the current list, not a merge. Each entry is a discriminated union over five rule kinds (tag / iab_v3 / brand / ai_category / custom_taxonomy)."
      • removedInput schema / properties / entries / items / additionalProperties
        Removed value: -false
      • addedInput schema / properties / entries / items / anyOf
        Added value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "country_codes": {
        +        "description": "Restrict the rule to these countries (ISO 3166-1 alpha-2 / alpha-3). Empty = all.",
        +        "items": {
        +          "maxLength": 3,
        +          "minLength": 2,
        +          "type": "string"
        +        },
        +        "maxItems": 50,
        +        "type": "array"
        +      },
        +      "rule_type": {
        +        "const": "tag",
        +        "description": "Match a specific tag slug emitted by the scan pipeline.",
        +        "type": "string"
        +      },
        +      "tag_slug": {
        +        "description": "Tag slug (see `list_tags` for the catalogue).",
        +        "maxLength": 100,
        +        "minLength": 1,
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "rule_type",
        +      "tag_slug",
        +      "country_codes"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "country_codes": {
        +        "$ref": "#/properties/entries/items/anyOf/0/properties/country_codes"
        +      },
        +      "iab_v3": {
        +        "additionalProperties": false,
        +        "properties": {
        +          "tier1": {
        +            "description": "Top-level IAB Content Taxonomy V3 category (e.g. 'Sensitive Topics').",
        +            "maxLength": 200,
        +            "minLength": 1,
        +            "type": "string"
        +          },
        +          "tier2": {
        +            "anyOf": [
        +              {
        +                "maxLength": 200,
        +                "type": "string"
        +              },
        +              {
        +                "type": "null"
        +              }
        +            ],
        +            "description": "Sub-category (optional). Empty/null = subtree match."
        +          },
        +          "tier3": {
        +            "$ref": "#/properties/entries/items/anyOf/1/properties/iab_v3/properties/tier2",
        +            "description": "Sub-sub-category (optional)."
        +          },
        +          "tier4": {
        +            "$ref": "#/properties/entries/items/anyOf/1/properties/iab_v3/properties/tier2",
        +            "description": "Leaf-level category (optional). When all 4 tiers set, leaf-only match."
        +          }
        +        },
        +        "required": [
        +          "tier1"
        +        ],
        +        "type": "object"
        +      },
        +      "rule_type": {
        +        "const": "iab_v3",
        +        "description": "Match the scan's canonical IAB V3 category prefix.",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "rule_type",
        +      "iab_v3",
        +      "country_codes"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "brand": {
        +        "description": "Brand string.",
        +        "maxLength": 200,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "country_codes": {
        +        "$ref": "#/properties/entries/items/anyOf/0/properties/country_codes"
        +      },
        +      "rule_type": {
        +        "const": "brand",
        +        "description": "Match the scan's advertiser brand (case-insensitive).",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "rule_type",
        +      "brand",
        +      "country_codes"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "ai_category": {
        +        "additionalProperties": false,
        +        "properties": {
        +          "tier1": {
        +            "description": "Top-level freeform AI-generated category (e.g. 'Gambling').",
        +            "maxLength": 200,
        +            "minLength": 1,
        +            "type": "string"
        +          },
        +          "tier2": {
        +            "$ref": "#/properties/entries/items/anyOf/1/properties/iab_v3/properties/tier2",
        +            "description": "Sub-category (optional)."
        +          },
        +          "tier3": {
        +            "$ref": "#/properties/entries/items/anyOf/1/properties/iab_v3/properties/tier2",
        +            "description": "Sub-sub-category (optional)."
        +          },
        +          "tier4": {
        +            "$ref": "#/properties/entries/items/anyOf/1/properties/iab_v3/properties/tier2",
        +            "description": "Leaf-level category (optional)."
        +          }
        +        },
        +        "required": [
        +          "tier1"
        +        ],
        +        "type": "object"
        +      },
        +      "country_codes": {
        +        "$ref": "#/properties/entries/items/anyOf/0/properties/country_codes"
        +      },
        +      "rule_type": {
        +        "const": "ai_category",
        +        "description": "Match the freeform LLM-generated category prefix on the scan.",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "rule_type",
        +      "ai_category",
        +      "country_codes"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "country_codes": {
        +        "$ref": "#/properties/entries/items/anyOf/0/properties/country_codes"
        +      },
        +      "custom_taxonomy": {
        +        "additionalProperties": false,
        +        "properties": {
        +          "taxonomy_id": {
        +            "description": "ID of the per-org custom taxonomy (see `list_custom_taxonomies`).",
        +            "format": "uuid",
        +            "type": "string"
        +          },
        +          "tier1": {
        +            "description": "Top-level node name in the taxonomy.",
        +            "maxLength": 200,
        +            "minLength": 1,
        +            "type": "string"
        +          },
        +          "tier2": {
        +            "$ref": "#/properties/entries/items/anyOf/1/properties/iab_v3/properties/tier2",
        +            "description": "Tier 2 node name (optional)."
        +          },
        +          "tier3": {
        +            "$ref": "#/properties/entries/items/anyOf/1/properties/iab_v3/properties/tier2",
        +            "description": "Tier 3 node name (optional)."
        +          },
        +          "tier4": {
        +            "$ref": "#/properties/entries/items/anyOf/1/properties/iab_v3/properties/tier2",
        +            "description": "Leaf node name (optional)."
        +          }
        +        },
        +        "required": [
        +          "taxonomy_id",
        +          "tier1"
        +        ],
        +        "type": "object"
        +      },
        +      "rule_type": {
        +        "const": "custom_taxonomy",
        +        "description": "Match a per-org custom taxonomy node prefix on the scan.",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "rule_type",
        +      "custom_taxonomy",
        +      "country_codes"
        +    ],
        +    "type": "object"
        +  }
        +]
      • addedInput schema / properties / entries / items / description
        Added value: +"One policy rule. Discriminated by `rule_type`; populate the matching value-block (tag_slug / iab_v3 / brand / ai_category / custom_taxonomy)."
      • removedInput schema / properties / entries / items / properties
        Removed value: -{
        -  "country_codes": {
        -    "items": {
        -      "maxLength": 2,
        -      "minLength": 2,
        -      "type": "string"
        -    },
        -    "maxItems": 50,
        -    "type": "array"
        -  },
        -  "tag_slug": {
        -    "maxLength": 100,
        -    "minLength": 1,
        -    "type": "string"
        -  }
        -}
      • removedInput schema / properties / entries / items / required
        Removed value: -[
        -  "tag_slug",
        -  "country_codes"
        -]
      • removedInput schema / properties / entries / items / type
        Removed value: -"object"
    • Changedupdate_tag_definition2 fields changed
      • removedInput schema / properties / show_in_public_report
        Removed value: -{
        -  "description": "Whether the tag appears in the public scan-report view.",
        -  "type": "boolean"
        -}
      • addedInput schema / properties / visibility
        Added value: +{
        +  "description": "Tag visibility on the scan report: hidden = not surfaced; internal = visible to org members; public = appears in the public scan-share view.",
        +  "enum": [
        +    "hidden",
        +    "internal",
        +    "public"
        +  ],
        +  "type": "string"
        +}
  12. 5 tool updatesv0.2.0
    • Changedcreate_custom_rule1 field changed
      • changedInput schema / properties / target / description
        Previous value: -"Where to apply: page | offer_url | html. Default: page."New value: +"Where to apply the rule (e.g. 'page' for landing HTML). Default: page. See API docs for the full set of valid values."
    • Addedlist_campaigns_picker
    • Changedlist_policy_sets2 fields changed
      • addedInput schema / properties / limit
        Added value: +{
        +  "default": 50,
        +  "description": "Page size.",
        +  "maximum": 200,
        +  "minimum": 1,
        +  "type": "integer"
        +}
      • addedInput schema / properties / page
        Added value: +{
        +  "default": 1,
        +  "description": "1-indexed page number.",
        +  "maximum": 500,
        +  "minimum": 1,
        +  "type": "integer"
        +}
    • Changedtest_custom_rule1 field changed
      • changedInput schema / properties / target / description
        Previous value: -"Where to apply the rule: page / offer_url / html."New value: +"Where to apply the rule (e.g. 'page' for landing HTML). See API docs for the full set of valid values."
    • Changedupdate_custom_rule1 field changed
      • changedInput schema / properties / target / description
        Previous value: -"Where to apply: page / offer_url / html."New value: +"Where to apply the rule (e.g. 'page' for landing HTML). See API docs for the full set of valid values."
  13. 82 tool updatesv0.1.1
    • First observedarchive_campaign
    • First observedarchive_campaign_group
    • First observedbulk_replay_webhook
    • First observedcancel_campaign
    • First observedcancel_campaign_group
    • First observedcancel_run
    • First observedcancel_scan
    • First observedcreate_api_key
    • First observedcreate_bulk_scans
    • First observedcreate_campaign
    • First observedcreate_campaign_group
    • First observedcreate_custom_rule
    • First observedcreate_policy_set
    • First observedcreate_scan
    • First observedcreate_webhook
    • First observeddelete_alert_destination
    • First observeddelete_custom_rule
    • First observeddelete_policy_set
    • First observeddelete_tag_definition
    • First observeddelete_webhook
    • First observedget_account
    • First observedget_alert_stats
    • First observedget_billing_summary
    • First observedget_campaign
    • First observedget_campaign_alert_overrides
    • First observedget_campaign_group
    • First observedget_custom_rule
    • First observedget_policy_set
    • First observedget_run
    • First observedget_scan
    • First observedget_tag_definition
    • First observedget_usage_summary
    • First observedget_webhook
    • First observedinvite_user
    • First observedlist_alert_destinations
    • First observedlist_alerts
    • First observedlist_api_keys
    • First observedlist_balance_history
    • First observedlist_campaign_groups
    • First observedlist_campaign_runs
    • First observedlist_campaigns
    • First observedlist_custom_rules
    • First observedlist_emulators
    • First observedlist_geos
    • First observedlist_invoices
    • First observedlist_org_roles
    • First observedlist_org_users
    • First observedlist_policy_sets
    • First observedlist_run_scans
    • First observedlist_scan_tags
    • First observedlist_scans
    • First observedlist_tags
    • First observedlist_usage
    • First observedlist_webhook_deliveries
    • First observedlist_webhook_event_types
    • First observedlist_webhooks
    • First observedpause_campaign_group_schedule
    • First observedrecheck_scans
    • First observedremove_user
    • First observedreplay_webhook_delivery
    • First observedrequest_policy_set_approval
    • First observedresume_campaign_group_schedule
    • First observedrevoke_api_key
    • First observedrotate_webhook_secret
    • First observedrun_campaign
    • First observedrun_campaign_group
    • First observedset_alert_destination_version
    • First observedset_campaign_alert_overrides
    • First observedtest_custom_rule
    • First observedtest_webhook
    • First observedtransfer_ownership
    • First observedunarchive_campaign
    • First observedunarchive_campaign_group
    • First observedupdate_alert_status
    • First observedupdate_campaign
    • First observedupdate_campaign_group
    • First observedupdate_custom_rule
    • First observedupdate_org
    • First observedupdate_policy_set
    • First observedupdate_tag_definition
    • First observedupdate_user_role
    • First observedupdate_webhook

TDQS

A3.9/5.0

Scored across 108 tools

Disambiguation4/5

Most tools have clearly distinct purposes (scans, campaigns, policy sets, webhooks, billing, org admin), but there are a few near-overlaps: list_campaigns vs list_campaigns_picker, list_scans vs list_run_scans, and the many get_scan_* artifact fetchers could confuse an agent at first glance. Descriptions are detailed enough to disambiguate most pairs.

Naming Consistency4/5

The vast majority follow a consistent verb_noun pattern (create_*, list_*, get_*, update_*, delete_*, cancel_*, archive_*). Minor deviations exist: set_default_policy_set vs update_policy_set, request_policy_set_approval vs unpublish_policy_set, and replay_webhook_delivery vs bulk_replay_webhook are slightly less uniform but still readable.

Tool Count2/5

108 tools is a very large surface for an MCP server. While the domain is broad (scanning, campaigns, policy, alerts, webhooks, billing, org admin), the count is excessive and will burden an agent's tool-selection context. Many tools could be consolidated (e.g., the 6+ get_scan_* artifact fetchers, the many campaign-group tools).

Completeness5/5

The tool surface is remarkably complete for the domain: full CRUD for campaigns, custom rules, policy sets, taxonomies, webhooks, org users, API keys, plus billing, alerts, usage, and scan artifacts. There are no obvious dead ends—every entity has create/read/update/delete or lifecycle equivalents, and cross-references (e.g., list_policy_set_campaigns before delete_policy_set) are explicitly documented.

Maintenance

ActivityActive
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    Not graded
    maintenance
    Enables AI assistants to execute penetration testing commands and security tools on Kali Linux remotely. Supports automated reconnaissance, vulnerability scanning, and CTF solving through integration with 25+ offensive security tools like nmap, gobuster, and nuclei.
    16
    -
  • F
    license
    Not graded
    quality
    D
    maintenance
    Enables AI agents to perform automated security testing through Caido, providing 10 security tools for vulnerability scanning (XSS, SQLi, command injection), HTTP request manipulation, and penetration testing workflows with whitelist protection.
    1
    -
  • F
    license
    Not graded
    quality
    C
    maintenance
    Connects AI assistants to the watchTowr Platform for real-time access to external attack surface data, findings, and threat intelligence. Provides 113 tools for querying and managing assets, findings, hunts, and more.
    -