yahoo-finance-mcp-server 1.2.1 → 1.2.4

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,126 +1,169 @@
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.1] - 2026-06-02
9
-
10
- Packaging only. No runtime code changes.
11
-
12
- ### Added
13
-
14
- - `server.json` and an `mcpName` field for listing on the official MCP Registry.
15
-
16
- ## [1.2.0] - 2026-06-01
17
-
18
- Major feature release: **seven new data tools (6 → 13)** plus rate-limit
19
- hardening. Every tool was verified end to end by driving the real MCP server
20
- over stdio against live Yahoo Finance data.
21
-
22
- ### Added
23
-
24
- - **`get_market_news`** — latest news headlines for a ticker, with source,
25
- date, summary, and link. Handles the modern nested yfinance news format.
26
- - **`get_options_chain`** — list available expiration dates, or fetch the
27
- calls/puts chain (strike, bid/ask, volume, open interest, implied
28
- volatility) for a given expiration.
29
- - **`get_holders`** — institutional holders, mutual-fund holders, the
30
- major-holders breakdown, or recent insider transactions.
31
- - **`get_dividends_splits`** — full dividend payment history (with a trailing
32
- summary) and stock-split history.
33
- - **`get_analyst_estimates`** — forward analyst price targets, EPS and revenue
34
- estimates by period, and growth estimates (complements the existing
35
- recommendations tool).
36
- - **`search_symbols`** — find ticker symbols by company name or keyword, with
37
- exchange, type, sector, and industry.
38
- - **`get_market_status`** — whether a market (by region) is open or closed,
39
- with timing and a summary of its major indices.
40
- - **Shared `curl_cffi` browser-impersonating HTTP session** reused across all
41
- tools. This cuts down on Yahoo's HTTP 429 rate-limiting and speeds up
42
- repeated calls; it degrades gracefully to the default session if
43
- `curl_cffi` is unavailable.
44
- - Friendly, specific handling of `YFRateLimitError` ("wait and retry")
45
- across all tools.
46
-
47
- ### Changed
48
-
49
- - `requirements.txt`: add `curl_cffi`; raise the `yfinance` floor to
50
- `>=0.2.61` (which carries upstream rate-limit-handling fixes and the
51
- `Search`/`Market` APIs used by the new tools).
52
-
53
- ## [1.1.1] - 2026-05-31
54
-
55
- Documentation and packaging only. No runtime code changes; behavior is
56
- identical to 1.1.0.
57
-
58
- ### Changed
59
-
60
- - Reworked the README: clearer structure, a tools table with parameters and
61
- supported `period`/`interval` values, example prompts, and a note clarifying
62
- that the repository name (`yahoo-finance-mcp`) differs from the npm package
63
- name (`yahoo-finance-mcp-server`).
64
- - Added shields.io badges, including a monthly-downloads pill and a Python
65
- version badge.
66
- - Normalized `repository.url` to the `git+https://` form npm expects.
67
-
68
- ### Added
69
-
70
- - This `CHANGELOG.md`, now shipped in the npm tarball.
71
-
72
- ## [1.1.0] - 2026-05-30
73
-
74
- A full QA pass that fixed several bugs which broke core functionality, and made
75
- the documented `npx` installation actually work. Every fix was verified end to
76
- end by driving the real MCP server over stdio against live Yahoo Finance data.
77
-
78
- ### Fixed
79
-
80
- - **Tool inputs failed validation.** Each tool took a single Pydantic model
81
- argument, so the MCP schema nested every field under a required `params`
82
- object while the docs told the model to send fields directly. The result was
83
- that calls were rejected. Tools now expose their parameters directly.
84
- - **`get_analyst_recommendations` crashed** with `'RangeIndex' object has no
85
- attribute 'strftime'` due to a change in the `yfinance` recommendations
86
- format. It now reads the current format and also reports recent
87
- upgrades/downgrades.
88
- - **Dividend yield was shown 100x too high** (for example `35.00%` for AAPL).
89
- Modern `yfinance` already returns this value as a percentage, so it is no
90
- longer multiplied again.
91
- - **Markdown tables broke** when the optional `tabulate` package was missing.
92
- It is now a declared dependency, with a graceful plain-text fallback.
93
- - **Truncated JSON responses are now valid JSON** instead of being cut off
94
- mid-structure.
95
-
96
- ### Added
97
-
98
- - **`bin/cli.js` Node launcher** so `npx -y yahoo-finance-mcp-server` works. It
99
- locates Python 3.10+, creates an isolated virtual environment, installs the
100
- Python dependencies on first run, and starts the server with the protocol
101
- stream kept clean on stdout.
102
- - `tabulate` added to the dependencies.
103
-
104
- ### Changed
105
-
106
- - `package.json` `bin` now points at the Node launcher, the binary name matches
107
- the package name, and a Node engine requirement was added.
108
- - Tightened dependency floors (`yfinance>=0.2.40`, `mcp>=1.2.0`).
109
- - Replaced the deprecated Pydantic `min_items`/`max_items` with
110
- `min_length`/`max_length`.
111
- - Rewrote the README and corrected the installation and troubleshooting docs.
112
-
113
- ## [1.0.0] - 2025-11-01
114
-
115
- ### Added
116
-
117
- - Initial release of the Yahoo Finance MCP Server, distributed on npm.
118
- - Six tools: `get_stock_quote`, `get_historical_prices`, `get_company_info`,
119
- `get_financial_statements`, `compare_stocks`, and
120
- `get_analyst_recommendations`.
121
- - Markdown and JSON output formats.
122
-
123
- [1.2.0]: https://github.com/danishashko/yahoo-finance-mcp/releases/tag/v1.2.0
124
- [1.1.1]: https://github.com/danishashko/yahoo-finance-mcp/releases/tag/v1.1.1
125
- [1.1.0]: https://github.com/danishashko/yahoo-finance-mcp/releases/tag/v1.1.0
126
- [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.4] - 2026-07-30
9
+
10
+ ### Fixed
11
+
12
+ - Fresh installs no longer crash on startup. `requirements.txt` had no upper
13
+ bound on `mcp`, so after the MCP Python SDK 2.0.0 release (2026-07-28)
14
+ `pip install -r requirements.txt` pulled 2.x, which removed
15
+ `mcp.server.fastmcp` and made the server die with
16
+ `ModuleNotFoundError: No module named 'mcp.server.fastmcp'`. The requirement
17
+ is now `mcp>=1.2.0,<2`. Existing installs were unaffected (the launcher
18
+ caches its virtualenv per requirements hash).
19
+
20
+ ## [1.2.3] - 2026-06-06
21
+
22
+ ### Changed
23
+
24
+ - Enriched every tool description with purpose, when-to-use/disambiguation
25
+ guidance, and return/error behavior. This raises self-describing quality for
26
+ AI agents (and Glama's Tool Definition Quality score) while staying lean
27
+ (~140 tokens per tool); parameters remain self-documented via their field
28
+ descriptions.
29
+
30
+ ### Added
31
+
32
+ - `Dockerfile`, `.dockerignore`, and `glama.json` to support a containerized
33
+ Glama release (builds `python:3.12-slim`, runs the server over stdio as a
34
+ non-root user). Verified locally: the image builds and `tools/list` returns
35
+ all 13 tools.
36
+
37
+ ## [1.2.2] - 2026-06-04
38
+
39
+ ### Fixed
40
+
41
+ - Oversized responses no longer overflow the response size cap. Previously a
42
+ too-large JSON response could be returned larger than the limit (and dumped a
43
+ giant truncated preview into context); it now returns a small message asking
44
+ to narrow the request.
45
+
46
+ ### Changed
47
+
48
+ - Trimmed verbose tool descriptions to cut the always-loaded schema size
49
+ (~1,800 fewer tokens on connect). Tool behavior unchanged.
50
+
51
+ ## [1.2.1] - 2026-06-02
52
+
53
+ Packaging only. No runtime code changes.
54
+
55
+ ### Added
56
+
57
+ - `server.json` and an `mcpName` field for listing on the official MCP Registry.
58
+
59
+ ## [1.2.0] - 2026-06-01
60
+
61
+ Major feature release: **seven new data tools (6 → 13)** plus rate-limit
62
+ hardening. Every tool was verified end to end by driving the real MCP server
63
+ over stdio against live Yahoo Finance data.
64
+
65
+ ### Added
66
+
67
+ - **`get_market_news`** — latest news headlines for a ticker, with source,
68
+ date, summary, and link. Handles the modern nested yfinance news format.
69
+ - **`get_options_chain`** — list available expiration dates, or fetch the
70
+ calls/puts chain (strike, bid/ask, volume, open interest, implied
71
+ volatility) for a given expiration.
72
+ - **`get_holders`** — institutional holders, mutual-fund holders, the
73
+ major-holders breakdown, or recent insider transactions.
74
+ - **`get_dividends_splits`** — full dividend payment history (with a trailing
75
+ summary) and stock-split history.
76
+ - **`get_analyst_estimates`** — forward analyst price targets, EPS and revenue
77
+ estimates by period, and growth estimates (complements the existing
78
+ recommendations tool).
79
+ - **`search_symbols`** — find ticker symbols by company name or keyword, with
80
+ exchange, type, sector, and industry.
81
+ - **`get_market_status`** — whether a market (by region) is open or closed,
82
+ with timing and a summary of its major indices.
83
+ - **Shared `curl_cffi` browser-impersonating HTTP session** reused across all
84
+ tools. This cuts down on Yahoo's HTTP 429 rate-limiting and speeds up
85
+ repeated calls; it degrades gracefully to the default session if
86
+ `curl_cffi` is unavailable.
87
+ - Friendly, specific handling of `YFRateLimitError` ("wait and retry")
88
+ across all tools.
89
+
90
+ ### Changed
91
+
92
+ - `requirements.txt`: add `curl_cffi`; raise the `yfinance` floor to
93
+ `>=0.2.61` (which carries upstream rate-limit-handling fixes and the
94
+ `Search`/`Market` APIs used by the new tools).
95
+
96
+ ## [1.1.1] - 2026-05-31
97
+
98
+ Documentation and packaging only. No runtime code changes; behavior is
99
+ identical to 1.1.0.
100
+
101
+ ### Changed
102
+
103
+ - Reworked the README: clearer structure, a tools table with parameters and
104
+ supported `period`/`interval` values, example prompts, and a note clarifying
105
+ that the repository name (`yahoo-finance-mcp`) differs from the npm package
106
+ name (`yahoo-finance-mcp-server`).
107
+ - Added shields.io badges, including a monthly-downloads pill and a Python
108
+ version badge.
109
+ - Normalized `repository.url` to the `git+https://` form npm expects.
110
+
111
+ ### Added
112
+
113
+ - This `CHANGELOG.md`, now shipped in the npm tarball.
114
+
115
+ ## [1.1.0] - 2026-05-30
116
+
117
+ A full QA pass that fixed several bugs which broke core functionality, and made
118
+ the documented `npx` installation actually work. Every fix was verified end to
119
+ end by driving the real MCP server over stdio against live Yahoo Finance data.
120
+
121
+ ### Fixed
122
+
123
+ - **Tool inputs failed validation.** Each tool took a single Pydantic model
124
+ argument, so the MCP schema nested every field under a required `params`
125
+ object while the docs told the model to send fields directly. The result was
126
+ that calls were rejected. Tools now expose their parameters directly.
127
+ - **`get_analyst_recommendations` crashed** with `'RangeIndex' object has no
128
+ attribute 'strftime'` due to a change in the `yfinance` recommendations
129
+ format. It now reads the current format and also reports recent
130
+ upgrades/downgrades.
131
+ - **Dividend yield was shown 100x too high** (for example `35.00%` for AAPL).
132
+ Modern `yfinance` already returns this value as a percentage, so it is no
133
+ longer multiplied again.
134
+ - **Markdown tables broke** when the optional `tabulate` package was missing.
135
+ It is now a declared dependency, with a graceful plain-text fallback.
136
+ - **Truncated JSON responses are now valid JSON** instead of being cut off
137
+ mid-structure.
138
+
139
+ ### Added
140
+
141
+ - **`bin/cli.js` Node launcher** so `npx -y yahoo-finance-mcp-server` works. It
142
+ locates Python 3.10+, creates an isolated virtual environment, installs the
143
+ Python dependencies on first run, and starts the server with the protocol
144
+ stream kept clean on stdout.
145
+ - `tabulate` added to the dependencies.
146
+
147
+ ### Changed
148
+
149
+ - `package.json` `bin` now points at the Node launcher, the binary name matches
150
+ the package name, and a Node engine requirement was added.
151
+ - Tightened dependency floors (`yfinance>=0.2.40`, `mcp>=1.2.0`).
152
+ - Replaced the deprecated Pydantic `min_items`/`max_items` with
153
+ `min_length`/`max_length`.
154
+ - Rewrote the README and corrected the installation and troubleshooting docs.
155
+
156
+ ## [1.0.0] - 2025-11-01
157
+
158
+ ### Added
159
+
160
+ - Initial release of the Yahoo Finance MCP Server, distributed on npm.
161
+ - Six tools: `get_stock_quote`, `get_historical_prices`, `get_company_info`,
162
+ `get_financial_statements`, `compare_stocks`, and
163
+ `get_analyst_recommendations`.
164
+ - Markdown and JSON output formats.
165
+
166
+ [1.2.0]: https://github.com/danishashko/yahoo-finance-mcp/releases/tag/v1.2.0
167
+ [1.1.1]: https://github.com/danishashko/yahoo-finance-mcp/releases/tag/v1.1.1
168
+ [1.1.0]: https://github.com/danishashko/yahoo-finance-mcp/releases/tag/v1.1.0
169
+ [1.0.0]: https://github.com/danishashko/yahoo-finance-mcp/releases/tag/v1.0.0
package/package.json CHANGED
@@ -1,51 +1,51 @@
1
- {
2
- "name": "yahoo-finance-mcp-server",
3
- "version": "1.2.1",
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
- }
1
+ {
2
+ "name": "yahoo-finance-mcp-server",
3
+ "version": "1.2.4",
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/requirements.txt CHANGED
@@ -1,10 +1,11 @@
1
- # Yahoo Finance MCP Server Requirements
2
- # Install all dependencies with: pip install -r requirements.txt
3
-
4
- yfinance>=0.2.61
5
- curl_cffi>=0.7.0
6
- pandas>=1.5.0
7
- tabulate>=0.9.0
8
- mcp>=1.2.0
9
- pydantic>=2.0.0
10
- httpx>=0.24.0
1
+ # Yahoo Finance MCP Server Requirements
2
+ # Install all dependencies with: pip install -r requirements.txt
3
+
4
+ yfinance>=0.2.61
5
+ curl_cffi>=0.7.0
6
+ pandas>=1.5.0
7
+ tabulate>=0.9.0
8
+ # Pinned below 2.0: the v2 SDK removed mcp.server.fastmcp, which this server uses.
9
+ mcp>=1.2.0,<2
10
+ pydantic>=2.0.0
11
+ httpx>=0.24.0
package/server.json CHANGED
@@ -1,21 +1,23 @@
1
1
  {
2
2
  "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
3
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.",
4
+ "description": "Real-time Yahoo Finance data: quotes, history, financials, analyst ratings, options, and news.",
5
5
  "title": "Yahoo Finance",
6
6
  "repository": {
7
7
  "url": "https://github.com/danishashko/yahoo-finance-mcp",
8
8
  "source": "github"
9
9
  },
10
- "version": "1.2.1",
10
+ "version": "1.2.4",
11
11
  "packages": [
12
12
  {
13
13
  "registryType": "npm",
14
14
  "registryBaseUrl": "https://registry.npmjs.org",
15
15
  "identifier": "yahoo-finance-mcp-server",
16
- "version": "1.2.1",
16
+ "version": "1.2.4",
17
17
  "runtimeHint": "npx",
18
- "transport": { "type": "stdio" }
18
+ "transport": {
19
+ "type": "stdio"
20
+ }
19
21
  }
20
22
  ]
21
23
  }
@@ -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,26 +302,11 @@ 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
+ """Real-time quote snapshot for ONE stock: last price, day change ($ and %), open, previous close, day range, 52-week range, volume and average volume, market cap, beta, trailing P/E, EPS, dividend yield, and sector/industry/website.
305
306
 
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.
307
+ Use for "what's the price of X" or a quick single-stock snapshot. For several stocks side by side use compare_stocks; for the full company profile use get_company_info; for a past price series use get_historical_prices.
308
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.
309
+ Returns Markdown by default, or structured JSON when response_format='json'. An unknown ticker or an upstream/rate-limit error returns a short error message rather than raising.
324
310
  """
325
311
  ticker = _norm_ticker(ticker)
326
312
  try:
@@ -458,28 +444,11 @@ async def get_historical_prices(
458
444
  ),
459
445
  ] = ResponseFormat.MARKDOWN,
460
446
  ) -> 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.
