Agency MCP Server
Provides read-only Google Search Console reporting via the Search Analytics API, returning clicks, impressions, CTR and position by query, page, country, device or date.
Calls Google PageSpeed Insights API v5 to retrieve Core Web Vitals field data and a Lighthouse lab audit, including performance score, LCP, CLS and TBT for audited pages and origins.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Agency MCP ServerAudit the dental client's homepage for SEO and metadata issues."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Agency MCP Server
A read-only Model Context Protocol server that gives MCP clients eight website-audit tools for an agency's client sites: page audits, structured-data validation, crawler access, Core Web Vitals, site crawls, answerability scoring, Search Console reporting and answer-engine visibility checks.
Every tool is scoped to one client's domain allowlist, fetches through an SSRF guard, and returns third-party text inside a fenced untrusted-data block.
Playground: https://vedantkinikar.duckdns.org/demos/agency-mcp/ runs the tools against three fictional demo sites over Streamable HTTP.
Recorded session: docs/mcp-session.md, also shown in the playground. The MCP SDK's client calls every tool, and every message is captured as it was sent.
Built with TypeScript, the official MCP TypeScript SDK (stdio and Streamable HTTP), Zod, Vitest and Docker.
What is real, and what is fixture or mock
# | Tool | Data source | Status |
1 |
| Fetches the page | Real |
2 |
| The page's JSON-LD | Real |
3 |
| The host's | Real |
4 |
| Google PageSpeed Insights API v5 | Real API call. Without a key, calls share Google's anonymous daily quota, which was exhausted when this was written (HTTP 429). The tool then reports Google's error as it is. Set |
5 |
| Fetches pages and sitemaps | Real |
6 |
| Fetches the page | Real, deterministic heuristic (see below) |
7 |
| Search Console API (read-only scope) | The live client is implemented but has never run against Google: no credentials exist. Unit tests check the JWT signing and the request it builds against a fake endpoint. Without credentials, and always in the playground, it returns rows from |
8 |
| A configurable chat-completions endpoint | The HTTP provider is implemented but has never run against a real model: no key is configured. It is tested against a fake endpoint. Without an endpoint, and always in the playground, a mock provider generates replies locally from a hash, naming the client with a fixed 35% probability. Results say |
The three demo sites (a dental clinic, a coffee roaster and a plumber in Melbourne) are fictional. They come from seo-geo-starter and run at /demos/dental, /demos/cafe and /demos/plumber. Their pages are noindex, and audit_page says so.
Related MCP server: Keytomic MCP
Tools
All tools take a client id. Every URL must be inside that client's allowlist.
audit_pagechecks one URL: title and meta description length, canonical, robots meta,lang, heading structure (missing or repeated h1, skipped levels, empty headings), links (internal, external, nofollow, links with no accessible name), images withoutalt, and the four required Open Graph tags. Length limits are conventions (results pages cut titles at about 60 characters), not published rules.validate_structured_dataextracts JSON-LD (top level,@graphand nested) and checks LocalBusiness (and 37 common subtypes such as Dentist and Plumber), Service, FAQPage, Article (and subtypes) and BreadcrumbList for required and recommended properties. It also checks value shapes: ISO dates, absolute URLs, coordinates and crumb positions. It is a checklist based on Google's rich-result documentation, not a full schema.org vocabulary validator.check_crawler_accessreads/robots.txtat the host root as RFC 9309 specifies:a crawler uses its own groups, else
*;the longest match wins, and Allow wins a tie;
*and$are supported;a 4xx means allow all, and a 5xx or network failure means disallow all.
It reports whether GPTBot, ClaudeBot, PerplexityBot, Google-Extended and Googlebot (plus any agents you add) may fetch the URL, and which rule decides. For a site served under a path, it notes a
robots.txtthere that crawlers will never read. It then checksllms.txtat the root and under that path: H1 title, summary, sections and link count.core_web_vitalscalls PageSpeed Insights. It keeps real-user field data (CrUX p75 LCP, INP and CLS for the page and the origin, when Google has enough traffic) separate from one Lighthouse lab run (score, LCP, CLS, TBT), rated against the web.dev thresholds.crawl_siteruns a breadth-first crawl inside the allowlist. It obeysrobots.txtfor its own user-agent and is held to 2 requests per second per host (configurable). Sitemap URLs (fromrobots.txtand<path>/sitemap.xml, one sitemap-index level) are queued after the link crawl. It reports broken links with the pages that link to them, redirects, duplicate titles and descriptions, and orphans: sitemap URLs that no crawled page links to. When the page limit cuts the crawl short, it says the orphan list may be incomplete.score_answerabilityscores 0 to 100 how easily answers can be lifted from a page. It is deterministic: no model is involved.Question headings (25 points): the share of h2-h4 and
<summary>headings phrased as questions. Full marks at half or more.Answer first (35 points): the share of question sections, plus the page lead after the h1, whose first sentence passes three checks. It is 50 words or fewer, it is not filler ("Welcome…", "In this article…"), and it shares a key word with the heading or opens with yes/no or a number.
FAQ markup (15 points): FAQPage JSON-LD is present. The result also counts how many of its questions are visible on the page.
Paragraph length (25 points): the share of paragraphs of 80 words or fewer.
Each failing section gets an answer-first suggestion. It names the sentence in that section that shares the most key words with the question, preferring one short enough to lead with. The score measures structure, not whether the answers are correct.
search_console_reportreturns search analytics (clicks, impressions, CTR, position) by query, page, country, device or date. The token request is signed withnode:crypto(no Google SDK), for a service account or an OAuth refresh token, with thewebmasters.readonlyscope.answer_engine_visibilitysends each prompt N times and counts replies that name the client (whole-word, case-insensitive brand terms).Rates come with a 95% Wilson interval.
Given a baseline (mentions out of runs), the difference gets a Newcombe hybrid score interval. A change counts as real only when that interval excludes zero; otherwise it is run-to-run variance.
Only the operator's prompt is sent to the model. Page text never is.
Safety
Each item below has tests in test/.
Read-only. The fetcher only sends GET requests. Search Console uses the read-only scope. Every tool is annotated
readOnlyHint: true.Per-client allowlists.
config/clients.jsonmaps each client to hostnames (example.com, or*.example.comfor subdomains only) or URL prefixes (https://host/demos/dentalmatches that path and below, but not/demos/dentalx). Hostname entries allow default ports only. The allowlist is checked before the first request and again on every redirect hop. A path-scoped client may also read/robots.txt,/llms.txtand/sitemap.xmlat its host root.SSRF guard. The address check runs inside the socket's own DNS lookup, so the address checked is the address connected to. It blocks private, loopback, link-local, CGNAT (which includes Tailscale), documentation, multicast and reserved ranges, plus IPv4-mapped and NAT64 IPv6. IP literals are checked too, and so is every redirect. Responses are capped at 2 MB, with a 15-second timeout.
Rate limiting. A token bucket per host for outbound fetches (shared by all clients), one for PageSpeed and model calls, and, in the playground, 20 tool calls per visitor per 10 minutes and 300 an hour overall.
Secret redaction. Configured keys, bearer tokens,
key=query parameters, private-key blocks and JSON secret fields are scrubbed from logs and from errors returned to clients. Logs go to stderr, because stdout carries the protocol.Untrusted data. Every result's text is fenced between markers carrying a random id the page cannot guess. Every
<inside is JSON-escaped, so a page cannot forge the closing marker. The fixturetest/fixtures/bad.htmlcarries a prompt-injection line and a fake marker to prove it.
Use it
Requires Node 22 or later.
npm ci
npm run build
npm testConnect an MCP client over stdio with a config like this:
{
"mcpServers": {
"agency": {
"command": "node",
"args": ["/path/to/agency-mcp-server/dist/stdio.js"],
"env": { "CLIENTS_FILE": "/path/to/clients.json", "PAGESPEED_API_KEY": "..." }
}
}
}Run the Streamable HTTP server and the playground with npm run start:http (port 3000, POST /mcp), or with Docker:
docker build -t agency-mcp-server .
docker run --rm -p 3000:3000 -e DEMO_MODE=1 agency-mcp-serverVariable | Purpose |
| Client allowlists (default |
| Optional PageSpeed Insights key |
| Service-account key, as a file path or inline JSON |
| Or an OAuth client with a refresh token |
| Any endpoint that accepts |
| Search Console and visibility always use fixture and mock data |
| Outbound politeness: default 2 per second, 200 pages |
| HTTP server port and path prefix |
npm run record rebuilds and re-records the MCP session against the live demo sites.
Tests
88 Vitest tests, run in CI on Node 22 and 24, followed by a Docker build that boots the image and lists the tools over HTTP. They use local fixture servers and fake API responses, so no network is needed. They cover:
each tool's findings;
the allowlist and SSRF cases: private DNS answers, redirects into metadata and private addresses, redirects out of the allowlist, loops, size caps;
rate limiting and redaction;
the untrusted fence;
the MCP server over an in-memory transport;
the HTTP endpoint's per-visitor limit;
the published Wilson and Newcombe values.
Limits
The robots.txt matcher does not normalise percent-encoding, and does not fall back from sub-agents (Googlebot-News) to their parent token.
The crawl is sequential and follows one sitemap-index level. Links outside the allowlist are counted, not checked.
Answerability uses a 4-letter prefix as a stemmer and simple sentence splitting.
The structured-data checks cover five types and their common subtypes, not the whole vocabulary.
License
MIT
This server cannot be deployed
Maintenance
Related MCP Connectors
Hosted, read-only Google Search Console MCP: performance, comparisons, URL inspection, sitemaps.
Audit, rank-track and analyze SEO for sites via an authenticated MCP server.
Read-only Google Search Console MCP server for AI assistants.
Your agent needs to crawl a site and say what is wrong with it — broken tags, duplicate content, pages nothing can index, resources that never load. **What you can ask for** • "Crawl this site and list every page with a duplicate title or missing description." • "Which pages are non-indexable, and why?" • "Run Lighthouse on these URLs and give me the failing audits." • "Show the internal link graph and the orphan pages." • "Give me this page's raw HTML and its microdata." **How to use it** Point any MCP client at https://mcp.aisa.one/seo-onpage/mcp and sign in with OAuth — there is no key to create or paste. 20 tools: submit a crawl and read its summary, pages, resources, links and waterfall; duplicate content and duplicate tags; keyword density; non-indexable and uncrawlable resources; parsed content, raw HTML, microdata, screenshots and Lighthouse. **Why this rather than the source** A crawler you drive from the agent, with the audit results as structured data rather than a PDF. **It is also a door to the rest** The same login reaches 26 sources and 580+ operations. Find the broken pages here, then ask the same agent what those pages used to rank for — without adding a second server. **What it costs** Finding and inspecting an operation is free. Running one is billed per call at API prices, with no seat and no monthly minimum, and every call takes max_price_usd so an agent cannot overspend by accident. **Where else it reaches** https://mcp.aisa.one/seo/mcp for all of it at once — rankings, keywords, backlinks, site health and AI-answer visibility across DataForSEO, Semrush and Ahrefs.
Related MCP Servers
- AlicenseAqualityBmaintenanceRead-only MCP server for Google Search Console: performance queries, URL inspection, indexing checks, sitemaps, and one-call HTML SEO audit reports.17544 PyPI9MIT
- AlicenseNot gradedqualityBmaintenanceEnables AI clients to perform bounded website Quick Audits via MCP tools, covering crawlability, indexability, and metadata.1MIT
- AlicenseAqualityAmaintenanceEnables MCP clients to query Google Search Console search performance, inspect indexing, analyze sitemaps, and run SEO analyses such as cannibalisation detection, query clustering, and wins/losses, all with read-only access.20553 npmApache 2.0
- AlicenseAqualityAmaintenanceEnables running comprehensive website audits from any MCP client, returning actionable plain-language reports covering SEO, accessibility, performance, security, and more.653 npmMIT