{
  "markdown": "# Hermoso — MCP, CLI & Skills\n\nRun your whole marketing operation from **any AI agent**: Claude Code, Claude.ai, Cursor, Codex, or your own\nscripts. Research the ads already winning in a market, generate finished image & video ads (your real product\ncomposited in, copy + CTA included), publish them to your own social channels, and build & manage the ad\ncampaigns behind them — all over [MCP](https://modelcontextprotocol.io) tools, a CLI, or installable Claude skills.\n\n**801 tools.** `tools/list` is always the authoritative set; `hermoso_capabilities` (free) returns the live model\ncatalog with exact per-render credit costs plus the full capability map.\n\n**What it connects to.** Ad platforms: Meta, Google Ads, TikTok Ads, LinkedIn Ads, Reddit Ads, X Ads,\nPinterest Ads, Snapchat Ads, Microsoft Advertising, Apple Search Ads and ChatGPT Ads, plus product feeds in\nGoogle Merchant Center. Publishing and scheduling — **ten** channels: Facebook, Instagram, Threads, TikTok,\nYouTube, X, LinkedIn, Pinterest, Bluesky and Telegram. Messaging: WhatsApp (you message a person, so it is not an\neleventh publishing channel). Ad research: the Meta, Google and LinkedIn ad libraries plus organic TikTok,\nInstagram, YouTube, Threads and Reddit. Analytics: Google Analytics 4, Google Search Console and every\nconnected platform's own post and campaign insights. Files: Google Drive, Sheets, Docs and OneDrive.\n\n**It is not all-or-nothing.** Research, creation, publishing/scheduling and ads management are four *independent*\nareas — no tool requires that you used another one first. Publish or schedule creative you already have and\ngenerate nothing here (`upload_file` turns any local or external file into a URL every publish, schedule and\nad-build tool accepts); build and read campaigns on your own ad accounts with your own creative; research\ncompetitors with no brand drafted and no channel connected; or generate a file with nothing connected at all and\njust download it. Use the one piece you need, or all of it together.\n\n## Which surface should your agent use?\n\nTwo shapes, and the right one is decided by **what your client can do**, not by which we prefer.\n\n| Your client | Use | Why |\n| --- | --- | --- |\n| **Runs in a browser** — Claude.ai, ChatGPT, Claude Desktop | the hosted connector `https://app.hermoso.ai/mcp` | It cannot spawn a local process, so a URL is the only shape it has. Nothing to install, no key to paste, and the full toolset arrives with your saved brand context. This is the right answer for these clients, not a lesser one. |\n| **Can run a shell** — Claude Code, Cursor, Codex, Cline, OpenClaw, Hermes, your own scripts | the CLI, `npm install -g hermoso` | A tool manifest is loaded into every session whether or not a tool is called. A shell command costs nothing until it runs, and it reaches **every** tool rather than the default roster. |\n\n**The measured difference** (2026-08-27, counted as real tool definitions rather than estimated from bytes):\n\n| | tools in range | loaded per session |\n| --- | --- | --- |\n| Hosted connector, default roster | 306 | **181,713 tokens** |\n| Hosted connector, `?tools=all` | 718 | **472,062 tokens** |\n| stdio server (`npx -y hermoso mcp`) | 306 | **181,713 tokens** |\n| **CLI** | **all 718** | **0** |\n\nThe CLI answers the same questions on demand instead, and only when asked:\n\n```bash\nnpx -y hermoso tools --search reddit   # every matching tool, name + one line   2,459 tokens\nnpx -y hermoso tools plan_ad           # one tool's full argument schema           633 tokens\nnpx -y hermoso call plan_ad --json '{\"product\":\"…\"}'   # run it\n```\n\nSo a terminal agent reaches its first call in roughly **3.4K tokens with the whole roster in range**, against\n**182K for a fraction of it**. `tools` and `tools <name>` read a registry bundled in the package — no key, no\nnetwork, no sign-in — so an agent can browse the entire product before anyone signs in. Only `call` spends, and\nonly that needs `hermoso auth login` once.\n\n**Both at once is fine, and is what we suggest for Claude Code.** One `hermoso auth login` covers the CLI *and*\nlets `claude mcp add hermoso -- npx -y hermoso mcp` pick the key up with no `env` block, so the agent can reach for\na native tool when it wants structured results and shell out when it wants breadth. If you only want one, take the\nCLI: it covers strictly more.\n\n**When the connector is still the better trade on a shell-capable client:** a session that is going to make many\ncalls into one area. `enable_tools({groups:['ads']})` turns campaign management on in a single free call and the\ntools are then native — no shell quoting, structured results. One shell round trip beats loading a 221K-token\ngroup for a single tool; the reverse is true once a session settles into that area.\n\n## Your agent can sign itself up\n\nAn agent with no Hermoso account can provision one, get its own key, and be rendering ads in the same session.\nNo human at a browser, no ticket, no waiting.\n\n```bash\n# 1. Start a signup. This call takes no credential, because the credential is what it creates.\ncurl -sX POST https://app.hermoso.ai/v1/signup \\\n  -H 'content-type: application/json' \\\n  -d '{\"plan\":\"pro\",\"period\":\"mo\",\"email\":\"you@yourcompany.com\"}'\n# -> { \"id\": \"cs_...\", \"checkout_url\": \"https://checkout.stripe.com/...\", \"claim_token\": \"hsc_...\", \"email\": { \"address\": \"you@yourcompany.com\", \"verified\": false } }\n# email = the human behind the account. A verification link goes there; the account works before it is clicked.\n# It is a contact mailbox only, never a sign-in. GET /v1/account/email reports the state; POST /v1/account/email/resend re-sends or changes it.\n\n# 2. Pay at checkout_url. Store claim_token first: it is returned only in that response.\n\n# 3. Claim it. Poll until status is \"ready\".\ncurl -sX POST https://app.hermoso.ai/v1/signup/cs_.../claim \\\n  -H 'content-type: application/json' \\\n  -d '{\"claim_token\":\"hsc_...\"}'\n# -> { \"status\": \"ready\", \"api_key\": \"hmk_...\", \"credits\": 3000 }\n```\n\nThat `hmk_` key is the same credential everything else on this page takes: `/v1`, the MCP server, the CLI. Point\nyour client at it and the full surface is open.\n\n**Paying is something a browser-capable agent can already do itself.** Checkout is Stripe's own hosted page, so\nClaude in Chrome and clients like it complete it unattended today. Everything else is a one-click handoff: send\n`checkout_url` to whoever holds the card. The same shape covers you later, once you are running: `buy_credits`\nand `upgrade_plan` mint a ready-to-pay link for more credits or a bigger plan, and `billing_status` reads the\nbalance any time.\n\n**An agent with its own payment credential can pay with no human at all.** `POST /api/billing/machine-payment`\nwith `{\"packId\": \"pack-1k\"}` answers HTTP 402 carrying a `WWW-Authenticate: Payment` challenge (Stripe, through the\nMachine Payments Protocol); pay the challenge and retry, and the same credit pack lands on the same balance.\n`GET /api/billing/config` lists the packs under `machinePayments`. Same packs, same prices, no per-call billing.\n\n**The agentic path takes a paid plan.** Any of them. The free plan is there for a person signing up at\n[app.hermoso.ai](https://app.hermoso.ai), and asking for it here returns a refusal that says so. Nothing is\ncreated until the payment completes, so an unpaid signup leaves no account behind and charges nothing.\n\n**One thing still wants a person, and it is worth knowing up front.** Connecting a social or ad account means an\nOAuth consent screen, and a consent screen cannot be completed headlessly on any platform. `list_connectors`\nshows what is already connected and what is not. Everything else runs with no browser at all: research,\ngeneration, publishing to a channel that is already connected, campaign builds, reporting.\n\nFull request and response shapes, plus every other endpoint, are in the OpenAPI document at\n[app.hermoso.ai/openapi.json](https://app.hermoso.ai/openapi.json), served live from the same table that mounts\nthe routes.\n\n## Instant: the hosted Claude.ai connector\n\nPaste **`https://app.hermoso.ai/mcp?src=readme`** into Claude → Settings → Connectors → *Add custom connector*, pick\n**Always required** when Claude asks about authentication (its detector suggests \"None\" because our discovery\nhandshake is open; \"None\" would leave every tool call unauthenticated), approve with your Hermoso account, done — the full toolset with your saved brand context, billed to your plan.\n\n## Quickstart for Claude Code (one line)\n\n1. **Get an account** at [app.hermoso.ai](https://app.hermoso.ai) — free tier included; plans & credits are the\n   same ones the web Studio uses. Or skip the browser entirely and let your agent sign itself up on a paid plan\n   with `POST /v1/signup` (above).\n2. **Run one line.** Your browser opens once to sign in. Nothing to paste, and no key lands in `.claude.json`:\n\n```bash\nnpm install -g hermoso && hermoso auth login && claude mcp add hermoso -- npx -y hermoso mcp\n```\n\n3. **Ask for what you want**, in your normal prompts. Claude Code reaches for a tool, or runs the `hermoso`\n   command in your terminal, whichever the job needs. You type neither.\n\nAd campaign and analytics tools stay out of the tool list until you switch them on with `enable_tools`, which\nkeeps it small. On a machine with no browser, sign in with `hermoso auth login --token hmk_…` using a key from\n**Settings → Agents & API**, or skip the sign-in and pass the key to the client instead:\n\n```bash\nclaude mcp add hermoso -e HERMOSO_TOKEN=hmk_… -- npx -y hermoso mcp\n```\n\nThe hosted URL works in Claude Code too, but it is the worse path there and it is worth knowing why:\n`claude mcp add --transport http hermoso \"https://app.hermoso.ai/mcp?src=readme\"` is accepted, and then `claude mcp list`\nreports `! Needs authentication` because the client will not start the OAuth flow by itself — you have to open a\nsession, run `/mcp`, find the server and press Authenticate. Measured against Claude Code 2.1.241 on 2026-08-23.\n\nYour agent now has the full studio **with your workspace's context**: the brand profile, products, logos and\nlearned memory you set up in the web app apply automatically (`get_brand` shows what's saved; omit `brand` in\n`plan_ad`/`plan_variations` to use it). Renders bill your Hermoso credits — same prices as the Studio. Only AI model runs and Ad Spy research spend credits; publishing, scheduling, ads management and analytics are free on every plan (X is the one per-call exception).\n\n## 1. MCP server (stdio) — Claude Code / Cursor / Codex\n\n`hermoso mcp` runs a stdio MCP server exposing the full toolset. The published `hermoso` package means no clone —\n`npx -y hermoso mcp` fetches and runs it. Sign in once with the CLI and no key goes into any client config,\nbecause `hermoso mcp` reads the bearer `hermoso auth login` stored:\n\n```bash\nnpm install -g hermoso && hermoso auth login && claude mcp add hermoso -- npx -y hermoso mcp\n```\n\nCursor / Codex — sign in the same way, then add to `mcp.json` (Codex uses the TOML equivalent). Drop the `env`\nblock entirely if you signed in above; it is there for CI, where the process cannot read your home directory:\n\n```json\n{ \"mcpServers\": { \"hermoso\": { \"command\": \"npx\", \"args\": [\"-y\", \"hermoso\", \"mcp\"],\n  \"env\": { \"HERMOSO_API_BASE\": \"https://app.hermoso.ai\", \"HERMOSO_TOKEN\": \"<your token>\" } } } }\n```\n\nThen ask your agent: *“Generate an image ad with Hermoso.”*\n\n### What the 801 tools cover\n\n**Ad spy / research** — `find_competitors`, `competitor_teardown`, `pull_competitor_ads`, `research_ads`; the\nMeta / Google / LinkedIn ad libraries (`search_meta_ads`, `search_google_ads`, `search_linkedin_ads`); organic\nsocial (`search_tiktok`, `search_instagram`, `search_youtube`, `search_reddit`, `search_threads`);\n`fetch_social_data`, `mine_angles`, `analyze_video`, `check_ad_policy`, `list_skills` / `get_skill`.\n\n**Create** — `draft_brand` → `plan_ad` → `render_ad` (the Studio quality pipeline: composited text, clean speech,\nmusic, brand end card), or `generate_image` / `generate_video` / `generate_avatar` (UGC creators + lip-sync).\nThe workspace's **saved cast** is reusable: `list_creators` returns every saved creator with their portrait url,\n`save_creator` adds one, `delete_creator` drops one — re-pass a portrait to `generate_avatar` / `generate_video` /\n`recast_motion` and the SAME person stars in every ad, instead of a new face each render.\nAlso `make_template_ad` (native HTML ad formats), `make_explainer`, `product_sizzle`, `make_thumbnail`,\n`remix_static`, `recast_motion`, `reframe_video`, `upscale_video`, `dub_video`, `change_voice`, `finish_video`,\n`fix_beat`, `stitch_video`, `clip_video`, `post_edit`, plus `plan_variations` + `score_ad` to fan out and rank.\n**Length is yours to set:** pass `durationSeconds` to `plan_ad` and the storyboard is *authored* to it — a length\nthat fits one clip of the render model renders as a single continuous take, longer is stitched from acts (on a\n15s-clip model, 40s = 15+15+10), never time-compressed. What fits one clip is the model's own maximum, not a fixed\nnumber: most video models cap a clip at 15 seconds and the longest-clip one takes **30 seconds in one unbroken\ntake** with native synchronized audio. `hermoso_capabilities` is the live list — durations, resolutions and the\nexact credit cost of every tier — and naming that model in `model` is how you get it, since an unnamed render is\nrouted by a narrower auto-pool.\n\n**Raw model playground** — the full catalog (30+ image / video / voice / writing models, each with its exact\nper-render credit cost) with no ad framing: `generate_image` / `generate_video` with `useBrand:false`,\n`generate_voice`, `generate_text`.\n\n**Publish to your own channels** — **ten** of them: Facebook, Instagram and Threads (`post_to_meta`), TikTok\n(`post_to_tiktok`), YouTube (`post_to_youtube` + `update_youtube_video`, `youtube_video_insights`, comments\nread/reply), X (`post_to_x`, `x_post_metrics`, `x_post_insights`, `x_mentions`, `list_x_dms`, `send_x_dm`),\nLinkedIn profile **and** company Pages (`post_to_linkedin`, `post_to_linkedin_page`), Pinterest\n(`post_to_pinterest` + boards), Bluesky (`post_to_bluesky`, `delete_bluesky_post`, `bluesky_post_metrics`, plus\n`list_bluesky_convos` / `read_bluesky_dm` / `send_bluesky_dm`) and Telegram (`post_to_telegram`,\n`delete_telegram_message`, `list_telegram_chats`). `schedule_post` / `list_scheduled` / `cancel_scheduled` give\nyou one content calendar over exactly that set. `upload_file` brings in any external or local media, not just\nHermoso renders.\n*X posting bills credits per API call (X charges per request); a post containing a link costs 13× one without.*\n*Held back, and named rather than hidden:* **Google Business Profile** is built (`post_to_google_business`,\nreviews, Q&A, insights) and is not offered — Google allowlists that API per project and ours reads 0 QPM, so\nevery call would 403 for every user. It is in `schedule_post`'s channel enum and refused at enqueue.\n\n**Message customers on WhatsApp** — messaging, not an eleventh publishing channel: you message a person, and\nnothing here posts to a feed. `list_whatsapp_accounts` finds the Business Account and its\nnumbers, `list_whatsapp_templates` / `create_whatsapp_template` / `delete_whatsapp_template` manage the templates\nMeta reviews, and `send_whatsapp_message` sends one — confirm-gated, because it reaches a real phone and Meta\nbills the business for the conversation. Two limits that are permanent facts about Meta's API rather than\nanything pending: **Hermoso does not receive WhatsApp webhooks, so there is no message history to read** — it is\nnot an inbox surface and `list_inbox` does not cover it — and **outside the 24-hour window that opens when the\ncustomer messages first, WhatsApp accepts an APPROVED template and nothing else.**\n\n**Run the ads** — full campaign trees, built paused and read back before anything is reported, with every spend\nchange confirm-gated, on **eleven** platforms: **Meta**, **Google Ads**, **LinkedIn Ads**, **Reddit Ads**,\n**Pinterest Ads**, **Microsoft Advertising**, **ChatGPT Ads** (OpenAI's Advertiser API), **X Ads**, **TikTok Ads**,\n**Snapchat Ads** and **Apple Ads** (Apple Search Ads on the App Store). Each has list + report + create + budget/status tools\n(e.g. `list_google_ads_campaigns`, `google_ads_report`, `create_google_ads_campaign`, `set_google_ads_budget`,\n`set_google_ads_status`). *Snapchat needs one extra step the others do not: an ad points at a CREATIVE, and every\nSnapchat creative must carry a Public Profile id — build it with `upload_snapchat_ads_creative`.*\n\n**Feed the shopping surfaces** — **Google Merchant Center** is the catalog a retail Performance Max or Shopping\ncampaign advertises (`create_google_ads_performance_max_campaign` takes a `merchantCenterId`), and you manage it\nfrom here: accounts and account status, data sources, product upsert / update / delete, per-region inventory,\nquota, `merchant_report` for product-level performance, notifications and conversion sources, plus the disapproval\nloop — `list_merchant_issues` says what is wrong and `merchant_issue_help` returns Google's own documented fix.\n*Promotions need the merchant's own enrolment in Google's promotions program; without it Google refuses that\nsub-API outright.* **Microsoft Merchant Center** is covered on the same shape (stores, catalogs, products, issues)\nfor Bing Shopping.\n\n**Measure what the ads achieved** — Google Analytics 4 closes the loop. Every other connector here reports what an\nad *cost*; this is the one that reports what it *did*. `analytics_report` breaks sessions, users, conversions and\nrevenue down by channel, source/medium, campaign, landing page, country, device or date, so the campaign Hermoso\nbuilt and the revenue it drove sit in one conversation. `analytics_realtime` shows who is on the site right now.\nStart at `list_analytics_properties` — the tools take a numeric property id, not the `G-XXXXXXXXX` Measurement ID\nfrom your tracking snippet, and this is what resolves one from the other. It writes as well as reads:\n`create_analytics_key_event` marks an event GA4 already collects as a key event — which is what makes it importable\ninto Google Ads as a conversion — and `create_analytics_custom_dimension` registers an event parameter so reports\ncan break down by it, with `list_analytics_definitions` showing what the property already measures. It signs in\nwith the same Google account as Google Ads, YouTube and Drive, but it is its own connection.\n*GA4 only — the API has no Universal Analytics surface. A custom dimension can be archived but never deleted, and a\nproperty holds 50 event-scoped ones.*\n\n**Files** — Google Drive CRUD (`save_to_drive`, `list_drive_files`, `update_drive_file`, `delete_drive_file`,\n`create_drive_folder`), Google Sheets (`create_sheet`, `append_to_sheet`, `read_sheet`), Google Docs\n(`create_doc`, `append_to_doc`), and OneDrive (`save_to_onedrive` + full CRUD).\n\n**Workspace & account** — brand workspaces (`list_brands`, `create_brand`, `use_brand`, `update_brand`,\n`delete_brand` — one account holds many brands, so an agency runs every client through here), memory\n(`remember`, `forget`, `list_memory`), custom skills (`save_skill`, `get_skill`, `list_skills`,\n`delete_skill` — the one library, which absorbed the old AI-Employee personas), team (`list_team`, `invite_member`, `remove_member`,\n`set_role`), settings (`get_settings`, `update_settings` — including the **language** every ad, script and plan\nis written in), connectors (`list_connectors`, `list_connector_accounts`, `set_connector_accounts`,\n`disconnect_connector`), and billing (`hermoso_credits`, `billing_status`, `buy_credits`, `upgrade_plan`,\n`set_auto_reload`), plus `list_jobs` / `get_job` for async renders.\n\n**Connector accounts are picked, not guessed.** One person often administers several Facebook Pages, Google Ads\ncustomers or LinkedIn company Pages. Only the accounts ticked for a brand are usable — enforced server-side, and\nan empty selection shares nothing. Linking a *new* account is the one step that is not headless (it is an OAuth\nconsent screen, so the user does it in the app).\n\nRender jobs queue server-side and poll to completion, returning a served URL.\n\n## 2. CLI — the token-cheap path for terminal agents\n\n`bin/hermoso.mjs` exposes the full MCP toolset as subprocess commands, so an agent can shell out instead of carrying a\nfat tool manifest.\n\n```bash\nnpm install -g hermoso                             # installs `hermoso`\nhermoso capabilities                               # valid model ids + costs (run first)\nhermoso create --brand \"YourBrand\" --product \"your best-selling product\" --format image\nhermoso generate image --prompt \"…\" --ref ./product.png --wait\nhermoso generate video --prompt \"…\" --duration 8 --wait\nhermoso competitors yourbrand.com\nhermoso research \"Liquid Death’s longest-running ads\"\n```\n\nAdd `--json` to any command for machine output.\n\n**Those shortcuts are the common path, not the limit.** Every tool the MCP server has is reachable here too,\nincluding the ad-campaign and analytics groups a connector leaves out of its default roster:\n\n```bash\nhermoso tools                          # every tool, grouped, name + one line\nhermoso tools --group ads --search reddit   # narrow it\nhermoso tools create_meta_campaign     # that tool's full argument schema\nhermoso call create_meta_campaign --json '{\"name\":\"…\"}'   # run it\nhermoso create_meta_campaign --name \"…\"                   # same thing, shorter\n```\n\n`call` goes through the same handler, the same argument validation and the same confirm/spend gates the MCP\nserver uses — there is no second implementation to drift. `tools` and `tools <name>` read a registry bundled in\nthe package, so they need no key, no network and no sign-in.\n\n## 3. Claude skills — slash commands that wrap the CLI\n\n`skills/` holds four installable skills: `hermoso-generate`, `hermoso-ad-from-brand`,\n`hermoso-product-photoshoot`, `hermoso-research`.\n\n```bash\ncp -r skills/* ~/.claude/skills/\n```\n\nThen invoke `/hermoso-ad-from-brand an ad for yourbrand.com — our hero product`.\n\n## Configuration\n\n| Env | Meaning |\n| --- | --- |\n| `HERMOSO_API_BASE` | The Hermoso API origin (default `https://app.hermoso.ai` — set `http://localhost:3000` if you run the app yourself) |\n| `HERMOSO_TOKEN` | Bearer agent key (`hmk_…`) — required against the hosted app |\n| `HERMOSO_PROFILE` | Brand-workspace id, for accounts with multiple brand profiles |\n| `HERMOSO_OWNER` | Only for a brand **another account shared with you** (a team workspace): the owning account id. Set it together with `HERMOSO_PROFILE`, and set `HERMOSO_PROFILE` to that workspace's **profileUuid** — a brand's short slug is refused. Run `list_brands` (or `hermoso list_brands` from the CLI) to print both values for every workspace you can enter. The server re-authorizes the pair on every request, so a wrong value is refused, never trusted. |\n\n`mcp/http.mjs` is the hosted remote-connector transport (paste-a-URL into Claude.ai → Connectors). It ships in\nthis repo for transparency and refuses to mount without authenticated identity — no anonymous spend, ever.\n\n## License\n\nMIT © Hermoso\n",
  "bytes": 23245,
  "sha": "4fd1f94f0c84073b57c9228eeebf243d24fbeaa08a6675ae3aef3cd83e2fd7fe",
  "repo_slug": "hermoso-ai/hermoso",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_hermoso_ai_hermoso_ca7f33a2/readme"
}