447
+ """Historical OHLCV price series for one stock over a chosen period/interval, plus summary stats (highest/lowest/average close, average volume) and total return over the window.
465
448
 
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
449
+ Use for performance, trends, or charting ("how has X done over the last year"). For a single current price use get_stock_quote; for dividend/split events use get_dividends_splits. Note: intraday intervals (1m-90m) are only available for short recent periods, and long periods return many rows, so prefer JSON or a shorter period if the output is truncated.
470
450
 
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
451
+ Returns Markdown (summary stats plus the last 10 rows) by default, or the full series as JSON when response_format='json'. An empty or unsupported period/interval combination returns a short message.
483
452
  """
484
453
  ticker = _norm_ticker(ticker)
485
454
  try:
@@ -574,24 +543,11 @@ async def get_company_info(
574
543
  ),
575
544
  ] = ResponseFormat.MARKDOWN,
576
545
  ) -> 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'.
546
+ """Detailed company profile for one stock: long business summary, sector/industry, key executives, headquarters/website/employee count, and valuation & financial-highlight stats (market cap, P/E, margins, and similar).
588
547
 
589
- Returns:
590
- str: Detailed company information in requested format.
548
+ Use for "what does X do", company background, or a business overview. For the statement-level numbers (income/balance/cash flow) use get_financial_statements; for just the live price use get_stock_quote.
591
549
 
592
- Example:
593
- Input: {"ticker": "AAPL", "response_format": "markdown"}
594
- Output: Full company profile with description, officers, statistics
550
+ Returns Markdown by default, or JSON when response_format='json'. An unknown ticker or upstream error returns a short error message.
595
551
  """
