zuckerbot-mcp 0.4.0 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -11
- package/dist/cli.js +8 -5
- package/dist/cli.js.map +1 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +9 -2
- package/dist/client.js.map +1 -1
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +102 -83
- package/dist/tools.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +5 -4
package/dist/tools.js
CHANGED
|
@@ -130,14 +130,14 @@ function buildQuickstartPayload(client) {
|
|
|
130
130
|
{
|
|
131
131
|
step: 4,
|
|
132
132
|
tool: "zuckerbot_create_campaign",
|
|
133
|
-
description: "
|
|
133
|
+
description: "Create a reviewed launch-ready campaign draft",
|
|
134
134
|
requires_key: true,
|
|
135
135
|
flow: "quick_launch",
|
|
136
136
|
},
|
|
137
137
|
{
|
|
138
138
|
step: 5,
|
|
139
139
|
tool: "zuckerbot_launch_campaign",
|
|
140
|
-
description: "
|
|
140
|
+
description: "Launch the reviewed legacy draft on Meta",
|
|
141
141
|
requires_key: true,
|
|
142
142
|
flow: "quick_launch",
|
|
143
143
|
},
|
|
@@ -269,12 +269,12 @@ const businessContextTypeSchema = z
|
|
|
269
269
|
// always available.
|
|
270
270
|
function registerCreativeGenerationTools(server, client) {
|
|
271
271
|
// ── Generate Static Ad ──────────────────────────────────────────
|
|
272
|
-
server.tool("zuckerbot_generate_static_ad", "Generate a brand-aware 1080×1080 static ad image
|
|
272
|
+
server.tool("zuckerbot_generate_static_ad", "Generate a brand-aware 1080×1080 static ad image. Automatically injects brand context (logo, colors, brand name, value props, social proof) from the business profile when business_id is provided — no need to pass brand data manually. Templates: stat_hook (statistic + supporting copy), pain_headline (bold headline + benefit bullets), testimonial (customer quote + portrait), feature_showcase (product + benefits). Returns a public image URL and QA scores. Present the image to the customer for approval; to generate more variants, call again with different parameters.", {
|
|
273
273
|
business_id: z.string().optional().describe("Business ID for automatic brand context injection (logo, colors, CTA, testimonials)"),
|
|
274
274
|
session_id: z.string().optional().describe("Architect session ID — when provided, the generated asset is linked to this campaign session"),
|
|
275
275
|
template: z
|
|
276
276
|
.enum(["stat_hook", "pain_headline", "testimonial", "feature_showcase"])
|
|
277
|
-
.describe("
|
|
277
|
+
.describe("Ad template"),
|
|
278
278
|
headline: z.string().optional().describe("Primary headline (required for stat_hook, pain_headline, feature_showcase)"),
|
|
279
279
|
subtext: z.string().optional().describe("Subtext below headline (stat_hook only)"),
|
|
280
280
|
body: z.string().optional().describe("Body copy (stat_hook only)"),
|
|
@@ -301,8 +301,8 @@ function registerCreativeGenerationTools(server, client) {
|
|
|
301
301
|
}
|
|
302
302
|
});
|
|
303
303
|
// ── Generate Video Ad ───────────────────────────────────────────
|
|
304
|
-
server.tool("zuckerbot_generate_video_ad", "Generate a video ad
|
|
305
|
-
business_id: z.string().describe("Business ID (required for
|
|
304
|
+
server.tool("zuckerbot_generate_video_ad", "Generate a video ad through ZuckerBot's video generation pipeline (AI scripting → AI video → captioned overlay → hosted upload). ASYNC operation: returns a job_id immediately. Poll with zuckerbot_get_video_ad_status every 30 seconds for completion. Brand context is loaded server-side. Typical generation time: 5-15 minutes. Note: AI-generated video ads may face Meta ad review scrutiny — rejection tracking is built in.", {
|
|
305
|
+
business_id: z.string().describe("Business ID (required for creative routing)"),
|
|
306
306
|
focus: z.string().describe("Product/feature focus for the ad (e.g., 'missed_calls', 'quoting', 'scheduling')"),
|
|
307
307
|
market: z.string().default("AU").describe("Target market code (AU, US, UK, NZ)"),
|
|
308
308
|
ad_account_id: z.string().optional().describe("Meta ad account ID (auto-resolved if omitted)"),
|
|
@@ -357,8 +357,8 @@ function registerCreativeGenerationTools(server, client) {
|
|
|
357
357
|
return formatError(err);
|
|
358
358
|
}
|
|
359
359
|
});
|
|
360
|
-
// ── Request Creative (
|
|
361
|
-
server.tool("zuckerbot_request_creative", "Dispatch a creative production request for an approved intelligence campaign. If
|
|
360
|
+
// ── Request Creative (creative-pipeline dispatch) ───────────────
|
|
361
|
+
server.tool("zuckerbot_request_creative", "Dispatch a creative production request for an approved intelligence campaign. If a creative-production webhook is configured on the business, ZuckerBot generates full video scripts and fires the production payload. Use this when you want ZuckerBot to handle creative production end-to-end rather than uploading your own assets.", {
|
|
362
362
|
campaign_id: z.string().describe("Intelligence campaign ID"),
|
|
363
363
|
creative_handoff: creativeHandoffSchema.describe("Optional creative handoff configuration"),
|
|
364
364
|
}, async ({ campaign_id, creative_handoff }) => {
|
|
@@ -367,14 +367,14 @@ function registerCreativeGenerationTools(server, client) {
|
|
|
367
367
|
if (creative_handoff)
|
|
368
368
|
body.creative_handoff = creative_handoff;
|
|
369
369
|
const result = await client.post(`/campaigns/${campaign_id}/request-creative`, body);
|
|
370
|
-
return formatResult(appendHint(result, "Creative request dispatched. Monitor progress with zuckerbot_get_creative_status.
|
|
370
|
+
return formatResult(appendHint(result, "Creative request dispatched for planning/review. Monitor progress with zuckerbot_get_creative_status. Multi-tier activation is temporarily disabled; use a legacy campaign draft for a live launch."));
|
|
371
371
|
}
|
|
372
372
|
catch (err) {
|
|
373
373
|
return formatError(err);
|
|
374
374
|
}
|
|
375
375
|
});
|
|
376
376
|
// ── Generate Creatives ──────────────────────────────────────────
|
|
377
|
-
server.tool("zuckerbot_generate_creatives", "Generate standalone ad creative variants (images or video) using AI image
|
|
377
|
+
server.tool("zuckerbot_generate_creatives", "Generate standalone ad creative variants (images or video) using AI image and video models. Works independently of campaign creation — useful for quick mockups, creative testing, or building assets before attaching them to a campaign. If the description mentions video, reels, UGC, or TikTok, the tool auto-routes to the video model.", {
|
|
378
378
|
business_id: z.string().optional()
|
|
379
379
|
.describe("Optional business ID. When provided, brand context (name, tagline, value props, audience) is automatically injected into the generation request for more on-brand results."),
|
|
380
380
|
business_name: z.string().describe("Business name"),
|
|
@@ -389,7 +389,7 @@ function registerCreativeGenerationTools(server, client) {
|
|
|
389
389
|
model: z
|
|
390
390
|
.enum(["auto", "seedream", "imagen", "kling"])
|
|
391
391
|
.optional()
|
|
392
|
-
.describe("Model selection. auto/seedream/imagen are image paths, kling is video path. Optional; inferred when omitted."),
|
|
392
|
+
.describe("Model selection. auto/seedream/imagen are image paths, kling is the video path. Optional; inferred from the description when omitted."),
|
|
393
393
|
media_type: z
|
|
394
394
|
.enum(["image", "video"])
|
|
395
395
|
.optional()
|
|
@@ -433,26 +433,53 @@ export function registerTools(server, client) {
|
|
|
433
433
|
registerQuickstartTool(server, client);
|
|
434
434
|
registerBillingStatusTool(server, client);
|
|
435
435
|
// ── 0a. Account Audit ───────────────────────────────────────────
|
|
436
|
-
server.tool("zuckerbot_audit_account", "Run a full audit of the connected Meta ad account: wasted spend detection, creative fatigue, opportunity score (0-100
|
|
436
|
+
server.tool("zuckerbot_audit_account", "Run a full audit of the connected Meta ad account: wasted spend detection, creative fatigue, a complete-account opportunity score (0-100 when all inputs return), and prioritised action items. Saves a shareable web report when the API key resolves to one saved business. Read-only and available on every tier — the recommended FIRST call for any new account or when a user asks 'how are my ads doing?'.", {
|
|
437
437
|
meta_ad_account_id: z.string().optional().describe("Meta ad account ID to audit (format: act_XXXXX). Defaults to the connected account."),
|
|
438
438
|
company_name: z.string().optional().describe("Company name used in the audit narrative. Defaults to the connected business name."),
|
|
439
439
|
}, async ({ meta_ad_account_id, company_name }) => {
|
|
440
440
|
try {
|
|
441
441
|
client.requireAuth();
|
|
442
|
-
|
|
442
|
+
// Ask the API to persist when one business is resolvable, but keep the
|
|
443
|
+
// audit itself available when setup/selection is still incomplete.
|
|
444
|
+
// This stays one metered request and one Meta audit in both cases.
|
|
445
|
+
const body = {
|
|
446
|
+
save_report: true,
|
|
447
|
+
save_report_if_available: true,
|
|
448
|
+
};
|
|
443
449
|
if (meta_ad_account_id)
|
|
444
450
|
body.meta_ad_account_id = meta_ad_account_id;
|
|
445
451
|
if (company_name)
|
|
446
452
|
body.company_name = company_name;
|
|
447
453
|
const result = await client.post("/audit", body);
|
|
448
|
-
|
|
454
|
+
const record = asRecord(result);
|
|
455
|
+
const audit = asRecord(record?.audit);
|
|
456
|
+
const raw = asRecord(audit?.rawInsights);
|
|
457
|
+
const dataCompleteness = asRecord(raw?.data_completeness);
|
|
458
|
+
// Raw Meta insight rows drown the agent's context; the summarised
|
|
459
|
+
// findings above them carry everything the report presents.
|
|
460
|
+
if (raw && "campaign_rows" in raw)
|
|
461
|
+
delete raw.campaign_rows;
|
|
462
|
+
const reportUrl = typeof record?.report_url === "string" ? `https://zuckerbot.ai${record.report_url}` : null;
|
|
463
|
+
const partialDataHint = raw?.data_truncated === true
|
|
464
|
+
? " NOTE: Meta returned incomplete data. Check audit.rawInsights.data_completeness and do not present opportunityScore or exact spend/fatigue ratios as complete-account measures."
|
|
465
|
+
: "";
|
|
466
|
+
const scoreHint = typeof audit?.opportunityScore !== "number"
|
|
467
|
+
? " NOTE: No opportunity score is available for this result. Do not present or infer a numeric account rating."
|
|
468
|
+
: "";
|
|
469
|
+
const currencyHint = dataCompleteness?.account_currency_available === false
|
|
470
|
+
? " NOTE: Meta did not return the account currency. Describe money as account-currency units; do not label it AUD or invent another currency code."
|
|
471
|
+
: "";
|
|
472
|
+
const reportHint = reportUrl
|
|
473
|
+
? ` A shareable web report was saved — give the user this link: ${reportUrl}`
|
|
474
|
+
: " No shareable report was saved because this API key does not resolve to one saved business.";
|
|
475
|
+
return formatResult(appendHint(result, `Audit complete.${reportHint}${partialDataHint}${scoreHint}${currencyHint} Present complete observed findings and audit.rawInsights.action_items to the user, then act on them: zuckerbot_get_performance to drill into a specific campaign, zuckerbot_pause_campaign to stop wasted spend, or zuckerbot_creative_analysis to diagnose fatigued creatives.`));
|
|
449
476
|
}
|
|
450
477
|
catch (err) {
|
|
451
478
|
return formatError(err);
|
|
452
479
|
}
|
|
453
480
|
});
|
|
454
481
|
// ── 0b. Redeem Lifetime Licence ─────────────────────────────────
|
|
455
|
-
server.tool("zuckerbot_redeem_license", "Redeem a ZuckerBot lifetime licence code (format ZB-XXXXX-XXXXX-XXXXX) purchased on Dealify or AppSumo.
|
|
482
|
+
server.tool("zuckerbot_redeem_license", "Redeem a ZuckerBot lifetime licence code (format ZB-XXXXX-XXXXX-XXXXX) purchased on Dealify or AppSumo. Each code activates the plan it was purchased for: Tier 1 (1 ad account, 2,500 calls/mo), Tier 2 (3 accounts, 10K calls/mo) or Tier 3 (10 accounts, 30K calls/mo). Codes also stack additively on one account up to Tier 3 — e.g. two Tier 1 codes = Tier 2. Redeeming upgrades ALL of the account's API keys to the new tier immediately.", {
|
|
456
483
|
code: z.string().describe("Lifetime licence code in the format ZB-XXXXX-XXXXX-XXXXX"),
|
|
457
484
|
}, async ({ code }) => {
|
|
458
485
|
try {
|
|
@@ -462,7 +489,7 @@ export function registerTools(server, client) {
|
|
|
462
489
|
const mintedKey = asRecord(record?.api_key);
|
|
463
490
|
const hint = mintedKey
|
|
464
491
|
? "IMPORTANT: a new API key was minted during redemption. Show the full api_key.key value to the user IMMEDIATELY and tell them to store it securely — it will NEVER be shown again. Then follow the next_steps in the response."
|
|
465
|
-
: "Licence redeemed — all of this account's API keys are upgraded to the new tier.
|
|
492
|
+
: "Licence redeemed — all of this account's API keys are upgraded to the new tier. If the tier is below Lifetime Tier 3, stacking another code raises it. Run zuckerbot_audit_account to put the new limits to work.";
|
|
466
493
|
return formatResult(appendHint(result, hint));
|
|
467
494
|
}
|
|
468
495
|
catch (err) {
|
|
@@ -583,7 +610,7 @@ export function registerTools(server, client) {
|
|
|
583
610
|
}
|
|
584
611
|
});
|
|
585
612
|
// ── 3. Generate Campaign Brief ─────────────────────────────────
|
|
586
|
-
server.tool("zuckerbot_generate_campaign_brief", "Generate a detailed creative brief from an approved campaign structure. SAFE — pure function, no Meta API calls, no money spent. Automatically pulls brand context and historical creative patterns (or uses brand context alone for cold-start accounts). Returns per-slot creative directions: for static ads, specific
|
|
613
|
+
server.tool("zuckerbot_generate_campaign_brief", "Generate a detailed creative brief from an approved campaign structure. SAFE — pure function, no Meta API calls, no money spent. Automatically pulls brand context and historical creative patterns (or uses brand context alone for cold-start accounts). Returns per-slot creative directions: for static ads, specific ad template + headline/body/CTA + hero image prompt; for video ads, hook concept + voiceover direction + visual style. After brief is generated, present it to the customer, then call zuckerbot_generate_static_ad / zuckerbot_generate_video_ad for each slot.", {
|
|
587
614
|
business_id: z.string().optional().describe("Business ID (auto-resolved from API key if omitted)"),
|
|
588
615
|
session_id: z.string().optional().describe("Architect session ID from zuckerbot_recommend_campaign_structure"),
|
|
589
616
|
approved_structure: z.string().optional().describe("JSON string of approved campaign structure (if no session_id)"),
|
|
@@ -608,15 +635,15 @@ export function registerTools(server, client) {
|
|
|
608
635
|
}
|
|
609
636
|
});
|
|
610
637
|
// ── 7. Create Full Campaign ─────────────────────────────────────
|
|
611
|
-
server.tool("zuckerbot_create_full_campaign", "Build a complete Meta campaign from an approved Campaign Architect session. IMPORTANT: dry_run defaults to TRUE. When dry_run=true, returns the exact campaign structure that WOULD be created without calling Meta — safe, free, no side effects. Present this to the customer first. Only set dry_run=false after explicit customer approval. When dry_run=false, creates
|
|
638
|
+
server.tool("zuckerbot_create_full_campaign", "Build a complete PAUSED Meta campaign from an approved Campaign Architect session. IMPORTANT: dry_run defaults to TRUE. When dry_run=true, returns the exact campaign structure that WOULD be created without calling Meta — safe, free, no side effects. Present this to the customer first. Only set dry_run=false after explicit customer approval. When dry_run=false, creates Meta objects in PAUSED state for review; Architect auto-activation is temporarily disabled. Generated videos get linked for rejection tracking automatically.", {
|
|
612
639
|
session_id: z.string().describe("Campaign Architect session ID with approved strategy and creatives"),
|
|
613
640
|
dry_run: z.boolean().default(true)
|
|
614
641
|
.describe("DEFAULT TRUE. Set to false ONLY after customer has approved the dry-run preview. Live mode creates real Meta objects."),
|
|
615
642
|
meta_access_token: z.string().optional().describe("Meta access token override (live mode only)"),
|
|
616
643
|
meta_ad_account_id: z.string().optional().describe("Meta ad account ID override (live mode only)"),
|
|
617
644
|
meta_page_id: z.string().optional().describe("Facebook Page ID override (live mode only)"),
|
|
618
|
-
activate: z.
|
|
619
|
-
.describe("
|
|
645
|
+
activate: z.literal(false).default(false)
|
|
646
|
+
.describe("Must remain false. Architect auto-activation is temporarily disabled; live mode creates PAUSED Meta objects only."),
|
|
620
647
|
}, async ({ session_id, dry_run, meta_access_token, meta_ad_account_id, meta_page_id, activate }) => {
|
|
621
648
|
try {
|
|
622
649
|
client.requireAuth();
|
|
@@ -632,9 +659,7 @@ export function registerTools(server, client) {
|
|
|
632
659
|
const isDryRun = record.dry_run === true;
|
|
633
660
|
const hint = isDryRun
|
|
634
661
|
? "DRY RUN — no Meta objects were created. Present the would_create structure to the customer. If they approve, call again with dry_run=false to create live Meta objects."
|
|
635
|
-
:
|
|
636
|
-
? "Campaign built and activated on Meta. Monitor performance with zuckerbot_get_performance. Videos from ad_factory_jobs are linked for rejection tracking."
|
|
637
|
-
: "Campaign built in PAUSED state on Meta. Present the meta_structure to the customer, then resume the campaign on Meta only after approval. Videos linked for rejection tracking.";
|
|
662
|
+
: "Campaign built in PAUSED state on Meta for review. Architect auto-activation and campaign resume are temporarily disabled; use a reviewed legacy draft with zuckerbot_launch_campaign for the supported live path. Videos linked for rejection tracking.";
|
|
638
663
|
return formatResult(appendHint(result, hint));
|
|
639
664
|
}
|
|
640
665
|
catch (err) {
|
|
@@ -657,14 +682,14 @@ export function registerTools(server, client) {
|
|
|
657
682
|
url,
|
|
658
683
|
ad_count,
|
|
659
684
|
});
|
|
660
|
-
return formatResult(appendHint(result, "Preview generated. Call zuckerbot_create_campaign with the same URL to
|
|
685
|
+
return formatResult(appendHint(result, "Preview generated. Call zuckerbot_create_campaign with the same URL; it defaults to the reviewed legacy draft path that can be launched safely."));
|
|
661
686
|
}
|
|
662
687
|
catch (err) {
|
|
663
688
|
return formatError(err);
|
|
664
689
|
}
|
|
665
690
|
});
|
|
666
691
|
// ── 7. Create Campaign ──────────────────────────────────────────
|
|
667
|
-
server.tool("zuckerbot_create_campaign", "Create a new campaign draft for a business.
|
|
692
|
+
server.tool("zuckerbot_create_campaign", "Create a new campaign draft for a business. Defaults to legacy mode, the only launch-ready path during Dealify hardening. Intelligence mode remains available for planning only and cannot be activated. This tool does not spend money or create anything on Meta; review the draft, then use zuckerbot_launch_campaign.", {
|
|
668
693
|
url: z.string().describe("Business website URL"),
|
|
669
694
|
business_id: z.string().optional().describe("Existing ZuckerBot business ID to anchor intelligence mode"),
|
|
670
695
|
architect_session_id: z.string().optional()
|
|
@@ -682,8 +707,8 @@ export function registerTools(server, client) {
|
|
|
682
707
|
.describe("Daily budget in cents (e.g., 2000 = $20/day)"),
|
|
683
708
|
mode: z
|
|
684
709
|
.enum(["auto", "legacy", "intelligence"])
|
|
685
|
-
.
|
|
686
|
-
.describe("Campaign planning mode.
|
|
710
|
+
.default("legacy")
|
|
711
|
+
.describe("Campaign planning mode. Default legacy is the only launch-ready path. auto/intelligence are planning-only while multi-tier activation is disabled."),
|
|
687
712
|
objective: z
|
|
688
713
|
.enum(["leads", "traffic", "conversions", "awareness"])
|
|
689
714
|
.optional()
|
|
@@ -713,8 +738,7 @@ export function registerTools(server, client) {
|
|
|
713
738
|
body.location = location;
|
|
714
739
|
if (budget_daily_cents !== undefined)
|
|
715
740
|
body.budget_daily_cents = budget_daily_cents;
|
|
716
|
-
|
|
717
|
-
body.mode = mode;
|
|
741
|
+
body.mode = mode ?? "legacy";
|
|
718
742
|
if (objective)
|
|
719
743
|
body.objective = objective;
|
|
720
744
|
if (lead_destination)
|
|
@@ -726,7 +750,9 @@ export function registerTools(server, client) {
|
|
|
726
750
|
if (creative_handoff)
|
|
727
751
|
body.creative_handoff = creative_handoff;
|
|
728
752
|
const result = await client.post("/campaigns/create", body);
|
|
729
|
-
return formatResult(appendHint(result,
|
|
753
|
+
return formatResult(appendHint(result, mode === "legacy"
|
|
754
|
+
? "Launch-ready legacy draft created. Review it, confirm Meta credentials and budget, then call zuckerbot_launch_campaign."
|
|
755
|
+
: "Planning-only intelligence draft created. Multi-tier activation is temporarily disabled; create a legacy-mode draft when the user is ready to launch."));
|
|
730
756
|
}
|
|
731
757
|
catch (err) {
|
|
732
758
|
return formatError(err);
|
|
@@ -789,7 +815,7 @@ export function registerTools(server, client) {
|
|
|
789
815
|
}, async ({ campaign_id }) => {
|
|
790
816
|
try {
|
|
791
817
|
const result = await client.get(`/campaigns/${campaign_id}`);
|
|
792
|
-
return formatResult(appendHint(result, "Inspect creative_status and workflow state.
|
|
818
|
+
return formatResult(appendHint(result, "Inspect creative_status and workflow state. Legacy campaigns can launch directly after review. Intelligence campaigns are planning-only while multi-tier activation is disabled."));
|
|
793
819
|
}
|
|
794
820
|
catch (err) {
|
|
795
821
|
return formatError(err);
|
|
@@ -807,13 +833,13 @@ export function registerTools(server, client) {
|
|
|
807
833
|
if (angle_names?.length)
|
|
808
834
|
body.angle_names = angle_names;
|
|
809
835
|
const result = await client.post(`/campaigns/${campaign_id}/approve-strategy`, body);
|
|
810
|
-
return formatResult(appendHint(result, "Strategy approved.
|
|
836
|
+
return formatResult(appendHint(result, "Strategy approved. Upload your creative assets with zuckerbot_upload_creative, or use the Campaign Architect flow: analyse_account_history → recommend_campaign_structure → generate_campaign_brief."));
|
|
811
837
|
}
|
|
812
838
|
catch (err) {
|
|
813
839
|
return formatError(err);
|
|
814
840
|
}
|
|
815
841
|
});
|
|
816
|
-
server.tool("zuckerbot_upload_creative", "Upload finished creative assets (images or videos) to an approved intelligence campaign. ZuckerBot queues the Meta upload and ad-creation jobs asynchronously, then polls until they complete or the polling window expires. Use this when you have your own creative assets ready
|
|
842
|
+
server.tool("zuckerbot_upload_creative", "Upload finished creative assets (images or videos) to an approved intelligence campaign. ZuckerBot queues the Meta upload and ad-creation jobs asynchronously, then polls until they complete or the polling window expires. Use this when you have your own creative assets ready.", {
|
|
817
843
|
campaign_id: z.string().describe("Intelligence campaign ID"),
|
|
818
844
|
creatives: z.array(creativeUploadSchema).min(1).describe("Creative assets to attach to the campaign"),
|
|
819
845
|
meta_access_token: z.string().optional().describe("Optional Meta/Facebook access token override"),
|
|
@@ -833,7 +859,7 @@ export function registerTools(server, client) {
|
|
|
833
859
|
const creativeStatus = typeof payload?.creative_status === "string" ? payload.creative_status : null;
|
|
834
860
|
const queuedJobs = Array.isArray(payload?.queued_jobs) ? payload.queued_jobs : [];
|
|
835
861
|
if (creativeStatus !== "uploading" || queuedJobs.length === 0) {
|
|
836
|
-
return formatResult(appendHint(result, "Creatives uploaded. Call zuckerbot_get_creative_status to check processing status
|
|
862
|
+
return formatResult(appendHint(result, "Creatives uploaded. Call zuckerbot_get_creative_status to check processing status. Intelligence activation is temporarily disabled; use a reviewed legacy draft for live launch."));
|
|
837
863
|
}
|
|
838
864
|
try {
|
|
839
865
|
const polled = await pollCreativeStatus(client, campaign_id);
|
|
@@ -847,7 +873,7 @@ export function registerTools(server, client) {
|
|
|
847
873
|
interval_seconds: CREATIVE_STATUS_POLL_INTERVAL_MS / 1000,
|
|
848
874
|
},
|
|
849
875
|
final_status: polled.lastStatus,
|
|
850
|
-
}, "All creatives uploaded and processed.
|
|
876
|
+
}, "All creatives uploaded and processed for review. Intelligence activation is temporarily disabled; use a reviewed legacy draft for live launch."));
|
|
851
877
|
}
|
|
852
878
|
return formatResult(appendHint({
|
|
853
879
|
initial_response: payload,
|
|
@@ -860,7 +886,7 @@ export function registerTools(server, client) {
|
|
|
860
886
|
suggested_tool: "zuckerbot_get_creative_status",
|
|
861
887
|
},
|
|
862
888
|
last_status: polled.lastStatus,
|
|
863
|
-
}, "Uploads still processing. Call zuckerbot_get_creative_status in 15–30 seconds to check progress.
|
|
889
|
+
}, "Uploads still processing. Call zuckerbot_get_creative_status in 15–30 seconds to check progress. Completed intelligence creatives remain review-only while activation is disabled."));
|
|
864
890
|
}
|
|
865
891
|
catch (pollError) {
|
|
866
892
|
return formatResult(appendHint({
|
|
@@ -876,40 +902,36 @@ export function registerTools(server, client) {
|
|
|
876
902
|
return formatError(err);
|
|
877
903
|
}
|
|
878
904
|
});
|
|
879
|
-
server.tool("zuckerbot_get_creative_status", "Check the asynchronous upload queue for an intelligence campaign to see if Meta ad-creation jobs are complete. Poll this after zuckerbot_upload_creative when the initial response shows creative_status='uploading'. Returns all_complete=true when every queued job has finished
|
|
905
|
+
server.tool("zuckerbot_get_creative_status", "Check the asynchronous upload queue for an intelligence campaign to see if Meta ad-creation jobs are complete. Poll this after zuckerbot_upload_creative when the initial response shows creative_status='uploading'. Returns all_complete=true when every queued job has finished for review; intelligence activation is temporarily disabled.", {
|
|
880
906
|
campaign_id: z.string().describe("Intelligence campaign ID"),
|
|
881
907
|
}, async ({ campaign_id }) => {
|
|
882
908
|
try {
|
|
883
909
|
const result = await client.get(`/campaigns/${campaign_id}/creative-status`);
|
|
884
|
-
return formatResult(appendHint(result, "If
|
|
910
|
+
return formatResult(appendHint(result, "If still uploading, poll again in 15–30 seconds. Completed intelligence creatives remain available for review, but multi-tier activation is temporarily disabled; use a legacy draft for live launch."));
|
|
885
911
|
}
|
|
886
912
|
catch (err) {
|
|
887
913
|
return formatError(err);
|
|
888
914
|
}
|
|
889
915
|
});
|
|
890
|
-
server.tool("zuckerbot_activate_campaign", "
|
|
916
|
+
server.tool("zuckerbot_activate_campaign", "Temporarily unavailable during Dealify launch hardening. Intelligence campaigns are planning-only; create a legacy-mode draft and use zuckerbot_launch_campaign for the supported live path.", {
|
|
891
917
|
campaign_id: z.string().describe("Intelligence campaign ID"),
|
|
892
918
|
tier_names: z.array(z.string()).optional().describe("Optional subset of approved tiers to activate"),
|
|
893
919
|
meta_access_token: z.string().optional().describe("Optional Meta/Facebook access token override"),
|
|
894
920
|
meta_ad_account_id: z.string().optional().describe("Optional Meta ad account ID override (format: act_XXXXX)"),
|
|
895
921
|
meta_page_id: z.string().optional().describe("Optional Facebook Page ID override"),
|
|
896
922
|
}, async ({ campaign_id, tier_names, meta_access_token, meta_ad_account_id, meta_page_id }) => {
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
}
|
|
910
|
-
catch (err) {
|
|
911
|
-
return formatError(err);
|
|
912
|
-
}
|
|
923
|
+
void tier_names;
|
|
924
|
+
void meta_access_token;
|
|
925
|
+
void meta_ad_account_id;
|
|
926
|
+
void meta_page_id;
|
|
927
|
+
return formatResult({
|
|
928
|
+
error: true,
|
|
929
|
+
code: "intelligence_activation_temporarily_disabled",
|
|
930
|
+
message: "Multi-tier activation is temporarily disabled. Create a campaign with mode='legacy', review it, then call zuckerbot_launch_campaign.",
|
|
931
|
+
campaign_id,
|
|
932
|
+
supported_create_mode: "legacy",
|
|
933
|
+
supported_launch_tool: "zuckerbot_launch_campaign",
|
|
934
|
+
});
|
|
913
935
|
});
|
|
914
936
|
server.tool("zuckerbot_suggest_angles", "Return only the creative angles and audience tiers for a campaign draft — a lightweight alternative to zuckerbot_get_campaign when you need just the strategy summary without the full campaign payload, stored creatives, or tier execution details.", {
|
|
915
937
|
campaign_id: z.string().describe("Campaign ID"),
|
|
@@ -976,19 +998,19 @@ export function registerTools(server, client) {
|
|
|
976
998
|
return formatError(err);
|
|
977
999
|
}
|
|
978
1000
|
});
|
|
979
|
-
// ── 4. Pause
|
|
980
|
-
server.tool("zuckerbot_pause_campaign", "Pause
|
|
1001
|
+
// ── 4. Pause Campaign ──────────────────────────────────────────
|
|
1002
|
+
server.tool("zuckerbot_pause_campaign", "Pause a running Meta ad campaign. Pausing stops ad delivery and spend immediately while leaving the campaign in Meta. Use this when creative needs refreshing, budget is exhausted, entitlement is withdrawn, or the user asks to stop spending. Resume is temporarily disabled during Dealify launch hardening.", {
|
|
981
1003
|
campaign_id: z.string().describe("ZuckerBot campaign ID"),
|
|
982
1004
|
action: z
|
|
983
|
-
.
|
|
1005
|
+
.literal("pause")
|
|
984
1006
|
.default("pause")
|
|
985
|
-
.describe("
|
|
1007
|
+
.describe("Pause the campaign"),
|
|
986
1008
|
}, async ({ campaign_id, action }) => {
|
|
987
1009
|
try {
|
|
988
1010
|
const result = await client.post(`/campaigns/${campaign_id}/pause`, {
|
|
989
1011
|
action,
|
|
990
1012
|
});
|
|
991
|
-
return formatResult(appendHint(result, "Campaign paused
|
|
1013
|
+
return formatResult(appendHint(result, "Campaign paused. Call zuckerbot_get_performance to confirm delivery has stopped, or zuckerbot_get_campaign to inspect the full workflow state."));
|
|
992
1014
|
}
|
|
993
1015
|
catch (err) {
|
|
994
1016
|
return formatError(err);
|
|
@@ -1036,7 +1058,7 @@ export function registerTools(server, client) {
|
|
|
1036
1058
|
if (summary_mode)
|
|
1037
1059
|
params.set("summary_mode", "true");
|
|
1038
1060
|
const result = await client.get(`/creative/analysis?${params.toString()}`);
|
|
1039
|
-
return formatResult(appendHint(result, "Analysis complete. Call zuckerbot_creative_cross_analysis to find winning attribute combinations, rerun with include_ads=true to inspect the best and worst individual ads, or use zuckerbot_generate_briefs to produce new
|
|
1061
|
+
return formatResult(appendHint(result, "Analysis complete. Call zuckerbot_creative_cross_analysis to find winning attribute combinations, rerun with include_ads=true to inspect the best and worst individual ads, or use zuckerbot_generate_briefs to produce new creative briefs weighted toward the strongest patterns. Feed these insights into zuckerbot_recommend_campaign_structure for data-driven campaign planning."));
|
|
1040
1062
|
}
|
|
1041
1063
|
catch (err) {
|
|
1042
1064
|
return formatError(err);
|
|
@@ -1081,13 +1103,13 @@ export function registerTools(server, client) {
|
|
|
1081
1103
|
return formatError(err);
|
|
1082
1104
|
}
|
|
1083
1105
|
});
|
|
1084
|
-
server.tool("zuckerbot_generate_briefs", "Generate
|
|
1106
|
+
server.tool("zuckerbot_generate_briefs", "Generate creative production briefs based on the business's tagged ad-performance patterns. Each brief specifies hook type, visual style, copy tone, CTA, and script guidance weighted toward the top-performing creative attributes. Use after running zuckerbot_creative_analysis to know which patterns to bias toward.", {
|
|
1085
1107
|
business_id: z.string().optional().describe("Optional business ID override"),
|
|
1086
1108
|
count: z.number().int().min(1).max(10).optional().describe("How many briefs to generate. Defaults to 5."),
|
|
1087
1109
|
bias: z.string().optional().describe("Optional generation bias, for example performance or exploration"),
|
|
1088
1110
|
exclude_angles: z.array(z.string()).optional().describe("Optional angles or product focuses to avoid"),
|
|
1089
1111
|
target_market: z.string().optional().describe("Optional target market override, for example AU or US"),
|
|
1090
|
-
font_preset: z.string().optional().describe("Optional
|
|
1112
|
+
font_preset: z.string().optional().describe("Optional font preset override"),
|
|
1091
1113
|
metric: z.enum(["cpl", "ctr", "cpc", "frequency"]).optional().describe("Optional ranking metric. Defaults to cpl."),
|
|
1092
1114
|
}, async ({ business_id, count, bias, exclude_angles, target_market, font_preset, metric }) => {
|
|
1093
1115
|
try {
|
|
@@ -1106,7 +1128,7 @@ export function registerTools(server, client) {
|
|
|
1106
1128
|
if (metric)
|
|
1107
1129
|
body.metric = metric;
|
|
1108
1130
|
const result = await client.post("/creative/generate-briefs", body);
|
|
1109
|
-
return formatResult(appendHint(result, "Briefs generated. Pass them to your creative team
|
|
1131
|
+
return formatResult(appendHint(result, "Briefs generated. Pass them to your creative team for production. Once assets are ready, use zuckerbot_upload_creative to attach them to a campaign. For automated brief generation tied to a campaign plan, use zuckerbot_generate_campaign_brief."));
|
|
1110
1132
|
}
|
|
1111
1133
|
catch (err) {
|
|
1112
1134
|
return formatError(err);
|
|
@@ -1580,7 +1602,7 @@ export function registerTools(server, client) {
|
|
|
1580
1602
|
}
|
|
1581
1603
|
});
|
|
1582
1604
|
// ── 22. Create Portfolio ───────────────────────────────────────
|
|
1583
|
-
server.tool("zuckerbot_create_portfolio", "Create a multi-tier audience portfolio for a business from a shared template (e.g., 'Local Services', 'eCommerce') or a custom tier array. Portfolios split
|
|
1605
|
+
server.tool("zuckerbot_create_portfolio", "Create a planning and monitoring-only multi-tier audience portfolio for a business from a shared template (e.g., 'Local Services', 'eCommerce') or a custom tier array. Portfolios split a proposed total budget across prospecting, retargeting, and reactivation tiers with per-tier CPA targets. Portfolio launch is temporarily disabled during Dealify hardening.", {
|
|
1584
1606
|
business_id: z.string().optional().describe("Optional business ID override"),
|
|
1585
1607
|
template_id: z.string().optional().describe("Optional portfolio template ID"),
|
|
1586
1608
|
template_name: z.string().optional().describe("Optional portfolio template name, such as 'Local Services'"),
|
|
@@ -1615,19 +1637,19 @@ export function registerTools(server, client) {
|
|
|
1615
1637
|
if (tiers)
|
|
1616
1638
|
body.tiers = tiers;
|
|
1617
1639
|
const result = await client.post("/portfolios/create", body);
|
|
1618
|
-
return formatResult(appendHint(result, "
|
|
1640
|
+
return formatResult(appendHint(result, "Planning portfolio created. Call zuckerbot_get_portfolio to review the tier configuration. Portfolio launch is temporarily disabled; use a reviewed legacy draft for live launch."));
|
|
1619
1641
|
}
|
|
1620
1642
|
catch (err) {
|
|
1621
1643
|
return formatError(err);
|
|
1622
1644
|
}
|
|
1623
1645
|
});
|
|
1624
1646
|
// ── 23. Get Portfolio ─────────────────────────────────────────
|
|
1625
|
-
server.tool("zuckerbot_get_portfolio", "Fetch the configuration and current performance snapshot for an audience portfolio by ID. Returns tier definitions, budget allocations, CPA targets, and
|
|
1647
|
+
server.tool("zuckerbot_get_portfolio", "Fetch the configuration and current performance snapshot for an audience portfolio by ID. Returns tier definitions, budget allocations, CPA targets, and any existing performance data. Use this to inspect a portfolio for planning, monitoring, or rebalancing an already-active portfolio.", {
|
|
1626
1648
|
portfolio_id: z.string().describe("Audience portfolio ID"),
|
|
1627
1649
|
}, async ({ portfolio_id }) => {
|
|
1628
1650
|
try {
|
|
1629
1651
|
const result = await client.get(`/portfolios/${portfolio_id}`);
|
|
1630
|
-
return formatResult(appendHint(result, "Review tier config and performance. To adjust settings, call zuckerbot_update_portfolio.
|
|
1652
|
+
return formatResult(appendHint(result, "Review tier config and performance. To adjust planning settings, call zuckerbot_update_portfolio. Existing active portfolios can be monitored or rebalanced, but new portfolio launch is temporarily disabled."));
|
|
1631
1653
|
}
|
|
1632
1654
|
catch (err) {
|
|
1633
1655
|
return formatError(err);
|
|
@@ -1696,26 +1718,23 @@ export function registerTools(server, client) {
|
|
|
1696
1718
|
}
|
|
1697
1719
|
});
|
|
1698
1720
|
// ── 27. Launch Portfolio ──────────────────────────────────────
|
|
1699
|
-
server.tool("zuckerbot_launch_portfolio", "
|
|
1721
|
+
server.tool("zuckerbot_launch_portfolio", "Temporarily unavailable during Dealify launch hardening. Portfolio planning and monitoring remain available, but new multi-tier launches must not create Meta objects. Create a legacy-mode draft and use zuckerbot_launch_campaign for the supported live path.", {
|
|
1700
1722
|
portfolio_id: z.string().describe("Audience portfolio ID to launch"),
|
|
1701
1723
|
meta_access_token: z.string().optional().describe("Optional Meta/Facebook access token override"),
|
|
1702
1724
|
meta_ad_account_id: z.string().optional().describe("Optional Meta ad account ID override (format: act_XXXXX)"),
|
|
1703
1725
|
meta_page_id: z.string().optional().describe("Optional Facebook Page ID override"),
|
|
1704
1726
|
}, async ({ portfolio_id, meta_access_token, meta_ad_account_id, meta_page_id }) => {
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
}
|
|
1716
|
-
catch (err) {
|
|
1717
|
-
return formatError(err);
|
|
1718
|
-
}
|
|
1727
|
+
void meta_access_token;
|
|
1728
|
+
void meta_ad_account_id;
|
|
1729
|
+
void meta_page_id;
|
|
1730
|
+
return formatResult({
|
|
1731
|
+
error: true,
|
|
1732
|
+
code: "portfolio_launch_temporarily_disabled",
|
|
1733
|
+
message: "Portfolio launch is temporarily disabled. Create a campaign with mode='legacy', review it, then call zuckerbot_launch_campaign.",
|
|
1734
|
+
portfolio_id,
|
|
1735
|
+
supported_create_mode: "legacy",
|
|
1736
|
+
supported_launch_tool: "zuckerbot_launch_campaign",
|
|
1737
|
+
});
|
|
1719
1738
|
});
|
|
1720
1739
|
// ── 28. Tag Creative ──────────────────────────────────────────
|
|
1721
1740
|
server.tool("zuckerbot_tag_creative", "Tag Meta ads with creative attributes (hook type, visual style, product focus, CTA type, copy tone, setting) by providing ad metadata and optional asset URLs. ZuckerBot uses Claude vision to analyze the creative and store structured tags. These tags feed the zuckerbot_creative_analysis pipeline. Run this after launching new ads to keep the creative intelligence database current.", {
|