hermoso 0.1.269 → 0.1.270
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 +2 -2
- package/mcp/tools.mjs +23 -4
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@ scripts. Research the ads already winning in a market, generate finished image &
|
|
|
5
5
|
composited in, copy + CTA included), publish them to your own social channels, and build & manage the ad
|
|
6
6
|
campaigns behind them, all over [MCP](https://modelcontextprotocol.io) tools, a CLI, or installable Claude skills.
|
|
7
7
|
|
|
8
|
-
**
|
|
8
|
+
**856 tools.** `tools/list` is always the authoritative set; `hermoso_capabilities` (free) returns the live model
|
|
9
9
|
catalog with exact per-render credit costs plus the full capability map.
|
|
10
10
|
|
|
11
11
|
**Most of it costs nothing.** Publishing and scheduling posts, building and managing paid campaigns, analytics
|
|
@@ -216,7 +216,7 @@ block entirely if you signed in above; it is there for CI, where the process can
|
|
|
216
216
|
|
|
217
217
|
Then ask your agent: *“Generate an image ad with Hermoso.”*
|
|
218
218
|
|
|
219
|
-
### What the
|
|
219
|
+
### What the 856 tools cover
|
|
220
220
|
|
|
221
221
|
**Ad spy / research** — `find_competitors`, `competitor_teardown`, `pull_competitor_ads`, `research_ads`; the
|
|
222
222
|
Meta / Google / LinkedIn ad libraries (`search_meta_ads`, `search_google_ads`, `search_linkedin_ads`); organic
|
package/mcp/tools.mjs
CHANGED
|
@@ -7073,7 +7073,7 @@ function buildTools(rawServer, opts = {}, sink = null) {
|
|
|
7073
7073
|
title: 'Subscribe a Facebook Page to real-time events',
|
|
7074
7074
|
description: 'Have Meta PUSH events to Hermoso instead of Hermoso polling for them. Subscribe a Page to `feed` (comments, posts, likes and shares — this is what makes a new comment ARRIVE rather than be polled for), `mention` (someone mentions the Page), `leadgen` (a lead-ad form submission delivered the moment it happens, which turns "read the leads when asked" into "the leads arrive"), and `messages` (an inbound Messenger or Instagram DM — THE ONLY WAY to be told about one, and Meta’s 24-hour reply window starts the moment it arrives, so being told rather than polling is time on the clock). Read what has arrived with list_meta_webhook_events. THE ANSWER IS READ BACK FROM META, never the 200: Meta can accept a subscription and record FEWER fields than you asked for, and a caller told "subscribed to leadgen" whose leads never arrive has no way to discover why — so any field Meta did not record is named. Fields Hermoso does not consume (message_reactions, messaging_postbacks, message_echoes) are refused by name with the reason, so an agent gets a fact rather than "unsupported". 0 credits.',
|
|
7075
7075
|
inputSchema: {
|
|
7076
|
-
fields: z.array(z.enum(['feed', 'mention', 'leadgen', 'messages'])).describe('what to be told about. At least one — Meta marks it required, and defaulting it would decide on the brand’s behalf what they hear about.'),
|
|
7076
|
+
fields: z.array(z.enum(['feed', 'mention', 'leadgen', 'messages', 'marketing_messages', 'marketing_message_echoes', 'marketing_message_deliveries', 'marketing_message_reads', 'marketing_message_clicks', 'marketing_message_delivery_failed'])).describe('what to be told about. `marketing_messages` is shorthand for the five marketing_message_* outcome fields (sent / delivered / read / clicked / failed of a paid Messenger marketing message, read with get_messenger_marketing_message_status). Pass every field the Page should keep: Meta does not document whether a subscribe merges or replaces the list, and the read-back shows what it recorded. At least one — Meta marks it required, and defaulting it would decide on the brand’s behalf what they hear about.'),
|
|
7077
7077
|
pageId: z.string().optional().describe('Facebook Page id — omit when only one Page is connected'),
|
|
7078
7078
|
},
|
|
7079
7079
|
outputSchema: { pageId: z.string().optional(), page: z.string().optional(), asked: z.array(z.string()).optional(), subscribed: z.boolean().nullable().optional(), fields: z.array(z.string()).optional(), summary: z.string().optional(), retry: z.string().optional(), callback: z.string().optional() },
|
|
@@ -7651,8 +7651,8 @@ function buildTools(rawServer, opts = {}, sink = null) {
|
|
|
7651
7651
|
|
|
7652
7652
|
// ── MESSENGER MARKETING MESSAGES (2026-09-05). Meta's paid re-engagement channel: messages OUTSIDE the 24-hour
|
|
7653
7653
|
// window to people who opted in, billed by Meta to the brand's ad account per delivered message. Flow 2 of Meta's
|
|
7654
|
-
// onboarding (user token + marketing_messages_messenger) rides the existing Meta connection.
|
|
7655
|
-
//
|
|
7654
|
+
// onboarding (user token + marketing_messages_messenger) rides the existing Meta connection. The scope was
|
|
7655
|
+
// APPROVED in App Review round 5 (2026-09-22); list_messenger_subscribers reports whether THIS connection carries it.
|
|
7656
7656
|
// Every endpoint, limit and error code: lib/messenger-marketing.mjs (read live 2026-09-05).
|
|
7657
7657
|
// MESSENGER MARKETING MESSAGES ARE A CHANNEL CAPABILITY, NOT PAID ADS (2026-09-07). This block was registered inside
|
|
7658
7658
|
// the ads section, so it rode the heaviest opt-in group while dispatching to no paid-advertising route — unreachable
|
|
@@ -7697,6 +7697,25 @@ function buildTools(rawServer, opts = {}, sink = null) {
|
|
|
7697
7697
|
const d = await apiGet('/api/meta/marketing-messages/campaigns', a);
|
|
7698
7698
|
return ok(`${d.note}${(d.campaigns || []).length ? `\n${d.campaigns.map(c => `• ${c.name || '(unnamed)'} — ${c.campaignId}${c.dailyBudgetUsd != null ? `, $${c.dailyBudgetUsd}/day` : ''}${c.lifetimeBudgetUsd != null ? `, $${c.lifetimeBudgetUsd} lifetime` : ''}`).join('\n')}` : ''}`, d);
|
|
7699
7699
|
}));
|
|
7700
|
+
// DID IT LAND? (2026-09-22). The send returns a tracking id meaning ACCEPTED. The outcome arrives only on the
|
|
7701
|
+
// Page webhook; every payload shape and what each one lacks is in lib/messenger-marketing.mjs.
|
|
7702
|
+
server.registerTool('get_messenger_marketing_message_status', {
|
|
7703
|
+
title: 'Did a Messenger marketing message land?',
|
|
7704
|
+
description: 'Whether a paid Messenger marketing message was delivered. send_messenger_marketing_message returns a tracking id, which only means Meta ACCEPTED it; this reads what Meta pushed back on the Page webhook for each tracking id: sent, delivered (the event Meta bills on), read, clicked (with count), or failed (with Meta’s reason). "unknown" means NO event has arrived, never that it failed: events arrive only when the Page is subscribed to the marketing_message_* fields (the reply says whether it is, read back from Meta; fix with subscribe_meta_webhooks fields ["marketing_messages"]) and only for messages sent after Hermoso began recording them on 2026-09-22. A failure carries no tracking id, so it is matched through Hermoso’s own send log. Read-only, 0 credits.',
|
|
7705
|
+
inputSchema: {
|
|
7706
|
+
trackingId: z.string().optional().describe('the marketing_message_tracking_id send_messenger_marketing_message returned'),
|
|
7707
|
+
trackingIds: z.array(z.string()).optional().describe('several at once, ≤200'),
|
|
7708
|
+
campaignId: z.string().optional().describe('instead of ids: every send Hermoso logged from this campaign'),
|
|
7709
|
+
pageId: z.string().optional().describe('the sending Page, for the subscription check; defaults to the brand’s one shared Page'),
|
|
7710
|
+
},
|
|
7711
|
+
outputSchema: { count: z.number().optional(), counts: z.record(z.number()).optional(), results: z.array(z.any()).optional(), pageId: z.string().nullable().optional(), subscribed: z.boolean().nullable().optional(), missingFields: z.array(z.string()).optional(), note: z.string().optional() },
|
|
7712
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: true },
|
|
7713
|
+
}, wrap(async (a) => {
|
|
7714
|
+
const q = { ...a, ...(Array.isArray(a.trackingIds) ? { trackingIds: a.trackingIds.join(',') } : {}) };
|
|
7715
|
+
const d = await apiGet('/api/meta/marketing-messages/status', q);
|
|
7716
|
+
const lines = (d.results || []).slice(0, 50).map(r => `• ${r.trackingId}: ${r.state} — ${r.note}`);
|
|
7717
|
+
return ok(`${d.note}${lines.length ? `\n${lines.join('\n')}` : ''}`, d);
|
|
7718
|
+
}));
|
|
7700
7719
|
server.registerTool('estimate_messenger_marketing_delivery', {
|
|
7701
7720
|
title: 'Estimate Messenger marketing-message delivery and cost',
|
|
7702
7721
|
description: 'Meta’s own estimate of how many marketing messages a budget would deliver from a Page and what it would cost, before anything is created. Free. Meta marks the metric “in development”, so treat it as a range.',
|
|
@@ -7705,7 +7724,7 @@ function buildTools(rawServer, opts = {}, sink = null) {
|
|
|
7705
7724
|
}, wrap(async (a) => { const d = await apiGet('/api/meta/marketing-messages/estimate', a); return ok(d.note, d); }));
|
|
7706
7725
|
server.registerTool('send_messenger_marketing_message', {
|
|
7707
7726
|
title: 'Send a paid Messenger marketing message',
|
|
7708
|
-
description: 'Send a PAID marketing message on Messenger to opted-in subscribers (Meta act_<AD>/messages). A campaign created in the last ~hour answers 2300012 then 2300041 (Meta still preparing it) with the seconds left; prefer an existing campaign from list_messenger_marketing_campaigns. One message per subscriber per 12 hours — Meta’s rule, enforced before dispatch and by Meta. message.type: text | button (text + up to 3 web_url buttons) | generic (a card: title, subtitle, image, tap-through url, up to 3 buttons) | media (imageUrl or videoId + buttons). Give subscriptionTokens (≤200 per call, from list_messenger_subscribers) OR customAudienceId of a MESSENGER_SUBSCRIBER_LIST audience of 100+ people for a bulk send. Meta bills the ad account per delivered message
|
|
7727
|
+
description: 'Send a PAID marketing message on Messenger to opted-in subscribers (Meta act_<AD>/messages). A campaign created in the last ~hour answers 2300012 then 2300041 (Meta still preparing it) with the seconds left; prefer an existing campaign from list_messenger_marketing_campaigns. One message per subscriber per 12 hours — Meta’s rule, enforced before dispatch and by Meta. message.type: text | button (text + up to 3 web_url buttons) | generic (a card: title, subtitle, image, tap-through url, up to 3 buttons) | media (imageUrl or videoId + buttons). Give subscriptionTokens (≤200 per call, from list_messenger_subscribers) OR customAudienceId of a MESSENGER_SUBSCRIBER_LIST audience of 100+ people for a bulk send. Meta bills the ad account per delivered message. A successful send means ACCEPTED, not delivered: read sent / delivered / read / clicked / failed per tracking id with get_messenger_marketing_message_status (Meta pushes them on the Page webhook; the Page must be subscribed with subscribe_meta_webhooks fields ["marketing_messages"]). dryRun:true previews the wire body and sends nothing. Meta’s frequency caps are silent: a refusal saying the person is capped is Meta protecting them, not a broken send.',
|
|
7709
7728
|
inputSchema: {
|
|
7710
7729
|
adAccountId: z.string(),
|
|
7711
7730
|
campaignId: z.string().describe('the message campaign id (from create_messenger_marketing_campaign or list_messenger_marketing_campaigns) — OR the campaign NAME as the user said it: a non-numeric value is resolved against the account\'s own campaigns, so you never need to ask for an id'),
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hermoso",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.270",
|
|
4
4
|
"mcpName": "io.github.hermoso-ai/hermoso",
|
|
5
|
-
"description": "Marketing on autopilot, run from your own AI agent.
|
|
5
|
+
"description": "Marketing on autopilot, run from your own AI agent. 856 tools. Publishing, scheduling, ad campaign management, comments, DMs and analytics cost no credits on every plan; credits are only for generating creative and for Ad Spy research. AD PLATFORMS: Meta, Google Ads, TikTok Ads, LinkedIn Ads, Reddit Ads, X Ads, Pinterest Ads, Snapchat Ads, Microsoft Advertising, Apple Search Ads and ChatGPT Ads, plus product feeds in Google Merchant Center. PUBLISHING AND SCHEDULING: Facebook, Instagram, Threads, TikTok, YouTube, X, LinkedIn, Pinterest, Bluesky and Telegram. AD RESEARCH: the Meta, Google and LinkedIn ad libraries plus organic TikTok, Instagram, YouTube, Threads and Reddit. ANALYTICS: Google Analytics 4, Google Search Console and every connected platform's own post and campaign insights. Also brand onboarding, 50+ image and video generation models, ad scoring, competitor teardowns, Google Drive and OneDrive, a CLI and installable Claude skills.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
8
8
|
"hermoso": "bin/hermoso.mjs"
|