596
552
  ticker = _norm_ticker(ticker)
597
553
  try:
@@ -714,24 +670,11 @@ async def get_financial_statements(
714
670
  ),
715
671
  ] = ResponseFormat.MARKDOWN,
716
672
  ) -> str:
717
- """Get comprehensive financial statements including income statement, balance sheet, and cash flow.
673
+ """Annual financial statements for one company: income statement, balance sheet, and cash flow statement, each with multiple years of data.
718
674
 
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
675
+ Use for revenue, earnings, assets/liabilities, cash flow, or fundamental analysis. For headline ratios only use get_company_info; for forward projections use get_analyst_estimates. Quarterly data is not returned; request JSON for the complete machine-readable export.
724
676
 
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
677
+ Returns Markdown by default, or JSON when response_format='json'. Companies without filed statements (for example some ETFs or ADRs) return empty sections or a short message.
735
678
  """
736
679
  ticker = _norm_ticker(ticker)
737
680
  try:
@@ -817,23 +760,11 @@ async def compare_stocks(
817
760
  ),
818
761
  ] = ResponseFormat.MARKDOWN,
819
762
  ) -> 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'.
763
+ """Side-by-side comparison of 2-10 stocks across key metrics (price, market cap, P/E, EPS, dividend yield, 52-week range, and period performance) with brief auto-generated insights.
830
764
 
