0.3.2 exposes ten tools with the default configuration. Four additional legacy launcher.* tools are available only when Launcher is explicitly enabled. Use MCP discovery to check the tools available on your connection. Account-scoped tools use the advertising account selected during workspace-token issuance.
Start with the MCP introduction for supported tasks and access boundaries. For client configuration and your first account read, follow Setup.
The server version is separate from the MCP protocol revision. For custom clients, see the stateless discovery and request-header requirements. MCP App support is advertised under capabilities.extensions["io.modelcontextprotocol/ui"] in the server card.
Conditional legacy tools
The four
launcher.* entries above describe the conditional legacy contract. Launcher is disabled by default, so those tools are absent from discovery and the file-import route returns 404.Test mode and production boundaries
Usehttps://plainrouter.com/mcp/sandbox to prove an integration without an
account or credential. It exposes four tools:
Every result is marked with
"sandbox": true. The endpoint reads no tenant
data, writes nothing, and contacts no advertising provider. It does not expose
production proposal, creative, approval, Launcher, or spend-affecting tools.
The production endpoint is https://plainrouter.com/mcp. Its handshake, tool
and resource catalogs, and static ui:// MCP App shells are publicly
discoverable. Every tool call and account-data read requires an account-bound
workspace execution token.
Busy-workspace errors
A concurrent operation can returnworkspace_lock_timeout through MCP. Affected JSON HTTP routes return HTTP 503 with Retry-After: 1; the browser shows The workspace is busy. Retry the operation shortly. Wait before retrying and retain the original idempotency key for the same operation.
Shared authorization and scope
Signals read tools require an active principal withad-account.read. verify_signal_ingestion requires signals.verify. propose-actions requires actions.propose. Creative-library reads require creative.read. Creative proposal tools require both creative.write and actions.propose. Every Launcher tool requires the ad-account.read baseline.
Clients authenticate with an owner-issued workspace execution token. A Read token derives the read scopes. Write and Admin tokens also derive the proposal scopes. OAuth management credentials cannot authenticate to the MCP server.
launcher.batch_status accepts a Read, Write, or Admin token. launcher.draft_batch, launcher.preview_batch, launcher.execute_batch, and the file-import adapter require the Write or Admin tier. Drafting also requires creative.write and actions.propose; preview and the closed execution entry require actions.propose.
Every production call also checks an active, unexpired grant for the same workspace and the requested operation. Revoked grants cannot authorize a call. The revoke_grant tool applies its separate revocation-authority check described below.
Scoped responses identify:
destination_id and dataset_id are null until the authorized account has a matching destination. The caller cannot provide a different account ID.
get_account_state
Call this first in every account-specific workflow. It returns:
- Agent ID, name, and granted permissions.
- Shared scope.
- Advertising account ID, platform-native ID, name, platform, currency, timezone, and status.
- Workspace ID and name.
- Platform connection status and expiry.
- Signal ID, status, collection domain, and connected destination.
- Available capability flags.
- Response generation time.
verified_performance becomes true only when the matching destination is active. It describes stored reconciliation availability, not live target performance. The marketing_api_reads and writes flags describe this Signals-oriented account-state call; use the separately permissioned creative tools for live creative-library reads and governed creative proposals.
get_signal_health
Use this diagnostic for collection, delivery, and stored account health. Both production and sandbox accept the same optional reporting window:
activity.completed_window: arrivals for the retained completed-day reporting window.activity.today_so_far: the separate incomplete local-day arrival count.activity.receivingandactivity.last_event_at: collection activity and freshness.delivery: non-test delivery counts and acceptance rate for the last 24 hours, independently of the requested arrival window.match_quality: the latest stored Meta score, measurement time, and history when available.performance: stored reconciliation for the requested window.diagnostics,data_sources, andgenerated_at: explanations, provenance, and response freshness.
partial marks that component, not a reduced total. Missing platform history is not zero activity. See Signals measurements and troubleshooting.
This call reads stored measurements. It does not trigger a live Meta Marketing API read.
get_performance
Use this tool for a stored reconciliation window.
Plainrouter excludes modeled and portfolio-only events from this proposal-evidence path. Only eligible observed reconciliation data contributes to its performance fields.
Input
Output
The response includes:- Shared scope.
- Requested period with
days,since, anduntil. - Measurability state.
- Gateway-verified accepted count.
- Meta-reported count.
- Observed gap.
- Alignment percentage.
- Number of alert days.
- Latest report date.
- Totals grouped by event.
- Daily report rows.
data_source: "stored_reconciliation_reports".marketing_api_called: false.- Response generation time.
platform_claimed_clicks, platform_impressions, platform_spend, per-day platform_daily read states, and claimed_clicks_last_read_at when available. These platform fields are descriptive context, not admissible spend or target-performance evidence for Actions proposals.
Measurability
no_history and stale_history. When quantitative_citations_allowed is false, an agent must not cite count, gap, alignment, alert-day, daily, or by-event values as proposal evidence.
verify_signal_ingestion
Use this tool to run an identity-free write-path diagnostic against an active Signal. It accepts no input and resolves the Signal from the authorized workspace.
The tool writes one idempotent signal_verification event and returns:
duplicate: true. The tool has no spend capability.
The call fails if the connection lacks signals.verify or the authorized workspace has no active Signal.
revoke_grant
Revoke a workspace grant using its 26-character ULID in grant_id. Obtain the grant ID from the authorized token-management response; it is different from the token ID and plaintext credential.
revoke_grant permission or authority as the human who delegated the target agent. Admin-tier grants include revocation permission. Knowing a grant ID does not grant access to another workspace.
The tool returns grant_id, workspace_id, and revoked_at. It records the revocation in the audit chain and prevents credentials backed by that grant from authorizing subsequent operations. An authorized repeat returns the existing revocation without creating another one. It does not undo previously executed advertising actions.
Invalid grant-ID input fails validation. Missing or inactive caller authorization, another workspace’s grant, or insufficient revocation authority is refused.
show_spend_cap_approval
This read-only, idempotent tool renders the static
ui://resources/spend-cap-approval-app MCP App preview. It accepts no input and
returns only a confirmation that the preview card loaded.
The card contains fixed demonstration values and is labeled Preview — not a
live control. Its Approve and Reject buttons are disabled. The tool
does not read an account, submit an approval, call another tool, persist data,
contact Meta, or change spend. Use it only to verify that an MCP host can render
Plainrouter’s app presentation.
propose-actions
This tool validates the action shapes, captures fresh evidence provenance, evaluates policy, and creates one batch.
Top-level input
Each evidence declaration contains:
source_tool values are get_account_state, get_signal_health, and get_performance. Creative actions can also use the action-bound sources get-creative-library and staged-asset-manifest.
Every field path must exist in a fresh server-side capture. Aggregate sources cannot include action_index. An action-bound source requires action_index and can cite only its matching creative action.
Action object
Every action has this common shape. Theset_status example below describes a recommendation only: delivery-status and budget execution are disabled, even after approval. For the executable creative path, use Create governed Meta creatives.
ad_account, campaign, ad_set, and ad.
Action parameters
adjust_budget
adjust_budget
Requires
new_daily_budget_minor, a positive integer in the account currency’s minor unit. For example, 4900 means 49.00 for a two-decimal currency.set_status
set_status
Requires
status equal to active or paused.duplicate_ad_with_creative
duplicate_ad_with_creative
Requires
asset_id and status: "paused". An optional name_suffix can identify the duplicate.upload_asset
upload_asset
Requires
staged_asset_id, asset_type (image or video), filename, and a lowercase 64-character content_sha256. Optional fields include detected mime_type and positive size_bytes.Evidence restrictions
Plainrouter rejects evidence paths that claim campaign, ad set, ad, target, CPA, spend, budget, or learning-phase state from aggregate Signals reads.get_signal_health is diagnostic and cannot support a batch containing adjust_budget, set_status, or duplicate_ad_with_creative. This rule applies to the entire batch: adding an upload_asset action does not make a mixed spend-affecting proposal eligible. An upload-only upload_asset batch is the current non-spend exception and may retain signal-health context.
Use get_performance when a spend-affecting proposal needs stored reconciliation-derived performance evidence.
It also rejects:
- Unknown source tools.
- Field paths absent from the cited response.
- Quantitative performance fields from non-measurable history.
- A target source other than
human_supplied. - Proposals from a connection without
actions.propose.
Response
The response includes the batch ID, scope, evidence provenance, status, policy decision and reasons, approval requirement, queue URL, proposer, rationale, and normalized action records. Evidence provenance records the source service, scope level, exact fields, observation time, reporting window, measurability, and the target-selection boundary.get-creative-library
This tool makes live Meta Marketing API reads for the approved account. It requires creative.read and an active Meta connection with ads_read or ads_management.
Input
Output
The response includes:- Images as
image:<hash>and videos asvideo:<id>. - Names, status, dimensions or duration, previews, and creation time when available.
- Ads historically associated with each asset.
- Aggregated last-30-day impressions, clicks, spend, and conversions.
- Separate image and video pagination cursors.
performance_window: "last_30d".
upload-asset
This tool validates and privately stages an image, then creates one canonical upload_asset proposal. It requires creative.write and actions.propose.
The response wraps the canonical proposal with its ID, scope, evidence provenance, immutable execution-mode snapshot, status, policy result, approval requirement, approval-queue URL, and action record.
Plainrouter freezes the staged bytes and records only the approved manifest fields: staged ID, SHA-256 digest, detected MIME type, byte size, account binding, and frozen/immutable state. Raw bytes do not enter the action or audit record.
Only JPEG and PNG upload execution is supported. Video upload execution remains blocked.
duplicate-ad-with-creative
This tool creates one canonical duplicate_ad_with_creative proposal. It requires creative.write and actions.propose.
Plainrouter re-reads the source ad and selected asset under the approved account before creating the proposal. The normalized action always contains
status: "paused".
If approved in an executable mode, the worker rechecks policy, creates the copy as PAUSED, persists the provider ad ID in a durable receipt, and verifies the exact receipt-addressed object. IN_PROCESS can enter scheduled verification for up to 48 hours. The batch is not Landed until every receipt is exactly verified.
launcher.draft_batch
Available only when legacy Launcher is enabled. This tool creates a Launcher draft batch from Drive assets already synced into the token’s workspace. It writes only the Plainrouter draft model; it does not write to Meta, evaluate the final execution gate, or activate spend.
It requires an owner-issued workspace token with the Write or Admin tier.
Input
Overrides use contract version
v: 1 and can contain up to five primary_texts, headlines, and descriptions, plus website_url and display_link.
Workspace and account IDs are never accepted as input. Plainrouter derives them from the execution token. A Drive link that is unknown, stale, failed, removed, or belongs to another workspace is rejected without widening the token scope.
Output
The response includes the draft batch ID and status, frozen tier and capacity limits, item and media counts, accepted items, bounded rejected-item reason codes, import provenance when present, and an advisory gate result. Possible rejection codes are:drive_asset_unresolvedoverrides_invalidoverrides_limit_exceededbatch_limit_exceededmedia_limit_exceeded
not_evaluated. Treat the result as a draft, not authorization to execute.
Launcher batch status and preview
These tools are available only when legacy Launcher is enabled. They accept onebatch_id: the 26-character ULID returned by launcher.draft_batch or the file-import adapter. Plainrouter resolves it only inside the workspace and ad account bound to the token. A caller cannot inspect another account by guessing an ID.
launcher.batch_status
Use this read-only tool to inspect a batch without evaluating its gate or contacting a provider. It returns:
- Batch status, mode, and item counts.
- Sub-batch status.
- The latest stored gate result.
- Ordered item status, bounded failure stage and code, and linked Actions proposal IDs.
- Partition status and latest proposal attempts for duplicate-ad-set modes.
ad-account.read scope.
launcher.preview_batch
Use this non-destructive checkpoint before presenting a batch as ready. Plainrouter re-evaluates the authoritative gate and returns status: "previewed" or status: "gated", the resulting batch status, and checks for source relationships, tracking verification, tracked-domain coverage, ledger health, and Actions readiness.
The previews array is intentionally empty in this release. No provider preview, Meta write, Actions proposal, or spend activation happens during the call. A successful preview is not execution authorization; any future execution path must evaluate the gate again.
This tool requires a Write or Admin token with actions.propose.
launcher.execute_batch
When legacy Launcher is enabled, the execution entry is discoverable but deliberately closed. After validating the token and token-bound batch, every call returns not_executable_in_phase_b1.
It does not evaluate the gate, advance the batch, create an Actions proposal or receipt, contact Meta, or mutate provider state.
Refusals
All three tools can returninvalid_token, insufficient_scope, invalid_arguments, batch_not_found, or internal_error. Preview can also return batch_not_operable or gate_receipt_raced. Execute returns not_executable_in_phase_b1 after successful authorization and batch resolution.