Google Search Console & GA4
Query Search Console performance, inspect indexing, and run GA4 reports and funnels from your AI agent. 10 read-only tools, Google OAuth sign-in, works with any MCP client.
Agentman Certified
Built and operated by Agentman.
Connection checked by Agentman on .
Not listed in Anthropic’s Connectors Directory, which covers third-party connectors.
Connect Google Search Console & GA4 via MCP
https://mcp.agentman.ai/google-search/mcpWorks in any MCP-compatible client. In Agentman Studio it is one click — no config file to edit.
Use in Agentman
Connect Google Search Console & GA4 once and your agents call these tools on their own — on a schedule, in a workflow, with nobody at the keyboard.
Open in Agentman StudioGoogle Search Console & GA4 Tools & Capabilities (10)
Every Search Console property this login can reach. Call this FIRST when the user has not named a property. Every other gsc_* tool needs a site_url, and a guessed one returns 403 — which the API also returns for a property you genuinely cannot access, so a wrong guess is indistinguishable from a permissions problem. Args: - response_format ('markdown' | 'json') Returns: siteEntry[] with siteUrl and permissionLevel. Two things to read carefully before picking one: - 'sc-domain:example.com' (domain property) and 'https://example.com/' (URL-prefix property) are DIFFERENT properties covering different URLs, and they return different numbers. A login often has both for one site. Pass the siteUrl string exactly as returned; do not compose one by hand. - permissionLevel 'siteUnverifiedUser' means the property is listed but its data is NOT readable. Those entries will fail on every other tool. An empty list is a real answer — this login has no properties — not a failed lookup. Errors surface as errors.
Every GA4 property this login can reach, with display names, grouped by account. Call this FIRST when the user has not named a property. Every ga4_* tool needs a numeric property id, and that id is a bare number with nothing memorable about it — without this tool a human has to go dig it out of the GA4 UI. This is also how a name resolves to an id: the user says "our main site" or "the agentman property", and the displayName here maps it to the number. Args: - page_token (string): from a previous response's nextPageToken - response_format ('markdown' | 'json') Returns: accountSummaries[], each with the account displayName and its propertySummaries[] — property ('properties/123456789'), displayName, and propertyType. STRIP THE PREFIX: property comes back as 'properties/471838641'. Other tools want the digits only — '471838641'. If nextPageToken is present, more properties exist than are shown; pass it back as page_token rather than concluding the list is complete. propertyType matters when a name is ambiguous: PROPERTY_TYPE_SUBPROPERTY and PROPERTY_TYPE_ROLLUP report filtered or combined data, so they will not match the ordinary property they resemble.
Query Search Console performance: clicks, impressions, CTR, average position. Args: - site_url (string): GSC property, e.g. 'sc-domain:agentman.ai'. Call gsc_list_sites if you do not have one — a guessed property returns 403, which is also what a real permissions problem returns. - start_date / end_date (string): YYYY-MM-DD - dimensions (string[]): any of query, page, country, device, date, searchAppearance (default: ['query']) - row_limit (number): 1-25000 (default 100) - dimension_filter_groups: scope the query, e.g. to a single page - response_format ('markdown' | 'json') To get the queries for ONE page — the most common real question — you MUST pass a filter. Without it you get property-wide rows that look page-specific: dimensions: ["query"], dimension_filter_groups: [{"filters":[ {"dimension":"page","operator":"equals","expression":"https://example.com/post"} ]}] Verify it applied: the response's responseAggregationType reads "byPage" when a page filter is active and "byProperty" when it is not. If you asked for one page and see "byProperty", the filter did not take effect — do not report those numbers as belonging to that page. Returns: rows plus a _meta block naming source, property, range and fetch time. IMPORTANT: Search Console withholds low-volume queries for privacy, so the sum of returned rows is LOWER than the property total. Never present a row sum as "total clicks".
What Google actually sees at one URL: index status, canonical, last crawl, mobile usability. Use this when a page "should" be ranking but is not — it distinguishes "not indexed" from "indexed but ranking poorly", which need completely different fixes. Args: - site_url (string): GSC property the URL belongs to - url (string): the full URL to inspect
List submitted sitemaps and what Google discovered in each. Read-only. Sitemap SUBMISSION is a write operation and is deliberately not exposed by this server.
Run a GA4 report: any dimensions x metrics over a date range. Args: - property (string): numeric GA4 property id (call ga4_list_properties if you do not have one — do not guess) - start_date / end_date (string): YYYY-MM-DD or 'NdaysAgo' / 'today' - dimensions (string[]): e.g. ['eventName'], ['landingPage'], ['sessionSource'], ['sessionCampaignName'] - metrics (string[]): e.g. ['eventCount'], ['sessions'], ['keyEvents'], ['totalRevenue'] - dimension_filter: scope the report to a campaign, page, or source - limit (number) SCOPING — read this before reporting any number as belonging to a campaign or a page. Without dimension_filter the report covers the WHOLE property. To measure one campaign: dimensions: ["eventName"], metrics: ["keyEvents","totalRevenue"], dimension_filter: {"filter":{"fieldName":"sessionCampaignName", "stringFilter":{"value":"spring_sale","matchType":"EXACT"}}} Landing-page scoping has a trap worth knowing: 'landingPage' is a PATH ('/pricing'), not a full URL, and it excludes the query string. Filtering it with a 'https://...' value matches nothing and returns zero rows — which reads exactly like "this page got no traffic". Use 'hostName' alongside it when one property collects several domains, or the rows silently merge same-path pages across them. MEASURING CONVERSIONS: 'keyEvents' counts only events marked as key events, and 'totalRevenue' only fires where ecommerce or value parameters are sent. Both return a legitimate 0 when nothing is configured. Call ga4_key_events first to tell "no conversions happened" apart from "nothing is marked as a conversion" — they are the same number here and different problems. RECONCILING WITH ADS: GA4 attributes by session source with its own lookback and model; Google Ads counts conversions against the click's date. The two will not match, and neither is wrong. Compare trends, not totals, and say which source a number came from. NOTE: counting two events here is NOT a funnel — it tells you nothing about whether the same user did one then the other. Use ga4_run_funnel for ordered step-over-step analysis.
Events arriving in the last 30 minutes. The post-deploy check. Use immediately after shipping tracking changes: fire the flow, then call this to confirm the event actually reaches GA4 with the expected parameters. Catches "we shipped tracking and it silently stopped working", which is otherwise invisible until someone asks for a number weeks later.
A REAL funnel: ordered steps, per-step completion and drop-off. Args: - property (string): call ga4_list_properties if you do not have an id - start_date / end_date (string) - steps (array): [{ name, event_name }] in order - dimension_filter: scope the WHOLE funnel to a segment SCOPING: without dimension_filter the funnel covers all property traffic. To ask "how did the people this campaign sent actually convert" — the question worth asking about paid traffic, since a campaign can drive plenty of clicks that all drop at the same step: dimension_filter: {"filter":{"fieldName":"sessionCampaignName", "stringFilter":{"value":"spring_sale","matchType":"EXACT"}}} Compare a scoped run against an unscoped one to tell "this campaign converts badly" apart from "this funnel converts badly for everyone". This uses Google's runFunnelReport, which is an ALPHA endpoint — the response carries that caveat, and numbers may not match the Explore UI exactly. It is still the only API that answers "did the same user do A then B", which event counts cannot.
Which events this property counts as key events (conversions). Args: - property (string): call ga4_list_properties if you do not have an id Ask this FIRST when a property reports zero conversions. A site can emit perfect events and still show nothing, because none of them are marked as key events — the instrumentation is fine and the reporting is empty. That exact state has occurred on a live property with ~40 tracked CTAs and zero key events.
Audit what a page ships in its HTML: schema types, FAQ schema-vs-visible agreement, title/meta/canonical, and outward citation count. Fetches the URL directly and needs no Google authorization, so it works on ANY public page — ours or a competitor's. That symmetry is the point: a structural comparison only means something when both sides are measured the same way. Args: - urls (string[]): 1-20 http/https URLs to audit - response_format ('markdown' | 'json') Args: - include_links (boolean): also return the full link inventory (default false) - related_hosts (string[]): other hosts in the same funnel, e.g. ['studio.example.com'], so their links are checked for tracking params too Returns per URL: status, title (+length), meta description, canonical, the distinct JSON-LD @types present, an FAQ block when FAQPage schema exists, the number of distinct external links, internalLinksWithTracking, and notes on anything suspicious. ATTRIBUTION CHECK — internalLinksWithTracking is always returned and is the highest-severity thing here. An internal link carrying utm_*, gclid, fbclid or similar RESTARTS the visitor's session attribution, re-crediting the conversion away from the campaign that paid for the click. The analytics keep working and the numbers stay plausible, which is why this goes unnoticed. Each entry gives the href, the resolved URL, the link text, and which parameters were found, so the offending CTA can be identified without opening the page. The same parameters on an OUTBOUND link are correct and normal — that is how you tag traffic you send elsewhere. Only same-host links are flagged by default. TWO-DOMAIN FUNNELS — pass related_hosts. When the landing page and the signup live on different subdomains of one root (example.com -> studio.example.com), they share a root-domain cookie, so a tracking parameter on the cross-host CTA restarts the session exactly as a same-host one would. Those links are NOT flagged unless you name the host: urls: ["https://example.com/lp"], related_hosts: ["studio.example.com"] Related hosts are never inferred. A shared registrable domain does not imply a shared analytics setup, and guessing would flag legitimate outbound tagging. A note fires when external links exist and no related_hosts were given, so a narrowed check does not read as a full pass. Pass include_links: true to get every link (href, resolved, text, internal, rel) for a check this tool does not perform. It is off by default because a large page returns a lot of rows. The FAQ block is the one to read first. Google requires FAQ content to be VISIBLE on the page; schema that declares questions a reader cannot see is the most common structured-data violation we hit, and it is invisible in a browser. 'visibleCount' below 'schemaCount' means the page is claiming answers it does not show. LIMITS — this reads server-rendered HTML only. Content injected by client-side JavaScript is invisible to it (and to a raw crawler, which is often the finding that matters). It does not resolve ancestor visibility, so a visible question inside a hidden container can read as visible. Treat a clean result as "nothing obviously wrong", not as proof. This bites hardest on the link check. If a page renders its CTAs in JavaScript, zero flagged links means THIS TOOL COULD NOT SEE THEM — not that the page is clean. A notes entry says so explicitly when no links were found at all. Report that case as PARTIAL, never as a pass.
Read from the server on 2026-09-07, including each tool's own safety annotations.
Frequently asked questions
No. Both requested Google scopes end in readonly, and every one of the ten tools only reads. Submitting a sitemap and requesting indexing are write operations that the server deliberately does not expose, so those remain manual steps in the Search Console interface. An agent using this connector cannot alter your property, your data or your settings.
Because URL Inspection reports Google's stored index state, not a live fetch. The verdict reflects the last crawl, whose date the same response carries, so a fix deployed after that date is not represented yet. Compare the lastCrawlTime field against your deploy date before concluding the tag is still present, or run a live test in the Search Console interface.
Pass a page filter to gsc_search_analytics, because without one the response returns property-wide rows that look page-specific. Verify the filter applied by reading responseAggregationType in the response: it reads byPage when a page filter is active and byProperty when it is not. Numbers returned under byProperty do not belong to the page you asked about.
No, and it is always lower. Search Console withholds low-volume queries for privacy, so the sum of returned rows under-counts real totals. Never present a row sum as total clicks for a property. Use an unfiltered query when you need the property-level figure, and treat per-query breakdowns as a sampled view rather than a complete one.
Only those the signed-in Google account can already reach. gsc_list_sites and ga4_list_properties enumerate them, and calling either first matters because a guessed property returns 403 — the same status a genuine permissions problem returns, making the two indistinguishable. A Search Console domain property and a URL-prefix property are also different properties that return different numbers.
Sources
- Live
tools/listhandshake againsthttps://mcp.agentman.ai/google-search/mcp— 10 tools, 7 September 2026 - Live
prompts/listandresources/listprobes —-32601method not found, 7 September 2026 - The server's own RFC 9728 descriptor at
/.well-known/oauth-protected-resource— two read-only scopes, 7 September 2026
Server Info
- Category
- Marketing
- Developer
- Google Search Console & GA4
- Tools
- 10
- Domain
- mcp.agentman.ai
Using Claude Desktop or another MCP client? Setup docs — the connection URL above works anywhere.
Similar MCP Servers for Marketing
Related Resources
Ready to connect Google Search Console & GA4?
Connect Google Search Console & GA4 once and your agents call these tools on their own — on a schedule, in a workflow, with nobody at the keyboard.