Tools
The MCP server exposes 13 read-only tools across two layers:
- Event-level: clustered and analyzed. Carries divergence, market relevance, market sentiment, fact ledger, per-outlet framing.
- Article-level: individual articles tagged with ~720 ticker symbols and 47 topics. Pre-clustering, so duplicates from different outlets are expected. Broader ticker coverage than event-level.
All tools return JSON strings. Empty results return {"results": [], "count": 0, "message": "..."} rather than an error.
get_digest
Zero-parameter morning briefing. The right starting point for any session.
get_digest()
Returns a 24-hour summary: top market events, sentiment breakdown, most contested stories, category counts, and top tickers. No parameters needed.
Response fields
| Field | Type | Description |
|---|---|---|
generated_at | ISO 8601 | When the digest was built |
window_hours | int | Always 24 |
market_summary.total_events | int | All events in the window |
market_summary.market_events | int | Events with market_relevance_score ≥ 70 |
market_summary.sentiment | object | {bullish, bearish, neutral} counts |
market_summary.top_tickers | list | Most-mentioned tickers, up to 10 |
top_market_events | list | Up to 5 events sorted by market relevance |
most_contested | list | Up to 5 events sorted by divergence score |
categories | object | Event count by category |
get_market_news
Recent events with material market relevance.
get_market_news(limit=10, hours=24, min_score=70)
Parameters
| Name | Type | Default | Notes |
|---|---|---|---|
limit | int | 10 | 1 to 25 |
hours | int | 24 | Lookback window. Max 168 (7 days) |
min_score | int | 70 | Minimum market_relevance_score. Use 50 for broader results, 85+ for high-impact only |
get_market_articles
Article-level market desk items. Pre-clustering, so duplicates from different outlets covering the same story are expected.
get_market_articles(tag="", tags="", outlet="", hours=168, limit=25, offset=0)
Two filter modes:
tag- single exact tag, e.g."ticker:NVDA"or"topic:fed".tags- comma-separated tags, all must match (intersection), e.g."ticker:LLY,topic:fda"for Eli Lilly FDA articles only.
Tag taxonomy
ticker:<SYMBOL> - ~720 names: equities and ETFs. Use get_market_tags(tag_type="ticker") to discover what's active.
topic:<NAME> - 47 topics:
| Group | Topics |
|---|---|
| Central banks | fed, ecb, boe, boj |
| Macro / data | rates, inflation, cpi, ppi, gdp, jobs, recession, confidence, retail |
| Markets / instruments | indices, treasuries, bonds, credit, pe_vc, fx |
| Corporate | earnings, guidance, ipo, m&a, layoffs, dividend, bankruptcy |
| Trade / policy | trade, sanctions, antitrust, regulation, litigation |
| Healthcare | fda |
| Management | management, labor |
| Tech / cyber | ai, cyber |
| Multilateral | imf, rating |
| Corporate events | contract, split, offering |
| Crypto / commodities | crypto, oil, gold, commodities |
| Catch-all | markets, analyst |
Parameters
| Name | Type | Default | Notes |
|---|---|---|---|
tag | string | - | Single exact tag. Ignored if tags is provided |
tags | string | - | Comma-separated AND-filter |
outlet | string | - | Exact outlet name |
hours | int | 168 | Lookback. Max 336 (14 days) |
limit | int | 25 | 1 to 50 |
offset | int | 0 | Pagination offset |
Response fields
| Field | Description |
|---|---|
results | Article rows with id, headline, outlet, url, image_url, published_at, fetched_at, sentiment, bias_label, tickers, topics, tags |
count | Number of rows returned |
tag | Single-tag filter used (if any) |
tags | Multi-tag filter used (if any) |
outlet, offset, limit | Echo of inputs |
get_market_tags
Most common market classifier tags in recent article-level data.
get_market_tags(hours=168, limit=50, tag_type="all")
Use this before get_market_articles to discover active ticker and topic tags, or to build a current "hot tickers" or "hot topics" scan.
Parameters
| Name | Type | Default | Notes |
|---|---|---|---|
hours | int | 168 | Lookback. Max 336 (14 days) |
limit | int | 50 | 1 to 200 |
tag_type | enum | all | ticker, topic, or all |
Response fields
| Field | Description |
|---|---|
results | Tag rows with tag and count, sorted by count descending |
count | Number of tag rows returned |
window_hours | Echo of input |
tag_type | Echo of input |
get_ticker_news
Event-level lookup for a specific ticker (last 30 days).
get_ticker_news(ticker)
Returns clustered events with divergence and sentiment for a given ticker. If empty, try get_ticker_articles for article-level coverage, which has broader ticker recognition including smaller-cap and foreign issuers.
Parameters
| Name | Type | Notes |
|---|---|---|
ticker | string | Required. Case-insensitive. No $ prefix. |
get_ticker_articles
Article-level lookup for a specific ticker. Wider coverage than get_ticker_news: ~720 names including foreign issuers (SFTBY, BAYRY, NU), small caps (TEM, RXRX), and ETFs (SPY, XBI, IBIT).
get_ticker_articles(ticker, hours=168, limit=25)
Parameters
| Name | Type | Default | Notes |
|---|---|---|---|
ticker | string | required | Case-insensitive. No $ prefix |
hours | int | 168 | Lookback. Max 336 (14 days) |
limit | int | 25 | 1 to 50 |
get_trending_tickers
Surfaces tickers with disproportionate recent mention activity compared to a baseline window. Unlike get_market_tags (ranked by volume), this ranks by acceleration.
Returns ratio = recent_per_hour / baseline_per_hour. Ratios above 3 indicate a story is breaking around the name; above 6 indicates a major event.
get_trending_tickers(hours=24, baseline_hours=168, limit=10, min_recent_mentions=2)
Parameters
| Name | Type | Default | Notes |
|---|---|---|---|
hours | int | 24 | Recent window |
baseline_hours | int | 168 | Baseline window. Must be larger than hours |
limit | int | 10 | 1 to 25 |
min_recent_mentions | int | 2 | Excludes one-off mentions |
Response fields per row
| Field | Description |
|---|---|
ticker | Symbol |
recent_mentions | Mention count in hours window |
baseline_mentions | Mention count in baseline_hours window |
ratio | recent rate / baseline rate, rounded to 2 decimals |
scan_portfolio
Batch ticker check. Returns hits, no-news tickers, and an aggregate sentiment breakdown.
scan_portfolio(tickers, hours=24, include_articles=False)
Parameters
| Name | Type | Default | Notes |
|---|---|---|---|
tickers | string | required | Comma-separated. E.g. "NVDA,AAPL,MSFT". Max 20, excess silently dropped |
hours | int | 24 | Lookback. Max 168 (events) / 336 (articles) |
include_articles | bool | false | Also surface per-ticker article-level hits, which cover foreign and smaller-cap names that event-level may miss |
Response fields
| Field | Description |
|---|---|
hits | Tickers with at least one event, each with a list of matching events |
no_news | Tickers with no events (and no articles, when include_articles=true) in the window |
tickers_checked | Echo of inputs (capped) |
overall_sentiment | {bullish, bearish, neutral} counts across all hits |
article_hits | Present when include_articles=true. Per-ticker article-level matches (up to 10 each) |
get_market_sentiment_overview
Aggregate bullish/bearish breakdown for the market as a whole.
get_market_sentiment_overview(hours=48, min_score=70)
Parameters
| Name | Type | Default | Notes |
|---|---|---|---|
hours | int | 48 | Lookback. Max 168 |
min_score | int | 70 | Minimum market_relevance_score to include |
Response fields
| Field | Description |
|---|---|
window_hours | Echo of input |
total_market_events | Events meeting the score threshold |
sentiment_breakdown | {bullish, bearish, neutral} counts |
top_tickers | Most-mentioned tickers in market events |
most_divergent | Up to 5 highest-divergence market events |
query_news
Power query. Combine any filters in a single call.
query_news(tickers="", sentiment="", category="", min_divergence=0,
max_divergence=100, min_market_score=0, hours=24,
sort="recent", limit=10)
Parameters
| Name | Type | Default | Notes |
|---|---|---|---|
tickers | string | - | Comma-separated ticker symbols |
sentiment | enum | - | bullish, bearish, neutral |
category | enum | - | war, economy, politics, ai, health, other |
min_divergence | int | 0 | 0 to 100 |
max_divergence | int | 100 | 0 to 100 |
min_market_score | int | 0 | Minimum market_relevance_score |
hours | int | 24 | Lookback. Max 168 |
sort | enum | recent | recent, divergence, market |
limit | int | 10 | 1 to 25 |
get_top_divergent
Most editorially contested stories, sorted by divergence score.
get_top_divergent(category="", hours=24, limit=10)
Returns events sorted by divergence_score descending. Each result includes a takeaway sentence summarising the editorial split. Use get_event for the full per-outlet breakdown.
Parameters
| Name | Type | Default | Notes |
|---|---|---|---|
category | enum | - | war, economy, politics, ai, health, other. Empty = all |
hours | int | 24 | Lookback. Max 168 |
limit | int | 10 | 1 to 25 |
search_news
Keyword search across event titles and summaries.
search_news(query, category="", sentiment="", min_divergence=0, limit=10)
Case-insensitive substring match. Does not search raw article text.
Parameters
| Name | Type | Default | Notes |
|---|---|---|---|
query | string | required | Matched against title and event_summary |
category | enum | - | war, economy, politics, ai, health, other |
sentiment | enum | - | bullish, bearish, neutral |
min_divergence | int | 0 | 0 to 100 |
limit | int | 10 | 1 to 25 |
get_event
Full event detail: sources, facts, takeaway, and article count.
get_event(event_id)
Parameters
| Name | Type | Notes |
|---|---|---|
event_id | int | From the id field on any other tool result |
Response fields
| Field | Description |
|---|---|
id | Event ID |
title | Event title |
summary | 2–3 sentence factual summary |
takeaway | Summary of how outlet coverage diverges on this event |
category | war, economy, politics, ai, health, other |
divergence_score | 0–100. See Divergence score |
market_relevance_score | 0–100, or null |
market_sentiment | bullish, bearish, neutral, or null |
market_relevance_reason | Why this event is market-relevant, or null |
tickers | Stock ticker symbols extracted from coverage |
companies | Company names mentioned |
sources | Per-outlet: outlet, headline, framing_label, framing_color |
facts | Per-fact: status (confirmed/disputed), text, source_attribution |
article_count | Articles clustered into this event |
Returns {"error": "not_found"} if the event ID does not exist or the event was rejected during analysis.