← All MCP tools

MCP tool

create_manual_plan

Build a media plan from inventory items YOU picked (via browse_inventory) instead of the AI planner. Trade-off: generate_plan optimizes the budget split across channels with reasoning and forecasts; create_manual_plan gives you exact control over which billboards/shows/channels/venues run, at the cost of that optimization. Budget is split across your selections and the platform fee is disclosed per line, exactly like an AI plan. The result is a normal draft plan: approve_plan and launch_campaign work the same afterwards. Optionally attach a persona for targeting/fidelity context.

Input

Pass fields from this schema as the tool arguments. Runtime ownership, product scope and readiness checks still apply.

Input JSON Schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "budgetPounds": {
      "type": "number",
      "minimum": 0.01,
      "maximum": 19000000,
      "description": "total budget in GBP pounds, e.g. 15000"
    },
    "goal": {
      "type": "string",
      "enum": [
        "awareness",
        "consideration",
        "performance"
      ],
      "description": "campaign goal"
    },
    "startDate": {
      "type": "string",
      "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      "description": "flight start, YYYY-MM-DD"
    },
    "endDate": {
      "type": "string",
      "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      "description": "flight end, YYYY-MM-DD (must be after startDate)"
    },
    "selections": {
      "minItems": 1,
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "channel": {
            "type": "string",
            "enum": [
              "ctv",
              "audio",
              "tv",
              "cinema",
              "dooh",
              "search",
              "social"
            ],
            "description": "channel these items belong to"
          },
          "adapterKey": {
            "type": "string",
            "description": "adapter that owns the items, e.g. \"vistar\""
          },
          "itemIds": {
            "minItems": 1,
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "inventory item ids from browse_inventory"
          }
        },
        "required": [
          "channel",
          "adapterKey",
          "itemIds"
        ]
      },
      "description": "hand-picked inventory grouped by channel + adapter"
    },
    "personaId": {
      "description": "optional persona for targeting/fidelity context",
      "type": "string"
    },
    "commercialBrief": {
      "description": "optional commercial and measurement context; monetary fields are integer pence",
      "type": "object",
      "properties": {
        "productOrOffer": {
          "type": "string",
          "minLength": 1,
          "maxLength": 200
        },
        "landingPageUrl": {
          "type": "string",
          "maxLength": 2048,
          "format": "uri"
        },
        "primaryKpi": {
          "type": "string",
          "enum": [
            "reach",
            "brand-awareness",
            "consideration",
            "site-visits",
            "leads",
            "sales",
            "app-installs",
            "custom"
          ]
        },
        "conversionDefinition": {
          "type": "string",
          "minLength": 1,
          "maxLength": 300
        },
        "outcomeSource": {
          "type": "string",
          "enum": [
            "campaign-tracking",
            "analytics",
            "crm",
            "commerce",
            "offline",
            "none"
          ]
        },
        "targetValueMinor": {
          "type": "integer",
          "minimum": 0,
          "maximum": 2000000000
        },
        "baselineWeeklyConversions": {
          "type": "integer",
          "minimum": 0,
          "maximum": 10000000
        },
        "priorMonthlyMediaSpendMinor": {
          "type": "integer",
          "minimum": 0,
          "maximum": 2000000000
        },
        "existingMediaMix": {
          "maxItems": 11,
          "type": "array",
          "items": {
            "type": "string",
            "enum": [
              "ctv",
              "audio",
              "tv",
              "cinema",
              "dooh",
              "search",
              "social",
              "display",
              "email",
              "print",
              "other"
            ]
          }
        },
        "firstPartyDataAvailability": {
          "type": "string",
          "enum": [
            "none",
            "limited",
            "ready"
          ]
        },
        "creativeReadiness": {
          "type": "string",
          "enum": [
            "needs-production",
            "in-progress",
            "ready"
          ]
        },
        "measurementIntent": {
          "minItems": 1,
          "maxItems": 4,
          "type": "array",
          "items": {
            "type": "string",
            "enum": [
              "delivered",
              "responded",
              "caused",
              "remembered"
            ]
          }
        },
        "exclusions": {
          "maxItems": 20,
          "type": "array",
          "items": {
            "type": "string",
            "minLength": 1,
            "maxLength": 300
          }
        },
        "mandatories": {
          "maxItems": 20,
          "type": "array",
          "items": {
            "type": "string",
            "minLength": 1,
            "maxLength": 300
          }
        }
      },
      "required": [
        "productOrOffer",
        "primaryKpi",
        "outcomeSource",
        "existingMediaMix",
        "firstPartyDataAvailability",
        "creativeReadiness",
        "measurementIntent",
        "exclusions",
        "mandatories"
      ],
      "additionalProperties": false
    }
  },
  "required": [
    "budgetPounds",
    "goal",
    "startDate",
    "endDate",
    "selections"
  ]
}

REST mapping and authority

The tool wraps this REST endpoint. The mapping identifies path/query/body transformations and approval or idempotency headers.

