groundhog
Safe, self-hosted web grounding for AI agents and crawlers — stealth Chrome over MCP
- 1 estrellas
- 0 forks
- 2 issues abiertos
- Lenguaje: Python
- Licencia: MIT
- actualizado
Instalación
local · uvx (python)claude mcp add groundhog -- uvx groundhog-mcp{
"mcpServers": {
"groundhog": {
"command": "uvx",
"args": ["groundhog-mcp"]
}
}
}{
"mcpServers": {
"groundhog": {
"command": "uvx",
"args": ["groundhog-mcp"]
}
}
}- Run the command above in your terminal (Claude Code), or paste the JSON config into claude_desktop_config.json (Claude Desktop).
- Replace any <placeholder> values with your API keys or paths.
- Restart Claude. The MCP server and its tools appear automatically.
Resumen de MCP Servers
Groundhog
Web search, read and research for AI agents, through a real, stealth-patched Chrome. Groundhog is an MCP server that returns clean Markdown a model can trust: text no human could see is stripped before the model reads it and reported, every source comes with a provenance receipt, and a real browser reads pages that block plain fetchers.
agent / crawler ──MCP──▶ Groundhog (search, read_url, research) ──CDP──▶ stealth Chrome ──▶ the webMeasured against other fetch layers
Twenty-eight pages carry text a human can't see, and three controls carry none. A case passes when the payload doesn't reach the model and the article text still does.
| contained | kept the article | reported it | false positives | |
|---|---|---|---|---|
requests + trafilatura | 25/28 | 28/28 | 0/28 | 0/3 |
| Scrapling (HTTP) | 16/28 | 28/28 | 0/28 | 0/3 |
| Jina Reader | 15/28 | 28/28 | 0/28 | 0/3 |
| Firecrawl | 7/28 | 28/28 | 0/28 | 0/3 |
| Groundhog | 28/28 | 28/28 | 25/28 | 0/3 |
Other extractors often drop hidden text by accident, but none of them tells the caller
anything was removed. The three cases Groundhog doesn't report (a hidden input value, a meta
description, an iframe srcdoc) never reach any extractor. The corpus is public at
dmytrome.github.io/groundhog; the harness and its
limits are in benchmark/.
Quick start
Claude Code:
claude mcp add groundhog -- uvx groundhog-mcpClaude Desktop, Cursor, Windsurf:
{
"mcpServers": {
"groundhog": {
"command": "uvx",
"args": ["groundhog-mcp"]
}
}
}On the first fetch Groundhog starts the Chrome you already have, headless, in its own
profile at ~/.groundhog/chrome. Your own browsing, tabs and logins are never touched. If
Chrome is missing, status and the error say what to install.
GROUNDHOG_BROWSER=stealth runs the hardened browser container instead (Docker or Podman;
the first pull takes a few minutes). To run it yourself:
docker run -d --rm --name groundhog-browser --shm-size 512m \
-p 127.0.0.1:9222:9222 -- ghcr.io/dmytrome/groundhog:latestCDP_URL points Groundhog at any browser and is used as given: http:// is probed for
/json/version, ws:// or wss:// (what hosted browsers hand out) is connected to directly.
Auto-start only runs for a local address that isn't answering, and
GROUNDHOG_AUTO_START_BROWSER=false turns it off. From source: cd mcp && uv sync && uv run groundhog-mcp.
All four tools are annotated readOnlyHint: they write nothing and change no remote state.
The one side effect is auto-start, which may launch Chrome or, with stealth, run the
container after removing an unreachable one named groundhog-browser.
What makes it different
Hidden text is stripped and reported. A rendered DOM shows what a human would see; everything else goes, and each removal is listed in
threats. It's a strong heuristic, not a proof: see the limits.Every source carries a receipt: a SHA-256 of the extracted content, canonical URL, language, word count, and author and date when the page declares them.
Safe by default. An SSRF guard checks every document request, redirects and frames included, with per-domain rate limiting. See Security.
No automation tell. Groundhog drives Chrome over raw CDP and never enables the
Runtimedomain that anti-bots detect in Puppeteer, Playwright and Selenium.A real fingerprint. Real Chrome means real TLS, HTTP/2, WebGL and canvas. In headless mode the
HeadlessChrometoken is replaced and client hints are copied from the browser; shared and service workers aren't covered. The stealth image runs headful under Xvfb.No model, no API key.
researchreturns extracts and your agent does the synthesis.
Tools
read_url(url, format="markdown", max_tokens=None, query=None, include_hidden=False)
| Key | Meaning |
|---|---|
markdown | Extracted content, article first, falling back to the rendered text inside a code fence, so none of it reads as markdown; format may be markdown or text |
title | Page title |
url | The URL you asked for |
final_url | The URL after redirects, re-checked by the SSRF guard. If unusable, the requested URL is reported with a final_url_suppressed threat |
fetched_at | UTC ISO-8601 timestamp |
status | ok, or challenge / blocked / rate_limited / not_found / server_error / unsupported_content when what came back isn't the page you asked for. blocked covers 401, 403 and other 4xx error pages. empty means the rendered page showed no text a reader would see (text in closed shadow roots, iframes and alt attributes doesn't count), whatever markdown holds. With include_hidden, text hidden by styling counts as shown; invisible characters never do. unknown means no usable status was observed. Judged on the document the text came from, after client-side redirects |
http_status | The top-level HTTP status, or null |
truncated | Whether the token budget cut the content |
threats | What was stripped; empty when nothing was found |
matches | With query: ranked passages with id, heading, offset, end and score |
set_aside | With query: scoring passages the relevance floor dropped |
provenance | Content hash, canonical URL, language, word count, author and date |
Stripped by default: display:none, visibility:hidden, content-visibility:hidden,
opacity ≤ 0.05, font-size < 4px, zero-size and display:contents boxes that render
nothing, .sr-only-style sub-pixel boxes, clip: rect(...), transparent or
background-coloured text, off-page positioning, collapsed , content,
long alt / aria-label / aria-description / title text, and zero-width, bidi and
Unicode Tag characters. HTML comments are reported too. include_hidden=True keeps the text
but still reports it.
Treat threats as untrusted: its excerpts are page-authored text, cleaned and length-capped.
type | Carries |
|---|---|
hidden_css | The hiding reason, an 80-character excerpt and the DOM location |
hidden_attribute | The same, for text in an alt, aria-label, aria-description or title attribute |
hidden_template | The same, for text inside a `` |
zero_width / bidi / tag | A codepoint and count in reason, detected on the served text |
report_truncated | How many entries the cap dropped |
final_url_suppressed | The page's final URL was unusable and not returned |
detection_degraded | Detection ran in the page's own JavaScript world, which the page can tamper with |
strip_incomplete | The text was rebuilt from markup rather than layout, usually because of open shadow roots |
At most 50 findings per page are returned (10 per source in research), with the two classes
capped separately so decoys can't bury a real payload. Notices are appended after the cap.
query swaps head-truncation for BM25 passage ranking on the sanitized content, keeping
passages within half the best score up to the budget.
search(query, limit=10)
Returns hits (title, url, snippet, engine, score, published) and the backend
that answered. Nothing is fetched. With SEARXNG_URL set it uses your
SearXNG instance, which needs formats: [html, json]; otherwise
it renders a search page through the browser. Hit text is cleaned and capped, and a hit whose
URL would change under cleaning, isn't http(s), carries credentials or exceeds 2048
characters is dropped. A backend that can't answer raises an error instead of returning an
empty web.
research(query, max_sources=5, max_tokens=None, include_domains=None, exclude_domains=None, published_after=None, aim=None)
Searches, reads the top sources and ranks passages from all of them in one pass.
passages:id,text,source_url,heading,score,start,end,clamped,fence.textis exactlymarkdown[start:end]unlessclamped. A passage cut from a long code block carries the block's opening line infence: reopen with it whentextdoesn't start with it, and close the block whentextdoesn't end with a closing fence.idstays stable while the page doesn't change.sources:url,title,status(ok/blocked/timeout/error),page_status(as inread_url),threats,provenance,filtered. A failed source doesn't fail the call. A challenge, an error page, anemptypage or any page whosemarkdownis blank counts asnot_contentand contributes no passages.One page per registrable domain unless
include_domainsis set, and then no more pages per site thanGROUNDHOG_MAX_CONCURRENT_PAGES;max_sourcesgoes up to 10.
include_domains reads only those domains and their subdomains, exclude_domains never
reads them, and published_after (YYYY-MM-DD) drops pages dated earlier. Up to 8 domains
can be included and 50 excluded. A page that redirects into an excluded domain or out of the
included ones, is dated too early, or repeats the URL or text of a page already used is listed
with filtered and contributes no passages. The query sent to the engine names at most eight
domains; further excluded ones are filtered after the search. aim (up to 200 characters)
Lo que la gente pregunta sobre groundhog
¿Qué es dmytrome/groundhog?
dmytrome/groundhog es mcp servers para el ecosistema de Claude AI. Safe, self-hosted web grounding for AI agents and crawlers — stealth Chrome over MCP Tiene 1 estrellas en GitHub y su última actualización registrada es del 2026-10-23.
¿Cómo se instala groundhog?
Puedes instalar groundhog clonando el repositorio (https://github.com/dmytrome/groundhog) o siguiendo las instrucciones del README en GitHub. ClaudeWave también te ofrece bloques de instalación rápida en esta misma página.
¿Es seguro usar dmytrome/groundhog?
Nuestro agente de seguridad ha analizado dmytrome/groundhog y le ha asignado un Trust Score de 95/100 (tier: Verified). Revisa el desglose completo de comprobaciones superadas y flags en esta página.
¿Quién mantiene dmytrome/groundhog?
dmytrome/groundhog es mantenido por dmytrome. La última actividad registrada en GitHub es del 2026-10-23, con 2 issues abiertos.
¿Hay alternativas a groundhog?
Sí. En ClaudeWave puedes explorar mcp servers similares en /categories/mcp, ordenados por popularidad o actividad reciente.