Skip to main content
Glama
vlearner

mcp-etf-holdings

by vlearner

mcp-etf-holdings

License

An MCP server for ETF data. Ask which funds hold a stock, compare fees, or pull top holdings. Data comes live from Yahoo Finance. No API key.


What you can ask

Ask Claude

Tool it calls

"Which ETFs hold NVDA?"

find_etfs_holding_stock

"What's the cheapest ETF for Nvidia exposure?"

stock_exposure_summary

"Compare SPY, VOO, QQQ and SCHD"

compare_etfs

"What are SPY's top holdings?"

etf_holdings

"What is QQQ's expense ratio and AUM?"

etf_info

"Find me semiconductor ETFs"

search_etfs

"What's the ticker for Berkshire Hathaway?"

lookup_symbol

Search by company name or ticker symbol. "Which ETFs hold Nvidia?" works the same as "Which ETFs hold NVDA?". Ask about several funds at once and you get one comparison table.


Related MCP server: Stock Assistant MCP Server

Requirements

  • Python 3.11+

  • An MCP client: Claude Code, Claude Desktop, VS Code, or Cursor

  • uv, which runs the server without a manual install

Install uv:

curl -LsSf https://astral.sh/uv/install.sh | sh

Setup

You don't need to install the server first. Every config below launches it on demand with uvx, in its own isolated environment.

To put it on your PATH instead, run pip install mcp-etf-holdings, then swap uvx mcp-etf-holdings for a plain mcp-etf-holdings in any config below.

Claude Code

claude mcp add etf-holdings -- uvx mcp-etf-holdings

Claude Desktop

  1. Open your config file:

    • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json

    • Windows: %APPDATA%\Claude\claude_desktop_config.json

  2. Add the server:

    {
      "mcpServers": {
        "etf-holdings": {
          "command": "uvx",
          "args": ["mcp-etf-holdings"]
        }
      }
    }
  3. Quit Claude Desktop and reopen it. Closing the window is not enough.

VS Code

  1. Create .vscode/mcp.json in your workspace. For a global config, run MCP: Open User Configuration instead.

  2. Add the server. VS Code uses the key servers, not mcpServers:

    {
      "servers": {
        "etf-holdings": {
          "type": "stdio",
          "command": "uvx",
          "args": ["mcp-etf-holdings"]
        }
      }
    }
  3. Restart VS Code.

Cursor

Use the same JSON as Claude Desktop. Put it in .cursor/mcp.json for one project, or ~/.cursor/mcp.json for all of them. Restart Cursor.

Verify it works

Ask your client each of these:

  • "Which ETFs hold NVDA?" — calls find_etfs_holding_stock

  • "Compare SPY, QQQ and VTI" — calls compare_etfs, returns one table

  • "Which ETFs hold Nvidia?" — resolves the name to NVDA and says so

If you get real numbers back, you're done.


Example prompts

Copy any of these into a client that has the server connected.

Compare funds

Compare SPY, VOO, IVV and SPLG — they all track the S&P 500, so which is cheapest?

Compare QQQ, VGT, XLK and SMH on expense ratio and 5-year return.

Search by name or ticker

Which ETFs hold Nvidia?

What's the ticker for Berkshire Hathaway?

Find me the Vanguard total stock market fund and show its top holdings.

Find the cheapest exposure to a stock

What's the cheapest ETF to get exposure to Nvidia?

I want AMD exposure without buying the stock directly. What are my options, and what do they cost?

Check a portfolio for overlap

I own VOO, QQQ and VGT. Am I doubling up?

Show me every holding that appears in more than one of SPY, SCHD and DGRO.

Discover funds by theme

Find semiconductor ETFs and compare the three biggest.

What dividend ETFs exist, and which has the highest yield?

Research one fund

Give me a deep dive on SCHD.

How concentrated is QQQ? What share of it is the top 5 positions?

Prompt templates

The server registers five prompt templates. Claude Desktop and Claude Code show them as slash-commands, so you don't have to write the prompt yourself.

Template

Argument

What it does

etf_deep_dive

ticker

Costs, size, returns, and a concentration read on one fund

compare_funds

tickers

Side-by-side table plus a cost and return comparison

stock_exposure

stock

Ranks the ETFs holding a stock by weight and cost

portfolio_checkup

tickers

Finds positions duplicated across the funds you hold

theme_explorer

theme

Finds funds for a theme and compares the leaders


Tool reference

Tools that return more than one row format the result as a markdown table.

etf_info(ticker)

Metadata for one ETF. For two or more funds, use compare_etfs.

  • ticker (string) — ETF symbol, e.g. "SPY"

Returns name, category, AUM, expense ratio, dividend yield, NAV/price, and YTD / 3-yr / 5-yr returns.

compare_etfs(tickers)

Compares several ETFs in one table.

  • tickers (array of strings) — e.g. ["SPY", "QQQ", "VTI", "SCHD"]. Case-insensitive and de-duplicated. Capped at 10 funds per call.

Returns Ticker, Name, Category, AUM, Expense, Yield, YTD, 3-Yr, 5-Yr. A ticker with no data still gets a row, plus a note naming it, so one typo doesn't discard the rest.

etf_holdings(ticker)

Top holdings of an ETF with portfolio weights.

  • ticker (string) — ETF symbol, e.g. "QQQ"

Returns a ranked table of symbol, name, and weight %.

find_etfs_holding_stock(stock_ticker, limit, custom_etf_universe)

Reverse lookup. Finds which ETFs hold a given stock in their disclosed top positions.

  • stock_ticker (string) — a ticker like "NVDA" or a company name like "Nvidia". Names are resolved to a ticker, and the output says which one it used.

  • limit (int, default 20) — capped at 50

  • custom_etf_universe (JSON string, optional) — search a specific list instead of the default universe, e.g. '["SPY","QQQ","XLK"]'

Returns matching ETFs sorted by the stock's weight, highest first.

Only top holdings are checked, roughly 10–15 positions per ETF. A stock held outside those positions will not appear.

stock_exposure_summary(stock, limit)

The same reverse lookup, joined with each fund's cost and size. Use it for "what's the cheapest or largest way to hold this stock?".

  • stock (string) — ticker or company name, e.g. "NVDA" or "Nvidia"

  • limit (int, default 10) — capped at 25

Returns ETF, Name, Weight, Rank, Expense, AUM, sorted by weight in the stock.

lookup_symbol(query, limit, asset_type)

Resolves a company or fund name to its ticker symbol.

  • query (string) — e.g. "Nvidia" or "Vanguard total stock market"

  • limit (int, default 10) — capped at 25

  • asset_type (string, default "any") — "any", "stock", or "etf"

Returns Symbol, Name, Type, Exchange.

search_etfs(query, limit)

Finds ETFs by name, theme, or category.

  • query (string) — e.g. "semiconductor" or "dividend"

  • limit (int, default 10) — capped at 25

Returns matching ETF tickers with names and exchanges. To resolve a stock name instead of finding funds, use lookup_symbol.


From source

For development, or to run without waiting on a release:

git clone https://github.com/vlearner/mcp-etf-holdings.git
cd mcp-etf-holdings
uv sync

Without uv:

python3 -m venv .venv && .venv/bin/pip install -e ".[dev]"

The repo ships a .vscode/mcp.json pointed at your working tree, so VS Code picks up local changes with no extra setup. Point other clients at:

{
  "command": "uv",
  "args": ["run", "--directory", "/absolute/path/to/mcp-etf-holdings", "mcp-etf-holdings"]
}

Check that the server starts:

uv run mcp-etf-holdings

It will sit silent, waiting for JSON-RPC on stdin. That is correct for a stdio MCP server.

To poke at the protocol by hand:

npx @modelcontextprotocol/inspector uv run mcp-etf-holdings

Tests

uv run pytest -q

The suite is fully offline. Both yf.Ticker and yf.Search are mocked, the latter by an autouse fixture, so no test can reach Yahoo by accident.

For coverage:

uv run pytest -q --cov=mcp_etf_holdings --cov-report=term-missing

Layout

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

Dependencies: mcp (protocol SDK), yfinance (data), pandas (holdings frames), httpx (transport).


Troubleshooting

Symptom

Fix

command not found: uvx

Install uv, then restart your editor so it picks up the new PATH.

Server missing from the client

Editors read MCP config only at startup. Fully quit and reopen. Check the client's MCP logs for the launch error.

Works in a terminal, not in the editor

GUI apps often don't inherit your shell PATH. Use an absolute path to uvx — run which uvx to get it.

Tool calls return "No data found"

Check the symbol is real. Yahoo rate-limits sometimes, so wait and retry.

Python version error on install

Needs 3.11+. Check with python3 --version.


Limits

Worth knowing before you trust a number:

  • Only the top ~10–15 positions per ETF are published. Anything derived from holdings — reverse lookups, exposure summaries, overlap checks — is a floor, not the full picture.

  • The default universe is ~365 funds. A stock held only in small or niche ETFs may not turn up.

  • Responses are cached in memory for 24h. Override with ETF_CACHE_TTL_SECONDS.

  • Data is fetched live from Yahoo Finance. No API key, but Yahoo's terms and rate limits apply. See NOTICE for attribution.


Contributing

PRs welcome. The most useful contribution is expanding the ETF universe in top_etfs.py. Wider coverage means better reverse-lookup results in niche sectors and international markets.

Open an issue first for larger changes.


Disclaimer

Not affiliated with Yahoo Finance, yfinance, or any financial institution. Data is retrieved from Yahoo Finance at runtime and is subject to availability and their terms of service. This is not financial advice.

Available Tools

7 tools
compare_etfsA

Compare several ETFs side by side in a single table: name, category, AUM, expense ratio, dividend yield, and YTD / 3-yr / 5-yr returns.

Use this whenever the user mentions more than one ETF — it is one call instead of several etf_info calls, and the result is already tabular.

ParametersJSON Schema
NameRequiredDescriptionDefault
tickersYesETF tickers to compare side by side, e.g. ['SPY', 'QQQ', 'VTI', 'SCHD']

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.2/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden. It discloses the return shape (a comparison table with defined columns), which is useful, but says nothing about whether tickers must exist, how invalid tickers are handled, or any rate/permission constraints. For a low-risk read-only lookup this is adequate but not rich.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short paragraphs with zero waste: the output contents are front-loaded, then the usage rule and the alternative. Every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so the description needn't explain return values, yet it helpfully previews the table columns. Combined with the clear usage routing, an agent has everything needed to invoke it correctly; only edge-case behavior (invalid/missing tickers) is unaddressed.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the single 'tickers' array parameter is documented in the schema with a concrete example (['SPY','QQQ','VTI','SCHD']). The description adds no format or cardinality guidance beyond what the schema already provides, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb ('Compare') and resource ('ETFs'), and enumerates the exact output fields (name, category, AUM, expense ratio, dividend yield, returns), so the agent knows what it gets back. It is clearly distinguishable from the sibling etf_info, which it explicitly contrasts.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives an explicit trigger ('whenever the user mentions more than one ETF') and names the alternative it replaces ('one call instead of several etf_info calls'), with the added rationale that the result is already tabular. Nothing is left to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

etf_holdingsB

Return the top holdings of an ETF with their portfolio weight percentages.

ParametersJSON Schema
NameRequiredDescriptionDefault
tickerYesETF ticker symbol, e.g. 'SPY'

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

B3.4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral burden. It does disclose that only 'top' holdings are returned with weights, implying a truncated result set, which is useful scoping context. But it never quantifies 'top', states data freshness, or notes any auth/rate constraints.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single tight sentence with the key output (weights) front-loaded alongside the resource. No filler or redundant restatement of the tool name.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple one-parameter read tool with an output schema present, return-shape explanation is unnecessary. The only real gap is the undefined size of the 'top' list, which mildly affects expectations but not invocation correctness.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% for the single ticker parameter, so the schema already documents the argument including an example ('SPY'). The description adds no parameter-level meaning beyond that, so the baseline of 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (Return) and resource (top holdings of an ETF) plus the payload (portfolio weight percentages). However, it does not distinguish itself from siblings like etf_info or find_etfs_holding_stock, leaving the agent to infer the boundary.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No when-to-use guidance, no prerequisites, and no mention of alternatives such as etf_info for broader fund data or find_etfs_holding_stock for the reverse lookup. The agent must infer the appropriate context entirely.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

etf_infoA

Return metadata for a single ETF: name, category, AUM, expense ratio, NAV, and trailing returns.

For two or more ETFs, use compare_etfs instead — it returns one table.

ParametersJSON Schema
NameRequiredDescriptionDefault
tickerYesETF ticker symbol, e.g. 'SPY' or 'QQQ'

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.1/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are supplied, so the description carries the full behavioral burden. It implies a pure read operation and lists what comes back, but never states read-only status, auth requirements, rate limits, or behavior for an unknown ticker. Adequate for a trivial one-param lookup, but thin for a tool with zero annotation coverage.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two tight sentences with the primary purpose front-loaded and the routing rule appended. Minor waste: enumerating the returned fields duplicates what the output schema already declares.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With one required, fully documented parameter and a companion output schema, the description supplies everything needed to select and call the tool correctly. Only the absence of any error/permission context keeps it short of a 5.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Only one parameter (ticker) and schema coverage is 100%, with the schema already supplying the 'SPY'/'QQQ' example. The description adds nothing beyond the schema, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Specific verb ('Return') plus resource ('metadata for a single ETF') and an explicit enumeration of the returned fields (name, category, AUM, expense ratio, NAV, trailing returns). It is immediately distinguishable from the sibling compare_etfs, which is named directly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The second sentence gives an explicit when-not rule: for two or more ETFs, use compare_etfs instead, with the rationale (it returns one table). This is a clear alternative routing rule rather than implied usage.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

find_etfs_holding_stockA

Reverse-lookup: find ETFs (from a ~365-ETF universe or a custom list) that hold a given stock in their disclosed top holdings.

Results are sorted by the stock's weight in each ETF, highest first. For a version that also reports each ETF's expense ratio and size, use stock_exposure_summary.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMaximum number of ETFs to return (1-50, default 20)
stock_tickerYesStock ticker or company name to search for, e.g. 'NVDA' or 'Nvidia'
custom_etf_universeNoOptional JSON array of ETF tickers to search instead of the default universe. Example: '["SPY","QQQ","XLK"]'

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does meaningful work: it discloses the default universe size (~365 ETFs), that results are sorted by weight descending, and that coverage is limited to 'disclosed top holdings' (i.e., partial data). It omits failure modes such as what happens for an unknown ticker or an empty result set, so it stops short of a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short sentences, zero filler, with the core purpose and the sorting/universe semantics front-loaded before the sibling routing at the end.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need not be explained. Between the description's scope, sorting, universe size, and explicit alternative, plus a fully covered parameter schema, an agent has everything needed to select and invoke it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema already documents all three parameters and the baseline is 3. The description adds useful semantic context beyond the schema by stating the default universe is ~365 ETFs and that a custom list substitutes for it, clarifying the intent of custom_etf_universe.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Reverse-lookup: find ETFs that hold a given stock') plus the scope of the lookup ('disclosed top holdings'), which immediately separates it from etf_holdings and search_etfs.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly names the alternative sibling and the condition that selects it: 'For a version that also reports each ETF's expense ratio and size, use stock_exposure_summary.' This is exactly the when/when-not routing an agent needs.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

lookup_symbolA

Resolve a company or fund name to its ticker symbol.

Call this first whenever the user names a company instead of giving a ticker — "Which ETFs hold Nvidia?" needs NVDA. Covers stocks and ETFs; use asset_type='stock' to exclude funds from the results.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMaximum number of results (1-25, default 10)
queryYesCompany or fund name to resolve, e.g. 'Nvidia' or 'Vanguard total stock market'
asset_typeNoFilter results: 'any' (default), 'stock', or 'etf'any

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.2/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the behavioral burden. It discloses scope (stocks and ETFs) and a filtering lever, but says nothing about ambiguous multi-match results, ranking, or the fact that this is a side-effect-free read (though the output schema covers the return shape).

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short sentences, front-loaded with the core action, then the when-to-call rule, then the coverage caveat. Nothing is wasted and no sentence restates the title or name.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present and all three parameters documented in the schema, the description supplies the essential entry-point guidance. The only gap is behavior on ambiguous or no-match queries, which is minor for a lookup tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds intent beyond the schema by explaining why one would set asset_type='stock' — to exclude funds from results. That is real semantic value on top of the schema's mechanical enum listing.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a precise verb and resource — resolve a company or fund name to its ticker symbol — so the transformation is unambiguous. It also declares coverage (stocks and ETFs), which separates it from the ETF-only siblings like etf_info and search_etfs.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives an explicit trigger: 'Call this first whenever the user names a company instead of giving a ticker,' with a concrete example (Nvidia → NVDA). It does not state when-not-to-use or name a sibling alternative, so it stops short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_etfsA

Search for ETFs by name, theme, or category using Yahoo Finance search.

Returns matching ETF tickers with their full names and exchanges. Useful for discovering ETFs to pass to etf_info, compare_etfs, etf_holdings, or find_etfs_holding_stock.

To resolve a stock or company name rather than find ETFs, use lookup_symbol.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMaximum number of ETFs to return (1-25, default 10)
queryYesSearch term: fund name, theme, or category, e.g. 'semiconductor' or 'dividend'

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.3/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral burden. It discloses the data source and that results include ticker, name, and exchange, but says nothing about rate limits, failure/empty-result behavior, or whether results are cached or live. Adequate context for a simple read search, but not rich.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short sentences, zero waste, front-loaded with purpose, then return, then routing. Every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need not be spelled out further, and the description already covers purpose, discovery role, and the sibling alternative. Nothing an agent needs to invoke it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so both parameters are already documented, including the query examples ('semiconductor', 'dividend') that the description echoes. The description adds no syntax or format guidance beyond the schema, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Search for ETFs') plus the scope of the search (name, theme, or category) and the backing source (Yahoo Finance). It also summarizes the return (matching tickers with names and exchanges), so an agent can distinguish it from siblings like etf_info without opening schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Names the downstream consumers (etf_info, compare_etfs, etf_holdings, find_etfs_holding_stock), which tells the agent this is a discovery entry point. It also gives an explicit when-not with the alternative: use lookup_symbol to resolve a stock or company name instead.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

stock_exposure_summaryA

Find the ETFs that give exposure to a stock, with each fund's weight in that stock alongside its expense ratio and AUM.

Answers "what is the cheapest / largest ETF for exposure to X?" — the weight column shows how much exposure you get, expense ratio what it costs.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMaximum number of ETFs to return (1-25, default 10)
stockYesStock ticker or company name to find ETF exposure for, e.g. 'NVDA' or 'Nvidia'

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.5/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full behavioral burden. It conveys the shape of the result (per-fund weight, expense ratio, AUM), which is useful, but says nothing about ordering of results, what happens with an unknown ticker, or that this is a read-only lookup. With an output schema present, the return-value gap is forgivable, but the behavioral coverage is thin for an unannotated tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences, front-loaded with the core action and outputs. The second sentence is partly redundant with the first but earns its place by naming the decision it supports. No filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With a full output schema and 100% parameter coverage, the description need not explain return values or argument formats, and it correctly stays brief. The remaining omission is sibling differentiation in a crowded ETF-tool family, which is a meaningful but bounded gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%: both 'stock' (ticker or name, with examples) and 'limit' (range and default) are fully documented in the schema. The description adds only the meaning of the returned metrics, not new parameter semantics, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('find the ETFs that give exposure to a stock') and enumerates the returned metrics (weight, expense ratio, AUM), so the agent knows exactly what this produces. It does not, however, differentiate itself from the near-identical sibling find_etfs_holding_stock or from compare_etfs, which leaves a real disambiguation gap.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The framing question 'what is the cheapest / largest ETF for exposure to X?' implies a use case and hints that this tool is for comparison-style selection. But it never states when to prefer it over find_etfs_holding_stock or compare_etfs, nor any exclusions, so routing must be inferred.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 7 tool updatesv0.4.1
    • First observedcompare_etfs
    • First observedetf_holdings
    • First observedetf_info
    • First observedfind_etfs_holding_stock
    • First observedlookup_symbol
    • First observedsearch_etfs
    • First observedstock_exposure_summary

TDQS

A3.9/5.0

Scored across 7 tools

Disambiguation4/5

Most tools have clearly distinct purposes: etf_info vs compare_etfs is well-differentiated by the single-vs-multiple guidance, and search_etfs vs lookup_symbol target different lookup types. The main overlap is find_etfs_holding_stock and stock_exposure_summary, which both find ETFs holding a stock, but the descriptions explicitly clarify the difference (extra expense ratio/AUM and sorting).

Naming Consistency3/5

All names use snake_case, but the patterns vary: etf_info (noun_noun), compare_etfs (verb_noun), etf_holdings (noun_noun), find_etfs_holding_stock (verb_noun_noun), stock_exposure_summary (noun_noun_noun), search_etfs (verb_noun), lookup_symbol (verb_noun). The inconsistency in verb-first vs noun-first and use of prefixes/suffixes makes it mixed but still readable.

Tool Count5/5

Seven tools is well-scoped for an ETF holdings and exposure analysis server. Each tool covers a distinct operation (metadata, comparison, holdings, reverse lookup, exposure summary, search, symbol resolution) without obvious redundancy or bloat.

Completeness4/5

The surface covers the core workflows well: ETF discovery, metadata, comparison, holdings, reverse holdings lookup, and exposure analysis with cost/size. Minor gaps exist (e.g., no full holdings beyond top positions, no historical performance beyond trailing returns), but these are likely outside the server's stated scope and can be worked around.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    Provides real-time stock market data through Yahoo Finance without requiring an API key. Get quotes, historical data, company information, financial statements, and ticker search capabilities.
    -
  • F
    license
    Not graded
    quality
    C
    maintenance
    Enables AI assistants to perform live stock and portfolio research using Yahoo Finance data, including quotes, fundamentals, price history, news, portfolio analysis, and ticker comparisons.
    -
  • A
    license
    A
    quality
    A
    maintenance
    Free stock, ETF & crypto analysis for AI agents: 10-point score, descriptive verdict and all key metrics for any ticker. Remote MCP server (Streamable HTTP, no auth, nothing to install) at https://www.stoxlyonline.com/api/mcp, plus a stdio server (server.js) for platforms that run MCP servers as a local process. Rate limit: 30 tool calls per IP per hour. Docs: https://www.stoxlyonline.com/mcp
    4
    2
    MIT