google-surf-mcp-search
Google search MCP server with academic PDF extraction, no API key required, CAPTCHA recovery, and parallel search capabilities
How do I install this agent skill?
npx skills add https://github.com/reason-machines/mcp-skills --skill google-surf-mcp-searchIs this agent skill safe to install?
- Gen Agent Trust Hubwarn
This skill provides Google search and content extraction capabilities for AI agents. It carries security risks typical of web-crawling tools, including susceptibility to indirect prompt injection from malicious websites or PDFs. It also includes configuration options that disable critical security features like the browser sandbox and allow access to private network addresses (SSRF), which should be handled with caution. The software components are downloaded from an unverified third-party repository.
- Socketpass
No alerts
- Snykwarn
Risk: MEDIUM · 2 issues
What does this agent skill do?
google-surf-mcp-search
Skill by ara.so — MCP Skills collection.
What It Does
google-surf-mcp is an MCP server that provides Google search functionality without requiring API keys. It combines three capabilities in one:
- Google search with ad/spam filtering
- URL content extraction (HTML + PDF)
- Academic paper extraction (arXiv, Nature, PubMed, etc.)
Key features:
- Works with actual Google search (not an API wrapper)
- Automatic CAPTCHA recovery with persistent browser profiles
- Parallel search and extraction
- Token-efficient abstract mode for triage
- Built-in rate limiting and caching
- Geometric verification to drop sponsored ads and knowledge panels
Installation
Quick Install (npx)
Add to your MCP client config (e.g., ~/.claude.json for Claude Code):
{
"mcpServers": {
"google-surf": {
"command": "npx",
"args": ["-y", "google-surf-mcp"]
}
}
}
Local Clone Installation
git clone https://github.com/HarimxChoi/google-surf-mcp
cd google-surf-mcp
npm install
npm run build
Config for local installation:
{
"mcpServers": {
"google-surf": {
"command": "node",
"args": ["/absolute/path/to/google-surf-mcp/build/index.js"]
}
}
}
Manual Bootstrap (if auto-bootstrap fails)
npm run bootstrap
With custom paths:
CHROME_PATH=/usr/bin/google-chrome SURF_TZ=America/New_York npm run bootstrap
Available Tools
1. search - Single Google Search
Performs a single Google search, returns filtered results (ads removed).
Parameters:
query(string, required): Search querylimit(number, optional): Max results, default 10
Returns:
results[]: Array of{ title, url, snippet }dropped: Count of filtered results (ads, knowledge panels)dropped_reasons[]: Why items were droppedcache_hit: Boolean indicating cache use
Example Usage:
// Via MCP tool call
{
"query": "typescript async patterns",
"limit": 5
}
Response:
{
"results": [
{
"title": "Async/Await in TypeScript",
"url": "https://example.com/typescript-async",
"snippet": "Learn how to use async/await patterns..."
}
],
"dropped": 2,
"dropped_reasons": ["sponsored", "knowledge_panel"],
"cache_hit": false
}
2. search_parallel - Parallel Multi-Query Search
Execute multiple searches in parallel using a worker pool (max 10 queries).
Parameters:
queries(string[], required): Array of search querieslimit(number, optional): Max results per query, default 10
Returns:
- Array of search results (same format as
search)
Example Usage:
{
"queries": [
"mcp server best practices",
"playwright stealth techniques",
"typescript pdf extraction",
"google search scraping 2026"
],
"limit": 3
}
3. extract - Fetch and Extract Content
Extract text content from a URL (HTML or PDF).
Parameters:
url(string, required): URL to extractmax_chars(number, optional): Character limit, default 100kmode(string, optional):"full"|"abstract"|"metadata"
Modes:
full: Complete article text (HTML via Readability, PDF via unpdf)abstract: ~1500 chars for triage (PDF page 1 or HTML meta description)metadata: PDF page count only
Returns:
content: Extracted text (markdown for HTML)title: Document titleexcerpt: Short summarylength: Character countis_pdf: Booleanpage_count: Number (PDFs only)extraction_quality:"high"|"medium"|"low"
Example Usage:
// Extract full academic paper
{
"url": "https://arxiv.org/pdf/2301.12345.pdf",
"mode": "full"
}
// Quick abstract for triage
{
"url": "https://nature.com/articles/s41586-023-12345-6",
"mode": "abstract",
"max_chars": 2000
}
Response:
{
"content": "# Paper Title\n\nAbstract: This paper presents...",
"title": "Novel Approach to AI Safety",
"excerpt": "This paper presents a novel approach...",
"length": 45678,
"is_pdf": true,
"page_count": 12,
"extraction_quality": "high"
}
4. search_extract - Combined Search + Extract
Search and extract content in one call. Efficiently parallelizes extraction.
Parameters:
query(string, required): Search querylimit(number, optional): Max results to extract, default 5max_chars(number, optional): Per-result char limitmode(string, optional):"abstract"(default) |"full"
Best Practices:
- Use
mode="abstract"(default) for cheap triage with ~1500-char summaries - Use
mode="full"only when you need complete article text (slower, more tokens)
Returns:
results[]: Search results enriched withextracted_content
Example Usage:
// Triage mode (default, token-efficient)
{
"query": "claude mcp server tutorials",
"limit": 5,
"mode": "abstract"
}
// Full extraction (when you need complete content)
{
"query": "machine learning interpretability survey",
"limit": 3,
"mode": "full",
"max_chars": 50000
}
Response:
{
"results": [
{
"title": "Building MCP Servers",
"url": "https://example.com/mcp-tutorial",
"snippet": "Complete guide to MCP servers...",
"extracted_content": {
"content": "# Building MCP Servers\n\nMCP (Model Context Protocol)...",
"title": "Building MCP Servers",
"length": 1523,
"is_pdf": false,
"extraction_quality": "high"
}
}
]
}
5. health - Server Status
Check server health and configuration.
Returns:
status:"healthy"|"degraded"cascade_mode: Current stealth moderate_limiter: Request counts and limitscache_stats: Cache size and hit ratesconfig: Active configuration values
Example Usage:
// No parameters
{}
Configuration
All configuration via environment variables:
Essential Variables
# Chrome binary path (auto-detected if not set)
CHROME_PATH=/usr/bin/google-chrome
# Profile storage (default: ~/.google-surf-mcp)
SURF_PROFILE_ROOT=/custom/path/profiles
# Browser locale and timezone
SURF_LOCALE=en-US
SURF_TZ=America/New_York
Headless & CAPTCHA Recovery
# Run Chrome visibly (for demos/debugging)
SURF_HEADLESS=false
# Remote debugging mode (headless servers)
SURF_REMOTE_DEBUG=true
# Cloud/serverless mode (fail-fast on CAPTCHA)
SURF_CLOUD_MODE=true
Performance Tuning
# Idle close timeout (ms), 0 disables
SURF_IDLE_CLOSE_MS=30000
# Rate limit (requests per minute)
SURF_RATE_LIMIT_PER_MIN=10
# Search cache TTL (ms), 0 disables
SURF_CACHE_TTL_SEARCH_MS=86400000
# Cache LRU size
SURF_CACHE_MAX_ENTRIES=1000
Security
# Allow private IPs in extract (default: false)
SURF_ALLOW_PRIVATE=true
# Ignore TLS errors (auto-on in cloud mode)
SURF_INSECURE_TLS=false
# Disable sandbox (auto-on in cloud mode)
SURF_NO_SANDBOX=false
Advanced
# Disable cascade fallback (pin single mode)
SURF_CASCADE_DISABLED=true
SURF_USE_STEALTH=true
# Humanlike browsing (off | background | inline)
SURF_HUMANLIKE_MODE=background
Common Patterns
Pattern 1: Research Assistant
Search academic papers and extract abstracts for quick review:
// Step 1: Search and triage with abstracts
const triage = await use_mcp_tool("google-surf", "search_extract", {
query: "transformer architecture improvements 2026",
limit: 10,
mode: "abstract"
});
// Step 2: Extract full text for promising papers
const topPapers = triage.results.slice(0, 3);
const fullTexts = await Promise.all(
topPapers.map(paper =>
use_mcp_tool("google-surf", "extract", {
url: paper.url,
mode: "full",
max_chars: 100000
})
)
);
Pattern 2: Parallel Research
Search multiple related topics simultaneously:
const relatedTopics = await use_mcp_tool("google-surf", "search_parallel", {
queries: [
"MCP server authentication patterns",
"MCP server error handling",
"MCP server rate limiting",
"MCP server caching strategies"
],
limit: 5
});
// Process results by topic
relatedTopics.forEach((topicResults, index) => {
console.log(`Topic ${index + 1}:`, topicResults.results.length, "results");
});
Pattern 3: Content Aggregation
Build a comprehensive knowledge base:
// 1. Find relevant sources
const sources = await use_mcp_tool("google-surf", "search", {
query: "typescript best practices 2026",
limit: 20
});
// 2. Extract abstracts to filter quality
const abstracts = await Promise.all(
sources.results.map(result =>
use_mcp_tool("google-surf", "extract", {
url: result.url,
mode: "abstract"
})
)
);
// 3. Full extraction for high-quality sources
const highQuality = abstracts
.filter(a => a.extraction_quality === "high")
.slice(0, 5);
const fullContent = await Promise.all(
highQuality.map(a =>
use_mcp_tool("google-surf", "extract", {
url: a.url,
mode: "full"
})
)
);
Pattern 4: Health Check Before Heavy Operations
// Check server health before batch operations
const health = await use_mcp_tool("google-surf", "health", {});
if (health.status !== "healthy") {
console.warn("Server degraded, reducing concurrency");
}
const rateLimit = health.rate_limiter.requests_per_minute;
if (rateLimit > 8) {
// Wait before starting batch
await sleep(60000);
}
CAPTCHA Recovery Modes
The server handles CAPTCHAs automatically based on environment:
Mode 1: Local Desktop (default)
# No config needed - default behavior
When CAPTCHA appears:
- OS notification fires
- Headed Chrome window opens
- Human solves CAPTCHA
- Call automatically retries
- Profile reputation preserved
Mode 2: Visible Chrome (demos/debugging)
SURF_HEADLESS=false
- Chrome runs visibly at all times
- CAPTCHA recovery skips notification (user is watching)
- Good for demos and debugging
Mode 3: Remote Debugging (headless servers)
SURF_HEADLESS=true
SURF_REMOTE_DEBUG=true
When CAPTCHA appears:
- DevTools port printed to logs
- Error thrown with instructions
- SSH port-forward from local machine
- Open
chrome://inspectlocally - Solve CAPTCHA remotely
- Retry the call
Example SSH forward:
ssh -L 9222:localhost:9222 your-server
Mode 4: Cloud/Serverless (fail-fast)
SURF_CLOUD_MODE=true
- No CAPTCHA recovery
- Throws
CAPTCHA_REQUIREDerror immediately - Worker pool disabled
- Sandbox disabled, TLS bypass enabled
Troubleshooting
Chrome Not Found
Error: Chrome binary not found
Solution:
# Find your Chrome installation
which google-chrome
which chromium
# Set explicitly
CHROME_PATH=/usr/bin/google-chrome npm run bootstrap
CAPTCHA Loops
Symptoms: Repeated CAPTCHA requests
Solutions:
- Run bootstrap to warm the profile:
npm run bootstrap
- Reduce request rate:
SURF_RATE_LIMIT_PER_MIN=5 npx google-surf-mcp
- Check cascade mode:
const health = await use_mcp_tool("google-surf", "health", {});
console.log(health.cascade_mode); // Should cycle: none → stealth → humanlike
Empty or No Results
Check health first:
const health = await use_mcp_tool("google-surf", "health", {});
// Check rate_limiter.requests_per_minute
// Check cache_stats for anomalies
Clear cache if stale:
SURF_CACHE_TTL_SEARCH_MS=0 npx google-surf-mcp
Check dropped reasons:
const results = await use_mcp_tool("google-surf", "search", {
query: "test query"
});
console.log(results.dropped_reasons);
// If all results dropped as "sponsored", selector may be stale
Extraction Failures
PDF extraction fails:
// Try metadata mode first
const meta = await use_mcp_tool("google-surf", "extract", {
url: "https://example.com/paper.pdf",
mode: "metadata"
});
console.log(meta.page_count); // If 0, PDF is inaccessible
SSRF blocked:
# Allow private IPs (only if you control the URLs)
SURF_ALLOW_PRIVATE=true npx google-surf-mcp
Low extraction quality:
const result = await use_mcp_tool("google-surf", "extract", {
url: "https://example.com/article"
});
if (result.extraction_quality === "low") {
// HTML was poorly structured or blocked
// Try fetching directly via other means
}
Performance Issues
Slow first call:
Normal. First call bootstraps the profile (~4s sequential, ~9s parallel). Subsequent calls are faster (~1.5s).
Idle timeout too aggressive:
# Keep contexts warm longer
SURF_IDLE_CLOSE_MS=120000 npx google-surf-mcp
Too many parallel queries:
Limit to 10 per search_parallel call. For more, batch them:
const queries = [...100queries];
const batches = chunk(queries, 10);
for (const batch of batches) {
const results = await use_mcp_tool("google-surf", "search_parallel", {
queries: batch
});
// Process batch
await sleep(5000); // Respect rate limits
}
Academic Sources Supported
Inline PDF extraction for:
- arXiv
- bioRxiv, medRxiv
- Nature, Science, Cell
- OpenReview
- NeurIPS, ICML, ICLR proceedings
- JMLR, PMLR
- Springer
- PubMed (via PMC)
- ACL Anthology
All extracted to markdown-formatted text.
Cache Management
# Disable search caching
SURF_CACHE_TTL_SEARCH_MS=0
# Increase cache size
SURF_CACHE_MAX_ENTRIES=5000
# Custom cache location
SURF_CACHE_ROOT=/tmp/google-surf-cache
Cache namespaces:
search: Google search results (24h TTL default)extract: URL content extractions (no TTL, LRU only)
Rate Limiting
Built-in rate limiter prevents Google blocks:
# Default: 10 requests/minute
SURF_RATE_LIMIT_PER_MIN=10
# Conservative for shared IPs
SURF_RATE_LIMIT_PER_MIN=5
# Aggressive (may trigger CAPTCHAs)
SURF_RATE_LIMIT_PER_MIN=20
Check current usage:
const health = await use_mcp_tool("google-surf", "health", {});
console.log(health.rate_limiter);
// { requests_per_minute: 7, limit: 10, window_start: "2026-05-17T..." }
Best Practices
-
Use abstract mode for triage: Default
search_extracttomode="abstract"to save tokens and time. Only requestmode="full"when needed. -
Batch related queries: Use
search_parallelinstead of sequentialsearchcalls. -
Check health before batch ops: Prevents hitting rate limits mid-batch.
-
Respect cache TTLs: Default 24h for search is sensible. Don't disable unless debugging.
-
Handle extraction failures gracefully: Always check
extraction_qualityand handle{ error }responses. -
Profile warmth: First call of the day may be slower. Acceptable for human-in-the-loop workflows.
-
CAPTCHA strategy: For long-running agents, use
SURF_CLOUD_MODE=falseand solve CAPTCHAs as they appear to preserve profile reputation.
How can the creator link this skill?
Add the canonical catalog link to the repository README so users can inspect current installs and available audits. The publishing guide covers the complete discovery path.
<a href="https://skillzs.dev/skills/reason-machines/mcp-skills/google-surf-mcp-search">View google-surf-mcp-search on skillZs</a>