searchpin
Searchpin is a self-hosted, zero-API-key web search and page-fetch server for AI agents, with multi-engine search, semantic re-ranking, and clean content extraction.
web_search: searches Baidu, Sogou, Bing CN, and Bing Intl in parallel and returns ranked titles, URLs, and snippets.Supports
general/newssearch topics, freshness filters (d,w,m,y), result limits, and include/exclude domain filters.Re-ranks merged results by embedding similarity to improve relevance and support cross-source verification.
web_fetch: fetches URLs and returns clean extracted text with boilerplate, ads, and navigation removed.Handles modern SSR pages, extracts JSON-LD/microdata, and detects/extracts PDF text locally with size/page/text limits and explicit errors for unreadable PDFs.
Optimized for iterative agent workflows: read snippets first, fetch only promising URLs, and retry or reformulate queries when results are noisy or fetches fail.
Searchpin
Self-hosted web search for AI agents — zero API keys, zero cost. In 2026, the center of gravity in AI development is shifting from "chatting" to "autonomous task execution" — locally deployed, long-running agents are becoming the norm. When an agent runs 24/7, every web search must not be interrupted by API quotas or billing. Searchpin was designed for this from day one: zero external dependencies, zero usage limits. Agents can search, fetch, and verify without restriction, and developers never worry about cost.
Why Searchpin
🇨🇳 Optimized for Chinese Network Environments
Defaults to Baidu, Sogou, Bing CN, and Bing Intl — four search engines queried in parallel. Works natively within China's network, no proxy or VPN needed. Most overseas alternatives rely on Google, DuckDuckGo, or Brave, which are largely inaccessible inside China.
🧠 Semantic Re-ranking — a Differentiator Few Offer
Results from all four engines are not simply concatenated. They are merged and re-ranked by an embedding model based on semantic similarity to the query. What your AI receives is a curated list of high-quality results, not a pile of noisy links. Among free MCP search servers, very few offer this capability.
💰 Completely Free, Zero Barrier
No account registration, no API key application, no usage limits. No dependency on any commercial API — no risk of sudden paywalls or quota restrictions. The entire pipeline runs on your own machine.
🔍 Built for Modern Websites
Built-in SSR content extraction can parse pages rendered by Next.js, Nuxt, and similar frameworks, and extract JSON-LD structured data and microdata. Plain HTML scraping gets nothing from these sites.
web_fetch also detects PDFs by content type or file signature and extracts page-labelled text locally. Unreadable, encrypted, or image-only PDFs return an explicit error instead of binary garbage; OCR is not included. Extraction is limited to 25 MiB, 200 pages, and 2 million text characters.
🛡️ Pollution Detection + Cross-Verification
Automatically detects and flags results unrelated to your query. Four independent search engines provide cross-verifiable results, enabling your LLM to corroborate information across sources for more credible answers.
⚡ Deliberate Engineering Trade-offs
Every design decision was made with real-world usage in mind:
Token-conscious — Search results return only titles, URLs, and snippets. Structured extraction data is compact and truncated. Your LLM decides which pages are worth fetching in full, without wasting context window.
Fast response — Four engines queried asynchronously in parallel. Total time depends on the slowest engine, not the sum of all four. A typical search completes in 1–2 seconds.
Memory-friendly — The embedding model (~118MB) is downloaded once through hf-mirror.com (HuggingFace mirror for China), then reused from local cache.
Related MCP server: GroundRoute
Quick Start
pip install searchpin && searchpin-setupOn first run, the embedding model (~118MB) is downloaded once via hf-mirror.com (HuggingFace mirror for China). That is the only one-time setup.
Configuration
Claude Desktop / Cursor / any MCP client
Add to your mcpServers config:
{
"mcpServers": {
"Searchpin": {
"command": "searchpin-server",
"args": []
}
}
}VS Code
Or manually, add to .vscode/mcp.json:
{
"servers": {
"Searchpin": {
"command": "searchpin-server",
"args": []
}
}
}Docker
docker run -i --rm ghcr.io/telly6/searchpin:latestPython API
from searchpin import SearchEngine
engine = SearchEngine()
results = engine.search("Python 3.13 新特性")
page = engine.fetch("https://docs.python.org/3/whatsnew/3.13.html")
engine.close()Available Tools
2 toolsweb_fetchA
Fetch a URL and return clean, extracted text content (boilerplate, ads, and nav removed). Use to read articles, documentation pages, or API responses in full. PDF text layers are extracted locally with page labels; unreadable PDFs return an explicit error. OCR is not included. For broad queries, use web_search first, then fetch specific URLs from its results. After fetching, look for technical terms, names, or references you can use as keywords for a better follow-up search.
⚠️ FAILURE IS NORMAL — DO NOT GIVE UP AFTER 1-2 FAILED FETCHES:
If a fetch returns empty body, 403, or obvious JS-template garbage, try the NEXT URL from the search results immediately. Each retry costs only ~0.5s.
Common failure causes: JS-rendered SPA shells (stock pages, forums), Chinese paywalls/captchas (wenku.baidu.com, zhihu.com), government site timeouts.
Rule of thumb: try at least 3 URLs from 3 different domains before concluding the content is unreachable. Skipping this wastes the search you already paid for.
When retrying, pick a URL from a DIFFERENT domain — same-domain failures often share the same root cause (e.g., all pages behind the same Cloudflare/WAF).
RETRY SILENTLY: When a fetch fails, retry with the next URL immediately as another tool call. Do NOT narrate each failure to the user ('this one failed, trying another…'). Only mention failures in your final reply if ALL attempts were exhausted.
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | The URL to fetch |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations exist, so the description carries the full burden and does so: it discloses the extraction behavior, that PDF text layers are processed locally with page labels, that OCR is absent, that unreadable PDFs return an explicit error, and enumerates real failure modes (JS SPA shells, Baidu/Zhihu captchas, government timeouts) with an approximate retry cost of ~0.5s.
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?
Front-loaded with purpose and usage routing before the failure block, and the bolded header makes the retry rule scannable. Slightly long — the 'FAILURE IS NORMAL' and 'RETRY SILENTLY' sections partially overlap and could be merged, but no sentence is truly wasted given the operational stakes.
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?
With no output schema and no annotations, the description still conveys what comes back (clean extracted text, page labels for PDFs, explicit error on unreadable files) and what to do when it doesn't. An agent has enough to invoke it correctly and recover from failure without further 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?
Only one parameter (url) and schema coverage is 100%, so the schema already documents it; the description adds nothing about URL syntax — absolute vs relative, redirect handling, or scheme restrictions. Given a single param, baseline-level credit is appropriate rather than more.
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?
States a specific verb+resource ('Fetch a URL and return clean, extracted text content') and immediately qualifies scope (boilerplate, ads, nav removed). Names its sibling web_search as the different counterpart for broad queries, so an agent can route without opening either schema.
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?
Explicit 'use web_search first, then fetch specific URLs from its results,' plus a concrete retry protocol: try at least 3 URLs from 3 different domains, prefer different domains to avoid shared WAF causes, and retry silently rather than narrating. Covers when-to-use, when-not, and the escalation path after failure.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
web_searchA
Search the web via multiple engines (Baidu, Sogou, Bing CN, Bing Intl). Returns ranked titles, URLs, and snippets (no full page content — use web_fetch to get the full text of any result). Results re-ranked by embedding similarity — the top results are the most relevant.
Iterative search is normal: search → read → refine → search → read → synthesize. Search returns only titles + snippets. Read snippets to identify promising results, then call web_fetch to get full page content for the URLs that look most useful.
BEFORE FETCHING, READ THE SNIPPETS FIRST:
Search results come with title + URL + snippet only (no full content). Read snippets to decide which URLs are worth fetching.
Fetch only the 1-3 most promising URLs — do not blindly fetch everything. Each unnecessary web_fetch wastes 1-3s per call.
⛔ WHEN RESULTS LOOK WRONG, DO NOT GIVE UP — ITERATE IMMEDIATELY: If search results are all irrelevant (wrong topic, wrong domain, generic encyclopedia entries, piracy sites, brand pages, file format tools, or dictionary entries), DO NOT conclude the information is unavailable. The fix is almost always a query reformulation. The most common root cause is Bing's tokenizer splitting your query words into fragments that collide with unrelated content. Replace fragile/generic terms with INSEPARABLE identifiers — proper nouns, compound terms, subdomain names, or acronyms that the tokenizer CANNOT split. Then immediately re-search. Do not narrate the failure — just try a different formulation. The PRINCIPLE (not the specific domain) matters:
A law query: 'GDPR enforcement tracker 2026' not 'GDPR fine'
A car query: '全固态电池量产线' not 'solid state battery'
A finance query: 'USDJPY exchange rate' not 'yen dollar'
A programming query: 'rustc 1.87 changelog' not 'Rust release notes'
FOR CHINESE: no spaces around Chinese chars! '2026年新能源汽车补贴' ✓, '新能源汽车补贴 2026' ✗
SEARCH STRATEGY (patterns drawn from real-world use):
DATE TERMS HIJACK QUERIES — Putting year numbers or month names ("2026年", "June") directly in query text often backfires: the engine weights them as the primary topic and you get calendar summaries or current-events roundups instead of your actual topic. PREFER the 'freshness' parameter to control recency — it filters by publication date without polluting the query text.
SHORT COMMON WORDS COLLIDE — In Chinese, single characters that are also standalone dictionary headwords get tokenized independently and matched to dictionary/encyclopedia entries, regardless of surrounding context. In English, short common words that also name major products/services (credit card brands, consumer goods) cause the same problem. RECOGNISE THE PATTERN: if any word in your query could appear as a dictionary headword or a product name on its own, it WILL collide. Embed such terms inside longer inseparable compounds.
LONG PROPER NOUNS ARE ANTI-NOISE ANCHORS — Full institutional names, drug trade names, legal case codes, product model numbers resist tokenizer fragmentation. They act as unbreakable signals that pull results toward the right topic. When a shorter query goes off-target, try a version built around a specific long-form name.
LANGUAGE-SWITCH ESCAPES TOKENIZER TRAPS — When a Chinese query keeps hitting noise despite retries, switch the query to English. English-language media covers many China-specific topics, and the English tokenizer does not fragment CJK characters into dictionary entries.
REPLACE THE ANCHOR — Adding another word to a noisy query rarely fixes it (the original offending token still dominates the ranking). Instead, restructure the query around a DIFFERENT anchor term entirely — a proper noun, a model number, or a multi-word technical phrase that the tokenizer cannot split.
THE VOCABULARY BRIDGE — Chinese search engines match on LEXICOGRAPHIC (word-level), NOT semantic. The words you use MUST match how the target documents actually phrase things. This creates a critical gap:
User language (descriptive): 极端天气, 气候灾害, 高温热浪
Source language (operational): 暴雨橙警, 三级应急响应, 解除预警 These are two entirely different vocabulary systems and the engine CANNOT automatically map between them. When abstract category terms return only encyclopedia definitions and year-old retrospectives, switch to the OPERATIONAL terms that the institutions/sources themselves use — alert levels, government response codes, proper institutional names, numeric thresholds ("四十度"), or named entities ("台风蔷薇").
Abstract: '2026年极端天气气候灾害' → only dictionaries & retrospectives
Operational: '暴雨橙警 应急响应 中央气象台' → nmc.cn real-time alerts This is not a data-coverage problem. The documents exist in the index. They just use a different vocabulary than you searched for.
⚡ NUMERIC DATA CROSS-VERIFICATION:
When a critical number appears in one result, confirm it against at least one other source before accepting it as fact. Different aggregators can lag; conflicting values demand a third source.
⛔ DO NOT STOP EARLY — PERSISTENCE IS REQUIRED:
When a search returns 10 irrelevant results, that does NOT mean the information doesn't exist. It means the current query formulation failed to reach it. Real-world testing shows: the same engine (baidu/bing_cn) that returned 100% calendar-dictionary noise for '2026年极端天气' returned nmc.cn real-time severe weather alerts (rerank 0.908) when reformulated as '暴雨洪涝 应急响应 中央气象台 预警'.
Top-10 failure is a QUERY PROBLEM, not a content-availability problem. The valid pages are likely at positions 11-30, pushed out of view by noise that matched your abstract terms. Do not conclude 'information unavailable' from a failed top 10.
EXHAUST AT LEAST 3-4 DISTINCT STRATEGIES before any 'not found' verdict:
Different vocabulary (descriptive → operational)
Different language (CN ↔ EN)
Different anchors (category term → proper name/number)
Site-restricted search (site:target-source.tld)
Never stop after 1-2 rounds just because the first attempts returned noise. The difference between 'completely unsolvable' and 'fully answered in 1 round' is often a single query reformulation — changing '极端天气' to '暴雨橙警'.
CONDUCT ALL ITERATIONS SILENTLY: When you need multiple rounds of searching and fetching to gather information, run all iterations as tool calls without narrating each step in your reply. Present only the final synthesized answer to the user. Do NOT say things like 'let me search again' or 'I tried searching for X but got Y, let me try Z instead' — just do it and deliver the result.
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | Search query keywords | |
| topic | No | Search vertical. 'general' (default, web search) or 'news' (Bing News — prioritises recent articles from mainstream media; best for earnings, sports scores, political events, breaking stories). Also useful as an escape hatch: when 'general' returns Chinese dictionary entries for a query that should have news coverage, switching to 'news' can bypass the dictionary index entirely. | |
| freshness | No | Time filter. One of: d (past day), w (past week), m (past month), y (past year). PREFER this over putting years/months in the query text — date words in queries get weighted as the primary topic and cause noise. This parameter filters by publication date without polluting the query. Omit for no filter. | |
| max_results | No | Max results to return (default 10, max 20). Controls output count only. | |
| exclude_domains | No | Domains to filter OUT of results before re-ranking. Use when a previous search returned pages from a noise domain (e.g. a dictionary site, a brand page, a mirror). Example: ['zidian.gushici.net', 'hancibao.com']. Supply at runtime only — no permanent blocklist. | |
| include_domains | No | Limit results to ONLY these domains (whitelist). Use when you want results from specific sources (e.g. ['docs.python.org', 'python.org'] for Python docs only). Applied before re-ranking. Empty/omitted = no restriction. Supplied by the LLM at runtime — no hardcoded list. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations provided, but description fully discloses re-ranking by embedding similarity, multiple engines, tokenizer issues, noise causes, and the lack of full content. Also mentions numeric data cross-verification and failure handling.
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?
Very long but well-structured with sections, examples, and warnings. Each sentence adds value, though some repetition exists. Impressive detail without being bloated.
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?
No output schema but explicitly states returns titles, URLs, snippets. Covers edge cases, iteration strategies, query reformulation, and cross-verification. Highly complete for a complex search tool.
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 100%, but description adds significant meaning: explains topic parameter's use to bypass dictionary, freshness parameter's advantage over date terms, and real-world use cases for exclude/include domains.
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?
Description clearly states the tool searches the web via multiple engines returning ranked titles, URLs, and snippets. Explicitly distinguishes from sibling web_fetch by noting it does not return full page content.
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?
Provides extensive guidance: iterative search strategy, when to fetch vs search, query reformulation patterns, language switching, and domain filtering. Explicitly contrasts with web_fetch and advises on when to use each.
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.
2 tool updates
v1.0.8- First observed
web_fetch - First observed
web_search
TDQS
Scored across 2 tools
The two tools have clearly distinct roles: web_search discovers ranked results, while web_fetch retrieves and extracts full page content. The descriptions explicitly direct the agent to use search first and fetch selected URLs afterward, so there is no realistic misselection.
Both tool names follow the same web_<verb> convention: web_search and web_fetch. The pattern is predictable and clearly describes each operation.
Only two tools are provided, but they are the essential primitives for this server's retrieval purpose. It is slightly under the typical 3-15 range, though the narrow search-and-fetch scope makes the minimal surface reasonable.
The core lifecycle of web information retrieval is covered: search for candidate URLs and fetch full text from chosen URLs. Minor gaps exist, such as batch fetching or richer search controls, but agents can work around these by iterating.
Maintenance
Related MCP Connectors
Web search for AI agents — one tool across 6 engines, routed to the cheapest + cached.
Free web search for AI agents. No API key required. Hosted MCP in active development.
Multi-engine search for AI agents. Trust scoring, local corpus, MCP-native. Self-hostable, BYOK.
The best web search for your AI Agent
Related MCP Servers
- AlicenseAqualityDmaintenanceAn advanced web browsing server enabling headless browser interactions via a secure API, providing features like navigation, content extraction, element interaction, and screenshot capture.627MIT
- AlicenseAqualityFmaintenanceWeb search for AI agents across 6 engines (Serper, Brave, Exa, Tavily, Firecrawl, Perplexity) through one search tool. Routes each query to the cheapest engine that clears a quality bar and caches repeats. Hosted, streamable-HTTP, BYOK supported.11MIT
- AlicenseAqualityFmaintenanceFree multi-source web search server for AI agents, with confidence scoring and token optimization.3193 npmApache 2.0
- AlicenseAqualityBmaintenanceEnables web search via a real browser for any LLM, bypassing anti-bot measures without API keys.5MIT