Skip to main content
Glama
affset

affset MCP server

affset MCP server

An MCP server that lets a media buyer run affset from a chat client — pull stats, manage campaigns/zones/team, payouts, targeting, sub labels, and cut underperforming zones in plain language, no dashboard.

The tools wrap the existing affset tenant API. Connect through the hosted endpoint (OAuth, no API key) or run this package locally (Bearer token + X-Namespace). One connection serves one tenant.

Fastest way to connect — the hosted endpoint. Add https://mcp.affset.com/mcp as a remote MCP server in Claude (web or desktop), Cursor, Claude Code, or any client that supports streamable HTTP with OAuth: paste the URL, sign in with your affset email, keep Read-only (the consent default) or grant full access. Every connection shows up on the dashboard Integrations page and can be revoked individually. Setup guide: affset.com/integrations.

The npm package below is the self-host path: same tool roster, runs on your machine with an API key you manage yourself. Stdio defaults to full access unless you set AFFSET_READ_ONLY=true.

Tools

Tool

What it does

whoami

Show the tenant this server is bound to: namespace, API base, derived dashboard URL, and (when readable) company / timezone / custom API domain. Read-only.

get_stats

Traffic stats grouped by a dimension (date, campaign, zone, country, sub1–5, advertiser, publisher, …), optionally narrowed with advertiser_email/publisher_email filters (one user, any group_by). Returns clicks, conversions, CR, payout, media cost and ROI as a table. paid_only defaults to true (same as the dashboard) so CR excludes informative conversions. Sub columns use the tenant's sub labels when configured. Per-user groupings and filters are owner/manager plus the matching side's manager role.

list_campaigns

List campaigns (status / name filter, pagination).

get_campaign

One campaign's full record — every field (untruncated offer URL, exact schedule, budgets/pacing, silent flag, payout goal type) plus its targeting rules and payout rules, in one call.

list_zones

List traffic-source zones (status / name filter, pagination, linked source).

list_team

List team members (email, role, manager). Never returns API tokens.

create_team_member

Invite a team member (owner, manager, publisher, advertiser, publisher_manager, advertiser_manager). A scoped manager key can only create its own managed role, self-assigned. Returns the new API key oncelist_team never shows it again. Dry-run by default; confirm: true to apply.

create_campaign

Create a campaign from an advertiser email, offer URL, geo, payout and name. Defaults: CPA / rate 0, paused, global payout rule, and a ready tracking link (linked source template when configured; otherwise source_click_id={clickid} + sub placeholders). Dry-run by default; confirm: true to apply.

set_campaign_status

Run or pause a campaign (action: "run" | "pause"). Dry-run by default; confirm: true to apply. Running can hit the plan's active-campaign limit.

update_campaign

Partial update (name, offer URL, status, rate, budgets, dates, …). Dry-run by default; confirm: true to apply. Prefer set_campaign_status for run/pause.

create_zone

Create a traffic-source zone (name + optional postback/site/traffic-back URLs, optional traffic_source_id link). Always created active. Dry-run by default; confirm: true to apply.

update_zone

Partial update (name, status, URLs, traffic_source_id). Dry-run by default; confirm: true to apply. Pass null to clear a URL or unlink the source.

list_traffic_sources

List traffic sources — the networks bought from, each with the tracking/postback templates its linked zones use. API token shown only as set/none.

create_traffic_source

Create a traffic source, optionally from a network preset (exoclick, trafficstars, propellerads, adsterra, richads) that copies verified templates into an editable row. Dry-run by default; confirm: true to apply.

update_traffic_source

Partial update (name, templates, api_token, status). Linked zones pick the new tracking template up immediately. Dry-run by default; confirm: true to apply.

list_source_bids

