
Your agent needs keyword volumes, live SERPs, and Search Console data for every customer site it touches. OpenSEO, the open-source alternative to Semrush and Ahrefs, exposes all of it through one MCP server. Look for the REST API beside it and you will not find one.
The real decision is between OpenSEO's server and the upstream APIs OpenSEO itself calls. It turns on tool coverage, credit governance, and how many credentials you are prepared to own. Here is how to pick.
One side is a product with a curated tool surface. The other is the set of services that product is assembled from.
OpenSEO is an MIT-licensed project maintained in the every-app/open-seo repository on GitHub, with a managed hosted version. The hosted MCP server lives on the /mcp path of the OpenSEO app over streamable HTTP, and the same server runs on self-hosted Cloudflare and Docker deployments.
On the current main branch it registers 57 tools: keyword research, live SERPs, domain and backlink analysis, local SEO, rank tracking, site audits, Search Console, GA4, shared project context, and HTML reports. The server reports version 0.0.12, so treat the tool contract as pre-1.0. Setup instructions live in the official "Set up OpenSEO MCP" guide in the OpenSEO docs.
OpenSEO does not maintain its own keyword or backlink index. It fetches SEO data from DataForSEO. Self-hosters bring their own DataForSEO key, and the hosted service adds 28% to each DataForSEO request, per the project README. First-party data comes from Google Search Console and GA4 through Google OAuth.
Going direct means three integrations: the DataForSEO v3 API over HTTP Basic auth, the Search Console API, and the GA4 Data API. The official references are DataForSEO's API v3 documentation and Google's Search Console API and Analytics Data API guides.
Recommended reading: DataForSEO MCP vs DataForSEO API for AI Agents covers the Live versus Standard queue cost split in detail.
The four dimensions below are the same ones this series uses for every tool. For OpenSEO, auth and operational surface carry most of the weight. Tool names below are OpenSEO's own; Scalekit prefixes each one with openseomcp_.
OpenSEO's value on the MCP side is not the raw data, which DataForSEO also sells. It is the state OpenSEO keeps: saved keywords, rank history, audit results, and a project memory other agents can read.
The direct path wins on control. Standard-queue delivery, postbacks, and full payloads are there when a nightly job needs thousands of keywords at the cheaper rate. OpenSEO's scheduled rank trackers already use queued tasks internally, with a separately billed live fallback, but the agent cannot choose the delivery method per call.
The MCP path wins on composition. A 3x3 local rank grid is nine Maps searches plus business matching. get_search_opportunities joins Search Console pages in positions 4 to 20 with GA4 outcomes and scores them. Rebuilding either against raw APIs is real work.
Scalekit's OpenSEO connector exposes 46 of the 57 tools on OpenSEO's main branch. The 11 not in the catalog today are save_report, list_reports, get_report, delete_report, list_report_templates, save_report_template, delete_report_template, list_site_audits, delete_site_audit, remove_saved_keywords, and search_serp_locations.
Seven of the 11 manage HTML reports and report templates. If your agent's deliverable is an OpenSEO report, plan around that. Every keyword, SERP, domain, backlink, local, audit, rank tracking, Search Console, and GA4 data tool is present. Without the location lookup, pass DataForSEO location codes directly.
OpenSEO's auth depends on where it runs, and only the hosted service has a per-user model.
On the hosted service, the OAuth grant carries a single mcp scope, and API keys receive the same scopes as OAuth grants. There is no read-only credential.
The only boundary OpenSEO enforces is membership. Every call that names a projectId is authorized against the caller's membership in that project's organization, and that organization is billed. That makes least privilege a tool-surface problem: a credential that can read Search Console can also start a live rank check or buy a backlink profile.
Self-hosting moves the auth problem rather than removing it. Cloudflare self-hosting puts every allowed user into one shared workspace, so per-user isolation disappears. Docker self-hosting disables auth entirely and is meant for a private network behind your own proxy.
For a multi-tenant B2B agent, the hosted service is the only OpenSEO deployment where each customer's grant is bound to their own organizations. The access control patterns for multi-tenant agents post covers why that boundary matters.
Hosted API-key traffic is throttled at 5,000 requests per minute per user. An interactive agent rarely approaches that. Credits run out first.
Most research tools charge credits: roughly 5 per keyword for a live SERP at default depth, 30 to 100 per seed in research_keywords, and 100 to 300 for a domain overview. Search Console, GA4, saved keywords, project context, and audit reads are free.
The server's own instructions tell agents to ask before batches over 2,000 credits. run_rank_tracker rejects any run whose fresh estimate exceeds the maxCostCredits the user approved, and scheduled trackers can add separately billed live fallback.
On the MCP path, OpenSEO maintains tool schemas, DataForSEO request construction, caching (domain overviews cache for 12 hours), and, on the hosted service, the Google OAuth clients for Search Console and GA4. You own per-user credential storage and refresh, the tool subset each agent sees, and credit approval.
Expect schema movement. Several parameters are already marked deprecated or legacy, including includeSubdomains in favor of scope, and the US-only market selector in favor of locationCode.
On the direct path you own everything: three auth models, the Live versus Standard choice, pagination, retries, rank history storage, and your own Google Cloud OAuth clients.
Pick either path and you still hold one credential per user, per provider. Neither path gives you a vault, refresh orchestration, or a revocation flow.
On the MCP path, each user's OpenSEO grant has an access token that expires daily and a refresh token that lasts 30 days. If a grant is not refreshed inside that window, the next run fails until the user signs in again. The API-key shortcut is worse for B2B: a personal key acts as that user with the full mcp scope.
On the direct path, the count multiplies: a DataForSEO credential per tenant plus Google OAuth grants per user. The token type differs. The storage, refresh, and revocation work does not.
Recommended reading: How to Handle Token Refresh for AI Agents.
Scalekit's OpenSEO MCP connector runs the OAuth flow, stores each user's grant in its token vault, and refreshes it, so credentials never touch the agent runtime. The same connected-account model covers the direct path through the DataForSEO MCP, Google Search Console, and Google Analytics connectors in AgentKit. The MCP vs API decision does not change your auth infrastructure.
The examples below use Python and LangChain. The sequence is fixed: authorize the user, retrieve the tools their connected account may call, then run the agent.
Create an OpenSEO MCP connection in the Scalekit dashboard under AgentKit > Connections. Copy your environment URL, client ID, and client secret from Developers > API Credentials into .env.
The connection name in code must match the dashboard exactly. These examples use openseomcp, as in Scalekit's quickstart; replace it with the name your dashboard shows. A mismatch is the most common integration error.
get_or_create_connected_account resolves the user's OpenSEO connected account by your app's identifier. If the account is not ACTIVE, send the user through OpenSEO's login once. Scalekit keeps and refreshes the grant after that.
The agent does not load the 46-tool catalog. actions.langchain.get_tools calls list_scoped_tools for this user's connected account and returns native LangChain StructuredTool objects.
Passing tool_names narrows that surface further, here to six tools that spend no OpenSEO credits. Because OpenSEO has one scope, this is where read-only access actually gets expressed.
The loop is plain LangChain. Scalekit resolves the user's OpenSEO token inside each tool call, so the model never sees a credential.
For deterministic jobs, skip the model and call execute_tool directly. OpenSEO's live rank check expects the approved ceiling as maxCostCredits, so the approval step belongs in your code, where a model cannot talk itself past it. Live checks require a paid plan on the hosted service.
Keep the returned execution_id with your job record so each credit spend maps to one call and one user.
Most SEO agents do not stop at research. They post a digest to Slack or file a ticket. A Virtual MCP server gives that agent one endpoint covering both connectors, scoped to named tools and to one user per session.
Hand an agent the full OpenSEO server and it sees every tool, including the ones that spend credits. At roughly 200 tokens per tool, 46 tools consume about 9,200 tokens before the agent does any work.
A Virtual MCP server declares exactly which tools each agent role sees. One server definition serves every user; before each run you mint a short-lived session token bound to that user's connected accounts. The endpoint is static; the identity is per-user. There is no MCP server to deploy, host, or maintain.
This digest agent gets four read-only OpenSEO tools and one Slack write. The Slack connection name must also match your dashboard. The full walkthrough is in the Virtual MCP setup guide.
Before each run, confirm every connection in the config is active for this user, then mint a token. Authorization links from list_mcp_connected_accounts are valid for one minute, so surface them immediately. Session tokens default to about one hour, and minting again is the refresh.
The same config serves every tenant. Only the identifier and the session token change between runs.
When a customer asks why their credits dropped, you need the answer by user, not by agent. Scalekit gives you that at two levels.
In the Scalekit dashboard, AgentKit > Connected Accounts shows each user's connection status, token refresh history, and tool execution logs. Every OpenSEO call runs under the connected account that authorized it, so a disputed run_rank_tracker traces to one user and one grant, not a shared key.
Recommended reading: Audit Trails for Agent Auth in B2B SaaS.
Subscribe to the connected_account.status_updated webhook. It fires on every status transition and carries both the old and new status, so filter on ACTIVE moving to EXPIRED and send the user a fresh authorization link. Add connected_account.token_refresh_failed for refresh failures.
With OpenSEO's 30-day refresh window, this is the difference between a re-authorization email and a weekly report that silently never arrives. The connected accounts guide has the payload details.
If your agent works alongside a user inside their own SEO data, build on OpenSEO MCP. It keeps rank history, audits, and project memory that raw APIs do not, and hosted OAuth gives each user a real identity.
If your agent is a high-volume pipeline that needs queued delivery, full payloads, or per-tenant DataForSEO billing, go direct to DataForSEO and Google's APIs. Many teams will run both.
Either way, you hold one credential per user per provider, and OpenSEO's single scope makes tool scoping your only least-privilege control. That is the layer that needs production-grade infrastructure. Understanding secure token management for AI agents at scale is a prerequisite before either path goes to production.
Building an OpenSEO agent and want help with the auth design? Talk to us for immediate help.
Start with the OpenSEO MCP connector docs.