> **Building with AI coding agents?** Install the authstack plugin with one command. This equips your agent with accurate Scalekit implementation patterns.
>
> **Recommended** (the `-y` flags skip prompts, so the command runs without an interactive terminal):
> ```bash
> npx -y @scalekit-inc/cli setup -y
> ```
>
> Global:
> ```bash
> npm install -g @scalekit-inc/cli
> scalekit setup -y
> ```
>
> Supports Claude Code, Cursor, GitHub Copilot, Codex + skills for other Agent Skills-compatible agents in `~/.agents/skills`.
> Skills: integrate-agentkit, implement-saaskit, add-mcp-oauth, implement-sso, implement-scim.
> [Full setup guide](https://docs.scalekit.com/dev-kit/build-with-ai/)

---

# Connect AI agents to the OpenRush MCP server

The OpenRush MCP connector routes your AI agent's tool calls to OpenRush's own MCP server through Scalekit. Each user signs in to OpenRush once, and Scalekit stores and refreshes their tokens, so your agent never handles credentials. It comes with 20 tools.

**Authentication:** OAuth 2.1/DCR
**Categories:** Marketing, Analytics
**Tools:** 20: 20 read, 0 write, 0 destructive
**Users sign in with:** OAuth
**OAuth app:** Your own OpenRush MCP server app
**Built by:** Vendor MCP
**Try it:** [Playground in the Scalekit dashboard](https://app.scalekit.com/ws/signup?sk_intent=playground&provider=OPENRUSHMCP)

## Setup

1. ### Install the SDK

   **Node.js**

   ```bash
   npm install @scalekit-sdk/node dotenv
   ```

   **Python**

   ```bash
   pip install scalekit-sdk-python python-dotenv
   ```

2. ### Set your credentials

   Add your Scalekit credentials to your `.env` file. Find values in **[app.scalekit.com](https://app.scalekit.com)** > **Developers** > **API Credentials**.

   ```sh title=".env"
   SCALEKIT_ENVIRONMENT_URL=<your-environment-url>
   SCALEKIT_CLIENT_ID=<your-client-id>
   SCALEKIT_CLIENT_SECRET=<your-client-secret>
   ```

3. ### Create the OpenRush MCP connection

   In **AgentKit > Connections**, create an OpenRush MCP connection and copy its redirect URI. The name you give it is the `connection_name` your code passes. See [Configure connections](/agentkit/connections/).

4. ### Register an OAuth app

   OpenRush MCP server connections use your own OAuth app. Register one with OpenRush MCP server and add the redirect URI you copied.

   Then enter the app's Client ID and Client Secret on the OpenRush MCP connection.

5. ### Authorize a user and make your first call

   **Node.js** (`quickstart.mts`)

   ```typescript
   import { ScalekitClient } from '@scalekit-sdk/node'
   import 'dotenv/config'
   import { createInterface } from 'node:readline/promises'

   const scalekit = new ScalekitClient(
     process.env.SCALEKIT_ENVIRONMENT_URL,
     process.env.SCALEKIT_CLIENT_ID,
     process.env.SCALEKIT_CLIENT_SECRET,
   )
   const actions = scalekit.actions

   const connector = 'openrushmcp'
   const identifier = 'user_123'

   // Generate an authorization link for the user
   const { link } = await actions.getAuthorizationLink({ connectionName: connector, identifier })
   console.log('Authorize OpenRush MCP:', link)
   const rl = createInterface({ input: process.stdin, output: process.stdout })
   await rl.question('Press Enter after authorizing...')
   rl.close()

   // Make your first call
   const result = await actions.executeTool({
     connector,
     identifier,
     toolName: 'openrushmcp_describe_capabilities',
     toolInput: {},
   })
   console.log(result)
   ```

   ```bash
   npx tsx quickstart.mts
   ```

   **Python** (`quickstart.py`)

   ```python
   import os
   from scalekit import ScalekitClient
   from dotenv import load_dotenv
   load_dotenv()

   scalekit_client = ScalekitClient(
       env_url=os.getenv("SCALEKIT_ENVIRONMENT_URL"),
       client_id=os.getenv("SCALEKIT_CLIENT_ID"),
       client_secret=os.getenv("SCALEKIT_CLIENT_SECRET"),
   )
   actions = scalekit_client.actions

   connection_name = "openrushmcp"
   identifier = "user_123"

   # Generate an authorization link for the user
   link_response = actions.get_authorization_link(
       connection_name=connection_name,
       identifier=identifier,
   )
   print("Authorize OpenRush MCP:", link_response.link)
   input("Press Enter after authorizing...")

   # Make your first call
   result = actions.execute_tool(
       tool_input={},
       tool_name="openrushmcp_describe_capabilities",
       connection_name=connection_name,
       identifier=identifier,
   )
   print(result)
   ```

   ```bash
   python quickstart.py
   ```

   Each user signs in once. See [Authorize a user](/agentkit/tools/authorize/) for the full flow and statuses.

## Tools

Pass the exact name to `execute_tool`, with an input like each tool's example. To ask for a tool that's missing, use the [request form](https://scalekitsupport.portal.usepylon.com/forms/request-a-connector-tool).

**Node.js**

```typescript
const result = await actions.executeTool({
  toolName: 'openrushmcp_audit_site',
  toolInput: {
    domain: '<domain>',
  },
  connector: 'openrushmcp',
  identifier: 'user_123',
})
```

**Python**

```python
result = actions.execute_tool(
    tool_name="openrushmcp_audit_site",
    tool_input={
        "domain": "<domain>",
    },
    connection_name="openrushmcp",
    identifier="user_123",
)
```

`result.data` is the app's response as JSON, and `result.execution_id` (`executionId` in Node.js) is the ID of the call.

### `openrushmcp_audit_site`

Audit Site · Read-only

Fast, opinionated technical / content health audit across a sampled set of
a domain's pages, tuned for organic-search signal over noise.

Discovers URLs from the sitemap/robots (or a homepage link-crawl fallback),
then samples one representative per URL template BY VALUE: money/content
pages first, while enumerated low-value sections (e.g. a jobs board or event
listings) get a single spot-check rather than eating the budget. Fetches the
sample concurrently, then GATES OUT non-indexable pages — anything
intentionally `noindex` (on a low-value page) or canonicalized to another URL
is excluded from scoring instead of being reported as a problem (a noindexed
job listing is working as intended). Returns: grouped `issue_clusters`
(issue + severity + affected page count + which page roles + a fix), a ranked
`recommendations` list weighted by the *value* of the pages affected, an
`onpage_score`, and cross-page duplicate-title/description checks. Full
per-page rows — including excluded pages and why — are linked via `resources`
(fetch with export_dataset). Runs in seconds.

- `max_pages` (default 10, max 20): how many sampled pages to audit.

Key fields: `page_class_summary` (sampled pages by role: core/content/
utility/ephemeral), `pages_excluded` + `excluded_summary` (non-indexable
pages skipped, by reason), and `worst_page` (the highest-value page with the
most issues — the best drill-down target). Each cluster/recommendation
carries `page_classes` so you can tell whether a finding hits money pages or
just utility ones.

Scope: this reads each page's raw HTML — it does NOT execute JavaScript or
measure Core Web Vitals. `render_warning: true` means ≥1 audited page looks
client-rendered (its raw HTML is near-empty), so its content checks are
low-confidence. Also read `coverage` (audited vs discovered),
`discovery_source` (a `homepage_fallback` means no sitemap was found), and
`fetch_failures` (pages that didn't respond in time). To confirm which
findings hit pages that actually earn search traffic, follow the
`inspect_domain` / `inspect_page` next_actions.

Read only: yes. Destructive: no. Idempotent (safe to retry): no.

Inputs:

- `domain` (`string`, required): The site to audit: "example.com", or a subdomain host to audit that property alone. A URL or www. prefix is normalized; must be a public host.
- `max_pages` (`integer`, optional): How many sampled pages to audit (1-20). Default: `10`.

Example input: `{"domain":"<domain>"}`

### `openrushmcp_compare_backlink_gap`

Backlink Gap · Read-only

THE backlink gap / link intersect, done server-side in ONE call:
referring domains that link to several of a client's competitors,
ranked by how many competitors link them, spam- and authority-filtered,
with the ones the client already earned flagged.

This replaces the hand-run recipe (pull each competitor's referring
domains, union thousands of rows, dedupe against the client, enrich for
true authority, filter, sort) — all of which used to run in the agent's
context. Here it is one call and a compact, report-ready result.

How it works: ranks the competitors by true authority, fans out
referring-domain pulls to the strongest of them (the top-N recover
essentially the full intersect), unions and counts the overlap, attaches
TRUE domain authority + spam via the bulk endpoint (the row-level rank on
a referring row is page-level and must not be trusted), drops spam ≥
`max_spam` and authority < `min_authority`, flags each row `earned`
(client already links from it) or a fresh gap, and sorts by
(competitor_count desc, authority desc). Fan-out and per-competitor depth
are handled for you — there are no knobs for them.

Read `data.summary` for the funnel (union → candidates → after-filter →
gap/earned) and per-competitor coverage, and `coverage.scope_note` for
what was and wasn't covered. `data.gap` holds the top `limit` rows;
`resources` holds the FULL ranked list — fetch it with export_dataset,
don't re-run per-competitor pulls. A short list is a good result: if the
client already owns the strong domains, that shows up as earned=true, not
as junk padding.

First get a real competitor set from discover_competitors (seed_keywords
mode for a specific vertical); passing domain-similarity giants produces
a meaningless gap.

Read only: yes. Destructive: no. Idempotent (safe to retry): no.

Inputs:

- `competitors` (`array`, required): The competitor domains to measure the gap against.
- `domain` (`string`, required): The client's domain — the site the gap is measured FOR. Domains it already links from are flagged earned=true rather than re-pitched.
- `include_earned` (`boolean`, optional): Keep domains the client already links from, flagged earned=true (so a report can say 'already earned' instead of re-pitching them). Set false for the pure 'what's left to earn' list. Default: `true`.
- `limit` (`integer`, optional): How many top rows to return inline as facts / data.gap. The FULL ranked set is always in resources (export_dataset). Default: `50`.
- `max_spam` (`integer`, optional): Drop referring domains at/above this spam score (0-100). Default: `30`.
- `min_authority` (`integer`, optional): Drop referring domains below this TRUE domain authority (0-1000 scale). Set 0 to keep every domain regardless of strength. Default: `100`.
- `min_competitors` (`integer`, optional): A referring domain must link to at least this many competitors to be in the gap. 2 = the classic 'links to several rivals' intersect. Default: `2`.

Example input: `{"competitors":[],"domain":"<domain>"}`

### `openrushmcp_compare_keyword_coverage`

Compare Keyword Coverage · Read-only

Keyword gap analysis: terms one or more competitors (1-10 domains) rank for
that `domain` does not, plus terms where the target is losing ground.

Use after discover_competitors to turn a competitor set into a concrete
content/keyword target list. Results group into intent clusters so the agent
can prioritize. Both target and competitors must be reasonably indexed for
the gap set to be meaningful — see `coverage`.

Read only: yes. Destructive: no. Idempotent (safe to retry): no.

Inputs:

- `competitors` (`array`, required): 1-10 competitor domains to compare against.
- `domain` (`string`, required): The target site whose keyword gaps you want. A bare domain covers all its subdomains; pass a subdomain to narrow to that property.
- `language` (`string`, optional): Result language ("English", "Spanish"). Default: `English`.
- `limit` (`integer`, optional): How many gap keywords to return. Default: `50`.
- `location` (`string`, optional): Target market as a COUNTRY name ("United States", "Mexico"); sub-country values are rejected. Defaults to the United States.

Example input: `{"competitors":[],"domain":"<domain>"}`

### `openrushmcp_describe_capabilities`

Describe Capabilities · Read-only

START HERE. List the live OpenRush surface: enabled data domains, the
tools in each, the fact types every tool can emit, which sources back them
(live SERP, search index, backlinks, owned Search Console/Analytics/Ads),
and which tools need an owned-data connection.

Use this to discover what's available before assuming a tool exists.
Returns the standard OFE envelope; the tool list is in `data.tools`.

Read only: yes. Destructive: no. Idempotent (safe to retry): no.

Inputs: none.

Example input: `{}`

### `openrushmcp_discover_ai_citations`

Discover AI Citations · Read-only

Which domains AI cites on a category — the map of where to earn a
mention, and who AI cites instead of you. Provide `topic` (a real category
keyword) or `domain`, and if both are given `topic` wins.

Prefer `topic` whenever you know the brand's real category: pass the
category as `topic` (and the brand as `domain` if you also want its
standing). Fall back to `domain` alone only when the category is unknown —
the tool then derives it from the domain's top ranking keywords, which is
reliable for an established site but can pick a tangential term for a thin
or new site that barely ranks (e.g. a website-migration brand whose top
keyword is "migrate ai", an AI/cloud term). When that happens the result
is labeled `data.category_confidence: "derived_weak"` and carries a
next-action asking you to supply the real category as `topic`; re-run with
an explicit `topic` for an accurate map.

Coverage is Google AI Overview only (the deep, independently validated
surface); this does NOT cover ChatGPT, Claude, Gemini, Perplexity, or
CoPilot. The metric is "this domain cited as a source", not "brand
discussed". Results are domain-anchored, never brand-name matched. A
scattered or tagline-like input returns a low-signal `data_freshness`
note instead of junk rows, and "AI search volume" is never surfaced.
Use this even when a brand has zero AI presence: it shows where its
category is cited so it knows where to earn placement. `next_actions`
point to inspect_ai_visibility to see where a domain stands among these
sources.

Read only: yes. Destructive: no. Idempotent (safe to retry): no.

Inputs:

- `domain` (`string`, optional): The brand's domain, used alone to derive the category from its top ranking keywords. One of `topic` / `domain` is required.
- `language` (`string`, optional): Result language ("English", "Spanish"). Default: `English`.
- `limit` (`integer`, optional): How many citing domains to return. Default: `20`.
- `location` (`string`, optional): Target market as a COUNTRY name ("United States", "Mexico"); sub-country values are rejected. Defaults to the United States.
- `topic` (`string`, optional): The category to map, as a real category keyword ("website migration services") — not a tagline or brand name. Preferred input, and wins if `domain` is also given. One of `topic` / `domain` is required.

Example input: `{}`

### `openrushmcp_discover_competitors`

Discover Competitors · Read-only

Find organic competitors. Provide exactly one of `domain` or `seed_keywords`.

- domain mode: competitors by keyword overlap with the target's indexed set.
  Broad, but unreliable for new/small sites because the search index
  lags the live SERP — the response flags this with a `data_freshness` fact.
- seed_keywords mode (1-20 queries): aggregates who consistently ranks across
  those queries by hitting the live SERP database directly. Needs the SEEDS
  indexed in that market, not the target — returns empty, with a reason, when
  they are not. Prefer it when domain mode came back thin; read `coverage`.

Read only: yes. Destructive: no. Idempotent (safe to retry): no.

Inputs:

- `domain` (`string`, optional): domain mode: the site to find competitors for. Pass this or `seed_keywords`; if both are given `seed_keywords` wins and this is ignored.
- `language` (`string`, optional): Result language ("English", "Spanish"). Default: `English`.
- `limit` (`integer`, optional): How many competitor domains to return. Default: `10`.
- `location` (`string`, optional): Target market as a COUNTRY name ("United States", "Mexico"); sub-country values are rejected. Defaults to the United States.
- `seed_keywords` (`array`, optional): seed_keywords mode: 1-20 real search queries to find who consistently ranks across them (e.g. ["crm software", "sales pipeline tool"]). A list of strings, not a JSON-encoded string. Takes precedence over `domain`.

Example input: `{}`

### `openrushmcp_export_dataset`

Export Dataset · Read-only

Fetch the full rows behind a dataset `uri` that another tool returned in its
`resources` block (results too large to inline). Pass the uri verbatim; do not
construct one yourself.

Datasets are retained for a limited window and may be dropped sooner under
load, so a valid uri can come back empty. That is not an error: when it
happens the response has `data.available = false` with a `note`, and
`next_actions` contains the tool to re-run to regenerate the dataset.
Follow that action, then export the fresh uri from the new `resources` block.

Read only: yes. Destructive: no. Idempotent (safe to retry): no.

Inputs:

- `uri` (`string`, required): A dataset uri from another tool's `resources` block.

Example input: `{"uri":"<uri>"}`

### `openrushmcp_get_ad_performance`

Get Ad Performance · Read-only

Measured, normalized ad performance (spend, impressions, clicks, CTR,
CPC, CPM, conversions, conversion value, cost/conversion, conversion
rate, ROAS) for one of the user's OWN connected ad accounts — Google Ads
today, more ad platforms later — straight from the platform, not a
modeled estimate. THE single tool for every ad platform: ask once, and
OpenRush handles which platforms are connected.

`platform` and `ad_account` are optional: omit both and the single
connected platform + activated account are auto-selected. Several
connected platforms return `platform_required`; several activated
accounts return `account_required`; nothing connected/activated returns
`connection_required` (set up in the dashboard). One platform per call —
`next_actions` point to any other connected platform and to deeper slices.

- `report`: overview (default: account totals + top campaigns + daily
  trend + Google network split) | campaign | ad_group | asset_group |
  ad | date | device | network | keyword | search_term (the last three
  Google-only). Use asset_group for Performance Max campaigns — they
  have no ad_group/ad rows; their creative unit is the asset group.
  Every other type (Search, Shopping, Demand Gen, Video, Display) has
  ad groups and ads. next_actions route to the right drilldown per
  campaign type, and to both on a mixed account.
- `group_by`: the lower-level equivalent of `report` (one dimension)
- `period`: last_7_days | last_28_days (default) | last_3_months |
  last_6_months | last_12_months
- `compare_to`: previous_period (default) | previous_year | none

Every monetary value carries its currency and is NEVER converted; every
conversion/ROAS number carries its attribution basis. Windows are in the
account's own time zone; the most recent ~1-2 days are preliminary. Ad
clicks are PAID clicks — not GA4 sessions and not Search Console clicks.
Read-only: no campaign, budget, or bid changes.

Read only: yes. Destructive: no. Idempotent (safe to retry): no.

Inputs:

- `ad_account` (`string`, optional): An OpenRush ad-account id, from list_connections (`data.ad_accounts[].ad_account`) or an `account_required` error's `data.options`. NOT a raw Google customer id. Omit it to auto-select the single activated account; never invent one.
- `compare_to` (`string`, optional): Comparison baseline: previous_period | previous_year | none. One of: `previous_period`, `previous_year`, `none`. Default: `previous_period`.
- `filters` (`array`, optional): Up to 10 filters, each {dimension, operator, expression}. dimension: campaign | device | network. operator: equals | contains for campaign (matched on the campaign name); equals only for device and network. device values: mobile | desktop | tablet | connected_tv | other. network values: search | search_partners | display | youtube | youtube_search | mixed.
- `group_by` (`array`, optional): One dimension, any `report` token except overview. Overrides `report` when given — use `report` unless you are mapping a raw dimension name.
- `limit` (`integer`, optional): Maximum rows for a single-slice report (1-1000). Defaults to 100. Default: `100`.
- `period` (`string`, optional): Reporting window in the account's own time zone: last_7_days | last_28_days | last_3_months | last_6_months | last_12_months. One of: `last_7_days`, `last_28_days`, `last_3_months`, `last_6_months`, `last_12_months`. Default: `last_28_days`.
- `platform` (`string`, optional): Ad platform: google_ads. Omit it to auto-select when one platform is connected; a `platform_required` error lists the choices in `data.options`.
- `report` (`string`, optional): Prebuilt slice: overview (default: account totals + top campaigns + daily trend + Google network split) | campaign | ad_group | asset_group | ad | date | device | network | keyword | search_term (the last three are Google-only). Use asset_group for Performance Max campaigns, which have asset groups instead of ad groups and ads; every other campaign type (Search, Shopping, Demand Gen, Video, Display) drills into ad_group and ad. One of: `overview`, `campaign`, `ad_group`, `asset_group`, `ad`, `date`, `device`, `network`, `keyword`, `search_term`. Default: `overview`.

Example input: `{}`

### `openrushmcp_get_search_performance`

Get Search Performance · Read-only

Measured Google Search performance (clicks, impressions, CTR,
impression-weighted position) for one of the user's OWN websites,
straight from their connected Search Console — not a modeled estimate.

`website_id` and `domain` are optional, interchangeable selectors:
omit both and the single connected website is auto-selected. If the
account has several connected websites the call returns a
`website_required` error listing safe options in `data.options` —
retry with one `website_id`. If nothing is connected yet it returns
`connection_required`/`binding_required` (set up in the dashboard).

- `period`: last_7_days | last_28_days (default) | last_3_months |
  last_6_months | last_12_months | last_16_months
- `compare_to`: previous_period (default) | previous_year | none
- `group_by`: any of page | query | date | device | country (omit for
  the site total; page + query is allowed but bounded)
- `search_type`: web (default) | image | video | news | discover
The most recent ~3 days are labeled preliminary; GSC reports search
performance, which is not the same as total website traffic.

Read only: yes. Destructive: no. Idempotent (safe to retry): no.

Inputs:

- `compare_to` (`string`, optional): Comparison baseline: previous_period | previous_year | none. One of: `previous_period`, `previous_year`, `none`. Default: `previous_period`.
- `domain` (`string`, optional): Alternative to `website_id`: the domain of one of the user's OWN connected websites. Not a way to query a site they have not connected.
- `filters` (`array`, optional): Up to 10 filters, each {dimension, operator, expression}. dimension: query | page | country | device | searchAppearance. operator: equals | notEquals | contains | notContains | includingRegex | excludingRegex (note these differ from the analytics operators).
- `group_by` (`array`, optional): Breakdown dimensions: page | query | date | device | country. Two are accepted only as page + query. Omit for the site total.
- `limit` (`integer`, optional): Maximum number of rows to return (1-1000). Defaults to 100. Default: `100`.
- `period` (`string`, optional): Reporting window: last_7_days | last_28_days | last_3_months | last_6_months | last_12_months | last_16_months. One of: `last_7_days`, `last_28_days`, `last_3_months`, `last_6_months`, `last_12_months`, `last_16_months`. Default: `last_28_days`.
- `search_type` (`string`, optional): Search surface: web | image | video | news | discover | googleNews. One of: `web`, `image`, `video`, `news`, `discover`, `googleNews`. Default: `web`.
- `website_id` (`string`, optional): An OpenRush website id, from list_connections or a `website_required` error's `data.options`. Omit it and `domain` to auto-select the single connected website; never invent one.

Example input: `{}`

### `openrushmcp_get_website_analytics`

Get Website Analytics · Read-only

Measured website analytics (sessions, users, engaged sessions,
engagement rate, average engagement time, page views, bounce rate) for
one of the user's OWN websites, straight from their connected Google
Analytics (GA4) property — not a modeled estimate.

`website_id` and `domain` are optional, interchangeable selectors: omit
both and the single connected website is auto-selected. If the account
has several connected websites the call returns a `website_required`
error listing safe options in `data.options` — retry with one
`website_id`. If nothing is connected yet it returns
`connection_required`/`binding_required` (set up in the dashboard).

- `report`: overview (default, a rich summary: site totals + top
  channels + top landing pages + a daily trend) | channel |
  source_medium | campaign | landing_page | country | device | date
- `group_by`: the lower-level equivalent of `report` (one dimension)
- `period`: last_7_days | last_28_days (default) | last_3_months |
  last_6_months | last_12_months
- `compare_to`: previous_period (default) | previous_year | none

Windows are computed in the property's own reporting timezone. The most
recent ~1-2 days are labeled preliminary. Sessions are visits, not
users, and are not the same as Search Console clicks. This is the
universal traffic/attribution/engagement tool: it deliberately reports
NO conversions, revenue, or custom events.

Read only: yes. Destructive: no. Idempotent (safe to retry): no.

Inputs:

- `compare_to` (`string`, optional): Comparison baseline: previous_period | previous_year | none. One of: `previous_period`, `previous_year`, `none`. Default: `previous_period`.
- `domain` (`string`, optional): Alternative to `website_id`: the domain of one of the user's OWN connected websites. Not a way to query a site they have not connected.
- `filters` (`array`, optional): Up to 10 filters, each {dimension, operator, expression}. dimension: any `report` token except overview and date, plus content | term. operator: exact | contains | begins_with | ends_with | full_regexp (note these differ from the Search Console operators).
- `group_by` (`array`, optional): One dimension, any `report` token except overview. Overrides `report` when given — use `report` unless you are mapping a raw dimension name.
- `limit` (`integer`, optional): Maximum number of rows to return (1-1000). Defaults to 100. Default: `100`.
- `period` (`string`, optional): Reporting window: last_7_days | last_28_days | last_3_months | last_6_months | last_12_months. One of: `last_7_days`, `last_28_days`, `last_3_months`, `last_6_months`, `last_12_months`. Default: `last_28_days`.
- `report` (`string`, optional): Prebuilt slice: overview (default: site totals + top channels + top landing pages + a daily trend) | channel | source | medium | source_medium | campaign | landing_page | country | city | device | browser | operating_system | date. One of: `overview`, `channel`, `source`, `medium`, `source_medium`, `campaign`, `landing_page`, `country`, `city`, `device`, `browser`, `operating_system`, `date`. Default: `overview`.
- `website_id` (`string`, optional): An OpenRush website id, from list_connections or a `website_required` error's `data.options`. Omit it and `domain` to auto-select the single connected website; never invent one.

Example input: `{}`

### `openrushmcp_inspect_ai_visibility`

Inspect AI Visibility · Read-only

How a domain shows up in AI answers — its citation count, alone or
against named competitor DOMAINS (up to 9), with the gap. Always
domain-anchored: pass domains, never brand names (a brand name matches
thousands of unrelated answers; a domain is an exact entity).

Coverage is Google AI Overview only; this does NOT cover ChatGPT, Claude,
Gemini, Perplexity, or CoPilot. The number is "your domain cited as a
source", not "how often AI talks about you", and it is a sampled corpus
observation, not what any one user sees. AI answers are non-deterministic,
so treat movement as directional.

A zero is a first-class answer, not an error: a domain AI has not cited
yet returns a `brand_mentions` fact with `mentions: 0` plus a
`next_actions` pointer to discover_ai_citations (where to earn a mention).
Comparing more competitors costs no more — they are batched into one call.

Call it solo (no competitors) to also get `data.sample_answers` — real
questions where the domain is cited, with the sources cited alongside it.
With competitors you get the ranked comparison and share-of-citations
gap instead (no sample answers).

Read only: yes. Destructive: no. Idempotent (safe to retry): no.

Inputs:

- `domain` (`string`, required): The domain to check AI-citation visibility for.
- `competitors` (`array`, optional): Up to 9 competitor DOMAINS. Omit for a solo read, which also returns `data.sample_answers`.
- `language` (`string`, optional): Result language ("English", "Spanish"). Default: `English`.
- `location` (`string`, optional): Target market as a COUNTRY name ("United States", "Mexico"); sub-country values are rejected. Defaults to the United States.

Example input: `{"domain":"<domain>"}`

### `openrushmcp_inspect_backlinks`

Inspect Backlinks · Read-only

One domain's link profile, deep. Lean per `view`: ask for only the
slices you need. `view` is any subset of (default is just `authority`):

- "authority": the headline summary — domain_rank (0-1000, higher =
  stronger), referring-domain count, total backlinks, dofollow ratio,
  spam score. The cheap call for judging how established a site is.
- "referring_domains": a deep, paginated list of the domains that link
  to the target. Its row-level rank is PAGE-level, not true domain
  authority, so don't rank or filter on it directly. Use `limit` (up to
  1000) and `offset` to page. For a competitor link-gap, don't page and
  union these lists yourself — call compare_backlink_gap, which does the
  union/rank/filter server-side.
- "anchors": the anchor-text distribution.
- "backlinks": individual links (from-url, anchor, dofollow, first_seen,
  lost_date). Use `status="lost"` to find lost links to reclaim, and the
  full list for disavow review. Set `domain_from` to a single source
  domain to see exactly where and how it links to the target (source-page
  URL + anchor) — the drill-down after a compare_backlink_gap row.

`status` ("live" default | "lost" | "new") and `since` (ISO date; only
links new/lost on/after it) apply to the referring_domains and backlinks
views for velocity and reclaim work. Backed by the cross-engine backlinks
index, so this works even when the organic search-index tools are thin.
For a competitor link-gap, `next_actions` point at compare_backlink_gap
(server-side join), not a hand-run union.

Read only: yes. Destructive: no. Idempotent (safe to retry): no.

Inputs:

- `domain` (`string`, required): The domain whose backlink profile to inspect.
- `domain_from` (`string`, optional): backlinks view only: return just the links coming FROM this source domain (e.g. the referring domain from a compare_backlink_gap row), so one call yields their exact source-page URLs and anchor text instead of paging the target's full inbound set. Ignored by the other views.
- `limit` (`integer`, optional): Rows per list view (referring_domains / anchors / backlinks). Max 1000; the vendor prices per call not per row, so pull deep. Default: `100`.
- `offset` (`integer`, optional): Row offset for paging a deep list view. Default: `0`.
- `since` (`string`, optional): ISO date (e.g. '2025-01-01'). Limits the referring_domains and backlinks views to links new or lost on/after it.
- `status` (`string`, optional): Link state for the referring_domains and backlinks views: live (default) | lost (for reclaim) | new. One of: `live`, `lost`, `new`. Default: `live`.
- `view` (`array`, optional): Which slices to return; each is one vendor call. Any subset of authority | referring_domains | anchors | backlinks. Defaults to ['authority'].

Example input: `{"domain":"<domain>"}`

### `openrushmcp_inspect_domain`

Inspect Domain · Read-only

Starting map for any domain: top organic keywords, top pages, estimated
traffic, dominant search intents, and likely competitors in one call.

Use this first when handed a bare domain. The `next_actions` typically point
to inspect_page (for a winning URL), research_keywords (around a theme), or
discover_competitors. Backed by the search index, so a brand-new or
barely-indexed domain may return thin `data` — check `coverage` before
concluding a site ranks for nothing. If `data.result_status` is `partial`,
check `data.section_status`: unavailable sections are unknown, not empty.

Read only: yes. Destructive: no. Idempotent (safe to retry): no.

Inputs:

- `domain` (`string`, required): The site to map: "example.com", or a named subdomain ("news.example.com") to scope to that property alone. A URL or www. prefix is normalized.
- `language` (`string`, optional): Result language ("English", "Spanish"). Default: `English`.
- `location` (`string`, optional): Target market as a COUNTRY name ("United States", "Mexico"); sub-country values are rejected. Defaults to the United States.

Example input: `{"domain":"<domain>"}`

### `openrushmcp_inspect_keyword`

Inspect Keyword · Read-only

Full detail on a single keyword: monthly volume, CPC, competition level,
intent, 12-month trend, the current top SERP, and which SERP features it
triggers.

Use to validate or deep-dive one term surfaced by research_keywords or a gap
analysis before committing to it.

Read only: yes. Destructive: no. Idempotent (safe to retry): no.

Inputs:

- `keyword` (`string`, required): The keyword to look up full detail for (1-200 characters).
- `language` (`string`, optional): Result language ("English", "Spanish"). Default: `English`.
- `location` (`string`, optional): Target market as a COUNTRY name ("United States", "Mexico"); sub-country values are rejected. Defaults to the United States.

Example input: `{"keyword":"<keyword>"}`

### `openrushmcp_inspect_page`

Inspect Page · Read-only

Full detail on a single page (exact URL): how many organic keywords it
ranks for, estimated monthly traffic, and the top terms driving that traffic.

Use to understand why a specific competitor URL wins, or to profile one of
your own pages surfaced by inspect_domain's top_pages.

Read only: yes. Destructive: no. Idempotent (safe to retry): no.

Inputs:

- `url` (`string`, required): The page URL INCLUDING scheme ("https://example.com/pricing"). Matched exactly against ranking data, so the scheme and path must be the real ones.
- `language` (`string`, optional): Result language ("English", "Spanish"). Default: `English`.
- `location` (`string`, optional): Target market as a COUNTRY name ("United States", "Mexico"); sub-country values are rejected. Defaults to the United States.

Example input: `{"url":"<url>"}`

### `openrushmcp_inspect_search_visibility`

Inspect Search Visibility · Read-only

Where `domain` ranks across a specific keyword set (1-100 keywords), with a
position summary.

mode controls the data backend:
- "auto" (default): search-index lookup, auto-falling back to live SERPs
  when the target is underindexed. Best signal-to-noise for any-size domain.
- "index": search index only. Fastest; reports unranked for new domains.
- "live": one live SERP fetch per keyword — slowest and most expensive
  (one billed query per keyword, capped at 10 per call); always reflects
  today's Google. Use when "auto"/"index" look stale for a new site. Prefer
  "auto", which already falls back to live when the target is underindexed.
This is a point-in-time read of current positions.

Read only: yes. Destructive: no. Idempotent (safe to retry): no.

Inputs:

- `domain` (`string`, required): The site whose positions you want. A named subdomain is scoped as its own property.
- `keywords` (`array`, required): 1-100 keywords to check positions for. Note the live path resolves at most 10 per call; the rest are reported as unchecked in `coverage`.
- `language` (`string`, optional): Result language ("English", "Spanish"). Default: `English`.
- `location` (`string`, optional): Target market as a COUNTRY name ("United States", "Mexico"); sub-country values are rejected. Defaults to the United States.
- `mode` (`string`, optional): Data backend. Prefer "auto"; "live" is billed per keyword and capped at 10. One of: `auto`, `index`, `live`. Default: `auto`.

Example input: `{"domain":"<domain>","keywords":[]}`

### `openrushmcp_inspect_serp`

Inspect SERP · Read-only

Live SERP snapshot for one query: ranked organic results plus which SERP
features are present (AI overview, featured snippet, local pack, paid,
people-also-ask, related searches).

Use to see who actually ranks right now and what the result page looks like
before targeting a query. `depth` (10-100) is how many organic results to
pull; raise it only when you need the long tail. Reflects Google today, not
the index.

Read only: yes. Destructive: no. Idempotent (safe to retry): no.

Inputs:

- `query` (`string`, required): The search query to fetch a live SERP snapshot for (1-200 characters).
- `depth` (`integer`, optional): How many SERP results to pull (10-100). Raise it only when you need the long tail. Default: `10`.
- `language` (`string`, optional): Result language ("English", "Spanish"). Default: `English`.
- `location` (`string`, optional): Target market: a country ("United States") or a full sub-country location ending in its country ("London,England,United Kingdom"). A bare city is rejected. Defaults to the United States when omitted.

Example input: `{"query":"<query>"}`

### `openrushmcp_list_connections`

List Connections · Read-only

List the owned-data this account has connected. Two sibling sections,
because the products are addressed differently:

`data.websites` — the website-addressed products (Search Console, GA4).
Each website reports its per-product state under `connections`:
- `search_console`: connected | reconnect_required | not_connected
- `website_analytics`: connected | reconnect_required | not_connected
`search_console` connected means get_search_performance can return data for
that website; `website_analytics` connected means get_website_analytics can.

`data.ad_accounts` — the account-addressed ad platforms (Google Ads now,
more later). Ads are NOT website-addressed: the ad account is the unit, so
this is a flat list independent of `websites`, each row carrying `platform`,
the opaque `ad_account` id (pass it back to get_ad_performance), `name`,
`currency`, `customer_id_display`, and `connection_status`. Only ACTIVATED
accounts appear — the ones get_ad_performance can actually query. (A website
may separately show an `ad_platform` key under its `connections` only when
the user made the OPTIONAL website↔account association; that key is NOT the
way to tell whether ads are connected — use `data.ad_accounts` for that.)

An account that has connected nothing at all returns EMPTY `websites` and
`ad_accounts` with `data.connection_required: true`. Do not invent a website
or ad account in that case; tell the user a connection is required.

You usually do NOT need to call this first: get_search_performance,
get_website_analytics, and get_ad_performance auto-select when the account
has exactly one eligible target. Call this when the user asks what's
connected, wants to switch target, or an owned-data tool returned a
`website_required` / `account_required` error — then retry that tool with a
`website_id` from `data.websites` or an `ad_account` from `data.ad_accounts`.

Read only: yes. Destructive: no. Idempotent (safe to retry): no.

Inputs: none.

Example input: `{}`

### `openrushmcp_list_websites`

List Websites · Read-only

List the owned-data this account has connected. Two sibling sections,
because the products are addressed differently:

`data.websites` — the website-addressed products (Search Console, GA4).
Each website reports its per-product state under `connections`:
- `search_console`: connected | reconnect_required | not_connected
- `website_analytics`: connected | reconnect_required | not_connected
`search_console` connected means get_search_performance can return data for
that website; `website_analytics` connected means get_website_analytics can.

`data.ad_accounts` — the account-addressed ad platforms (Google Ads now,
more later). Ads are NOT website-addressed: the ad account is the unit, so
this is a flat list independent of `websites`, each row carrying `platform`,
the opaque `ad_account` id (pass it back to get_ad_performance), `name`,
`currency`, `customer_id_display`, and `connection_status`. Only ACTIVATED
accounts appear — the ones get_ad_performance can actually query. (A website
may separately show an `ad_platform` key under its `connections` only when
the user made the OPTIONAL website↔account association; that key is NOT the
way to tell whether ads are connected — use `data.ad_accounts` for that.)

An account that has connected nothing at all returns EMPTY `websites` and
`ad_accounts` with `data.connection_required: true`. Do not invent a website
or ad account in that case; tell the user a connection is required.

You usually do NOT need to call this first: get_search_performance,
get_website_analytics, and get_ad_performance auto-select when the account
has exactly one eligible target. Call this when the user asks what's
connected, wants to switch target, or an owned-data tool returned a
`website_required` / `account_required` error — then retry that tool with a
`website_id` from `data.websites` or an `ad_account` from `data.ad_accounts`.

Read only: yes. Destructive: no. Idempotent (safe to retry): no.

Inputs: none.

Example input: `{}`

### `openrushmcp_research_keywords`

Research Keywords · Read-only

Expand a seed term into a ranked demand list (volume, CPC, competition,
intent per keyword).

mode:
- "ideas" (default): broad, category-level expansion. Best for mapping a topic.
- "suggestions": autocomplete-style long-tail off the exact seed.
- "related": semantically adjacent terms.
Optional filters: `min_volume` drops low-demand noise; `intent` restricts to
one of informational | navigational | commercial | transactional.

Read only: yes. Destructive: no. Idempotent (safe to retry): no.

Inputs:

- `seed` (`string`, required): The ONE seed term to expand — a single search phrase ("seo audit tool"), not a list, not a JSON-encoded array, not a domain. Call once per seed; discover_competitors is the tool that takes a keyword LIST (`seed_keywords`).
- `intent` (`string`, optional): Restrict results to one search intent. One of: `informational`, `navigational`, `commercial`, `transactional`.
- `language` (`string`, optional): Result language ("English", "Spanish"). Default: `English`.
- `limit` (`integer`, optional): How many keywords to fetch. `min_volume` and `intent` filter afterwards, so the result can be smaller. Default: `25`.
- `location` (`string`, optional): Target market as a COUNTRY name ("United States", "Mexico"); sub-country values are rejected. Defaults to the United States.
- `min_volume` (`integer`, optional): Drop keywords below this monthly search volume.
- `mode` (`string`, optional): Expansion style: "ideas" = broad category-level expansion (best for mapping a topic), "suggestions" = autocomplete-style long-tail off the exact seed, "related" = semantically adjacent terms. One of: `ideas`, `suggestions`, `related`. Default: `ideas`.

Example input: `{"seed":"<seed>"}`

## Related

Other Marketing connectors ([all 59](/agentkit/connectors/?category=marketing)):

- [HubSpot](/agentkit/connectors/hubspot/): Scalekit connector, OAuth, 457 tools
- [Mailchimp](/agentkit/connectors/mailchimp/): Scalekit connector, OAuth, 73 tools
- [Twitter / X](/agentkit/connectors/twitteroauth/): Scalekit connector, OAuth, 92 tools


---

## More Scalekit documentation

| Resource | What it contains | When to use it |
|----------|-----------------|----------------|
| [/llms.txt](/llms.txt) | Structured index with routing hints per product area | Start here — find which documentation set covers your topic before loading full content |
| [/llms-full.txt](/llms-full.txt) | Complete documentation for all Scalekit products in one file | Use when you need exhaustive context across multiple products or when the topic spans several areas |
| [sitemap-0.xml](https://docs.scalekit.com/sitemap-0.xml) | Full URL list of every documentation page | Use to discover specific page URLs you can fetch for targeted, page-level answers |
