关于 mcp-etf-holdings
mcp-etf-holdings 是用于查询 ETF 数据的 MCP 服务,数据来自 Yahoo Finance,无需 API 密钥。它面向投资者,支持通过 MCP 客户端查看基金、股票敞口、费用和持仓。
主要功能
- 01查询持有指定股票的 ETF
- 02比较费用、规模、收益率和回报
- 03获取 ETF 信息和主要持仓
- 04按名称、主题或类别搜索基金
- 05解析公司和基金代码
- 06提供五种 ETF 研究提示词模板
适用场景
- 01查找持有某公司的基金
- 02比较多只 ETF 的费用和回报
- 03检查投资组合中的持仓重叠
- 04按投资主题探索 ETF
MCP 相关
向 MCP 客户端提供七种 ETF 研究工具和五种提示词模板。默认使用 stdio,也支持可选的 Streamable HTTP 传输。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
7收录的工具列表 · 更新于 2 天前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| ticker | string | 是 | ETF 股票代码,例如 'SPY' 或 'QQQ' |
详细介绍
mcp-etf-holdings
用于 ETF 数据的 MCP 服务。询问哪些基金持有某只股票、比较费用,或获取主要持仓。数据实时来自 Yahoo Finance。无需 API 密钥。
可以询问的问题
| 询问 Claude | 调用的工具 |
|---|---|
| “哪些 ETF 持有 NVDA?” | find_etfs_holding_stock |
| “哪只 ETF 的 Nvidia 投资成本最低?” | stock_exposure_summary |
| “比较 SPY、VOO、QQQ 和 SCHD” | compare_etfs |
| “SPY 的主要持仓有哪些?” | etf_holdings |
| “QQQ 的费用比率和 AUM 是多少?” | etf_info |
| “帮我找一些半导体 ETF” | search_etfs |
| “Berkshire Hathaway 的股票代码是什么?” | lookup_symbol |
可以按公司名称或股票代码搜索。“哪些 ETF 持有 Nvidia?”和“哪些 ETF 持有 NVDA?”的效果相同。一次询问多只基金,即可获得一张对比表。
要求
- Python 3.11+
- MCP 客户端:Claude Code、Claude Desktop、VS Code、Cursor 或 Antigravity
- uv,可在无需手动安装的情况下运行服务
安装 uv:
curl -LsSf https://astral.sh/uv/install.sh | sh
设置
无需先安装服务。以下所有配置都会通过 uvx 按需启动服务,并在独立的隔离环境中运行。
如需将其添加到 PATH,请运行 pip install mcp-etf-holdings,然后在以下任一配置中,将 uvx mcp-etf-holdings 替换为普通的 mcp-etf-holdings。
Claude Code
claude mcp add etf-holdings -- uvx mcp-etf-holdings
Claude Desktop
-
打开配置文件:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
- macOS:
-
添加服务:
{ "mcpServers": { "etf-holdings": { "command": "uvx", "args": ["mcp-etf-holdings"] } } } -
退出 Claude Desktop 并重新打开。仅关闭窗口是不够的。
VS Code
-
在工作区中创建
.vscode/mcp.json。如需使用全局配置,请改为运行 MCP: Open User Configuration。 -
添加服务。VS Code 使用
servers键,而不是mcpServers:{ "servers": { "etf-holdings": { "type": "stdio", "command": "uvx", "args": ["mcp-etf-holdings"] } } } -
重启 VS Code。
Cursor
使用与 Claude Desktop 相同的 JSON。单个项目使用 .cursor/mcp.json,所有项目使用
~/.cursor/mcp.json。重启 Cursor。
Antigravity
Antigravity 会从 mcp_config.json 读取 mcpServers。所有项目使用
~/.gemini/config/mcp_config.json,单个项目使用 <workspace>/.agents/mcp_config.json:
{
"mcpServers": {
"etf-holdings": {
"command": "uvx",
"args": ["mcp-etf-holdings"]
}
}
}
在 IDE 中,可以通过 Agent 面板打开配置:MCP Servers → Manage MCP Servers → View raw config。
也可以从此仓库的检出副本中将其安装为插件(该插件只是相同的配置文件加上清单,位于 antigravity/etf-holdings):
agy plugin install /path/to/mcp-etf-holdings/antigravity/etf-holdings
在 IDE 中,将该文件夹复制到 .agents/plugins/(单个工作区)或
~/.gemini/config/plugins/(所有工作区)。
如需使用可选的 HTTP 传输方式,Antigravity 将 URL 字段命名为 serverUrl:
{"mcpServers": {"etf-holdings": {"serverUrl": "http://127.0.0.1:8000/mcp"}}}。
验证是否正常运行
向客户端询问以下问题:
- “哪些 ETF 持有 NVDA?” — 调用
find_etfs_holding_stock - “比较 SPY、QQQ 和 VTI” — 调用
compare_etfs,并返回一张表 - “哪些 ETF 持有 Nvidia?” — 将名称解析为
NVDA并说明这一点
如果返回了真实数据,就大功告成了。
示例提示词
将以下任意内容复制到已连接该服务的客户端中。
比较基金
比较 SPY、VOO、IVV 和 SPLG——它们都跟踪 S&P 500,那么哪只费率最低?
比较 QQQ、VGT、XLK 和 SMH 的费率和 5 年回报。
按名称或代码搜索
哪些 ETF 持有 Nvidia?
Berkshire Hathaway 的代码是什么?
帮我找出 Vanguard 全市场股票基金,并列出它的主要持仓。
寻找持有某只股票的最低成本方式
持有 Nvidia 的最低成本 ETF 是哪只?
我想获得 AMD 敞口,但不直接购买该股票。有哪些选择,成本分别是多少?
检查投资组合是否有重仓重复
我持有 VOO、QQQ 和 VGT。我的持仓是否有重复?
列出同时出现在 SPY、SCHD 和 DGRO 中任意两只以上基金里的所有持仓。
按主题查找基金
找出半导体 ETF,并比较规模最大的三只。
有哪些股息 ETF?哪只收益率最高?
深入研究某只基金
深入分析 SCHD。
QQQ 的持仓有多集中?前 5 大持仓占比是多少?
提示词模板
该服务注册了五种提示词模板。Claude Desktop 和 Claude Code 会将它们显示为斜杠命令,因此你不必自己编写提示词。
| 模板 | 参数 | 功能 |
|---|---|---|
etf_deep_dive | ticker | 分析单只基金的成本、规模、回报和持仓集中度 |
compare_funds | tickers | 并排表格,以及成本和回报比较 |
stock_exposure | stock | 按权重和成本对持有某只股票的 ETF 排名 |
portfolio_checkup | tickers | 找出你持有的基金之间重复的持仓 |
theme_explorer | theme | 查找某个主题的基金,并比较领头基金 |
工具参考
返回多行结果的工具会将结果格式化为 Markdown 表格。
etf_info(ticker)
获取单只 ETF 的元数据。要查询两只或更多基金,请使用 compare_etfs。
ticker(字符串)——ETF 代码,例如"SPY"
返回名称、类别、资产管理规模(AUM)、费率、股息收益率、净值/价格以及年初至今、3 年和 5 年回报。
compare_etfs(tickers)
在一张表格中比较多只 ETF。
tickers(字符串数组)——例如["SPY", "QQQ", "VTI", "SCHD"]。不区分大小写,并会去重。每次调用最多比较 10 只基金。
返回代码、名称、类别、资产管理规模、费率、收益率、年初至今回报、3 年回报和 5 年回报。没有数据的代码仍会显示一行,并附上说明标明该代码,因此即使有一处拼写错误,也不会影响其余结果。
etf_holdings(ticker)
获取 ETF 的主要持仓及其在投资组合中的权重。
ticker(字符串)——ETF 代码,例如"QQQ"
返回按排名排列的表格,包含代码、名称和权重百分比。
find_etfs_holding_stock(stock_ticker, limit, custom_etf_universe)
反向查询,查找披露的主要持仓中持有指定股票的 ETF。
stock_ticker(字符串)——股票代码,例如"NVDA",或公司名称,例如"Nvidia"。名称会被解析为股票代码,输出会说明使用了哪个代码。limit(整数,默认值为 20)——上限为 50custom_etf_universe(JSON 字符串,可选)——搜索指定列表,而非默认范围,例如'["SPY","QQQ","XLK"]'
返回匹配的 ETF,并按该股票的持仓权重从高到低排序。
仅检查主要持仓,每只 ETF 大约 10–15 个持仓。若某只股票不在这些持仓之列,则不会出现在结果中。
stock_exposure_summary(stock, limit)
此工具执行相同的反向查询,并结合各基金的成本和规模。可用于回答“持有这只股票的最低成本或规模最大的方式是什么?”。
stock(字符串)——股票代码或公司名称,例如"NVDA"或"Nvidia"limit(整数,默认值为 10)——上限为 25
返回 ETF、名称、权重、排名、费率和资产管理规模,并按该股票的持仓权重排序。
lookup_symbol(query, limit, asset_type)
将公司或基金名称解析为股票代码。
query(string)——例如"Nvidia"或"Vanguard total stock market"limit(int,默认值为 10)——上限为 25asset_type(string,默认值为"any")——"any"、"stock"或"etf"
返回代码、名称、类型和交易所。
search_etfs(query, limit)
按名称、主题或类别查找 ETF。
query(string)——例如"semiconductor"或"dividend"limit(int,默认值为 10)——上限为 25
返回匹配的 ETF 代码、名称和交易所。若要解析股票名称,而不是查找基金,
请使用 lookup_symbol。
从源码运行
用于开发,或无需等待发布即可运行:
git clone https://github.com/vlearner/mcp-etf-holdings.git
cd mcp-etf-holdings
uv sync
不使用 uv:
python3 -m venv .venv && .venv/bin/pip install -e ".[dev]"
此仓库附带指向工作树的 .vscode/mcp.json,因此 VS Code 无需额外设置即可获取
本地更改。其他客户端请指向:
{
"command": "uv",
"args": ["run", "--directory", "/absolute/path/to/mcp-etf-holdings", "mcp-etf-holdings"]
}
检查服务是否启动:
uv run mcp-etf-holdings
它会保持静默,等待从 stdin 接收 JSON-RPC。这是 stdio MCP 服务的正常行为。
手动试用该协议:
npx @modelcontextprotocol/inspector uv run mcp-etf-holdings
HTTP 传输(可选)
stdio 是默认传输方式,也是上述所有编辑器配置使用的方式。若要改为通过可流式 HTTP 提供服务:
uv run mcp-etf-holdings --transport http # http://127.0.0.1:8000/mcp
uv run mcp-etf-holdings --transport http --port 9000
将客户端指向它,配置为 { "type": "http", "url": "http://127.0.0.1:8000/mcp" }
(VS Code 中位于 servers 下)。MCP_TRANSPORT、MCP_HOST 和 MCP_PORT 可设置相同选项。
默认情况下,服务绑定到环回地址,且没有身份验证。除非传入 --allow-insecure(或设置
MCP_ALLOW_INSECURE=1),否则不允许绑定到其他地址;在将其暴露到本机之外之前,请在前面
部署身份验证代理。
在 Docker 中试用
示例 Dockerfile 可从此检出版本构建服务:
docker build -t mcp-etf-holdings .
docker run --rm -e MCP_ALLOW_INSECURE=1 -p 127.0.0.1:8000:8000 mcp-etf-holdings
由于容器会绑定到所有接口,因此必须设置 MCP_ALLOW_INSECURE=1。保留端口映射中的
127.0.0.1::它能防止网络中的其他机器访问该容器。服务会在容器内记录无身份验证警告;
这是预期行为。此方式仅用于试用该功能,并非托管方案。
测试
uv run pytest -q
整个测试套件完全离线运行。yf.Ticker 和 yf.Search 均使用了模拟对象,后者由
自动使用的 fixture 提供,因此测试不会意外访问 Yahoo。
查看覆盖率:
uv run pytest -q --cov=mcp_etf_holdings --cov-report=term-missing
目录结构
src/mcp_etf_holdings/
server.py ← FastMCP entry point, 7 tools
prompts.py ← prompt templates, exposed as client slash-commands
fetcher.py ← async wrappers around yfinance + 24h TTL cache
formatting.py ← markdown tables and shared number formatting
top_etfs.py ← ~365 ETF tickers scanned for reverse lookups
__main__.py ← enables `python -m mcp_etf_holdings`
tests/ ← pytest suite, fully offline
.vscode/mcp.json ← VS Code config pointing at the working tree
pyproject.toml
依赖项:mcp(协议 SDK)、yfinance(数据)、pandas(持仓数据框)、
httpx(传输)。
故障排除
| 症状 | 解决方法 |
|---|---|
command not found: uvx | 安装 uv,然后重启编辑器,使其获取新的 PATH。 |
| 客户端中找不到服务 | 编辑器只会在启动时读取 MCP 配置。请完全退出并重新打开。检查客户端的 MCP 日志,查看启动错误。 |
| 在终端中能运行,在编辑器中却不行 | GUI 应用通常不会继承 shell 的 PATH。请使用 uvx 的绝对路径——运行 which uvx 获取路径。 |
| 工具调用返回 "No data found" | 检查代码是否有效。Yahoo 有时会进行速率限制,请稍后重试。 |
| 安装时出现 Python 版本错误 | 需要 3.11 或更高版本。运行 python3 --version 检查。 |
限制
信任数据前,建议了解以下限制:
- 每只 ETF 仅公布排名靠前的约 10–15 项持仓。任何基于持仓得出的结果—— 反向查询、敞口摘要、重叠检查——都是下限,而非完整情况。
- 默认覆盖范围约为 365 只基金。若某只股票仅由小型或小众 ETF 持有,可能无法 查到。
- 响应会在内存中缓存 24 小时。可通过
ETF_CACHE_TTL_SECONDS修改。 - 数据实时从 Yahoo Finance 获取。无需 API 密钥,但须遵守 Yahoo 的 条款和速率限制。 归属信息请参阅 NOTICE。
贡献
欢迎提交 PR。最有价值的贡献是扩展 top_etfs.py 中的 ETF 范围。
覆盖面越广,小众行业和国际市场的反向查询结果就越好。
较大的更改请先提交 issue。
免责声明
与 Yahoo Finance、yfinance 或任何金融机构均无关联。数据在运行时从 Yahoo Finance 获取,具体取决于其可用性,并受其服务条款约束。本内容不构成财务建议。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。