Skip to main content
Glama

mureo_state_upsert_campaign

Atomically upsert a campaign snapshot into STATE.json, keeping metadata in sync with vendor MCPs or BYOD imports and persisting metrics and ad-level status for dashboard KPIs and next-run diffing.

Instructions

Atomically upsert a CampaignSnapshot into STATE.json (root campaigns array). Use this to keep STATE.json in sync with campaign metadata changes the agent observes via vendor MCPs or BYOD imports. Pass the optional metrics object to persist the campaign's performance numbers (spend, clicks, conversions, cpa, ctr, …) so the reporting dashboard can render KPIs from STATE.json. Pass the optional ads array to persist ad-level delivery status, so a pause applied outside mureo is recorded and can be diffed on the next run.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
pathNoOptional path to the file. Defaults to STRATEGY.md / STATE.json in the MCP server's current working directory. Paths outside cwd are refused.
campaignYesA CampaignSnapshot for STATE.json plus its platform context. Required: campaign_id, campaign_name, status, platform, account_id. The platform + account_id populate the per-platform ``platforms`` section the dashboard reads (omit them and the client renders as inactive). Optional fields mirror the snapshot schema in docs/strategy-context.md, including ``metrics`` (spend / impressions / clicks / conversions / cpa / ctr / result_indicator / period / fetched_at) for dashboard KPIs.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed4 schema fields changedv0.13.1
    • changedInput schema / properties / campaign / properties / bidding_details / description
      Previous value: -"Free-form bidding detail (e.g. {'target_cpa': 5000}). One key is read by mureo: for Google Ads, 'bidding_strategy_system_status' — the value google_ads_campaigns_get / google_ads_campaigns_diagnose returns — is what the learning-period pre-flight (mureo_learning_reset_preflight, and the block_learning_resets* guardrails) uses to tell whether the campaign is already re-learning. Without it that state is reported 'unknown', never 'steady'."New value: +"Free-form bidding detail in the platform's own vocabulary (e.g. {'target_cpa': 5000}); omit it alongside bidding_strategy_type where the platform has neither. One key is read by mureo: for Google Ads, 'bidding_strategy_system_status' — the value google_ads_campaigns_get / google_ads_campaigns_diagnose returns — is what the learning-period pre-flight (mureo_learning_reset_preflight, and the block_learning_resets* guardrails) uses to tell whether the campaign is already re-learning. Without it that state is reported 'unknown', never 'steady'."
    • addedInput schema / properties / campaign / properties / bidding_strategy_type / description
      Added value: +"Bid strategy as the platform itself names it, verbatim. Omit it for a platform that does not select delivery by a bid — never borrow another platform's strategy name."
    • addedInput schema / properties / campaign / properties / monthly_budget
      Added value: +{
      +  "description": "The campaign's own MONTHLY budget, on a platform that has that concept alongside the daily one. Omit it entirely for a platform configured per day (Google Ads, Meta) — do not send a daily budget multiplied out, which is an implied cap and not what the campaign is set to spend. mureo never stores a total over these: it sums them on read, and only where every campaign of a declaring platform carries one.",
      +  "type": "number"
      +}
    • changedInput schema / properties / campaign / properties / platform / description
      Previous value: -"Platform key this campaign belongs to, e.g. ``google_ads`` / ``meta_ads`` / ``tiktok_ads``, or a plugin bridge ``plugin:<dist>``. Use the SAME key the account is already stored under — one ad account has exactly one platform key, and a second key for an account another key already holds is REJECTED (the reporting view sums the entries, so it would double-count)."New value: +"Platform key this campaign belongs to, e.g. ``google_ads`` / ``meta_ads`` / ``tiktok_ads``, a platform an installed plugin registered (its provider name), or a plugin bridge ``plugin:<dist>:<provider>``. Use the SAME key the account is already stored under — one ad account has exactly one platform key, and a second key for an account another key already holds is REJECTED (the reporting view sums the entries, so it would double-count). A NEW key that is none of the three is REJECTED too: do not invent or abbreviate a platform name."
  2. Changed1 schema field changedv0.10.44
    • addedInput schema / properties / campaign / properties / bidding_details / description
      Added value: +"Free-form bidding detail (e.g. {'target_cpa': 5000}). One key is read by mureo: for Google Ads, 'bidding_strategy_system_status' — the value google_ads_campaigns_get / google_ads_campaigns_diagnose returns — is what the learning-period pre-flight (mureo_learning_reset_preflight, and the block_learning_resets* guardrails) uses to tell whether the campaign is already re-learning. Without it that state is reported 'unknown', never 'steady'."
  3. Changed4 schema fields changedv0.10.43
    • changedInput schema / properties / campaign / properties / account_id / description
      Previous value: -"Platform account id (Google ``customer_id`` / Meta ``act_*``) written onto the platform entry."New value: +"Platform account id (Google ``customer_id`` / Meta ``act_*``) written onto the platform entry, and used to detect a second entry for the same account."
    • addedInput schema / properties / campaign / properties / account_id / minLength
      Added value: +1
    • changedInput schema / properties / campaign / properties / platform / description
      Previous value: -"Platform key this campaign belongs to, e.g. ``google_ads`` / ``meta_ads``."New value: +"Platform key this campaign belongs to, e.g. ``google_ads`` / ``meta_ads`` / ``tiktok_ads``, or a plugin bridge ``plugin:<dist>``. Use the SAME key the account is already stored under — one ad account has exactly one platform key, and a second key for an account another key already holds is REJECTED (the reporting view sums the entries, so it would double-count)."
    • addedInput schema / properties / campaign / properties / platform / minLength
      Added value: +1
  4. Changed2 schema fields changedv0.10.37
    • addedInput schema / additionalProperties
      Added value: +false
    • addedInput schema / properties / campaign / properties / ads
      Added value: +{
      +  "description": "Ad-level (creative-level) delivery state for this campaign. Send it so a change made OUTSIDE mureo — an ad paused by hand in the platform UI, stopped by its ad set/campaign, or rejected by policy — is recorded as fact and can be diffed on the next run. ``status`` is what the ad is configured as; ``effective_status`` is whether it is actually delivering, and the two disagreeing is the signal. Omit the whole field when you did not fetch ad-level status (that is different from sending an empty list, which means 'fetched, this campaign has no ads').",
      +  "items": {
      +    "properties": {
      +      "ad_id": {
      +        "description": "Platform ad id.",
      +        "type": "string"
      +      },
      +      "as_of": {
      +        "description": "IGNORED — the server stamps each ad with its own clock (ISO 8601 with UTC offset), so a drifted client date can never be persisted and later read back as when the status was observed.",
      +        "type": "string"
      +      },
      +      "effective_status": {
      +        "description": "Actual delivery status where the platform exposes one (Meta: ACTIVE / ADSET_PAUSED / CAMPAIGN_PAUSED / DISAPPROVED / …). Omit when the platform does not report it rather than copying ``status`` into it.",
      +        "type": "string"
      +      },
      +      "name": {
      +        "description": "Ad name.",
      +        "type": "string"
      +      },
      +      "status": {
      +        "description": "Configured status (e.g. ACTIVE / PAUSED).",
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "ad_id"
      +    ],
      +    "type": "object"
      +  },
      +  "type": "array"
      +}
  5. Changed5 schema fields changedv0.10.7
    • changedInput schema / properties / campaign / description
      Previous value: -"A CampaignSnapshot for STATE.json. Required: campaign_id, campaign_name, status. Optional fields mirror the snapshot schema in docs/strategy-context.md."New value: +"A CampaignSnapshot for STATE.json plus its platform context. Required: campaign_id, campaign_name, status, platform, account_id. The platform + account_id populate the per-platform ``platforms`` section the dashboard reads (omit them and the client renders as inactive). Optional fields mirror the snapshot schema in docs/strategy-context.md, including ``metrics`` (spend / impressions / clicks / conversions / cpa / ctr / result_indicator / period / fetched_at) for dashboard KPIs."
    • addedInput schema / properties / campaign / properties / account_id
      Added value: +{
      +  "description": "Platform account id (Google ``customer_id`` / Meta ``act_*``) written onto the platform entry.",
      +  "type": "string"
      +}
    • addedInput schema / properties / campaign / properties / metrics
      Added value: +{
      +  "description": "Optional performance metrics for the reporting dashboard: spend, impressions, clicks, conversions, cpa, ctr, result_indicator (Meta: clicks vs leads), period (e.g. ``LAST_30_DAYS``), fetched_at (ISO 8601).",
      +  "type": "object"
      +}
    • addedInput schema / properties / campaign / properties / platform
      Added value: +{
      +  "description": "Platform key this campaign belongs to, e.g. ``google_ads`` / ``meta_ads``.",
      +  "type": "string"
      +}
    • changedInput schema / properties / campaign / required
      Previous value: -[
      -  "campaign_id",
      -  "campaign_name",
      -  "status"
      -]New value: +[
      +  "campaign_id",
      +  "campaign_name",
      +  "status",
      +  "platform",
      +  "account_id"
      +]
  6. Addedv0.9.12
  7. Removedv0.9.6
  8. Addedv0.9.2
  9. Removedv0.9.1
  10. Addedv1.0.6

TDQS

A4.5/5.0
Behavior4/5

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

No annotations are provided, so the description carries the full burden. It discloses key behaviors: atomicity ('Atomically upsert'), the rejection of invalid platform keys ('a second key ... is REJECTED', 'A NEW key that is none of the three is REJECTED too'), the stamping of ad timestamps by the server (with the as_of field being IGNORED), and the refusal of paths outside cwd. This goes well beyond a simple action description, though it could mention what happens on conflict (does upsert replace entirely or merge?) and whether the operation returns success/error details.

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

Conciseness4/5

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

The description is three sentences, front-loaded with the core action ('Atomically upsert a CampaignSnapshot...') followed by the 'why' and the optional-field semantics. It's dense but not overly long; no wasted words. Slightly under the top score because it packs a lot into long sentences, which could be more scannable, but it's efficient overall.

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

Completeness4/5

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

Given the tool's complexity (nested objects, optional metrics and ads, platform validation logic), the description plus the extensive schema cover the key details. The output schema is absent, but the tool likely returns a status that is self-explanatory; still, the description doesn't mention what the response contains, and edge cases like behavior when the campaign already exists (upsert semantics) are implied by the name but not explicitly stated. It's near-complete but leaves a couple of transactional details to inference.

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

Parameters4/5

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

Schema description coverage is 100%, so the schema already documents each parameter thoroughly (e.g., `platform` has a detailed description of allowed values and rejection rules; `ads` explains the distinction between configured vs. effective status). The description adds value by explaining the overall purpose of the optional parameters and the significance of `effective_status` and the pre-flight logic for `bidding_strategy_system_status`. However, since the schema is already very rich, the description's incremental contribution is moderate, though it does synthesize the meaning (e.g., 'the two disagreeing is the signal').

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

Purpose5/5

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

The description clearly states the tool's purpose: 'Atomically upsert a CampaignSnapshot into STATE.json (root campaigns array)'. It specifies the verb (upsert), the resource (CampaignSnapshot into STATE.json), and the intent (keep STATE.json in sync with campaign metadata changes). This distinguishes it from sibling tools like mureo_state_get or platform-specific campaign tools, as it acts on the mureo state file rather than a vendor API.

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

Usage Guidelines5/5

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

The description provides explicit usage guidance: 'Use this to keep STATE.json in sync with campaign metadata changes the agent observes via vendor MCPs or BYOD imports.' It also explains when optional fields should be passed (`metrics` for dashboard KPIs, `ads` for ad-level tracking) and contrasts with omitting vs. sending an empty list. It doesn't name alternatives explicitly but clearly scopes the use case, and the sibling list suggests this is the only state upsert tool for campaigns, so the route is unambiguous.

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

Install Server

Other Tools