Request contract
{
  "method": "POST",
  "path": "/api/v1/plans/manual",
  "pathFields": [],
  "pathSchema": {
    "type": "object",
    "properties": {},
    "additionalProperties": false
  },
  "pathEncoding": "encodeURIComponent for each path field",
  "governedAction": null,
  "headers": {},
  "bodySchema": {
    "type": "object",
    "properties": {
      "goal": {
        "type": "string",
        "enum": [
          "awareness",
          "consideration",
          "performance"
        ],
        "description": "campaign goal"
      },
      "startDate": {
        "type": "string",
        "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
        "description": "flight start, YYYY-MM-DD"
      },
      "endDate": {
        "type": "string",
        "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
        "description": "flight end, YYYY-MM-DD (must be after startDate)"
      },
      "selections": {
        "minItems": 1,
        "type": "array",
        "items": {
          "type": "object",
          "properties": {
            "channel": {
              "type": "string",
              "enum": [
                "ctv",
                "audio",
                "tv",
                "cinema",
                "dooh",
                "search",
                "social"
              ],
              "description": "channel these items belong to"
            },
            "adapterKey": {
              "type": "string",
              "description": "adapter that owns the items, e.g. \"vistar\""
            },
            "itemIds": {
              "minItems": 1,
              "type": "array",
              "items": {
                "type": "string"
              },
              "description": "inventory item ids from browse_inventory"
            }
          },
          "required": [
            "channel",
            "adapterKey",
            "itemIds"
          ]
        },
        "description": "hand-picked inventory grouped by channel + adapter"
      },
      "personaId": {
        "description": "optional persona for targeting/fidelity context",
        "type": "string"
      },
      "commercialBrief": {
        "description": "optional commercial and measurement context; monetary fields are integer pence",
        "type": "object",
        "properties": {
          "productOrOffer": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "landingPageUrl": {
            "type": "string",
            "maxLength": 2048,
            "format": "uri"
          },
          "primaryKpi": {
            "type": "string",
            "enum": [
              "reach",
              "brand-awareness",
              "consideration",
              "site-visits",
              "leads",
              "sales",
              "app-installs",
              "custom"
            ]
          },
          "conversionDefinition": {
            "type": "string",
            "minLength": 1,
            "maxLength": 300
          },
          "outcomeSource": {
            "type": "string",
            "enum": [
              "campaign-tracking",
              "analytics",
              "crm",
              "commerce",
              "offline",
              "none"
            ]
          },
          "targetValueMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 2000000000
          },
          "baselineWeeklyConversions": {
            "type": "integer",
            "minimum": 0,
            "maximum": 10000000
          },
          "priorMonthlyMediaSpendMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 2000000000
          },
          "existingMediaMix": {
            "maxItems": 11,
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "ctv",
                "audio",
                "tv",
                "cinema",
                "dooh",
                "search",
                "social",
                "display",
                "email",
                "print",
                "other"
              ]
            }
          },
          "firstPartyDataAvailability": {
            "type": "string",
            "enum": [
              "none",
              "limited",
              "ready"
            ]
          },
          "creativeReadiness": {
            "type": "string",
            "enum": [
              "needs-production",
              "in-progress",
              "ready"
            ]
          },
          "measurementIntent": {
            "minItems": 1,
            "maxItems": 4,
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "delivered",
                "responded",
                "caused",
                "remembered"
              ]
            }
          },
          "exclusions": {
            "maxItems": 20,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 300
            }
          },
          "mandatories": {
            "maxItems": 20,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 300
            }
          }
        },
        "required": [
          "productOrOffer",
          "primaryKpi",
          "outcomeSource",
          "existingMediaMix",
          "firstPartyDataAvailability",
          "creativeReadiness",
          "measurementIntent",
          "exclusions",
          "mandatories"
        ],
        "additionalProperties": false
      },
      "budgetMinor": {
        "type": "integer",
        "minimum": 1,
        "maximum": 1900000000
      },
      "currency": {
        "const": "GBP",
        "type": "string"
      }
    },
    "additionalProperties": false,
    "required": [
      "goal",
      "startDate",
      "endDate",
      "selections",
      "budgetMinor",
      "currency"
    ]
  },
  "bodyMapping": {
    "passthroughOtherFields": true,
    "budgetMinor": {
      "from": "budgetPounds",
      "transform": "Math.round(value * 100)"
    },
    "constants": {
      "currency": "GBP"
    }
  },
  "responseMapping": "REST JSON is returned as MCP structuredContent and a compatibility text block; privacy-sensitive tools validate their output schema."
}

Output

This is the registered MCP output envelope. Nested fields are only modeled where the schema explicitly defines them.

Output JSON Schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "plan": {
      "type": "object",
      "propertyNames": {
        "type": "string"
      },
      "additionalProperties": {}
    }
  },
  "required": [
    "plan"
  ],
  "additionalProperties": {}
}

Safety annotations

MCP annotations
{
  "readOnlyHint": false,
  "destructiveHint": false,
  "idempotentHint": false,
  "openWorldHint": true
}

Annotations help a client present the tool. The API independently enforces authorization and exact action approvals. Error and retry guidance →

create_manual_plan | AdBuyMCP docs