{
  "markdown": "# openresearch-mcp\n\n[![PyPI version](https://img.shields.io/pypi/v/openresearch-mcp)](https://pypi.org/project/openresearch-mcp/)\n[![Python versions](https://img.shields.io/pypi/pyversions/openresearch-mcp)](https://pypi.org/project/openresearch-mcp/)\n[![License](https://img.shields.io/pypi/l/openresearch-mcp)](LICENSE)\n[![CI](https://img.shields.io/github/actions/workflow/status/olanokhin/openresearch-mcp/ci.yml?branch=main&label=CI)](https://github.com/olanokhin/openresearch-mcp/actions/workflows/ci.yml)\n[![MCP Registry](https://img.shields.io/badge/MCP_Registry-listed-blue)](https://registry.modelcontextprotocol.io)\n\n**Zero-auth, security-hardened research MCP for cross-domain agents.**\n\nGive Claude, Cursor, OpenCode, Open WebUI, or any MCP-compatible agent a full research stack — web search, academic papers, PDFs, GitHub repos, news, macro & finance data, SEC filings, biomedical literature, Bluesky, and YouTube — with **no API keys to manage**. 22 tools, one install.\n\n## Why\n\nResearch agents are only as good as the sources they can reach. But every extra source usually means another API key, another signup, another quota to babysit — and more attack surface.\n\nopenresearch-mcp is built for **local-first agents that need useful public data now**, with safer defaults:\n\n- **No logins, no keys** — every tool works out of the box; optional env vars only *raise* rate limits.\n- **Hardened by design** — loopback-bound by default, SSRF-filtered URL fetching, prompt-injection-aware extraction, bounded downloads, graceful failures. [Security-reviewed](SECURITY.md) against OWASP for AI agents.\n- **Cheap in context** — the whole 22-tool surface is a measured ~6.2K tokens (~3% of a 200K window), and the number is [generated by a script in the repo](scripts/context_cost.py), not guessed.\n\n## What you can do\n\nThe value isn't 22 tools in isolation — it's chaining them into one cross-domain research pass:\n\n- **Company research** → `search_sec_filings` / `get_company_financials` → `search_news` → `read_repo` → `read_url`\n- **Academic deep-dive** → `search_openalex` → `search_europepmc` → `read_pdf`\n- **Macro & country context** → `search_indicators` → `get_country_indicator` → `get_fx_rate` → `get_historical_weather`\n\n## Quickstart\n\n```bash\nuvx openresearch-mcp --stdio\n```\n\nPoint any MCP client at it (Claude Desktop, Cursor, or an HTTP agent — see [Connect](#connect-to-an-mcp-client)) and ask something cross-domain:\n\n> *\"Pull Apple's latest annual revenue from its SEC filings, then find recent news on its AI strategy.\"*\n\nThe agent chains `get_company_financials` → `search_news` for you — no keys, no setup.\n\n## Install\n\n### From the MCP Registry (recommended for Claude Desktop / Cursor)\n\nThe server is listed on the [official MCP Registry](https://registry.modelcontextprotocol.io) as `io.github.olanokhin/openresearch-mcp`. Registry-aware clients can discover and install it without manual config — search for `openresearch-mcp` in your client's MCP browser.\n\n### From PyPI\n\n```bash\n# Zero install, always isolated — recommended for manual use\nuvx openresearch-mcp\n\n# Or install globally\npip install openresearch-mcp\nopenresearch-mcp\n```\n\nBy default the server starts on `http://127.0.0.1:8000/mcp` (Streamable HTTP, MCP 1.1+) — bound to loopback so it is not exposed to your local network. To expose it (e.g. in a container or behind a gateway), bind all interfaces explicitly:\n\n```bash\n# Custom port\nuvx openresearch-mcp --port 9000\n\n# Bind all interfaces (only behind an auth/rate-limit gateway)\nuvx openresearch-mcp --host 0.0.0.0 --port 9000\n```\n\n> **Note:** when binding beyond loopback, put an auth/rate-limit gateway in front. The server is zero-auth by design, and `read_url`/`read_pdf` fetch arbitrary URLs (private/link-local/loopback ranges are blocked to prevent SSRF, but rate limiting is your responsibility).\n\n## Connect to an MCP client\n\n### Claude Desktop\n\nEdit `~/Library/Application Support/Claude/claude_desktop_config.json`  \n(Windows: `%APPDATA%\\Claude\\claude_desktop_config.json`)\n\n```json\n{\n  \"mcpServers\": {\n    \"openresearch\": {\n      \"command\": \"uvx\",\n      \"args\": [\"openresearch-mcp\", \"--stdio\"]\n    }\n  }\n}\n```\n\nRestart Claude Desktop after saving. The server runs in stdio mode — no port needed.\n\n### Cursor\n\nCreate or edit `~/.cursor/mcp.json` (global) or `.cursor/mcp.json` (per-project):\n\n```json\n{\n  \"mcpServers\": {\n    \"openresearch\": {\n      \"command\": \"uvx\",\n      \"args\": [\"openresearch-mcp\", \"--stdio\"]\n    }\n  }\n}\n```\n\n### HTTP agents (OpenCode, Open WebUI, custom)\n\nStart the server:\n\n```bash\nuvx openresearch-mcp\n# or: openresearch-mcp\n```\n\nPoint your agent at:\n\n```text\nhttp://localhost:8000/mcp\n```\n\n## Tools\n\n<!-- context-cost:start -->\n\nThe `~Tok` column is each tool's full definition (name + description + JSON input schema, as sent in `tools/list`) — injected into the agent context on **every request**.\n\n| Tool | Source | Notes | ~Tok |\n| ---- | ------ | ----- | ---: |\n| `web_search` | DuckDuckGo | Optional `site=` param to scope to a domain (e.g. `arxiv.org`) | 251 |\n| `read_url` | Any webpage | Strips nav/scripts, returns clean text | 164 |\n| `read_pdf` | Any PDF or arXiv | Accepts `/abs/`, `/pdf/`, `/html/` arXiv URLs interchangeably | 181 |\n| `read_repo` | GitHub public repos | README + file tree + key docs; set `GITHUB_TOKEN` for 5k req/hr | 211 |\n| `search_hacker_news` | HN via Algolia | Story search with points + comment counts | 206 |\n| `search_stackoverflow` | Stack Overflow API | Set `STACKEXCHANGE_KEY` for higher quota | 212 |\n| `search_openalex` | OpenAlex | 250M+ works, zero rate limiting; set `OPENALEX_EMAIL` for polite pool | 231 |\n| `get_youtube_transcript` | YouTube captions | Accepts full URLs, `youtu.be/` links, shorts, or bare video IDs | 194 |\n| `get_current_date` | Server clock | Current UTC date/time — anchors relative requests (\"last 30 days\") instead of guessing | 240 |\n| `get_weather_forecast` | Open-Meteo | Current conditions + up to 16-day forecast by place name; no key. See licensing note below | 229 |\n| `get_historical_weather` | Open-Meteo | Climate series since 1940 for a place + date range, aggregated monthly/yearly; no key. See licensing note below | 328 |\n| `search_indicators` | World Bank | Find an indicator code by keyword (\"GDP\", \"migration\"); feed into `get_country_indicator` | 240 |\n| `get_country_indicator` | World Bank | Yearly socio-economic series (GDP, population, inflation, migration, life expectancy…) by country + code; no key | 338 |\n| `get_fx_rate` | Frankfurter (ECB) | Currency rates: latest, a historical date, or a date-range series (downsample week/month); no key | 367 |\n| `get_crypto_price` | CoinGecko | Crypto price (current or daily history) by coin id/symbol vs a quote currency; no key | 284 |\n| `search_news` | GDELT | Fresh global news on a topic (multilingual); returns articles to feed into `read_url`; no key (rate-limited ~1/5s) | 481 |\n| `search_europepmc` | Europe PMC | Biomedical/life-science papers; flags open-access and gives a PDF URL to feed into `read_pdf`; no key | 264 |\n| `search_bluesky_users` | Bluesky | Find researcher/dev profiles by name, handle, or bio; no key | 227 |\n| `get_bluesky_profile` | Bluesky | Full bio + follower/post counts for a handle; no key | 200 |\n| `read_bluesky_feed` | Bluesky | A user's recent original posts (reposts/replies filtered); no key | 228 |\n| `get_company_financials` | SEC EDGAR | Annual revenue, earnings, assets for a US-listed company by ticker (10-K filings); no key (set `SEC_USER_AGENT` for heavy use) | 233 |\n| `search_sec_filings` | SEC EDGAR | Full-text search of filings (10-K/10-Q/8-K) by keyword/company; returns a document URL to feed into `read_url`/`read_pdf`; no key | 300 |\n| **All 22 tool definitions** | | | **5,609** |\n| Server `instructions` | | selection guide + chaining recipes | 815 |\n| **Total per request** | | ≈ 3% of a 200K context window | **6,424** |\n\n_Tokens measured with tiktoken `o200k_base` (GPT-4o / o-series encoding), offline; Claude's tokenizer differs by ~±10-15%. This table is generated — run `uv run python scripts/context_cost.py --write`; CI fails if it drifts._\n\n<!-- context-cost:end -->\n\n## Optional env vars\n\nAll tools work without any keys. Set these to increase rate limits:\n\n| Variable | Effect |\n| -------- | ------ |\n| `GITHUB_TOKEN` | GitHub: 60 → 5,000 req/hr |\n| `OPENALEX_EMAIL` | OpenAlex polite pool (higher limits) |\n| `STACKEXCHANGE_KEY` | Stack Overflow: higher daily quota |\n| `SEC_USER_AGENT` | Your contact (e.g. email) for SEC EDGAR fair-access; a default is used otherwise |\n\nExample with keys:\n\n```bash\nGITHUB_TOKEN=ghp_... OPENALEX_EMAIL=you@example.com uvx openresearch-mcp\n```\n\nOr in Claude Desktop config:\n\n```json\n{\n  \"mcpServers\": {\n    \"openresearch\": {\n      \"command\": \"uvx\",\n      \"args\": [\"openresearch-mcp\", \"--stdio\"],\n      \"env\": {\n        \"GITHUB_TOKEN\": \"ghp_...\",\n        \"OPENALEX_EMAIL\": \"you@example.com\"\n      }\n    }\n  }\n}\n```\n\n## Security\n\nopenresearch-mcp was reviewed and hardened using **[agent-security-skill](https://github.com/olanokhin/agent-security-skill)**,\nan OWASP-aligned AI agent security review skill developed by the maintainer.\n\nThat review directly led to concrete hardening in this server: SSRF-resistant URL fetching,\nuntrusted-content framing for tool outputs, bounded downloads, pinned GitHub Actions,\ndependency major-version caps, and regression tests for security-sensitive behavior.\n\nSee the hardening notes and current security posture in **[SECURITY.md](SECURITY.md)**.\n\n## Health check\n\nWhen running in HTTP mode, check which sources are reachable:\n\n```bash\ncurl http://localhost:8000/health\n```\n\n```json\n{\n  \"status\": \"ok\",\n  \"sources\": {\n    \"duckduckgo\":    { \"status\": \"ok\", \"latency_ms\": 173 },\n    \"github\":        { \"status\": \"ok\", \"latency_ms\": 101 },\n    \"hacker_news\":   { \"status\": \"ok\", \"latency_ms\": 308 },\n    \"stackoverflow\": { \"status\": \"ok\", \"latency_ms\": 247 },\n    \"openalex\":      { \"status\": \"ok\", \"latency_ms\": 412 },\n    \"worldbank\":     { \"status\": \"ok\", \"latency_ms\": 296 },\n    \"frankfurter\":   { \"status\": \"ok\", \"latency_ms\": 184 },\n    \"europepmc\":     { \"status\": \"ok\", \"latency_ms\": 356 },\n    \"bluesky\":       { \"status\": \"ok\", \"latency_ms\": 152 },\n    \"youtube\":       { \"status\": \"ok\", \"latency_ms\": 320 }\n  }\n}\n```\n\n`status` is `\"ok\"`, `\"degraded\"` (some sources down), or `\"down\"` (all unreachable). HTTP 200 / 503.\n`/health` is a lightweight upstream reachability sample, not a per-tool status matrix.\nRate-limited or policy-sensitive sources (GDELT, SEC, CoinGecko, etc.) are checked when their tools are called.\n\n## Known limitations\n\n- **Reddit / Zenodo**: block unauthenticated scraping — not included\n- **YouTube**: rate-limited at scale; works well for personal/low-volume use\n- **Weather (Open-Meteo)**: data is licensed **[CC BY 4.0](https://open-meteo.com/en/license)** and free for **non-commercial** use up to ~10,000 requests/day. **Commercial use requires Open-Meteo's paid plan or self-hosting** — embedding `get_weather_forecast` in a commercial product without one inherits a license obligation. Attribution to Open-Meteo is required.\n- **PDF parsing**: `read_pdf` parses untrusted PDFs in-process (with download-size and page caps). Fine for personal/low-volume use; a public high-volume deployment should isolate parsing in a subprocess with CPU/memory limits.\n\n## Roadmap\n\n- [ ] Reddit OAuth (browser-based, no user key management)\n- [ ] GitHub Device Flow login\n- [ ] PubMed / NCBI (optional key)\n- [ ] NewsAPI support (optional key)\n\n## License\n\nApache 2.0\n\n<!-- mcp-name: io.github.olanokhin/openresearch-mcp -->\n",
  "bytes": 11631,
  "sha": "7e8135d1ed81426b2f6e34fa88199f749c55f509ae032bde594efd0ea6402579",
  "repo_slug": "olanokhin/openresearch-mcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_olanokhin_openresearch_mcp_866e3a0c/readme"
}