affset MCP server
This server lets a media buyer run an affset tenant from a chat client — pull stats, manage campaigns/zones/team/payouts/targeting, and generate tracking links.
Inspect the tenant:
whoamishows namespace, API base, dashboard URL, company/timezone.Stats:
get_statsreturns clicks, conversions, CR, payout, media cost, ROI grouped by date, campaign, zone, country, advertiser/publisher, or sub1–sub5, with filters (campaigns, zones, subs, conversion type, emails, paid_only).Campaigns: list, fetch full records, create (geo/payout/offer URL), update (budgets, dates, URLs), and run/pause.
Zones: list, create (with postback/site/traffic-back URLs), update, and link to traffic sources.
Team: list members (API keys redacted) and invite new members, returning the new API key once.
Traffic sources: list, create from presets (ExoClick, RichAds, etc.), update tracking/postback templates.
Links: generate
/servezone URLs and direct/track/clicktracking links with sub/cost macros and source templates.Optimization:
cut_zonesblacklists underperforming zones by CR/spend/ROI thresholds.Payouts: list/set/delete global or per-zone payout rules; set payout goal types.
Targeting: list rule types, list/set/remove targeting rules (geo, device, OS, browser, unique users).
Sub labels: list and set display names for sub1–sub5.
Conversions: audit conversion records with filters (paid_only server-side; click_id, source_click_id, type, zero_payout, payload client-side).
Docs: exposes the affset API reference as MCP resources.
Safety: mutations are dry-run by default (
confirm: trueto apply); read-only mode removes all mutating tools.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@affset MCP servershow me stats for campaign 'Summer Sale' grouped by zone"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
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 |
| Show the tenant this server is bound to: namespace, API base, derived dashboard URL, and (when readable) company / timezone / custom API domain. Read-only. |
| Traffic stats grouped by a dimension (date, campaign, zone, country, sub1–5, advertiser, publisher, …), optionally narrowed with |
| List campaigns (status / name filter, pagination). |
| 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 traffic-source zones (status / name filter, pagination, linked source). |
| List team members (email, role, manager). Never returns API tokens. |
| 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 once — |
| 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 |
| Run or pause a campaign ( |
| Partial update (name, offer URL, status, rate, budgets, dates, …). Dry-run by default; |
| Create a traffic-source zone (name + optional postback/site/traffic-back URLs, optional |
| Partial update (name, status, URLs, |
| 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 a traffic source, optionally from a network preset ( |
| Partial update (name, templates, api_token, status). Linked zones pick the new tracking template up immediately. Dry-run by default; |
| 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 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 |
| The |
| The |
| Blacklist underperforming zones on a campaign by threshold (CR / spend / ROI). Dry-run by default; |
| List a campaign's global + per-zone payout rules and its |
| Upsert a global or zone-specific payout. Dry-run by default; |
| Delete a global or zone-specific payout rule. Dry-run by default; |
| Set or clear |
| Catalog of targeting rule types, flagging the seeded ones |
| List a campaign's targeting rules, flagging any that have no effect. |
| Upsert one targeting rule (safe merge), normalised to what |
| Remove one targeting rule by id or type+method. Dry-run by default; |
| List tenant display names for sub1–sub5. |
| Set or clear sub labels (partial; |
| List conversion audit records (payout, spend, pixel type, payload, postback). |
Which URL do I give the network?
|
| |
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 |
| 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 |
|
| The full API reference — endpoints, auth, roles, examples. |
|
| 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 |
| Origin of the affset API, e.g. |
| Tenant API key. Its namespace must match |
| Tenant namespace (lowercase letters, numbers, hyphens; 3–63 chars — same rules as signup). |
| Optional, default |
| Optional, default |
| Optional, default |
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 Code —
claude mcp add --transport http affset https://mcp.affset.com/mcpthen 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.
From npm (recommended for self-hosting)
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/mcpSame 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 scriptThen 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 campaigns →
list_campaigns(status: "paused")show me everything about campaign 42 →
get_campaign(campaign_id: 42)show zones →
list_zones()who's on the team? →
list_team()add sarah@offer.com as a publisher →
create_team_member(email: "sarah@offer.com", role: "publisher")(dry-run) → confirmstats for today by sub1 →
get_stats(group_by: "sub1")stats by advertiser →
get_stats(group_by: "advertiser_email")stats for one publisher, grouped by zone →
get_stats(group_by: "zone_id", publisher_email: "publisher@example.com")stats including informative conversions →
get_stats(paid_only: false)set up RichAds end to end →
create_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 $2 →
create_campaign(user_email: "buyer@example.com", offer_url: "https://offer.example/lp?s={click_id}", geo: ["BR"], payout: 2)(dry-run) → confirmwhat URL do I paste into RichAds? →
get_zone_url()— a zone linked to a traffic source gets the source's template filled ingive me the link for campaign 42 again →
get_tracking_link(campaign_id: 42)run campaign 42 →
set_campaign_status(campaign_id: 42, action: "run")(dry-run) → confirmpause campaign 42 →
set_campaign_status(campaign_id: 42, action: "pause")(dry-run) → confirmset zone postback →
update_zone(zone_id, postback_url: "…")(dry-run) → confirmcut zones with CR < 0.2% and spend > $5 →
cut_zones(campaign_id, cr_max: 0.002, spend_min: 5)(dry-run) → confirmshow payouts for campaign 42 →
list_payout_rules(campaign_id: 42)set zone payout to $3 →
set_payout_rule(campaign_id: 42, payout: 3, zone_id: "…")(dry-run) → confirmonly pay on deposit conversions →
set_payout_goal(campaign_id: 42, goal_type: "deposit")(dry-run) → confirmwhat targeting types exist? →
list_targeting_types()whitelist BR+MX on campaign 42 →
set_targeting_rule(campaign_id: 42, type: "geo", method: "whitelist", rule: "BR,MX")(dry-run) → confirmname sub1 Zone, sub2 Creative →
set_sub_labels(sub1: "Zone", sub2: "Creative")(dry-run) → confirmshow recent conversions →
list_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 id →
list_conversions(source_click_id: "abc123")
Notes & limits
get_statsgroups by one dimension per call. Drill-down is a sequence of calls, each narrowing withcampaign_ids/zone_ids/sub1..sub5/conversion_type/advertiser_email/publisher_email/paid_onlyfilters. The two email filters select one user's campaigns or zones without changinggroup_by; access is limited to owner/manager or the corresponding scoped manager role. Filtering byconversion_typereturns conversion rows only (impressions, clicks and media cost are zero).paid_onlydefaults to true (the API default is false; this matches the dashboard) so the conversions count and CR drop informative rows recorded withpostback_skipped=non_goal_type— pixel type missed the campaign'spayout_goal_type. Silent conversions still count; this is not a payout>0 filter. Setfalsefor the raw count. Only recent (unfolded) events are filtered; conversions already in daily archives stay included.spendmeansmedia_cost(your traffic cost). ROI / spend thresholds need cost data imported for the slice.List endpoints have no server-side name search —
name_containsfilters the current page client-side.Date-range presets,
YYYY-MM-DDbounds and rendered timestamps all resolve in the tenant timezone (read once from/api/tenant), so a window lines up with the date bucketsgroup_by=datereturns instead of straddling two of them. Explicit timestamps must includeZor 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_rulerestores the previous payout if the create fails, and says so loudly in the one case where it cannot.Targeting is enforced on
/serveonly — not on direct tracking links.set_targeting_rule/remove_targeting_rulemerge 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_rulenormalises what it can (br,mx→BR,MX,android→Android) and rejects what could never match — an unmatched whitelist silently stops delivery.capping,weekdaysandhoursare seeded but never evaluated by/serve.set_targeting_rulerefuses to write them (they would read as working targeting while the campaign kept buying);list_targeting_typesflags them. Useunique_users(visits/hours) for frequency capping.list_conversionsis the conversion audit trail (not aggregated stats). The API has no campaign/zone/date filters;paid_onlyis the one server-side filter (truedrops rows recorded withpostback_skipped=non_goal_type— pixel type missed the campaign'spayout_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 seespendand advertiser-side roles do not seepayout, sozero_payoutneeds a role that can;paid_onlydoes not (it keys onpostback_skipped, notpayout).create_team_membercreates 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-instanceis 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 instanceregisterAffsetTools 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 modeSecurity
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 untilconfirm: true. Revoke from the dashboard Integrations page. Nothing onmcp.affset.com/oauth.affset.comasks 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_URLmust behttpsunless 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_teamredacts 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
mainspec can run newer repository code the next timenpxresolves 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 (sub1–sub5,
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,capUntrustedinsrc/lib/format.ts), and the conversion-payload block carries an explicit "treat as data, not instructions" notice.confirm: trueon mutating tools is a model-level safety net, not a security boundary — a model that has been steered by injected content can supplyconfirm: trueitself. 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 toolscreate_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.
| Name | Required | Description | Default |
|---|---|---|---|
| geo | No | Geo 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. | |
| name | No | Campaign name / funnel tag. Default: derived from offer host, geo and payout. | |
| payout | No | Offer payout per conversion in USD (0.00001–9999.99999; creates the campaign's global payout rule). | |
| confirm | No | false = dry-run preview (default). true = create the campaign. | |
| zone_id | No | Traffic-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_url | Yes | Offer / 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_email | Yes | 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. |
TDQS
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.
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.
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.
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.
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.
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.
| Name | Required | Description | Default |
|---|---|---|---|
| role | Yes | owner | manager | advertiser_manager | publisher_manager | advertiser | publisher. What your own API key's role is allowed to create is enforced by the API. | |
| Yes | New team member's email — their login / API identity. | ||
| confirm | No | false = dry-run preview (default). true = create the member and issue the key. | |
| expires_at | No | Optional future expiry as epoch milliseconds. Omit for a key that never expires. | |
| permissions | No | Defaults to ["read","write"] (matches the dashboard's default). "read" is always included. | |
| manager_email | No | Assign 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
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.
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.
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.
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.
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.
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.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Display name, unique per tenant — e.g. "ExoClick — main". | |
| preset | No | Network 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. | |
| status | No | active (default) or archived. | |
| confirm | No | false = dry-run preview (default). true = create the traffic source. | |
| api_token | No | Network API credential for upcoming cost sync. Stored write-only — reads only ever return has_api_token. | |
| postback_template | No | The 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_template | No | Query 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
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.
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.
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.
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.
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.
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.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Zone display name (traffic source / placement). | |
| confirm | No | false = dry-run preview (default). true = create the zone. | |
| site_url | No | Optional site / inventory URL. | |
| user_email | No | Optional publisher email to own this zone (owner/manager only). | |
| postback_url | No | S2S postback URL for the traffic source. Should include {source_click_id} so conversions can be attributed back to the source click. | |
| traffic_back_url | No | Optional traffic-back / fallback URL when no campaign can serve. | |
| traffic_source_id | No | 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. |
TDQS
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.
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.
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.
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.
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.
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 zonesADestructiveInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| to | No | Explicit end bound: YYYY-MM-DD (tenant-local end of day), ISO timestamp with Z/UTC offset, or epoch ms. | |
| from | No | Explicit start bound: YYYY-MM-DD (tenant-local start of day), ISO timestamp with Z/UTC offset, or epoch ms. | |
| range | No | Evaluation window. Ignored if from/to are given. Defaults to last 7 days. | |
| cr_max | No | Cut zones with conversion rate BELOW this fraction (e.g. 0.002 = 0.2%). | |
| confirm | No | false = dry-run preview (default). true = apply the blacklist changes. | |
| roi_max | No | Cut zones with ROI BELOW this fraction (e.g. -0.3 = -30%). Needs cost data. | |
| spend_min | No | Cut zones with media_cost ABOVE this many dollars (e.g. 5 = $5). | |
| min_clicks | No | Ignore zones with fewer clicks than this (significance guard). Default 10. | |
| campaign_id | Yes | Campaign whose zone blacklist to edit. |
TDQS
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.
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.
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.
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.
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.
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 ruleADestructiveInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| confirm | No | false = dry-run preview (default). true = apply. | |
| zone_id | No | Zone UUID of the zone-specific rule. Omit to delete the global rule. | |
| campaign_id | Yes | Campaign whose payout rule to delete. |
TDQS
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.
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.
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.
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.
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.
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 recordARead-onlyIdempotentInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| campaign_id | Yes | Campaign id to fetch. |
TDQS
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.
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.
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.
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.
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.
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 statsARead-onlyIdempotentInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| to | No | Explicit end bound: YYYY-MM-DD (tenant-local end of day), ISO timestamp with Z/UTC offset, or epoch ms. | |
| from | No | Explicit start bound: YYYY-MM-DD (tenant-local start of day), ISO timestamp with Z/UTC offset, or epoch ms. | |
| sub1 | No | Filter by sub1 value(s), comma-separated for multiple. | |
| sub2 | No | Filter by sub2 value(s). | |
| sub3 | No | Filter by sub3 value(s). | |
| sub4 | No | Filter by sub4 value(s). | |
| sub5 | No | Filter by sub5 value(s). | |
| range | No | Convenience time window. Ignored if from/to are given. Defaults to today. | |
| group_by | No | Dimension to group by (one at a time). Drill down by changing this across calls. | date |
| zone_ids | No | Restrict to these zone IDs. | |
| paid_only | No | 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. | |
| campaign_ids | No | Restrict to these campaign IDs. | |
| conversion_type | No | Filter by conversion type value(s) (e.g. deposit, register), comma-separated for multiple. Pass "" to select conversions recorded without a type. | |
| publisher_email | No | 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. | |
| advertiser_email | No | 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. |
TDQS
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.
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.
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.
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.
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.
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_tracking_linkGet a campaign's tracking linkARead-onlyIdempotentInspect
Get the tracking link for an existing campaign + zone — the /track/click link that goes straight to that one campaign with no rotation or targeting checks. Both the campaign and zone must be active for the public link to work. Same link create_campaign echoes on create; this re-derives it later, for any campaign, with whatever sub values you want. A zone linked to a traffic source renders that source's tracking template instead. Uses the tenant's custom API domain when one is set. Read-only: builds the URL, changes nothing.
| Name | Required | Description | Default |
|---|---|---|---|
| cost | No | The 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. | |
| sub1 | No | Value or macro for sub1 (analytics only). Defaults to a placeholder named after the tenant's label for this slot. | |
| sub2 | No | Value or macro for sub2 (analytics only). Defaults to a placeholder named after the tenant's label for this slot. | |
| sub3 | No | Value or macro for sub3 (analytics only). Defaults to a placeholder named after the tenant's label for this slot. | |
| sub4 | No | Value or macro for sub4 (analytics only). Defaults to a placeholder named after the tenant's label for this slot. | |
| sub5 | No | Value or macro for sub5 (analytics only). Defaults to a placeholder named after the tenant's label for this slot. | |
| zone_id | No | Traffic-source zone to attribute the clicks to. Optional when the namespace has exactly one active zone — it is picked automatically. | |
| campaign_id | Yes | Campaign the link should send traffic to. | |
| source_click_id | No | 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. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark the tool as readOnly and idempotent, and the description adds behavior not inferable from the schema: both resources must be active, source-linked zones render the source's template, and the tenant's custom API domain is used. The explicit 'Read-only: builds the URL, changes nothing' reinforces rather than contradicts 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.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the core purpose and then adds prerequisite, derivation, source-template, domain, and safety details in a compact paragraph. Minor redundancy with the source_click_id parameter description keeps it from being a perfect 5, but every sentence still earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only URL builder with 9 parameters and no output schema, this description covers prerequisites, derivation behavior, source-template overrides, domain selection, and side-effect safety. An agent has enough information to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, and the schema itself documents each parameter well. The description adds useful context by connecting those parameters to the generated URL — 'with whatever sub values you want' — and by explaining how source-linked zones affect the resulting link.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a concrete verb and resource ('Get the tracking link for an existing campaign + zone'), explains what kind of link it is ('/track/click ... no rotation or targeting checks'), and distinguishes it from the creation-time link generated by create_campaign. This makes it easy to separate from get_zone_url and other campaign tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It states when the tool is appropriate ('existing campaign + zone', after creation), and notes the same link is produced by create_campaign at creation, implying this is the re-derivation path. It also flags the prerequisite that campaign and zone must be active. It doesn't explicitly enumerate when not to use it versus get_zone_url, but the context is clear.
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 sourceARead-onlyIdempotentInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| cost | No | The 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. | |
| sub1 | No | Value or macro for sub1 (analytics only). Defaults to a placeholder named after the tenant's label for this slot. | |
| sub2 | No | Value or macro for sub2 (analytics only). Defaults to a placeholder named after the tenant's label for this slot. | |
| sub3 | No | Value or macro for sub3 (analytics only). Defaults to a placeholder named after the tenant's label for this slot. | |
| sub4 | No | Value or macro for sub4 (analytics only). Defaults to a placeholder named after the tenant's label for this slot. | |
| sub5 | No | Value or macro for sub5 (analytics only). Defaults to a placeholder named after the tenant's label for this slot. | |
| zone_id | No | Zone 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_id | No | 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. |
TDQS
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.
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.
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.
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.
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.
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 campaignsARead-onlyIdempotentInspect
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).
| Name | Required | Description | Default |
|---|---|---|---|
| sort | No | Sort field. Default created_at. | created_at |
| limit | No | Page size (1–100). Default 20. | |
| order | No | Sort order. Default desc. | desc |
| offset | No | Pagination offset. Default 0. | |
| status | No | Filter by campaign status. | |
| name_contains | No | Case-insensitive substring match on campaign name (client-side). |
TDQS
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.
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.
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.
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.
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.
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 conversionsARead-onlyIdempotentInspect
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).
| Name | Required | Description | Default |
|---|---|---|---|
| sort | No | Sort field. Default created_at. | created_at |
| type | No | Match payload `type` (pixel goal type), case-insensitive (client-side, current page). | |
| limit | No | Page size (1–100). Default 20. | |
| order | No | Sort order. Default desc. | desc |
| offset | No | Pagination offset. Default 0. | |
| click_id | No | Exact click_id match (client-side, current page). | |
| paid_only | No | 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). | |
| zero_payout | No | If 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_id | No | Exact source_click_id match (client-side, current page). | |
| payload_contains | No | Substring match on raw payload JSON (client-side, current page). |
TDQS
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.
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.
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.
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.
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.
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 rulesARead-onlyIdempotentInspect
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).
| Name | Required | Description | Default |
|---|---|---|---|
| campaign_id | Yes | Campaign whose payout rules to list. |
TDQS
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.
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.
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.
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.
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.
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 labelsARead-onlyIdempotentInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
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.
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.
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.
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.
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.
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 rulesARead-onlyIdempotentInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| campaign_id | Yes | Campaign whose targeting rules to list. |
TDQS
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.
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.
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.
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.
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.
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 typesARead-onlyIdempotentInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
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.
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.
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.
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.
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.
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 membersARead-onlyIdempotentInspect
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).
| Name | Required | Description | Default |
|---|---|---|---|
| role | No | Optional role filter, e.g. owner, manager, publisher, advertiser, publisher_manager, advertiser_manager. | |
| include_expired | No | Include members whose expires_at is in the past. Default false. |
TDQS
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.
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.
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.
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.
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.
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 sourcesARead-onlyIdempotentInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Sources per page (1–100). | |
| offset | No | Pagination offset. | |
| status | No | Filter by status. Omit for all sources. |
TDQS
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.
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.
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.
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.
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.
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 zonesARead-onlyIdempotentInspect
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).
| Name | Required | Description | Default |
|---|---|---|---|
| sort | No | Sort field. Default created_at. | created_at |
| limit | No | Page size (1–100). Default 20. | |
| order | No | Sort order. Default desc. | desc |
| offset | No | Pagination offset. Default 0. | |
| status | No | Filter by zone status. | |
| name_contains | No | Case-insensitive substring match on zone name (client-side). |
TDQS
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.
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.
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.
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.
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.
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 ruleADestructiveInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| type | No | Targeting type id or name. Required with method when rule_id is omitted. | |
| method | No | whitelist or blacklist. Required with type when rule_id is omitted. | |
| confirm | No | false = dry-run preview (default). true = apply. | |
| rule_id | No | Existing rule id (from list_targeting_rules). Prefer this when known. | |
| campaign_id | Yes | Campaign to edit. |
TDQS
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.
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.
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.
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.
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.
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 campaignADestructiveInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| action | Yes | run = active serving. pause = both /serve and direct tracking links stop. | |
| confirm | No | false = dry-run preview (default). true = apply the status change. | |
| campaign_id | Yes | Campaign id to run or pause. |
TDQS
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.
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.
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.
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.
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.
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 typeADestructiveInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| confirm | No | false = dry-run preview (default). true = apply. | |
| goal_type | Yes | Goal type string (e.g. "deposit", "lead", "purchase"), or null/"" to clear. | |
| campaign_id | Yes | Campaign to set the payout goal type on. |
TDQS
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.
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.
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.
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.
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.
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 ruleADestructiveInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| payout | Yes | Payout per conversion in USD (0.00001–9999.99999). | |
| confirm | No | false = dry-run preview (default). true = apply. | |
| zone_id | No | Zone UUID for a zone-specific override. Omit for the global rule. | |
| campaign_id | Yes | Campaign to set the payout rule on. |
TDQS
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.
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.
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.
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.
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.
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 labelsADestructiveInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| sub1 | No | Display name for sub1, or null/"" to clear. | |
| sub2 | No | Display name for sub2, or null/"" to clear. | |
| sub3 | No | Display name for sub3, or null/"" to clear. | |
| sub4 | No | Display name for sub4, or null/"" to clear. | |
| sub5 | No | Display name for sub5, or null/"" to clear. | |
| confirm | No | false = dry-run preview (default). true = apply. |
TDQS
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.
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.
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.
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.
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.
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 ruleADestructiveInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| rule | Yes | Rule value(s). Usually comma-separated (e.g. "BR,MX", zone UUIDs, "desktop"). unique_users uses "visits/hours". | |
| type | Yes | Targeting type id (number) or name (e.g. "geo", "zone_id", "device_type"). Call list_targeting_types for the catalog. | |
| method | Yes | whitelist or blacklist. | |
| confirm | No | false = dry-run preview (default). true = apply. | |
| campaign_id | Yes | Campaign to edit. |
TDQS
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.
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.
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.
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.
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.
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 campaignADestructiveInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | New campaign name. | |
| rate | No | Internal advertiser rate (usually 0 for media-buying). | |
| pacing | No | Budget pacing: asap or even. | |
| status | No | active | paused | archived. active enters /serve rotation (plan limit). | |
| confirm | No | false = dry-run preview (default). true = apply the update. | |
| end_date | No | End bound: YYYY-MM-DD (tenant-local end of day), ISO timestamp with Z/UTC offset, epoch ms, or null to clear. | |
| start_date | No | Start bound: YYYY-MM-DD (tenant-local start of day), ISO timestamp with Z/UTC offset, epoch ms, or null to clear. | |
| campaign_id | Yes | Campaign id to update. | |
| daily_budget | No | Daily budget cap in USD, or null to clear. | |
| redirect_url | No | Offer / lander URL (redirect target). http(s) required. | |
| total_budget | No | Total budget cap in USD, or null to clear. | |
| payment_model | No | cpa or cpm. |
TDQS
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.
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.
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.
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.
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.
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 sourceADestructiveInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | New display name (unique per tenant). | |
| status | No | active or archived. Archiving keeps the source linked to its zones — deletion is only possible once no zone references it. | |
| confirm | No | false = dry-run preview (default). true = apply the update. | |
| api_token | No | Replacement network API credential (stored write-only), or null/"" to clear the stored one. Omit to leave it unchanged. | |
| postback_template | No | New postback template (http(s) URL with our macros), or null to clear it. | |
| tracking_template | No | New tracking template (query string appended to the zone URL; must not start with ? or &), or null to clear it. | |
| traffic_source_id | Yes | Traffic source id to update. |
TDQS
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.
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.
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.
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.
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.
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 zoneADestructiveInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | New display name. | |
| status | No | active or inactive. | |
| confirm | No | false = dry-run preview (default). true = apply the update. | |
| zone_id | Yes | Zone id to update. | |
| site_url | No | Site URL, or null to clear. | |
| postback_url | No | S2S postback URL, or null to clear. Prefer including {source_click_id}. | |
| traffic_back_url | No | Traffic-back URL, or null to clear. | |
| traffic_source_id | No | Traffic source to link (see list_traffic_sources; must be in this namespace), or null to unlink. |
TDQS
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.
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.
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.
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.
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.
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 toARead-onlyIdempotentInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
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.
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.
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.
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.
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.
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.
7 tool updates
v0.3.0- Added
create_traffic_source - Changed
create_zone1 field changed- added
Input schema / properties / traffic_source_idAdded 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" +}
- Changed
get_tracking_link1 field changed- changed
Input schema / properties / source_click_id / descriptionPrevious 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."
- Changed
get_zone_url1 field changed- changed
Input schema / properties / source_click_id / descriptionPrevious 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."
- Added
list_traffic_sources - Added
update_traffic_source - Changed
update_zone1 field changed- added
Input schema / properties / traffic_source_idAdded 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 tool updates
v0.2.1- Changed
get_stats5 fields changed- added
Input schema / properties / advertiser_emailAdded 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" +} - added
Input schema / properties / conversion_typeAdded 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" +} - changed
Input schema / properties / group_by / enumPrevious 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" +] - added
Input schema / properties / paid_onlyAdded 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" +} - added
Input schema / properties / publisher_emailAdded 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" +}
- Changed
list_conversions1 field changed- added
Input schema / properties / paid_onlyAdded 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" +}
1 tool update
v0.1.3- Added
get_campaign
2 tool updates
v0.1.1- Changed
create_campaign1 field changed- changed
Input schema / properties / user_email / descriptionPrevious 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."
- Added
create_team_member
24 tool updates
v0.1.0- First observed
create_campaign - First observed
create_zone - First observed
cut_zones - First observed
delete_payout_rule - First observed
get_stats - First observed
get_tracking_link - First observed
get_zone_url - First observed
list_campaigns - First observed
list_conversions - First observed
list_payout_rules - First observed
list_sub_labels - First observed
list_targeting_rules - First observed
list_targeting_types - First observed
list_team - First observed
list_zones - First observed
remove_targeting_rule - First observed
set_campaign_status - First observed
set_payout_goal - First observed
set_payout_rule - First observed
set_sub_labels - First observed
set_targeting_rule - First observed
update_campaign - First observed
update_zone - First observed
whoami
TDQS
Scored across 29 tools
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.
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.
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.
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
Related MCP Connectors
Conversational access to advertising performance data, creative analysis, and campaign insights
Conversational access to advertising performance data, creative analysis, and campaign insights
- mcpOAuthio.autoady.www
Run Meta ads from your AI assistant: briefings, drop diagnosis, winners, budgets, receipts.
- AdCrunchOAuthdev.adcrunch
Ask AI about your ads — query Meta, TikTok, and Google Ads performance in natural language.
Related MCP Servers
- AlicenseBqualityDmaintenanceIntegrates 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.213MIT
- AlicenseNot gradedqualityDmaintenanceEnables management and analysis of Meta (Facebook/Instagram) ads through natural language conversations, with 30 tools for reading and writing ad data.MIT
- FlicenseNot gradedqualityBmaintenanceEnables 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.-

AdCrunch MCP Serverofficial
FlicenseNot gradedqualityDmaintenanceEnables querying ad campaign performance and setup across Meta, TikTok, and Google Ads using natural language through AI agents.1-