831
- Returns:
832
- str: Comparison table in requested format.
765
+ Use for "which is better, X or Y", peer/relative comparison, or screening a small set. For a deep dive on a single name use get_stock_quote or get_company_info.
833
766
 
834
- Example:
835
- Input: {"tickers": ["AAPL", "MSFT", "GOOGL"], "response_format": "markdown"}
836
- Output: Side-by-side comparison table of key metrics
767
+ Pass 2-10 tickers in the tickers list. Returns a Markdown comparison table by default, or JSON when response_format='json'. A ticker that fails to resolve is reported per-symbol rather than failing the whole call.
837
768
  """
838
769
  tickers = [_norm_ticker(t) for t in tickers]
839
770
  try:
@@ -935,24 +866,11 @@ async def get_analyst_recommendations(
935
866
  ),
936
867
  ] = ResponseFormat.MARKDOWN,
937
868
  ) -> str:
938
- """Get analyst recommendations, price targets, and the recent rating trend.
869
+ """Wall Street analyst view on one stock: price targets (high/mean/low), consensus rating, the buy/hold/sell recommendation-trend breakdown, and recent upgrades/downgrades.
939
870
 
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
871
+ Use for "what do analysts think of X", ratings, or sentiment. For forward EPS/revenue/growth projections use get_analyst_estimates instead: this tool is ratings and targets, that one is the numeric estimates.
945
872
 
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
873
+ Returns Markdown by default, or JSON when response_format='json'. A stock with no analyst coverage returns the available fields as N/A; errors return a short message.
956
874
  """
