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.
{
"$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.
{
"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.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"plan": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {}
}
},
"required": [
"plan"
],
"additionalProperties": {}
}Safety 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 →