A plan is saved the moment a material event publishes for a symbol (eps_update,
eps_release, 8k_release, financials_release, ir_publication, transcript_update) and
nightly for company_update. This tool is the INVENTORY of those plans — it does not
build or return a report. Returns `plans`, newest plan first:
{"plans": [{"symbol": "NVDA", "event_type": "eps_release",
"planned_at": "<iso>", # when the plan was built
"queued_at": "<iso>", # the report inputs (the event) it was built from
"fresh": true, # see below
"source": "redis"}, ...]} # redis = built within 3 days, s3 = older durable copy
`fresh` applies the SAME rule get_latest_report (/get-cached-reports) applies:
fresh: true -> get_latest_report([ticker]) renders this plan into the user's
template in ~10-20 s (it comes back under `rendering`). These are
the names to pull.
fresh: false -> a newer event landed after the plan; get_latest_report returns the
stale cached PDF, and only generate_report_for_stock(ticker) — a full
rebuild, ~10 min — refreshes it. Say so before the user waits on it.
not listed -> no plan IN THE WINDOW. An empty result does not mean there is no
research — it means nothing was planned in the window. Widen
`report_date` before concluding a symbol has no plan; only then is
a first build a full ~10 min run (or `onboard_symbol` if the ticker
is not covered).
TWO WAYS IN:
1) Event-first — list_realtime_events(event_type=...) shows what just published; call
this with event_types=[<that type>] to confirm which of those symbols have a plan
and which are fresh, then get_latest_report(symbols=[...]) for the ones the user
wants. (An event in the 12h cache with no plan here means the plan is still being
built — check again in a minute.)
2) Research-first — skip the events step: call this with no filter for every symbol
planned TODAY, grouped by the event that triggered it. Plans stay renderable for 7
days, so pass report_date="YYYY-MM-DD" (e.g. 3 days back) when the user wants the
running inventory rather than today's, or when today's list comes back thin.
PICKING THE MOST PERTINENT PLANS ("pull the most relevant reports today", "what's worth
reading right now"): the list is an inventory, not a ranking — a nightly company_update
plan sits next to a transcript that just landed. Rank by the EVENT, not by the plan:
a) FILTER on what published — list_realtime_events for the material types
(transcript_update, 8k_release, ir_publication, eps_release / eps_update,
financials_release) and for the tape (biggest_mover, biggest_loser,
biggest_gainer). A symbol on BOTH lists — a filing or call AND a move — is
the strongest candidate.
b) ANALYZE the content — read the event payloads (what the 8-K discloses, what the
call said, what the deck guides to) and keep the ones that change something;
`situate(question=...)` and get_event_ontology say what each type means.
c) CONFIRM with intraday price action — detect_intraday_outlier_jumps(tickers=[...])
(and get_aftermarket_data after the close) shows whether the market treated it
as significant; a print with no reaction ranks below a mover with a filing.
d) MATCH to plans — call this tool with event_types=[<the types from a>] and keep
the candidates that appear, preferring `fresh: true`; `queued_at` should be the
event you just read.
e) PULL the winners — get_latest_report(symbols=[...]) for the few that survived,
not the whole list: the fresh ones render in seconds; a stale one comes back as
its cached PDF. Tell the user which is which, and offer generate_report_for_stock
rebuilds (~10 min each) only if they want to wait.
Not `get_latest_report`: that PULLS the reports for named tickers (renders the fresh
plans, serves the cached PDF for the rest). This tool answers "for which symbols could
I get a fresh report?" — by event, across the universe — before anything is pulled. Not
`generate_research_report`: that is the broad, topical, or multi-company writeup;
the plans listed here are single-symbol, event-anchored reports.
Synchronous, cheap (500/hour). Requires auth (your MCP client attaches the OAuth
bearer automatically).