roasr-mcp
Official# roasr-mcp
<!-- mcp-name: io.github.RoASr-com/roasr-mcp -->
**English · [Русский](README.ru.md)**
**MCP server for [RoASr](https://roasr.com)** — connect **Claude, ChatGPT, Codex, Cursor, or any MCP-compatible client** to your RoASr ad-analytics workspace: **Meta, Google Ads and Yandex Direct** ad-audit findings, KPI summaries, competitor spy and Vision creative analysis. A thin, **dependency-free** client over the public `/v1` REST API.
> Auth is by your `pg_live_…` API key; workspace isolation and scopes are enforced API-side. The server is stateless, and read-only apart from one Yandex Direct campaign pause/resume tool that works solely inside permissions you granted.
---
## Quick start
### 1. Get an API key
Sign in at **https://roasr.com → Settings → API keys** → create a `pg_live_…` key with the scopes you need (shown once).
### 2. Connect — pick one
**A. Remote connector — no install** (Claude.ai web, ChatGPT, Codex, or any HTTP/streamable-http MCP client):
```
URL: https://roasr.com/api/mcp
Auth: Bearer pg_live_…
```
The tool catalog at that URL is public (any client can list the tools without a key); every actual tool call requires the `Authorization: Bearer pg_live_…` header — the API key scopes the call to your workspace. Most MCP-capable clients (Claude.ai, ChatGPT connectors, Codex) accept this URL + bearer token directly in their "add remote MCP server" UI, no local process needed.
**B. Local via npx** (Claude Desktop, Cursor, Claude Code) — add to your MCP config:
```json
{
"mcpServers": {
"roasr": {
"command": "npx",
"args": ["-y", "roasr-mcp"],
"env": {
"ROASR_API_KEY": "pg_live_…",
"ROASR_BASE_URL": "https://roasr.com"
}
}
}
}
```
> Until the npm package is published, use `"args": ["-y", "github:RoASr-com/roasr-mcp"]`.
**C. From source:**
```bash
git clone https://github.com/RoASr-com/roasr-mcp && cd roasr-mcp
npm install && npm run build
ROASR_API_KEY=pg_live_… node dist/index.js
```
---
## Tools
| Tool | Description | Endpoint · scope |
|---|---|---|
| `roasr_list_findings` | AI-audit findings by priority (optional client filter) | `GET /v1/findings` · `findings:read` |
| `roasr_metrics_summary` | Ad KPI summary over a date window (spend, impressions, clicks, conversions, revenue, CTR, CPC, CPM, ROAS, CPA, reach, frequency). Optional `entityRef` scopes to one campaign/adset | `GET /v1/metrics/summary` · `metrics:read` |
| `roasr_metrics_daily` | Daily metric time series over a date window (incl. reach/frequency) — for trends and charts. Optional `entityRef` scopes to one campaign/adset | `GET /v1/metrics/daily` · `metrics:read` |
| `roasr_metrics_breakdown` | Metric breakdown by dimension (`audience` / `placement` / `platform` / `country` / `region` / `device` / `dma` / `hourly`), segments as of the latest snapshot date in the window | `GET /v1/metrics/breakdowns` · `metrics:read` |
| `roasr_metrics_campaigns` | Per-campaign/adset metrics and KPIs over a date window (spend, CTR, CPC, ROAS, CPA, reach, frequency…), sorted by spend | `GET /v1/metrics/campaigns` · `metrics:read` |
| `roasr_metrics_actions` | Conversion breakdown by action type over a date window: `actions` (raw action-type → sum map) + `buckets` (canonical: purchase, lead, add_to_cart, complete_registration, landing_page_view, engagement…) | `GET /v1/metrics/actions` · `metrics:read` |
| `roasr_list_clients` | Workspace clients with context | `GET /v1/clients` · `clients:read` |
| `roasr_spy_tag_leaderboard` | Competitor creative tag leaderboard (days_live ≈ winner) | `GET /v1/spy/tags` · `spy:read` |
| `roasr_spy_search` | Search stored competitor creatives (hook / headline / tags / brand) | `GET /v1/spy/search` · `spy:read` |
| `roasr_vision_analyze` | Vision breakdown of a creative by `ad_archive_id` (hook / angle / risks + transcript) | `GET /v1/vision/analyze` · `spy:read` |
| `roasr_signals` | Rich platform signals by `kind` (required — one of 16 `SIGNAL_KINDS`: search terms, keyword quality score, impression share, auction insights, conversion actions, asset performance, landing pages, shopping, video funnel, bidding, asset groups, Meta ad quality + the four Yandex Direct kinds). Per-account latest snapshot in the window, response capped by `limit` | `GET /v1/signals` · `metrics:read` |
| `roasr_yandex_search_queries` | **Direct only.** Search queries for a window: text, campaign/ad group, match type, impressions, clicks, spend, conversions. The strongest Direct signal — sizes the share of spend on queries with zero conversions | `GET /v1/signals` · `metrics:read` |
| `roasr_yandex_ads` | **Direct only.** Ads with moderation state and metrics: `state`/`status`/`statusClarification`, second headline, sitelinks, UTM markup, image, turbo page | `GET /v1/signals` · `metrics:read` |
| `roasr_yandex_goals` | **Direct only.** Which Yandex.Metrika goals the account's conversions are counted against. No date window — current config. Empty goals ⇒ conversions cannot be attributed | `GET /v1/yandex/goals` · `metrics:read` |
| `roasr_yandex_breakdown` | **Direct only.** One call for the four Direct kinds by `dimension`: `search_queries` \| `keywords` \| `ads` \| `bidding` | `GET /v1/signals` · `metrics:read` |
| `roasr_limits` | Plan limits and the remaining daily Yandex API unit quota (Direct meters per login; its Reports endpoint hides its own consumption) | `GET /v1/limits` · `metrics:read` |
| `roasr_campaign_set_state` | **The one write tool.** Pauses/resumes a live Direct campaign, only within permissions the account owner granted for that key. Idempotent by `idempotencyKey` | `POST /v1/campaigns/state` · `campaigns:write` |
| `roasr_command_get` | Status and attempt history of a write command — resolves one left in `verifying`/`unknown` | `GET /v1/commands/{id}` · `campaigns:read` |
> `roasr_metrics_summary` / `roasr_metrics_daily` / `roasr_metrics_breakdown` / `roasr_metrics_campaigns` / `roasr_metrics_actions` / `roasr_signals` share the same date-window params: `since`/`until` (YYYY-MM-DD, `since` takes priority) or `sinceDays` (1–365, default 30), plus optional `accountId`/`clientId` filters. `roasr_metrics_breakdown` also requires `dimension` and accepts `limit` (1–200, default 50). `roasr_metrics_campaigns` accepts `level` (`campaign` default, or `adset`) and `limit` (1–200, default 50); its response includes `dataSince` — the earliest date entity-level data has been collected since. `roasr_metrics_summary`/`roasr_metrics_daily` accept an optional `entityRef` (`campaign:<id>` | `adset:<id>`) to scope to one entity instead of the whole workspace. `roasr_signals` requires `kind` and accepts `limit` (1–200, default 50); its response includes `asOf` (per-account latest). `reach`/`frequency` (summary/daily/breakdown) are Meta-only — `null` for older data or non-Meta accounts; `reach` is a sum of daily reach (not de-duplicated), `frequency` is always the derived `impressions/reach`. Action buckets are not additive — `engagement` is an aggregate of `reactions`/`comments`/`shares`, don't sum them together.
> Spy (`spy_search` + `vision_analyze`) is the edge — your AI gets data that lives nowhere else. Ad Library scans and Vision analysis (LLM/credits) run **inside the RoASr app**; this server returns the already-stored result.
---
## Configuration
| Env | Required | Default |
|---|---|---|
| `ROASR_API_KEY` | ✅ | — (server exits with an actionable error if missing) |
| `ROASR_BASE_URL` | — | `https://roasr.com` |
---
## Development
```bash
npm install # installs devDeps + builds dist/ (prepare hook)
npm run build # tsc → dist/index.js (executable bin, shebang)
npm run dev # tsx src/index.ts
```
Layout: `src/index.ts` (entry, env validation, fail-loud) · `src/protocol.ts` (dependency-free JSON-RPC 2.0 stdio + `runMcpServer`/`ToolDef`) · `src/client.ts` (`RoasrClient`, Bearer auth, error-envelope unwrap) · `src/tools.ts` (`buildTools` → 18 tools).
> Unit tests (vitest, fake client, no network) live in the RoASr monorepo, which is the source of
> truth for `src/` — this repository is its published mirror.
---
## Agent skills
Tool schemas tell an agent *what it can call*; these tell it *how to reason*. Drop the folder into
your agent's skills directory (Claude Code: `.claude/skills/`), or just paste the file into context.
| Skill | For |
|---|---|
| [`SKILL.md`](SKILL.md) | The cross-platform working method: order of analysis, per-platform gotchas, ready workflows, safety rules for the write tool |
| [`skills/yandex-direct`](skills/yandex-direct/SKILL.md) | Yandex Direct in depth — goal selection before any conversion number, archived campaigns, `State` vs `Status`, micro-units, the daily unit quota |
| [`skills/hermes`](skills/hermes/SKILL.md) | Driving RoASr from Hermes (remote HTTP MCP) |
| [`skills/openclaw`](skills/openclaw/SKILL.md) | Driving RoASr from OpenClaw (remote HTTP **or** local stdio) |
---
## Notes / invariants
- **stdout is protocol-only** — all logs go to `stderr` (a stray `console.log` breaks JSON-RPC).
- **Fail-loud** — missing `ROASR_API_KEY` → actionable stderr message + `exit(1)`.
- **Tool errors** surface as `{ isError: true }` (MCP convention), so the client can recover.
- **Read-only except `roasr_campaign_set_state`** — that one pauses/resumes a live Yandex Direct campaign, and only inside the permissions the account owner granted for that key. Scopes are enforced API-side.
- **Vision / Ad-Library results are pre-computed** in the app — `vision_analyze` returns a stored breakdown.
---
## License
[MIT](LICENSE) © 2026 SmartFlow LLC — [roasr.com](https://roasr.com)
TDQS
Scored across 18 tools
Most tools have clearly distinct purposes: metrics tools are separated by granularity (summary, daily, breakdown, campaigns, actions), and spy/vision tools are differentiated. The only overlap is roasr_yandex_breakdown duplicating data from roasr_yandex_search_queries and roasr_yandex_ads, but the descriptions explicitly clarify when to use which, minimizing misselection.
All tools share the roasr_ prefix and follow snake_case naming. The pattern is not strictly verb_noun (e.g., roasr_metrics_summary is a noun phrase), but it is consistent across domains: roasr_metrics_*, roasr_spy_*, roasr_yandex_*, roasr_campaign_set_state, and roasr_command_get follow a predictable structure.
18 tools is slightly above the typical 15 but appropriate for the server's broad scope: ad analytics, competitor intelligence, vision analysis, Yandex account management, and subscription limits. Each tool serves a distinct purpose and the count is not overwhelming for the feature set.
The tool surface covers core read-only analytics (metrics, findings, signals), competitor research (spy search, vision), and a limited write capability (pause/resume campaigns) with proper command status tracking. Minor gaps exist, such as no campaign creation or update tools, but the server appears focused on analysis and optimization rather than full campaign management, so the coverage is largely complete.