Skip to main content
Glama
gabriansa

finviz-screener-mcp

by gabriansa

finviz-screener-mcp

FastMCP server that exposes only Finviz’s stock screener via finvizfinance.

US-only: every screen() call hardcodes Country=USA. No news, maps, insider trading, or Elite API — just screener filters → structured JSON.

Tools

Tool

Purpose

list_filters

Progressive discovery (index / one category / one section / search) — avoids dumping ~1694 values

screen

Compact screener results (default limit 25, max 100; offset capped at 400; null fields and the always-USA Country column stripped)

Both tools are annotated read-only (readOnlyHint) so clients can skip confirmation prompts. Invalid input and upstream failures are raised as MCP tool errors (isError: true) with messages like [invalid_filter] ... or [upstream] ..., so agents can self-correct.

Keep agent context small

list_filters()                         → category names + counts only
list_filters(category="Sector")        → values for Sector only
list_filters(section="signals")        → signals only
list_filters(query="rsi")              → matching names
screen(..., limit=15, table="custom", columns=[...])  → only needed fields

Example screen call:

{
  "filters": {
    "Sector": "Technology",
    "Market Cap.": "Large ($10bln to $200bln)"
  },
  "table": "custom",
  "order": "Market Cap.",
  "ascend": false,
  "columns": ["Ticker", "Market Cap.", "P/E", "RSI", "Price"],
  "limit": 15
}

Important caveats

  • Unofficial scrape. finvizfinance parses the free Finviz HTML screener. There is no free official API; Elite’s CSV/API export is a separate paid surface and is not used here.

  • Quotes on the free site are delayed.

  • Scraping can break if Finviz changes its DOM, and may be against Finviz Terms of Service. Use responsibly.

Proxy fallback (for hosted/cloud IPs)

Datacenter hosts (e.g. Horizon) are often IP-blocked by Finviz (screen → HTTP 403), even though the same code works fine from a home connection. screen() handles this automatically:

  1. Reuse the proxy that served the previous request, if there is one — no probing needed.

  2. Try the direct connection (the only path taken locally). Once it fails, it's skipped for FINVIZ_DIRECT_COOLDOWN seconds (default 600) so a blocked host stops paying the timeout on every call, then retried in case the block was temporary.

  3. Rotate through free proxies from a handful of actively-maintained GitHub lists (proxy_pool.py), pulling fresh lists as older ones are used up, until a request lands or FINVIZ_FETCH_BUDGET seconds (default 45) elapse.

Most free proxies are dead, so trying them one at a time would spend a full connect timeout per corpse. Instead the pool probes candidates concurrently against Finviz itself (40 at a time) and only hands back ones that answered HTTP 200 — which also screens out proxies Finviz has already blocked. In practice a cold rotation finds a working route in ~15s and subsequent calls reuse it in ~5s.

No configuration needed. This is still best-effort — free proxies are inherently unreliable. For a guaranteed hosted fix, point finvizfinance.util.set_proxy at a paid residential proxy instead (datacenter proxies tend to get 403'd same as the host itself).

Local setup

Requires Python 3.11+ (3.12 recommended; see .python-version).

python -m venv .venv
source .venv/bin/activate   # Windows: .venv\Scripts\activate
pip install -r requirements.txt

Run the server (stdio):

fastmcp run main.py:mcp
# or
python main.py

Inspect tools:

fastmcp inspect main.py:mcp

Cursor / Claude Desktop (stdio)

{
  "mcpServers": {
    "finviz-screener": {
      "command": "uv",
      "args": ["run", "--with-requirements", "requirements.txt", "fastmcp", "run", "main.py:mcp"],
      "cwd": "/absolute/path/to/finviz-screener-mcp"
    }
  }
}

Or with an activated venv:

{
  "mcpServers": {
    "finviz-screener": {
      "command": "/absolute/path/to/finviz-screener-mcp/.venv/bin/fastmcp",
      "args": ["run", "main.py:mcp"],
      "cwd": "/absolute/path/to/finviz-screener-mcp"
    }
  }
}

No API key or .env is required.

Deploy on Prefect Horizon (FastMCP Cloud)

Horizon is the managed host from the FastMCP team (docs; console: horizon.prefect.io). URLs look like https://{name}.fastmcp.app/mcp.

  1. Push this repo to GitHub.

  2. Sign in at horizon.prefect.io with GitHub and select the repo.

  3. Configure:

    • Entrypoint: main.py:mcp

    • Dependencies: requirements.txt (auto-detected)

  4. Deploy. Horizon ignores if __name__ == "__main__" and installs deps from requirements.txt.

  5. Connect clients to https://your-server-name.fastmcp.app/mcp.

No environment variables or secrets are required for this server. If you add any later: Settings → Environment Variables, mark sensitive, then rebuild and redeploy (env changes do not hot-reload).

Smoke check

python -c "
from main import list_filters, screen
print([c['name'] for c in list_filters()['categories'][:5]])
print(screen(filters={'Sector': 'Technology'}, limit=3)['count'])
"