Server data from the Official MCP Registry
Screen and score stocks with the Quality Screener engine: filters, custom scores, and history.
Screen and score stocks with the Quality Screener engine: filters, custom scores, and history.
Remote endpoints: streamable-http: https://mcp.qualityscreener.io/mcp
A well-architected MCP server for the Quality Screener financial API with proper authentication, secure token handling, and appropriate permission scoping. The codebase is clean with good separation of concerns. Minor code quality issues around broad exception handling do not materially impact security posture. Supply chain analysis found 3 known vulnerabilities in dependencies (0 critical, 3 high severity).
5 files analyzed · 7 issues found
Security scores are indicators to help you make informed decisions, not guarantees. Always review permissions before connecting any MCP server.
This plugin requests these system permissions. Most are normal for its category.
Set these up before or after installing:
Environment variable: QSCREENER_API_URL
Environment variable: QSCREENER_MCP_TRANSPORT
Environment variable: QSCREENER_WEBSITE_URL
Environment variable: QSCREENER_MCP_PUBLIC_URL
Environment variable: QSCREENER_MCP_PORT
Environment variable: QSCREENER_MCP_HOST
Environment variable: QSCREENER_CONFIG_DIR
Available as Local & Remote
This plugin can run on your machine or connect to a hosted endpoint. during install.
From the project's GitHub README.
A standalone Model Context Protocol (MCP) server that exposes the Quality Screener stock-screening engine as tools for AI agents (Claude, Cursor, and any other MCP client).
Once connected, an agent can screen and filter the scored universe, compute custom quality scores, inspect score history, manage saved scoring systems, and generate shareable screen links — acting as the signed-in user, against the same data they see in the web dashboard.
CustomScoreConfig┌─────────────┐ MCP (stdio | streamable-HTTP) ┌──────────────────┐ HTTPS ┌──────────────────────┐
│ AI agent │ ────────────────────────────────► │ qscreener-mcp │ ────────► │ Quality Screener API │
│ (MCP client)│ ◄──────────────────────────────── │ (this server) │ ◄──────── │ (FastAPI backend) │
└─────────────┘ tool calls / JSON └──────────────────┘ REST └──────────────────────┘
Each MCP tool maps to one Quality Screener REST endpoint. The server attaches
the caller's bearer token to every outbound request (header
X-Stobot-CLI-Token, Authorization: Bearer … also accepted) and returns the
decoded JSON. There is no business logic in the server itself — it is a typed,
authenticated façade over the API.
It runs in two transport modes:
| Transport | Use | Authentication |
|---|---|---|
stdio (default) | A local agent (e.g. Claude Code) launches the server as a subprocess | Token from $QSCREENER_TOKEN or ~/.config/qscreener/credentials.json |
streamable-http | A remote, externally reachable deployment (e.g. Railway) | End-to-end MCP OAuth 2.0 — the client opens the browser once, then sends the token automatically; or a per-request X-Stobot-CLI-Token header |
Over HTTP the MCP endpoint is served at /mcp.
The easiest way to use the server is to point your MCP client at the hosted deployment. No token to copy — the client triggers a browser sign-in on first connect:
{
"mcpServers": {
"qscreener": {
"type": "streamable-http",
"url": "https://mcp.qualityscreener.io/mcp"
}
}
}
On first use your browser opens the Quality Screener sign-in page. Approve once, and the agent stays connected. You need a Quality Screener account; the agent inherits exactly your access.
Requires uv.
# Install dependencies
uv sync
# stdio — for a local agent that launches this as a subprocess
uv run qscreener-mcp
# streamable-HTTP — mirrors the remote deployment
QSCREENER_MCP_TRANSPORT=streamable-http QSCREENER_MCP_PORT=8080 \
QSCREENER_API_URL=http://localhost:8001 \
uv run qscreener-mcp
# -> MCP endpoint at http://localhost:8080/mcp
With Docker:
docker build -t qscreener-mcp .
docker run --rm -p 8080:8080 \
-e QSCREENER_API_URL=https://your-backend.example.com \
-e QSCREENER_MCP_PUBLIC_URL=http://localhost:8080 \
qscreener-mcp
# -> MCP endpoint at http://localhost:8080/mcp
By default the container runs the streamable-http transport on port 8080.
All configuration is via environment variables, resolved at startup.
| Env var | Default | Meaning |
|---|---|---|
QSCREENER_API_URL | http://localhost:8001 | Base URL of the Quality Screener backend API the tools call |
QSCREENER_MCP_TRANSPORT | stdio | stdio, streamable-http, or sse |
QSCREENER_WEBSITE_URL | http://localhost:3001 | Web-app base URL used to build the OAuth browser-login link and shareable screen URLs |
QSCREENER_MCP_PUBLIC_URL | http://localhost:{PORT|8080} | Publicly reachable base URL of this server; used to build the OAuth callback URL |
PORT | — | Bind port for HTTP transports (Railway sets this automatically) |
QSCREENER_MCP_PORT | 8080 | Bind port fallback when PORT is unset |
QSCREENER_MCP_HOST | 0.0.0.0 | Bind host for HTTP transports |
QSCREENER_TOKEN | — | Bearer-token override for stdio mode (single user) |
QSCREENER_CONFIG_DIR | ~/.config/qscreener | Directory holding credentials.json for stdio mode |
The server resolves a bearer token for each call with the following precedence:
X-Stobot-CLI-Token, then Authorization: Bearer <token>.$QSCREENER_TOKEN environment variable.$QSCREENER_CONFIG_DIR/credentials.json — the token field.For a streamable-http deployment, authentication is fully automated via the
MCP OAuth flow:
/oauth/callback.The token is validated on each request by calling the backend's
/v1/cli/auth/whoami endpoint, so a revoked or expired token is rejected
immediately. The server never persists user tokens.
Mint a token through the browser login flow and store it locally, then run the server over stdio:
qscreener auth login # opens the web app, stores a token
cat ~/.config/qscreener/credentials.json # the "token" field is your bearer token
Or set QSCREENER_TOKEN directly for CI / scripted use.
All tools require authentication. Filters use OR logic within a filter and AND logic across filters. Market caps are always in USD.
| Tool | Signature | Description |
|---|---|---|
auth_status | auth_status() | Whether a token is present and which user it authenticates as. |
account_profile | account_profile() | The signed-in user's profile (email, username, organization). |
health | health() | API and database health check. |
| Tool | Signature | Description |
|---|---|---|
scores_top | scores_top(limit=20) | Top tickers by quality score, as a {ticker: score} map. |
scores_list | scores_list(ticker=None, sectors=None, industries=None, countries=None, currencies=None, exchanges=None, min_score=None, max_score=None, min_market_cap_usd=None, max_market_cap_usd=None, sort_by="quality_score", sort_order="desc", offset=0, limit=50, include_duplicates=False) | List scored tickers with optional filters. |
scores_show | scores_show(ticker) | Full score row(s) for a single ticker. |
scores_for_tickers | scores_for_tickers(tickers, scoring_system_id=None) | Current scores for a specific list of tickers, under default scoring or a saved scoring system. Unknown tickers are omitted. |
scores_statistics | scores_statistics(sectors=None, min_score=None, max_score=None, min_market_cap_usd=None, max_market_cap_usd=None) | Min / max / average score statistics for a filtered universe. |
scores_market_cap | scores_market_cap(sectors=None, min_score=None) | Aggregated total market cap (USD) for a filtered universe. |
score_compute | score_compute(config, sectors=None, industries=None, countries=None, currencies=None, exchanges=None, min_market_cap_usd=None, max_market_cap_usd=None, sort_by="quality_score", sort_order="desc", offset=0, limit=50, include_duplicates=False) | Compute custom scores from a CustomScoreConfig, restricted to a filtered universe. |
| Tool | Signature | Description |
|---|---|---|
screen_share | screen_share(config) | Persist a CustomScoreConfig and return a public, copy-pasteable share link (url, slug, created, view_count). Content-addressed: an identical config returns the same link. |
| Tool | Signature | Description |
|---|---|---|
filters_list | filters_list() | Available filter values (sectors, industries, countries, currencies, exchanges). |
tickers_list | tickers_list(limit=None) | Available tickers, optionally truncated to limit. |
tickers_search | tickers_search(query) | Search available tickers by case-insensitive substring. |
Dates are YYYY-MM-DD. Pass scoring_system_id to compute history against a
saved scoring system instead of the default quality score.
| Tool | Signature | Description |
|---|---|---|
history_ticker | history_ticker(ticker, start=None, end=None, scoring_system_id=None) | Score history for a single ticker over a date range. |
history_batch | history_batch(tickers, start=None, end=None, scoring_system_id=None) | Score history for several tickers at once. |
history_top | history_top(top=10, scoring_system_id=None) | Fetch the current top-N tickers and return their score history. |
A scoring system is a named, reusable CustomScoreConfig stored against your
account.
| Tool | Signature | Description |
|---|---|---|
systems_list | systems_list() | List your saved scoring systems. |
systems_show | systems_show(system_id) | Show a saved scoring system by ID. |
systems_create | systems_create(name, config, description=None) | Create a saved scoring system from a config object. |
systems_update | systems_update(system_id, name=None, config=None, description=None) | Update a saved scoring system. |
systems_delete | systems_delete(system_id) | Delete a saved scoring system. |
systems_apply | systems_apply(system_id) | Apply a saved scoring system (increments its usage count). |
CustomScoreConfigscore_compute, screen_share, and the systems_* tools accept a
CustomScoreConfig object describing how to weight financial metrics. Its shape
mirrors the score builder in the web dashboard: weighted metric groups, each
containing weighted metrics, plus statistical options. A minimal example:
{
"name": "My quality screen",
"groups": [
{
"id": "returns",
"name": "Returns",
"weight": 0.5,
"metrics": [
{ "id": "roe", "name": "ROE", "weight": 0.5 },
{ "id": "roic", "name": "ROIC", "weight": 0.5 }
]
},
{
"id": "profitability",
"name": "Profitability",
"weight": 0.5,
"metrics": [
{ "id": "profit_margin", "name": "Profit Margin", "weight": 1.0 }
]
}
],
"winsorize": true,
"zScore": true
}
Use filters_list to discover valid filter values, and build a config
interactively in the dashboard if you want a starting point to copy.
Any streamable-http MCP client works. No token needed — OAuth handles login:
{
"mcpServers": {
"qscreener": {
"type": "streamable-http",
"url": "https://mcp.qualityscreener.io/mcp"
}
}
}
If your client cannot perform the OAuth flow, send a minted token directly:
{
"mcpServers": {
"qscreener": {
"url": "https://mcp.qualityscreener.io/mcp",
"headers": { "X-Stobot-CLI-Token": "<your token>" }
}
}
}
{
"mcpServers": {
"qscreener": {
"command": "uv",
"args": ["run", "--directory", "/path/to/quality-screener-mcp-server", "qscreener-mcp"],
"env": { "QSCREENER_API_URL": "https://your-backend.example.com" }
}
}
}
The server deploys as a single container. On Railway:
New service → Deploy from repo, pointing at this repository. The Dockerfile is self-contained, so the build context is the repo root.
Set environment variables:
QSCREENER_MCP_TRANSPORT=streamable-httpQSCREENER_API_URL=https://<your-backend-domain>QSCREENER_WEBSITE_URL=https://<your-frontend-domain>QSCREENER_MCP_PUBLIC_URL=https://<generated-mcp-domain>Railway injects PORT automatically; the server binds to it.
Networking → Generate Domain. The MCP endpoint is
https://<generated-domain>/mcp.
/mcp answers
406 Not Acceptable to a plain GET, so an HTTP healthcheck expecting
200 would mark the deploy unhealthy.Connect your MCP client — the OAuth flow triggers automatically on first connection.
uv sync # install dependencies (including dev)
uv run pytest # run the test suite
The codebase is small and self-contained:
| Path | Purpose |
|---|---|
qscreener_mcp/server.py | FastMCP server, tool definitions, transport entry point |
qscreener_mcp/client.py | Minimal httpx client that attaches the bearer token |
qscreener_mcp/oauth.py | MCP OAuth 2.0 provider (token validation, browser flow) |
tests/ | pytest suite (token resolution, filter forwarding, share-link building) |
MIT © Quality Screener.
Be the first to review this server!
by Modelcontextprotocol · Developer Tools
Web content fetching and conversion for efficient LLM usage
by Modelcontextprotocol · Developer Tools
Read, search, and manipulate Git repositories programmatically
by Toleno · Developer Tools
Toleno Network MCP Server — Manage your Toleno mining account with Claude AI using natural language.