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 -> the report get_latest_report([ticker]) returns was written from
this plan and reflects the latest event. These are the names to pull.
fresh: false -> a newer event landed after the plan. Its own report may still be in
progress (minutes); otherwise get_latest_report returns the older PDF
flagged stale, and generate_report_for_stock(ticker) writes a new
note in a few minutes. 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 generate_report_for_stock note (a few minutes) the answer
(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 listed 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;
get_event_ontology(event_type=...) says 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: every one comes back in seconds, flagged fresh or stale.
Tell the user which is which, and offer generate_report_for_stock (a few minutes
each) only if they want to wait.
Not `get_latest_report`: that PULLS the reports for named tickers (each one's latest
document). 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).