Skip to main content

A local MCP server aggregating web tools with API-key-gated dynamic exposure

Project description

MCP Server Metasearch

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.6 — 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

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=true and 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.AsyncClient across all tools eliminates per-request connection overhead, with graceful shutdown via atexit.
  • 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 resources or prompts capabilities. 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 uvx for 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 — no pip install needed. uvx auto-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_APIKEY instead of JINA_API_KEY).
  • The .env file 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_KEY missing → all jina tools hidden
  • TAVILY_API_KEY missing → 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-metasearch so uv can find pyproject.toml and set the correct working directory.
  • The .env path ~/.config/mcp-server-metasearch/.env uses 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:

  1. AI receives a user question about a blog post.
  2. AI calls jina_reader with the blog URL.
  3. 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:

  1. User asks "What are the latest Python 3.14 features?"
  2. AI calls jina_search with query="Python 3.14 new features".
  3. 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:

  1. User asks "What are the trade-offs between Weaviate, Qdrant, and Milvus for production RAG?"
  2. AI calls jina_deepsearch with the full question.
  3. Server sends the query to https://deepsearch.jina.ai/v1/chat/completions.
  4. 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:

  1. User asks "What happened in AI this week?"
  2. AI calls tavily_search with query="AI news", topic="news", time_range="week", include_answer=true.
  3. 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:

  1. AI finds 3 relevant URLs from a prior search.
  2. AI calls tavily_extract with urls=[url1, url2, url3].
  3. 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:

  1. User asks "What are the trade-offs between Weaviate, Qdrant, and Milvus for production RAG?"
  2. AI calls tavily_research with the full question.
  3. Server submits an async research task and polls until completion.
  4. 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:

  1. User asks "Find Series A agtech companies in the US."
  2. AI calls exa_search with query="agtech companies US Series A", category="company", content_mode="highlights".
  3. 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:

  1. AI finds a relevant documentation URL.
  2. AI calls exa_contents with urls="https://docs.example.com", subpages=10, subpage_target=["api", "reference"].
  3. 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:

  1. User asks "What is SpaceX's latest valuation?"
  2. AI calls exa_answer with the question.
  3. 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:

  1. Switch check: TOOL_<NAME>_ENABLED must be true.
  2. Key check: All required_env_vars must 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

  1. Create src/mcp_server_metasearch/tools/my_tool.py.
  2. 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:
        ...
  1. Add the key and switch to ~/.config/mcp-server-metasearch/.env.
  2. Restart the MCP client. The tool is auto-discovered — no edits to server.py or tool_registry.py needed.

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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mcp_server_metasearch-0.2.7.tar.gz (136.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mcp_server_metasearch-0.2.7-py3-none-any.whl (49.7 kB view details)

Uploaded Python 3

File details

Details for the file mcp_server_metasearch-0.2.7.tar.gz.

File metadata

  • Download URL: mcp_server_metasearch-0.2.7.tar.gz
  • Upload date:
  • Size: 136.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for mcp_server_metasearch-0.2.7.tar.gz
Algorithm Hash digest
SHA256 e8fc5ae68162f07fcc30e3d24a8c591bce668144592ce6e3b820e5bc6626e319
MD5 fb8080f7a2fbe75f28f96f383cf12927
BLAKE2b-256 068360d3eb0c472e40dbe73e2775cf16ee1af3cf3749a12dc01065a90a97279d

See more details on using hashes here.

Provenance

The following attestation bundles were made for mcp_server_metasearch-0.2.7.tar.gz:

Publisher: publish.yml on busigui2023/mcp-server-metasearch

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file mcp_server_metasearch-0.2.7-py3-none-any.whl.

File metadata

File hashes

Hashes for mcp_server_metasearch-0.2.7-py3-none-any.whl
Algorithm Hash digest
SHA256 439ab623dc9ae204dd6df7da6e7d2c134ad98e6a065b7edcf6733792a996f3db
MD5 bbaf283b47a2461ffa8e30b186ee2481
BLAKE2b-256 26226c127fc74e2511e84c29258c3edc7cca35b62661a329c86faed4a5d0b407

See more details on using hashes here.

Provenance

The following attestation bundles were made for mcp_server_metasearch-0.2.7-py3-none-any.whl:

Publisher: publish.yml on busigui2023/mcp-server-metasearch

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page