google-search-mcp
This server provides MCP tools for personalized, ad-free Google searches and web page retrieval through a dedicated logged-in browser profile, with full access to advanced operators.
google_search: Perform advanced searches with operators like
site:,filetype:, exact phrases, date ranges (before:,after:,freshness), verbatim mode, and country/language bias. Choose from web, news, videos, images, etc. Paginate up to 5 pages (10 results each). Optionally fetch and attach full article content as markdown, handling JS-rendered pages, soft paywalls, and cookie-walled articles. Personalization can be toggled on/off.google_multi_search: Run multiple related queries in a single call, amortizing browser launch cost. Executes sequentially to avoid anti-bot detection and stops early on rate limiting.
google_fetch: Fetch up to 5 arbitrary URLs per call, rendered by a real browser to handle dynamic content and paywalls. Boilerplate is stripped, returning only article body as markdown with configurable character limit.
google_ai_mode: Retrieve Google's AI-generated answers along with citations. The prose should be treated as a lead; focus on the citations for reliability. Gracefully handles unavailability.
google_session_status: Check the login state and active account of the dedicated browser profile to confirm personalization is active.
Deployment as a single HTTP server supports multiple clients with safe queuing and a shared browser profile. Designed to counter anti-bot measures by stripping automation flags and requiring a residential IP, with structured error indicators (auth_expired, schema_drift, rate_limited).
Provides MCP tools for Google Search, including advanced operators, personalized results, multiple verticals, and reading pages through a logged-in browser.
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., "@google-search-mcpsearch for 'MCP stateless server migration' and fetch the first result"
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.
google-search-mcp
MCP tools over Google Search, through a dedicated logged-in browser profile. Personalized organic results, ads stripped, the full advanced-operator surface, and pagination.
Published on PyPI as gsearch-mcp (google-search-mcp was already taken, by an
unrelated Custom Search API wrapper). Import package and repo keep the longer name.
Three-layer shape: all site knowledge in client.py, a CLI that mirrors the tools 1:1 as the
debugging surface, and a thin MCP wrapper.
Why this exists
No official Google Search API serves this intent. The Custom Search JSON API returns results from a configured subset of the web with no personalization, is closed to new customers, and sunsets 1 Jan 2027. That is a §0 Q1 negative on all three sub-questions.
What you get that a keyword search API does not:
The advanced-operator surface —
site:,filetype:, exact phrase, exclusions,before:/after:bounds, freshness windows down to the past hour, verbatim (no synonyms or stemming), every Google vertical, region and language bias. All server-side, all free once the transport works. This is the strongest reason to use it; no keyword API has an equivalent.Better sources on technical queries. Measured head-to-head against the harness
WebSearchand the Brave API onMCP stateless server migration: this returned the Google and Cloudflare engineering blogs, the spec's own GitHub issue and the Spring docs, where both alternatives returned a page of SEO blogspam paraphrasing the same announcement. Full comparison indocs/ROADMAP.md.Personalized ranking. Measured at ~3.4× the run-to-run noise floor: disabling it moved roughly a third of the top-10. Qualitatively it resolves ambiguous technical queries toward the domain sense —
springreturns Spring Framework rather than the film,mcp serverreturns Cloudflare's engineering blog rather than a content farm. Full method and caveats in~/dev/google-search-recon/RESULT.md.Ads stripped structurally, before the agent sees them.
Related MCP server: SearchMCP
Setup
No checkout needed. Sign in once, then point your MCP client at it.
uvx --from gsearch-mcp gsearch loginlogin opens a window; it downloads a browser first if you have neither Chrome nor
Playwright's Chromium. Sign in to the account you want searches personalized to. The window
closes itself once the sign-in lands. This profile is separate from your Chrome, so
Chrome's /u/0 default does not apply — whatever you sign in as here is what gets used,
deliberately. Check with uvx --from gsearch-mcp gsearch status, which reads the account off
the page rather than assuming it.
Signed out still works; it just returns the neutral, unpersonalized view.
Then, in your MCP client's config:
{
"mcpServers": {
"google-search": {
"type": "stdio",
"command": "uvx",
"args": ["gsearch-mcp"]
}
}
}That entry is the same on every OS. Nothing in it is a path.
Bring your own account
There is no API key. The credential is a Google account you sign into once, and the tool
uses whatever that is — so results are personalized to your history, not to a service
account's. Run gsearch login again to switch accounts.
Several agents on one box each want their own profile, because Chromium takes an exclusive lock on a profile directory and two agents sharing one will collide:
GOOGLE_MCP_PROFILE=agent uvx --from gsearch-mcp gsearch loginthen set "env": {"GOOGLE_MCP_PROFILE": "agent"} on that client's server entry.
Environment
var | default | what it does |
|
| which signed-in profile to use; one per agent |
| per-OS user data dir | where profiles live |
| the host's | browser locale, e.g. |
| the host's | browser timezone, e.g. |
|
| headless is a different fingerprint; verify against |
|
| park the window offscreen instead of taking over the desktop |
|
|
|
|
| http transport only |
|
| http transport only |
Profiles default to %LOCALAPPDATA%\gsearch-mcp\profiles on Windows,
~/Library/Application Support/gsearch-mcp/profiles on macOS, and
$XDG_DATA_HOME/gsearch-mcp/profiles on Linux. They are deliberately not stored next to
the code: under uvx that location is rebuilt on every version bump, and a session kept
there would vanish on upgrade and report itself as a login failure.
Use
uvx --from gsearch-mcp gsearch status
uvx --from gsearch-mcp gsearch search "model context protocol" --site modelcontextprotocol.io
uvx --from gsearch-mcp gsearch search "agent harness" --freshness week --no-personalized
uvx --from gsearch-mcp gsearch multi-search "mcp spec" "mcp security" "mcp transports"As an MCP server (stdio): gsearch-mcp.
One server, many agents
The profile is exclusive. Chromium takes an exclusive lock on a user-data-dir, and the
browser is launched on first use and held until the process exits -- so under stdio, where
every client spawns its own server, the first agent to search keeps the profile for its
whole lifetime and every other agent gets rate_limited. Measured 2026-08-11: one client
held it from 19:15 to 21:53, releasing only when that client exited.
Run one server and point every client at it:
GOOGLE_MCP_TRANSPORT=http gsearch-mcpthen register it as a URL server rather than a command, e.g.
claude mcp add --transport http google-search http://127.0.0.1:8766/mcpFunnelling concurrent callers into one process is safe by construction: every browser call
goes through session.in_browser_thread, a single-worker executor, so requests queue
instead of colliding. Verified with two simultaneous clients -- both returned results, no
rate_limited, finishing at 2.0s and 7.5s. Sequential service is what the anti-bot side
wants anyway, which is why google_multi_search is deliberately serial.
The alternative, one profile per agent via GOOGLE_MCP_PROFILE, costs a gsearch login
each, a browser each, and more query volume from a single exit IP -- which is what draws
/sorry/.
From a checkout
uv venv --python 3.12
uv pip install -e ".[dev]"
.venv/Scripts/python.exe -m google_search_mcp.cli loginA checkout keeps its profiles in a repo-local .session/ if that directory already exists,
so an existing signed-in profile keeps working after upgrading to a packaged install.
tool | what it is for |
| one query, ads stripped, full operator surface, every vertical |
| several queries through one warmed browser — the compound tool |
| read pages as markdown through the logged-in browser |
| Google's AI Mode answer + citations. Unreliable — see below |
| whether the profile is signed in, and as whom; the poll surface for a started login |
| ⚠️ opens a sign-in window on the user's screen and returns immediately. Attended contexts only |
google_initiate_login is gsearch login reached from an agent: it spawns that same command
as a detached child and returns a state in under a second, because a tool call that waits for
a person to type a password and a 2FA code is indistinguishable, from the agent's side, from a
hung server. Poll google_session_status for the outcome — login_in_progress, then
signed_in or signed_out. It is single-flighted, so a second call reports the first rather
than opening a second window.
The cost to know before calling it: while that window is open, every search on the box is
paused. Chromium locks a profile directory exclusively, so the server has to let go of the
browser for the login window to take it, and one server backs every agent session (below). All
four search tools return rate_limited until the login finishes or is abandoned.
Reading pages
google_search(..., with_content=True) attaches the top results' article text as markdown,
and google_fetch does it for arbitrary URLs. Both go through the same warmed, logged-in
Chrome, which is the point: it reads JS-rendered apps, soft paywalls and cookie-walled
articles that a plain HTTP fetch cannot. For a static public page an ordinary fetch is
cheaper and you should use one.
The browser renders; trafilatura strips the boilerplate. Nav, footers, cookie banners and related-story rails go; headings, lists, tables and code fences survive. Markdown rather than plain text because on a technical page the structure carries most of the meaning, and it still costs far fewer tokens than the HTML.
Measured 2026-08-07, whole article against the raw DOM it came from:
page | raw HTML | markdown | |
| 615,709 | 18,093 | 2.9% |
| 294,995 | 4,708 | 1.6% |
Roughly a 30–60× reduction before truncation even applies.
There is no cached copy to read instead. Google retired its page cache on 2 Feb 2024 —
cache: and webcache.googleusercontent.com are both gone. The Wayback Machine is the only
general cache left and it is the wrong source here: it would serve months-old text to a tool
whose entire edge is recency. Live fetch is fresher and more capable.
Bounded by default (3 results, 2000 chars each, 5 URLs per google_fetch) because unbounded
this is a crawler, and each page is a real load — budget a few seconds per result.
Verticals
Each one renders differently and each names its own extractor. Counts below are live, 2026-08-07, on the same query.
|
| anchor | notes |
| — |
| the default SERP, rich blocks included |
|
|
| the "Web" tab. Cleanest for research — 17 external anchors against 56 on the default SERP |
|
|
| every result carries a date |
|
|
| |
|
|
| |
|
|
| results are google-hosted by nature |
|
|
| single page; title comes from the anchor, not |
shopping (udm=28) is deliberately unmapped: it renders product cards with no
external anchors and no headings, so there is nothing for a link-and-snippet projection to
return. Shipping it would mean advertising a vertical that always yields zero.
Why not one selector for all of them. Broadening the anchor to [role="heading"]
everywhere looks like the obvious fix and quietly breaks the ad guarantee. On
hotel berlin buchen, a h3 found 10 results with 0 inside an ad container, while
a [role="heading"] found 2 — both of them ads. It fails invisibly, because on a
technical query the same selector returns 7 with no ads at all. So web keeps a h3 and
its structural guarantee, and on role-anchored verticals the ad-container filter is
load-bearing rather than defence-in-depth.
AI Mode
google_ai_mode returns Google's generated answer and its citations. Treat the answer as
a lead, never as a fact. It is hit or miss, confidently wrong in the same voice it is
right, and not authoritative even about Google's own products — which is the trap, since
those are the queries where it reads most credible. The citations are the part worth
keeping; read them and believe those.
Absence is normal, not a failure: it is not offered for every query, region or account, and
returns available: false with a reason rather than an error. Slower than a search — the
answer streams and is polled until it stops growing (~4s typical, 20s cap).
Cost model
The first call in a process launches a browser and warms the profile (~10s). Each page after
that is one throttled load (4–7s). Pages are 10 results and depth costs a round trip —
Google stopped honouring num= on 11 Sept 2025. Prefer google_multi_search over several
google_search calls; it amortises the launch across the set.
google_ai_mode costs more: the answer streams, so it is polled until the text stops
growing — typically ~4–8s on top of the page load, capped at 20s.
Profiles take an exclusive lock. Chromium locks a user-data-dir, so Claude Code, pi and
a dispatch worker cannot share one. Give each consumer its own: set GOOGLE_MCP_PROFILE and
run cli login once for that name. A collision surfaces as rate_limited with a message
naming the real cause, because the correct response genuinely is back off and retry.
Transport, and the one flag that matters
ignore_default_args=["--enable-automation"]. Measured 2026-08-07 on a residential IP:
vehicle | result |
bundled Chromium, flag present |
|
bundled Chromium, flag stripped | OK |
real Chrome ( | OK |
any vehicle over a VPN | CAPTCHA |
playwright-stealth and full behavioural realism did not substitute for it. A residential
exit IP is required regardless of vehicle. Chrome does not need to be installed — bundled
Chromium passes on its own with the flag stripped, so this runs on pi or any other box.
Environment: GOOGLE_MCP_PROFILE (default default), GOOGLE_MCP_HEADLESS (default 0),
GOOGLE_MCP_OFFSCREEN (default 1, parks the window at -2400,-2400).
Errors
Failing results carry a kind field (paradigm §3.1): auth_expired (sign in, never retry),
schema_drift (extractor stale, never retry, flag it), rate_limited (back off),
bad_argument (fix the call, never retry unchanged).
auth_expired also carries its remedy as a field rather than as prose to be regex'd —
detail.login_tool: "google_initiate_login". Staying strict about auth (never falling back,
never silently driving a browser) only stays useful if the envelope names the next move.
empty is not an error — a query matching nothing returns count: 0 with no kind.
Neither is an absent AI Mode answer, which returns available: false with a reason.
schema_drift is the expected long-run failure mode here: Google's SERP markup is obfuscated
and rotates by design. When it fires, the extractor in client.py::EXTRACT_JS needs updating,
and docs/API.md's field-semantics section records the traps that make that quick.
Legal
Automated querying of google.com/search is contrary to Google's ToS. Recorded as an owner
decision in docs/API.md: read-only, sequential, throttled, personal-scale, no republication.
The session profile is gitignored and is never copied, attached, or handed to another agent.
Available Tools
5 toolsgoogle_ai_modeA
Google's AI Mode answer for a query, with the sources it cites.
The answer is unreliable. Treat it as a lead, never as a fact. It is hit or miss, it is confidently wrong at the same tone it is right, and it is not authoritative even about Google's own products -- which is the trap, because those are exactly the queries where it reads most credible. Nothing from here should reach a user, a document or a decision without being confirmed against a real source.
The citations are the valuable part; the prose is a map to them. Normal use is: read
this for orientation on an unfamiliar topic, then google_search for the primary
sources and believe those instead. For anything load-bearing, skip this tool.
Absence is normal. AI Mode is not offered for every query, region or account. When
it is not there you get available: False and a reason, NOT an error and NOT
schema_drift -- so do not retry the same query hoping for a different shape.
Slower than a search: the answer streams, and this polls until it stops growing (typically ~4s, capped at 20s).
| Name | Required | Description | Default |
|---|---|---|---|
| lang | No | ||
| query | Yes | ||
| country | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries full burden and excels. It discloses unreliability, confident wrongness, the risk of false authority on Google products, the meaning of absent results (available: False vs error/schema_drift), and the slower streaming/polling behavior. This is far beyond a generic tool disclaimer.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is longer than necessary but every paragraph and warning earns its place. It is front-loaded with the core purpose, then structured warnings, normal-use pattern, absence behavior, and latency. Bolded headings aid scannability. Slight verbosity prevents a 5.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given no output schema and no annotations, the description is remarkably complete. It conveys what the response contains (answer + citations), how to interpret the answer, what absence looks like, and latency expectations. The tool's complexity is high, and the description covers the key edge cases (missing availability, unreliability, comparison to sibling tool) without needing structured output docs.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description must compensate for parameter ambiguity. While 'query' is implicitly described, there is no explanation of the lang or country parameters, their allowed values, defaults, or how they affect results. The mention of region/account relates to availability, not parameter semantics, leaving optional parameters under-specified.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool returns Google's AI Mode answer with citations, using a specific verb ('answer') and distinct resource. It distinguishes itself from google_search by positioning AI Mode as an unreliable lead-generation tool, and it explicitly names google_search as the alternative for authoritative sources.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit usage guidance: use for orientation on unfamiliar topics, then follow up with google_search for primary sources, and skip for anything load-bearing. It clearly states when not to use it and names the alternative tool, satisfying the highest bar for this dimension.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
google_fetchA
Read web pages as markdown, through the warmed logged-in browser.
Use this instead of a plain HTTP fetch when the page needs a real browser: JS-rendered apps, soft paywalls, cookie-walled articles, anything behind the Google login. That capability is the whole point -- for a static public page an ordinary fetch is cheaper.
Boilerplate (nav, footers, cookie banners, related-story rails) is stripped and only the article body comes back, so the payload is a fraction of the raw HTML. Output is markdown, which keeps headings, lists and code fences intact.
Capped at 5 URLs per call and read sequentially with per-host throttling -- this is a
real browser making real requests. max_chars truncates each page on a paragraph
boundary and sets truncated with the full length in chars_total.
A page that cannot be read comes back with ok: false and a reason rather than
sinking the call.
| Name | Required | Description | Default |
|---|---|---|---|
| urls | Yes | ||
| max_chars | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It discloses boilerplate stripping, markdown output, 5-URL cap, sequential reading with throttling, max_chars truncation behavior (paragraph boundary, `truncated` and `chars_total` fields), and error handling (`ok: false`). This is rich behavioral detail that goes far beyond what the schema reveals.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is appropriately sized, with each paragraph serving a distinct purpose: purpose, usage guidance, output behavior, limits/parameters, error handling. It is front-loaded with the core purpose and every sentence contributes value. No fluff or redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with no annotations, no output schema, and underspecified parameters, the description covers all essential aspects: purpose, usage boundaries, output format, limits, parameter behavior, and failure modes. It is complete enough for an agent to select and invoke the tool correctly without additional context.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema has 0% description coverage, so the description must compensate. It does: `urls` is implicitly defined as the web pages to read, and `max_chars` is fully explained (truncates on paragraph boundary, sets `truncated`/`chars_total`). The cap of 5 URLs also adds meaning to the `urls` parameter. Both parameters are semantically clarified.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource ('Read web pages as markdown') and immediately distinguishes itself from ordinary HTTP fetch and sibling tools by clarifying its unique value (browser-based fetching for JS-rendered, paywalled, or logged-in content). The purpose is unmistakable and distinctive.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states when to use this tool instead of a plain HTTP fetch ('JS-rendered apps, soft paywalls, cookie-walled articles') and when not to ('for a static public page an ordinary fetch is cheaper'). This is a textbook example of when/when-not usage guidance with a named alternative.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
google_multi_searchA
Run several related queries in one call. Prefer this when researching a topic.
Google makes you search, read ten results, then search again -- and every separate tool call otherwise pays the browser launch and warm-up again. This amortises that across the whole set.
Runs sequentially on purpose: concurrent requests are exactly what Google's anti-bot watches for, so the win here is the shared warm browser, not parallelism. Budget roughly 5-7 seconds per query after the first.
One failing query does not sink the call -- failures land in errors keyed by query,
and the rest still return. A rate_limited stops the run early rather than hammering.
| Name | Required | Description | Default |
|---|---|---|---|
| pages | No | ||
| queries | Yes | ||
| personalized | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations available, the description fully carries the behavioral transparency burden. It discloses sequential execution, anti-bot reasons, approximate timing, failure isolation via an 'errors' key, and early stop on rate_limited. This is rich, non-obvious behavioral detail that goes far beyond a simple operation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the core purpose, then efficiently delivers rationale, behavior, performance expectations, and failure handling. Each paragraph earns its place, with no fluff or redundancy. The structure is logical and scannable.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers purpose, usage, performance, sequencing, and error handling, which is substantial for a multi-search tool. However, it omits any description of the successful return value (e.g., result format) and leaves 'pages' and 'personalized' undefined. Given there is no output schema, these gaps slightly detract from completeness, though the overall context is strong.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema provides only names/types/defaults for 'queries', 'pages', and 'personalized', with 0% description coverage. The description mentions 'queries' only in passing and does not explain the meaning or usage of 'pages' or 'personalized'. Parameters are left ambiguous, and the description fails to compensate for the schema's lack of detail.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Run several related queries in one call.' It clearly distinguishes from sibling google_search by stating 'Prefer this when researching a topic' and explaining the multi-query nature. This is a clear, differentiated purpose.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit guidance on when to use this tool ('Prefer this when researching a topic') and explains the benefit over repeated single searches. It also clarifies the deliberate sequential execution and its rationale, giving agents a clear decision framework and behavioral expectations.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
google_searchA
Search Google. Ads stripped; results are {rank, title, url, host, snippet, date}.
Use the structured arguments rather than typing operators into query -- they
assemble the correct syntax for you:
site='arxiv.org' restrict to one domain filetype='pdf' only PDFs exact='model context protocol' quoted phrase, must appear verbatim exclude=['tutorial'] drop results containing a term after='2026-01-01' published after a date (before= for the other bound) freshness='week' hour | day | week | month | year verbatim=True no synonyms or stemming; the words as typed strict_dates=True apply before/after as Tools > Custom range instead of as query operators (index date rather than document date) country='de', lang='de' region and language bias personalized=False the neutral view, no account history applied
vertical selects which Google tab to read:
web the default SERP, including rich blocks
web_only the "Web" tab -- plain links, no rich blocks. Cleanest for research;
measured 17 external anchors against 56 on the default SERP.
news news, with dates
videos video results
short_videos the shorts feed
books Google Books (results are google-hosted by nature)
images the image grid; single page, title comes from alt text
date is populated where Google shows one ("2 days ago", "28 Jul 2026") and is null
otherwise. total_matches is Google's own estimate for the whole query, not the
number returned.
with_content=True also READS the top content_top_n results and attaches each as
markdown on result.content, saving a fetch round trip per link. It goes through the
same logged-in browser, so it reads JS-rendered pages and soft paywalls that a plain
HTTP fetch cannot. Costs a real page load each -- budget a few seconds per result, and
raise content_chars (default 2000) only when you actually need the whole article.
A page that could not be read sets content: null and content_error.
pages is 10 results each, max 5, and each page is a separate round trip -- ask for
depth only when you actually need it. Ignored for images.
On failure the result carries a kind field: auth_expired (sign in), schema_drift
(the extractor is stale, do not retry), rate_limited (back off). An empty result set
is NOT an error -- it returns count=0 with no kind, and means Google matched nothing.
| Name | Required | Description | Default |
|---|---|---|---|
| lang | No | ||
| site | No | ||
| after | No | ||
| exact | No | ||
| pages | No | ||
| query | Yes | ||
| before | No | ||
| country | No | ||
| exclude | No | ||
| filetype | No | ||
| verbatim | No | ||
| vertical | No | web | |
| freshness | No | ||
| personalized | No | ||
| strict_dates | No | ||
| with_content | No | ||
| content_chars | No | ||
| content_top_n | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description bears the full burden and excels. It discloses failure kinds (auth_expired, schema_drift, rate_limited), cost of with_content (page loads), behavior of strict_dates vs query operators, empty result sets not being errors, and the neutral view for personalized=False. This is exceptionally transparent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but deliberately organized: opening summary, argument examples with syntax hints, vertical list, and performance/failure notes. Each paragraph and bullet earns its place; nothing is redundant. The most important facts (what it does, return shape) are front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with 18 parameters, no output schema, and no annotations, this description is remarkably complete. It covers output fields, pagination, date behavior, error kinds, cost/performance trade-offs, and even distinguishes total_matches from returned count. There is no significant missing context.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description must explain all 18 parameters—and it does. It provides examples for site, filetype, exact, exclude, before/after, freshness, verbatim, strict_dates, country, lang, personalized, and details each vertical value. It also explains pages, content_chars, and content_top_n with caveats. This fully compensates for the bare schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb ('Search Google'), names the resource, and states the output format ('results are {rank, title, url, host, snippet, date}'). It also notes ads are stripped, clearly distinguishing it from sibling tools like google_multi_search or google_fetch. This is a model of purpose clarity.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives abundant usage context: structured arguments instead of operators, recommended 'web_only' for research, 'ask for depth only when you actually need it', and budget warnings for with_content. However, it never explicitly contrasts with sibling tools (e.g., when to use google_multi_search instead), so it stops short of full exclusion guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
google_session_statusA
Whether the dedicated profile has a live Google session, and which account it is.
Worth calling once before relying on personalization: signed out still works, it just returns the neutral (unpersonalized) view. The account is read off the page rather than assumed, because "whoever was signed in" is not a safe default on a box with more than one Google account.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description fully carries the behavioral disclosure burden. It explains that the account is read off the page rather than assumed, and that a signed-out session produces a neutral/unpersonalized view. This transparently describes key behaviors without contradiction.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise yet information-dense: it front-loads the purpose, then adds usage guidance, and finishes with a behavioral nuance about account detection. Every sentence earns its place without unnecessary fluff.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Despite lacking an output schema, the description effectively communicates what the tool returns: session status, account identity, and the neutral view for signed-out states. For a simple status-check tool, this is complete and actionable without needing to enumerate return fields.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so the schema is complete with 100% coverage. The description does not need to explain parameter semantics; the baseline of 4 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool reports whether the dedicated profile has a live Google session and which account it is. This is a specific status-checking verb+resource, and it is immediately distinguishable from sibling tools that search, fetch, or modify.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly advises calling this tool before relying on personalization, and explains that a signed-out state still works by returning a neutral view. This provides clear when-to-use guidance and practical context, even without explicitly naming alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
5 tool updates
v0.1.0- First observed
google_ai_mode - First observed
google_fetch - First observed
google_multi_search - First observed
google_search - First observed
google_session_status
TDQS
Scored across 5 tools
Each tool serves a distinct purpose: session status, single search, page fetch, AI mode, and batch search. google_search and google_multi_search overlap in search capability, but the latter is explicitly framed as a batching tool for research, so agents can select appropriately.
All tools share the google_ prefix and are descriptively named, but the second part mixes verbs (search, fetch), nouns (session_status, ai_mode), and a compound (multi_search). This minor inconsistency doesn't obscure meaning.
Five tools is well-scoped for a search-focused server: it covers the core operations without redundancy or bloat. Each tool addresses a specific need, from session verification to batch research.
The set covers the complete search workflow: verify session, search across verticals, fetch full page content, get AI-generated overviews, and run multiple queries in one call. No obvious gaps for the stated purpose.
Maintenance
Related MCP Connectors
MCP server for Google search results via SERP API
Official SerpApi MCP server for Google, Bing, and other search engines.
Docs: https://docs.keenable.ai/mcp-server Keenable is a free, remote MCP server that gives agents access to the web index. Search the web with ranked results and date/site filters, then fetch any indexed page as clean markdown. Works out of the box with no account or API key.
Serper MCP — wraps the Serper Google Search API (serper.dev)
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceMCP server for internet search via direct Google and DuckDuckGo HTML scraping with AI-powered result normalization and optional summarization, requiring no API keys for search.MIT
- AlicenseAqualityDmaintenanceA privacy-focused web search and content extraction MCP server. It integrates SearxNG with fallback to Google scraping, featuring relevance ranking, security-aware search, and rate limiting.3MIT
- AlicenseNot gradedqualityCmaintenanceAn MCP server that aggregates web search results from multiple engines and optionally renders pages to Markdown, providing a unified search interface.7 npm3ISC
- AlicenseAqualityFmaintenanceMCP server for web search powered by Google AI Mode (Gemini). Enables any AI agent to search the web in real-time for free and without rate limits.2182MIT