Server Metasearch
БесплатноНе проверенA unified MCP server aggregating 15 web search and extraction tools across 5 providers (Jina, Tavily, Exa, Firecrawl, Bocha) with automatic API key validation a
Описание
A unified MCP server aggregating 15 web search and extraction tools across 5 providers (Jina, Tavily, Exa, Firecrawl, Bocha) with automatic API key validation and plugin architecture.
README
CI Python 3.10+ License: MIT PyPI
English | 简体中文
A local MCP (Model Context Protocol) server that aggregates 15 web search and extraction tools across 5 providers (Jina, Tavily, Exa, Firecrawl, Bocha) behind a unified interface. Each tool is gated by both an on/off switch and an API key check — AI agents only see tools they can actually use.
Status: v0.2.7 — Production-ready with full test coverage (123 tests, 91% coverage).
Why MCP Server Metasearch?
Instead of configuring 5 separate MCP servers (one per provider), metasearch gives you a single unified interface with:
- Zero-config tool exposure — only tools with valid API keys are visible to AI agents
- Plugin architecture — add a new provider by dropping one Python file, no framework changes
- Shared infrastructure — connection pooling, response caching, and startup diagnostics out of the box
Table of Contents
- Quick Start
- Core Features
- Deployment Guide
- Built-in Tools
- Configuration Reference
- Adding New Tools
- Troubleshooting FAQ
- Development & Testing
Quick Start
1. Configure
mkdir -p ~/.config/mcp-server-metasearch
cp .env.example ~/.config/mcp-server-metasearch/.env
# Edit ~/.config/mcp-server-metasearch/.env with your API keys
2. Run
Recommended — via uvx (no install needed):
uvx mcp-server-metasearch
Or connect via any MCP client — see Deployment Guide below.
Alternative: install globally with pip
pip install mcp-server-metasearch
mcp-server-metasearch
Alternative: install from source
git clone https://github.com/busigui2023/mcp-server-metasearch.git
cd mcp-server-metasearch
uv venv && uv pip install -e ".[dev]"
mcp-server-metasearch
Core Features
- Plugin architecture: Add or remove web tools by dropping a single Python file. No framework code changes.
- Dual validation: Every tool requires both
TOOL_*_ENABLED=trueand the presence of its API key(s) to be exposed. - Key-optional support: Some tools may work without an API key; others strictly require one.
- Startup resilience: If zero tools are available, the server fails with a detailed diagnostic report and retries up to 3 times before giving up.
- Local logging: All runtime logs write to both stderr (safe for stdio transport) and
logs/mcp-server-metasearch.log. - Connection pool reuse: Shared
httpx.AsyncClientacross all tools eliminates per-request connection overhead, with graceful shutdown viaatexit. - Response caching: In-memory TTL cache (600s) with registry-level wrapping — zero tool code changes.
- Optimized config loading: Environment file is read only once per process lifetime, avoiding repeated disk I/O on every tool call.
- Clean protocol handshake: The server does not advertise unused
resourcesorpromptscapabilities. This prevents MCP clients (e.g. Hermes) from auto-generating utility stubs for features this server does not implement, keeping the agent's tool list focused on the 15 actual search tools.
Deployment Guide
Prerequisites
- Python 3.10+
- uv installed (provides
uvxfor zero-install runs) - API keys for the services you want to enable
1. Configure
See Quick Start above, then continue with your MCP client setup.
2. Connect to an MCP Client
Note: The recommended way is
uvx— nopip installneeded.uvxauto-downloads and caches the package on first run, then reuses the cache. If you installed from source, use the "From Source" tab instead.
Claude Code
uvx (recommended):
claude mcp add metasearch -- uvx mcp-server-metasearch
Or edit ~/.claude/settings.json directly
{
"mcpServers": {
"metasearch": {
"type": "stdio",
"command": "uvx",
"args": ["mcp-server-metasearch"]
}
}
}
From Source:
claude mcp add metasearch -- uv run --directory /absolute/path/to/mcp-server-metasearch mcp-server-metasearch
Or edit ~/.claude/settings.json directly
{
"mcpServers": {
"metasearch": {
"type": "stdio",
"command": "uv",
"args": [
"run",
"--directory",
"/absolute/path/to/mcp-server-metasearch",
"mcp-server-metasearch"
]
}
}
}
Restart Claude Code (/quit then re-enter). Run /mcp to verify the server appears.
OpenClaw
uvx (recommended):
openclaw mcp add metasearch --command uvx --arg mcp-server-metasearch
Or edit openclaw.json directly
{
"mcp": {
"servers": {
"metasearch": {
"command": "uvx",
"args": ["mcp-server-metasearch"],
"transport": "stdio"
}
}
}
}
From Source:
openclaw mcp add metasearch \
--command uv \
--arg run \
--arg --directory \
--arg /absolute/path/to/mcp-server-metasearch \
--arg mcp-server-metasearch
Or edit openclaw.json directly
{
"mcp": {
"servers": {
"metasearch": {
"command": "uv",
"args": [
"run",
"--directory",
"/absolute/path/to/mcp-server-metasearch",
"mcp-server-metasearch"
],
"transport": "stdio"
}
}
}
}
Run openclaw mcp probe metasearch to test the connection without starting a full agent turn.
Hermes Agent
uvx (recommended):
# ~/.hermes/config.yaml
mcp_servers:
metasearch:
command: "uvx"
args: ["mcp-server-metasearch"]
From Source:
# ~/.hermes/config.yaml
mcp_servers:
metasearch:
command: "uv"
args:
- "run"
- "--directory"
- "/absolute/path/to/mcp-server-metasearch"
- "mcp-server-metasearch"
Restart Hermes or run hermes mcp list to verify. Use hermes mcp test metasearch to check connectivity and tool discovery.
Manual Test
uvx (recommended):
uvx mcp-server-metasearch
From Source:
uv run --directory /absolute/path/to/mcp-server-metasearch mcp-server-metasearch
If no tools are enabled, you will see a diagnostic table and the process exits with code 1. Fix your .env and retry.
Troubleshooting FAQ
Q: The diagnostic table shows all tools as "Skipped (switch disabled)" even though I set them to true.
A: The .env file must live at ~/.config/mcp-server-metasearch/.env, not in the project root. The server does not read a local .env file inside the repository. Double-check the path and ensure there are no trailing spaces after true.
Q: The diagnostic table shows "Skipped (missing API key)" but I added the key.
A: Check for these common mistakes:
- The key value is empty after the
=sign. - There is a
#comment on the same line that truncates the value. - The key name is misspelled (e.g.
JINA_APIKEYinstead ofJINA_API_KEY). - The
.envfile was saved with Windows line endings (\r\n) in a way that breaks parsing.
Q: The MCP client says "MCP server metasearch failed to start" or the process exits immediately.
A: This usually means zero tools passed validation and the server exited with code 1. Check the client logs (stderr) for the diagnostic table. If you see retry messages (Retry 1/3, Retry 2/3), the server is working as designed — fix your .env before the 3rd retry or the client may stop trying.
Q: I enabled some tools but the client only shows a subset of them.
A: Each tool is validated independently. The missing tools likely failed their own key or switch check. Look at the startup diagnostics — the table lists every tool and the exact reason it was skipped. Common cases:
JINA_API_KEYmissing → all jina tools hiddenTAVILY_API_KEYmissing → all tavily tools hidden- A tool's switch set to
false→ that single tool hidden
Since jina tools share the same key, they appear or hide together. Tavily tools also share the same key.
Q: uv run mcp-server-metasearch works manually but fails when launched by the MCP client.
A: MCP clients often launch the server with a different working directory or environment. Ensure:
- You use
--directory /absolute/path/to/mcp-server-metasearchsouvcan findpyproject.tomland set the correct working directory. - The
.envpath~/.config/mcp-server-metasearch/.envuses the absolute home directory and does not depend on the working directory.
Q: How do I completely reset the startup retry counter?
A: Delete the retry file:
rm ~/.cache/mcp-server-metasearch/startup_retries
This is useful when testing configuration changes and you want a fresh start.
Q: Where do I find logs when the server is launched by a client?
A: Logs are written to stderr (safe for stdio transport) and also persisted to:
logs/mcp-server-metasearch.log
If the client captures stderr, look there. If not, check the log file in the project directory. Note: the log file is created relative to the server's working directory, so if the client changes CWD, the log may appear in an unexpected location.
Q: Can I run the server without uv or uvx?
A: Yes. Install globally with pip install mcp-server-metasearch (preferably in a dedicated virtual environment to avoid polluting your system Python), then run mcp-server-metasearch directly. Note: some Linux distributions (Ubuntu 23.04+) block global pip install due to PEP 668 — in that case, use uvx or a virtual environment.
Built-in Tools
Current total: 15 tools across 5 providers.
Not sure which tool to use? Here's the decision matrix:
| Goal | Recommended Tool | Why |
|---|---|---|
| Read a known URL / PDF | jina_reader, exa_contents, or firecrawl_scrape |
Direct extraction, clean markdown. Firecrawl supports HTML/links output too |
| General web search | exa_search, tavily_search, firecrawl_search, or bocha_web_search |
Token-efficient, rich filters. Firecrawl adds image/news search. Bocha: Chinese-optimized, domestic network |
| Company / people lookup | exa_search with category |
Exa's indexed categories (50M+ companies, 1B+ people) |
| Academic papers | exa_search with category="research paper" or firecrawl_search with categories=["research"] |
100M+ papers indexed |
| Quick fact-check Q&A | exa_answer or bocha_ai_search with answer=True |
Direct answer + citations. Bocha AI Search returns modal cards + AI summary |
| Batch URL extraction | tavily_extract or firecrawl_map + selective scrape |
Tavily: up to 20 URLs. Firecrawl map: discover all site URLs, then scrape what you need |
| Deep research report | tavily_research |
Async multi-step synthesis with citations |
| Fastest possible search | exa_search with type="instant" |
~250ms latency |
| Website URL discovery | firecrawl_map |
1 credit to map an entire site structure |
| Recursive site crawl | firecrawl_crawl |
Auto-discover and scrape all subpages. Default 10-page limit for safety |
| GitHub code search | firecrawl_search with categories=["github"] |
Search repos, issues, code docs |
| Chinese content / domestic network | bocha_web_search or bocha_ai_search |
DeepSeek official search supplier, China-optimized, no proxy needed |
jina_reader
Fetch and extract clean, LLM-friendly content from any webpage, PDF, or document URL using jina.ai Reader.
When to use: The AI needs to read a specific URL, parse a PDF link, or extract article content from a JS-heavy site.
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
url |
str |
— | Target webpage or PDF URL. |
return_format |
str |
"markdown" |
Output format. "markdown", "text", or "html". |
target_selector |
str | None |
None |
CSS selector to extract only matching elements (e.g. article.main-content). |
remove_selectors |
str | None |
None |
Comma-separated CSS selectors to remove (e.g. nav, footer, .ads). |
timeout |
int |
30 |
Page load timeout in seconds (1–180). |
API requirement: JINA_API_KEY is required.
Example flow:
- AI receives a user question about a blog post.
- AI calls
jina_readerwith the blog URL. - Server requests
https://r.jina.ai/http://<url>and returns clean Markdown.
jina_search
Search the web using jina.ai Search and retrieve LLM-friendly results with full page summaries.
When to use: The AI needs current web information, fact-checking, or multi-source summaries.
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
query |
str |
— | Search keywords or natural-language question. |
num_results |
int |
5 |
Number of results to return (1–20). |
site |
str | None |
None |
Restrict search to a specific domain (e.g. reddit.com). |
search_type |
str |
"web" |
"web", "news", or "images". |
return_format |
str |
"markdown" |
Result format. "markdown", "text", or "html". |
API requirement: JINA_API_KEY is required.
Example flow:
- User asks "What are the latest Python 3.14 features?"
- AI calls
jina_searchwithquery="Python 3.14 new features". - Server returns up to 5 results, each with title, URL, and full content summary.
jina_deepsearch
Perform multi-step research on a complex topic using jina.ai DeepSearch. Combines web search, page reading, and reasoning into a single comprehensive answer with cited sources.
When to use: The question is broad or exploratory (e.g. "Compare vector databases for RAG in 2026"). DeepSearch autonomously searches multiple sources, reads them, and synthesizes a report.
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
query |
str |
— | The research question or topic. Be specific for best results. |
max_tokens |
int |
4096 |
Maximum tokens in the response. |
API requirement: JINA_API_KEY is required.
Example flow:
- User asks "What are the trade-offs between Weaviate, Qdrant, and Milvus for production RAG?"
- AI calls
jina_deepsearchwith the full question. - Server sends the query to
https://deepsearch.jina.ai/v1/chat/completions. - Response is a structured research report with inline citations.
tavily_search
Search the web using Tavily with fine-grained filters, relevance scoring, and optional AI-generated answers.
When to use: You need precise search with time-range filters, domain restrictions, country boosting, or an AI-generated summary answer.
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
query |
str |
— | Search keywords or natural-language question. |
search_depth |
str |
"basic" |
"basic", "fast", "advanced" (2 credits), or "ultra-fast". |
max_results |
int |
5 |
Number of results to return (0–20). |
topic |
str |
"general" |
"general", "news", or "finance". |
time_range |
str | None |
None |
"day", "week", "month", or "year". |
include_answer |
bool |
False |
Include an LLM-generated answer to the query. |
include_raw_content |
bool |
False |
Include full cleaned page content per result. |
include_images |
bool |
False |
Include images from search results. |
include_favicon |
bool |
False |
Include favicon URLs per result. |
include_domains |
list[str] | None |
None |
Domains to restrict results to (max 300). |
exclude_domains |
list[str] | None |
None |
Domains to exclude from results (max 150). |
API requirement: TAVILY_API_KEY is required. 1,000 free credits/month.
Example flow:
- User asks "What happened in AI this week?"
- AI calls
tavily_searchwithquery="AI news",topic="news",time_range="week",include_answer=true. - Server returns ranked results plus a concise AI-generated answer.
tavily_extract
Extract clean, LLM-friendly content from one or more URLs using Tavily Extract. Supports batch extraction and query-guided chunk reranking.
When to use: You already know the URLs and want to extract their content in bulk, or you want query-relevant chunks instead of full pages.
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
urls |
str | list[str] |
— | Single URL or list of URLs to extract. |
query |
str | None |
None |
User intent for reranking chunks. |
extract_depth |
str |
"basic" |
"basic" or "advanced" (tables, embedded content). |
return_format |
str |
"markdown" |
"markdown" or "text". |
API requirement: TAVILY_API_KEY is required.
Example flow:
- AI finds 3 relevant URLs from a prior search.
- AI calls
tavily_extractwithurls=[url1, url2, url3]. - Server returns clean markdown for all three pages.
tavily_research
Perform comprehensive, multi-step research using Tavily Research. Conducts multiple searches, analyzes sources, and generates a cited research report.
When to use: The question is broad and requires a synthesized report with citations (e.g. "Compare cloud providers for ML workloads in 2026"). Higher credit consumption than search.
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
input |
str |
— | The research task or question to investigate. |
model |
str |
"auto" |
"mini", "pro", or "auto" (default). |
citation_format |
str |
"numbered" |
"numbered", "mla", "apa", or "chicago". |
API requirement: TAVILY_API_KEY is required. Research consumes significantly more credits than a single search because it runs multiple internal search + extract + synthesis steps.
Example flow:
- User asks "What are the trade-offs between Weaviate, Qdrant, and Milvus for production RAG?"
- AI calls
tavily_researchwith the full question. - Server submits an async research task and polls until completion.
- Response is a structured research report with numbered citations and a source list.
exa_search
Search the web using Exa, a search engine optimized for LLMs. Returns highly relevant excerpts (highlights) by default for 10x token efficiency. Supports category filters and deep-reasoning modes.
When to use: You need token-efficient search results, company/people/research-paper category filtering, or the fastest search latency (instant ~250ms).
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
query |
str |
— | Natural language search query. |
type |
str |
"auto" |
"auto", "fast", "instant", "deep-lite", "deep", "deep-reasoning". |
num_results |
int |
10 |
Number of results (1–100). |
category |
str | None |
None |
"company", "people", "research paper", "news", "personal site", "financial report". |
content_mode |
str |
"highlights" |
"highlights" (default), "text", or "summary". |
include_domains |
list[str] | None |
None |
Whitelist domains (max 1200). |
exclude_domains |
list[str] | None |
None |
Blacklist domains (max 1200). Not supported with company/people. |
max_age_hours |
int | None |
None |
0=always livecrawl, -1=cache only. |
API requirement: EXA_API_KEY is required.
Example flow:
- User asks "Find Series A agtech companies in the US."
- AI calls
exa_searchwithquery="agtech companies US Series A",category="company",content_mode="highlights". - Server returns up to 10 company pages with key excerpts.
exa_contents
Extract clean, LLM-ready content from one or more URLs using Exa Contents. Handles JS-rendered pages, PDFs, and complex layouts. Supports subpage crawling.
When to use: You already know the URLs and want to extract their content, optionally crawling linked subpages.
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
urls |
str | list[str] |
— | Single URL or list of URLs. |
content_mode |
str |
"text" |
"text" (full page), "highlights", or "summary". |
max_age_hours |
int | None |
None |
Content freshness control. |
subpages |
int |
0 |
Number of subpages to crawl per URL. |
subpage_target |
list[str] | None |
None |
Keywords to prioritize subpages. |
API requirement: EXA_API_KEY is required.
Example flow:
- AI finds a relevant documentation URL.
- AI calls
exa_contentswithurls="https://docs.example.com",subpages=10,subpage_target=["api", "reference"]. - Server returns content from the root page plus up to 10 linked subpages.
exa_answer
Get a direct LLM answer to a question informed by Exa search results. Ideal for quick factual lookups.
When to use: You need a concise answer to a specific question, not a list of search results.
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
query |
str |
— | The question to answer. |
text |
bool |
False |
Include full source text in citations. |
API requirement: EXA_API_KEY is required.
Example flow:
- User asks "What is SpaceX's latest valuation?"
- AI calls
exa_answerwith the question. - Server returns "$350 billion" plus cited sources.
firecrawl_scrape
Extract clean, LLM-ready content from any webpage using Firecrawl. Supports multiple output formats and dynamic content rendering.
When to use: The AI needs precise content from a known URL, especially JS-rendered sites, or wants HTML/links in addition to markdown.
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
url |
str |
— | Target webpage or PDF URL. |
formats |
list[str] |
["markdown"] |
Output formats: "markdown", "html", "links". |
only_main_content |
bool |
True |
Exclude navigation, ads, footers. |
timeout |
int |
30000 |
Page load timeout in milliseconds. |
wait_for |
int |
0 |
Wait time for dynamic content (ms). |
API requirement: FIRECRAWL_API_KEY is required.
firecrawl_search
Search the web using Firecrawl and get structured content from results. Supports web, news, and image search with specialized category filtering.
When to use: The AI needs to search with image results, news results, or filter by GitHub/research-paper/PDF categories.
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
query |
str |
— | Natural language search query. |
limit |
int |
5 |
Results per source type (1–50). |
sources |
list[str] |
["web"] |
Result types: "web", "news", "images". |
categories |
list[str] |
None |
Filters: "github", "research", "pdf". |
include_domains |
list[str] |
None |
Restrict to these domains. |
exclude_domains |
list[str] |
None |
Exclude these domains. |
scrape_content |
bool |
False |
Fetch full markdown per result (extra credits). |
API requirement: FIRECRAWL_API_KEY is required.
Cost note: 2 credits per 10 search results. scrape_content=True adds 1 credit per result page.
firecrawl_map
Discover all URLs on a website quickly. Returns a complete link list with titles and descriptions.
When to use: The AI wants to explore a site's structure before deciding which pages to read, or needs to find specific pages on a large site.
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
url |
str |
— | Website to map. |
limit |
int |
100 |
Maximum URLs to return (1–10,000). |
search |
str |
None |
Keyword filter within the site. |
API requirement: FIRECRAWL_API_KEY is required.
Cost note: Always 1 credit per call, regardless of URL count.
firecrawl_crawl
Recursively crawl a website, discovering and scraping all reachable subpages automatically.
When to use: The AI needs to ingest an entire documentation site, blog, or any multi-page resource.
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
url |
str |
— | Starting URL to crawl from. |
limit |
int |
10 |
Max pages to crawl (1–100). Default is conservative to control credit usage. |
max_discovery_depth |
int |
None |
Max link-hops from start URL. None = unlimited. |
include_paths |
list[str] |
None |
Regex patterns for paths to include. |
exclude_paths |
list[str] |
None |
Regex patterns for paths to exclude. |
allow_subdomains |
bool |
False |
Follow links to subdomains. |
formats |
list[str] |
["markdown"] |
Output format per page. |
API requirement: FIRECRAWL_API_KEY is required.
Cost note: 1 credit per page crawled. Default limit=10 = max 10 credits.
bocha_web_search
Search the web using Bocha AI, a China-optimized search engine powering DeepSeek's web search. Returns clean, structured results with webpage titles, URLs, snippets, site info, and optional AI summaries.
When to use: The AI needs to search Chinese content, access domestic websites, or needs a search tool that works reliably without proxy.
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
query |
str |
— | Natural language search query. |
count |
int |
5 |
Number of results (1–50). |
freshness |
str |
None |
Time filter: oneDay, oneWeek, oneMonth, oneYear, noLimit, or YYYY-MM-DD..YYYY-MM-DD. |
summary |
bool |
False |
Include AI-generated summary per result. |
include_domains |
list[str] |
None |
Only return results from these domains. |
exclude_domains |
list[str] |
None |
Exclude results from these domains. |
API requirement: BOCHA_API_KEY is required.
Cost note: ¥0.036 per call. Free tier available for personal use.
bocha_ai_search
Advanced AI-powered search using Bocha AI. Returns web results plus structured modal cards (weather, encyclopedia, stock, train schedules, medical info, etc.) and optional AI-generated answers with follow-up questions.
When to use: The AI needs structured data extraction (e.g., "What's the weather in Beijing?", "Stock price of Alibaba"), or wants an AI-generated summary answer alongside search results.
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
query |
str |
— | Natural language search query. |
count |
int |
5 |
Number of web results (1–50). |
freshness |
str |
None |
Time filter (same as web search). |
answer |
bool |
False |
Include AI-generated summary answer and follow-up questions. |
API requirement: BOCHA_API_KEY is required.
Cost note: ¥0.060 per call. Returns modal cards + AI answer when answer=True.
Configuration Reference
.env Full Example
# ── Jina AI ──
JINA_API_KEY=jina_xxxxxxxxxxxxxxxxxxxxxxxx
TOOL_JINA_READER_ENABLED=true
TOOL_JINA_SEARCH_ENABLED=true
TOOL_JINA_DEEPSEARCH_ENABLED=true
# ── Tavily ──
# TAVILY_API_KEY=tvly-xxxxxxxx
# TOOL_TAVILY_SEARCH_ENABLED=true
# TOOL_TAVILY_EXTRACT_ENABLED=true
# TOOL_TAVILY_RESEARCH_ENABLED=true
# ── Exa ──
# EXA_API_KEY=your_exa_api_key_here
# TOOL_EXA_SEARCH_ENABLED=true
# TOOL_EXA_CONTENTS_ENABLED=true
# TOOL_EXA_ANSWER_ENABLED=true
# ── Firecrawl ──
# FIRECRAWL_API_KEY=fc-xxxxxxxxxxxxxxxx
# TOOL_FIRECRAWL_SCRAPE_ENABLED=true
# TOOL_FIRECRAWL_SEARCH_ENABLED=true
# TOOL_FIRECRAWL_MAP_ENABLED=true
# TOOL_FIRECRAWL_CRAWL_ENABLED=true
# ── 博查 Bocha AI ──
# BOCHA_API_KEY=sk-xxxxxxxxxxxxxxxx
# TOOL_BOCHA_WEB_SEARCH_ENABLED=true
# TOOL_BOCHA_AI_SEARCH_ENABLED=true
How Dual Validation Works
For every discovered tool, the server checks two conditions at startup:
- Switch check:
TOOL_<NAME>_ENABLEDmust betrue. - Key check: All
required_env_varsmust be present and non-empty in.env.
Both must pass for the tool to be registered. If a tool fails either check, it appears in the startup diagnostic table with the exact reason.
Development & Testing
Run Tests
uv run pytest tests/ -v
View Logs
Runtime logs are written to:
- stderr (MCP-safe, visible in client consoles)
logs/mcp-server-metasearch.log(rotated at 5 MB, 3 backups kept)
tail -f logs/mcp-server-metasearch.log
Startup Diagnostics
If no tools are registered, the server prints a diagnostic table to stderr:
[MCP-Metasearch] STARTUP DIAGNOSTICS
┌────────────────────┬─────────┬─────────────────┬─────────────────────────────┐
│ Tool │ Switch │ API Key │ Result │
├────────────────────┼─────────┼─────────────────┼─────────────────────────────┤
│ jina_reader │ OFF │ JINA_API_KEY │ Skipped (switch disabled) │
│ jina_search │ ON │ MISSING │ Skipped (missing API key) │
└────────────────────┴─────────┴─────────────────┴─────────────────────────────┘
Adding New Tools
- Create
src/mcp_server_metasearch/tools/my_tool.py. - Inherit from
BaseTool:
from mcp_server_metasearch.tools.base import BaseTool
class MyTool(BaseTool):
name = "my_tool"
description = "What this tool does."
required_env_vars = ["MY_API_KEY"] # or [] if no key needed
enabled_env_var = "TOOL_MY_TOOL_ENABLED"
async def call(self, param: str) -> str:
...
- Add the key and switch to
~/.config/mcp-server-metasearch/.env. - Restart the MCP client. The tool is auto-discovered — no edits to
server.pyortool_registry.pyneeded.
Project Structure
mcp-server-metasearch/
├── .env.example # Config template
├── pyproject.toml # Package metadata & dependencies
├── scripts/ # E2E smoke tests per provider
├── src/mcp_server_metasearch/
│ ├── server.py # FastMCP instance & startup flow
│ ├── tool_registry.py # Auto-discovery, dual validation & cache wrapping
│ ├── config.py # .env loading (single-read) & pydantic-settings
│ ├── http_client.py # Shared httpx.AsyncClient with graceful shutdown
│ ├── cache.py # In-memory TTL response cache
│ ├── diagnostics.py # Startup failure reports
│ ├── retry.py # Persistent retry counter
│ └── tools/ # One file per tool (plugin architecture)
│ ├── base.py # BaseTool abstract class
│ ├── formatting.py # Shared formatting utilities
│ ├── jina_*.py # Jina AI tools (reader, search, deepsearch)
│ ├── tavily_*.py # Tavily tools (search, extract, research)
│ ├── exa_*.py # Exa tools (search, contents, answer)
│ ├── firecrawl_*.py # Firecrawl tools (scrape, search, map, crawl)
│ └── bocha_*.py # Bocha tools (web_search, ai_search)
└── tests/ # Unit tests (123 tests, 91% coverage)
Acknowledgments
This project integrates with the following search and extraction services:
- Jina AI — Web reader and search
- Tavily — Search, extract, and research
- Exa — Semantic search for LLMs
- Firecrawl — Web scraping and crawling
- Bocha AI — Chinese-optimized search
Users need their own API keys for these services. This project does not provide or distribute any API keys.
License
MIT License — see LICENSE for details.
Contributing
See CONTRIBUTING.md for development setup and guidelines.
Установка Server Metasearch
У этого сервера нет опубликованного пакета — он собирается из исходников. Открой репозиторий и следуй инструкции в README.
▸ github.com/busigui2023/mcp-server-metasearchFAQ
Server Metasearch MCP бесплатный?
Да, Server Metasearch MCP бесплатный — установка в пару кликов через Unyly без оплаты.
Нужен ли API-ключ для Server Metasearch?
Нет, Server Metasearch работает без API-ключей и переменных окружения.
Server Metasearch — hosted или self-hosted?
Self-hosted: сервер запускается локально на твоей машине командой из раздела установки.
Как установить Server Metasearch в Claude Desktop, Claude Code или Cursor?
Открой Server Metasearch на unyly.org, выбери вкладку своего клиента (Claude Desktop, Claude Code, Cursor) и нажми Install — конфиг сгенерируется автоматически, без правки JSON.
Похожие MCP
GitHub
PRs, issues, code search, CI status
автор: GitHubFilesystem
Secure file operations with configurable access controls.
Memory
Knowledge graph-based persistent memory system.
Template MCP Server
A CLI tool to create a new Model Context Protocol server project with TypeScript support, dual transport options, and an extensible structure
автор: mcpdotdirectCompare Server Metasearch with
Не уверен что выбрать?
Найди свой стек за 60 секунд
Автор?
Embed-бейдж для README
Похожее
Все в категории development