957
875
  ticker = _norm_ticker(ticker)
958
876
  try:
@@ -1093,24 +1011,11 @@ async def get_market_news(
1093
1011
  ),
1094
1012
  ] = ResponseFormat.MARKDOWN,
1095
1013
  ) -> 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
1014
+ """Latest news articles for one stock; each item has a title, publisher/source, publish date, a short summary, and a link.
1102
1015
 
1103
- Args:
1104
- ticker: Stock ticker symbol.
1105
- count: How many articles to return (1-20).
1106
- response_format: 'markdown' or 'json'.
1016
+ Use for "what's the latest news on X", recent headlines, or catalysts. Returns news only: for price use get_stock_quote, for fundamentals use the financials tools.
1107
1017
 
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
1018
+ count sets how many articles to return (1-20, default 10). Returns Markdown by default, or JSON when response_format='json'. No recent news returns a short message.
1114
1019
  """
1115
1020
  ticker = _norm_ticker(ticker)
1116
1021
  try:
@@ -1215,27 +1120,11 @@ async def get_options_chain(
1215
1120
  ),
1216
1121
  ] = ResponseFormat.MARKDOWN,
1217
1122
  ) -> 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'.
1123
+ """Equity options data for one underlying, in two modes: call with no expiration_date to LIST every available expiration date; call again with a specific 'YYYY-MM-DD' to get that expiration's chain (strike, bid/ask, last, volume, open interest, implied volatility).
1232
1124
 
1233
- Returns:
1234
- str: Either the list of expiration dates, or the requested options chain.
1125
+ Use for options pricing, implied volatility, or open-interest analysis. option_type selects 'calls', 'puts', or 'both'. Always discover the valid dates first (call with no date) before requesting a chain, since only listed expirations work.
1235
1126
 
1236
- Example:
1237
- Input: {"ticker": "SPY"} -> lists expirations
1238
- Input: {"ticker": "SPY", "expiration_date": "2026-06-20", "option_type": "calls"}
1127
+ Returns Markdown by default, or JSON when response_format='json'. A ticker with no listed options returns a short message.
1239
1128
  """
