MCP Server # Approval model and safety controls What Synter checks before a write reaches an ad platform, which writes wait for a person, and who that person is on each surface. A write here means anything that can start, stop, or change ad spend. ## Every write passes the safety gate Every script run, from the Synter app, REST, an SDK, the CLI, or MCP, goes through the same server-side safety gate. Each decision (allowed, changed, held, or blocked) is written to the workspace audit log. The gate does three things: - **Blocks** writes the workspace policy forbids: tools on the deny list or off the allow list, calls outside allowed operating hours, changes over the configured monetary limits, and budgets above the daily-budget ceiling. Nobody can approve past a block. - **Creates paused.** New campaigns and ads are created paused while "Enforce paused on create" is on (the default). Turning them on is a separate write. - **Holds** higher-risk writes for approval, depending on the workspace autonomy level and the surface (table below). A held write returns `pending_review` with an `audit_id` and the exact reviewed arguments. Nothing runs until it is approved. Workspace owners and admins set the autonomy level in the Synter app under Settings → Autonomous: **Off** (live changes blocked), **Suggest** (the default), **Auto (safe)**, or **Auto (full)**. Under Off and Suggest, these writes are held: enabling or resuming something, deleting or removing something, creating campaigns, sending ad creative to a platform, and unrecognized write scripts. Routine updates, including pausing and changing a budget, bid, or keyword, run immediately and are audited. Auto (full) skips the hold but never a block. ## Who approves what, by surface | Surface | Pause, budget, bid changes | Held writes (default Suggest policy) | Who approves a held write | | --- | --- | --- | --- | | Synter app agent (campaign conversation) | Run immediately, audited | Shown in the conversation as the exact reviewed action | The person who asked, by replying I APPROVE in that conversation. An active owner or admin of the workspace can approve a teammate's held action with their own reply. | | REST, SDKs, CLI, local stdio MCP (API key) | Run immediately, audited | Returned as HTTP 202: status: "pending_review" on /api/v1/tools/run, error: "APPROVAL_REQUIRED" on api.synterai.com/v1 | Not the API key. Run the action again from a campaign conversation in the Synter app, check the reviewed action, and reply I APPROVE. | | Hosted MCP (OAuth or X-Synter-Key) | Run immediately, audited | Production: held, same as REST. Staging: accepted automatically (see rollout note) | Production: same as REST. Staging: the authenticated MCP user is treated as having approved the call; nobody else is asked. | | Background autonomous agents | Governed by the approval mode in Settings → Autonomous. The default, "Ask before acting", holds changes to your ad accounts for approval; read-only work and low-risk housekeeping run on their own. Draft, Auto, and Fully autonomous loosen this step by step; workspace limits and blocks still apply. | Rollout note (as of October 7, 2026) A change merged to staging on October 7, 2026 makes the hosted MCP server accept held writes automatically for the signed-in caller. This covers creates, enable/delete updates, creative sends, and unrecognized writes. These calls are logged with `approval_basis: "mcp_auto_acceptance"`. New campaigns are still created paused, and blocks still apply. The same change lets plan execution through an API key or MCP approve a draft or in-review plan automatically (next section). It is not in production yet; in production today, hosted MCP writes are held exactly like REST writes. REST, the SDKs, the CLI, and the Synter app are unchanged. ## Your MCP client's confirmation Synter marks every write tool with the MCP `destructiveHint` annotation. Spend-changing tools such as `execute_campaign_plan` and `update_campaign_budget` also tell the agent to confirm the account, amount, and campaign with you before calling. Whether you see a prompt depends on your client and its settings: Claude Code, Cursor, and others can ask before each tool call or be set to auto-approve. That prompt runs on your machine; Synter does not enforce it. Where hosted MCP accepts held writes automatically (staging, above), your client's prompt is the only per-call confirmation. Keep it on for write tools, or set the workspace autonomy level to Off for a read-only workspace. ## Campaign launches: plan → approve → execute 1. `create_campaign_plan` builds the launch plan. Pass a `plan_key` for idempotency; the response carries the `execute_token`. 2. `run_launch_preflight` checks conversion tracking and the landing page at plan time (read-only). `get_launch_gate_policy` reads whether a failing Plan QA review blocks launch in this workspace. 3. `publish_plan_document` moves the plan to review. A person approves it from the share link, or the agent calls `approve_campaign_plan` after you have seen the plan. That call requires the `expected_version` you saw, so a plan edited in between is not approved unseen. It is recorded under the account that owns the key or OAuth session. 4. `execute_campaign_plan` activates the entities in dependency order. If a step fails, entities it already activated are paused (best effort). `get_plan_execution` reports per-entity results. In production, execution refuses a plan that is not approved, and `qa_override_approved` defaults to false. On staging (rollout note above), executing through an API key or MCP approves a draft or in-review plan automatically, with a review row recorded as "MCP Operator", and `qa_override_approved` defaults to true. Launching from the Synter app still requires an approved plan. ## Pausing Pausing is a routine update. It runs without an approval step on every surface under the default policy and is audited. Through REST, `POST /v1/campaigns/{id}/pause` pauses child ad sets or ad groups too on Meta, Microsoft, Reddit, TikTok, and X. Turning a campaign back on is an enable, which is held under Off and Suggest. A campaign guardrail (below) can pause a Google Ads campaign for you. ## Ongoing controls - **Campaign guardrails** (Google Ads only): `set_campaign_guardrail` arms an automatic pause for one campaign once it passes a minimum age and spend threshold with zero conversions on a verified conversion action. Setting it up counts as standing approval for that pause. `list_campaign_guardrails` shows state; `disable_campaign_guardrail` turns the rule off without changing the campaign. - **Spend alerts**: `set_spend_alert` notifies by email, Slack, SMS, or WhatsApp when weekly spend passes a threshold. It alerts; it does not pause anything. ## After a change: verify - `get_ad_readback` reads a launched ad back from the platform API and checks the CTA and copy. Supported for Meta, Reddit, LinkedIn, and Google Ads; other platforms return a labeled unsupported result. - `get_account_changelog` returns the Google Ads change history (the platform API caps it at 30 days). Other platforms report `changelog_supported: false`. - `get_spend_reconciliation` compares Google Ads and The Trade Desk totals for up to 92 days (read-only). ## Pending writes over REST On `https://api.synterai.com/v1`, a held or blocked write returns HTTP 202. `safety_gate_action` tells you which: `pending` is waiting for approval; `block` was refused by policy. Credits are only deducted when a write succeeds. json ``` { "success": false, "error": "APPROVAL_REQUIRED", "safety_gate_action": "pending", "audit_id": "3f0c…", "reviewed_args": ["--campaign-id", "1234567890", "--action", "enable"] } ``` - `GET /v1/tools/pending` lists held writes for the key's workspace. - `POST /v1/tools/approve/{audit_id}` and `POST /v1/tools/reject/{audit_id}` (alias `DELETE /v1/tools/pending/{audit_id}`) need the caller to be a workspace owner or admin _and_ a review saved by the Synter app when that person replied `I APPROVE`. With an API key alone they return 409 `review_required_or_changed` (403 for non-admins). Approve in the Synter app instead. Related: [scopes](https://docs.synterai.com/mcp/scopes) (a key without a write scope cannot write at all), [Pause Campaign](https://docs.synterai.com/api/pause-campaign), [Update Budget](https://docs.synterai.com/api/update-budget), [errors](https://docs.synterai.com/mcp/errors). Was this page helpful? YesNo [Previous Tool Reference](https://docs.synterai.com/mcp/tools) [Next Scopes & Permissions](https://docs.synterai.com/mcp/scopes) --- Source: https://docs.synterai.com/mcp/approval-model Full docs as one file: https://docs.synterai.com/llms-full.txt