Researcher MCP Server
README.md
# Researcher MCP Server
A Model Context Protocol (MCP) server that researches answers to user
questions using full DuckDuckGo web search, DuckDuckGo news search, and
Wikipedia. Connect it to any MCP-capable client (LM Studio, Claude Desktop,
VS Code, etc.) to give a local LLM web-research abilities with current-events
coverage.
## Tools Provided
| Tool | Description |
|------|-------------|
| `research(query)` | Full research report — classifies the query and mixes sources: news queries get dated recent articles, factual questions get a Wikipedia summary plus corroborating web sources and related news, everything else gets full web results |
| `search(query, max_results?)` | Raw web search results (title, URL, snippet) |
| `news(query, timelimit?, max_results?)` | Recent news articles with publication date and source name; `timelimit` is `d`/`w`/`m` (day/week/month) |
| `extract(url)` | Fetches a URL and returns its readable text (HTML parsed with BeautifulSoup); http/https text content only, size-capped, non-public addresses refused |
| `get_current_time(location_hint?)` | Current date and time, labeled with the timezone used |
When a search backend is unavailable (DuckDuckGo rate-limits under heavy use),
the tools report that explicitly — `research` adds a "SOURCES UNAVAILABLE"
section and `search`/`news` raise an error — so an empty result always means
"nothing found" rather than "the lookup failed".
## Transports
The server picks its transport from the `MCP_TRANSPORT` environment variable:
- **`stdio`** (default) — for MCP clients that launch the server directly
- **`streamable-http`** — network mode; listens on `MCP_HOST`:`MCP_PORT`
(default `0.0.0.0:8000`) at the **`/mcp`** path. This is what
`docker-compose.yml` uses.
## Configuration
| Variable | Default | Purpose |
|----------|---------|---------|
| `MCP_TRANSPORT` | `stdio` | `stdio` or `streamable-http` |
| `MCP_HOST` / `MCP_PORT` | `0.0.0.0` / `8000` | Bind address for HTTP mode |
| `DEFAULT_TIMEZONE` | `UTC` | IANA zone for timestamps when no hint is given. **Set this** — containers run on UTC, so leaving it default makes the server report a time hours off from yours (and sometimes the wrong day). |
| `ALLOW_PRIVATE_URLS` | unset | Set to `1` to let `extract` reach private/loopback addresses. Leave unset unless you specifically need to fetch internal pages. |
| `LOG_LEVEL` | `INFO` | Logging verbosity (logs go to stderr) |
## Quick Start (Docker, recommended)
```powershell
cd "d:/Local Development/Researcher MCP Server"
docker compose up -d --build
```
The server is then available to MCP clients at `http://localhost:8000/mcp`.
Check status and logs:
```powershell
docker compose ps
docker compose logs -f researcher
```
## Quick Start (Python, stdio)
```powershell
pip install -r requirements.txt
```
Then configure your MCP client to launch it — for example in an
`mcp.json`-style config:
```json
{
"mcpServers": {
"researcher": {
"command": "python",
"args": ["d:/Local Development/Researcher MCP Server/researcher_server.py"]
}
}
}
```
Don't run `python researcher_server.py` standalone and expect an HTTP port —
in stdio mode the client launches and owns the process. For HTTP mode outside
Docker, set the env vars first:
```powershell
$env:MCP_TRANSPORT = "streamable-http"; python researcher_server.py
```
## Connecting LM Studio
See [LM_STUDIO_SETUP.md](./LM_STUDIO_SETUP.md) (both methods) and
[LM_STUDIO_DOCKER_SETUP.md](./LM_STUDIO_DOCKER_SETUP.md) (Docker walkthrough).
The short version — in LM Studio 0.3.17+, edit `mcp.json` via
Chat → Program sidebar → Install → Edit mcp.json:
```json
{
"mcpServers": {
"researcher": {
"url": "http://localhost:8000/mcp"
}
}
}
```
## How It Works
```
User question
↓
MCP client (LM Studio, Claude, ...) calls the `research` tool
↓
Query classification (news / factual / general)
↓
Sources queried in parallel:
- DuckDuckGo web search (full index, via ddgs)
- DuckDuckGo news search (dated articles with sources)
- Wikipedia API (encyclopedic summaries)
↓
Formatted research report with dates and source URLs → back to the client
```
## Dependencies
- `mcp` — official MCP Python SDK (FastMCP server)
- `httpx` — async HTTP client for Wikipedia and page extraction
- `ddgs` — DuckDuckGo web and news search
- `beautifulsoup4` — HTML parsing for page extraction
- `tzdata` — timezone database (slim/Windows images don't ship one)
## Running the Tests
The test suite covers the classification, timezone, URL-policy, and formatting
logic without touching the network:
```powershell
pip install -r requirements-dev.txt
pytest -q
```
## Troubleshooting
### Container exits immediately
Make sure `MCP_TRANSPORT=streamable-http` is set (docker-compose.yml does
this). Without it the server runs in stdio mode and exits as soon as stdin
closes — which is immediately, in a detached container.
### Client can't connect over HTTP
- Confirm the container is up: `docker compose ps`
- The endpoint is `http://localhost:8000/mcp` — the `/mcp` path is required
- `curl http://localhost:8000/mcp` returning a JSON-RPC error object means the
server is up (a bare GET is expected to be rejected)
### Empty or thin search results
- Check internet connectivity from where the server runs
- DuckDuckGo occasionally rate-limits heavy usage; the report will say
"SOURCES UNAVAILABLE" when that happens — wait a moment and retry
### Reported time is wrong
Set `DEFAULT_TIMEZONE` to your IANA zone (e.g. `America/Los_Angeles`) in
`docker-compose.yml`. Containers run on UTC by default.
### `extract` refuses a URL
Non-public addresses (loopback, `10.x`, `192.168.x`, `169.254.x`) and
non-text content types are blocked by design. Set `ALLOW_PRIVATE_URLS=1` if
you genuinely need to fetch internal pages.
## License
MIT License - See LICENSE file for details.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessSyncing