yahoo-finance-mcp-server 1.2.0 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,118 +1,140 @@
1
- # Changelog
2
-
3
- All notable changes to this project are documented in this file.
4
-
5
- The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
- and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
-
8
- ## [1.2.0] - 2026-06-01
9
-
10
- Major feature release: **seven new data tools (6 → 13)** plus rate-limit
11
- hardening. Every tool was verified end to end by driving the real MCP server
12
- over stdio against live Yahoo Finance data.
13
-
14
- ### Added
15
-
16
- - **`get_market_news`** — latest news headlines for a ticker, with source,
17
- date, summary, and link. Handles the modern nested yfinance news format.
18
- - **`get_options_chain`** — list available expiration dates, or fetch the
19
- calls/puts chain (strike, bid/ask, volume, open interest, implied
20
- volatility) for a given expiration.
21
- - **`get_holders`** — institutional holders, mutual-fund holders, the
22
- major-holders breakdown, or recent insider transactions.
23
- - **`get_dividends_splits`** — full dividend payment history (with a trailing
24
- summary) and stock-split history.
25
- - **`get_analyst_estimates`** — forward analyst price targets, EPS and revenue
26
- estimates by period, and growth estimates (complements the existing
27
- recommendations tool).
28
- - **`search_symbols`** — find ticker symbols by company name or keyword, with
29
- exchange, type, sector, and industry.
30
- - **`get_market_status`** — whether a market (by region) is open or closed,
31
- with timing and a summary of its major indices.
32
- - **Shared `curl_cffi` browser-impersonating HTTP session** reused across all
33
- tools. This cuts down on Yahoo's HTTP 429 rate-limiting and speeds up
34
- repeated calls; it degrades gracefully to the default session if
35
- `curl_cffi` is unavailable.
36
- - Friendly, specific handling of `YFRateLimitError` ("wait and retry")
37
- across all tools.
38
-
39
- ### Changed
40
-
41
- - `requirements.txt`: add `curl_cffi`; raise the `yfinance` floor to
42
- `>=0.2.61` (which carries upstream rate-limit-handling fixes and the
43
- `Search`/`Market` APIs used by the new tools).
44
-
45
- ## [1.1.1] - 2026-05-31
46
-
47
- Documentation and packaging only. No runtime code changes; behavior is
48
- identical to 1.1.0.
49
-
50
- ### Changed
51
-
52
- - Reworked the README: clearer structure, a tools table with parameters and
53
- supported `period`/`interval` values, example prompts, and a note clarifying
54
- that the repository name (`yahoo-finance-mcp`) differs from the npm package
55
- name (`yahoo-finance-mcp-server`).
56
- - Added shields.io badges, including a monthly-downloads pill and a Python
57
- version badge.
58
- - Normalized `repository.url` to the `git+https://` form npm expects.
59
-
60
- ### Added
61
-
62
- - This `CHANGELOG.md`, now shipped in the npm tarball.
63
-
64
- ## [1.1.0] - 2026-05-30
65
-
66
- A full QA pass that fixed several bugs which broke core functionality, and made
67
- the documented `npx` installation actually work. Every fix was verified end to
68
- end by driving the real MCP server over stdio against live Yahoo Finance data.
69
-
70
- ### Fixed
71
-
72
- - **Tool inputs failed validation.** Each tool took a single Pydantic model
73
- argument, so the MCP schema nested every field under a required `params`
74
- object while the docs told the model to send fields directly. The result was
75
- that calls were rejected. Tools now expose their parameters directly.
76
- - **`get_analyst_recommendations` crashed** with `'RangeIndex' object has no
77
- attribute 'strftime'` due to a change in the `yfinance` recommendations
78
- format. It now reads the current format and also reports recent
79
- upgrades/downgrades.
80
- - **Dividend yield was shown 100x too high** (for example `35.00%` for AAPL).
81
- Modern `yfinance` already returns this value as a percentage, so it is no
82
- longer multiplied again.
83
- - **Markdown tables broke** when the optional `tabulate` package was missing.
84
- It is now a declared dependency, with a graceful plain-text fallback.
85
- - **Truncated JSON responses are now valid JSON** instead of being cut off
86
- mid-structure.
87
-
88
- ### Added
89
-
90
- - **`bin/cli.js` Node launcher** so `npx -y yahoo-finance-mcp-server` works. It
91
- locates Python 3.10+, creates an isolated virtual environment, installs the
92
- Python dependencies on first run, and starts the server with the protocol
93
- stream kept clean on stdout.
94
- - `tabulate` added to the dependencies.
95
-
96
- ### Changed
97
-
98
- - `package.json` `bin` now points at the Node launcher, the binary name matches
99
- the package name, and a Node engine requirement was added.
100
- - Tightened dependency floors (`yfinance>=0.2.40`, `mcp>=1.2.0`).
101
- - Replaced the deprecated Pydantic `min_items`/`max_items` with
102
- `min_length`/`max_length`.
103
- - Rewrote the README and corrected the installation and troubleshooting docs.
104
-
105
- ## [1.0.0] - 2025-11-01
106
-
107
- ### Added
108
-
109
- - Initial release of the Yahoo Finance MCP Server, distributed on npm.
110
- - Six tools: `get_stock_quote`, `get_historical_prices`, `get_company_info`,
111
- `get_financial_statements`, `compare_stocks`, and
112
- `get_analyst_recommendations`.
113
- - Markdown and JSON output formats.
114
-
115
- [1.2.0]: https://github.com/danishashko/yahoo-finance-mcp/releases/tag/v1.2.0
116
- [1.1.1]: https://github.com/danishashko/yahoo-finance-mcp/releases/tag/v1.1.1
117
- [1.1.0]: https://github.com/danishashko/yahoo-finance-mcp/releases/tag/v1.1.0
118
- [1.0.0]: https://github.com/danishashko/yahoo-finance-mcp/releases/tag/v1.0.0
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [1.2.2] - 2026-06-04
9
+
10
+ ### Fixed
11
+
12
+ - Oversized responses no longer overflow the response size cap. Previously a
13
+ too-large JSON response could be returned larger than the limit (and dumped a
14
+ giant truncated preview into context); it now returns a small message asking
15
+ to narrow the request.
16
+
17
+ ### Changed
18
+
19
+ - Trimmed verbose tool descriptions to cut the always-loaded schema size
20
+ (~1,800 fewer tokens on connect). Tool behavior unchanged.
21
+
22
+ ## [1.2.1] - 2026-06-02
23
+
24
+ Packaging only. No runtime code changes.
25
+
26
+ ### Added
27
+
28
+ - `server.json` and an `mcpName` field for listing on the official MCP Registry.
29
+
30
+ ## [1.2.0] - 2026-06-01
31
+
32
+ Major feature release: **seven new data tools (6 → 13)** plus rate-limit
33
+ hardening. Every tool was verified end to end by driving the real MCP server
34
+ over stdio against live Yahoo Finance data.
35
+
36
+ ### Added
37
+
38
+ - **`get_market_news`** — latest news headlines for a ticker, with source,
39
+ date, summary, and link. Handles the modern nested yfinance news format.
40
+ - **`get_options_chain`** — list available expiration dates, or fetch the
41
+ calls/puts chain (strike, bid/ask, volume, open interest, implied
42
+ volatility) for a given expiration.
43
+ - **`get_holders`** — institutional holders, mutual-fund holders, the
44
+ major-holders breakdown, or recent insider transactions.
45
+ - **`get_dividends_splits`** — full dividend payment history (with a trailing
46
+ summary) and stock-split history.
47
+ - **`get_analyst_estimates`** — forward analyst price targets, EPS and revenue
48
+ estimates by period, and growth estimates (complements the existing
49
+ recommendations tool).
50
+ - **`search_symbols`** — find ticker symbols by company name or keyword, with
51
+ exchange, type, sector, and industry.
52
+ - **`get_market_status`** — whether a market (by region) is open or closed,
53
+ with timing and a summary of its major indices.
54
+ - **Shared `curl_cffi` browser-impersonating HTTP session** reused across all
55
+ tools. This cuts down on Yahoo's HTTP 429 rate-limiting and speeds up
56
+ repeated calls; it degrades gracefully to the default session if
57
+ `curl_cffi` is unavailable.
58
+ - Friendly, specific handling of `YFRateLimitError` ("wait and retry")
59
+ across all tools.
60
+
61
+ ### Changed
62
+
63
+ - `requirements.txt`: add `curl_cffi`; raise the `yfinance` floor to
64
+ `>=0.2.61` (which carries upstream rate-limit-handling fixes and the
65
+ `Search`/`Market` APIs used by the new tools).
66
+
67
+ ## [1.1.1] - 2026-05-31
68
+
69
+ Documentation and packaging only. No runtime code changes; behavior is
70
+ identical to 1.1.0.
71
+
72
+ ### Changed
73
+
74
+ - Reworked the README: clearer structure, a tools table with parameters and
75
+ supported `period`/`interval` values, example prompts, and a note clarifying
76
+ that the repository name (`yahoo-finance-mcp`) differs from the npm package
77
+ name (`yahoo-finance-mcp-server`).
78
+ - Added shields.io badges, including a monthly-downloads pill and a Python
79
+ version badge.
80
+ - Normalized `repository.url` to the `git+https://` form npm expects.
81
+
82
+ ### Added
83
+
84
+ - This `CHANGELOG.md`, now shipped in the npm tarball.
85
+
86
+ ## [1.1.0] - 2026-05-30
87
+
88
+ A full QA pass that fixed several bugs which broke core functionality, and made
89
+ the documented `npx` installation actually work. Every fix was verified end to
90
+ end by driving the real MCP server over stdio against live Yahoo Finance data.
91
+
92
+ ### Fixed
93
+
94
+ - **Tool inputs failed validation.** Each tool took a single Pydantic model
95
+ argument, so the MCP schema nested every field under a required `params`
96
+ object while the docs told the model to send fields directly. The result was
97
+ that calls were rejected. Tools now expose their parameters directly.
98
+ - **`get_analyst_recommendations` crashed** with `'RangeIndex' object has no
99
+ attribute 'strftime'` due to a change in the `yfinance` recommendations
100
+ format. It now reads the current format and also reports recent
101
+ upgrades/downgrades.
102
+ - **Dividend yield was shown 100x too high** (for example `35.00%` for AAPL).
103
+ Modern `yfinance` already returns this value as a percentage, so it is no
104
+ longer multiplied again.
105
+ - **Markdown tables broke** when the optional `tabulate` package was missing.
106
+ It is now a declared dependency, with a graceful plain-text fallback.
107
+ - **Truncated JSON responses are now valid JSON** instead of being cut off
108
+ mid-structure.
109
+
110
+ ### Added
111
+
112
+ - **`bin/cli.js` Node launcher** so `npx -y yahoo-finance-mcp-server` works. It
113
+ locates Python 3.10+, creates an isolated virtual environment, installs the
114
+ Python dependencies on first run, and starts the server with the protocol
115
+ stream kept clean on stdout.
116
+ - `tabulate` added to the dependencies.
117
+
118
+ ### Changed
119
+
120
+ - `package.json` `bin` now points at the Node launcher, the binary name matches
121
+ the package name, and a Node engine requirement was added.
122
+ - Tightened dependency floors (`yfinance>=0.2.40`, `mcp>=1.2.0`).
123
+ - Replaced the deprecated Pydantic `min_items`/`max_items` with
124
+ `min_length`/`max_length`.
125
+ - Rewrote the README and corrected the installation and troubleshooting docs.
126
+
127
+ ## [1.0.0] - 2025-11-01
128
+
129
+ ### Added
130
+
131
+ - Initial release of the Yahoo Finance MCP Server, distributed on npm.
132
+ - Six tools: `get_stock_quote`, `get_historical_prices`, `get_company_info`,
133
+ `get_financial_statements`, `compare_stocks`, and
134
+ `get_analyst_recommendations`.
135
+ - Markdown and JSON output formats.
136
+
137
+ [1.2.0]: https://github.com/danishashko/yahoo-finance-mcp/releases/tag/v1.2.0
138
+ [1.1.1]: https://github.com/danishashko/yahoo-finance-mcp/releases/tag/v1.1.1
139
+ [1.1.0]: https://github.com/danishashko/yahoo-finance-mcp/releases/tag/v1.1.0
140
+ [1.0.0]: https://github.com/danishashko/yahoo-finance-mcp/releases/tag/v1.0.0
package/package.json CHANGED
@@ -1,49 +1,51 @@
1
- {
2
- "name": "yahoo-finance-mcp-server",
3
- "version": "1.2.0",
4
- "description": "Yahoo Finance MCP Server - Real-time stock data, company info, financial statements, and market analysis via Model Context Protocol",
5
- "main": "bin/cli.js",
6
- "bin": {
7
- "yahoo-finance-mcp-server": "bin/cli.js",
8
- "yahoo-finance-mcp": "bin/cli.js"
9
- },
10
- "scripts": {
11
- "test": "python test_installation.py"
12
- },
13
- "keywords": [
14
- "mcp",
15
- "model-context-protocol",
16
- "yahoo-finance",
17
- "stocks",
18
- "finance",
19
- "market-data",
20
- "stock-prices",
21
- "financial-data",
22
- "yfinance",
23
- "claude",
24
- "ai",
25
- "llm"
26
- ],
27
- "author": "Daniel Shashko",
28
- "license": "MIT",
29
- "repository": {
30
- "type": "git",
31
- "url": "git+https://github.com/danishashko/yahoo-finance-mcp.git"
32
- },
33
- "homepage": "https://github.com/danishashko/yahoo-finance-mcp#readme",
34
- "bugs": {
35
- "url": "https://github.com/danishashko/yahoo-finance-mcp/issues"
36
- },
37
- "engines": {
38
- "node": ">=16",
39
- "python": ">=3.10"
40
- },
41
- "files": [
42
- "bin/",
43
- "yahoo_finance_mcp.py",
44
- "requirements.txt",
45
- "README.md",
46
- "CHANGELOG.md",
47
- "LICENSE"
48
- ]
49
- }
1
+ {
2
+ "name": "yahoo-finance-mcp-server",
3
+ "version": "1.2.2",
4
+ "mcpName": "io.github.danishashko/yahoo-finance-mcp",
5
+ "description": "Yahoo Finance MCP Server - Real-time stock data, company info, financial statements, and market analysis via Model Context Protocol",
6
+ "main": "bin/cli.js",
7
+ "bin": {
8
+ "yahoo-finance-mcp-server": "bin/cli.js",
9
+ "yahoo-finance-mcp": "bin/cli.js"
10
+ },
11
+ "scripts": {
12
+ "test": "python test_installation.py"
13
+ },
14
+ "keywords": [
15
+ "mcp",
16
+ "model-context-protocol",
17
+ "yahoo-finance",
18
+ "stocks",
19
+ "finance",
20
+ "market-data",
21
+ "stock-prices",
22
+ "financial-data",
23
+ "yfinance",
24
+ "claude",
25
+ "ai",
26
+ "llm"
27
+ ],
28
+ "author": "Daniel Shashko",
29
+ "license": "MIT",
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "git+https://github.com/danishashko/yahoo-finance-mcp.git"
33
+ },
34
+ "homepage": "https://github.com/danishashko/yahoo-finance-mcp#readme",
35
+ "bugs": {
36
+ "url": "https://github.com/danishashko/yahoo-finance-mcp/issues"
37
+ },
38
+ "engines": {
39
+ "node": ">=16",
40
+ "python": ">=3.10"
41
+ },
42
+ "files": [
43
+ "bin/",
44
+ "yahoo_finance_mcp.py",
45
+ "requirements.txt",
46
+ "README.md",
47
+ "CHANGELOG.md",
48
+ "LICENSE",
49
+ "server.json"
50
+ ]
51
+ }
package/server.json ADDED
@@ -0,0 +1,21 @@
1
+ {
2
+ "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
3
+ "name": "io.github.danishashko/yahoo-finance-mcp",
4
+ "description": "Real-time stock market data from Yahoo Finance: quotes, history, financials, analyst ratings, options, holders, dividends, news, and market status.",
5
+ "title": "Yahoo Finance",
6
+ "repository": {
7
+ "url": "https://github.com/danishashko/yahoo-finance-mcp",
8
+ "source": "github"
9
+ },
10
+ "version": "1.2.2",
11
+ "packages": [
12
+ {
13
+ "registryType": "npm",
14
+ "registryBaseUrl": "https://registry.npmjs.org",
15
+ "identifier": "yahoo-finance-mcp-server",
16
+ "version": "1.2.2",
17
+ "runtimeHint": "npx",
18
+ "transport": { "type": "stdio" }
19
+ }
20
+ ]
21
+ }
@@ -247,27 +247,28 @@ def truncate_response(response: str, message: str = "") -> str:
247
247
  if len(response) <= CHARACTER_LIMIT:
248
248
  return response
249
249
 
250
- truncated = response[:CHARACTER_LIMIT]
251
- truncation_msg = (
252
- f"\n\n⚠️ Response truncated at {CHARACTER_LIMIT} characters. {message}"
250
+ suffix = (
251
+ f"\n\n⚠️ Response truncated at {CHARACTER_LIMIT} characters. {message}".rstrip()
253
252
  )
254
- return truncated + truncation_msg
253
+ # Reserve room for the suffix so the total never exceeds CHARACTER_LIMIT.
254
+ return response[: max(0, CHARACTER_LIMIT - len(suffix))] + suffix
255
255
 
256
256
 
257
257
  def truncate_json_response(payload: str, message: str = "") -> str:
258
- """Truncate a JSON payload while keeping the result valid JSON.
258
+ """Cap an oversized JSON payload without dumping it into context.
259
259
 
260
- Rather than slicing a JSON string mid-structure (which yields unparseable
261
- output), wrap an oversized payload in a small valid JSON envelope.
260
+ Returns a small, valid-JSON message asking the caller to narrow the request
261
+ rather than a giant mid-cut preview (which is both context-bloating and
262
+ useless to the model). Keeps the total response tiny.
262
263
  """
263
264
  if len(payload) <= CHARACTER_LIMIT:
264
265
  return payload
265
266
 
266
- note = f"Response exceeded {CHARACTER_LIMIT} characters and was truncated. {message}".strip()
267
- return json.dumps(
268
- {"warning": note, "truncatedPreview": payload[:CHARACTER_LIMIT]},
269
- indent=2,
267
+ note = (
268
+ f"Response was too large (~{len(payload)} characters) and was not returned in full. "
269
+ f"{message}".strip()
270
270
  )
271
+ return json.dumps({"error": "response_too_large", "message": note}, indent=2)
271
272
 
272
273
 
273
274
  # ============================================================================
@@ -301,27 +302,7 @@ async def get_stock_quote(
301
302
  ),
302
303
  ] = ResponseFormat.MARKDOWN,
303
304
  ) -> str:
304
- """Get current stock quote with real-time price, volume, and market data.
305
-
306
- This tool retrieves the latest stock quote including current price, day's range,
307
- trading volume, market cap, and other key metrics for a given ticker symbol.
308
-
309
- Use this tool when:
310
- - User wants current/latest stock price
311
- - User asks "what's the price of [stock]"
312
- - User wants basic stock information
313
-
314
- Args:
315
- ticker: Stock ticker symbol (e.g., 'AAPL', 'MSFT', 'TSLA').
316
- response_format: 'markdown' or 'json'.
317
-
318
- Returns:
319
- str: Current stock quote in requested format (markdown or JSON).
320
-
321
- Example:
322
- Input: {"ticker": "AAPL", "response_format": "markdown"}
323
- Output: Formatted markdown with current price, volume, market cap, etc.
324
- """
305
+ """Current stock quote: price, change, day/52-week range, volume, market cap, P/E, EPS, dividend yield. Use for "what's the price of [stock]"."""
325
306
  ticker = _norm_ticker(ticker)
326
307
  try:
327
308
  ticker_obj = make_ticker(ticker)
@@ -458,29 +439,7 @@ async def get_historical_prices(
458
439
  ),
459
440
  ] = ResponseFormat.MARKDOWN,
460
441
  ) -> str:
461
- """Get historical stock price data with OHLCV (Open, High, Low, Close, Volume).
462
-
463
- This tool retrieves historical price data for technical analysis, charting,
464
- and trend analysis.
465
-
466
- Use this tool when:
467
- - User wants to see price history/trends
468
- - User asks "how has [stock] performed over [time period]"
469
- - User wants data for charting or analysis
470
-
471
- Args:
472
- ticker: Stock ticker symbol.
473
- period: Time period ('1mo', '1y', '5y', etc.).
474
- interval: Data interval ('1d', '1h', etc.).
475
- response_format: 'markdown' or 'json'.
476
-
477
- Returns:
478
- str: Historical price data in requested format.
479
-
480
- Example:
481
- Input: {"ticker": "AAPL", "period": "1mo", "interval": "1d"}
482
- Output: Daily OHLCV data for the past month
483
- """
442
+ """Historical OHLCV price data with summary stats and total return, for trends/charting. Use for "how has [stock] performed over [period]"."""
484
443
  ticker = _norm_ticker(ticker)
485
444
  try:
486
445
  ticker_obj = make_ticker(ticker)
@@ -574,25 +533,7 @@ async def get_company_info(
574
533
  ),
575
534
  ] = ResponseFormat.MARKDOWN,
576
535
  ) -> str:
577
- """Get comprehensive company information including business description, officers, and key statistics.
578
-
579
- Use this tool when:
580
- - User wants to know "what does [company] do"
581
- - User asks about company leadership/executives
582
- - User wants detailed company background
583
- - User needs comprehensive financial statistics
584
-
585
- Args:
586
- ticker: Stock ticker symbol.
587
- response_format: 'markdown' or 'json'.
588
-
589
- Returns:
590
- str: Detailed company information in requested format.
591
-
592
- Example:
593
- Input: {"ticker": "AAPL", "response_format": "markdown"}
594
- Output: Full company profile with description, officers, statistics
595
- """
536
+ """Company profile: business summary, executives, valuation and financial-highlight stats. Use for "what does [company] do" or company background."""
596
537
  ticker = _norm_ticker(ticker)
597
538
  try:
598
539
  ticker_obj = make_ticker(ticker)
@@ -714,25 +655,7 @@ async def get_financial_statements(
714
655
  ),
715
656
  ] = ResponseFormat.MARKDOWN,
716
657
  ) -> str:
717
- """Get comprehensive financial statements including income statement, balance sheet, and cash flow.
718
-
719
- Use this tool when:
720
- - User wants to see revenue, earnings, expenses
721
- - User asks about balance sheet items (assets, liabilities)
722
- - User wants cash flow information
723
- - User needs data for financial analysis
724
-
725
- Args:
726
- ticker: Stock ticker symbol.
727
- response_format: 'markdown' or 'json'.
728
-
729
- Returns:
730
- str: Financial statements in requested format.
731
-
732
- Example:
733
- Input: {"ticker": "AAPL", "response_format": "markdown"}
734
- Output: Income statement, balance sheet, and cash flow data
735
- """
658
+ """Annual income statement, balance sheet, and cash flow. Use for revenue, earnings, assets/liabilities, or fundamental analysis."""
736
659
  ticker = _norm_ticker(ticker)
737
660
  try:
738
661
  ticker_obj = make_ticker(ticker)
@@ -817,24 +740,7 @@ async def compare_stocks(
817
740
  ),
818
741
  ] = ResponseFormat.MARKDOWN,
819
742
  ) -> str:
820
- """Compare key metrics across multiple stocks side-by-side.
821
-
822
- Use this tool when:
823
- - User wants to compare multiple stocks
824
- - User asks "which is better, [stock1] or [stock2]"
825
- - User wants to see relative performance
826
-
827
- Args:
828
- tickers: 2-10 ticker symbols to compare.
829
- response_format: 'markdown' or 'json'.
830
-
831
- Returns:
832
- str: Comparison table in requested format.
833
-
834
- Example:
835
- Input: {"tickers": ["AAPL", "MSFT", "GOOGL"], "response_format": "markdown"}
836
- Output: Side-by-side comparison table of key metrics
837
- """
743
+ """Compare key metrics for 2-10 stocks side by side, with quick insights. Use for "which is better, X or Y" or relative performance."""
838
744
  tickers = [_norm_ticker(t) for t in tickers]
839
745
  try:
840
746
  comparison_data = []
@@ -935,25 +841,7 @@ async def get_analyst_recommendations(
935
841
  ),
936
842
  ] = ResponseFormat.MARKDOWN,
937
843
  ) -> str:
938
- """Get analyst recommendations, price targets, and the recent rating trend.
939
-
940
- Use this tool when:
941
- - User wants to know what analysts think
942
- - User asks about price targets or recommendations
943
- - User wants to see recent upgrades/downgrades
944
- - User needs a professional analysis summary
945
-
946
- Args:
947
- ticker: Stock ticker symbol.
948
- response_format: 'markdown' or 'json'.
949
-
950
- Returns:
951
- str: Analyst recommendations and price targets.
952
-
953
- Example:
954
- Input: {"ticker": "AAPL", "response_format": "markdown"}
955
- Output: Analyst consensus, price targets, recommendation trend
956
- """
844
+ """Analyst price targets, consensus rating, recommendation trend, and recent upgrades/downgrades. Use for "what do analysts think of [stock]". For forward EPS/revenue estimates use get_analyst_estimates."""
957
845
  ticker = _norm_ticker(ticker)
958
846
  try:
959
847
  ticker_obj = make_ticker(ticker)
@@ -1093,25 +981,7 @@ async def get_market_news(
1093
981
  ),
1094
982
  ] = ResponseFormat.MARKDOWN,
1095
983
  ) -> str:
1096
- """Get the latest financial news articles for a stock.
1097
-
1098
- Use this tool when:
1099
- - User asks "what's the latest news on [stock]"
1100
- - User wants recent headlines or developments for a company
1101
- - User needs context behind a price move
1102
-
1103
- Args:
1104
- ticker: Stock ticker symbol.
1105
- count: How many articles to return (1-20).
1106
- response_format: 'markdown' or 'json'.
1107
-
1108
- Returns:
1109
- str: Recent news headlines with source, date, summary, and link.
1110
-
1111
- Example:
1112
- Input: {"ticker": "NVDA", "count": 5}
1113
- Output: The 5 most recent NVDA news articles
1114
- """
984
+ """Latest news headlines for a stock (source, date, summary, link). Use for "what's the latest news on [stock]"."""
1115
985
  ticker = _norm_ticker(ticker)
1116
986
  try:
1117
987
  articles = make_ticker(ticker).get_news(count=count) or []
@@ -1215,28 +1085,7 @@ async def get_options_chain(
1215
1085
  ),
1216
1086
  ] = ResponseFormat.MARKDOWN,
1217
1087
  ) -> str:
1218
- """Get the options chain (calls/puts) for a stock, or list expiration dates.
1219
-
1220
- Call without an expiration_date first to see the available dates, then call
1221
- again with a specific date to get the chain.
1222
-
1223
- Use this tool when:
1224
- - User asks about options, calls, puts, strikes, or implied volatility
1225
- - User wants the options chain for a specific expiration
1226
-
1227
- Args:
1228
- ticker: Stock ticker symbol.
1229
- expiration_date: 'YYYY-MM-DD', or empty to list available dates.
1230
- option_type: 'calls', 'puts', or 'both'.
1231
- response_format: 'markdown' or 'json'.
1232
-
1233
- Returns:
1234
- str: Either the list of expiration dates, or the requested options chain.
1235
-
1236
- Example:
1237
- Input: {"ticker": "SPY"} -> lists expirations
1238
- Input: {"ticker": "SPY", "expiration_date": "2026-06-20", "option_type": "calls"}
1239
- """
1088
+ """Options chain (strike, bid/ask, volume, open interest, IV) for an expiration. Call with no expiration_date first to list available dates, then again with a date."""
1240
1089
  ticker = _norm_ticker(ticker)
1241
1090
  try:
1242
1091
  t = make_ticker(ticker)
@@ -1329,25 +1178,7 @@ async def get_holders(
1329
1178
  ),
1330
1179
  ] = ResponseFormat.MARKDOWN,
1331
1180
  ) -> str:
1332
- """Get ownership breakdown and insider activity for a stock.
1333
-
1334
- Use this tool when:
1335
- - User asks who owns a stock, or about institutional/fund ownership
1336
- - User wants recent insider buying/selling
1337
- - User wants the major-holders summary (insider vs institutional %)
1338
-
1339
- Args:
1340
- ticker: Stock ticker symbol.
1341
- holder_type: 'institutional', 'mutualfund', 'major', or 'insider_transactions'.
1342
- response_format: 'markdown' or 'json'.
1343
-
1344
- Returns:
1345
- str: The requested ownership table.
1346
-
1347
- Example:
1348
- Input: {"ticker": "AAPL", "holder_type": "institutional"}
1349
- Output: Top institutional holders with shares and % held
1350
- """
1181
+ """Stock ownership and insider activity by holder_type: institutional, mutualfund, major (insider-vs-institutional %), or insider_transactions."""
1351
1182
  ticker = _norm_ticker(ticker)
1352
1183
  try:
1353
1184
  t = make_ticker(ticker)
@@ -1418,24 +1249,7 @@ async def get_dividends_splits(
1418
1249
  ),
1419
1250
  ] = ResponseFormat.MARKDOWN,
1420
1251
  ) -> str:
1421
- """Get the dividend payment and stock split history for a stock.
1422
-
1423
- Use this tool when:
1424
- - User asks about a company's dividend history or track record
1425
- - User asks when a stock split, or its split history
1426
- - User wants to see dividend growth over time
1427
-
1428
- Args:
1429
- ticker: Stock ticker symbol.
1430
- response_format: 'markdown' or 'json'.
1431
-
1432
- Returns:
1433
- str: Dividend history and split history with a short summary.
1434
-
1435
- Example:
1436
- Input: {"ticker": "KO"}
1437
- Output: Coca-Cola's dividend payments and any stock splits
1438
- """
1252
+ """Dividend payment history (with trailing summary) and stock-split history for a stock."""
1439
1253
  ticker = _norm_ticker(ticker)
1440
1254
  try:
1441
1255
  t = make_ticker(ticker)
@@ -1530,29 +1344,7 @@ async def get_analyst_estimates(
1530
1344
  ),
1531
1345
  ] = ResponseFormat.MARKDOWN,
1532
1346
  ) -> str:
1533
- """Get forward-looking analyst estimates: price targets, EPS/revenue estimates, and growth.
1534
-
1535
- This complements get_analyst_recommendations (which covers ratings/trend) with
1536
- the forward numbers analysts project.
1537
-
1538
- Use this tool when:
1539
- - User asks about the analyst price target or expected upside
1540
- - User wants projected EPS or revenue for upcoming quarters/years
1541
- - User asks how estimates have trended or expected growth rates
1542
-
1543
- Args:
1544
- ticker: Stock ticker symbol.
1545
- response_format: 'markdown' or 'json'.
1546
-
1547
- Returns:
1548
- str: Price targets, EPS estimate, revenue estimate, and growth estimates.
1549
- Estimate periods are labelled 0q (current quarter), +1q (next quarter),
1550
- 0y (current year), +1y (next year).
1551
-
1552
- Example:
1553
- Input: {"ticker": "AAPL"}
1554
- Output: Mean/high/low price target, forward EPS & revenue, growth outlook
1555
- """
1347
+ """Forward analyst estimates: price targets, EPS/revenue estimates by period, and growth. Complements get_analyst_recommendations (ratings/trend) with projected numbers."""
1556
1348
  ticker = _norm_ticker(ticker)
1557
1349
  try:
1558
1350
  t = make_ticker(ticker)
@@ -1655,25 +1447,7 @@ async def search_symbols(
1655
1447
  ),
1656
1448
  ] = ResponseFormat.MARKDOWN,
1657
1449
  ) -> str:
1658
- """Find ticker symbols by company name or keyword.
1659
-
1660
- Use this tool when:
1661
- - The user names a company but not its ticker ("what's the symbol for ...")
1662
- - You need to resolve a name to a ticker before calling other tools
1663
- - The user wants to discover related/similar listed companies
1664
-
1665
- Args:
1666
- query: Company name or keyword.
1667
- count: Max matches to return (1-20).
1668
- response_format: 'markdown' or 'json'.
1669
-
1670
- Returns:
1671
- str: Matching symbols with name, exchange, type, sector, and industry.
1672
-
1673
- Example:
1674
- Input: {"query": "Apple"}
1675
- Output: AAPL - Apple Inc. (NASDAQ, Equity, Technology) and related matches
1676
- """
1450
+ """Find ticker symbols by company name or keyword. Use to resolve a name to a ticker before calling other tools."""
1677
1451
  query = query.strip()
1678
1452
  try:
1679
1453
  session = _get_session()
@@ -1749,23 +1523,7 @@ async def get_market_status(
1749
1523
  ),
1750
1524
  ] = ResponseFormat.MARKDOWN,
1751
1525
  ) -> str:
1752
- """Check whether a market is open and get a summary of its major indices.
1753
-
1754
- Use this tool when:
1755
- - User asks "is the market open?" or when it opens/closes
1756
- - User wants a quick read on the major indices for a region
1757
-
1758
- Args:
1759
- region: Market region code (default 'US').
1760
- response_format: 'markdown' or 'json'.
1761
-
1762
- Returns:
1763
- str: Market open/closed status with timing, plus major index levels.
1764
-
1765
- Example:
1766
- Input: {"region": "US"}
1767
- Output: U.S. markets status, close time, and S&P/Dow/Nasdaq summary
1768
- """
1526
+ """Whether a market (by region code, e.g. US/GB/JP) is open or closed, with timing and a major-index summary."""
1769
1527
  region = region.strip().upper()
1770
1528
  try:
1771
1529
  session = _get_session()