Announcing CIMD support for MCP Client registration
Learn more

OpenRush MCP vs OpenRush API for AI Agents

Saif Ali Shaik
Founding Developer Advocate

TL;DR

  • OpenRush MCP and the OpenRush REST API expose the same research tools. Credit balance, usage logs, and API key management exist only on the REST API.
  • MCP is not OAuth-only. Most clients sign in with OAuth, PKCE, and refresh tokens; OpenRush also accepts an or_ API key on the MCP endpoint.
  • OpenRush OAuth tokens carry no per-tool scopes, so every token reaches every tool on the account. Least privilege must be enforced above OpenRush.
  • Credits are the production constraint: 1 to 40 per call, deducted when the call starts, with no MCP tool that reads the balance.
  • Scalekit's OpenRush MCP connector handles per-user OAuth, token storage, and refresh, and Virtual MCP limits each agent role to the tools it needs.

Why OpenRush MCP vs OpenRush API is a real decision

Your agent needs marketing data: who ranks for a query today, which keywords a client is losing to competitors, which domains Google's AI Overviews cite in a category. OpenRush ships a hosted MCP server and a public REST API over the same data, and on the surface the OpenRush MCP vs OpenRush API choice looks cosmetic. It isn't. The two paths differ on account control, on how credentials reach OpenRush, and on who absorbs the cost when an agent loops. For a multi-tenant agent, those differences decide the architecture. Here's how to pick.

What OpenRush MCP and OpenRush API actually are

Both paths sit on one OpenRush account model: one credit balance, one set of connected Google properties, one activity log. What differs is the interface your agent calls and how it authenticates.

OpenRush MCP

OpenRush operates a remote MCP server at the /mcp path of its API host, over Streamable HTTP. It is maintained by OpenRush and listed as a verified connector in Claude's directory, with a ChatGPT app alongside it. Every tool returns the same Open Fact Envelope (ofe/1.0) the REST API returns, and the tool descriptions are written for models: they tell the agent when a result is thin and which tool to call next.

Auth is an OAuth sign-in for most clients. For agents that cannot complete a sign-in, OpenRush accepts an API key in the Authorization header instead.

OpenRush API

