captain-search
Provides web search capabilities using Brave's independent search index, with a free tier of 2,000 searches per month.
Provides AI-powered web search answers using Perplexity's API, with a free tier of $5/month credit.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@captain-searchsearch for python async await tutorial"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Quick Start
Captain Search should usually start as a CLI workflow, not an MCP setup flow. Install the skill or run the CLI first, prove one command works, and only then add MCP if you explicitly need a server.
From this checkout today
git clone https://github.com/mnm-matin/captain-search.git
cd captain-search
uv sync
uv run csearch skill install --scope user
uv run csearch web "openai api" --max-results 5After the first PyPI release
uvx --from captain-search csearch skill install
uvx --from captain-search csearch web "openai api" --max-results 5Related MCP server: Web Researcher MCP
Supported Providers
Web Search
You only need one provider to get started. Add more for redundancy.
Provider | Free Tier | Best For | Get API Key |
Parallel | $20 on first signup | AI-native web search | |
Serper | 2,500/month | Google results | |
Brave | 2,000/month | Independent index | |
Tavily | 1,000/month | AI-optimized results | |
Exa | $10 credit | Neural/semantic search | |
Perplexity | $5/mo credit | AI-powered answers |
💡 Tip: Serper + Brave = 4,500 free searches/month with automatic failover
Code Search
Provider | Free Tier | Best For | Get API Key |
Exa (MCP) | Unlimited* | Semantic code context | |
Morph (Warp Grep) | Paid | Repo-local agentic search | |
grep.app | Free (no key) | Exact text matching | |
DeepWiki | Free (MCP) | Repo Q&A / Architecture | |
Noodlbox | Temporarily disabled | Local graph analysis |
Webpage Extraction
Provider | Free Tier | Best For | Get API Key |
Parallel Extract | Uses the $20 signup credit | JS-heavy pages, PDFs, clean markdown | |
Jina | 1M tokens | Webpage/PDF extraction | |
Trafilatura (fallback) | Free | Local HTML extraction fallback | |
MarkItDown (optional fallback) | Free | Local document → Markdown (DOCX/PPTX/XLSX/...) |
Enable MarkItDown locally with: uv sync --extra markitdown (minimal) or uv sync --extra markitdown-all (all formats)
Installation
Skill install
If you want an agent to keep reusing Captain Search across sessions or repos, install the Captain Search CLI skill first.
# User-level install from this checkout
uv run csearch skill install --scope user
# Project-local install for the current repo
uv run csearch skill install --scope project
# Claude Code-compatible skill directory
uv run csearch skill install --target claude
# Once published to PyPI
uvx --from captain-search csearch skill installThe installer writes captain-search-cli under .agents/skills by default and can target .claude/skills with --target claude. From a source checkout, --runtime auto bakes in uv run --directory /path/to/captain-search csearch .... From a published package, it defaults to uvx --from captain-search csearch .... Use --force to refresh an existing install.
MCP client install instructions (copy/paste)
Only use this section when the user explicitly wants MCP client setup.
These MCP client configs intentionally use uv run --directory ... because the client may launch the server from an arbitrary working directory and should not depend on your shell having the project virtualenv activated.
You are installing the Captain Search MCP server. First ask the user which API keys they want to configure: SERPER_API_KEY, BRAVE_API_KEY, TAVILY_API_KEY, PERPLEXITY_API_KEY, PARALLEL_API_KEY, EXA_API_KEY, JINA_API_KEY, MORPH_API_KEY. Then ask which client they want to set up (Cursor, Claude Code, VS Code, Windsurf/Antigravity, OpenCode). Use only the keys they choose and remind them at least one web-search key is required.
Then provide the client-specific setup:
- Cursor: give the Captain Search Cursor deeplink and tell them to set the chosen keys as environment variables, then restart Cursor.
- Claude Code: use `claude mcp add captain-search -- uv run --directory /path/to/captain-search csearch mcp` and pass only the chosen keys with `-e KEY=value`.
- VS Code: use the `code --add-mcp` command with only the chosen env keys (or leave them blank if the user wants to fill later).
- Windsurf/Antigravity: add the MCP server to ~/.codeium/windsurf/mcp_config.json with the chosen env keys.
- OpenCode: add to opencode.jsonc under `mcp` with `type: "local"`, `command: ["uv", "run", "--directory", "/path/to/captain-search", "csearch", "mcp"]`, and an `environment` object with the chosen keys.API keys are pulled from your environment (e.g., SERPER_API_KEY). Set them in your shell or system settings, then restart Cursor.
claude mcp add captain-search -e SERPER_API_KEY=your-key -- uv run --directory /path/to/captain-search csearch mcpInstall via terminal:
code --add-mcp '{"name":"captain-search","command":"uv","args":["run","--directory","/path/to/captain-search","csearch","mcp"],"env":{"SERPER_API_KEY":"your-key-here","BRAVE_API_KEY":"","TAVILY_API_KEY":"","PERPLEXITY_API_KEY":"","PARALLEL_API_KEY":"","EXA_API_KEY":"","MORPH_API_KEY":"","JINA_API_KEY":""}}'Or add to your User Settings (JSON) via Ctrl+Shift+P → Preferences: Open User Settings (JSON):
{
"mcp": {
"servers": {
"captain-search": {
"command": "uv",
"args": ["run", "--directory", "/path/to/captain-search", "csearch", "mcp"],
"env": {
"SERPER_API_KEY": "your-key-here",
"BRAVE_API_KEY": "",
"TAVILY_API_KEY": "",
"PERPLEXITY_API_KEY": "",
"PARALLEL_API_KEY": "",
"EXA_API_KEY": "",
"MORPH_API_KEY": "",
"JINA_API_KEY": ""
}
}
}
}
}Or add to .vscode/mcp.json in your workspace to share with your team.
Add to your ~/.codeium/windsurf/mcp_config.json (shared config for Windsurf and Antigravity):
{
"mcpServers": {
"captain-search": {
"command": "uv",
"args": ["run", "--directory", "/path/to/captain-search", "csearch", "mcp"],
"env": {
"SERPER_API_KEY": "your-key-here",
"BRAVE_API_KEY": "",
"TAVILY_API_KEY": "",
"PERPLEXITY_API_KEY": "",
"PARALLEL_API_KEY": "",
"EXA_API_KEY": "",
"MORPH_API_KEY": "",
"JINA_API_KEY": ""
}
}
}
}Add to your opencode.jsonc (project root) under mcp:
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"captain_search": {
"type": "local",
"command": ["uv", "run", "--directory", "/path/to/captain-search", "csearch", "mcp"],
"enabled": true,
"environment": {
"SERPER_API_KEY": "your-key-here",
"BRAVE_API_KEY": "",
"TAVILY_API_KEY": "",
"PERPLEXITY_API_KEY": "",
"PARALLEL_API_KEY": "",
"EXA_API_KEY": "",
"MORPH_API_KEY": "",
"JINA_API_KEY": ""
}
}
}
}git clone https://github.com/mnm-matin/captain-search.git
cd captain-search
uv sync
uv run csearch skill install --scope userIf you want a no-activation, one-off run from this checkout, use uvx:
uvx --from . csearch --help
uvx --from . csearch web "openai api"That creates console scripts in the project virtualenv. If you activate it, you can run the CLI directly:
source .venv/bin/activate
captain-search --help
csearch --helpIf you do not want to activate the virtualenv, you can still call the wrappers directly:
.venv/bin/captain-search --help
.venv/bin/csearch --helpuv run is just the convenience wrapper that runs those same commands inside the project environment.
If you want a persistent command on your shell PATH, install the tool:
uv tool install .If you publish Captain Search to PyPI, end users can skip cloning entirely:
# One-off runs
uvx --from captain-search csearch --help
uvx --from captain-search csearch web "openai api"
# Persistent install
uv tool install captain-searchThen update /path/to/captain-search in the configs above to your actual path.
Available Tools
Tool | Description |
| Search with weighted selection and optional multi-provider mode |
| Search code across Exa, grep.app, DeepWiki, Morph, and local exact matches |
| Extract content from any URL (articles, PDFs, docs) |
search_web provider selector:
auto(default): weighted single-provider selection with fallbackmultiorall: parallel search across all enabled providersProvider name:
serper,brave,tavily,perplexity,parallel,exa,exa_mcpComma-separated list for multi-provider search
search_code providers:
Exa Code Context: Semantic search (always runs)
grep.app: Exact text matching (always runs)
DeepWiki: Repo Q&A (requires repo filter)
Morph Warp Grep: Repo-local agentic search (requires repo filter + MORPH_API_KEY)
Local Exact Matches: Repo-local fixed-string search (requires repo filter)
Noodl: Temporarily disabled
CLI Usage
captain-search and csearch expose the same CLI. The docs use csearch, and MCP server startup now requires an explicit mcp subcommand.
# Bare invocation shows help
csearch
csearch version
csearch skill install --scope user
# Explicit MCP server startup
csearch mcp
csearch mcp --transport http --port 8000
# Direct CLI commands
csearch web "openai api" --max-results 5
csearch web "openai api" --all
csearch code "search_web" --repo mnm-matin/captain-search --format json
csearch fetch https://example.com --format json
# No-activation ephemeral runs with uvx
uvx --from . csearch web "openai api"
# Once published to PyPI
uvx --from captain-search csearch web "openai api"
# No-activation form if you want uv to launch the project env for you
uv run csearch web "openai api"
# Module form also works
uv run python -m captain_search web "openai api"Direct command exit codes are shell-friendly: 0 for successful output, 1 for a top-level command error, and 2 for invalid CLI usage.
Running as a Remote Server
For teams or cloud deployment:
# HTTP mode
captain-search mcp --transport http --port 8000
# SSE mode
captain-search mcp --transport sse --port 8000With Authentication
export MCP_AUTH_TOKEN="your-secret-token"
captain-search mcp --transport http --port 8000Connect via:
Header:
Authorization: Bearer your-secret-tokenQuery:
http://host:8000/mcp?token=your-secret-token
Environment Variables
Variable | Required |
| At least one provider |
| At least one provider |
| At least one provider |
| Optional |
| Optional (web search + webpage extraction) |
| Optional |
| Optional (code search) |
| Optional (defaults to https://api.morphllm.com/v1) |
| Optional (works without) |
| For remote mode |
| Optional (defaults to |
| Optional (defaults to |
| Optional (defaults to |
Every keyed provider also supports a comma-separated *_API_KEYS environment variable for rotation, for example SERPER_API_KEYS, BRAVE_API_KEYS, TAVILY_API_KEYS, PERPLEXITY_API_KEYS, PARALLEL_API_KEYS, EXA_API_KEYS, and JINA_API_KEYS.
Telemetry Logging
Captain Search writes daily JSONL telemetry files to ~/.captain-search/logs/YYYY-MM-DD.jsonl by default.
Each tool call logs:
full input arguments
final output returned to the client
provider attempts and per-provider results
repo resolution and cache events for
search_codeParallel/Jina/fallback stages for
fetch_webpage
If you want to reduce what gets stored, set CAPTAIN_SEARCH_LOG_FULL_PAYLOADS=false to log previews instead of full payloads. Set CAPTAIN_SEARCH_LOG_ENABLED=false to disable logging entirely.
How It Works
Weighted Selection: Providers chosen based on free tier limits
Health-Aware Fallback: If one fails or is cooling down, routing skips it and tries the next
Multi-Provider:
search_webstill supports multi-provider mode internally, while the CLI exposes that breadth ascsearch web --allFetch Routing:
fetch_webpageuses Parallel Extract first whenPARALLEL_API_KEYis configured, then Jina Reader, then local fallbackDoctor Command:
csearch doctorshows configured providers, recent telemetry, and current cooldown state
Default weights: Serper (42%) → Brave (33%) → Tavily (17%) → Perplexity (8%)
Customize via config.yaml:
providers:
serper:
weight: 50
enabled: true
brave:
weight: 30
enabled: trueDocker
docker build -t captain-search .
docker run -p 8000:8000 \
-e SERPER_API_KEY=your_key \
-e MCP_AUTH_TOKEN=your_secret \
captain-search mcp --transport http --port 8000Development
git clone https://github.com/mnm-matin/captain-search.git
cd captain-search
uv pip install -e ".[dev]"
pytestRun the opt-in live provider audit when you want real endpoint checks plus a per-task configured-vs-working summary for web search, code search, and fetch:
RUN_E2E=1 uv run --extra dev python -m pytest -q tests/test_providers.py
LIVE_PROVIDER_CACHE_TTL_SECONDS=900 RUN_E2E=1 uv run --extra dev python -m pytest -q tests/test_providers.py
LIVE_PROVIDER_FORCE_REFRESH=1 RUN_E2E=1 uv run --extra dev python -m pytest -q tests/test_providers.pyThe live audit reuses fresh results from .pytest_cache until the TTL expires and prints a
session-end summary showing how many active providers are working for each task.
License
MIT License - see LICENSE
Available Tools
3 toolsfetch_webpageFetch WebpageARead-onlyIdempotent
Fetch and extract content from a webpage or PDF.
Uses Jina Reader to fetch and convert web pages and PDFs to clean text. Handles JavaScript-rendered pages and extracts content from PDFs. Falls back to Trafilatura extraction if Jina fails.
Args: url: The URL to fetch (web page or PDF)
Returns: Extracted content in markdown format
Examples: - Fetch a webpage: fetch_webpage("https://example.com/article") - Fetch a PDF: fetch_webpage("https://example.com/document.pdf")
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | URL to fetch content from |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare the tool as read-only, non-destructive, and idempotent. The description adds behavioral context about Jina Reader, JavaScript handling, PDF extraction, and fallback to Trafilatura, providing useful transparency beyond annotations.
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?
The description is well-structured with clear sections (Args, Returns, Examples) and is appropriately sized for the tool's simplicity. No unnecessary words.
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?
Given the simple single-parameter tool with an output schema, the description fully covers usage, return format, and fallback behavior. Examples further complete the picture.
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%, so the baseline is 3. The description adds meaning by clarifying that the URL can be a web page or PDF and provides examples, enhancing the semantic understanding.
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?
The description clearly states the tool fetches and extracts content from web pages or PDFs, using a specific verb and resource. It distinguishes from sibling search tools by focusing on fetching a known URL rather than searching.
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?
The description implies usage when a URL is available, and examples demonstrate both web page and PDF fetches. It does not explicitly exclude alternatives, but the context of fetching a specific URL is clear relative to search tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_codeCode SearchARead-onlyIdempotent
Search code across multiple providers.
Args: query: Code search query string repo: Git URL or owner/repo (optional). When provided, results are scoped to this repo.
Returns: Search results in markdown format
| Name | Required | Description | Default |
|---|---|---|---|
| repo | No | Git URL, owner/repo, or local repo path to scope results (e.g., 'facebook/react' or '/path/to/repo'). When provided, enables DeepWiki Q&A, Morph, and local exact matching for that repo. | |
| query | Yes | Code search query (e.g., function names, error messages, API usage) |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, and destructiveHint=false. The description adds that results are in markdown format and that multiple providers are searched, but it does not disclose pagination, rate limits, or provider-specific behaviors.
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?
The description is concise, with three short labeled sections (Overview, Args, Returns). Every sentence serves a purpose, and the key information appears early.
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?
Given the tool's simplicity (2 params, 1 required), the presence of a complete schema and output schema, and annotations covering safety, the description is sufficiently complete. It states purpose, parameters, and return format, which is all a caller needs for basic use.
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%, so a baseline of 3 is appropriate. The description's Arg section mostly repeats the schema's parameter descriptions without adding meaningful new semantics, though it does briefly restate the repo scoping concept.
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?
The description uses a specific verb ('Search') with a clear resource ('code') and adds scope ('across multiple providers'). This distinguishes it from sibling tools like search_web and fetch_webpage.
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?
The description implies usage from the tool name and the phrase 'Search code', but it never explicitly states when to use this tool over search_web or fetch_webpage, nor does it mention exclusions or prerequisites.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_webWeb SearchARead-onlyIdempotent
Search the web using weighted selection or multi-provider search.
Args: query: The search query string max_results: Maximum number of results (1-50, default 10). Per provider in multi mode. provider: Provider selector (default: auto)
Returns: Search results in markdown format
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | Search query | |
| provider | No | Provider selector: auto (default), multi/all, a provider name, or a comma-separated list. | |
| max_results | No | Maximum number of results (1-50). In multi mode, per provider. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description adds context beyond annotations by mentioning the weighted selection or multi-provider modes and stating that results are returned in markdown format. Annotations already declare readOnlyHint=true and destructiveHint=false, so the safe, read-only nature is covered. However, the meaning of 'weighted selection' is not explained, which could confuse an agent.
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?
The description is concise and well-structured with Args and Returns sections. It avoids redundancy and provides essential information in a clear format.
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?
The tool is simple, has an output schema, and the description covers the key aspects. The main gap is the lack of guidance on when to choose this tool over siblings, and some ambiguity around 'weighted selection.' However, for a straightforward search tool, the description is adequately complete.
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?
The input schema already provides complete parameter descriptions (100% coverage). The description repeats the parameters with minimal added value: it clarifies that max_results is per provider in multi mode and specifies the default provider as auto. This is helpful but does not go far beyond the schema.
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?
The description clearly states it searches the web ('Search the web using weighted selection or multi-provider search'), which is a specific verb and resource. It distinguishes itself from sibling tools like search_code and fetch_webpage by its focus on general web search.
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?
The description does not explicitly specify when to use this tool vs alternatives. While the name and scope make it obvious, there is no explicit guidance such as 'for fetching a specific URL, use fetch_webpage instead.' Usage is implied rather than stated.
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.
3 tool updates
v0.1.0- First observed
fetch_webpage - First observed
search_code - First observed
search_web
TDQS
Scored across 3 tools
Each tool serves a clearly distinct purpose: web search, code search, and fetching a specific URL. There is no overlap between the tools, so an agent can easily select the correct one.
All tool names follow a consistent verb_noun pattern with underscores: search_web, fetch_webpage, search_code. This makes the tool set predictable and easy to navigate.
Three tools is slightly minimal for a search-focused server, but it covers the core operations of web search, code search, and page fetching. The count is reasonable for a niche tool set.
The tool set covers the primary search and fetch workflows, but it lacks options like image or news search. Minor gaps exist, but agents can accomplish most tasks without dead ends.
Maintenance
Related MCP Connectors
Search GitHub, npm, PyPI, StackOverflow, ArXiv from one MCP — built for coding agents.
Scrape, crawl and search the web for AI agents via MCP.
LLM-ready web search + instant answers + URL-to-clean-text fetch for agents and RAG.
Multi-engine search for AI agents. Trust scoring, local corpus, MCP-native. Self-hostable, BYOK.
Related MCP Servers
- AlicenseAqualityAmaintenanceA local-first, no-API-key MCP server that enables LLMs to search the web, fetch pages, and read documents using multiple engines and smart fallbacks.1073MIT
- AlicenseAqualityAmaintenanceMCP server for AI-powered web research — search (Google, Brave, Serper, SearXNG), scrape any page, extract PDFs/DOCX/YouTube transcripts, academic & patent search. Single Go binary. Works with Claude, Cursor, Copilot, and any MCP client.2558MIT
- AlicenseNot gradedqualityDmaintenanceWeb search, page fetching, and research from the terminal or any MCP client — no API key required.1MIT
- AlicenseNot gradedqualityCmaintenanceA self-hosted, MCP-native web-search backend for AI agents that provides meta-search, clean extraction, RAG with citations, and GitHub project selection.3MIT