hermoso 0.1.185 → 0.1.187
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/mcp/tools.mjs +4 -3
- package/package.json +1 -1
package/mcp/tools.mjs
CHANGED
|
@@ -3660,6 +3660,7 @@ function buildTools(rawServer, opts = {}, sink = null) {
|
|
|
3660
3660
|
link: z.string().optional().describe('a URL to attach (FB text post only)'),
|
|
3661
3661
|
collaborators: z.array(z.string()).optional().describe('INSTAGRAM COLLAB \u2014 up to 3 Instagram usernames invited to CO-AUTHOR this post. Once one accepts, the post appears on THEIR profile too, with both handles in the header and the likes and comments shared \u2014 it is how a brand reaches a creator\u2019s audience without paying for placement, and it is the single most-asked thing a scheduler normally cannot do. Pass handles only ("hermosoai"), not profile links; a leading @ is fine. INSTAGRAM ONLY \u2014 Facebook and Threads have no collab post at all and are refused BY NAME rather than silently dropping the co-authors \u2014 and never on a Story. AN INVITE IS NOT A CO-POST: publishing SENDS a request the other account must accept in their Instagram notifications, and until they do the post is on this brand\u2019s profile ALONE; they may also decline, and Instagram sends no notification either way. So never report the post as live on both accounts \u2014 read the invite status back out of the reply, and use instagram_collaborators later to find out whether they accepted.'),
|
|
3662
3662
|
target: z.enum(['facebook', 'instagram', 'threads']).optional().describe('default facebook; instagram → the Page’s linked IG; threads → the brand’s connected Threads account'),
|
|
3663
|
+
account: z.string().optional().describe('WHICH Instagram account when target is instagram and the brand has several — Page-linked and Instagram Login accounts alike; an @username or id from list_connector_accounts("instagram"). Several and none named is refused by name; omit when there is one.'),
|
|
3663
3664
|
scheduleAt: z.string().optional().describe('FACEBOOK ONLY — schedule instead of posting now. ISO timestamp (2026-08-01T09:00:00Z) or unix seconds; must be 10 minutes to 30 days ahead. Facebook holds the post and publishes it at that time, so nothing has to stay running on our side. Instagram and Threads have NO scheduling in Meta’s API — passing this for them is refused rather than silently posted immediately.'),
|
|
3664
3665
|
locationId: z.string().optional().describe('Threads only — a place id from search_threads_locations, to geotag the post to a physical location (restaurant, storefront)'),
|
|
3665
3666
|
trialReel: z.enum(['MANUAL', 'SS_PERFORMANCE']).optional().describe('INSTAGRAM TRIAL REEL \u2014 publish this Reel to NON-FOLLOWERS ONLY at first, so a hook can be tested on a cold audience without spending it on the people who already follow the brand. Instagram then shows it to followers only if it graduates. MANUAL = the creator graduates it by hand in the Instagram app; SS_PERFORMANCE = Instagram graduates it automatically if it performs well. REELS ONLY and INSTAGRAM ONLY: an image, a carousel, a Facebook post or a Threads post is REFUSED BY NAME rather than quietly published as an ordinary post \u2014 a trial that silently goes to every follower is the exact opposite of what was asked for. Omit it for a normal Reel.'),
|
|
@@ -15742,8 +15743,8 @@ function buildTools(rawServer, opts = {}, sink = null) {
|
|
|
15742
15743
|
// channel (each was its own OAuth run). There is nothing to "share" or tick — every connected account is usable —
|
|
15743
15744
|
// so `write` is null and set_connector_accounts refuses by name; add one by connecting again in the app, remove one
|
|
15744
15745
|
// with disconnect_connector({provider, account}). The listing is what post_to_* and schedule_post's `account(s)` take.
|
|
15745
|
-
...Object.fromEntries(['tiktok', 'x', 'youtube', 'threads', 'bluesky', 'telegram', 'reddit', 'pinterest'].map((p) => [p, {
|
|
15746
|
-
label: p === 'x' ? 'X' : p === 'youtube' ? 'YouTube' : p === 'tiktok' ? 'TikTok' : p.charAt(0).toUpperCase() + p.slice(1), read: `/api/connectors/${p}/accounts`, multiAccount: true,
|
|
15746
|
+
...Object.fromEntries(['tiktok', 'x', 'youtube', 'threads', 'bluesky', 'telegram', 'reddit', 'pinterest', 'instagram'].map((p) => [p, {
|
|
15747
|
+
label: p === 'x' ? 'X' : p === 'youtube' ? 'YouTube' : p === 'tiktok' ? 'TikTok' : p.charAt(0).toUpperCase() + p.slice(1), read: `/api/connectors/${p}/accounts`, multiAccount: true, // instagram: Page-linked AND Instagram Login accounts, one list (2026-09-02)
|
|
15747
15748
|
identities: (d) => (d.accounts || []).map(a => ({ id: String(a.id), name: a.handle ? '@' + a.handle : (a.label || a.id), type: 'account', selected: true, detail: [a.label && a.handle && a.label !== a.handle ? a.label : '', a.live === false ? 'RECONNECT NEEDED' : '', d.primaryAccount === a.id ? 'primary' : ''].filter(Boolean).join(' · ') })),
|
|
15748
15749
|
write: null,
|
|
15749
15750
|
}])),
|
|
@@ -15918,7 +15919,7 @@ function buildTools(rawServer, opts = {}, sink = null) {
|
|
|
15918
15919
|
if (p.needsConnect?.(d)) return { content: [{ type: 'text', text: `${p.label} isn’t connected to this workspace yet. Linking it is an OAuth consent screen, so the user has to do it in a browser: Workspace ▸ Connectors ▸ ${p.label}. Then call this again.` }], isError: true };
|
|
15919
15920
|
const rows = p.identities(d);
|
|
15920
15921
|
const sel = rows.filter(r => r.selected).map(r => r.id);
|
|
15921
|
-
return ok(`${p.label} — ${rows.length} account(s) this connection can reach, ${sel.length} shared with this brand:\n${connIdentityLines(rows) || ' (none)'}\n\
|
|
15922
|
+
return ok(`${p.label} — ${rows.length} account(s) this connection can reach, ${sel.length} shared with this brand:\n${connIdentityLines(rows) || ' (none)'}\n\n${p.write ? 'Change the shared set with set_connector_accounts (it REPLACES the selection).' : `Every account here is usable — name one with \`account\` on post_to_${a.provider} (or \`accounts\` on schedule_post). Add another by connecting again in the app; remove one with disconnect_connector({provider:'${a.provider}', account:'@handle', confirm:true}).`}`, { provider: a.provider, identities: rows, selectedIds: sel });
|
|
15922
15923
|
}));
|
|
15923
15924
|
server.registerTool('set_connector_accounts', {
|
|
15924
15925
|
title: 'Choose which accounts a brand may use',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hermoso",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.187",
|
|
4
4
|
"mcpName": "io.github.hermoso-ai/hermoso",
|
|
5
5
|
"description": "AI ad studio and marketing MCP server with 745 tools. Research the ads already running in any market, generate finished image, video and UGC avatar ads, publish and schedule them to your own channels, build and manage the ad campaigns behind them, and read what they achieved. 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",
|