1240
1129
  ticker = _norm_ticker(ticker)
1241
1130
  try:
@@ -1329,24 +1218,11 @@ async def get_holders(
1329
1218
  ),
1330
1219
  ] = ResponseFormat.MARKDOWN,
1331
1220
  ) -> str:
1332
- """Get ownership breakdown and insider activity for a stock.
1221
+ """Ownership and insider activity for one stock, selected by holder_type: 'institutional' (top institutional holders), 'mutualfund' (top fund holders), 'major' (insider-vs-institutional ownership % breakdown), or 'insider_transactions' (recent insider buys and sells).
1333
1222
 
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 %)
1223
+ Use for "who owns X", institutional ownership, or insider trading activity. One holder_type per call: call again to get a different view.
1338
1224
 
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
1225
+ Returns Markdown by default, or JSON when response_format='json'. Missing data for the chosen category returns a short message.
1350
1226
  """
1351
1227
  ticker = _norm_ticker(ticker)
1352
1228
  try:
@@ -1418,23 +1294,11 @@ async def get_dividends_splits(
1418
1294
  ),
1419
1295
  ] = ResponseFormat.MARKDOWN,
1420
1296
  ) -> 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'.
1297
+ """Full dividend payment history (with a trailing-period summary) and the stock-split history for one stock.
1431
1298
 