The REST API exposes each tool as POST /v1/tools/{tool_name}, plus account endpoints under /v1/me/* and an unauthenticated /v1/capabilities discovery route. Authentication is an OpenRush API key, prefixed or_, sent as Authorization: Bearer or X-API-Key. Public routes also accept a signed-in Dashboard session bearer token, which OpenRush maps to the same account.

Comparing them where it matters for agents

Four dimensions change what you build: capability coverage, auth model, operational surface, and fit. The first one is closer to parity than for most tools in this series.

What your agent can actually do

Every research tool maps one-to-one between the two paths, at the same credit cost per call.

Capability
OpenRush MCP
OpenRush API
Credits
Domain snapshot (inspect_domain)
Yes
Yes
9
Competitor discovery
Yes
Yes
7
Keyword research and drill-down
Yes
Yes
3 and 5
Keyword gap (compare_keyword_coverage)
Yes
Yes
12
Live SERP snapshot
Yes
Yes
2
Backlink profile and backlink gap
Yes
Yes
9 and 40
Google AI Overview citations
Yes
Yes
20 and 22
Site audit (raw HTML, no JavaScript)
Yes
Yes
9
Owned Search Console, GA4, Google Ads reads
Yes
Yes
2 each

Where the two paths split

The divergence is entirely in account and connection control.

Capability
OpenRush MCP
OpenRush API
Credit balance and usage log
No
Yes (/v1/me/credits, /v1/me/usage)
API key create and revoke
No
Yes (/v1/me/api-credentials)
Connect a Google property or ad account
No
No (Dashboard only)

Why the account gap matters

The gap is not data. It is account control. An agent on the MCP path can spend credits but cannot read how many remain, cannot see its own request history, and cannot rotate the key it may be running on. Those operations live under /v1/me/* on the REST API only.

For an interactive assistant, that is fine; the user watches their balance in the Dashboard. For a scheduled agent running compare_backlink_gap at 40 credits per call across a client roster, it means the agent has no way to stop before the balance runs out. Your orchestration layer has to check /v1/me/credits out of band, or budget calls itself.

The owned-data layer neither path can connect

The Search Console, GA4, and Google Ads tools read Google properties connected inside OpenRush. Connecting a property or activating an ad account is Dashboard-only on both paths, because Google's OAuth requires human consent. MCP and REST can list connections and read them. Neither can create one.

That is a second consent layer on top of the OpenRush sign-in. When a property is not ready, owned-data tools return recoverable states such as connection_required, website_required, or reconnect_required instead of data, and OpenRush does not charge for them. Your agent needs a path to send the user back to the OpenRush Dashboard, not a retry loop.

The auth path each one puts you on

OpenRush runs one identity model under both paths: an OpenRush account. The question is how your agent proves it is acting for that account, and what the credential can reach once it does.

MCP auth: OAuth by default, API key as fallback

Claude Code, Cursor, ChatGPT, and similar clients connect to the MCP endpoint and complete a browser-based OAuth sign-in. OpenRush's authorization server is a hosted Supabase Auth project. Its published metadata advertises the authorization_code and refresh_token grants, PKCE with S256, a Dynamic Client Registration (DCR) endpoint, and the offline_access scope. Because refresh tokens are supported, a background agent can keep running after one interactive consent, provided something refreshes the token correctly.

There is no client_credentials grant. An agent acting for an account that has never signed in must use the API key path, which OpenRush documents for MCP clients that cannot complete a sign-in.

What an OpenRush OAuth token can reach

The MCP endpoint's OAuth 2.0 Protected Resource Metadata (RFC 9728) declares scopes_supported as an empty list. The only scopes on offer are OpenID Connect identity scopes. An OAuth token for OpenRush therefore reaches every tool on that user's account: the 2-credit SERP lookup and the 40-credit backlink gap, public research data and the user's own Google Ads spend.

That is a reasonable design for a single-user assistant. For an agent product, it means OpenRush will not enforce least privilege for you. If your SEO brief agent should never read ad performance, that restriction has to live in your tool layer. This is precisely why access control for multi-tenant AI agents requires an additional enforcement layer above the upstream provider.

API auth: account keys with a one-time reveal

REST calls authenticate with an or_ key. OpenRush returns the raw key once at creation and stores only a hash, fingerprint, and display prefix. Keys accept an optional expires_at, can be created and revoked through /v1/me/api-credentials, and keep their own limits, including website scope and rate limits, when used against MCP.

An API key identifies an account, not a person. Every call made with it lands in the same credit balance and the same activity log.

Per-user OAuth in a multi-tenant agent

Here's where it gets complicated. Take a B2B agent serving 30 agency customers. With per-user OAuth, each end user signs in with their own OpenRush account. Credits, connected Google properties, and the activity log stay per user, which is the correct isolation boundary.

The cost moves to you: 30 refresh tokens to encrypt at rest, refresh before expiry, and revoke on disconnect, plus 30 sets of Google property connections your agent cannot see until it calls list_connections. Understanding how to handle token refresh for AI agents at scale is essential before you commit to this architecture.

A shared platform key in a multi-tenant agent

The alternative is one OpenRush account, one or_ key, and every client's Search Console property connected under it. Onboarding is simpler. But every tenant now draws from one credit balance and one set of account-level rate-limit windows: 60 requests per minute, 1,000 per hour, and 10,000 per day by default.

Worse, once several websites are connected, owned-data tools return website_required with a list of options, and the model picks which client's data to read. Tenant isolation becomes a model decision. Shared credentials are a single-user solution. They do not survive a second user.

Recommended Reading: Ahrefs MCP vs Ahrefs API for AI Agents

What you own in production

OpenRush manages the data pipeline, the tool schemas, and the response shape on both paths. The failure modes you own are about money, limits, and state.

Credits are the real budget

Every tool call deducts credits when it starts, not when it succeeds. At $10 per 1,000 credits, a live SERP check costs two cents and a backlink gap costs forty. A weekly competitive brief for 50 client domains that runs inspect_domain, compare_keyword_coverage, and compare_backlink_gap once each costs 61 credits per client, or 3,050 credits per run. MCP, Dashboard, and API usage all draw from the same balance.

An insufficient balance surfaces as HTTP 402 on the REST path. On the MCP path, the agent learns about an empty balance only from a failed call.

Rate limits, retries, and recoverable states

Protected REST endpoints enforce account-level minute, hour, and day windows, and return X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, and Retry-After on a 429. On the REST path, you read those headers and back off. On the MCP path, retry behavior is whatever your MCP client does with a tool error.

Two behaviors need explicit handling on either path. Datasets behind openrush:// resources expire, and export_dataset then returns data.available=false with a next_actions entry to regenerate. And inspect_search_visibility in live mode checks at most 10 keywords per call, reporting the rest as unchecked in coverage.

Schema drift and the capability surface

OpenRush tells you not to trust a static tool list. Backlink tools can be disabled by an operational kill switch, and /v1/capabilities, or describe_capabilities over MCP, is the documented source of truth for enabled tools and current costs. MCP clients pick up changes at tools/list time. REST integrations call fixed paths, so a disabled tool shows up as a failed request.

The envelope is the stable part. Every tool returns ofe/1.0 with typed facts, per-fact provenance (confidence runs from 0.95 for live SERP data down to 0.50 for modeled data), coverage, and next_actions. Build against the envelope, not the per-tool data payload.

When to use MCP, when to use the API

Both lists assume the same OpenRush data. The deciding factors are who is present, who pays, and who controls the account.

Use OpenRush MCP when

  • A marketer or founder works interactively in Claude, ChatGPT, Cursor, or Claude Code and signs in once with their own OpenRush account
  • Your agent chains OpenRush with other MCP servers, such as a report agent that pulls a keyword gap and posts the summary to Slack, and benefits from next_actions steering tool selection
  • You want OpenRush's model-facing tool descriptions and envelope without writing a client, and the user can watch their own credit balance
  • You are prototyping an SEO agent and want to learn which tools matter before hardening anything

Use the OpenRush API directly when

  • The agent runs headless on a schedule for an account that never completes an OAuth sign-in, such as a nightly rank check on a platform-owned or_ key
  • Your pipeline must read /v1/me/credits before expensive calls, or reconcile spend against /v1/me/usage
  • You need to create, expire, and revoke keys programmatically per client or per environment
  • The workflow is deterministic, for example the same compare_keyword_coverage call against a fixed competitor list every Friday, and you want fixed request bodies instead of model-chosen arguments

The credential problem that exists on both paths

Pick either path and you still hold one credential per OpenRush account your agent acts for. The token type differs. The infrastructure required does not.

What OpenRush gives you

OpenRush gives you a clean identity boundary: one account, one balance, one set of connected Google properties. The OAuth sign-in yields a refresh token under offline_access. API keys are hashed at rest on OpenRush's side, can expire, and can be revoked programmatically. The account model is sound.

What you still have to build

Neither path stores, refreshes, or revokes credentials inside your product. For 30 agency customers on per-user OAuth, that is 30 refresh tokens to encrypt, isolate per tenant, refresh without concurrent-refresh races, and delete on disconnect. On the key path, it is 30 or_ keys shown once and never again. Your agent also has to tell "OpenRush token revoked" apart from "Search Console access expired", because they fail differently. This is the core problem that a token vault for AI agent workflows is designed to solve.

Where Scalekit fits

Scalekit's OpenRush MCP connector handles the OAuth flow, token storage, and refresh for every user on the MCP path, and a custom connector on the same vault covers REST-only endpoints, so the MCP vs API decision doesn't change your credential infrastructure.

Recommended Reading: Token Vault: Why It's Critical for AI Agent Workflows

Building OpenRush agents with Scalekit

Scalekit's catalog lists one OpenRush connector, openrushmcp: a vendor MCP connector with 20 tools and OAuth 2.1 with DCR. Scalekit routes your agent's tool calls to OpenRush's own MCP server. Each user signs in to OpenRush once, Scalekit stores and refreshes their tokens, and credentials never touch the agent runtime.

The hard part is not calling OpenRush. It is keeping 30 users' OpenRush sessions alive, isolated, and scoped to the tools each agent role should spend credits on. The code below is Python with LangChain, following the LangChain example.

Prerequisites

Create an OpenRush MCP connection in the Scalekit dashboard under AgentKit > Connections, as described in Configure a connection. The connection_name in your code must match the connection name configured in the dashboard exactly. The examples use openrushmcp.

pip install scalekit-sdk-python python-dotenv langchain-openai "langchain-mcp-adapters>=0.3,<1"
# .env SCALEKIT_ENVIRONMENT_URL=<your-environment-url> SCALEKIT_CLIENT_ID=<your-client-id> SCALEKIT_CLIENT_SECRET=<your-client-secret> OPENAI_API_KEY=<your-openai-api-key>

Authorize the user and make a first call

get_or_create_connected_account returns this user's connected account. If it is not ACTIVE, get_authorization_link starts the OpenRush sign-in; see Authorize a user for production handling. The first call uses openrushmcp_describe_capabilities, which takes no parameters.

import os from dotenv import load_dotenv from scalekit import ScalekitClient 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" # must match the connection name in the Scalekit dashboard identifier = "user_123" # your app's unique ID for this end user response = actions.get_or_create_connected_account( connection_name=CONNECTION_NAME, identifier=identifier ) if response.connected_account.status != "ACTIVE": link = actions.get_authorization_link( connection_name=CONNECTION_NAME, identifier=identifier ) print("Authorize OpenRush:", link.link) input("Press Enter after authorizing...") response = actions.get_or_create_connected_account( connection_name=CONNECTION_NAME, identifier=identifier ) if response.connected_account.status != "ACTIVE": raise RuntimeError(f"OpenRush is {response.connected_account.status}, not ACTIVE") result = actions.execute_tool( tool_name="openrushmcp_describe_capabilities", tool_input={}, connection_name=CONNECTION_NAME, identifier=identifier, ) print(result.execution_id) print(result.data)

Scope the tool surface before the model sees it

Before the agent loop, retrieve the tools this user's connected account is authorized to call, then narrow them to the agent's job. actions.langchain.get_tools wraps list_scoped_tools and returns native LangChain StructuredTool objects. Passing tool_names is where cost control starts: an SEO brief agent gets five research tools, not the 40-credit backlink gap or the user's Google Ads spend.

It is an accuracy decision too. Several OpenRush tool descriptions run past 200 words, and loading all 20 burns tokens before the agent does any work. The fix is not better prompting. It is surface reduction. For a deeper look at how LangChain tool calling works and where it stops, the patterns translate directly to OpenRush agents.

Run the LangChain agent loop

Continuing from the block above:

from langchain_openai import ChatOpenAI from langchain_core.messages import HumanMessage, ToolMessage tools = actions.langchain.get_tools( identifier=identifier, connection_names=[CONNECTION_NAME], tool_names=[ "openrushmcp_inspect_domain", "openrushmcp_discover_competitors", "openrushmcp_compare_keyword_coverage", "openrushmcp_inspect_keyword", "openrushmcp_inspect_serp", ], page_size=100, ) tool_map = {t.name: t for t in tools} llm = ChatOpenAI(model="gpt-4o").bind_tools(tools) messages = [ HumanMessage( "Map example.com, find its top three organic competitors, " "and list the ten keyword gaps worth a content brief." ) ] while True: response = llm.invoke(messages) messages.append(response) if not response.tool_calls: print(response.content) break for tc in response.tool_calls: result = tool_map[tc["name"]].invoke(tc["args"]) messages.append(ToolMessage(content=str(result), tool_call_id=tc["id"]))

Each tool invocation routes through execute_tool with this user's connected account, so the OpenRush call runs on that user's token and draws that user's credits.

Virtual MCP for multi-tool, multi-tenant OpenRush agents

Direct tool calling works when your code owns the loop. When the runtime speaks MCP, as Claude Managed Agents, CrewAI, Mastra, and LangChain MCP clients do, Scalekit's Virtual MCP servers give it one scoped endpoint. Two objects drive the model: the server, created once per agent role, and a short-lived session token, minted per user before each run. The endpoint is static; the identity is per-user. There is no MCP server to deploy, host, or maintain.

Create the server once per agent role

This mapping exposes four OpenRush research tools and nothing else. The agent never sees compare_backlink_gap or get_ad_performance, so it cannot spend 40 credits or read ad spend by mistake. Full setup is in Set up and connect a Virtual MCP server.

from scalekit.actions.models.mcp_config import McpConfigConnectionToolMapping vmcp = scalekit_client.actions.mcp.create_config( name="seo-brief-agent", description="Keyword and competitor research only", connection_tool_mappings=[ McpConfigConnectionToolMapping( connection_name="openrushmcp", # must match the dashboard connection name tools=[ "openrushmcp_inspect_domain", "openrushmcp_compare_keyword_coverage", "openrushmcp_inspect_keyword", "openrushmcp_inspect_serp", ], ), ], ) config_id = vmcp.config.id mcp_server_url = vmcp.config.mcp_server_url # store both and reuse them for every user

Mint a session token before each run

Confirm the user's OpenRush connection is active, then mint a token bound to that user. Tokens default to roughly one hour. Set expiry above the expected run time; for long-lived hosts, call create_session_token again before expiry, since there is no refresh endpoint.

from datetime import timedelta accounts = scalekit_client.actions.mcp.list_mcp_connected_accounts( config_id=config_id, identifier="user_123", include_auth_link=True, ) for account in accounts.connected_accounts: if (account.connected_account_status or "").upper() != "ACTIVE": raise RuntimeError( f"{account.connection_name} needs auth: {account.authentication_link}" ) session = scalekit_client.actions.mcp.create_session_token( mcp_config_id=config_id, identifier="user_123", expiry=timedelta(minutes=30), ) mcp_token = session.token

Connect LangChain to the Virtual MCP server

The agent receives the static server URL and the per-user bearer token. Nothing else about the user or OpenRush reaches the runtime.

import asyncio from langchain_mcp_adapters.client import MultiServerMCPClient from langchain_openai import ChatOpenAI from langchain_core.messages import HumanMessage, ToolMessage async def run(): client = MultiServerMCPClient( { "openrush": { "transport": "streamable_http", "url": mcp_server_url, "headers": {"Authorization": f"Bearer {mcp_token}"}, } } ) tools = await client.get_tools() tool_map = {t.name: t for t in tools} llm = ChatOpenAI(model="gpt-4o").bind_tools(tools) messages = [ HumanMessage("Which keywords does example.org rank for that example.com misses?") ] while True: response = await llm.ainvoke(messages) messages.append(response) if not response.tool_calls: print(response.content) break for tc in response.tool_calls: result = await tool_map[tc["name"]].ainvoke(tc["args"]) messages.append(ToolMessage(content=str(result), tool_call_id=tc["id"])) asyncio.run(run())

Adding Slack, Notion, or Sheets to the same server

A weekly brief rarely stops at OpenRush. Add a second McpConfigConnectionToolMapping for your Slack or Notion connection with only the write tool the agent needs, using the exact tool names from that connector's docs page. One server definition serves every user, and one session token resolves that user's OpenRush and Slack accounts together. Each user connects each account once.

Recommended Reading: DataForSEO MCP vs DataForSEO API for AI Agents

Observability: who called which OpenRush tool, for whom

OpenRush and Scalekit log different layers. You need both to answer an auditor, or a customer asking why their credits disappeared overnight. This is the same challenge covered in depth when thinking about agent tool observability — knowing your agent is running is not the same as knowing it is working correctly.

What OpenRush logs

/v1/me/usage returns recent requests per OpenRush account with the endpoint, status code, response time, auth_source, and credits_charged. It is the right ledger for one account. It knows nothing about your product: which tenant triggered a call, which agent role made it, or which end user was in session when a shared key fired.

What Scalekit adds

Scalekit records downstream tool calls at the agent layer. Each execute_tool returns an execution_id, and Scalekit's auth logs tie tool calls and connection events to the connection and the user identifier behind them. When a tenant asks why their OpenRush balance dropped by 400 credits overnight, you can trace which agent role called which tool for which user, then revoke that one connected account without touching anyone else's. What the user can't do, the agent can't do.

Which one to build against

If your agent is an interactive assistant where a marketer signs in with their own OpenRush account and watches their own balance, use MCP. If it is a scheduled pipeline on a platform-owned key that must check credits before a 40-credit call and rotate keys per client, call the REST API directly. Many production OpenRush agents use both: MCP for the research loop, REST for /v1/me/credits and key hygiene.

Either way, OpenRush will not scope tools, isolate tenants, or refresh tokens inside your product. That layer is the same on both paths, and it is the part that needs production-grade infrastructure. The patterns for secure token management for AI agents at scale apply regardless of which OpenRush path you choose.

Get help building your OpenRush agent

Building a multi-tenant SEO, content, or competitive-intelligence agent on OpenRush? Talk to us for immediate help with connector setup, Virtual MCP design, and per-user credential isolation.

Start from the OpenRush MCP connector docs.

No items found.
Agent
Auth Quickstart
On this page
Share this article
Agent
Auth Quickstart

Acquire enterprise customers with
‍zero upfront cost.

Every feature unlocked. No hidden fees.