The network campaigns of one traffic source with their current bids, read live from the network account (ExoClick, TrafficStars, RichAds — needs the source's API token): status, pricing model, bid in USD, last change that entered Affset's mutation stage. Read-only.

set_source_bid

Set one network campaign's bid in USD using its existing pricing model (for RichAds: CPM for pops, CPC for push/display). The dry run returns expected_current_bid; pass that value back with confirm: true to bind the write to the bid reviewed, so a concurrent change is refused rather than overwritten. Records the attempt in the source's bid history and reports applied only when the network echoes the new value. Raising a bid above 5× needs allow_large_increase: true. Dry-run by default.

get_zone_url

The /serve URL to paste into a network's campaign settings — rotates across the zone's active campaigns. A zone linked to a traffic source renders that source's tracking template; otherwise prefilled sub convention + optional cost macro. Warns when no active campaigns are visible.

get_tracking_link

The /track/click link for an existing campaign + zone — straight to one active campaign, with no rotation or targeting checks. Renders a linked source's template like get_zone_url. Re-derives what create_campaign echoed on create.

cut_zones

Blacklist underperforming zones on a campaign by threshold (CR / spend / ROI). Dry-run by default; confirm: true to apply.

list_payout_rules

List a campaign's global + per-zone payout rules and its payout_goal_type.

set_payout_rule

Upsert a global or zone-specific payout. Dry-run by default; confirm: true to apply.

delete_payout_rule

Delete a global or zone-specific payout rule. Dry-run by default; confirm: true to apply.

set_payout_goal

Set or clear payout_goal_type (goal-based conversions). Dry-run by default; confirm: true to apply.

list_targeting_types

Catalog of targeting rule types, flagging the seeded ones /serve never evaluates.

list_targeting_rules

List a campaign's targeting rules, flagging any that have no effect.

set_targeting_rule

Upsert one targeting rule (safe merge), normalised to what /serve matches. Dry-run by default; confirm: true to apply.

remove_targeting_rule

Remove one targeting rule by id or type+method. Dry-run by default; confirm: true to apply.

list_sub_labels

List tenant display names for sub1–sub5.

set_sub_labels

Set or clear sub labels (partial; null clears). Dry-run by default; confirm: true to apply.

list_conversions

List conversion audit records (payout, spend, pixel type, payload, postback). paid_only filters server-side; other optional filters are client-side on the current page.

Which URL do I give the network?

get_zone_url (/serve/{zone})

get_tracking_link (/track/click/{campaign}/{zone})

Picks the campaign

affset, from the zone's rotation

you, one fixed campaign

Needs an active campaign

yes — otherwise traffic back / unsold

yes — otherwise 404

Needs an active zone

yes

yes

Geo & targeting rules

enforced

not enforced

cost= lands on

the impression row

the click row

Use one or the other for a given traffic stream — never both with cost=, or the media cost is counted twice.

Both use the tenant's custom API domain when one is set, since the URL gets pasted into the network verbatim. Macros ({clickid}, [CLICK_ID], ${SUBID}) are inserted without percent-encoding — the source expands them before the request reaches affset.

cut_zones only ever adds zones to a campaign's blacklist, and does a read-merge-write so existing targeting rules are never touched.

create_campaign needs a traffic-source zone for the tracking link: pass zone_id, or let it auto-pick when the namespace has exactly one active zone. Campaigns are created paused; activate them before sending traffic through either URL. Both URL types also require an active zone. Geo whitelist is enforced in /serve only — the direct tracking link is not geo-gated, but it still requires an active, currently serviceable campaign.

Related MCP server: Meta Ads MCP Server

Documentation resources

Beyond the tools, the server exposes the affset API reference as MCP resources, so an assistant can answer "how does conversion tracking work?" or "what does /serve accept?" from the docs themselves — not just from the tool schemas.

Resource URI

Type

Content

affset://docs/api-reference

text/markdown

The full API reference — endpoints, auth, roles, examples.

affset://docs/api-reference.json

application/json

The same reference as structured data, for programmatic use.

They're the exact content published at affset.com/docs, generated from one source, and fetched at read time from AFFSET_DOCS_URL ({origin}/api-reference.md and {origin}/api-reference.json) — so they always reflect the currently published docs, not a copy pinned to this package. The fetch sends no credentials (the docs are public and live on a different origin than the tenant API). HTML SPA fallbacks, redirects, invalid JSON, and oversized bodies are rejected. Both resources are always available, including under AFFSET_READ_ONLY.

Configuration

Self-host (stdio) only — hosted connections do not use these variables. All config comes from the environment (never hard-coded):

Variable

Description

AFFSET_BASE_URL

Origin of the affset API, e.g. https://api.affset.com (no path/query/credentials). Must be https unless the host is localhost/127.0.0.1/::1 — plain http would send the API key in cleartext.

AFFSET_API_KEY

Tenant API key. Its namespace must match AFFSET_NAMESPACE.

AFFSET_NAMESPACE

Tenant namespace (lowercase letters, numbers, hyphens; 3–63 chars — same rules as signup).

AFFSET_READ_ONLY

Optional, default false. Set to true/1 to register only the read-only tools (whoami, get_stats, get_campaign, every list_*, get_zone_url, get_tracking_link) — every create/update/delete/cut tool is unavailable, not just gated behind confirm. See Security for why this matters.

AFFSET_REQUEST_TIMEOUT_MS

Optional, default 30000. Per-request HTTP timeout in milliseconds (1000300000).

AFFSET_DOCS_URL

Optional, default https://affset.com. Origin the API-reference documentation resources are fetched from (origin only, no path). Fetched anonymously — no API key is sent here.

See .env.example.

Install

Hosted (fastest — no install)

Add the remote server in your MCP client and approve access in the browser. OAuth is discovered from the endpoint — do not paste an API key, and do not add an Authorization header.

  • Claude (web or desktop) — Customize → Connectors → + → Add custom connector → https://mcp.affset.com/mcp.

  • Cursor — Settings → MCP → Add server, transport "streamable HTTP", same URL.

  • Claude Codeclaude mcp add --transport http affset https://mcp.affset.com/mcp then authenticate with /mcp.

You sign in with your affset email (magic link). Read-only is selected on the consent screen unless you switch to Full access. The connection gets its own scoped credential — your API key is never involved — and appears on the dashboard's Integrations page, where it can be revoked at any time. Full guide: affset.com/integrations.

The self-host paths below run the same tool roster over stdio and require Node.js 22.13 or newer.

No clone, no build — your MCP client runs it with npx. For Claude Desktop (claude_desktop_config.json):

{
  "mcpServers": {
    "affset": {
      "command": "npx",
      "args": ["-y", "@affset/mcp"],
      "env": {
        "AFFSET_BASE_URL": "https://api.affset.com",
        "AFFSET_API_KEY": "sk_live_...",
        "AFFSET_NAMESPACE": "your-namespace"
      }
    }
  }
}

For Claude Code:

claude mcp add affset \
  -e AFFSET_BASE_URL=https://api.affset.com \
  -e AFFSET_API_KEY=sk_live_... \
  -e AFFSET_NAMESPACE=your-namespace \
  -- npx -y @affset/mcp

Same env flags with -- npx -y github:affset/mcp if you install from GitHub instead of the npm registry (see below).

Add -e AFFSET_READ_ONLY=true for a stats/reporting-only instance (see Security).

From GitHub directly (no npm publish required)

npx can install straight from the git repo instead of the npm registry — useful if you'd rather not publish, or just want to track main without a release step:

{
  "mcpServers": {
    "affset": {
      "command": "npx",
      "args": ["-y", "github:affset/mcp"],
      "env": {
        "AFFSET_BASE_URL": "https://api.affset.com",
        "AFFSET_API_KEY": "sk_live_...",
        "AFFSET_NAMESPACE": "your-namespace"
      }
    }
  }
}

A push to main makes that commit available to this unpinned install path — no npm publish is required. On resolution, npm fetches the repository and runs the prepare script to build dist/ before starting the binary. npm may reuse its cache on later starts; an already running MCP process is not updated until it is restarted and npx resolves the dependency again.

For reproducible deployments, pin a reviewed ref instead of floating on main: github:affset/mcp#<commit-sha> or github:affset/mcp#<tag>. Restart the MCP process deliberately when you want it to resolve and run a newer revision.

From source

git clone https://github.com/affset/mcp.git affset-mcp
cd affset-mcp
npm install        # builds via the prepare script

Then point your MCP client at the built entry file — swap the npx command above for "command": "node", "args": ["/absolute/path/to/affset-mcp/dist/index.js"].

Usage examples

list paused campaignslist_campaigns(status: "paused")

show me everything about campaign 42get_campaign(campaign_id: 42)

show zoneslist_zones()

who's on the team?list_team()

add sarah@offer.com as a publishercreate_team_member(email: "sarah@offer.com", role: "publisher") (dry-run) → confirm

stats for today by sub1get_stats(group_by: "sub1")

stats by advertiserget_stats(group_by: "advertiser_email")

stats for one publisher, grouped by zoneget_stats(group_by: "zone_id", publisher_email: "publisher@example.com")

stats including informative conversionsget_stats(paid_only: false)

set up RichAds end to endcreate_traffic_source(name: "RichAds", preset: "richads") (dry-run) → confirm → create_zone(name: "RichAds push", traffic_source_id: "…") (dry-run) → confirm → get_zone_url()

create a campaign for offer X, advertiser buyer@example.com, geo BR, payout $2create_campaign(user_email: "buyer@example.com", offer_url: "https://offer.example/lp?s={click_id}", geo: ["BR"], payout: 2) (dry-run) → confirm

what URL do I paste into RichAds?get_zone_url() — a zone linked to a traffic source gets the source's template filled in

give me the link for campaign 42 againget_tracking_link(campaign_id: 42)

run campaign 42set_campaign_status(campaign_id: 42, action: "run") (dry-run) → confirm

pause campaign 42set_campaign_status(campaign_id: 42, action: "pause") (dry-run) → confirm

set zone postbackupdate_zone(zone_id, postback_url: "…") (dry-run) → confirm

cut zones with CR < 0.2% and spend > $5cut_zones(campaign_id, cr_max: 0.002, spend_min: 5) (dry-run) → confirm

show payouts for campaign 42list_payout_rules(campaign_id: 42)

set zone payout to $3set_payout_rule(campaign_id: 42, payout: 3, zone_id: "…") (dry-run) → confirm

only pay on deposit conversionsset_payout_goal(campaign_id: 42, goal_type: "deposit") (dry-run) → confirm

what targeting types exist?list_targeting_types()

whitelist BR+MX on campaign 42set_targeting_rule(campaign_id: 42, type: "geo", method: "whitelist", rule: "BR,MX") (dry-run) → confirm

name sub1 Zone, sub2 Creativeset_sub_labels(sub1: "Zone", sub2: "Creative") (dry-run) → confirm

show recent conversionslist_conversions()

hide informative conversions (goal-type misses)list_conversions(paid_only: true)

find $0 payouts (no rule / still on this page)list_conversions(zero_payout: true)

lookup by source click idlist_conversions(source_click_id: "abc123")

Notes & limits

  • get_stats groups by one dimension per call. Drill-down is a sequence of calls, each narrowing with campaign_ids / zone_ids / sub1..sub5 / conversion_type / advertiser_email / publisher_email / paid_only filters. The two email filters select one user's campaigns or zones without changing group_by; access is limited to owner/manager or the corresponding scoped manager role. Filtering by conversion_type returns conversion rows only (impressions, clicks and media cost are zero). paid_only defaults to true (the API default is false; this matches the dashboard) so the conversions count and CR drop informative rows recorded with postback_skipped=non_goal_type — pixel type missed the campaign's payout_goal_type. Silent conversions still count; this is not a payout>0 filter. Set false for the raw count. Only recent (unfolded) events are filtered; conversions already in daily archives stay included.

  • spend means media_cost (your traffic cost). ROI / spend thresholds need cost data imported for the slice.

  • List endpoints have no server-side name searchname_contains filters the current page client-side.

  • Date-range presets, YYYY-MM-DD bounds and rendered timestamps all resolve in the tenant timezone (read once from /api/tenant), so a window lines up with the date buckets group_by=date returns instead of straddling two of them. Explicit timestamps must include Z or a UTC offset.

  • All mutations (creates, updates, cuts, deletes) stay on dry-run → confirm: true. Creates are additive once confirmed and echo what was written.

  • Activating a campaign or creating a zone can return 402 plan limit — the error surfaces dimension / current / limit.

  • Payout resolution at conversion: zone-specific → global → $0. Goal type gates spend/payout by pixel type= match; non-matching events still record at $0. Payouts go down to $0.00001, so payout amounts print at up to five decimals.

  • Changing a payout is delete + create — the API has no update and the (campaign, zone) pair is unique. set_payout_rule restores the previous payout if the create fails, and says so loudly in the one case where it cannot.

  • Targeting is enforced on /serve only — not on direct tracking links. set_targeting_rule / remove_targeting_rule merge safely; other rules are kept.

  • Targeting values are matched exactly and case-sensitively at serve time (geo from CF-IPCountry, os/browser from the user agent, device type from a fixed set). set_targeting_rule normalises what it can (br,mxBR,MX, androidAndroid) and rejects what could never match — an unmatched whitelist silently stops delivery.

  • capping, weekdays and hours are seeded but never evaluated by /serve. set_targeting_rule refuses to write them (they would read as working targeting while the campaign kept buying); list_targeting_types flags them. Use unique_users (visits/hours) for frequency capping.

  • list_conversions is the conversion audit trail (not aggregated stats). The API has no campaign/zone/date filters; paid_only is the one server-side filter (true drops rows recorded with postback_skipped=non_goal_type — pixel type missed the campaign's payout_goal_type; silent conversions and other skip reasons still come back — this is not a payout>0 filter). The other optional filters apply to the current page only. Rows do not include campaign_id/zone_id. Publisher-side roles do not see spend and advertiser-side roles do not see payout, so zero_payout needs a role that can; paid_only does not (it keys on postback_skipped, not payout).

  • create_team_member creates the API key directly (like the dashboard's "Add Team Member") — it does not send an invite email. Hand the returned key to the person yourself. Revoking/removing a team member is not yet a tool; use the dashboard's Team page.

  • Out of scope: deleting campaigns/zones/conversions, billing, creative management.

  • Tenant signup is deliberately not a tool. POST /api/public/create-instance is Origin-gated and fails closed, which is what keeps signup browser-only; a server-side caller would have to spoof an allowlisted Origin to get past it. The endpoint also withholds the API key when email delivery is configured (it sends a magic link instead), and this server binds one namespace from the environment at startup — so it could not use a tenant it just created. Sign up in the dashboard, then point a server instance at the new namespace.

Using as a library

Since 0.2.0 the package doubles as a runtime-agnostic library: everything the stdio server registers (tools, docs resources, read-only stripping) is exposed as one helper that runs on any fetch-capable runtime — Node ≥22.13 or Cloudflare Workers. The hosted affset MCP gateway (mcp.affset.com) consumes exactly this surface, so the remote roster can never drift from stdio.

import { registerAffsetTools, type Config } from "@affset/mcp/core";

const config: Config = {
  baseUrl: "https://api.affset.com",
  docsBaseUrl: "https://affset.com",
  apiKey: perRequestKey, // e.g. an OAuth grant's backing credential
  namespace: tenantNamespace,
  requestTimeoutMs: 30_000,
  readOnly: scope === "read", // never registers tools without readOnlyHint: true
};

registerAffsetTools(server, config); // server: your own McpServer instance

registerAffsetTools accepts your McpServer structurally, so your own @modelcontextprotocol/sdk install works — no need to match this package's copy. Env-var loading (AFFSET_*) is deliberately not part of the library surface; it belongs to the stdio entrypoint only. A third, optional { onToolCall } argument reports only tool name, duration, and success/error status for transport-owned audit logging; arguments and output are never included.

The library validates and normalizes config before registering anything. Remote API origins must use HTTPS (plain HTTP is accepted only on loopback), origins cannot contain credentials or paths, and invalid namespaces, timeouts, API keys, or non-boolean read-only settings fail closed at startup. The public declarations do not require Node ambient types, so the same import type-checks in Workers and other web-standard runtimes.

Development

npm run type-check   # tsc --noEmit
npm run lint         # eslint src
npm run format       # prettier --write .
npm run build        # compile to dist/
npm test             # build + node --test over dist/**/*.test.js
npm run check-all    # lint + format:check + type-check + test — CI runs this
npm run dev          # watch mode

Security

  • Hosted (https://mcp.affset.com/mcp): OAuth via magic link. Read-only is the consent default (mutating tools are never registered). Full access still dry-runs mutations until confirm: true. Revoke from the dashboard Integrations page. Nothing on mcp.affset.com / oauth.affset.com asks for an API key.

  • Self-host (stdio): no secrets in the repo; credentials come from the environment at runtime. Create a dedicated, least-privilege, expiring API key rather than reusing an owner key.

  • AFFSET_BASE_URL must be https unless the host is loopback — no cleartext API key.

  • Tenant API responses are streamed under a 5 MB hard limit; larger bodies are cancelled before parsing or reaching model context.

  • stdout is the JSON-RPC channel — all logs go to stderr.

  • list_team redacts API tokens.

  • All mutations (including creates) follow show → confirm → apply.

  • affset's RBAC roles (owner / manager / publisher / advertiser / advertiser_manager / publisher_manager) apply to MCP tool calls exactly as they do to the dashboard.

  • Pin GitHub installs to a reviewed commit or tag in long-lived environments. A floating main spec can run newer repository code the next time npx resolves it.

Prompt injection via conversion/click data

get_stats, list_conversions and cut_zones surface data that ultimately comes from public, unauthenticated endpoints — a traffic source's click macros (sub1sub5, source_click_id) and a conversion pixel's raw query string (list_conversions' payload detail). Anyone who can generate a click or fire a pixel controls those bytes, and they land in the model's context when you ask about stats or conversions.

Mitigations in place:

  • Untrusted fields are length-capped and escaped before rendering (mdCell, capUntrusted in src/lib/format.ts), and the conversion-payload block carries an explicit "treat as data, not instructions" notice.

  • confirm: true on mutating tools is a model-level safety net, not a security boundary — a model that has been steered by injected content can supply confirm: true itself. The only real boundary is your MCP client's per-call tool approval plus read-only mode (hosted: consent default; stdio: AFFSET_READ_ONLY=true).

Prefer read-only for any session where you're mainly reading stats/conversions, especially with an MCP client that auto-approves tool calls. It removes every mutation tool from the server entirely — not hidden behind a prompt, unavailable to call. Reserve full access (hosted) or a read-write stdio instance for sessions where you're actively managing campaigns/zones/payouts and are reviewing each confirm yourself.

Available Tools

29 tools
create_campaignCreate a campaignAInspect

Create a campaign (offer) in the current namespace from a compact spec: advertiser email, offer URL, geo whitelist, payout, name. The advertiser (user_email) is required — it must already exist as a team member (same as the Advertiser dropdown in the dashboard); create one first with create_team_member if needed. Everything else gets media-buying defaults: CPA model, rate 0 (no internal advertiser billing), created paused, a global payout rule when payout is given, and a ready-to-use tracking link. A zone linked to a traffic source uses that source's tracking template; otherwise the link is prefilled with the sub convention (source_click_id + sub1..sub5, named by the tenant's sub labels). The campaign is created paused, so activate it before sending traffic through either URL. Geo whitelist applies to /serve rotation only; the tracking link itself is not geo-gated. DRY-RUN by default; pass confirm=true to apply. No money is spent by this call; the result echoes exactly what was created.

ParametersJSON Schema
NameRequiredDescriptionDefault
geoNoGeo whitelist as ISO 3166-1 alpha-2 codes, e.g. ["BR"] or ["BR","MX"]. Omit for worldwide. Applies to /serve rotation only — the tracking link is not geo-gated.
nameNoCampaign name / funnel tag. Default: derived from offer host, geo and payout.
payoutNoOffer payout per conversion in USD (0.00001–9999.99999; creates the campaign's global payout rule).
confirmNofalse = dry-run preview (default). true = create the campaign.
zone_idNoTraffic-source zone for the tracking link. Optional when the namespace has exactly one active zone — it is picked automatically; otherwise the tool lists zones to choose from.
offer_urlYesOffer / lander URL the click redirects to. May carry {click_id} (affset's click id, for S2S postback back into affset) and {sub1}..{sub5} macros.
user_emailYesAdvertiser email that owns this campaign (required — the API rejects the call without it). Must already exist as a team member with the advertiser role; same as the dashboard's Advertiser dropdown. List candidates with list_team, or create one with create_team_member.

TDQS

A4.7/5.0
Behavior5/5

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

Annotations only signal readOnly=false, openWorld=true, idempotent=false, destructive=false. The description goes well beyond that by disclosing dry-run-by-default, no money spent, created-paused behavior, CPA model/rate 0 defaults, global payout rule creation, and the tracking-link derivation logic. It also explains that the response echoes exactly what was created, which is important given there is no output schema.

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 information-dense, and it is well structured with a front-loaded summary followed by defaults, tracking-link behavior, execution mode, and safety notes. There is minor redundancy — 'created paused' appears twice and payout-rule behavior is repeated in the schema — but nearly 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 complex create tool with no output schema, the description covers prerequisites, defaults, side effects, dry-run vs confirm semantics, activation requirement, geo scoping, and the result format. An agent has everything needed to call it correctly and predict the outcome, including whether money is spent.

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%, so the baseline is 3, but the description adds real value on top of the schema: it explains why user_email is required, how zone_id behaves with zero/one/many zones, that confirm=false means dry-run, and cross-parameter implications like payout creating a global payout rule and geo only affecting /serve rotation. This is far more than a restatement of schema fields.

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: 'Create a campaign (offer) in the current namespace from a compact spec'. It also clarifies what the tool is not (it does not create team members, it references create_team_member) and lists the concrete inputs, so an agent can distinguish it from sibling tools without opening schemas.

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 strong usage context: the advertiser must already exist as a team member, create_team_member is the fallback, zone selection is automatic when exactly one zone exists, and confirm=true is needed to leave dry-run mode. It does not explicitly contrast this tool with update_campaign or set_campaign_status, but the creation flow is clear enough that the missing exclusion is minor.

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

create_team_memberInvite a team memberAInspect

Invite a team member: create a user API key with an email in the current namespace — the same operation as the dashboard's "Add Team Member". Requires owner/manager, or a scoped manager role (publisher_manager / advertiser_manager), which can only create its own managed role (publisher / advertiser respectively) assigned to itself — the API enforces this, not this tool, so a scoped manager's role/manager_email args may be overridden. Returns the new member's plaintext API key ONCE, in the confirmed response — it is not shown again by list_team, which deliberately never echoes tokens, so copy it now and send it to them over a private channel. Does not send an invite email; the API key is the credential, handed over out of band. DRY-RUN by default; pass confirm=true to apply.

ParametersJSON Schema
NameRequiredDescriptionDefault
roleYesowner | manager | advertiser_manager | publisher_manager | advertiser | publisher. What your own API key's role is allowed to create is enforced by the API.
emailYesNew team member's email — their login / API identity.
confirmNofalse = dry-run preview (default). true = create the member and issue the key.
expires_atNoOptional future expiry as epoch milliseconds. Omit for a key that never expires.
permissionsNoDefaults to ["read","write"] (matches the dashboard's default). "read" is always included.
manager_emailNoAssign to a publisher_manager / advertiser_manager. Only valid with role=publisher or role=advertiser. A scoped manager key ignores this and assigns itself instead.

TDQS

A4.7/5.0
Behavior5/5

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

Description reveals critical behaviors beyond annotations: plaintext API key returned only once, no invite email sent, dry-run mode, and API-enforced role overrides. This far exceeds the minimal safety profile indicated by readOnlyHint=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?

The description is dense and front-loaded with the core action. While every sentence adds value, minor redundancy could be trimmed. Overall, it is well-structured for an agent to parse quickly.

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 tool complexity (6 parameters, no output schema), the description covers prerequisites, return value, dry-run behavior, and security notes. Missing details on error handling or duplicate emails, but sufficient for most agent use.

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 interactions (e.g., manager_email overridden for scoped managers) and dry-run context, elevating it above baseline but not fully exploring all 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 'Invite a team member: create a user API key with an email in the current namespace' and equates it to the dashboard's 'Add Team Member', making the action and resource unambiguous. It distinguishes itself from sibling tools like list_team and delete_payout_rule by focusing on creation.

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?

Description explicitly states required roles and their limitations, including how scoped manager roles override inputs. It also clarifies the default dry-run behavior and the need for confirm=true to apply, providing clear when-to-use guidance.

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

create_traffic_sourceCreate a traffic sourceAInspect

Create a traffic source — an ad network account bought from. Creating from a preset (exoclick, trafficstars, propellerads, adsterra, richads) copies the network's verified tracking + postback templates into an editable row; [BRACKETED] pieces in a postback template are account-specific values to fill in. Link zones to the source via create_zone/update_zone traffic_source_id, and get_zone_url renders its template. The api_token is stored write-only for upcoming cost sync. DRY-RUN by default; pass confirm=true to apply.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYesDisplay name, unique per tenant — e.g. "ExoClick — main".
presetNoNetwork preset id to copy templates from (e.g. exoclick, trafficstars, propellerads, adsterra, richads). The row stays fully editable and remembers its preset. Omit for a custom source.
statusNoactive (default) or archived.
confirmNofalse = dry-run preview (default). true = create the traffic source.
api_tokenNoNetwork API credential for upcoming cost sync. Stored write-only — reads only ever return has_api_token.
postback_templateNoThe network's S2S conversion endpoint using our postback macros ({source_click_id}, {payout}). Overrides the preset's template. Prefills the linked zones' postback_url suggestion — never applied automatically.
tracking_templateNoQuery string appended to the zone URL — our param names on the left, the network's macros on the right. Overrides the preset's template. Must not start with ? or &.

TDQS

A4.7/5.0
Behavior5/5

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

Beyond the annotations, it discloses the critical dry-run default ('DRY-RUN by default; pass confirm=true to apply'), write-only storage of api_token for 'upcoming cost sync,' and preset copy behavior with editable rows. These are exactly the behavioral traits that affect whether an agent mutates data without realizing it.

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 dense sentences, all high-signal and front-loaded with the core purpose before workflow and safety details. No filler or repetition of schema text; each clause 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 7-parameter creation tool with no output schema, the description covers the full lifecycle: preset usage, template editing, zone linking, URL rendering, API token storage, and the dry-run/confirm behavior. The absence of an output schema is mitigated by the explicit confirmation gate, so an agent has everything needed 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?

Schema coverage is 100%, so the schema carries most parameter meaning. The description still adds value by explaining how preset populates tracking/postback templates and by defining [BRACKETED] pieces as account-specific placeholders, which helps an agent fill postback_template or tracking_template correctly.

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 ('Create a traffic source') and immediately clarifies what that resource is: 'an ad network account bought from.' It also distinguishes the creation workflow from related tools by pointing to create_zone/update_zone and get_zone_url, making the tool's role clear relative to 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?

It provides clear when-to-use context: create by choosing a preset or omitting it for a custom source, then link zones and render templates via the named sibling tools. It does not explicitly state when update_traffic_source or list_traffic_sources should be used instead, so there is no formal exclusion, but the intended flow is evident.

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

create_zoneCreate a zoneAInspect

Create a traffic-source zone in the current namespace. Requires a name; optional postback_url (where conversions are reported back — include {source_click_id}), site_url, traffic_back_url, user_email (publisher owner), and traffic_source_id (get_zone_url then renders that source's tracking template). Status is always active on create. Counts against the plan's zone limit (402 if exceeded). DRY-RUN by default; pass confirm=true to apply.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYesZone display name (traffic source / placement).
confirmNofalse = dry-run preview (default). true = create the zone.
site_urlNoOptional site / inventory URL.
user_emailNoOptional publisher email to own this zone (owner/manager only).
postback_urlNoS2S postback URL for the traffic source. Should include {source_click_id} so conversions can be attributed back to the source click.
traffic_back_urlNoOptional traffic-back / fallback URL when no campaign can serve.
traffic_source_idNoTraffic source to link (see list_traffic_sources). Must be a source in this namespace. get_zone_url/get_tracking_link then render its tracking template.

TDQS

A4.5/5.0
Behavior5/5

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

The description discloses critical behaviors not visible in annotations: DRY-RUN by default, confirm=true required to apply, status always active on create, and the plan's zone limit error (402). These are valuable operational details that exceed 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?

Three dense sentences that front-load the purpose, then list required/optional parameters, then state the most important behavioral facts. No wasted words; 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 7-parameter creation tool with no output schema, the description covers the required input, key optional parameters, default dry-run behavior, confirmation requirement, resulting status, and quota error. This is sufficient for an agent to invoke it safely and 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 the schema already documents every parameter. The description mostly restates the optional parameters and adds minor context like postback_url being for conversions and traffic_source_id influencing get_zone_url, but it does not significantly add meaning 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 names a specific verb and resource: 'Create a traffic-source zone in the current namespace.' It clearly distinguishes this from sibling tools like update_zone, list_zones, and create_campaign by specifying the resource type and scope.

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: creating a new zone, requiring a name, and linking an optional traffic source. It does not explicitly state when not to use it or mention alternatives, but the context is enough for an agent to select it over update_zone or create_campaign.

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

cut_zonesCut underperforming zonesA
Destructive
Inspect

Blacklist underperforming zones on a campaign based on thresholds (CR, spend, ROI). Evaluates zone stats over the given window and adds matching zones to the campaign's zone blacklist. DRY-RUN by default: it shows which zones would be cut and how the blacklist changes. Pass confirm=true to actually apply. spend means media_cost (your traffic cost). A zone is cut only if it matches ALL provided thresholds.

ParametersJSON Schema
NameRequiredDescriptionDefault
toNoExplicit end bound: YYYY-MM-DD (tenant-local end of day), ISO timestamp with Z/UTC offset, or epoch ms.
fromNoExplicit start bound: YYYY-MM-DD (tenant-local start of day), ISO timestamp with Z/UTC offset, or epoch ms.
rangeNoEvaluation window. Ignored if from/to are given. Defaults to last 7 days.
cr_maxNoCut zones with conversion rate BELOW this fraction (e.g. 0.002 = 0.2%).
confirmNofalse = dry-run preview (default). true = apply the blacklist changes.
roi_maxNoCut zones with ROI BELOW this fraction (e.g. -0.3 = -30%). Needs cost data.
spend_minNoCut zones with media_cost ABOVE this many dollars (e.g. 5 = $5).
min_clicksNoIgnore zones with fewer clicks than this (significance guard). Default 10.
campaign_idYesCampaign whose zone blacklist to edit.

TDQS

A4.4/5.0
Behavior4/5

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

The description discloses the destructive nature (blacklist modification), the dry-run default, the AND logic for thresholds, and the significance guard (min_clicks). Annotations already indicate destructiveHint=true, so the description adds context on how the destruction works (adding to blacklist) and the evaluation window. 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 concise: four sentences that front-load the purpose and key behaviors (dry-run, confirm, threshold logic). No unnecessary words, and every sentence adds essential information. The structure is clear and easy to parse.

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 tool has 9 parameters and no output schema, the description covers the core behavior well: evaluation window, threshold criteria, dry-run vs confirm, and the significance guard. It could mention what the response looks like (e.g., list of zones to be cut) or error cases (e.g., invalid campaign). Still, it provides enough context for most use cases.

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 parameters are already described. The description adds value by clarifying that 'spend' means media_cost, explaining the AND logic for multiple thresholds, and noting that range is ignored if from/to are given. This extra context helps the agent understand parameter interactions 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's purpose: blacklisting underperforming zones based on thresholds. The verb 'cut' and resource 'zones' are specific. It distinguishes from sibling tools like list_zones, update_zone, or remove_targeting_rule by focusing on automated performance-based blacklisting with dry-run and confirm modes.

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 (to cut underperforming zones), how to use it (dry-run first, then confirm), the logic of threshold matching (ALL conditions), and defines key terms like 'spend'. However, it does not explicitly state when not to use it or contrast with alternatives like manual editing via update_zone.

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

delete_payout_ruleDelete a payout ruleA
Destructive
Inspect

Delete a campaign payout rule (global or per-zone). Omit zone_id to delete the global rule; pass a zone UUID to delete that zone's override. DRY-RUN by default; pass confirm=true to apply. Without a global rule, conversions resolve to $0.

ParametersJSON Schema
NameRequiredDescriptionDefault
confirmNofalse = dry-run preview (default). true = apply.
zone_idNoZone UUID of the zone-specific rule. Omit to delete the global rule.
campaign_idYesCampaign whose payout rule to delete.

TDQS

A5/5.0
Behavior5/5

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

Annotations indicate destructiveHint=true but description adds the dry-run behavior (preview before applying) and the fallback to $0 if no global rule exists. This provides behavioral context 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?

Two sentences cover the purpose, two modes, dry-run behavior, and consequences. No extraneous words; 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?

Given the tool's complexity (deletion with two modes, dry-run, fallback), the description covers all essential aspects. No output schema exists, but return values are not critical for operation. Sibling tools like set_payout_rule provide contrast.

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 has 100% coverage, but description adds meaning: it explains the interaction of zone_id with global vs per-zone deletion, and the role of the confirm parameter in applying changes. This clarifies parameter usage beyond the schema 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?

Description starts with 'Delete a campaign payout rule (global or per-zone)', clearly specifying the verb and resource. It distinguishes two modes of operation and mentions the consequence of no rule remaining ($0 conversions), 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?

Explicitly states when to omit zone_id (delete global rule) vs when to pass zone UUID (delete zone override). Also explains the dry-run default and the need for confirm=true to apply, giving clear usage instructions.

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

get_campaignGet a campaign's full recordA
Read-onlyIdempotent
Inspect

Get one campaign's full record: every field (including the untruncated offer URL, exact schedule, budgets/pacing, silent-conversions flag, payout goal type) plus its targeting rules and payout rules in one call. list_campaigns renders a summary table (offer URL truncated, no dates/pacing/silent) meant for scanning many campaigns; use this when you need one campaign's complete data — e.g. before recreating it as a new campaign, or before editing it with update_campaign.

ParametersJSON Schema
NameRequiredDescriptionDefault
campaign_idYesCampaign id to fetch.

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, openWorldHint=true, idempotentHint=true, and destructiveHint=false, so safety is clear. The description adds behavioral context about what the tool returns: untruncated offer URL, exact schedule, budgets/pacing, silent-conversions flag, payout goal type, and targeting/payout rules. This enriches 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?

The description is two sentences: the first enumerates the full record contents, the second provides usage context and alternatives. Every word earns its place, is front-loaded with the purpose, and is extremely 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?

For a simple read-only tool with one parameter and no output schema, the description fully covers what the tool does, what data it returns, and when to use it. Given the complexity, it is complete and leaves no necessary 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?

The schema covers campaign_id with 'Campaign id to fetch' and is 100% documented, so the baseline is 3. The description does not add parameter-specific semantics, but given the parameter is self-explanatory and there is only one, no further elaboration is necessary.

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 'Get one campaign's full record' and enumerates specific data included (untruncated offer URL, exact schedule, budgets/pacing, silent-conversions flag, payout goal type, targeting/payout rules), making the purpose highly specific. It also explicitly contrasts with list_campaigns, which renders a summary table, so it clearly distinguishes itself from its sibling.

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 when to use this tool: 'use this when you need one campaign's complete data — e.g. before recreating it as a new campaign, or before editing it with update_campaign.' It also contrasts with list_campaigns, which is meant for scanning many campaigns, 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.

get_statsGet affset statsA
Read-onlyIdempotent
Inspect

Pull affset traffic stats grouped by a single dimension. Returns impressions, clicks, conversions, CR, payout, media cost and ROI as a table. Drill down by calling repeatedly: first group_by=date or campaign_id, then narrow with filters (campaign_ids, zone_ids, sub1..sub5, conversion_type, advertiser_email, publisher_email, paid_only) and change group_by (zone_id, sub1, ...). Sub columns are titled with the tenant's configured labels (e.g. "Zone (sub1)") when set; group_by/filters always take the raw subN key. conversion_type only matches conversion rows, so filtering by it zeroes impressions, clicks and media cost — it narrows to conversions of that type, not clicks that led to one. paid_only defaults to true (same as the dashboard): conversions and CR exclude informative pings whose pixel type missed payout_goal_type, so CR is not inflated above 100%. Set false for the raw unfiltered count. ROI is blank until traffic cost has been imported for the slice. group_by=advertiser_email / publisher_email break down by team member; the API limits them to owner/manager plus the matching side's manager role (403 otherwise). advertiser_email / publisher_email are also standalone filters — narrow every row to one advertiser's campaigns or one publisher's zones regardless of group_by, instead of breaking every user out into its own row. Same role limits as the matching group_by value.

ParametersJSON Schema
NameRequiredDescriptionDefault
toNoExplicit end bound: YYYY-MM-DD (tenant-local end of day), ISO timestamp with Z/UTC offset, or epoch ms.
fromNoExplicit start bound: YYYY-MM-DD (tenant-local start of day), ISO timestamp with Z/UTC offset, or epoch ms.
sub1NoFilter by sub1 value(s), comma-separated for multiple.
sub2NoFilter by sub2 value(s).
sub3NoFilter by sub3 value(s).
sub4NoFilter by sub4 value(s).
sub5NoFilter by sub5 value(s).
rangeNoConvenience time window. Ignored if from/to are given. Defaults to today.
group_byNoDimension to group by (one at a time). Drill down by changing this across calls.date
zone_idsNoRestrict to these zone IDs.
paid_onlyNoDrop informative conversions (postback_skipped=non_goal_type, e.g. lp_view pings that missed payout_goal_type) from the conversions count and CR. Silent conversions still count — not a payout>0 filter. Default true (matches the dashboard) so CR is not inflated above 100%. Set false for the raw count.
campaign_idsNoRestrict to these campaign IDs.
conversion_typeNoFilter by conversion type value(s) (e.g. deposit, register), comma-separated for multiple. Pass "" to select conversions recorded without a type.
publisher_emailNoNarrow to one publisher's zones, independent of group_by. Owner/manager: any publisher. publisher_manager: only one of their own assigned publishers (else 403). Other roles: 403.
advertiser_emailNoNarrow to one advertiser's campaigns, independent of group_by. Owner/manager: any advertiser. advertiser_manager: only one of their own assigned advertisers (else 403). Other roles: 403.

TDQS

A4.7/5.0
Behavior5/5

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

Despite annotations already declaring read-only/idempotent behavior, the description adds substantial behavioral context: conversion_type filtering zeroes impressions/clicks/media cost, paid_only defaults true to avoid inflated CR, ROI remains blank until cost is imported, and advertiser/publisher_email have role-based 403 limits. These are meaningful traits not visible in annotations or schema alone.

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 and dense, but every sentence contributes actionable nuance, from drill-down patterns to auth edge cases. It is front-loaded with the core purpose. Some details overlap with parameter schema descriptions (e.g., role limits for email params), which slightly reduces efficiency, but the overall structure is justified for a 15-parameter stats 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?

The description covers purpose, metrics returned, drill-down workflow, filter semantics, defaults, label handling, ROI behavior, and authorization limits. It is complete for an aggregation tool with no output schema, and it compensates for the absence of an output schema by clearly stating what the table contains. No significant gaps remain for an agent to invoke this tool 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%, so the baseline is 3, but the description adds semantics beyond the schema: subN params always take raw keys while display uses tenant labels, conversion_type narrows to conversion rows rather than clicks, paid_only matches dashboard behavior and excludes informative pings, and email params can act as standalone filters versus group_by breakdowns. This materially improves an agent's understanding of parameter behavior.

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+resource statement: 'Pull affset traffic stats grouped by a single dimension' and enumerates the exact metrics returned. This clearly differentiates it from sibling list/crud tools like list_conversions and list_campaigns, which return raw rows rather than aggregated stats.

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 concrete drill-down workflow: 'first group_by=date or campaign_id, then narrow with filters... and change group_by' and explains role limitations (403 cases). It does not explicitly name alternative tools for row-level data or state when NOT to use this tool, but the workflow guidance is strong enough for an agent to choose and invoke it appropriately.

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

get_zone_urlGet the zone URL for a traffic sourceA
Read-onlyIdempotent
Inspect

Get the zone URL to paste into a traffic source's campaign settings — the /serve link that rotates across the zone's active campaigns. A zone linked to a traffic source renders that source's tracking template; otherwise the URL is prefilled with the sub convention (source_click_id + sub1..sub5) and optionally the network's cost macro. Uses the tenant's custom API domain when one is set. Read-only: builds the URL, changes nothing. For a link straight to one active campaign without targeting checks, use get_tracking_link instead.

ParametersJSON Schema
NameRequiredDescriptionDefault
costNoThe network's cost macro, e.g. `{cost}`. Adds `&cost=…` so media cost is imported and ROI shows up in get_stats. Omit if the source cannot pass cost.
sub1NoValue or macro for sub1 (analytics only). Defaults to a placeholder named after the tenant's label for this slot.
sub2NoValue or macro for sub2 (analytics only). Defaults to a placeholder named after the tenant's label for this slot.
sub3NoValue or macro for sub3 (analytics only). Defaults to a placeholder named after the tenant's label for this slot.
sub4NoValue or macro for sub4 (analytics only). Defaults to a placeholder named after the tenant's label for this slot.
sub5NoValue or macro for sub5 (analytics only). Defaults to a placeholder named after the tenant's label for this slot.
zone_idNoZone to build the URL for. Optional when the namespace has exactly one active zone — it is picked automatically; otherwise the tool lists zones to choose from.
source_click_idNoThe traffic source's click-token macro, e.g. `[CLICK_ID]` (RichAds), `${SUBID}` (PropellerAds). Default `{clickid}`. This is what conversion postbacks echo back via {source_click_id} — pass "" only to omit it deliberately. Zones linked to a traffic source render the source's tracking template instead; passing any explicit link parameter overrides that template.

TDQS

A4.9/5.0
Behavior5/5

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

Although annotations already provide readOnlyHint/idempotentHint, the description adds substantial behavioral context beyond them: the URL rotates across active campaigns, captures tracking-template rendering vs. sub-convention prefill, mentions the optional cost macro, and explains custom API domain usage. The read-only statement aligns with annotations and adds a plain-language safety cue.

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 tightly written sentences, each earning its place: purpose and artifact, conditional behavior, and sibling differentiation. The most important routing information is placed last but still compact, with no filler or 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 having 8 optional parameters and no output schema, the description conveys what the tool returns (a URL), how it behaves under different zone states, and when to avoid it. All parameter defaults and behaviors are covered by the schema descriptions, and the sibling reference completes the contextual picture. Nothing critical 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?

Schema description coverage is 100%, so the schema already documents every parameter in detail. The description adds contextual meaning by grouping source_click_id + sub1..sub5 and mentioning the cost macro, reinforcing the parameter conventions. It doesn't need to enumerate params because the schema does, but the description's reference to the sub convention adds a worthwhile layer.

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 verb+resource ('Get the zone URL') and a concrete use case ('paste into a traffic source's campaign settings'), then precisely describes the artifact ('the /serve link that rotates across the zone's active campaigns'). It explicitly contrasts itself with get_tracking_link, so an agent can distinguish the two tools without opening 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?

Gives clear context: when the zone is linked to a traffic source or not, and how the URL is built accordingly. Ends with an explicit alternative and the condition that selects it ('For a link straight to one active campaign without targeting checks, use get_tracking_link instead'), which fully routes the agent.

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

list_campaignsList campaignsA
Read-onlyIdempotent
Inspect

List campaigns in the current namespace. Filter by status and optionally by name (client-side contains match — the API has no search). Returns id, name, status, offer URL, model/rate, advertiser, budgets. Paginated (default 20, max 100).

ParametersJSON Schema
NameRequiredDescriptionDefault
sortNoSort field. Default created_at.created_at
limitNoPage size (1–100). Default 20.
orderNoSort order. Default desc.desc
offsetNoPagination offset. Default 0.
statusNoFilter by campaign status.
name_containsNoCase-insensitive substring match on campaign name (client-side).

TDQS

A3.9/5.0
Behavior4/5

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

Annotations already cover readOnly, idempotent, and non-destructive. Description adds details about client-side name matching, lack of API search, pagination limits, and returned fields--useful context 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?

Three sentences, no fluff, front-loaded with the core action. 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?

Covers scope, filtering, returned fields, and pagination. Missing mention of sorting/ordering parameters, but overall sufficient for a read-only list tool with rich annotations.

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%. Description clarifies the client-side nature of name_contains and contextualizes status and pagination parameters, adding meaning beyond the schema.

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?

Clearly states it lists campaigns in the current namespace with filtering. Does not explicitly differentiate from sibling list tools (e.g., list_targeting_types), but the context implies uniqueness.

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?

Describes typical use (list campaigns with optional filters) but lacks explicit guidance on when to use 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.

list_conversionsList conversionsA
Read-onlyIdempotent
Inspect

List recent conversion records (audit trail) for debugging payouts and pixel params. Shows payout, spend, pixel type, source_click_id, click_id, subs, postback outcome, and the raw payload. paid_only: true drops informative conversions server-side — rows recorded with postback_skipped=non_goal_type because the pixel type missed the campaign's payout_goal_type. Silent conversions and other skip reasons still come back (not a payout>0 filter). Default false, all rows. Beyond pagination/sort/paid_only, the optional click_id / source_click_id / type / payload_contains / zero_payout filters run client-side on the current page. Does not include campaign_id/zone_id (not returned by the API).

ParametersJSON Schema
NameRequiredDescriptionDefault
sortNoSort field. Default created_at.created_at
typeNoMatch payload `type` (pixel goal type), case-insensitive (client-side, current page).
limitNoPage size (1–100). Default 20.
orderNoSort order. Default desc.desc
offsetNoPagination offset. Default 0.
click_idNoExact click_id match (client-side, current page).
paid_onlyNotrue drops informative conversions — rows recorded with postback_skipped=non_goal_type because the pixel type missed the campaign's payout_goal_type. Silent conversions and other skip reasons still come back (not a payout>0 filter). Server-side (filters the whole dataset, not just this page). Works without payout visibility. Default false (all rows).
zero_payoutNoIf true, keep only rows with payout 0 or none recorded (goal mismatch / no payout rule). Client-side, current page. Needs a role that can see payout.
source_click_idNoExact source_click_id match (client-side, current page).
payload_containsNoSubstring match on raw payload JSON (client-side, current page).

TDQS

A4.8/5.0
Behavior5/5

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

The description goes far beyond the readOnly, openWorld, idempotent, non-destructive annotations. It discloses that paid_only is server-side and not a simple payout filter, that several filters run client-side on the current page only, and that campaign_id/zone_id are not returned by the API. This is rich, non-obvious 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 dense but every sentence carries unique value: purpose, returned fields, paid_only nuance, filter behavior, and API exclusions are all addressed. It is appropriately sized for a 10-parameter tool with subtle pagination and filtering behavior, and the critical semantics 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?

There is no output schema, so the description must explain return values—it does by enumerating payout, spend, pixel type, click IDs, subs, postback outcome, and raw payload. It also covers edge cases like skip reasons and excluded API fields, making it complete for a complex read-only listing tool.

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%, so the schema already documents each field, but the description adds critical semantics: which filters are server-side vs. client-side, what paid_only truly does with postback_skipped=non_goal_type, and that zero_payout needs payout visibility. This meaning is not inferable from parameter names 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 immediately states a specific verb and resource: 'List recent conversion records (audit trail) for debugging payouts and pixel params.' It also enumerates the exact fields returned, which makes the tool's scope unmistakable. It distinguishes itself by describing the audit/payout context, which is unique among sibling 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 clarifies the tool's intended use case ('for debugging payouts and pixel params') and even warns about paid_only semantics that could mislead users. It does not name alternatives, but no sibling tool appears to provide conversion records, so explicit exclusions were not necessary.

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

list_payout_rulesList payout rulesA
Read-onlyIdempotent
Inspect

List a campaign's payout rules (global + per-zone) and its payout_goal_type. Global rule applies to all zones; a zone-specific rule overrides it for that zone. When payout_goal_type is set, spend/payout apply only on conversions whose pixel type= exactly matches (others still record, but with $0).

ParametersJSON Schema
NameRequiredDescriptionDefault
campaign_idYesCampaign whose payout rules to list.

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, idempotentHint=true, and safe behavior. The description adds valuable behavioral context: the distinction between global and per-zone rules, and how payout_goal_type affects conversion attribution.

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, no redundant words. It efficiently communicates key concepts without 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 simple list tool with one parameter and thorough annotations, the description fully explains behavior, output structure, and edge cases (payout_goal_type effect). No gaps remain.

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 (campaign_id). The description adds context about the output structure but does not significantly expand on parameter meaning 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 lists a campaign's payout rules and payout_goal_type, explaining global vs per-zone rules. This specific verb+resource combination distinguishes it from sibling tools like list_targeting_rules or set_payout_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?

The description provides clear context on when to use the tool (to list payout rules) and explains the structure of rules and the effect of payout_goal_type. While it doesn't explicitly exclude alternatives, the purpose is well-defined.

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

list_sub_labelsList sub labelsA
Read-onlyIdempotent
Inspect

List the tenant's display names for sub1–sub5 (traffic-source breakdown slots). Unlabeled slots show as the raw key. Used by get_stats column titles and tracking-link / zone-URL query params.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.7/5.0
Behavior5/5

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

Annotations already indicate read-only and idempotent. The description adds details about what data is returned (display names, raw keys for unlabeled) and the specific slots (sub1-sub5), providing 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?

Two concise sentences, front-loaded with action and resource, followed by usage 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?

For a tool with no parameters and no output schema, the description fully covers what it does, what it returns, and how it is used. Complete and sufficient.

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 baseline is 4 per guidelines. Description adds no parameter info, which is acceptable as there are none.

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 the resource 'tenant's display names for sub1–sub5', specifies the scope (tenant-level) and behavior for unlabeled slots. It distinguishes from siblings like set_sub_labels and other list 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 implies usage context (used by get_stats, tracking-link, zone-URL) but does not explicitly state when to use or avoid this tool vs alternatives. However, the purpose is clear enough for a simple tool.

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

list_targeting_rulesList campaign targeting rulesA
Read-onlyIdempotent
Inspect

List a campaign's targeting rules (type, method whitelist/blacklist, rule values). Rules gate /serve rotation; the direct tracking link does not enforce them. Call list_targeting_types for type ids/names.

ParametersJSON Schema
NameRequiredDescriptionDefault
campaign_idYesCampaign whose targeting rules to list.

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, indicating safe read behavior. The description adds that rules gate serve rotation and the direct link does not enforce them, providing useful behavioral context beyond the annotations. It does not contradict 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, no fluff. The first sentence explains the main function and output, the second adds an important behavioral note and a pointer to a sibling tool. Each sentence serves a 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?

Given the tool's simplicity (one parameter, no output schema), the description covers the return fields, behavioral nuance, and provides a reference to a related tool. It does not mention pagination or whether all rules are returned at once, but for a list tool this is acceptable. Overall, it is sufficiently complete for an agent to use 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% coverage with a description for campaign_id. The description adds what the output includes (type, method, rule values), which is useful but not directly about the parameter. The parameter itself is sufficiently described 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 states it lists a campaign's targeting rules, specifies the type, method whitelist/blacklist, and rule values, and distinguishes from the sibling tool 'list_targeting_types' by directing the user to call that for type ids/names. The verb 'list' and resource 'targeting rules' are clear.

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 rules gate '/serve rotation' and the direct tracking link does not enforce them, providing context on when the rules are relevant. It also advises to call 'list_targeting_types' for type details. However, it does not explicitly state when to use this tool versus alternatives like list_campaigns or list_payout_rules.

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

list_targeting_typesList targeting rule typesA
Read-onlyIdempotent
Inspect

List targeting rule types available in this tenant (id, name, description), flagging the seeded types the /serve path does not actually evaluate. Use the id (or name) when setting campaign targeting rules. Enforced types: geo, device_type, zone_id, os, browser, unique_users.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.6/5.0
Behavior4/5

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

Annotations already indicate read-only, idempotent, non-destructive behavior. The description adds value by noting that seeded types not evaluated by /serve are flagged, 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.

Conciseness5/5

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

Two sentences, direct and front-loaded, with no extraneous information. Every sentence serves a 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?

Given no parameters and no output schema, the description fully covers what the tool returns and provides actionable details (enforced types), making it complete for this simple listing tool.

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?

With zero parameters, the description explains the output structure (id, name, description) and additional flagging, fully compensating for the absence of an output 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 lists targeting rule types available in the tenant, including id, name, description, and flags types not evaluated by /serve. It distinguishes from siblings like list_targeting_rules by focusing on types rather than rules.

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 using the id or name when setting campaign targeting rules and lists enforced types. While it lacks explicit when-not-to-use or alternatives, the context is sufficient for appropriate usage.

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

list_teamList team membersA
Read-onlyIdempotent
Inspect

List team members (user API keys) in the current namespace: email, role, manager, created/expiry. Never returns API tokens. Requires owner/manager (or a scoped manager role).

ParametersJSON Schema
NameRequiredDescriptionDefault
roleNoOptional role filter, e.g. owner, manager, publisher, advertiser, publisher_manager, advertiser_manager.
include_expiredNoInclude members whose expires_at is in the past. Default false.

TDQS

A4.5/5.0
Behavior5/5

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

Annotations already indicate read-only, idempotent, non-destructive behavior. The description adds valuable context: it never returns API tokens and requires specific permissions. This goes beyond annotations to disclose behavioral 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?

Two efficient sentences: first communicates purpose and output, second clarifies exclusions and permissions. 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.

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, lack of output schema is compensated by listing returned fields. Annotations cover safety and idempotency. The description is sufficiently complete for an AI agent to understand 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% with descriptions for both parameters (role filter and include_expired). The description does not add additional meaning to these parameters 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?

Clearly states the tool lists team members with specific fields (email, role, manager, created/expiry) and explicitly distinguishes itself by noting it never returns API tokens. The verb 'list' and resource 'team members' are 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?

Specifies required role (owner/manager or scoped manager) for usage, providing clear context on who can invoke it. Does not explicitly mention when not to use it or direct to alternatives, but given no sibling tool serves the same purpose, this is adequate.

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

list_traffic_sourcesList traffic sourcesA
Read-onlyIdempotent
Inspect

List the tenant's traffic sources — the ad networks bought from, each with the tracking template its linked zones render in get_zone_url/get_tracking_link and an optional postback template. The stored network API token is write-only and shown only as set/none. Read-only.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoSources per page (1–100).
offsetNoPagination offset.
statusNoFilter by status. Omit for all sources.

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, idempotentHint=true, and destructiveHint=false, so safety is covered. The description adds meaningful behavioral context beyond annotations by disclosing that the stored network API token is write-only and only shown as set/none, and by explaining that the tracking template is what linked zones render in get_zone_url/get_tracking_link. This is valuable non-obvious 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 dense sentences with no fluff. It front-loads the core purpose in the first clause and then packs only useful details: what is returned and the token visibility behavior. 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?

There is no output schema, so the description appropriately explains the main return fields: tracking template, optional postback template, and token presence as set/none. With three optional parameters already fully documented in the schema, this is complete for a read-only listing tool. Minor gap: it does not explicitly mention pagination or filtering, but the schema covers those and the description's core job is fulfilled.

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 limit, offset, and status are already fully documented in the schema. The description does not add any additional parameter semantics, such as how pagination interacts with the status filter, but the baseline of 3 is appropriate because the schema carries the parameter documentation burden completely.

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: 'List the tenant's traffic sources'. It further clarifies the scope (tenant-level), the kind of entities (ad networks), and the key fields returned (tracking template, postback template, token status), which clearly distinguishes it from sibling tools like create_traffic_source and update_traffic_source.

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 implies this is the read operation for traffic sources, and the read-only framing plus the mention of linked zone behavior gives context. It does not explicitly name alternatives like create_traffic_source/update_traffic_source or say 'use this when you need to view sources, not modify them', so there is no explicit exclusion, but the context is sufficiently clear.

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

list_zonesList zonesA
Read-onlyIdempotent
Inspect

List traffic-source zones in the current namespace. Filter by status and optionally by name (client-side contains match). Returns id, name, linked traffic source, status, postback_url, site_url, publisher. Paginated (default 20, max 100).

ParametersJSON Schema
NameRequiredDescriptionDefault
sortNoSort field. Default created_at.created_at
limitNoPage size (1–100). Default 20.
orderNoSort order. Default desc.desc
offsetNoPagination offset. Default 0.
statusNoFilter by zone status.
name_containsNoCase-insensitive substring match on zone name (client-side).

TDQS

A4.1/5.0
Behavior5/5

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

Annotations establish that this is read-only, idempotent, and non-destructive. The description adds valuable behavior beyond annotations: client-side contains matching, the exact set of returned fields, and pagination defaults/max. This gives an agent a clear picture of what happens when the tool is invoked.

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 efficiently packed sentences with no filler. The action and scope are front-loaded, followed by the most important filtering and return information, then pagination. Every clause 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 tool with no output schema, this description is complete: it lists the returned fields, the filter options, and pagination limits. Combined with the annotations, an agent has everything needed 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 description coverage is 100%, and each parameter already has a clear description. The tool description mostly restates status/name_contains and pagination behavior without adding new parameter-level meaning, so the schema carries the weight.

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 states a specific verb and resource ('List traffic-source zones') plus the namespace scope, which clearly conveys what the tool does. It is distinct enough from sibling list_traffic_sources, though it does not explicitly differentiate itself from sibling tools.

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 browsing and filtering zones by status/name with pagination. However, it does not provide explicit guidance about when to choose this tool over alternatives like get_zone_url, list_traffic_sources, or create_zone.

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

remove_targeting_ruleRemove a targeting ruleA
Destructive
Inspect

Remove one targeting rule from a campaign (safe merge — other rules are kept). Identify by rule_id, or by type + method. DRY-RUN by default; pass confirm=true to apply.

ParametersJSON Schema
NameRequiredDescriptionDefault
typeNoTargeting type id or name. Required with method when rule_id is omitted.
methodNowhitelist or blacklist. Required with type when rule_id is omitted.
confirmNofalse = dry-run preview (default). true = apply.
rule_idNoExisting rule id (from list_targeting_rules). Prefer this when known.
campaign_idYesCampaign to edit.

TDQS

A4.4/5.0
Behavior4/5

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

Beyond annotations (destructiveHint=true, readOnlyHint=false), the description adds that removal is a 'safe merge' preserving other rules, and reveals the dry-run default behavior. This provides useful context about non-destructive impact and preview capability.

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, using two short sentences to convey the core action, parameter identification methods, and default behavior. Every sentence adds value, with 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?

For a tool with 5 parameters, no output schema, and simple operation, the description covers the essential logic (what it does, how to specify the target, and the dry-run/default mode). The missing output format is a minor gap but not critical 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 coverage is 100%. The description adds value by explaining the alternative parameter groups (rule_id OR type+method) and the default behavior of confirm, going beyond individual parameter descriptions to clarify their interplay.

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 'remove', the resource 'targeting rule from a campaign', and adds context that it's a safe merge where other rules are kept, distinguishing it from siblings like set_targeting_rule and list_targeting_rules.

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 guidance on how to identify the rule (by rule_id or by type+method) and mentions the dry-run default with confirm=true to apply. It implicitly contrasts with set_targeting_rule but does not explicitly state 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.

set_campaign_statusRun or pause a campaignA
Destructive
Inspect

Run (activate) or pause a campaign. 'run' enters /serve zone rotation and counts against the plan's active-campaign limit (402 if exceeded). 'pause' removes the campaign from active serving, so both /serve selection and direct tracking links stop. DRY-RUN by default; pass confirm=true to apply. For name/offer/budget edits use update_campaign.

ParametersJSON Schema
NameRequiredDescriptionDefault
actionYesrun = active serving. pause = both /serve and direct tracking links stop.
confirmNofalse = dry-run preview (default). true = apply the status change.
campaign_idYesCampaign id to run or pause.

TDQS

A4.6/5.0
Behavior5/5

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

Annotations already indicate mutable (readOnlyHint=false) and potentially destructive (destructiveHint=true). The description adds significant context: dry-run by default, need confirm=true to apply, what 'run' does (enters rotation, counts against limit with specific error 402), and what 'pause' does (stops /serve and tracking links). This goes well 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: first states core purpose, second adds operational details and behavior, third provides explicit alternative. Every sentence is substantive with no fluff. Perfectly sized and structured for quick comprehension.

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 thoroughly covers when to use, behavior, and alternatives. However, since there is no output schema, the description could mention what the response looks like (e.g., status confirmation or updated campaign object). This minor gap prevents a perfect score.

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 descriptions in schema already explain each parameter. The description reinforces the action meanings but doesn't add new parameter-level details. Baseline 3 is appropriate since the schema already does the work.

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 specific verbs ('Run (activate) or pause') and identifies the resource ('campaign'), and explicitly distinguishes from sibling 'update_campaign' by saying 'For name/offer/budget edits use update_campaign.' This leaves no ambiguity about the tool's function.

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 clearly states when to use this tool (to run or pause a campaign), explains the default dry-run behavior and how to apply changes, and explicitly tells the agent when NOT to use it (for edits, use update_campaign). This is exemplary guidance.

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

set_payout_goalSet payout goal typeA
Destructive
Inspect

Set or clear a campaign's payout_goal_type (goal-based conversions). When set, spend and payout apply only when the conversion pixel's type= exactly matches; other types are still recorded with $0. Pass null (or empty string) to clear. DRY-RUN by default; pass confirm=true to apply.

ParametersJSON Schema
NameRequiredDescriptionDefault
confirmNofalse = dry-run preview (default). true = apply.
goal_typeYesGoal type string (e.g. "deposit", "lead", "purchase"), or null/"" to clear.
campaign_idYesCampaign to set the payout goal type on.

TDQS

A4.2/5.0
Behavior4/5

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

Annotations indicate destructiveHint=true and readOnlyHint=false, but the description adds significant behavioral context: the exact matching behavior on conversion pixel type, zero-dollar recording for non-matching types, and the dry-run safety mechanism. This 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?

Three sentences, each conveying essential information: purpose, behavior, and confirmation mechanism. No redundant words, front-loaded with primary action. Excellent structure.

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 tool's complexity (3 params, no output schema), the description covers core behavior, matching logic, dry-run, and clearing. It lacks details on error states or permissions, but the annotations provide destructive hint and open-world hint, making this level of completeness 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 coverage is 100% with clear parameter descriptions. The description reinforces key points (e.g., null/empty to clear) but does not add new semantic information beyond what the schema provides. 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 verb 'set or clear' and the resource 'campaign's payout_goal_type', with specific behavioral details about when spend/payout apply. It distinguishes itself from sibling payout tools by focusing on goal-based conversion matching.

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 usage guidance: use to set or clear a goal type, pass null/empty to clear, and dry-run default with confirm=true to apply. It does not explicitly contrast with alternatives, but the sibling list shows distinct tools, so context is sufficient.

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

set_payout_ruleSet a payout ruleA
Destructive
Inspect

Set a campaign payout rule (global or per-zone). Upserts: if a rule already exists for that scope it is replaced (delete + create, with the old payout restored if the create fails). Omit zone_id for the global rule; pass a zone UUID for a zone override. DRY-RUN by default; pass confirm=true to apply.

ParametersJSON Schema
NameRequiredDescriptionDefault
payoutYesPayout per conversion in USD (0.00001–9999.99999).
confirmNofalse = dry-run preview (default). true = apply.
zone_idNoZone UUID for a zone-specific override. Omit for the global rule.
campaign_idYesCampaign to set the payout rule on.

TDQS

A4.6/5.0
Behavior5/5

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

The description discloses the upsert behavior (delete+create) and rollback on failure, which goes well beyond the destructiveHint annotation. It also mentions dry-run default, providing full 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?

Three sentences, no wasted words. Front-loaded with the primary action, then provides key details on behavior and parameters. 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?

Given the tool's complexity (upsert, destructive, dry-run), the description covers essential behavioral aspects. It would benefit from mentioning the return value or success indicator, but it is mostly complete considering sibling tools provide listing/deletion.

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. The description adds value by clarifying the semantics of zone_id (global vs override) and confirm (dry-run vs apply), which is not detailed in the schema 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 verb 'Set' and the resource 'campaign payout rule', and further distinguishes global vs per-zone, which differentiates it from sibling tools like list_payout_rules or delete_payout_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?

It provides explicit instructions on when to use zone_id vs omit it for global rule, and explains the dry-run vs apply mode with confirm parameter. It does not contrast with alternatives like list_payout_rules, but the guidance is clear for correct usage.

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

set_sub_labelsSet sub labelsA
Destructive
Inspect

Set or clear tenant display names for sub1–sub5. Partial update — only provided keys change; pass null or "" to clear a label. Max 40 chars each. DRY-RUN by default; pass confirm=true to apply. Affects stats column titles and link helpers.

ParametersJSON Schema
NameRequiredDescriptionDefault
sub1NoDisplay name for sub1, or null/"" to clear.
sub2NoDisplay name for sub2, or null/"" to clear.
sub3NoDisplay name for sub3, or null/"" to clear.
sub4NoDisplay name for sub4, or null/"" to clear.
sub5NoDisplay name for sub5, or null/"" to clear.
confirmNofalse = dry-run preview (default). true = apply.

TDQS

A4.2/5.0
Behavior4/5

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

Discloses side effects on 'stats column titles and link helpers', dry-run default, and destructive nature (matches destructiveHint=true). Adds value beyond annotations by specifying partial update and null clearing.

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, no wasted words. First sentence states core purpose, followed by key behaviors. Efficient 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?

No output schema, but description explains dry-run mode and impacts. Covers mutation behavior, constraints, and required confirmation. Adequate for a 6-parameter tool with full schema 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 covers all 6 parameters at 100% with descriptions. Description adds 'max 40 chars each' (already in schema via maxLength) and 'partial update', but does not significantly enhance beyond 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 'Set or clear tenant display names for sub1–sub5', a specific verb-resource pair. Distinguishes from sibling list_sub_labels by implying mutation vs listing.

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?

Describes partial update behavior and dry-run vs apply. Implicitly separates from list_sub_labels. Could explicitly mention when to use this vs list_sub_labels 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.

set_targeting_ruleSet a targeting ruleA
Destructive
Inspect

Upsert one targeting rule on a campaign (safe merge — other rules are kept). Identify the type by id or name (e.g. geo, zone_id, device_type, os, browser, unique_users). If a rule with the same type + method already exists it is updated; otherwise a new one is added. rule is comma-separated values (geo: BR,MX; unique_users: visits/hours). Values are normalised to what /serve matches — an unmatched whitelist stops delivery. DRY-RUN by default; pass confirm=true to apply.

ParametersJSON Schema
NameRequiredDescriptionDefault
ruleYesRule value(s). Usually comma-separated (e.g. "BR,MX", zone UUIDs, "desktop"). unique_users uses "visits/hours".
typeYesTargeting type id (number) or name (e.g. "geo", "zone_id", "device_type"). Call list_targeting_types for the catalog.
methodYeswhitelist or blacklist.
confirmNofalse = dry-run preview (default). true = apply.
campaign_idYesCampaign to edit.

TDQS

A4.7/5.0
Behavior5/5

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

The description adds value beyond annotations by detailing the upsert behavior (safe merge, rule matching by type+method), the dry-run default and confirm flag, the comma-separated rule format, and the normalization effect on delivery. This fully informs the agent about the tool's operations.

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 (three sentences), front-loaded with the core purpose, and each sentence adds essential detail without redundancy. 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 5 parameters, no output schema, and moderate complexity (upsert, dry-run, rule format), the description covers all necessary aspects: identification, merge behavior, rule format, confirm flag, and delivery implications. It is complete for an AI agent to use 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?

While the schema already has 100% parameter descriptions, the description adds extra context: rule format with examples (geo: BR,MX; unique_users: visits/hours), and that type can be looked up via list_targeting_types. This enhances understanding beyond 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 clearly states it upserts a targeting rule on a campaign, using a safe merge that preserves other rules. The verb 'Upsert' and resource 'targeting rule on a campaign' are specific and distinguish it from sibling tools like remove_targeting_rule and list_targeting_rules.

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 (to add or update a rule), how to identify the type via list_targeting_types, and mentions the dry-run behavior. It implicitly distinguishes from removal and listing tools, though it does not explicitly state when not to use it.

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

update_campaignUpdate a campaignA
Destructive
Inspect

Update a campaign (partial): name, offer URL (redirect_url), status, rate, payment_model, start/end dates, daily/total budget, pacing. DRY-RUN by default; pass confirm=true to apply. For run/pause prefer set_campaign_status. Activating a paused campaign can hit the plan's active-campaign limit (402). Targeting rules and payout rules are separate tools.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameNoNew campaign name.
rateNoInternal advertiser rate (usually 0 for media-buying).
pacingNoBudget pacing: asap or even.
statusNoactive | paused | archived. active enters /serve rotation (plan limit).
confirmNofalse = dry-run preview (default). true = apply the update.
end_dateNoEnd bound: YYYY-MM-DD (tenant-local end of day), ISO timestamp with Z/UTC offset, epoch ms, or null to clear.
start_dateNoStart bound: YYYY-MM-DD (tenant-local start of day), ISO timestamp with Z/UTC offset, epoch ms, or null to clear.
campaign_idYesCampaign id to update.
daily_budgetNoDaily budget cap in USD, or null to clear.
redirect_urlNoOffer / lander URL (redirect target). http(s) required.
total_budgetNoTotal budget cap in USD, or null to clear.
payment_modelNocpa or cpm.

TDQS

A4.6/5.0
Behavior4/5

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

Annotations already indicate destructiveHint=true, but description adds valuable context: dry-run default behavior, confirmation requirement, and the specific error condition (plan limit). 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?

Three concise sentences: first lists updatable fields, second explains dry-run/confirm, third provides alternative and warning. 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?

Covers key behaviors (dry-run, activation limit, separation from other tools) and field semantics. Lacks description of return value or error details, but no output schema is provided, making this acceptable.

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%, but description adds extra context for some parameters (e.g., 'rate: Internal advertiser rate (usually 0 for media-buying)' and 'status: active enters /serve rotation (plan limit)'), which helps the agent understand usage beyond basic schema types.

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 'Update a campaign (partial)' and lists the specific fields it can modify. Distinguishes from sibling tools by naming set_campaign_status for run/pause and mentioning separate tools for targeting and payout rules.

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: DRY-RUN by default, pass confirm=true to apply, prefer set_campaign_status for run/pause, and warns about the active-campaign limit (402) when activating a paused campaign.

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

update_traffic_sourceUpdate a traffic sourceA
Destructive
Inspect

Update a traffic source (name, tracking_template, postback_template, api_token, status). Partial update — only provided fields change; pass null (or "") to clear a template or the stored api_token. Zones linked to the source pick the new tracking template up immediately in get_zone_url/get_tracking_link. DRY-RUN by default; pass confirm=true to apply.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameNoNew display name (unique per tenant).
statusNoactive or archived. Archiving keeps the source linked to its zones — deletion is only possible once no zone references it.
confirmNofalse = dry-run preview (default). true = apply the update.
api_tokenNoReplacement network API credential (stored write-only), or null/"" to clear the stored one. Omit to leave it unchanged.
postback_templateNoNew postback template (http(s) URL with our macros), or null to clear it.
tracking_templateNoNew tracking template (query string appended to the zone URL; must not start with ? or &), or null to clear it.
traffic_source_idYesTraffic source id to update.

TDQS

A4.6/5.0
Behavior5/5

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

Annotations declare destructiveHint=true and readOnlyHint=false, but the description adds crucial nuance: 'DRY-RUN by default; pass confirm=true to apply' reveals the tool is non-destructive unless explicitly confirmed. It also discloses the propagation side effect ('Zones linked to the source pick the new tracking template up immediately') and the partial-update behavior, going well beyond the annotation information.

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, starting with the operation and editable fields, then covering clearing semantics, propagation, and dry-run behavior in a few sentences. Every sentence adds a distinct behavioral fact with 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?

The description covers all call-affecting behaviors: partial updates, null clearing, zone propagation, and the dry-run/confirm default. With no output schema, an agent might not know what the dry-run returns, but the invocation path is well covered and the parameter schema fills in the remaining details.

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 baseline is 3. The description adds cross-cutting semantics not visible in individual parameter descriptions, such as the partial-update rule ('only provided fields change') and the effect on linked zones. This additional meaning justifies a score above 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 opens with 'Update a traffic source' and explicitly lists the editable fields (name, tracking_template, postback_template, api_token, status), making the verb and resource unambiguous. It clearly differentiates from sibling tools like create_traffic_source and update_zone by naming the resource type and the specific update 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?

The description provides clear context on how to use the tool: partial updates ('only provided fields change'), how to clear fields ('pass null (or "") to clear'), and the dry-run/confirm gate. It does not explicitly name alternatives or state when not to use it, but the usage context is strong enough for an agent to select it correctly.

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

update_zoneUpdate a zoneA
Destructive
Inspect

Update a traffic-source zone (name, status, postback_url, site_url, traffic_back_url, traffic_source_id). Partial update — only provided fields change. Pass null for a URL field or traffic_source_id to clear it. Linking a traffic source makes get_zone_url/get_tracking_link render its tracking template. DRY-RUN by default; pass confirm=true to apply.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameNoNew display name.
statusNoactive or inactive.
confirmNofalse = dry-run preview (default). true = apply the update.
zone_idYesZone id to update.
site_urlNoSite URL, or null to clear.
postback_urlNoS2S postback URL, or null to clear. Prefer including {source_click_id}.
traffic_back_urlNoTraffic-back URL, or null to clear.
traffic_source_idNoTraffic source to link (see list_traffic_sources; must be in this namespace), or null to unlink.

TDQS

A4.5/5.0
Behavior5/5

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

Annotations already mark this as non-read-only and destructive, so the description's added dry-run behavior ('DRY-RUN by default; pass confirm=true to apply') is highly valuable and clarifies the safety model. It also discloses side effects ('Linking a traffic source makes get_zone_url/get_tracking_link render its tracking template') and partial update behavior beyond what annotations 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?

Four sentences with no fluff. The most important facts—what is updated, partial update semantics, null-clearing, and the dry-run default—are front-loaded and each 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 an 8-parameter mutation with no output schema and destructive annotations, the description covers the critical operational needs: partial update, null semantics, dry-run confirmation, and the downstream effect on tracking template rendering. It is complete enough for an agent to call the tool 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. The description adds meaningful semantics beyond the schema: 'only provided fields change' clarifies partial update, and the linking side effect ties traffic_source_id to the get_zone_url/get_tracking_link behavior.

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 ('Update') and a specific resource ('a traffic-source zone'), then enumerates the exact fields affected. This clearly distinguishes it from update_traffic_source and create_zone, so an agent can select it without opening the schema.

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 gives useful operational context—partial update semantics, null-to-clear, and dry-run/confirm—but does not explicitly state when to choose this tool over alternatives such as update_traffic_source or set_campaign_status. Sibling tools are available, but no when-not-to-use guidance is provided.

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

whoamiShow the tenant this MCP is bound toA
Read-onlyIdempotent
Inspect

Return the tenant this MCP server is bound to: namespace, API base URL, and the derived dashboard URL (https://{namespace}.affset.com) — everything you need to hand the operator a working deep link, or to pick the right host for a URL you were about to guess. Also reports the tenant's company name, timezone and custom API domain when the /api/tenant read succeeds. Read-only, no side effects. Call this once at the start of a session instead of guessing the namespace from the owner's email — one MCP instance = exactly one tenant, and that binding is already fixed at startup.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

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, destructiveHint false. The description adds: conditional data (company info only if /api/tenant read succeeds), that binding is fixed at startup, and reassures 'Read-only, no side effects'. 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.

Conciseness4/5

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

The description is somewhat lengthy but front-loaded and every sentence adds value. Could be slightly more concise, but it efficiently packs all necessary 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?

Given zero parameters and no output schema, the description is remarkably complete: it lists all return fields, notes conditional availability, provides usage rationale, and gives an anti-pattern to avoid. No gaps remain.

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?

No parameters exist, so the description focuses entirely on output semantics, which are fully detailed: namespace, API base, dashboard URL, plus optional fields. This adds significant value beyond the empty input 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 returns tenant information including namespace, API base URL, dashboard URL, and optionally company name/timezone/custom domain. The verb 'return' and resource 'tenant' are specific. It distinguishes itself from sibling tools like list_campaigns or get_stats which operate on different resources.

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 advises calling 'once at the start of a session' and contrasts with 'guessing the namespace from the owner's email'. Mentions one MCP instance = one tenant. No sibling alternative is needed as no other tool serves this purpose.

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. 7 tool updatesv0.3.0
    • Addedcreate_traffic_source
    • Changedcreate_zone1 field changed
      • addedInput schema / properties / traffic_source_id
        Added value: +{
        +  "description": "Traffic source to link (see list_traffic_sources). Must be a source in this namespace. get_zone_url/get_tracking_link then render its tracking template.",
        +  "minLength": 1,
        +  "type": "string"
        +}
    • Changedget_tracking_link1 field changed
      • changedInput schema / properties / source_click_id / description
        Previous value: -"The traffic source's click-token macro, e.g. `{clickid}` (RichAds), `[CLICK_ID]`, `${SUBID}`. Default `{clickid}`. This is what conversion postbacks echo back via {source_click_id} — pass \"\" only to omit it deliberately."New value: +"The traffic source's click-token macro, e.g. `[CLICK_ID]` (RichAds), `${SUBID}` (PropellerAds). Default `{clickid}`. This is what conversion postbacks echo back via {source_click_id} — pass \"\" only to omit it deliberately. Zones linked to a traffic source render the source's tracking template instead; passing any explicit link parameter overrides that template."
    • Changedget_zone_url1 field changed
      • changedInput schema / properties / source_click_id / description
        Previous value: -"The traffic source's click-token macro, e.g. `{clickid}` (RichAds), `[CLICK_ID]`, `${SUBID}`. Default `{clickid}`. This is what conversion postbacks echo back via {source_click_id} — pass \"\" only to omit it deliberately."New value: +"The traffic source's click-token macro, e.g. `[CLICK_ID]` (RichAds), `${SUBID}` (PropellerAds). Default `{clickid}`. This is what conversion postbacks echo back via {source_click_id} — pass \"\" only to omit it deliberately. Zones linked to a traffic source render the source's tracking template instead; passing any explicit link parameter overrides that template."
    • Addedlist_traffic_sources
    • Addedupdate_traffic_source
    • Changedupdate_zone1 field changed
      • addedInput schema / properties / traffic_source_id
        Added value: +{
        +  "anyOf": [
        +    {
        +      "minLength": 1,
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "Traffic source to link (see list_traffic_sources; must be in this namespace), or null to unlink."
        +}
  2. 2 tool updatesv0.2.1
    • Changedget_stats5 fields changed
      • addedInput schema / properties / advertiser_email
        Added value: +{
        +  "description": "Narrow to one advertiser's campaigns, independent of group_by. Owner/manager: any advertiser. advertiser_manager: only one of their own assigned advertisers (else 403). Other roles: 403.",
        +  "format": "email",
        +  "type": "string"
        +}
      • addedInput schema / properties / conversion_type
        Added value: +{
        +  "description": "Filter by conversion type value(s) (e.g. deposit, register), comma-separated for multiple. Pass \"\" to select conversions recorded without a type.",
        +  "type": "string"
        +}
      • changedInput schema / properties / group_by / enum
        Previous value: -[
        -  "date",
        -  "campaign_id",
        -  "zone_id",
        -  "country",
        -  "conversion_type",
        -  "publisher_email",
        -  "sub1",
        -  "sub2",
        -  "sub3",
        -  "sub4",
        -  "sub5"
        -]New value: +[
        +  "date",
        +  "campaign_id",
        +  "zone_id",
        +  "country",
        +  "conversion_type",
        +  "publisher_email",
        +  "advertiser_email",
        +  "sub1",
        +  "sub2",
        +  "sub3",
        +  "sub4",
        +  "sub5"
        +]
      • addedInput schema / properties / paid_only
        Added value: +{
        +  "default": true,
        +  "description": "Drop informative conversions (postback_skipped=non_goal_type, e.g. lp_view pings that missed payout_goal_type) from the conversions count and CR. Silent conversions still count — not a payout>0 filter. Default true (matches the dashboard) so CR is not inflated above 100%. Set false for the raw count.",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / publisher_email
        Added value: +{
        +  "description": "Narrow to one publisher's zones, independent of group_by. Owner/manager: any publisher. publisher_manager: only one of their own assigned publishers (else 403). Other roles: 403.",
        +  "format": "email",
        +  "type": "string"
        +}
    • Changedlist_conversions1 field changed
      • addedInput schema / properties / paid_only
        Added value: +{
        +  "description": "true drops informative conversions — rows recorded with postback_skipped=non_goal_type because the pixel type missed the campaign's payout_goal_type. Silent conversions and other skip reasons still come back (not a payout>0 filter). Server-side (filters the whole dataset, not just this page). Works without payout visibility. Default false (all rows).",
        +  "type": "boolean"
        +}
  3. 1 tool updatev0.1.3
    • Addedget_campaign
  4. 2 tool updatesv0.1.1
    • Changedcreate_campaign1 field changed
      • changedInput schema / properties / user_email / description
        Previous value: -"Advertiser email that owns this campaign (required — the API rejects the call without it). Must already exist as a team member with the advertiser role; same as the dashboard's Advertiser dropdown. List candidates with list_team."New value: +"Advertiser email that owns this campaign (required — the API rejects the call without it). Must already exist as a team member with the advertiser role; same as the dashboard's Advertiser dropdown. List candidates with list_team, or create one with create_team_member."
    • Addedcreate_team_member
  5. 24 tool updatesv0.1.0
    • First observedcreate_campaign
    • First observedcreate_zone
    • First observedcut_zones
    • First observeddelete_payout_rule
    • First observedget_stats
    • First observedget_tracking_link
    • First observedget_zone_url
    • First observedlist_campaigns
    • First observedlist_conversions
    • First observedlist_payout_rules
    • First observedlist_sub_labels
    • First observedlist_targeting_rules
    • First observedlist_targeting_types
    • First observedlist_team
    • First observedlist_zones
    • First observedremove_targeting_rule
    • First observedset_campaign_status
    • First observedset_payout_goal
    • First observedset_payout_rule
    • First observedset_sub_labels
    • First observedset_targeting_rule
    • First observedupdate_campaign
    • First observedupdate_zone
    • First observedwhoami

TDQS

A4.1/5.0

Scored across 29 tools

Disambiguation5/5

Each tool targets a distinct resource or action, with clear boundaries between similar helpers like get_zone_url and get_tracking_link, and update_campaign vs set_campaign_status. Cross-references in descriptions further eliminate ambiguity.

Naming Consistency4/5

Most tools follow a consistent snake_case verb_noun pattern: list_*, create_*, get_*, update_*, set_*. Minor inconsistencies like delete_payout_rule vs remove_targeting_rule and non-pattern tools whoami and cut_zones keep it from a perfect score.

Tool Count2/5

29 tools exceeds the 25+ threshold and makes the server feel heavy for a single MCP surface, even though the underlying platform domain is broad. An agent faces a large decision space before it can pick the right operation.

Completeness4/5

The suite covers campaigns, zones, traffic sources, payout rules, targeting rules, stats, conversions, team members, and sub labels, with create/read/update operations for the main entities. The main gap is no delete/remove for campaigns, zones, traffic sources, or team members, but pause/status updates provide workarounds.

Maintenance

ActivityActive
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    B
    quality
    D
    maintenance
    Integrates PropellerAds' programmatic advertising platform with AI to automate campaign management, real-time optimization, and performance analysis. It enables users to create, scale, and manage ad campaigns through natural language commands for tasks like bid adjustment and zone blacklisting.
    21
    3
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables management and analysis of Meta (Facebook/Instagram) ads through natural language conversations, with 30 tools for reading and writing ad data.
    MIT
  • F
    license
    Not graded
    quality
    B
    maintenance
    Enables monitoring and managing multi-platform media buying accounts via natural language, detecting anomalies like creative fatigue and spend spikes, with AI-powered recommendations and a human-in-the-loop approval queue.
    -
  • F
    license
    Not graded
    quality
    D
    maintenance
    Enables querying ad campaign performance and setup across Meta, TikTok, and Google Ads using natural language through AI agents.
    1
    -