hermoso 0.1.235 → 0.1.237

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.
Files changed (2) hide show
  1. package/mcp/tools.mjs +9 -6
  2. package/package.json +1 -1
package/mcp/tools.mjs CHANGED
@@ -2709,11 +2709,13 @@ function buildTools(rawServer, opts = {}, sink = null) {
2709
2709
  }
2710
2710
  if (n === 'call_tool' || n === 'find_tools' || n === 'enable_tools') return { content: [{ type: 'text', text: `${n} is a roster tool; call it directly.` }], isError: true };
2711
2711
  const why = toolHoldReason(n, ctx);
2712
- if (why) reportDeadEnd(why, n, holdReasonText(n, why, ctx));
2713
- if (why === 'not_offered') return { content: [{ type: 'text', text: holdReasonText(n, why, ctx) }], isError: true };
2714
- if (why === 'host_policy') return { content: [{ type: 'text', text: `${n} is not offered on this host (the host's own commerce policy). Use the Hermoso app or another client for it.` }], isError: true };
2715
- if (why === 'not_connected') return { content: [{ type: 'text', text: `${n} needs the "${toolProvider(n)}" connection and this workspace has not made it. Connect it under Settings ▸ Connectors in the Hermoso app${Object.prototype.hasOwnProperty.call(KEY_CONNECTORS, toolProvider(n)) ? ', or right here with connect_connector if the user prefers' : ''}, then call again.` }], isError: true };
2716
- if (why === 'directory') return { content: [{ type: 'text', text: `${n} is outside what this Claude directory connection may run. Use the Hermoso app, or connect the unscoped server URL.` }], isError: true };
2712
+ // ONE sentence per hold, from holdReasonText. call_tool used to spell its own copies, so the connect link added there
2713
+ // never reached claude.ai or ChatGPT, the two hosts that run held tools through here.
2714
+ if (why) {
2715
+ const t = holdReasonText(n, why, ctx);
2716
+ reportDeadEnd(why, n, t);
2717
+ if (t) return { content: [{ type: 'text', text: t }], isError: true };
2718
+ }
2717
2719
  let input = args && typeof args === 'object' ? args : {};
2718
2720
  if (h.inputSchema) {
2719
2721
  const parsed = h.inputSchema.safeParse(input);
@@ -9896,7 +9898,8 @@ function buildTools(rawServer, opts = {}, sink = null) {
9896
9898
  title: z.string().describe('the headline — 3 to 50 characters, enforced'),
9897
9899
  body: z.string().describe('the description under the headline — 100 characters maximum, enforced'),
9898
9900
  targetUrl: z.string().describe('the landing page (must not block OAI-AdsBot / OAI-SearchBot in robots.txt)'),
9899
- imageUrl: z.string().optional().describe('public https URL of a STILL image — REQUIRED on every text ad (ChatGPT Ads refuses an ad with no creative.file_id unless the campaign is a product feed; measured 2026-09-06); a video URL is refused, this channel has no video format'),
9901
+ imageUrl: z.string().optional().describe('public https URL of a STILL image — every text ad needs imageUrl OR fileId (ChatGPT Ads refuses an ad with no creative.file_id unless the campaign is a product feed; measured 2026-09-06); a video URL is refused, this channel has no video format'),
9902
+ fileId: z.string().optional().describe('reuse an image ChatGPT Ads already holds: the fileId list_openai_ads_campaigns returns for an existing ad (list with adGroupId). Wins over imageUrl; use it to copy an ad exactly'),
9900
9903
  price: z.string().optional().describe('optional price string shown on the card'),
9901
9904
  });
9902
9905
  server.registerTool('list_openai_ads_campaigns', {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hermoso",
3
- "version": "0.1.235",
3
+ "version": "0.1.237",
4
4
  "mcpName": "io.github.hermoso-ai/hermoso",
5
5
  "description": "AI ad studio and marketing MCP server with 828 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",