关于 QualityScreener
QualityScreener 是将股票筛选和评分 API 提供给 AI Agent 使用的 MCP 服务。投资者可筛选已评分股票、创建自定义评分系统、查看历史分数并分享筛选结果,所有操作使用其个人账户权限。
主要功能
- 01筛选并排列已评分股票
- 02计算自定义质量分数
- 03查看历史评分
- 04管理已保存的评分系统
- 05生成可分享的筛选链接
适用场景
- 01按行业或市值筛选股票
- 02比较当前与历史评分
- 03创建并复用自定义评分标准
- 04分享配置好的股票筛选结果
MCP 相关
该服务通过 stdio 或 Streamable HTTP 将经过身份验证的 Quality Screener API 操作作为 MCP 工具提供。请求使用登录用户的令牌,每个工具返回对应的 API 响应。
配置
远程服务无需本地安装。选择你使用的客户端,复制配置或使用一键安装。
https://mcp.qualityscreener.io/mcpclaude mcp add --transport http quality-screener https://mcp.qualityscreener.io/mcp{"mcpServers":{"quality-screener":{"type":"http","url":"https://mcp.qualityscreener.io/mcp"}}}在 Cursor 中打开{"servers":{"quality-screener":{"type":"http","url":"https://mcp.qualityscreener.io/mcp"}}}在 VS Code 中打开{"mcpServers":{"quality-screener":{"type":"http","url":"https://mcp.qualityscreener.io/mcp"}}}{"mcpServers":{"quality-screener":{"serverUrl":"https://mcp.qualityscreener.io/mcp"}}}命令在终端中运行;JSON 粘贴到对应客户端的 MCP 配置后重启。需要授权的服务会在首次连接时提示登录。
工具
详细介绍
Quality Screener MCP 服务
一个独立的 Model Context Protocol(MCP)服务,可将 Quality Screener 股票筛选引擎作为工具提供给 AI Agent(Claude、Cursor 及其他 MCP 客户端)。
连接后,Agent 可以筛选和过滤已评分的股票池、计算自定义质量评分、查看评分历史、管理已保存的评分系统,并生成可分享的筛选链接——以已登录用户的身份操作,使用的数据与用户在 Web 控制面板中看到的相同。
- 不依赖 SDK。该服务是一个基于 Quality Screener 公共 API 的轻量 HTTP 层。它不依赖后端 Python 包——每个工具只调用 REST 端点并返回 JSON 载荷。
- **支持多租户,且无需服务凭据。**通过 HTTP 部署时,该服务不存储自身凭据。每个请求都携带调用者自己的访问令牌,服务会将其转发给 API,因此单个公开部署即可为许多用户提供服务,而无需使用共享账户。
目录
工作原理
┌─────────────┐ MCP (stdio | streamable-HTTP) ┌──────────────────┐ HTTPS ┌──────────────────────┐
│ AI agent │ ────────────────────────────────► │ qscreener-mcp │ ────────► │ Quality Screener API │
│ (MCP client)│ ◄──────────────────────────────── │ (this server) │ ◄──────── │ (FastAPI backend) │
└─────────────┘ tool calls / JSON └──────────────────┘ REST └──────────────────────┘
每个 MCP 工具都映射到一个 Quality Screener REST 端点。服务会在每个出站请求中附加调用者的 bearer 令牌(接受请求头
X-Stobot-CLI-Token,也接受 Authorization: Bearer …),并返回解码后的 JSON。服务本身不包含业务逻辑——它是 API 的类型化、经过身份验证的门面。
它支持两种传输模式:
| 传输方式 | 用途 | 身份验证 |
|---|---|---|
stdio(默认) | 本地 Agent(例如 Claude Code)将服务作为子进程启动 | 来自 $QSCREENER_TOKEN 或 ~/.config/qscreener/credentials.json 的令牌 |
streamable-http | 可从外部访问的远程部署(例如 Railway) | 端到端 MCP OAuth 2.0——客户端打开浏览器登录一次,之后会自动发送令牌;或者使用每个请求的 X-Stobot-CLI-Token 请求头 |
通过 HTTP 访问时,MCP 端点位于 /mcp。
快速开始(远程)
使用该服务最简单的方法是让 MCP 客户端连接到托管部署。无需复制令牌——客户端首次连接时会触发浏览器登录:
{
"mcpServers": {
"qscreener": {
"type": "streamable-http",
"url": "https://mcp.qualityscreener.io/mcp"
}
}
}
首次使用时,浏览器会打开 Quality Screener 登录页面。授权一次后,Agent 就会保持连接。你需要拥有 Quality Screener 账户;Agent 将继承你的所有访问权限。
本地运行
需要 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
使用 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
默认情况下,容器会在端口 8080 上运行 streamable-http 传输模式。
配置
所有配置均通过环境变量设置,并在启动时解析。
| 环境变量 | 默认值 | 含义 |
|---|---|---|
QSCREENER_API_URL | http://localhost:8001 | 工具调用的 Quality Screener 后端 API 基础 URL |
QSCREENER_MCP_TRANSPORT | stdio | stdio、streamable-http 或 sse |
QSCREENER_WEBSITE_URL | http://localhost:3001 | Web 应用基础 URL,用于构建 OAuth 浏览器登录链接和可分享的筛选网址 |
QSCREENER_MCP_PUBLIC_URL | http://localhost:{PORT|8080}(或在 Vercel 上为 https://$VERCEL_URL) | 此服务可公开访问的基础 URL,用作 OAuth 颁发者和回调 URL |
QSCREENER_OAUTH_SIGNING_KEY | — | 用于签署 OAuth 状态、授权码和客户端注册信息的 HMAC 密钥。在 Vercel 上为必填;单个长时间运行的进程可选 |
PORT | — | HTTP 传输的绑定端口(Railway 会自动设置) |
QSCREENER_MCP_PORT | 8080 | 未设置 PORT 时使用的备用绑定端口 |
QSCREENER_MCP_HOST | 0.0.0.0 | HTTP 传输的绑定主机 |
QSCREENER_TOKEN | — | stdio 模式的 Bearer 令牌覆盖值(单用户) |
QSCREENER_CONFIG_DIR | ~/.config/qscreener | stdio 模式下存放 credentials.json 的目录 |
身份验证
服务按以下优先级为每次调用解析 Bearer 令牌:
- HTTP 请求标头 —
X-Stobot-CLI-Token,然后是Authorization: Bearer <token>。 $QSCREENER_TOKEN环境变量。$QSCREENER_CONFIG_DIR/credentials.json—token字段。
远程(OAuth 2.0)
对于 streamable-http 部署,身份验证通过 MCP OAuth 流程全自动完成:
- MCP 客户端发现授权服务器,并打开用户的浏览器。
- 浏览器打开 Quality Screener Web 应用;该应用将用户的 Web 会话换取短期 CLI 令牌,然后重定向回此服务的
/oauth/callback。 - 服务将令牌交给 MCP 客户端,客户端随后在每个请求中将其作为 Bearer 令牌发送。
服务通过调用后端的 /v1/cli/auth/whoami 端点,在每次请求时验证令牌,因此已撤销或过期的令牌会立即被拒绝。服务绝不会持久化用户令牌。访问令牌本身就是 CLI 令牌,因此无需本地存储。设置 QSCREENER_OAUTH_SIGNING_KEY 后,待处理的登录状态、授权码和动态注册的客户端会使用 HMAC 签名的 JWT;多实例主机(Vercel)需要此设置。单个进程在未设置密钥时,则沿用原有的内存行为。
本地(stdio)
通过浏览器登录流程获取令牌并将其保存在本地,然后通过 stdio 运行服务:
qscreener auth login # opens the web app, stores a token
cat ~/.config/qscreener/credentials.json # the "token" field is your bearer token
也可以直接为 CI / 脚本化使用设置 QSCREENER_TOKEN。
工具
所有工具都需要身份验证。筛选条件在单个筛选项内采用 OR 逻辑,在多个筛选项之间采用 AND 逻辑。市值始终以 USD 计。
账户与状态
| 工具 | 签名 | 描述 |
|---|---|---|
auth_status | auth_status() | 是否存在令牌,以及该令牌对应的用户。 |
account_profile | account_profile() | 已登录用户的个人资料(电子邮件、用户名、组织)。 |
health | health() | API 和数据库健康检查。 |
评分与筛选
| 工具 | 签名 | 描述 |
|---|---|---|
scores_top | scores_top(limit=20) | 按质量评分列出排名靠前的股票代码,结果为 {ticker: score} 映射。 |
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) | 列出已评分的股票代码,可选应用筛选条件。 |
scores_show | scores_show(ticker) | 显示单个股票代码对应的完整评分行。 |
scores_for_tickers | scores_for_tickers(tickers, scoring_system_id=None) | 根据默认评分体系或已保存的评分体系,获取指定股票代码列表的当前评分。未知的股票代码将被忽略。 |
scores_statistics | scores_statistics(sectors=None, min_score=None, max_score=None, min_market_cap_usd=None, max_market_cap_usd=None) | 计算筛选后范围内的最低、最高和平均评分统计数据。 |
scores_market_cap | scores_market_cap(sectors=None, min_score=None) | 计算筛选后范围内的总市值(USD)。 |
score_compute | score_compute(config, scoring_universe=None, sectors=None, industries=None, regions=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) | 根据 CustomScoreConfig 计算自定义评分。scoring_universe 用于选择同类群组(会改变评分);其他筛选条件用于选择行(不会改变评分)。 |
分享
| 工具 | 签名 | 描述 |
|---|---|---|
screen_share | screen_share(config) | 保存 CustomScoreConfig,并返回一个公开、可复制粘贴的分享链接(url、slug、created、view_count)。内容寻址:相同的配置会返回相同的链接。 |
筛选条件与股票代码
| 工具 | 签名 | 描述 |
|---|---|---|
filters_list | filters_list() | 可用的筛选值(行业板块、行业、国家、货币、交易所)。 |
tickers_list | tickers_list(limit=None) | 可用的股票代码列表,可选择将结果截断至 limit 条。 |
tickers_search | tickers_search(query) | 根据不区分大小写的子字符串搜索可用的股票代码。 |
评分历史
日期格式为 YYYY-MM-DD。传入 scoring_system_id,即可使用已保存的评分体系而非默认质量评分来计算历史数据。
| 工具 | 签名 | 描述 |
|---|---|---|
history_ticker | history_ticker(ticker, start=None, end=None, scoring_system_id=None) | 查询单个股票代码在指定日期范围内的评分历史。 |
history_batch | history_batch(tickers, start=None, end=None, scoring_system_id=None) | 一次查询多个股票代码的评分历史。 |
history_top | history_top(top=10, scoring_system_id=None) | 获取当前排名前 N 的股票代码,并返回其评分历史。 |
已保存的评分体系
评分体系是一个命名的、可重复使用的 CustomScoreConfig,保存在你的账户中。
| 工具 | 签名 | 描述 |
|---|---|---|
systems_list | systems_list() | 列出你已保存的评分体系。 |
systems_show | systems_show(system_id) | 按 ID 显示已保存的评分体系。 |
systems_create | systems_create(name, config, description=None) | 根据配置对象创建已保存的评分体系。 |
systems_update | systems_update(system_id, name=None, config=None, description=None) | 更新已保存的评分体系。 |
systems_delete | systems_delete(system_id) | 删除已保存的评分体系。 |
systems_apply | systems_apply(system_id) | 应用已保存的评分体系(使用次数加 1)。 |
使用 CustomScoreConfig
score_compute、screen_share 和 systems_* 工具接受一个
CustomScoreConfig 对象,用于描述财务指标的权重设置。其结构与 Web 仪表板中的评分构建器相同:包含加权的分组,每组包含加权的指标,以及评分参数和可选的嵌套 filters 块。最简示例:
{
"name": "My quality screen",
"winsorizePercentile": 5,
"missingDataPercentile": 0.25,
"normalizeGroupZScores": false,
"includeDuplicatesInScoring": false,
"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 }
]
}
],
"scoringUniverseFilters": { "countries": ["Italy"], "min_market_cap": 1 },
"filters": { "min_score": 1.2 }
}
评分参数使用 camelCase:winsorizePercentile(1-10)、missingDataPercentile
(0.1-0.5)、normalizeGroupZScores 和 includeDuplicatesInScoring(布尔值)。
scoringUniverseFilters 定义计算分数时所依据的同类群体;嵌套的
filters 块保存已保存筛选条件的状态。这两个块中的市值单位均为十亿美元(USD)(工具参数使用 USD)。系统会自动将宽松输入规范化为此结构,例如 snake_case 键、旧版 winsorize/zScore 标记,或放在顶层的筛选键,但建议直接按此结构传入。使用 filters_list 查找有效的筛选值;如果想要一个可复制的起点,可以在仪表板中交互式地构建配置。
两个阶段:先确定评分范围,再筛选
质量分数是相对值——每家公司都要在某个群体中进行缩尾处理和 Z 分数标准化——因此,同类群体包含哪些公司与查看哪些行是两个不同的问题,score_compute 会分别处理。
| 阶段 | 位置 | 效果 |
|---|---|---|
| 1. 评分范围 | scoring_universe 参数,或 config.scoringUniverseFilters | 在缩尾处理/Z 分数标准化之前应用——会改变每个分数 |
| 2. 结果筛选条件 | sectors / countries / … 参数 | 在评分之后应用——绝不会改变分数 |
“以欧洲科技公司为参照评选最佳欧洲科技公司”与“以全球公司为参照评选最佳欧洲科技公司”会得到不同的列表,而不是同一列表经过重新缩放——缩小范围会以不同幅度改变每项指标的边界、均值和 σ,因此公司排名确实会发生变化:
// judged against European tech — the peer group is European tech
score_compute(config, scoring_universe={"sectors": ["Technology"], "regions": ["Europe"]})
// judged against the world — the peer group is everyone, then Europe is shown
score_compute(config, sectors=["Technology"], regions=["Europe"])
阶段 1 接受 sectors、industries、regions、countries、currencies、exchanges、
min_market_cap_usd 和 max_market_cap_usd。若传入 min_score、max_score、ticker
或 tickers,会报错而非忽略:前两个会根据正在计算的分数进行筛选,其余参数用于选择行。
每个响应都包含一个 scoring_universe 字段,用于说明同类群体及其规模。针对不同同类群体计算出的分数不可比较——不要将它们混在同一张表中。
需要了解的两个边界情况:
- **作为阶段 2 参数传入的
min_market_cap_usd也会设定评分群体的下限。**这是后端长期存在的行为,为保持兼容而保留。请在scoring_universe中设置min_market_cap_usd,以显式控制同类群体;该设置会覆盖阶段 2 的下限。max_market_cap_usd只筛选行,除非你也在scoring_universe中设置它。 - **群体规模很小时仍会评分。**目前没有最小群体规模限制,因此,对十几家公司按第 5/95 百分位进行缩尾处理,会得出看似确定、实则荒谬的结果。
嵌套 filters 块的作用
它保存的是已保存筛选条件的状态。screen_share 和 systems_create/systems_update 会持久化该状态,以便在仪表板中重新打开共享筛选视图或已保存的评分系统时,还原其筛选条件。
它不定义同类群体——这由 scoringUniverseFilters 定义。将已保存配置传给
score_compute 时,其中的 filters 块会作为阶段 2筛选条件应用(显式传入的参数优先),与仪表板的行为一致,因此重新评分已保存的系统时会保留其视图。
连接 MCP 客户端
远程(推荐)
任何 streamable-http MCP 客户端均可使用。无需令牌——通过 OAuth 登录:
{
"mcpServers": {
"qscreener": {
"type": "streamable-http",
"url": "https://mcp.qualityscreener.io/mcp"
}
}
}
如果你的客户端无法执行 OAuth 流程,可以直接发送生成的令牌:
{
"mcpServers": {
"qscreener": {
"url": "https://mcp.qualityscreener.io/mcp",
"headers": { "X-Stobot-CLI-Token": "<your token>" }
}
}
}
本地(stdio)
{
"mcpServers": {
"qscreener": {
"command": "uv",
"args": ["run", "--directory", "/path/to/quality-screener-mcp-server", "qscreener-mcp"],
"env": { "QSCREENER_API_URL": "https://your-backend.example.com" }
}
}
}
部署
此服务以单个容器的形式部署。在 Railway 上:
-
New service → Deploy from repo,指向此代码库。Dockerfile 是独立完整的,因此构建上下文为代码库根目录。
-
设置环境变量:
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 会自动注入
PORT;服务会绑定到该端口。 -
Networking → Generate Domain。MCP 端点为
https://<generated-domain>/mcp。- 将 HTTP 健康检查路径留空(或使用 TCP 检查):对普通
GET请求,/mcp会返回406 Not Acceptable,因此预期返回200的 HTTP 健康检查会将部署标记为不健康。
- 将 HTTP 健康检查路径留空(或使用 TCP 检查):对普通
-
Connect 你的 MCP 客户端——首次连接时会自动触发 OAuth 流程。
在 Vercel 上部署
Docker/Railway 通过 mcp.run() 提供服务的同一个 ASGI 应用,会从
app.py 导出为 FastAPI app,供 Vercel 的 Python 运行时作为单个
Function 托管。FastMCP 应用已监听 /mcp、/.well-known/*、
/authorize、/token、/register 和 /oauth/callback;Vercel 会将
每个请求连同原始路径一并路由到该 Function,因此这些 URL 无需重新映射即可正常访问。vercel.json 只为 app.py 设置了 maxDuration(60s)。
不要将 /mcp(或 OAuth 路径)重写到 /——FastMCP 会匹配
字面路径。
创建一个指向此代码库的 Vercel 项目(Framework Preset:FastAPI / Other,Root Directory:代码库根目录)。设置以下环境变量——只填写变量名;切勿提交变量值:
| 环境变量 | 必需 | 用途 |
|---|---|---|
QSCREENER_API_URL | 是 | 工具调用的 Quality Screener 后端基础 URL |
QSCREENER_WEBSITE_URL | 是 | 用于 OAuth 浏览器登录和可分享筛选链接的 Web 应用源站 |
QSCREENER_MCP_PUBLIC_URL | 使用自定义域名时必需 | 此部署的公共源站(OAuth 颁发者 + /oauth/callback)。预览部署可省略此项,并会使用 https://$VERCEL_URL |
QSCREENER_OAUTH_SIGNING_KEY | 是 | 用于签署 OAuth 待处理状态、授权码和动态客户端注册信息的 HMAC 密钥,使其在多次 Function 调用之间保持有效。请使用较长的随机字符串(至少 32 字节) |
Vercel 会自动注入 VERCEL_URL(不含协议的主机名)。仅当未设置
QSCREENER_MCP_PUBLIC_URL 时,它才会作为备用颁发者。如果 MCP 客户端将通过自定义域名连接,请勿将其用作生产环境的颁发者。
以下环境变量在 Vercel 上不需要(app.py 入口始终使用 HTTP,
且 Function 不会绑定端口):
QSCREENER_MCP_TRANSPORTQSCREENER_MCP_HOSTQSCREENER_MCP_PORT/PORTQSCREENER_TOKENQSCREENER_CONFIG_DIR
部署后,MCP 端点为 https://<vercel-domain>/mcp。像 Railway 部署一样,将
MCP 客户端指向此 URL。如果自定义评分达到 60s 上限,请提高
vercel.json 中的 functions["app.py"].maxDuration。
开发
uv sync # install dependencies (including dev)
uv run pytest # run the test suite
代码库小巧且自成一体:
| 路径 | 用途 |
|---|---|
qscreener_mcp/server.py | FastMCP 服务、工具定义、传输入口 |
qscreener_mcp/client.py | 附加 bearer token 的精简 httpx 客户端 |
qscreener_mcp/oauth.py | MCP OAuth 2.0 提供方(令牌验证、浏览器流程) |
app.py | Vercel FastAPI 入口,用于挂载 streamable-HTTP ASGI 应用 |
tests/ | pytest 测试套件(令牌解析、筛选器转发、分享链接构建) |
隐私政策
完整的隐私政策发布于 PRIVACY.md (https://github.com/quality-screener/quality-screener-mcp-server/blob/main/PRIVACY.md)。
简而言之:
- 唯一保留的个人数据是用于识别你账户的电子邮箱地址。用户名和组织是可选的个人资料字段。
- MCP 服务是无状态代理——它不持有数据库,也不会将任何个人数据写入自己的存储。每个请求都会使用你的访问令牌转发至 Quality Screener API,而非使用共享账户。
- 你的数据不会被出售,不会用于广告,也不会用于训练机器学习模型。
- 运营日志通过假名化用户 ID(而非电子邮箱)关联账户。
- 删除账户时,账户数据也会被删除。
有关数据保留期限、第三方接收方、国际传输和你的 GDPR 权利,请参阅隐私政策。
支持
| 渠道 | 用途 |
|---|---|
| [email protected] | 支持请求、安全报告、隐私和数据主体请求 |
| GitHub Issues | 错误报告和功能请求 |
本 README 是 MCP 服务的权威文档: https://github.com/quality-screener/quality-screener-mcp-server
如发现疑似安全漏洞,请通过电子邮件私下报告,而不要公开提交问题。
许可证
MIT © Quality Screener.
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。