1432
- Returns:
1433
- str: Dividend history and split history with a short summary.
1299
+ Use for dividend-income analysis, payment dates and amounts, dividend growth, or past split events. For the current/forward dividend yield use get_stock_quote; for price history use get_historical_prices.
1434
1300
 
1435
- Example:
1436
- Input: {"ticker": "KO"}
1437
- Output: Coca-Cola's dividend payments and any stock splits
1301
+ Returns Markdown by default, or JSON when response_format='json'. A stock that pays no dividend or has never split returns a short message noting that none exist.
1438
1302
  """
1439
1303
  ticker = _norm_ticker(ticker)
1440
1304
  try:
@@ -1530,28 +1394,11 @@ async def get_analyst_estimates(
1530
1394
  ),
1531
1395
  ] = ResponseFormat.MARKDOWN,
1532
1396
  ) -> str:
1533
- """Get forward-looking analyst estimates: price targets, EPS/revenue estimates, and growth.
1397
+ """Forward-looking analyst estimates for one stock: price targets, EPS and revenue estimates by period (current and next quarter and year), and growth estimates.
1534
1398
 
1535
- This complements get_analyst_recommendations (which covers ratings/trend) with
1536
- the forward numbers analysts project.
1399
+ Use for projected/expected numbers and forecasts. This complements get_analyst_recommendations: that tool returns ratings and the recommendation trend, this one returns the numeric forward estimates.
1537
1400
 
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
1401
+ Returns Markdown by default, or JSON when response_format='json'. A stock without analyst coverage returns the available fields as N/A or a short message.
1555
1402
  """
1556
1403
  ticker = _norm_ticker(ticker)
1557
1404
  try:
@@ -1655,24 +1502,11 @@ async def search_symbols(
1655
1502
  ),
1656
1503
  ] = ResponseFormat.MARKDOWN,
1657
1504
  ) -> 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
1505
+ """Resolve a company name or keyword to ticker symbols; each match returns the symbol, name, exchange, and instrument type (equity, ETF, and so on).
1664
1506
 
1665
- Args:
1666
- query: Company name or keyword.
1667
- count: Max matches to return (1-20).
1668
- response_format: 'markdown' or 'json'.
1507
+ Use this first when you have a company or brand name but not its ticker, then pass the resolved symbol to the other tools. Not for fetching prices or fundamentals.
1669
1508
 
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
1509
+ query is the name/keyword to search; count caps the number of matches (1-20, default 8). Returns Markdown by default, or JSON when response_format='json'. No matches returns a short message.
1676
1510
  """
1677
1511
  query = query.strip()
1678
1512
  try:
@@ -1749,22 +1583,11 @@ async def get_market_status(
1749
1583
  ),
1750
1584
  ] = ResponseFormat.MARKDOWN,
1751
1585
  ) -> 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'.
1586
+ """Whether a stock market is currently open or closed for a given region, with trading-session timing and a summary of that region's major indices.
1761
1587
 
1762
- Returns:
1763
- str: Market open/closed status with timing, plus major index levels.
1588
+ Use for "is the US market open", market hours, or a quick index overview. region is a country code (US, GB, CA, DE, FR, IN, JP, HK, AU; default US). This is market-wide, not per-stock: use get_stock_quote for an individual price.
1764
1589
 
1765
- Example:
1766
- Input: {"region": "US"}
1767
- Output: U.S. markets status, close time, and S&P/Dow/Nasdaq summary
1590
+ Returns Markdown by default, or JSON when response_format='json'. An unrecognized region returns a short message.
1768
1591
  """
1769
1592
  region = region.strip().upper()
1770
1593
  try: