Flexreport Finance
Server Details
An mcp dedicated to real-time streaming of financial market and research, giving ai agents a pulse on the markets.
- Status
- Healthy
- OAuth
- Works in Glama
- Last Tested
- Transport
- Streamable HTTP · MCP 2025-11-25
- URL
TDQS
Scored across 50 tools
Several clusters overlap heavily: reports (get_latest_report / generate_report_for_stock / generate_research_report), data access (explore_data_catalogue / explore_data_coverage / run_saved_query / get_signed_sql_drilldown), and event streaming (stream_events / stream_event_subscription / register_event_subscription). The descriptions explicitly route between them and warn about misuse, so an attentive agent can mostly tell them apart, but the boundaries require careful reading rather than being self-evident.
Nearly all tools use snake_case with a verb_noun pattern (list_options, get_latest_report, delete_saved_query, save_user_template), which is highly predictable. Minor deviations like the single-verb 'situate' and the question-form 'is_market_open' keep it from perfect consistency, but the convention is clear and readable.
At 50 tools this is far above the 3-15 ideal, and several near-duplicates inflate the count (optimize_portfolio vs optimize_portfolio_default, stream_events vs stream_event_subscription, multiple template lifecycle tools). The broad finance-platform scope explains some breadth, but the set feels heavy and could be consolidated.
Lifecycle coverage is strong across saved queries (list/save/run/delete), templates (get/draft/save/update/delete), scheduled tasks (schedule/list/delete), reports, events, and portfolio strategies. Minor gaps remain — no list endpoint for event subscriptions (acknowledged in the description) and no direct update for scheduled tasks beyond upsert via schedule_task — but agents can work around them.
Available Tools
50 toolsdelete_event_subscriptionADestructiveIdempotentInspect
Remove a saved event subscription (DELETE /event-subscription/{subscription_id}).
Returns {"status": "DELETED", "subscription_id": ...}; any stream still open on it
ends with a `closed` frame within one read cycle (<= 8 s). 404 `unknown
subscription_id` for a missing id or another user's id. Registrations are
rate-limited (30/hour), so delete subscriptions the user is done with rather than
registering fresh ones for every session.
Requires auth (your MCP client attaches the OAuth bearer automatically).
| Name | Required | Description | Default |
|---|---|---|---|
| subscription_id | Yes | The `subscription_id` returned by register_event_subscription. |
Output Schema
| Name | Required | Description |
|---|---|---|
| status | Yes | "DELETED". |
| subscription_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations: exact return payload ({"status": "DELETED", ...}), the side effect that open streams receive a `closed` frame within one read cycle (<= 8 s), the 404 unknown subscription_id behavior (including another user's id), rate limits, and the OAuth requirement. The idempotent/destructive hints are confirmed rather than repeated.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the operation and endpoint, then layers return shape, streaming side effect, error case, rate-limit rationale, and auth in compact sentences. Slightly dense with parentheticals, but every sentence carries decision-relevant information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers the full call surface: auth requirement, error semantics, post-delete streaming consequence, and the rate-limit context that motivates using this tool at all. With an output schema present it need not describe returns further, yet its extra detail is accurate and helpful rather than redundant.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, and the schema already ties subscription_id back to register_event_subscription's return value. The description restates the identifier but adds no format, syntax, or lookup detail beyond the schema, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Remove a saved event subscription') and even names the HTTP route, so there is no ambiguity about the operation. It does not explicitly name or contrast itself with siblings like register_event_subscription or stream_event_subscription, so it falls short of the top tier that requires sibling differentiation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives genuine operating guidance: because registrations are rate-limited (30/hour), the agent should delete subscriptions the user is done with rather than re-registering each session. This implies the when-to-use context clearly, though it does not name an alternative tool explicitly or state hard exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_saved_queryADestructiveIdempotentInspect
Delete one of your saved data requests by id.
Deletion is permanent and touches no data, but the query
tokens go with the row and cannot be reconstructed: re-creating it means running
`explore_data_catalogue` again and re-saving. When more than one row looks like a
match, confirm WHICH one with the user before calling.
Ownership is enforced server-side. A 404 ("No saved query with id N") means the id
does not exist OR is not yours — the backend deliberately does not distinguish the
two, so never tell the user the row belongs to someone else.
Returns {"msg": "Deleted saved query <id>"}.
Requires auth (your MCP client attaches the OAuth bearer automatically).
Rate-limited 100/min.
| Name | Required | Description | Default |
|---|---|---|---|
| query_id | Yes | The row's `id` from list_saved_queries — not a list position, not the user_request. |
Output Schema
| Name | Required | Description |
|---|---|---|
| msg | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations: it discloses that deletion is permanent and that query tokens are destroyed and cannot be reconstructed, explains that a 404 deliberately conflates 'does not exist' with 'not yours' so the agent must not leak ownership, documents the return payload, auth requirements, and a 100/min rate limit. This is exactly the behavioral context annotations cannot carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the action and keeps each sentence purposeful (destructiveness, ambiguity handling, 404 semantics, auth/rate limits). The explicit return-value line is somewhat redundant since an output schema exists, which keeps it from a 5.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter destructive tool with annotations and an output schema, the description covers everything an agent needs: safety profile, idempotency implications, failure semantics, prerequisites, and rate limits. No gaps remain.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the schema itself already clarifies that query_id is the row id from list_saved_queries, not a list position or user_request. The prose adds only the phrase 'by id', so it does not meaningfully extend the schema — baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Delete one of your saved data requests by id') and scopes it to the user's own saved queries, distinguishing it from siblings like list_saved_queries, run_saved_query, and save_user_query. An agent can identify the operation without inspecting the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a concrete precondition for invocation ('when more than one row looks like a match, confirm WHICH one with the user') and describes the recovery path for an accidental deletion (re-run explore_data_catalogue and re-save). It does not explicitly name list_saved_queries as the id source in prose (that lives in the schema), so it falls just short of naming alternatives outright.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_scheduled_taskADestructiveIdempotentInspect
Delete a scheduled task (cron job) by its name.
For workflow schedules `task_name` is the value `schedule_task` returned as
`task_name`. Deleting removes only
the cron schedule; the saved workflow definition is kept and can be
re-scheduled by re-saving it via `schedule_task`. Returns
{"msg": "<task_name> deleted"} on success, or an error if no such task exists.
| Name | Required | Description | Default |
|---|---|---|---|
| task_name | Yes | The task `name` from list_scheduled_tasks — for workflows the full "wf:{email}:{workflow-name}", NOT the bare workflow name. |
Output Schema
| Name | Required | Description |
|---|---|---|
| msg | Yes | "<task_name> deleted". |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and idempotentHint=true, but the description goes well beyond them: it specifies that only the cron schedule is removed while the saved workflow definition survives, gives the recovery path (re-save via `schedule_task`), and documents success/error return behavior. For a destructive tool, disclosing the exact scope of destruction and what is preserved is exactly the added value needed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded in the first sentence and the body earns its place with scope and return details. The phrasing around workflow schedules ('the value `schedule_task` returned as `task_name`') is slightly convoluted and could be tightened, but nothing is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers purpose, name-source convention, blast radius, recovery path, and return/error behavior, and an output schema exists for the response shape. Nothing an agent needs to call this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds cross-tool semantics the schema alone does not: for workflow schedules `task_name` is the value returned by `schedule_task` as `task_name`. This resolves real ambiguity about which identifier to pass.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (Delete) and resource (scheduled task / cron job) plus the identifier used to select it. It is immediately distinguishable from the many sibling delete_* tools (delete_event_subscription, delete_saved_query, delete_user_template) because the resource is named explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Clarifies the key selection consideration for workflow schedules and frames the operation as removable/re-creatable via `schedule_task`, which is genuinely useful routing context. It does not, however, state any explicit when-not-to-use condition or prerequisites (e.g. permissions, effect on running jobs).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_user_templateADestructiveIdempotentInspect
Delete the user's saved PDF template so their PDFs go back to the standard layouts.
Permanent and there is no history: re-creating the format means drafting and
saving again. Confirm with the user before calling. Ownership is enforced
server-side, so only the caller's own template can be removed.
Returns {"msg": "Template deleted. Your PDFs will use the standard layouts."}.
A 404 means there was nothing saved to delete.
Requires auth (your MCP client attaches the OAuth bearer automatically).
Rate-limited 100/min.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| msg | Yes | Confirmation message. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and idempotentHint=true, but the description adds substantially more: permanence with no history, server-side ownership enforcement limiting it to the caller's own template, the exact success payload, 404 semantics, OAuth auth requirement, and a 100/min rate limit. No claims conflict with the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded and well-paragraphed with each sentence carrying weight, but the explicit return-value sentence is partially duplicative given a structured output schema already exists.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-param destructive mutation, the description covers safety, reversibility, ownership, auth, rate limits and error behavior; an agent has everything needed to decide and invoke correctly, and return values are reinforced by the output schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so the baseline is 4; there is no argument meaning to convey and the description correctly avoids inventing any.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource (delete the user's saved PDF template) plus the consequence (PDFs revert to standard layouts), which cleanly separates it from draft_user_template, save_user_template, update_user_template and get_user_template.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit prerequisite ('Confirm with the user before calling') and a useful negative condition ('A 404 means there was nothing saved to delete'), and the 're-creating the format means drafting and saving again' line implicitly points at the sibling tools for the alternative path. It never names an alternative tool outright, so it stops short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
detect_intraday_outlier_jumpsARead-onlyInspect
Live look at TODAY's intraday tape, flagging outlier price jumps.
Pulls today's intraday bars for `symbol` (US/Eastern trading day) live at the given
`frequency` and flags each bar whose move is a statistical outlier versus the stock's
own daily-return volatility — i.e. bars where |z-score| of the move exceeds
`zscore_threshold`. Use it for a quick "is the stock making an abnormal intraday move
right now?" read.
Synchronous — returns the flagged bars directly (no task id to poll). Returns a
404-style error if no intraday data is available yet (e.g. before the market opens or
for an uncovered symbol).
Requires auth (your MCP client attaches the OAuth bearer automatically).
| Name | Required | Description | Default |
|---|---|---|---|
| symbol | Yes | Covered ticker, e.g. "AAPL". | |
| frequency | No | Intraday bar size; list_options(kind="intraday_frequency") lists the supported values. | one_minute |
| zscore_threshold | No | Daily-sigma cutoff for flagging a bar: higher = stricter (fewer, more extreme flags), lower = more sensitive. |
Output Schema
| Name | Required | Description |
|---|---|---|
| latest | No | The most recent bar. |
| series | Yes | Every bar today, ascending by time. |
| symbol | Yes | |
| outliers | Yes | Bars with |z-score| >= zscore_threshold. |
| prior_close | No | Prior session's close, the return baseline. |
| most_extreme | No | Today's bar with the largest |z-score|. |
| daily_std_20d | No | Std dev of the trailing 20 daily log returns (the sigma). |
| daily_mean_20d | No | Mean of the trailing 20 daily log returns. |
| is_outlier_now | Yes | True when the latest bar is beyond the threshold. |
| zscore_threshold | Yes | The |z| cutoff applied. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the readOnlyHint annotation: synchronous execution with no task id to poll, direct return of flagged bars, a 404-style error when no intraday data exists yet, and automatic OAuth bearer attachment. These are exactly the operational facts an agent needs before calling.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the live-today purpose, then mechanics, then error/auth notes. Every sentence carries information, though it runs slightly long for three parameters.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be described; the description nonetheless covers the synchronous contract, the failure mode, and auth. Nothing an agent needs to invoke this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is already 100%, so the baseline is 3, but the description adds real meaning: moves are scored against the stock's own daily-return volatility, the day is US/Eastern, and frequency is defined as the intraday bar size. Z-score semantics are clarified beyond the schema's terse 'Daily-sigma cutoff'.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource+scope: pulls TODAY's live intraday bars for a symbol and flags bars whose |z-score| exceeds a threshold. It is clearly distinguishable from siblings like get_technical_indicator_data, get_aftermarket_data, and get_company_snapshot.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a clear usage context ('quick is the stock making an abnormal intraday move right now? read') and implicitly scopes to live/today rather than historical analysis. It does not, however, name a sibling alternative or state when NOT to use it (e.g. after-hours vs. get_aftermarket_data).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
download_pdf_from_urlARead-onlyInspect
Fetch a presigned S3 PDF URL server-side and return the document as base64.
Use this to pull the actual PDF bytes for a presigned S3 link — e.g. the `url`
returned by `get_latest_report` — on clients that can't open the link directly and
need the document inline. The backend fetches the URL for you (clients never have
to reach S3) and streams the PDF back. Only S3 URLs are accepted: the host must end
in "amazonaws.com" and contain "s3"; any other host is rejected with a 400 (SSRF
guard). NOTE: if you already have `get_latest_report`'s `report` field (the same PDF
inline as base64), use that directly — there's no need to call this.
Returns {"file_name": ..., "media_type": "application/pdf", "report": "<base64 pdf>"}
— decode `report` to read, render, or save the PDF.
Requires auth (your MCP client attaches the OAuth bearer automatically).
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | Presigned S3 link, e.g. get_latest_report's `url`. The host must end in "amazonaws.com" and contain "s3" (anything else is a 400). | |
| file_name | Yes | Download filename to label the document, e.g. "AAPL.pdf". |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=true, but the description adds substantial behavior: the fetch happens server-side, only S3 hosts ending in amazonaws.com are accepted, other hosts get a 400 (SSRF guard), and OAuth auth is attached automatically. This is meaningful disclosure well beyond the annotation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action and return type, then layers the SSRF guard, alternative routing, and auth note. All sentences earn their place, though there is mild redundancy with the schema's own url description.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 2-parameter tool with no output schema, the description fully specifies the return shape ({file_name, media_type, report} as base64), the auth model, and the rejection behavior. Nothing an agent needs to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so both parameters are already documented, and the description largely restates the url constraint (presigned S3, amazonaws.com) that the schema already carries. The baseline 3 applies since the schema does the heavy lifting and the description adds little new parameter syntax.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (fetch/download) and resource (presigned S3 PDF URL), and describes the return (base64 document). It explicitly distinguishes itself from the sibling get_latest_report, so an agent can tell them apart without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-to-use (clients that can't open the link directly and need the document inline) and, rarer still, an explicit when-not-to (if you already have get_latest_report's report field, use it directly). It names the alternative and the condition selecting it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
draft_user_templateAInspect
Render preview images of a user's PDF template so they can approve it BY LOOKING, before anything is saved.
THE POINT: a user wants their research in THEIR format — their masthead, colours,
layout, branding. A saved template is a BLUEPRINT: the author's stylesheet and
page chrome plus one markup pattern per content kind, which the backend applies
automatically to every PDF it renders for that user. A template is a visual
choice, so it is signed off by looking at rendered pages, never by describing
them. This is STEP 1 OF 2: it compiles the submitted HTML into a blueprint under
several treatments and renders each one as PNG previews of the platform's
SPECIMEN DOCUMENT — one of every content kind (title, lead, sections, bullets,
KPI cards, tables, charts, figure, source line, footnote). The user signs off on
how the design treats each kind of content, not on sample text. NOTHING IS
STORED — the draft lives in a 24-hour cache; `save_user_template` is step 2.
THE FLOW:
1. Author the HTML with the user (or take the page they hand you).
2. Call this, then poll `get_task_status(task_id)` until SUCCESS. Show the user
EVERY variant's `preview_urls` (render the images
inline where the client can; otherwise give the links) with its `name` and
`rationale`, side by side.
3. The user picks one -> `save_user_template(draft_id, variant_id)`. Never save
a treatment the user has not seen and approved. Later changes go through
`update_user_template`.
`template_type`:
- "add_on" — the previews are rendered at the 360pt column width the block
will occupy inside a report — anything wider is clipped, not scaled — and
the treatments restyle it to sit inside the host document (its own page
background, masthead and disclaimer are stripped).
- "bespoke" — the template drives the whole document: page chrome, stylesheet
and the pattern for every content kind, previewed as full pages.
TEMPLATE RULES (violations come back as a 422 with `detail.errors`):
- Real CSS engine: grid, flexbox, gradients, absolute positioning all work.
Add `break-inside: avoid` to a panel that must not split across pages.
- Only `data:` URIs for images. External images, stylesheets and web fonts are
BLOCKED; <script>, <link> and similar are stripped.
- HTML only, max 200 KB; must parse as HTML.
Asynchronous: returns {"task_id", "status": "PENDING", "next_step"}. Poll
`get_task_status(task_id)`; the finished result is {"draft_id", "variants":
[{"variant_id", "name", "rationale", "preview_urls": [...], "preview_pages"}],
"expires_in_seconds", "next_step", "warnings"} (or {"error", "warnings"} when the
draft failed). `preview_urls` are time-limited presigned PNG links, one per page.
Read `warnings`: a treatment that "changed too much" was dropped, and an empty
variant list means no usable adaptation survived — revise the template rather
than retrying the same one.
Runs a model pass plus a render per treatment, so expect minutes. Requires auth
(your MCP client attaches the OAuth bearer automatically). Rate-limited 30/min.
| Name | Required | Description | Default |
|---|---|---|---|
| anchor | No | REQUIRED for add_on: the section it applies to, matched as a substring against the document's block keys (e.g. "technical", "financials", "ownership"). Omit for bespoke. | |
| template | Yes | The template as a complete HTML page in the intended style (max 200 KB; markdown is a 422). Its sample content is discarded at save — only structure and styling are kept. | |
| template_type | Yes | "add_on" restyles ONE section of the standard report and keeps the rest; "bespoke" drives the whole document. |
Output Schema
| Name | Required | Description |
|---|---|---|
| status | Yes | Task state at dispatch, normally "PENDING". |
| changed | No | update_user_template only: the fields that were updated. |
| task_id | Yes | Celery task id; poll it with get_task_status for the result. |
| next_step | No | What the finished task returns. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=false and destructiveHint=false; the description adds far more: nothing is persisted (24h cache), async with PENDING task_id and polling, minutes of latency from a model pass plus per-treatment render, OAuth auth, 30/min rate limit, 422 error shape via detail.errors, and the meaning of warnings/empty variant lists. No contradiction with the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded and organized with THE POINT / THE FLOW / TEMPLATE RULES headings, and nearly every sentence carries operational weight. It is on the long side, and the finished-result JSON shape partly duplicates the existing output schema, but the density is justified by the tool's complexity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers everything an agent needs for a complex, async, multi-step tool: the two-step workflow, polling requirement, template constraints, error and warning semantics, auth and rate limits, and the type-specific rendering behavior. Output schema exists, so return values are not the description's burden, yet the warnings interpretation is still supplied.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is already 100%, but the description still adds real meaning: it explains the visual consequence of template_type ('add_on' renders at the 360pt column and clips rather than scales, stripping the host page chrome; 'bespoke' previews full pages), restates the anchor substring-matching requirement, and notes the 200KB/markdown-422 constraint on template.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource+outcome: renders PNG previews of a user's PDF template so it can be approved visually before saving. It explicitly positions itself as 'STEP 1 OF 2' and names save_user_template as step 2, so an agent can distinguish it from the sibling save/update/get template tools without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit numbered flow (author HTML -> call this -> poll get_task_status -> user picks -> save_user_template), names the alternatives (save_user_template, update_user_template, get_task_status) and the condition that selects each, and states an exclusion: never save a treatment the user has not seen.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
explore_data_catalogueAInspect
Explore Flexreport's data platform with an OPEN-ENDED question — designed to handle many research based or open ended questions, enabling interactive EDA.
===> BEFORE running this, call `list_saved_queries` and match the question against
the saved rows — on each row's `metadata` (`summary`, `parameters`, `datasets`),
not on the `user_request` label, skipping any row marked `stale`. A row of the
same SHAPE — same metric, same window, only the company / filer / date / count
differs (saved: "the past 8 quarters of sales for TGT"; asked now: "KSS's last 8
quarters of sales") — is answered by `run_saved_query(query_tokens=<that row's
query_placeholder>, values={...}, max_rows=500)` in seconds, the values keyed by
`metadata.parameters`: the backend re-aims the saved queries at the new entities,
no planning job, no draw on the 20/hour budget. An EXACT repeat replays the row's
`queries` tokens as saved. Only when nothing saved fits, or the replay answers 422
(the request could not be mapped onto the saved slots), run this tool.
===> AFTER the exploration completes and the results are shown, offer ONCE to save
it with `save_user_query`: tell the user the request can then be re-run exactly
(same queries, live data) OR re-asked for other companies, filers, or windows in
seconds. Offer when the exploring is done, not mid-iteration, and never save by
reflex.
===> For anything EVENT-DRIVEN (a print, a filing, a 13F move, news, "what
happened"), call `situate(...)` first and take this tool's `query` from its plan —
the plan names the relations that HAVE refreshed since the event and omits the
ones that have not. Otherwise:
===> THE DEFAULT, FIRST-STEP tool whenever the user wants to EXPLORE the data or
understand a topic from the data (e.g. "use Flexreport to explore...", "how are
small caps doing — explore the data", "how have semiconductor margins trended?").
It validates the request, plans queries against the data catalogue, runs them, and
returns the raw result sets to render as INTERACTIVE CHARTS AND TABLES on the
dashboard. Coverage questions are NOT this tool: for an enumeration ("which
symbols / sectors / indicators are available?", "is X covered?") use
`list_options` — instant, no async job; for a coverage COUNT or breakdown ("how
many symbols are in the investor relations dataset?", "what's the count by
sector?") use `explore_data_coverage`, the dedicated public tool. Reach for THIS
tool when the user wants the DATA itself — values, history, trends, comparisons.
*** RUN THIS BY ITSELF FIRST. DO NOT ALSO LAUNCH `generate_research_report` FOR THE
SAME QUESTION. *** These two tools are SEQUENTIAL STEPS, never parallel:
1. `explore_data_catalogue` (this tool) — the LEAN route: a validate -> plan -> run
pipeline with no report-rendering step. Usually finishes in about a minute, but
run time varies with the tables queried and can reach ~5 minutes. Poll it, SHOW
the user the resulting charts/tables, and let them iterate.
2. `generate_research_report` — the slow (~10-12 min), professional analyst-grade
deep-dive. Reach for it ONLY LATER, AFTER the user has seen the exploration and
EXPLICITLY asks for the full report. Firing both at once wastes a ~10-min job,
burns the 20/hour budget, and produces confusing duplicate polling.
There is no `delivery` argument here: results always go to the dashboard so the user
can interact with them. The job is rate-limited to 20/hour per user server-side.
Asynchronous: returns {"task_id": "...", "status": "PENDING"}. Poll a SINGLE task
with `get_task_status` until SUCCESS (the result is a plain dict — there is NO nested
task to chase). Expect roughly 1-5 minutes depending on the tables queried — a task
still PENDING after a couple of minutes is normal, so keep polling. On SUCCESS,
`result` is:
{"user_query": "...", "delivery": "dashboard",
"results": {"<query name>": {"description": "...", "columns": [...],
"rows": [...the FULL result set...],
"row_count": N}, ...}}
`rows` is NOT sampled — it carries every row (`row_count` matches len(rows)), so
charts/tables reflect the whole population.
Each entry ALSO carries `query_token`: the planned SQL sealed into an opaque token.
It is not readable and never for display — its one use is `save_user_query`, which
stores the tokens so `run_saved_query` can replay THIS EXACT request later in
seconds instead of re-planning it. Saving also makes the backend author a
PLACEHOLDER twin of each query plus a `metadata` slot schema, so the same request
can be re-asked for another company, filer, or window by passing typed `values`
for those slots. That is what to offer once the exploring is done (see the top of
this docstring); a saved row also spares the 20/hour budget.
CITE WHAT YOU PUBLISH: a result's `columns`/`rows` may carry `_source_*` columns —
`_source_url`, `_source_filed_at`, `_source_document_id`, `_source_citations` —
alongside a `sources` block naming each relation, its grain, and whether it is
`traceable` per "row" or only as a "cohort". That is the provenance of the numbers,
not padding: quote `_source_url` when the user asks where a figure came from, and for anything
you are about to publish — or the moment they ask for the filing, the quote, or
"how do you know" — pass `sources.relations[].relation` plus each row's
identifying columns (the grain AND its date) to `trace_data_sources`, which
resolves them to the source document, the
section, or the verified quote behind the number. `get_document_section` then opens
the exact speaker turn a transcript citation points at.
Render each entry as a chart/table for the user. If the request can't be served from
the platform's data, `result` instead carries a `validation_status` of "REJECTED"
(with a reason) — relay that rather than retrying blindly.
EVENT-DRIVEN QUESTIONS: when the question is about something that just HAPPENED
(an earnings print, a 13F move, a downgrade, a news item), consult
get_event_ontology(event_type=...) BEFORE writing the query and name the relations
from its `entails.<layer>` in the query text (prefer gold / analysis relations over
base tables). Skip any relation whose refreshed_by[].schedule[].next_run_at is
after the event — it does not hold the event yet and the query will show the prior
period as if it were the reaction.
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | The exploration question in natural language, e.g. "how have semiconductor margins trended over the past 8 quarters?". |
Output Schema
| Name | Required | Description |
|---|---|---|
| queue | No | Worker queue the job was routed to. |
| status | Yes | PENDING on dispatch. |
| task_id | Yes | Poll this with get_task_status until SUCCESS. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Far exceeds the annotations: async task_id/PENDING contract, 1-5 min timing, single-task polling via get_task_status, full (non-sampled) row semantics, REJECTED validation_status path, the 20/hour server-side rate limit, and the query_token/save_user_query lifecycle. None of this is derivable from the structured fields.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core purpose and arrow-marked sections help scanning, but the description is extremely long and repeats the event-driven guidance twice (the ===> situate block and the later 'EVENT-DRIVEN QUESTIONS' paragraph), plus restates the saving offer after already covering it. Significant redundancy for a one-parameter tool.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers the async contract, result shape, provenance/citation workflow, rejection handling, and the save/replay lifecycle — more than enough given an output schema exists. The main gap is length-driven redundancy rather than missing information.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the tool has one well-described 'query' param, so baseline is high. The description adds real value beyond the schema by specifying that event-driven questions should take the query from situate(...)'s plan and by describing how query_token relates to saving, though it doesn't add syntax guidance for the query string itself.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource (explore the data platform/catalogue) and precisely delimits it against siblings: list_options for enumeration, explore_data_coverage for coverage counts, generate_research_report for the deep dive. An agent can route correctly without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit when-to-use defaults ('THE DEFAULT, FIRST-STEP tool whenever the user wants to EXPLORE'), when-not-to-use (coverage questions → list_options / explore_data_coverage; report → generate_research_report only after explicit ask), plus the ordered pre-steps (list_saved_queries, situate) and a 'RUN THIS BY ITSELF FIRST' rule.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
explore_data_coverageAInspect
Answer a question about WHAT THE PLATFORM COVERS — how many symbols a dataset holds, broken down any way you like.
===> THE TOOL for coverage COUNTS and BREAKDOWNS: "how many symbols are covered in
the investor relations dataset?", "what's that count by sector — how many tech
names?", "how many companies have earnings transcripts / 13F ownership / insider
activity / analyst estimates?", "how far back does the fundamentals history go?",
"what's your UK coverage by sector?". It plans queries over BOTH the catalogue's
own metadata and the datasets themselves, so it can count what no enumeration
endpoint knows: which symbols actually carry a PARTICULAR dataset, grouped by
sector, industry, country, market cap, or year.
PUBLIC at the backend — no account, plan, or entitlement is needed to answer a
coverage question, by design: a prospect evaluating the platform should be able to
ask what it covers. (The MCP connection itself still carries the client's OAuth
session — that gate is transport-wide, not this tool's.) Never treat a coverage
question as plan-gated or quota-gated, and never tell the user it needs an upgrade.
Pick between the three coverage-adjacent routes by what the answer looks like:
- a LIST of what exists ("which sectors / indicators are available?", "is X
covered?") -> `list_options`. Instant, no async job.
- a COUNT or breakdown of coverage -> THIS tool.
- the DATA itself (values, history, trends, comparisons) ->
`explore_data_catalogue`.
Do NOT answer a coverage count from memory, from the "2,900+ companies / ~420
indices" headline figures, or by eyeballing the length of a `list_options`
payload — those are universe-wide totals and say nothing about per-dataset
coverage. Run this tool.
There is no `delivery` argument: results always go to the dashboard so the user can
interact with them. Rate-limited to 20/hour server-side.
Asynchronous: returns {"task_id": "...", "status": "PENDING"}. Poll a SINGLE task
with `get_task_status` until SUCCESS (the result is a plain dict — there is NO
nested task to chase). Expect roughly 1-5 minutes depending on the tables queried —
a task still PENDING after a couple of minutes is normal, so keep polling. On
SUCCESS, `result` is:
{"user_query": "...", "delivery": "dashboard",
"results": {"<query name>": {"description": "...", "columns": [...],
"rows": [...the FULL result set...],
"row_count": N}, ...}}
`rows` is NOT sampled or truncated — every bucket of a breakdown comes back
(`row_count` matches len(rows)), so the totals you report are the real ones.
Render each entry as a chart/table for the user. If the request can't be served
from the platform's data, `result` instead carries a `validation_status` of
"REJECTED" (with a reason) — relay that rather than retrying blindly.
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | The coverage question in natural language, as asked — e.g. "count the distinct symbols in the investor relations dataset, broken out by sector". |
Output Schema
| Name | Required | Description |
|---|---|---|
| queue | No | Worker queue the job was routed to. |
| status | Yes | PENDING on dispatch. |
| task_id | Yes | Poll this with get_task_status until SUCCESS. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Without leaning on the thin annotations (readOnlyHint=false, destructiveHint=false), the description discloses that the backend is public and not plan/quota-gated, that there is a 20/hour server-side rate limit, that execution is asynchronous returning a task_id polled via get_task_status, the 1-5 minute latency profile, and that rows are not sampled or truncated. It even covers the REJECTED validation_status failure path — far beyond what annotations convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
It is long, but front-loaded and information-dense: routing rule first, then gating, then async contract and result shape. A few clauses repeat the coverage-counting idea, costing some tightness, yet nearly every sentence carries operational value an agent needs.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter async tool it covers everything an agent needs: routing, entitlement expectations, polling loop, timing tolerance, success and rejection result shapes, and rendering instructions. An output schema exists, so the embedded result description is a bonus rather than a necessity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% for the single `query` parameter, so the baseline is 3; the description adds real meaning by specifying the query should be the coverage question in natural language as asked, and by explicitly stating that no `delivery` argument exists and why. That last point resolves an ambiguity the schema alone leaves open.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb+resource ('Answer a question about WHAT THE PLATFORM COVERS') and immediately narrows the scope to counts and breakdowns of coverage, contrasted explicitly against list_options and explore_data_catalogue. An agent can distinguish it from every coverage-adjacent sibling without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives an explicit three-way routing rule keyed on the shape of the expected answer (list -> list_options, count/breakdown -> this tool, actual data -> explore_data_catalogue), plus a negative instruction not to answer from memory or from headline universe totals. When-to-use and when-not-to-use are both stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
generate_report_for_stockAInspect
FULL REBUILD of ONE ticker's report (~10 minutes). Use sparingly — never the first call.
The fast path is `get_latest_report([ticker])`: a symbol with a fresh saved report
plan comes back under `rendering` and is rendered into the user's template in
~10-20 s; any other symbol comes back with its cached PDF and a `stale` flag. This
tool re-runs the whole pipeline — brief, query planning, SQL, formatting — so it
is for rebuilds only, in one of two modes:
STANDARD (ticker only, ~10 min): rebuilds the symbol's report plan from its latest
event and SAVES it, so later `get_latest_report` calls render it in seconds. Call it
ONLY after `get_latest_report` returned the ticker with `stale: true` or in
`missing`, and the user wants the rebuilt report rather than the cached one — tell
them it takes ~10 minutes before you start it. NEVER for a symbol that came back in
`rendering` (that render already is the fresh report), and never fanned out across a
list of names.
CUSTOM (`user_override=true` + the shaping fields, ~10 minutes, NOT saved): a full
build from scratch around named line items, ratios, segments, indicators,
estimates, or holders. Bespoke asks usually do NOT belong here. The better route for
"a report on X covering Y":
1. EXPLORE the items the user named — `list_saved_queries` first, then
`explore_data_catalogue` (after `situate` when the ask is event-driven);
2. IDEATE with the user over the result sets — what to keep, cut, add, compare;
3. OVERLAY the agreed results into their template — `get_user_template` returns
the markup to lay the content out in with your own document tooling (no
template saved -> offer `draft_user_template`).
That is faster, iterative, and the user sees the data before it is set in a PDF.
Use CUSTOM mode only when the user explicitly wants the Flexreport pipeline's own
report rebuilt around those items and accepts the ~10 minute wait. Every parameter
after `user_override` shapes a custom report, and the backend rejects it (422)
without `user_override=true` — this tool sets the switch for you whenever any of
them is non-empty, so a shaped request is never silently served the standard
report. Each parameter's description names its vocabulary — never guess, look
each one up.
Event context is SERVER-owned: the backend reads the symbol's latest platform event
and frames the report around it. There is no thesis / change-summary / include_* /
price-date field any more — do not send editorial steer; unknown keys are ignored.
CHOOSING THE SHAPING FIELDS FROM THE ONTOLOGY (custom mode only — do not guess):
read get_company_event_web(ticker) for the latest node, then
get_event_ontology(event_type=node.type), and derive from the card's family and
`informs`:
earnings family -> financial_items + estimate_items from the fundamentals
and estimates families the card informs; add
include_as_report_financials when the user wants the
filed statement (a 10-Q / 10-K anchored event)
institutional_ownership -> institutional_ownership CIKs from the web node's
fetch.cik (a 13F node is FILER-scoped: one filer's
move across several names)
market_movement / news -> technical_analysis_items from the technical_indicators
family (validate names via list_options)
analyst_activity -> estimate_items + ratios
Omit anything the ontology gives no reason for.
Not `generate_research_report`: that answers an open-ended or multi-company
question (peer comps, a theme). This tool is one ticker — and in custom mode, a
very clear list of what to cover.
Asynchronous. Returns {"<TICKER>": {"task_id": "...", "status": "PENDING"}}: read
result[ticker]["task_id"] and poll it with `get_task_status` until SUCCESS; the
result carries the finished report as {"pdf": "<base64>", ...}. Requires auth
(your MCP client attaches the OAuth bearer automatically).
| Name | Required | Description | Default |
|---|---|---|---|
| ratios | No | EDGAR ratios ("grossProfitMargin") from list_options("financial_ratios"). | |
| ticker | Yes | The ONE ticker to rebuild, e.g. "SNOW". | |
| user_override | No | CUSTOM mode switch (build around the shaping fields, not saved). Set automatically whenever any shaping field is non-empty. | |
| estimate_items | No | Estimate line items to compare against actuals. | |
| financial_items | No | Standardized EDGAR line items ("revenue", "operatingIncome") from list_options("financial_items"). | |
| revenue_segment | No | The filer's revenue segments ("Product revenue") from list_options("revenue_segments", ticker=...). | |
| as_reported_periods | No | Window(s) the as-reported section shows: "quarter" (discrete three months, the default), "ytd" (cumulative), "annual" (fiscal year, from the 10-K). Several render as adjacent columns. Not cosmetic: a filing states the same concept over more than one window at the SAME period end, so the basis must be explicit. | |
| institutional_ownership | No | Managers to feature, by SEC CIK (any width; the backend pads to 10 digits). Get them from list_options("institutional_managers", q="berkshire") -> {cik, name, category, aum}; pass the `cik` values, never names. | |
| technical_analysis_items | No | Indicators to chart ("rsi", "macd") from list_options("technical_indicators"). | |
| as_reported_financial_items | No | The filer's OWN tagged XBRL concepts ("us-gaap_RevenueFromContractWithCustomer...", or a company extension such as "snow_...") from list_options("as_reported_items", ticker=...). | |
| include_as_report_financials | No | Add an AS-REPORTED statement section built from the SEC filing itself: every figure a tagged XBRL fact deep-linked to its location in the filed document (distinct from the standardized tables, whose derived figures no filer states). Line items come from `as_reported_financial_items` when given, else are chosen to match the narrative. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only say readOnlyHint=false/destructiveHint=false. The description adds critical behavior: ~10 minute duration, async task_id return with get_task_status polling, standard mode SAVES the plan while custom mode is NOT saved, a 422 backend rejection without user_override, and OAuth attachment. Far exceeds what the annotations convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the rebuild verb and the 'never the first call' warning, and organized into STANDARD/CUSTOM/ontology sections. It is long, but for an 11-param two-mode tool most content earns its place; a few connective passages could be tightened without losing meaning.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Despite an output schema existing, the description still documents the return contract ({"<TICKER>": {"task_id", "status": "PENDING"}} and the polled result's {"pdf": "<base64>"}). Combined with mode semantics, the 422 rule, auth, and the ontology workflow, an agent has everything needed to call and follow up correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so baseline is 3. The description adds real value beyond the schema: it explains that user_override is auto-set when any shaping field is non-empty (so a shaped request is never silently downgraded), and provides the ontology-driven derivation rules for choosing which shaping fields to populate. That derivation logic is not present in the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb+resource+scope: 'FULL REBUILD of ONE ticker's report (~10 minutes)'. It explicitly distinguishes itself from get_latest_report (the fast path) and generate_research_report (open-ended/multi-company), so an agent can identify the correct tool without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
States when to call it ('ONLY after get_latest_report returned stale: true or in missing'), when not to ('NEVER for a symbol that came back in rendering', 'never fanned out'), and names the preferred alternatives for bespoke asks (explore/ideate/overlay via list_saved_queries, explore_data_catalogue, get_user_template). Explicit routing to siblings throughout.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
generate_research_reportAInspect
Answer an OPEN-ENDED or THEMATIC research QUESTION (extensible, multi-section).
===> THE RIGHT TOOL when the user's intent is a QUESTION rather than a request for an
existing report — an exploratory or thesis-style ask about a ticker, or a market-wide
theme not tied to one company (e.g. "Are large caps driving earnings season?",
"What's the bull/bear case on NVDA?", "high-growth semis with rising estimates").
For a plain "get me the latest report/research on <ticker>", use `get_latest_report`
instead. This is the slow, professional DEEP-DIVE — reach for it only when the user
EXPLICITLY asks for a full writeup, not for an ordinary exploratory question.
If the user only wants to EXPLORE the data or "use Flexreport to explore...", do NOT
start here — call `explore_data_catalogue` first (interactive charts/tables, usually a
few minutes rather than ~10-12) and
reach for THIS deep-dive only later, once the user has reviewed the exploration and
EXPLICITLY asks for the full report. Never run both for the same question at once.
Rate-limited to 20/hour per user server-side.
Asynchronous: returns {"task_id": "...", "status": "PENDING"}. Poll with
`get_task_status` until SUCCESS, then read its `result`.
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | The research question in natural language, e.g. "high-growth semis with rising estimates". | |
| delivery | No | Delivery channel for the finished report, e.g. "email" or "dashboard". |
Output Schema
| Name | Required | Description |
|---|---|---|
| status | Yes | Task state at dispatch, normally "PENDING". |
| task_id | Yes | Celery task id; poll it with get_task_status until SUCCESS. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=false and destructiveHint=false; the description adds substantial context the annotations do not: a server-side rate limit of 20/hour per user, asynchronous execution semantics, the exact return shape ({"task_id", "status": "PENDING"}), and the polling workflow via `get_task_status`. It also warns this is the slow (~10-12 min) professional deep-dive. No annotation contradiction.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with a clear '===> THE RIGHT TOOL' marker and logically ordered routing rules. It is longer than needed: the 'EXPLICITLY asks for the full report' constraint is stated twice and the options are spread across several paragraph fragments.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a rate-limited, asynchronous, multi-minute job with an output schema present, the description supplies everything an agent needs: routing against three siblings, throttling, async return contract, and the polling follow-up. Since an output schema exists, it correctly avoids explaining the final report's contents.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so both `query` and `delivery` are already documented by the schema, establishing the baseline of 3. The description reinforces `query` semantics via inline examples but says nothing about `delivery` channels or the delivery effect, so it does not exceed the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (generate) and resource (research report) with clear scope: open-ended or thematic questions, extensible, multi-section. It explicitly contrasts itself with `get_latest_report` and `explore_data_catalogue`, so an agent can distinguish it from siblings without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-to-use ('intent is a QUESTION rather than a request for an existing report'), when-not-to-use (plain 'get me the latest report' → `get_latest_report`; exploration → `explore_data_catalogue` first), and sequencing rules ('never run both for the same question at once', 'reach for THIS deep-dive only later'). Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_aftermarket_dataARead-onlyInspect
Query STORED after-hours 15-minute bars (open/high/low/close/volume) for symbols.
Returns the extended-hours bars the backend has captured for `symbols` — one row per
symbol per 15-minute bar, 16:00-20:00 ET, ordered by symbol then bar time DESC (so the
first row per symbol is the latest bar). This is the recorded aftermarket tape, NOT a
live feed; it is polled every 15 minutes from 16:30 ET through the evening, so a bar
can lag the wall clock by up to ~15 minutes. For a live intraday read of the regular
session use `detect_intraday_outlier_jumps` instead.
Leave both datetimes off for "today's aftermarket tape". An empty `bars` list means no
bars were captured in the window (e.g. before 16:30 ET, or on a non-trading day) — not
an error.
Requires auth (your MCP client attaches the OAuth bearer automatically). Rate-limited
to 300/minute per user server-side.
| Name | Required | Description | Default |
|---|---|---|---|
| symbols | Yes | Covered tickers, e.g. ["AAPL", "MSFT"]. | |
| end_datetime | No | Inclusive upper bound on bar time, ET wall-clock ISO-8601. Omit for 23:59:59 today ET. | |
| start_datetime | No | Inclusive lower bound on bar time, ET wall-clock ISO-8601 ("2026-06-24T16:00:00"). Omit for 00:00:00 today ET. |
Output Schema
| Name | Required | Description |
|---|---|---|
| bars | Yes | One row per symbol per 15-min bar, 16:00-20:00 ET, ordered by symbol then time DESC (first row per symbol is the latest). Empty means no bars were captured in the window. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Although annotations already declare readOnlyHint=true, the description adds substantial context: the data is a stored tape rather than a live feed, it is polled every 15 minutes from 16:30 ET with up to ~15 min lag, the 16:00-20:00 ET window and row ordering, plus auth (OAuth bearer) and a 300/min rate limit.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the core purpose in the first sentence, then layers scope, caveats, defaults, and edge cases as separate short paragraphs. No sentence is redundant, and the sibling reference is placed at the point of contrast.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists so return values need not be described, and the description nonetheless covers the operational profile an agent needs: stored/lagged semantics, time window, ordering, defaults, empty-result behavior, auth, and rate limits.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and both datetime defaults are already documented in the schema, so the baseline is 3. The description still adds interpretive value by framing omitting both datetimes as 'today's aftermarket tape' and by explaining the sort order (symbol then bar time DESC, latest first) that shapes how the params return data.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource with scope: 'Query STORED after-hours 15-minute bars (open/high/low/close/volume) for symbols.' It explicitly distinguishes itself from the sibling detect_intraday_outlier_jumps by contrasting the recorded aftermarket tape with a live intraday read.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Names the alternative tool and the condition that selects it ('for a live intraday read of the regular session use detect_intraday_outlier_jumps instead'), and gives explicit guidance on omitting datetimes for today's tape. It also pre-empts a common confusion by stating an empty bars list is not an error.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_company_event_webARead-onlyInspect
Fetch the connected WEB of what recently HAPPENED to a company — the WHY behind its snapshot, and a time-ordered graph to CHAIN your next calls off.
===> `situate(symbols=[symbol])` already returns this web (newest 12 nodes) PLUS
the ontology cards, cache state and an ordered plan — start there. Call this
tool directly for the FULL graph or a wider `window_days`, and pair every node
you chain off with get_event_ontology(event_type=node.type): the web says WHICH
event, the ontology says what it entails and what to do about it.
===> A FIRST-LINE TOOL FOR SINGLE-COMPANY QUESTIONS, not a specialist one. Reach
for it whenever the user asks what has been going on with a name ("catch me up on
WM", "what happened at NVDA this week", "anything I should know before
earnings?"), asks WHY the company looks the way it does ("why is the thesis
negative?", "what drove the downgrade?", "what changed?"), or whenever you are
about to aim a targeted `explore_data_catalogue`, `generate_report_for_stock`, or
`list_realtime_events` request at ONE symbol. Synchronous, cheap, and public —
one call turns "I'll guess which event types and dates matter" into "here are
the exact events, their timestamps, the tables that were written, and the call
that returns each full payload".
*** THE STANDARD PAIR: `get_company_snapshot` + THIS. *** They answer the two
halves of almost every company question and are usually called TOGETHER:
- `get_company_snapshot(symbol)` -> the WHAT. Where the company stands now:
thesis, fundamentals, technicals, ownership, grades. A settled position with
no account of how it got there.
- `get_company_event_web(symbol)` -> the WHY. The episode behind that position:
the earnings print, the 8-K, the transcript update, the rating action, the
13F refresh — in order, with edges saying how each relates.
Read them together: the snapshot for the current position, the web for the
sequence that explains it. A snapshot delivered alone reads as a verdict with no
evidence; this tool is the evidence. Conversely, do NOT use this tool to state
the company's current position — it carries headlines and pointers, not values.
When the two disagree, say so plainly rather than smoothing it over: the blocks
in a snapshot carry independent as-of dates, so an ownership or grade block can
predate anything in the window (widen `window_days` before concluding a snapshot
move is unexplained).
Returns:
{"symbol": ..., "as_of": ISO8601, "window_days": N,
"nodes": [...], "edges": [...], "market_context": [...]}
NODES — two kinds, newest first, each with a short id ("n1", "n2", ...):
- kind="event" — a published realtime event. Carries `type` (the event
type, e.g. "8k_release"), `family`, and a `fetch` hint
— the exact call that returns its FULL payload, e.g.
{"tool": "list_realtime_events", "event_type": "8k_release",
"related_endpoints": [...]}.
- kind="data_update" — a write to a backing table for activity that publishes
NO event at all (insider filings, 13F refreshes, IPO
calendar entries, Companies House events, transcript and
fundamentals analysis). Carries `relation` (the table
written); most also carry a `fetch` hint (a ready-made
`explore_data_catalogue` query for the underlying rows),
and on some relations the hint additionally carries
`signed_query_url` — see step 2 below.
Every node carries `at` (when the write/publish happened) and `headline` (ONE
line, truncated at 200 chars).
EDGES — {"from": "n3", "to": "n1", "via": <relation>, "cause": ...}, pointing
from the EARLIER node to the LATER one. `cause` is a confidence grade — respect it:
- "same_chain_run" — OBSERVED. One backend chain run produced both nodes.
- "lineage" — DECLARED. One wrote the table the other's event derives from.
- "co_occurrence" — TEMPORAL ONLY. Same company, same window, no known causal
path. Report these as "happened alongside", NEVER as caused-by.
HOW TO CHAIN (the point of this tool):
1. Walk the edges back from the newest node to reconstruct the episode, then
follow each event node's `fetch` to get the detail — e.g.
`list_realtime_events(event_type="8k_release", tickers=["WM"])`. Always narrow
by `tickers=[symbol]`; an unfiltered call re-pulls the entire cache.
2. When a `data_update` node's `fetch` carries `signed_query_url`, call
`get_signed_sql_drilldown` with it FIRST — zero planning, and it returns the
new record (`is_new_record: true`) plus the context rows to read it against.
That follow-up needs the user SIGNED IN (this tool does not); if it comes back
not-authenticated, the link is fine — say sign-in is needed for the rows and
fall back to an `explore_data_catalogue` query on the node's `relation`.
Otherwise use the node's `fetch` query if it has one, or its `relation` and
`at` to write a PRECISE `explore_data_catalogue` query ("insider filings for
WM since 2026-08-09", "13F position changes for WM in the last week")
instead of a vague one.
3. Feed the concrete events and dates into `explore_data_catalogue` /
`generate_research_report` so the analysis is scoped to what actually
happened; for the company's own report, `get_latest_report` renders the plan
saved from that event.
4. Nothing here is a full payload — a headline is a pointer, never the content.
Do not quote a headline as if it were the event.
`window_days` and `max_nodes` widen the look-back. Beyond the node cap, edges are capped per node (~3 same_chain_run, ~3
co_occurrence) and `market_context` — market-wide macro/economic-calendar nodes
that carry no ticker and so attach to no symbol — is capped at 5. A MISSING edge
is therefore not evidence that two things are unrelated.
Traps:
- `at` is a WRITE/PUBLISH time, not a business date. An earnings call date or
fiscal period end can be well before the node's timestamp — never report `at`
as the date the underlying event occurred.
- A "<table> refreshed for N symbols" node is universe-wide scheduled
maintenance rolled up, not company-specific signal.
- An empty web (`"degraded": true`, empty lists) means the graph has no rows for
that symbol in the window — NOT that nothing happened and NOT that the symbol
is uncovered. Say so, and fall back to `list_realtime_events` /
`explore_data_catalogue` rather than concluding it was a quiet week.
PUBLIC at the backend — no account, plan, or entitlement is needed, the same
posture as `get_company_snapshot`. (The MCP connection itself still carries the
client's OAuth session; that gate is transport-wide, not this tool's.)
Rate-limited 60/min.
Every node's `type`, `relation` and `family` are join keys into get_event_ontology:
call get_event_ontology(event_type=node.type) to learn what that node ENTAILS (the
tables now fresh, the events that should follow and how soon, where the payload
lives after the 12h cache, whether downstream tables have refreshed yet) before
chaining further calls off it. Web = what happened to THIS company; ontology = what
that KIND of thing means. Read them together.
| Name | Required | Description | Default |
|---|---|---|---|
| symbol | Yes | Covered ticker, e.g. "WM". | |
| max_nodes | No | Node cap (default 40, max 200). | |
| window_days | No | Look-back in days (default 7, max 90). Widen before calling a snapshot move unexplained. |
Output Schema
| Name | Required | Description |
|---|---|---|
| as_of | No | |
| edges | Yes | |
| nodes | Yes | Newest first. |
| symbol | Yes | |
| degraded | No | True with empty lists when the graph has no rows for the symbol in the window. |
| window_days | No | |
| coverage_from | No | Earliest node in the whole graph; an older window cannot be answered. |
| market_context | No | Market-wide macro / economic-calendar nodes. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=true; the description carries far more — public backend/no entitlement, transport-level OAuth caveat, 60/min rate limit, edge caps (~3 per cause type), market_context cap of 5, and the degraded empty-web semantics. It also warns that a missing edge is not evidence of non-relation and that `at` is a write time, not a business date.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose and broken into labelled sections, which helps, but it is roughly a thousand words for a three-parameter tool. The get_event_ontology pairing is stated at least three times and the snapshot contrast is belaboured, so a meaningful share of the text does not earn its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, yet the description still covers node kinds, edge shape and confidence grades, the chaining recipe, auth fallback on get_signed_sql_drilldown, and the empty-web fallback — everything needed to call and interpret it correctly. No gap remains.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3, but the description adds real meaning: window_days should be widened before concluding a snapshot move is unexplained, and max_nodes interacts with per-node edge capping and the market_context cap. It stops short of documenting defaults in prose, but the capping semantics are genuinely additive.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('fetch the connected WEB of what recently HAPPENED to a company') and immediately frames the scope as the WHY behind the snapshot. It explicitly differentiates itself from siblings — situate already returns the web, get_company_snapshot gives the WHAT — so an agent can pick the right tool without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit when-to-use (single-company 'catch me up', 'why is the thesis negative', before aiming a targeted explore_data_catalogue/generate_report_for_stock call), when-not-to-use ('do NOT use this tool to state the company's current position'), and named alternatives (start with situate, pair with get_company_snapshot and get_event_ontology). Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_company_snapshotARead-onlyInspect
Fetch a structured, POINT-IN-TIME company snapshot — no report generation needed.
Returns thesis/bull/bear, financial overview (Piotroski, valuation signal),
price performance + technical indicators, price targets, institutional
ownership, and analyst grades for `symbol`. Synchronous and cheap — prefer
this for a quick CURRENT read instead of generating a full PDF report.
*** POINT-IN-TIME ONLY — THIS IS NOT A TIME SERIES. *** It captures where the
company stands right now, not how it got there. Do NOT use it to answer
temporal / trend / "over time" questions (e.g. "how has X evolved over the
past year", "quarter-over-quarter trend", "activity over the last 12 months",
"since ..."). Each block is an independently-sourced current cut with its own
as-of date (e.g. the institutional-ownership block is the latest 13F holder
snapshot), so the blocks are NOT a comparable historical series — reading a
trend off them, or treating two blocks' as-of dates as the same instant,
produces spurious results. For anything time-series, historical, or
"how did this change", use `explore_data_catalogue` instead.
Scope caveat: the snapshot is a FIXED set of current blocks, not the full
catalogue. Absence of a data domain HERE does NOT mean Flexreport lacks it —
do not infer coverage gaps from this tool. Route "which symbols / values are
available" enumerations to `list_options` (instant), and "do you have data
on <topic>" questions that need actual data to `explore_data_catalogue`.
*** RUN IT WITH `get_company_event_web(symbol)` — THE STANDARD PAIR. *** This
tool gives the WHAT (where the company stands); the event web gives the WHY
(the events that got it there, in order, and how they connect). The snapshot
states that the thesis shifted, the valuation signal changed, or ownership
moved; it does NOT say what caused any of it — every block here is a settled
output with the episode behind it stripped out. So whenever the user asks
about a company generally, or follows a snapshot with "why?" / "what changed?"
/ "what drove that?", call BOTH and read them together: quote the snapshot for
the current position, and the event web for the sequence that explains it.
Presenting a snapshot alone as the whole picture is the failure mode — it
reads as a verdict with no evidence.
Two honest limits when pairing them. (1) The event web defaults to a 7-day
window; a driver older than that needs `window_days` widened (up to 90) before
you can say the snapshot is unexplained. (2) The blocks here carry their own
as-of dates — a 13F ownership block can be a quarter old, so the event that
explains it may sit well outside any window. Absence of a matching event is
NOT proof the snapshot moved for no reason.
| Name | Required | Description | Default |
|---|---|---|---|
| symbol | Yes | Covered ticker, e.g. "AAPL". |
Output Schema
| Name | Required | Description |
|---|---|---|
| recent_news | No | |
| price_targets | No | Decommissioned pending a model revamp: values are null and active_coverage is false. |
| price_overview | No | |
| company_summary | No | Thesis, bull and bear case. |
| financial_overview | No | |
| stock_grades_overview | No | |
| institutional_ownership | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare only readOnlyHint=true, so the description carries the behavioral burden and does it well: synchronous and cheap, fixed block set, point-in-time semantics, per-block as-of dates (13F can be a quarter old), and the failure mode of misreading blocks as a comparable series. This is context an agent could not get from the structured fields.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose before the caveats, and the bolded section headers make it scannable. However, the point-in-time constraint is restated several times across the warning and pairing paragraphs, so the piece is longer than a one-parameter read tool strictly requires and carries mild redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return values need not be explained, and the description nonetheless enumerates the returned blocks. Combined with the routing rules, timing caveats, and pairing guidance, nothing an agent needs to call this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Only one parameter (symbol), schema description coverage is 100%, and the description adds nothing beyond the schema's 'Covered ticker, e.g. AAPL.' Baseline 3 for a fully documented single-param schema is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb+resource — 'Fetch a structured, POINT-IN-TIME company snapshot' — and immediately enumerates what blocks it returns (thesis/bull/bear, financial overview, price performance, targets, ownership, grades). It is clearly distinguished from near-siblings like generate_report_for_stock, explore_data_catalogue, and list_options, so an agent can pick it without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit when-to-use ('quick CURRENT read', general company questions), explicit when-NOT-to-use (any temporal/trend/'over time' question, coverage enumerations), and names the replacement tool for each case (explore_data_catalogue, list_options). It also instructs the standard pairing with get_company_event_web and states the selection reason (WHAT vs WHY).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_document_sectionARead-onlyInspect
Open ONE numbered section of a source document — the exact earnings-call speaker turn a citation points at.
The other end of a `trace_data_sources` citation, and the finest grain the platform
serves: not the whole call, one turn of it. Use it to read the passage behind a
number before quoting it, and to quote a speaker verbatim with the citation intact.
Every argument comes off the citation you are following — a `transcript_section`
citation's URL is `/query-section?name=...&symbol=...&year=...&quarter=...&n=...`,
so read the four values out of it rather than deriving them. If you pulled the row
from `earnings_call_transcript_sections` yourself you already hold all four
(`symbol`, `year`, `quarter`, `section_no`); no text search is needed or wanted.
*** `year` and `quarter` are the FISCAL period of the CALL, never the calendar
quarter a report covers. *** For most covered companies those differ — the call
everyone calls "Q2 2026" is stored as FY2026 Q4 for one name and FY2027 Q1 for
another. Take the period from the citation, the transcript record, or `call_date`.
A 404 here ("no section N for SYM YEARqQ") is almost always this, not a missing
call: re-check the period before concluding the transcript is not covered.
Returns {"name", "symbol", "year", "quarter", "n", "format": "paragraph",
"count", "rows": [{symbol, year, quarter, call_date, section_no, speaker,
content}], "highlights": [...], "total_sections": N, "transcript_url": ...}.
`content` is the turn's text and `speaker` is who said it — attribute the quote to
that speaker, never to "the company". `total_sections` bounds `n`, so neighbouring
turns (n-1, n+1) are how you read a passage in context when it starts mid-answer.
`highlights` are quotes the platform's own analysis pipeline verified against this
section; they mark evidence inside it but are NOT necessarily the passage you are
citing — verify your own quote against `content`. `transcript_url` is frequently
null, so offer "view the full call" only when it is present.
Requires auth (your MCP client attaches the OAuth bearer automatically).
| Name | Required | Description | Default |
|---|---|---|---|
| n | Yes | 1-based section number (the speaker turn), e.g. the citation's `n` or `section_no`. | |
| name | No | Whitelisted section source; "earnings_transcript" is the only one today. | earnings_transcript |
| year | Yes | FISCAL year of the call (never the calendar year a report covers), read off the citation URL or transcript record. | |
| symbol | Yes | Ticker the cited call belongs to, read off the citation. | |
| quarter | Yes | FISCAL quarter of the call, read off the citation URL or transcript record. |
Output Schema
| Name | Required | Description |
|---|---|---|
| n | Yes | 1-based section number. |
| name | Yes | |
| rows | Yes | |
| year | Yes | Fiscal year of the call. |
| count | No | |
| format | No | |
| symbol | Yes | |
| quarter | Yes | Fiscal quarter of the call. |
| highlights | No | Quotes the platform verified against this section. |
| total_sections | No | Upper bound for n; read n-1 / n+1 for context. |
| transcript_url | No | Full call link; frequently null. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With only readOnlyHint=true in annotations, the description carries real behavioral load: auth requirement, the common 404 cause and its remedy, that transcript_url is frequently null (so don't offer a link), that highlights are pipeline-verified but not necessarily your quote, and that total_sections bounds n. None of this contradicts the annotations and none of it is recoverable from structured fields.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The lead sentence is front-loaded and the purpose is clear before any caveats. It is on the long side, and the bold fiscal-period warning partially duplicates the schema's own field note, but every remaining sentence (citation derivation, 404 remedy, highlights semantics, null transcript_url) earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 5-parameter authenticated read tool with an output schema, the description covers the things the schema cannot: auth handling, error interpretation, how to read a mid-answer passage via adjacent sections, and caveats on two return fields. Nothing material an agent needs to call this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so a baseline of 3 applies, but the description goes beyond the schema by explaining where each value originates (the citation URL's name/symbol/year/quarter/n components, or the transcript row's section_no) and by stressing the fiscal-vs-calendar period trap. It doesn't add per-parameter syntax beyond that, so it stops short of 5.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening line states a specific verb and resource with exact scope: 'Open ONE numbered section of a source document — the exact earnings-call speaker turn a citation points at.' It positions itself against siblings by naming trace_data_sources as the counterpart and clarifying the grain ('not the whole call, one turn of it'). An agent can distinguish this from transcript-listing tools without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit when-to-use ('read the passage behind a number before quoting it... quote a speaker verbatim with the citation intact'), describes the alternative acquisition path ('if you pulled the row from earnings_call_transcript_sections yourself you already hold all four'), and instructs to derive args from the citation URL rather than guess. The 404 troubleshooting guidance is an unusually strong when-it-fails clause.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_event_ontologyARead-onlyInspect
The platform's event ONTOLOGY — what an event TYPE means for everything else. Call it FIRST on any real-time, single-company, or event-driven request; it is the map the other calls are planned from.
===> `situate(...)` composes this with the event web and the cache state and
hands you a plan — start there. Call this tool directly for the FULL card of an
event type, a relation card, a whole family, or the unfiltered graph, when the
plan did not cover what you need next.
===> REQUISITE for: any real-time / live-events request, any "what
happened / why / catch me up" question, and BEFORE aiming explore_data_catalogue or
generate_report_for_stock at a company whose situation is event-driven. Cheap,
synchronous, public, symbol-INDEPENDENT and cacheable — fetch once per event type
(or once unfiltered, ~230 KB) and reuse for the whole conversation.
Pass exactly ONE filter for a small card (~5-10 KB):
event_type="eps_update" one event type and the relations it entails
relation="eod_stock_prices" one table/view and the event types that entail it
family="earnings" every event type and relation in a family
No filter -> the whole class graph (21 event types, ~300 relations, 20 tools).
Web nodes from get_company_event_web carry the join keys verbatim: pass a node's
`type` as event_type, its `relation` as relation, its `family` as family.
An event_type card carries:
about what the event is ABOUT: symbol | filer | strategy. A 13F
event is a FILER's action across N names — the symbol
you asked about is one of them.
persisted_in the durable table to read once the event has aged out
of the realtime cache (realtime_cache_ttl_hours, 12h) —
list_realtime_events returns [] after that; the data is
still there, in this relation.
entails.<layer> the relations WRITTEN by the same chain run (mined, with
run counts) plus every view above them (pg_depend),
bucketed base / silver / gold / dimension / analysis.
These are the tables that are FRESH because this event
fired — name them explicitly in explore queries.
entails.realtime_events event types that usually FOLLOW, each with rate,
median_lag_hours, lift, mode (trigger = dispatched by the
same chain, near-certain; sequence = world-ordered,
independently detected, probabilistic), certainty /
expected_within_hours when declared, and persisted_in.
preceded_by the inverse — what should ALREADY exist earlier in the web.
episodes named world-order sequences (earnings, realtime_mover,
thirteen_f_cycle, news) with this event's position — the
whole shape of the situation from any one member.
produced_by[].schedule the workflow that publishes it, its cron, and
next_run_at (America/New_York).
deepened_by the tools that deepen this event once you have its payload.
informs DOMAIN causality (news -> prices, earnings -> estimates):
what an analyst checks next. Declared and the WEAKEST
edge — never present it as lineage.
evidence how many of these events the platform has seen.
A relation card carries: layer, family, cadence (update_frequency + prose),
derives_from / feeds (pg_depend), computed_from / computes (LLM and model writers),
refreshed_by[].schedule with next_run_at, read_by (the MCP tools that read it),
entailed_by (event types), informs.
THE FRESHNESS CHECK — the reason this tool exists: compare a web node's `at` with a
downstream relation's refreshed_by[].schedule[].next_run_at. If next_run_at is AFTER
the event, that relation does NOT reflect the event yet. Do not query it for the
reaction — use the intraday tools (detect_intraday_outlier_jumps,
get_aftermarket_data) or say the daily table lags.
Every edge carries `provenance` (mined | declared | pg_depend | static:tasks.py |
beat | catalogue | data_model), the same honesty axis as the web's `cause`: mined
and pg_depend are facts, declared is the platform's own judgment, informs is domain
intuition. Quote the grade when you lean on an edge. format="triples" returns raw
subject-predicate-object rows instead of cards. degraded=true means the table has
not been built yet, not that the type is unknown.
| Name | Required | Description | Default |
|---|---|---|---|
| family | No | One family, e.g. "earnings" (a web node's `family`). | |
| format | No | cards (grouped, default) or triples (raw subject-predicate-object rows). | cards |
| relation | No | One table/view, e.g. "eod_stock_prices" (a web node's `relation`). | |
| event_type | No | One event type, e.g. "eps_update" (a web node's `type`). Pass exactly one filter. |
Output Schema
| Name | Required | Description |
|---|---|---|
| as_of | No | |
| edges | No | Subject-predicate-object rows (triples format). |
| degraded | No | True when the ontology table is not built yet, not that the type is unknown. |
| episodes | No | |
| relations | No | Relation cards, keyed by table/view (cards format). |
| event_types | No | Event-type cards, keyed by type (cards format). |
| realtime_cache_ttl_hours | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=true, yet the description discloses cost/latency profile (cheap, synchronous, public, symbol-independent, cacheable, fetch once and reuse), response sizes (~5-10 KB per card, ~230 KB unfiltered), the `degraded=true` meaning, and the freshness/lag semantics that are the tool's whole rationale.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Well front-loaded and sectioned with headers, but it is very long and the field-by-field enumeration of what an event_type/relation card carries duplicates content that a present output schema already covers. Much of it earns its place; a meaningful fraction does not.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a complex ontology tool with a rich return surface, the description covers selection, sequencing relative to `situate`, filter semantics, freshness caveats, and provenance grading. Even accounting for the existing output schema, an agent has everything needed to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% so the baseline is 3, but the description adds real value beyond the schema: the 'pass exactly ONE filter' constraint, expected card sizes per filter, and the mapping of web-node keys (`type`/`relation`/`family`) onto the parameters. The per-parameter examples largely restate the schema, keeping it from a 5.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific resource and its scope: 'the platform's event ONTOLOGY — what an event TYPE means for everything else.' It explicitly distinguishes itself from siblings by naming `situate(...)` as the composing entry point and describing when to call this one directly instead.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-to-use ('Call it FIRST on any real-time, single-company, or event-driven request'), names the alternative (`situate` composes this), and lists when-not/requisite conditions plus the freshness-check routing to `detect_intraday_outlier_jumps` / `get_aftermarket_data`. Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_latest_reportARead-onlyInspect
Get the latest Flexreport research report(s) for one or more tickers. USE THIS BY DEFAULT.
===> THIS IS THE DEFAULT, CORRECT TOOL whenever a user asks for "the report",
"research", "the latest research", "analysis", "a writeup", or "the PDF" for a
ticker (e.g. "get me the latest research on SNOW"). It is the FAST path. For a
symbol with a FRESH saved report plan it does not hand back a pre-built PDF: it
pulls the plan itself — the JSON the platform saved when the symbol's latest
material event published (brief, queries, results, format map) — and renders it
straight into the user's template in ~10-20 s. Every other symbol comes back
with its cached PDF. ALWAYS call this before `generate_report_for_stock`, which
is a ~10 min full rebuild.
If the user's intent is an OPEN-ENDED or exploratory QUESTION rather than a request
for this existing report, do NOT use this tool — default to `explore_data_catalogue`
(fast, interactive), and reach for `generate_research_report` only when the user
EXPLICITLY asks for a full deep-dive writeup. A BESPOKE report ("the SNOW report,
but built around product revenue and RPO") is not a rebuild either: explore the
items the user named, ideate with them on the result sets, and lay the agreed
results out in their template (`get_user_template`) with your own document tooling.
Accepts one OR many symbols. Returns
{"result": [{"symbol": "AAPL", "url": "<presigned pdf url>",
"report": "<base64 pdf>", "generated_at": "<iso utc>",
"age_hours": 5.2, "latest_event_at": "<iso>", "stale": true}, ...],
"missing": ["XYZ", ...],
"rendering": {"PLAY": {"task_id": "...", "status": "PENDING", "symbol": "PLAY"}}}
Every symbol lands in exactly ONE of the three. A `result` hit carries BOTH
representations of the same PDF: `url` is a short-lived presigned link (valid
~6h) — hand it to the user to download/open the document directly (and prefer it
on clients that can't handle a large base64 blob); `report` is the inline base64
PDF — decode it to read, render, or summarize the report's contents yourself.
Split a list longer than 100 symbols across calls.
READ ALL THREE BEFORE YOU HAND ANYTHING OVER. Nothing regenerates on its own:
in `rendering` -> the symbol's saved plan is fresh and is being rendered into the
user's template (~10-20 s). Poll get_task_status(task_id); the
finished result carries {"pdf": "<base64>", ...} — hand the
user THAT. Never call generate_report_for_stock for it: the
render already is the fresh report.
stale: false -> the cached PDF reflects the symbol's latest report inputs. Serve it.
stale: true -> the saved plan itself is out of date (a print, a filing, a 13F
refresh landed after it; `latest_event_at` says when), so there
is nothing fresh to render. Hand over the stale PDF with that
caveat and offer generate_report_for_stock(ticker) — a full
rebuild, ~10 min. Start it when the user wants the refreshed
report; never fan rebuilds out across a list of names unasked.
stale: null -> no report inputs are known for the symbol, so freshness cannot
be judged. Serve the PDF and quote `generated_at` / `age_hours`.
in `missing` -> no plan to render and no cached PDF. generate_report_for_stock(ticker)
builds the first one (~10 min, saved so later calls here render
it in seconds) — say so before starting it — or `onboard_symbol`
if the ticker is not covered.
To see which symbols have a fresh plan READY to render — by the event that
triggered it, across the universe, before anything is pulled — use
`list_available_reports`: it lists saved plans, not cached PDFs.
Rate-limited to 500/hour. Requires auth (your MCP client attaches the OAuth bearer
automatically).
| Name | Required | Description | Default |
|---|---|---|---|
| symbols | Yes | One or many tickers, e.g. ["SNOW", "AAPL"]; uppercased and de-duplicated server-side, at most 100 after dedupe (413 above that). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=true, so the description carries the real burden and delivers: rate limit of 500/hour, OAuth auto-attached by the client, ~10-20s render vs ~10min rebuild, the fact that nothing regenerates on its own, and the meaning of stale true/false/null and the `rendering`/`missing` buckets. This is far beyond what the annotation provides.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Long but highly structured and front-loaded, with the default-tool claim in the first line and the branch semantics broken out per field. Slight redundancy: 'USE THIS BY DEFAULT', the ===> header, and 'ALWAYS call this before...' restate the same priority three times, but nothing is genuinely wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given no output schema, the description reproduces the return shape in full (result/missing/rendering, url vs base64 semantics, presigned ~6h validity) and covers every branch an agent must handle before handing a document over. Nothing needed to call or interpret the tool correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Single parameter with 100% schema description coverage (uppercasing, dedupe, 100-symbol cap, 413 status), so the schema baseline is 3. The description still adds operational meaning by stating lists longer than 100 symbols must be split across calls, which the schema does not express as workflow guidance.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource (retrieve the latest Flexreport research report for one or more tickers) and immediately positions itself against siblings, declaring itself the default and naming `generate_report_for_stock`, `explore_data_catalogue`, and `generate_research_report` as the alternatives. An agent can route to it without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit when-to-use (queries for 'the report', 'research', 'analysis', 'the PDF') and when-not-to-use (open-ended exploratory questions → explore_data_catalogue; bespoke reports → explore + get_user_template; full deep-dive → generate_research_report). Includes the ordering constraint to call this before generate_report_for_stock.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_signed_sql_drilldownARead-onlyInspect
Fetch the rows behind an event-web drilldown from its server-minted query token.
Some `get_company_event_web` nodes carry `signed_query_url` in their `fetch` hint —
an opaque, tamper-proof link the backend minted for exactly that node. This tool is
the zero-planning rung of the chain: no query to compose, the rows come back
directly. Pass either the full `signed_query_url` or just its `t` parameter; the
URL form is unwrapped automatically. A token that came from a
SAVED request rather than the event web belongs to `run_saved_query` instead — same
endpoint, but it replays every query in the saved row in one call.
Returns {"format": "table", "count": N, "rows": [...]} — rows only, never the
underlying SQL. For contextual drilldowns the NEW record is flagged
`is_new_record: true` and the remaining rows are the prior/context records to read
it against (the node's `signed_query_context` describes what they are).
CITE WHAT YOU PUBLISH: the rows may carry `_source_*` columns — `_source_url`,
`_source_filed_at`, `_source_document_id`, `_source_citations` — and the response a
`sources` block naming each relation, its grain, and whether it is `traceable` per
"row" or only as a "cohort". That is the provenance of the numbers, not padding:
quote `_source_url` when the user asks where a figure came from, and for anything
you are about to publish — or the moment they ask for the filing, the quote, or
"how do you know" — pass `sources.relations[].relation` plus each row's
identifying columns (the grain AND its date) to `trace_data_sources`, which
resolves them to the source document, the
section, or the verified quote behind the number. `get_document_section` then opens
the exact speaker turn a transcript citation points at.
HTTP 403 means the token is invalid or tampered — do not retry with an altered
token; re-fetch the event web for a fresh link instead.
`values` and `prompt` re-aim a token that is a PLACEHOLDER TWIN at other entities;
the response then carries `parameters` (what was substituted) alongside `rows`;
echo those to the user. A 422 means the request could not be
mapped onto the token's slots. The full slot vocabulary of a SAVED row lives in
`list_saved_queries` -> `metadata.parameters`, and replaying a saved row is
`run_saved_query`, not this tool.
An uncapped drilldown that fans out to constituents can return tens of thousands
of rows and stall the client for minutes — pass `max_rows`.
Requires auth (your MCP client attaches the OAuth bearer automatically) — unlike
`get_company_event_web`, which is public: the web hands out the LINK to anyone, but
following it to the underlying rows is for signed-in users. A signed-out caller gets
a not-authenticated error, not rows; the fix is signing in, never a different token.
| Name | Required | Description | Default |
|---|---|---|---|
| prompt | No | Placeholder-twin tokens only: natural-language fill for slots `values` did not cover, e.g. "the same rows for KSS". Omit for a plain event-web link. | |
| values | No | Placeholder-twin tokens only (preferred over prompt): {slot name: typed value}, filled deterministically, e.g. {"symbol": "KSS"}. Omit for a plain link. | |
| max_rows | No | Cap on rows returned, e.g. 500; the response then carries row_count and truncated: true. Pass it on any drilldown that can fan out to constituents. | |
| encrypted_query_token | Yes | A node's `signed_query_url` from get_company_event_web, or just its `t` parameter — verbatim. Never construct or edit one; never pass SQL. |
Output Schema
| Name | Required | Description |
|---|---|---|
| rows | No | Result rows (cell values are strings or null). May carry _source_* citation columns. Null on a replay entry whose token failed (see `error`). |
| count | No | Rows returned in `rows`. |
| format | No | "table". |
| sources | No | Provenance block; present when the numbers trace to documents. |
| row_count | No | Full row count when `truncated` (max_rows sliced the result). |
| truncated | No | |
| parameters | No | Values substituted into a placeholder twin; echo them to the user. |
| ignored_values | No | Keys in `values` this token does not use. |
| defaulted_parameters | No | Slots that kept the saved example value. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only give readOnlyHint=true, and the description layers substantial extra behavior on top: HTTP 403 means invalid/tampered token with no-retry guidance, 422 means slot-mapping failure, auth is required (unlike the public get_company_event_web), and uncapped drilldowns can stall the client for minutes. These are exactly the operational facts annotations cannot express.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The critical routing facts (what it fetches, which token, which sibling to use instead) are front-loaded in the first two paragraphs. It is long and somewhat sprawling across provenance, error codes, and auth, but nearly every sentence carries distinct, load-bearing information rather than filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers token provenance, the two value-fill paths, truncation via `max_rows`, 403/422 failure modes, auth requirements, and the `_source_*`/`sources` provenance contract with follow-on tools (trace_data_sources, get_document_section). Even though an output schema exists, the description goes further and explains the `is_new_record` flag and the `parameters` echo, leaving nothing an agent needs in order to call or interpret it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds real meaning: the URL form is auto-unwrapped so either the full `signed_query_url` or just its `t` works, and `values`/`prompt` only apply to PLACEHOLDER TWIN tokens and produce a `parameters` block to echo. It goes beyond restating the schema without fully exhausting token-slot vocabulary (which it delegates to list_saved_queries).
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb+resource+scope: 'Fetch the rows behind an event-web drilldown from its server-minted query token.' It explicitly distinguishes itself from the closest siblings — get_company_event_web, run_saved_query, list_saved_queries — so an agent can route correctly without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Names the exact precondition (a node carrying `signed_query_url` from get_company_event_web), the explicit exclusion (tokens from SAVED requests belong to `run_saved_query` instead, 'not this tool'), and the alternative-route vocabulary source (`list_saved_queries` -> `metadata.parameters`). When/when-not/alternatives are all covered.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_stock_picksARead-onlyInspect
Fetch the latest LLM-selected stock picks (current rebalance holdings).
Returns `picks`, the holdings selected for the most recent rebalance date — the names
the backend's strategies are currently positioned in. Each pick is a record (ticker,
strategy, weight, rebalance date, and related fields; values are strings).
Synchronous and read-only — no auth required.
Each holding also carries a CURRENT-BASKET YTD view: `ytd_return` (that stock's
Jan 1 -> now price return) and the strategy-level weighted `basket_ytd_return`.
For how the strategies have ACTUALLY performed since inception (the realized track
record of the book as held), use `get_strategy_performance_summary` /
`get_strategy_track_record` instead.
| Name | Required | Description | Default |
|---|---|---|---|
| strategy_name | No | Narrow to one strategy (e.g. "momentum", "multi_signal", "fundamentals_smid", "value_quality"); omit for picks across all strategies. |
Output Schema
| Name | Required | Description |
|---|---|---|
| picks | Yes | Current holdings, each strategy at its own latest rebalance. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, but the description adds genuinely useful context: synchronous execution, no auth required, and the semantic distinction between current-basket YTD returns and realized track record. It stops short of rate limits or response-size behavior, keeping it just below the top tier.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core purpose in the first sentence, followed by return semantics and routing guidance in logical order. It is slightly long, but nearly every sentence carries a distinct fact, so there is little waste.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values needn't be enumerated, yet the description still clarifies the semantics of ytd_return and basket_ytd_return. Combined with the no-auth/read-only disclosure and sibling routing, nothing an agent needs to call this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the single strategy_name parameter is already documented with examples in the schema; the description text adds no further parameter guidance. Baseline 3 is correct when the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Fetch the latest LLM-selected stock picks') and immediately clarifies scope with 'current rebalance holdings.' It also names the sibling tools it is not, so an agent can route between this and the performance tools without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly names the alternatives (get_strategy_performance_summary / get_strategy_track_record) and the condition that selects them ('how the strategies have ACTUALLY performed since inception'), contrasting with the current-basket YTD view this tool provides. Clear when/when-not guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_strategy_performance_summaryARead-onlyInspect
Leaderboard of since-inception performance vs the S&P 500 for all strategy books.
THE first stop for "how are the stock picks / strategies performing?". Returns
`strategies`, one headline row per book — the four strategies plus the pooled optimized book — sorted
by excess return over the S&P 500: {strategy_name, display_name, inception_date,
since_inception_return, sp_since_inception, excess_since_inception,
annualized_return, max_drawdown, sharpe, sp_sharpe, ytd_return, growth_strategy,
growth_sp, days_tracked}.
growth_strategy / growth_sp = what `amount` invested at inception would be worth in
the strategy vs the S&P 500.
Drill into one book's full daily series with `get_strategy_track_record`, or its
per-trade adds/drops with `get_strategy_swaps`.
| Name | Required | Description | Default |
|---|---|---|---|
| amount | No | Dollar amount assumed invested at inception; scales growth_strategy / growth_sp. |
Output Schema
| Name | Required | Description |
|---|---|---|
| strategies | Yes | One row per book with history, sorted by excess_since_inception (best first). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, so the safety profile is covered. The description adds real behavioral context beyond that: the sort key (excess return over the S&P 500), the one-row-per-book granularity, and the meaning of growth_strategy/growth_sp as the value of `amount` invested at inception.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the one-line purpose and the headline use case, then supporting detail. The inline enumeration of twelve return fields is somewhat long, but it is the tool's actual payload and each remaining sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool returns a single flat table with one parameter and an output schema, so almost nothing is left to infer: purpose, sorting, row shape, and drill-down paths are all stated. The field list partially duplicates the output schema, which keeps it just short of a 5.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the `amount` param already documents 'dollar amount assumed invested at inception; scales growth_strategy / growth_sp'. The description's explanation of growth_strategy/growth_sp restates that same semantics, so it adds little beyond the schema — baseline 3.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb+resource+scope: a since-inception performance leaderboard versus the S&P 500 across all strategy books. It also explicitly distinguishes itself from siblings get_strategy_track_record and get_strategy_swaps, so an agent can route without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'THE first stop for "how are the stock picks / strategies performing?"' gives an explicit entry-point condition, and the closing sentences name the two alternatives with the conditions that select them (full daily series vs per-trade adds/drops).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_strategy_swapsARead-onlyInspect
Per-trade swap ledger (adds/drops) vs the S&P 500 for ONE strategy book.
Answers "were the individual trades good?": across consecutive weekly rebalances,
an ADD is a name newly selected and a DROP a name removed. Each ADD is measured
from entry to its exit (or the latest close if still held); each DROP is the
FOREGONE return from its exit to the latest close. Both are compared to the S&P
500 over the same window.
Returns {strategy_name,
trades: [{symbol, action, event_date, window_end, still_open, name_return,
sp_return, excess}, ...] (newest first),
summary: {n_adds, n_drops, avg_add_excess_vs_sp, avg_drop_foregone_excess_vs_sp,
net_swap_value_add}}.
For the book-level return series use `get_strategy_track_record`.
| Name | Required | Description | Default |
|---|---|---|---|
| strategy_name | Yes | One of the four strategies, or "pooled" (the pooled optimized book). |
Output Schema
| Name | Required | Description |
|---|---|---|
| book | No | |
| trades | Yes | Adds and drops, newest first. |
| summary | Yes | |
| strategy_name | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=true, so the description carries the rest of the burden. It discloses the non-obvious measurement semantics (ADD measured entry-to-exit, DROP as foregone return exit-to-latest-close, both vs S&P over the same window), which materially affects interpretation. It omits any statement about data freshness/latency or weighting assumptions, keeping it short of a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the one-line purpose before the methodology and routing note, and each sentence serves a distinct purpose. However, the verbose restatement of the return shape duplicates the existing output schema and could be trimmed.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Read-only annotations plus a full output schema mean the safety and return-value burdens are covered elsewhere. The description adds the computational definitions needed to interpret the numbers correctly, though freshness/coverage caveats for the latest close are unstated.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the enum already enumerates the five valid values, so the schema does the heavy lifting. The description adds only the scoping emphasis "ONE strategy book" and does not explain why pooled behaves differently beyond what the enum description states; baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific artifact (per-trade swap ledger of adds/drops), the benchmark (S&P 500), and the scope (ONE strategy book). It also explicitly routes the agent elsewhere for the book-level time series, so it is distinguishable from siblings like get_strategy_track_record without reading either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives the exact question this tool answers ("were the individual trades good?") and names the alternative tool plus the condition that selects it (book-level return series -> get_strategy_track_record). When-to-use and when-to-use-something-else are both explicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_strategy_track_recordARead-onlyInspect
Since-inception daily track record vs the S&P 500 for ONE strategy book.
Returns the realized performance of the book as actually held — chartable series
plus headline stats: {strategy_name, book, inception_date, amount_invested,
summary: {since_inception_return, sp_since_inception, excess_since_inception,
annualized_return, max_drawdown, sharpe, sp_sharpe, ytd_return, growth_strategy,
growth_sp, days_tracked, last_date},
series: [{date, strategy_cumulative, benchmark_cumulative, excess, strategy_ytd,
growth_strategy, growth_sp, sharpe_expanding, holdings_count}, ...]}.
The Sharpe series is expanding-window and annualized (rf=0).
Backend returns 404 when the chosen book has no performance history yet. For the
cross-book leaderboard use `get_strategy_performance_summary`; for the current
holdings themselves use `get_stock_picks`.
| Name | Required | Description | Default |
|---|---|---|---|
| book | No | "llm" (LLM-curated selections) or "mechanical" (the raw quantitative screen, no LLM overlay). | llm |
| amount | No | Dollar amount assumed invested at inception; scales the growth-of-$ fields. | |
| strategy_name | Yes | One of the four strategies, or "pooled" (the pooled optimized book). |
Output Schema
| Name | Required | Description |
|---|---|---|
| book | No | |
| series | Yes | Daily points from inception, ascending by date. |
| summary | Yes | |
| strategy_name | Yes | |
| inception_date | No | |
| amount_invested | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=true, so the description carries the rest and does so well: the 404-on-missing-history behavior and the fact that the Sharpe series is expanding-window and annualized with rf=0 are non-obvious traits an agent could not infer. It does not cover pagination or rate limits, keeping it short of a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded in one line and the routing/404 caveat is well placed, but the multi-line inline JSON dump of summary and series fields is redundant given an output schema exists — it consumes most of the description without adding selection value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only reporting tool with full schema coverage and an output schema, the description supplies everything an agent needs: scope, the 404 edge case, metric semantics, and sibling routing. Nothing required for correct invocation is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and both enums (book, strategy_name) are fully documented in the schema, so the baseline of 3 applies. The description adds nothing about the 'amount' scaling or enum choices beyond what the schema already states.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource with explicit scope: 'Since-inception daily track record vs the S&P 500 for ONE strategy book.' The 'ONE' and the sibling routing immediately distinguish it from the cross-book summary and the holdings tool.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly names two alternatives and the condition that selects each: get_strategy_performance_summary for a cross-book leaderboard, get_stock_picks for current holdings. It also warns that the backend returns 404 when the chosen book has no history, which is a real usage constraint.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_task_statusARead-onlyInspect
Poll the status of an async job (a get_latest_report rendering task, generate_report_for_stock, generate_research_report, explore_data_catalogue, explore_data_coverage, screen_stocks, ...).
Returns {"task_id": ..., "status": ..., "result": ...}. `status` is one of
PENDING, SUCCESS, FAILURE, RETRY. `result` is populated once status is SUCCESS.
| Name | Required | Description | Default |
|---|---|---|---|
| task_id | Yes | The task_id an async tool returned. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=true, so the description carries the interesting burden and does so: it documents the status lifecycle (PENDING, SUCCESS, FAILURE, RETRY) and that `result` is only populated at SUCCESS. It omits polling interval, task retention/expiry, and what FAILURE returns, which are relevant for a poll-based tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the core action, then the return contract, then the status enum — a sensible ordering. The parenthetical tool list is long and trails off with an ellipsis, costing a little tightness, but nothing is redundant with the schema or annotations.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, so the description correctly steps in to describe the return shape, status values, and result population. It remains silent on polling frequency and on what `result` contains for each task type, minor gaps for a polling tool but not blocking.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Only one parameter with 100% schema description coverage ('The task_id an async tool returned'), so the schema already does the work. The description implies the task_id links to a prior async call but adds no syntax or format detail beyond that, making the baseline 3 appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Poll the status of an async job') and then enumerates the concrete producer tools (generate_report_for_stock, explore_data_catalogue, screen_stocks, etc.) whose task_ids this consumes. An agent immediately understands this is the status-check companion to the async report/exploration tools, and no sibling overlaps this role.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Clearly signals the usage context: call it after invoking one of the listed async tools that returned a task_id. It does not, however, give any when-not-to-use guidance or polling cadence advice, but the retrieval scenario is unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_technical_indicator_dataARead-onlyInspect
Fetch a historical technical-indicator series for a symbol over a date range.
Call `list_options("technical_indicators")` first for valid indicator names. An
unknown symbol returns 404 and an unknown indicator returns 400 listing valid values.
Returns `rows`, one record per trading day ordered by date (columns beyond
date/symbol/close vary by indicator), or an empty list when there's no data in the range.
Requires auth (your MCP client attaches the OAuth bearer automatically).
| Name | Required | Description | Default |
|---|---|---|---|
| symbol | Yes | Covered ticker, e.g. "AAPL" (see list_options("tickers")). | |
| end_date | Yes | Inclusive end date, YYYY-MM-DD. | |
| indicator | Yes | Indicator name from list_options("technical_indicators"), e.g. "rsi". | |
| start_date | Yes | Inclusive start date, YYYY-MM-DD. |
Output Schema
| Name | Required | Description |
|---|---|---|
| rows | Yes | One row per trading day, ascending by date. Beyond date/symbol/close, columns are indicator-specific (e.g. rsi carries `rsi`, `overbought`, `oversold`). Empty means no data in the range. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the readOnlyHint annotation: it discloses error semantics (404 for unknown symbol, 400 with valid values for unknown indicator), the return shape (one row per trading day, ordered by date, column set varying by indicator), and the empty-range behavior. Auth requirement is also stated explicitly.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the one-line purpose, then prerequisite, then error/return behavior, then auth – a logical order with no filler. The return-shape sentence is partially redundant given an output schema exists, which is the only real trim opportunity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 4-required-param read tool with an output schema, the description still covers the prerequisite dependency, both failure modes, ordering, and auth, so an agent can call it correctly on the first attempt. Nothing material is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, including the list_options cross-references and the YYYY-MM-DD inclusive semantics, so the schema already carries parameter meaning. The description adds only the aggregate notion of a date range and per-row date ordering, which is not materially beyond the schema. Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Names a specific verb ("Fetch"), a specific resource ("historical technical-indicator series"), and the scoping axes (symbol, date range). This is clearly distinguishable from siblings like get_company_snapshot or get_aftermarket_data without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a concrete prerequisite: call list_options("technical_indicators") first to obtain valid indicator names, which prevents a predictable 400. It stops short of stating when-not-to-use this tool or naming an alternative series endpoint, so it is clear context without exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_user_templateARead-onlyInspect
Return the PDF template this user has saved, or a 404 if they have none.
Call it to answer "what format am I on?", BEFORE `save_user_template` when a
template may already exist (saving replaces it without history, so the user
should know what they are overwriting), and whenever you are about to compose
a PDF yourself from Flexreport data: lay the content out in this markup so the
document matches the user's format. A 404 there is the cue to offer drafting
one (`draft_user_template` -> previews -> `save_user_template`).
Returns {"template_type", "template_format", "anchor", "template", "created_at",
"updated_at"}. `template` is the sanitized markup as submitted (up to 200 KB) —
the compiled blueprint the backend renders from is not returned. To change the
format, draft again and pass the chosen variant to `update_user_template`
rather than editing this text blind.
An HTTP 404 means no template is saved — the standard layouts are in force. An
HTTP 503 means the backend's user_templates table has not been created yet, NOT
that nothing is saved; report that difference.
Requires auth (your MCP client attaches the OAuth bearer automatically).
Rate-limited 100/min.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| anchor | No | Section an add_on applies to; null for bespoke. |
| template | No | The sanitized markup as submitted (up to 200 KB). |
| created_at | No | |
| updated_at | No | |
| template_type | No | "add_on" or "bespoke". |
| template_format | No | "html". |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=true; the description adds substantial context beyond that: the 404-vs-503 semantic distinction, the auth requirement, the 100/min rate limit, the fact that save replaces without history, and that the returned template is sanitized markup capped at 200 KB while the compiled blueprint is withheld.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the return value and the primary usage trigger, then layers routing guidance and edge cases. Most sentences earn their place, though the enumerated Returns listing partially duplicates the output schema and could be trimmed slightly.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given an output schema exists, return values needn't be spelled out, yet the description adds the useful nuance that the compiled blueprint is not returned and the 200 KB cap. Combined with auth, rate-limit, and error-code semantics, nothing an agent needs to call this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is nothing for the description to disambiguate; baseline 4 applies. No parameter detail is needed or missing.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource (returns the user's saved PDF template) and immediately distinguishes it from sibling tools like save_user_template, draft_user_template, and update_user_template. The one-line opener plus the 404 case makes the tool's identity unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly names three triggering scenarios (answering 'what format am I on?', before save_user_template because saving replaces without history, and before composing a PDF so the markup matches). It also names alternatives (draft_user_template, update_user_template) and gives the conditional cue that a 404 is the signal to offer drafting.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
is_market_openARead-onlyInspect
Check whether an exchange is currently open — a cheap routing helper.
An unknown or wrong-case code returns a 400 "Exchange not found." error.
Returns `exchanges`, a one-element list; the answer is its `isMarketOpen` boolean.
The record also carries the session hours (`openingHour`/`closingHour` with UTC
offsets), `timezone`, and any additional-session bounds.
Use it to route between the market-hours tools: when the market is CLOSED,
extended-hours data lives in `get_aftermarket_data`;
when OPEN, `detect_intraday_outlier_jumps` gives the live intraday read.
No auth required.
Unsure which exchange a ticker trades on? `get_company_snapshot` returns an
`exchange` field whose value can be passed here as-is.
| Name | Required | Description | Default |
|---|---|---|---|
| exchange | No | CASE-SENSITIVE uppercase exchange code, e.g. "NYSE", "NASDAQ", "LSE" (not full names). NYSE is right for US equities. | NYSE |
Output Schema
| Name | Required | Description |
|---|---|---|
| exchanges | Yes | One record for the requested exchange; read its isMarketOpen. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=true; the description adds real behavioral context: unknown/wrong-case codes yield a 400 'Exchange not found.', no auth is required, and it discloses the return shape (one-element list, isMarketOpen boolean, session hours, timezone).
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the core purpose and the error contract, then the routing guidance, then the code-sourcing tip. Multi-line but every sentence carries distinct, actionable information with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covered despite an existing output schema: error behavior, auth, routing, and parameter pitfalls are all addressed. Nothing an agent needs to call this correctly or act on the result is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% (baseline 3), and the description goes further by stressing the case-sensitivity pitfall, that full names are invalid, and that NYSE is the right default for US equities, plus how to source the value from get_company_snapshot.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('check whether an exchange is currently open') and distinguishes itself from market-hours siblings as a 'cheap routing helper'. An agent immediately knows this is a lightweight status probe rather than a data-fetch tool.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit routing rules: when CLOSED, use get_aftermarket_data; when OPEN, use detect_intraday_outlier_jumps. It also handles the prior-step question of how to get a valid exchange code via get_company_snapshot.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_available_reportsARead-onlyInspect
List the symbols with a report plan SAVED on or after report_date (default: TODAY) —
the real-time research get_latest_report can render right now, and whether each renders
in seconds or needs a rebuild.
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).
| Name | Required | Description | Default |
|---|---|---|---|
| event_types | No | Plan-earning event types to list: eps_update, eps_release, 8k_release, financials_release, ir_publication, transcript_update, company_update. Any other type is a 422. Omit for every type. | |
| report_date | No | Lower bound on when the plan was built, YYYY-MM-DD (default today). Earlier dates widen the window and cost more; plans stay renderable for 7 days. A malformed date is a 422. |
Output Schema
| Name | Required | Description |
|---|---|---|
| plans | Yes | Saved report plans in the window, newest first. Empty means nothing was planned in the window. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnlyHint annotation, it discloses that it does not build/return reports, rate limit (500/hour), synchronous behavior, auth requirement, the meaning of an empty result, the redis-vs-s3 source distinction, and the fresh/stale render semantics. This is well past what the annotation alone conveys.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded and the body is organized under clear headers (TWO WAYS IN, PICKING THE MOST PERTINENT PLANS). It is on the verbose side with some redundancy in the workflow narrative, but nearly every sentence carries routing or behavioral information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers auth, rate limits, error conditions, the empty-result edge case, and the full decision flow from event to plan to pull, despite an output schema already existing. An agent has everything needed to call it correctly and interpret the response.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema documents both params, but the description adds meaningful semantics: report_date is a lower bound defaulting to today, earlier dates widen the window and cost more, and plans stay renderable for 7 days. It also enumerates the valid event_types and the 422 failure mode.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening sentence states a specific verb and resource — 'List the symbols with a report plan SAVED on or after report_date' — and immediately scopes it as an inventory that does not build or return a report. It explicitly differentiates from the two nearest siblings, get_latest_report and generate_research_report.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides two named entry paths (event-first vs research-first), tells the agent when to widen report_date, when to use list_realtime_events first, and when generate_report_for_stock is the correct follow-up. Explicit exclusions ('Not get_latest_report... Not generate_research_report') remove ambiguity about alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_earnings_announcementsARead-onlyInspect
List scheduled earnings announcements within a date window, Flexreport names only.
Omit both dates for "who reports today". Results are restricted to Flexreport's
covered universe, so symbols outside coverage are dropped silently.
The optional filters are AND-ed together. `sector`, `industry`, and `market_cap` are
validated against fixed enums server-side; invalid values return a 422, so source them
from the tools named in their descriptions rather than guessing.
Returns `announcements` (empty list when nothing matches); values are strings and
"nan" means not available yet.
Requires auth (your MCP client attaches the OAuth bearer automatically).
| Name | Required | Description | Default |
|---|---|---|---|
| sector | No | Sector values from list_options("sectors"). | |
| symbols | No | Limit to these tickers, e.g. ["AAPL","MSFT"]. | |
| end_date | No | Window end, YYYY-MM-DD; defaults to today. Other formats return 422. | |
| industry | No | Industry values from list_sub_industries([...]). | |
| market_cap | No | Market-cap buckets: "Small-cap", "Medium-cap", "Large-cap", "Mega-cap". | |
| start_date | No | Window start, YYYY-MM-DD; defaults to today. Other formats return 422. |
Output Schema
| Name | Required | Description |
|---|---|---|
| announcements | Yes | Scheduled reports in the window; empty when nothing matches. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond readOnlyHint by disclosing silent dropping of out-of-coverage symbols, server-side enum validation returning 422, the AND-combination of filters, empty-list-on-no-match, and that "nan" means not available. This is rich behavioral context an agent needs.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the core action, then layers date-window defaults, coverage caveats, and validation notes in short, scannable sentences. Every sentence carries distinct information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 6-param read tool with an output schema, the description covers the missing pieces: date defaults, silent filtering, enum validation, auth, and the "nan" convention. Nothing needed to call it correctly is absent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds real meaning: dates default to today, filters combine with AND, and invalid enum values trigger 422. That goes beyond what the schema properties state individually.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (List), resource (scheduled earnings announcements), and scope (within a date window, Flexreport names only). An agent can immediately distinguish this from predict_earnings_move or get_company_event_web.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives concrete when-to-use guidance ('Omit both dates for "who reports today"') and warns the filters are AND-ed. It also routes the agent to list_options/list_sub_industries for valid enum values. It stops short of naming an alternative tool for overlapping needs, but the context is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_optionsARead-onlyInspect
Enumerate the valid values for a parameter, straight from the backend.
Call this BEFORE guessing a parameter value. `kind` selects which catalog; three
kinds are scoped by a query parameter (`ticker`, or `q` / `cik`) and refuse the call
without it:
- "event_types" -> valid `event_type` for `list_realtime_events`
(eps_update, company_update, biggest_mover, ...)
- "financial_items" -> standardized EDGAR line items ("revenue",
"operatingIncome") for a CUSTOM report's
`financial_items` (`generate_report_for_stock`,
or a scheduled "create-full-report" step)
- "financial_ratios" -> EDGAR ratios ("grossProfitMargin") for that
report's `ratios`
- "as_reported_items" -> NEEDS `ticker`. The filer's OWN tagged XBRL
concepts from its 10-Q / 10-K filings — {concept,
statement_type, label, standard_concept,
latest_period, facts} — for a custom report's
`as_reported_financial_items`
- "revenue_segments" -> NEEDS `ticker`. The filer's revenue segments as
tagged in its filings — {product_label,
product_member, product_axis, concept,
latest_period, facts} — for a custom report's
`revenue_segment` (pass the product_label).
A name lookup only: never sum members across it
- "institutional_managers" -> NEEDS `q` (name fragment, e.g. "berkshire")
and/or `cik` (SEC CIK, any width). Managers as
{cik, name, category, aum}, largest AUM first —
pass the `cik` values as a custom report's
`institutional_ownership`, never the names
- "sectors" -> valid `sector` filter values
- "institutional_investor_types" -> investor CATEGORIES (not managers) — the keys
`screen_stocks(institutional_ownership=...)`
filters on
- "countries" -> covered countries
- "fiscal_quarter" -> the most recent fiscal quarter being reported
- "market_cap" -> valid `market_cap` buckets (Small-cap,
Medium-cap, Large-cap, Mega-cap)
- "intraday_frequency" -> supported intraday chart frequencies
- "technical_indicators" -> indicator names accepted by
`get_technical_indicator_data` (rsi, macd,
sma_50, ...); an unknown indicator there
returns a 400 listing this set
- "tickers" -> the full covered symbol universe as bare
symbols — equities PLUS ~420 market indices
as caret-prefixed symbols (^GSPC, ^VIX, ...).
NOTE: thousands of names — a large payload
- "tickers_with_names" -> {symbol, company_name} pairs for the company
universe ONLY — market indices are NOT in
this list, only in "tickers" (an even larger
payload)
Returns `options` (the values for that kind). Authoritative and never stale: it
reads the backend's live config, not a hardcoded list. Public — no auth required.
| Name | Required | Description | Default |
|---|---|---|---|
| q | No | Manager name fragment, e.g. "berkshire" (institutional_managers). | |
| cik | No | SEC CIK, any width, e.g. "1067983" (institutional_managers). | |
| kind | Yes | Which catalog to list; see the kinds below. | |
| ticker | No | Filer ticker, e.g. "AAPL". Required for as_reported_items and revenue_segments. |
Output Schema
| Name | Required | Description |
|---|---|---|
| kind | Yes | The catalog that was listed. |
| options | Yes | The valid values. Usually a list — bare strings for most kinds, records for event_types, tickers, tickers_with_names, as_reported_items, revenue_segments and institutional_managers. fiscal_quarter is a single quarter number. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=true, but the description adds material behavior beyond that: it is authoritative because it reads live backend config (never stale), it is public with no auth required, it enumerates rejection behavior for the query-scoped kinds, and it warns about payload size for tickers/tickers_with_names. That is substantially more than the annotation provides.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the key imperative and organized as a scannable bulleted catalog, with no filler sentences. It is nonetheless a very long block, which is largely forced by the 15 enum values but does weigh on context budget for a lookup tool.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return-value documentation is not required, and the description still notes the returned `options` field. Combined with the per-kind routing, conditional-parameter rules, and payload/auth notes, all information needed to call it correctly is present.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Although schema coverage is 100%, the description goes well beyond the schema's flat enum: it defines the semantic content of each kind (e.g. financial_items vs as_reported_items, managers-as-CIKs vs investor categories), states the conditional requirement of ticker/q/cik per kind, and prescribes how returned values must be passed downstream.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource — enumerate the valid values for a parameter from the backend — and immediately frames the tool as a pre-flight lookup rather than a data-fetch. An agent can distinguish it from siblings like list_realtime_events or generate_report_for_stock because the description says this tool supplies the values those tools consume.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly instructs 'Call this BEFORE guessing a parameter value,' names which kinds require the ticker/q/cik qualifiers and that they refuse without it, and routes every kind to the consuming tool/parameter (e.g. event_types -> list_realtime_events, institutional_managers -> a report's institutional_ownership). This is exactly when/when-not/alternatives guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_realtime_eventsARead-onlyInspect
Pull live market events from the backend's Redis-backed cache (12h TTL).
===> Call `situate(...)` FIRST (symbols=[...] for named companies, none for the
market): its `cache.present` / `cache.expired` say which types this tool can
still return, its `plan` carries the exact calls to make, and its `skip` list
names the ones that would return [] — an event older than the 12h cache lives
in the ontology card's `persisted_in` relation, not here. Never call this for a
type situate marked expired. `list_options("event_types")` remains the
enumeration of valid type strings and descriptions. `event_type` is REQUIRED and
has no default on purpose: the type is the whole question, and a default
would answer a different one (eps_update is one slice of the earnings
family, not the family).
Then CONNECT THE DOTS: fetch the type asked about and follow the situation
across its related_events with follow-up calls narrowed by `tickers=[...]`
to the symbols just seen — e.g. eps_update -> check the intraday tape
(detect_intraday_outlier_jumps) -> 8k_release -> ir_publication. One hop
answers most questions; two covers a full earnings cycle. An unfiltered
follow-up call re-pulls the whole cache.
Returns `events`, a list of event objects (keys vary by type). An EMPTY list
means the cache is cold for that event type (12h TTL), not that nothing happened.
A material event here (eps_update, eps_release, 8k_release, financials_release,
ir_publication, transcript_update) means a report plan was saved for the symbol:
`list_available_reports(event_types=[<this type>])` says which of them
get_latest_report renders fresh in seconds.
Requires auth (your MCP client attaches the OAuth bearer automatically).
| Name | Required | Description | Default |
|---|---|---|---|
| sector | No | Sector values from list_options("sectors"). | |
| tickers | No | Narrow to these tickers; always set on follow-up calls (an unfiltered call re-pulls the whole cache). | |
| industry | No | Industry values from list_sub_industries([...]). | |
| event_type | Yes | REQUIRED realtime event type from list_options("event_types"), e.g. "eps_update", "8k_release", "ir_publication". | |
| market_cap | No | Market-cap buckets, e.g. ["Large-cap", "Mega-cap"]. |
Output Schema
| Name | Required | Description |
|---|---|---|
| events | Yes | Cached events of the requested type. Empty means the 12h cache is cold for that type, not that nothing happened. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only supply readOnlyHint=true, so the description carries the behavioral load and does so richly: 12h cache TTL, that an EMPTY list means a cold cache rather than no event, that older events live in the ontology card's persisted_in relation, auth requirements, and material-event side effects on report plans.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core purpose and the critical situate-first constraint, and the workflow, return semantics, and auth note follow in a logical order. It is dense and longer than typical, but nearly every sentence carries operational weight for a multi-step tool, with only mild redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Although an output schema exists, the description still clarifies the empty-list meaning, which is essential context. Combined with auth, cache lifetime, and the chained-call workflow, an agent has everything needed to invoke this correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema documents all five params and a baseline 3 applies. The description nonetheless adds real meaning beyond the schema: why event_type is REQUIRED with no default (a default would answer a different question), and that tickers should always be set on follow-up calls to avoid re-pulling the whole cache.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Pull live market events from the backend's Redis-backed cache') plus the distinguishing constraint (12h TTL). It clearly separates this tool from siblings like situate, get_event_ontology, and list_available_reports, which are named and given explicit roles.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit routing: call situate FIRST, never call for a type situate marked expired, use list_options('event_types') for the enumeration, and follow up on related_events narrowed by tickers. It even states when an empty result is expected versus meaningful, leaving nothing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_saved_queriesARead-onlyInspect
List the data requests you have saved with save_user_query, newest first.
The entry point to the replay flow: check HERE FIRST, before running
`explore_data_catalogue` for any exploration question — a saved row that matches
the question, exactly OR in shape, means the answer is seconds away via
`run_saved_query` instead of a ~1-5 minute planning job.
Returns {"count": N, "saved_queries": [{"id", "user_request", "queries",
"query_placeholder", "metadata", "created_at", "updated_at"}, ...]}, the calling
user's rows only.
MATCH ON `metadata`, NOT ON THE LABEL. `metadata` describes what the row actually
asks. It is authored after the save and is null until the placeholder task has run
(roughly 10 s to 5 minutes, depending on the size of the queries):
`summary` one line with the slots in braces, e.g. "13F positions of
{managers} in {symbol}, {date_prior} vs {date_latest}: shares,
value, weight, QoQ change"
`parameters` [{name, type, description, example}] — the slot schema, one
vocabulary across every query in the row. These names are the
keys of `run_saved_query(values=...)`.
`entities` {slot: resolved example} — what the row was saved for
`datasets` the public dataset names the row reads (the same names
`explore_data_coverage` reports)
`topics` classifier topics for the saved request
`result_schema` [{index, summary, slots, columns}] — per query, what its result
set holds
`stale` true when a query no longer plans (checked nightly)
`run_count`, `last_run_at`
Match the user's question against `summary` + `parameters` + `datasets`, NOT
against `user_request` — that is only the label the user typed while saving. SKIP
any row marked `stale: true`. For a row whose `metadata` has not landed yet, fall
back to the label and replay `queries` exactly.
Having picked a row:
- EXACT repeat (same entities, same window) -> `run_saved_query(query_tokens=
<the row's `queries`>)`; it replays as saved.
- SAME SHAPE, other values (saved "the past 8 quarters of sales for TGT"; asked
"KSS's last 8 quarters of sales") -> `run_saved_query(query_tokens=<the row's
`query_placeholder`>, values={...})`, the values keyed by
`metadata.parameters`; add a `prompt` only for slots you cannot type.
- Pick WHICH of the row's queries to run from `result_schema`: the ones that
answer the question, leaving the `_constituents` companion out — it is a
7,000-35,000 row payload. Pass `max_rows` (e.g. 500) whatever you run.
- TELL THE USER which saved row is being reused (its `summary` and `entities`)
and which values were substituted (the replay's `parameters`).
A row that is merely close in TOPIC but asks a different thing is a DIFFERENT
question; confirm with the user before replaying it.
The other fields:
- `queries` is the list of opaque query tokens for an exact replay.
- `query_placeholder` is the list of placeholder-twin tokens, index-aligned with
`queries`, or null while the placeholder task has not run yet (replay
`queries` exactly or list again shortly). Never show a token of either kind to
the user: it is ciphertext, not content, and says nothing about what the query
does.
- `user_request` is the user's own label — worth quoting when you say which row
you reused, but not what to decide on.
- `id` is what `delete_saved_query` takes.
Duplicate `user_request` values are possible — saving does not upsert.
An HTTP 503 here means the backend's saved-queries table has not been created yet,
NOT that the user has nothing saved — report that difference rather than an empty
list.
Requires auth (your MCP client attaches the OAuth bearer automatically).
Rate-limited 100/min.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max rows to return, newest first. |
Output Schema
| Name | Required | Description |
|---|---|---|
| count | Yes | |
| saved_queries | Yes | The calling user's saved rows, newest first. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=true, but the description adds substantial behavioral context: the full return shape, that rows are the calling user's only, the metadata-not-label matching rule, null-until-landed metadata with a 10s-5min window, stale-row skip logic, HTTP 503 meaning, auth requirement and a 100/min rate limit. This goes well beyond what the annotation provides.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Well front-loaded (the 'check HERE FIRST' directive comes before all detail) and organized with bulleted sections. However, it is very long and devotes substantial space to the downstream run_saved_query replay procedure and metadata field anatomy, which strains the size appropriate for a one-parameter list tool.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Despite an output schema existing, the description fully describes the return payload and every metadata field, plus edge cases (503, stale rows, null placeholder, duplicate user_request). Nothing an agent needs to act on the results is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% for the single `limit` parameter, so the schema already documents it fully. The description adds no additional semantics for `limit` (its 'max_rows' guidance applies to run_saved_query, not this tool). Baseline 3 is appropriate when the schema carries the parameter semantics.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb+resource: 'List the data requests you have saved with `save_user_query`, newest first,' and explicitly names the sibling tool that created the rows. An agent can immediately distinguish this from explore_data_catalogue or run_saved_query.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Unusually explicit routing: it tells the agent to 'check HERE FIRST, before running explore_data_catalogue,' and contrasts the saved-query replay (seconds) against a '~1-5 minute planning job.' It also names exact-repeat vs same-shape alternatives and their conditions, plus the caveat to confirm with the user when a row is merely topic-close.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_scheduled_tasksARead-onlyInspect
List the caller's scheduled tasks (cron jobs created via schedule_task).
Returns `tasks`, only the authenticated user's jobs, each as
{"name", "active", "schedule" (cron string), "args", "kwargs", "enabled",
"last_run_at", "total_run_count"}. Workflow schedules are named
"wf:{email}:{workflow-name}". Use `name` as the key to remove a job with
`delete_scheduled_task`.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| tasks | Yes | The caller's scheduled tasks; empty when there are none. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only supply readOnlyHint=true; the description adds the meaningful scoping fact that results are limited to the authenticated user's jobs and that workflow schedules follow a 'wf:{email}:{workflow-name}' naming convention. No pagination or ordering behavior is disclosed, but the scoping context is genuine added value.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the purpose, then the return shape, then the delete routing. The enumerated return-field list is somewhat redundant given an output schema exists, but the overall structure is tight and purposeful.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given an output schema exists, the return-value enumeration is more than sufficient, and the read-only scoping plus the sibling routing cover what an agent needs to call it correctly. Nothing critical is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so the schema carries no semantics to compensate for. The description does not need to explain parameters, and the baseline for a no-param tool applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('List the caller's scheduled tasks') and clarifies the resource is cron jobs created via `schedule_task`. It distinguishes itself from the many other list_* and delete_* siblings clearly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes the agent to `delete_scheduled_task` and tells it to use the `name` field as the key for removal, which is actionable usage guidance. It doesn't state when-not to use it or contrast with other listing tools, so it stops short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_sub_industriesARead-onlyInspect
List the sub-industries within one or more sectors.
Returns `industries`, the distinct industries used to narrow
`list_realtime_events(industry=[...])`.
| Name | Required | Description | Default |
|---|---|---|---|
| sectors | Yes | Sector values from list_options("sectors"), e.g. ["Technology"]. |
Output Schema
| Name | Required | Description |
|---|---|---|
| industries | Yes | Distinct industries within the requested sectors, for list_realtime_events(industry=[...]). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The readOnlyHint annotation already covers the safety profile, and the description's added detail (result key name, distinctness, downstream linkage) is largely duplicated by the output schema. No edge-case or failure behavior (e.g., unknown sector values) is disclosed, but the annotation bar makes this adequate.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, front-loaded with the action and following with the return linkage; nothing is padded. The return-detail sentence is partly redundant with the output schema, which keeps it from being flawless.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple one-parameter read tool with an output schema and a readOnlyHint, the definition covers what the tool does and how its output chains into list_realtime_events. Only the upstream call ordering (list_options first) is left implicit.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With a single parameter at 100% schema description coverage, the schema already explains that sectors are drawn from list_options("sectors"). The description only echoes the "one or more sectors" cardinality and adds no syntax or format detail beyond the schema, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource (list sub-industries) scoped to "one or more sectors", so the agent knows exactly what comes back. It does not explicitly contrast with the closest sibling, list_options, which is where sectors themselves come from, so it stops short of full sibling differentiation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives the downstream purpose of the result (narrowing list_realtime_events(industry=[...])) and the schema notes sectors come from list_options("sectors"), which implies the workflow. However there is no explicit when/when-not guidance or statement of which tool to call first versus this one.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
manage_billingAInspect
Get a link to the Stripe billing portal where the user can view invoices, update their card, or cancel their subscription. Use when the user asks to manage, change, or cancel their billing/subscription.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| url | No | The browser link; null when it could not be generated. |
| usage | No | Current plan usage (upgrade_plan only, when known). |
| message | Yes | Ready-to-show markdown for the user, including the link when there is one. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare readOnlyHint=false and destructiveHint=false, which is somewhat confusing for a tool that only returns a link; the description resolves this by explaining the actual mutating actions (updating card, cancelling) happen in the external Stripe portal, not here. That is meaningful added context beyond the annotations. It doesn't cover auth requirements or rate limits, hence not a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, zero waste. The 'what it does' sentence comes first, followed by the routing condition. Every clause earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so the return value (the portal link) need not be re-explained, and the description correctly focuses on purpose and routing. The only gap is the missing differentiation from upgrade_plan for plan-change requests.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is nothing for the description to clarify; baseline is 4. No spurious argument discussion is present, which is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb+resource: 'Get a link to the Stripe billing portal', with concrete scope (view invoices, update card, cancel subscription). An agent immediately knows this returns a URL, not a modification. It does not distinguish itself from the sibling upgrade_plan, which is the one adjacent tool a user query could plausibly route to.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit trigger condition: 'Use when the user asks to manage, change, or cancel their billing/subscription.' This is clear routing guidance, but it gives no exclusion against upgrade_plan, which is the obvious alternative for plan-change requests.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
onboard_symbolAInspect
Request onboarding of a NOT-yet-covered ticker (mutating, authenticated).
Kicks off a 30-60 min backend workflow and emails the authenticated user when
the first report is ready. Rate-limited to 5/hour per user. Use only when a
symbol is missing from `list_options("tickers")` / returns no data elsewhere.
Returns {"task_id": ..., "status": "PENDING"}.
| Name | Required | Description | Default |
|---|---|---|---|
| symbol | Yes | The ticker to onboard, e.g. "IMCR". |
Output Schema
| Name | Required | Description |
|---|---|---|
| status | Yes | PENDING on submission. |
| task_id | Yes | Onboarding request id; the user is emailed when the first report is ready. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations (readOnlyHint=false, destructiveHint=false): it discloses mutating+authenticated nature, a 30-60 min asynchronous backend workflow, email notification on completion, a 5/hour per-user rate limit, and the initial return shape. These are exactly the operational facts an agent needs before invoking an async, rate-limited mutation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four tight sentences, front-loaded with the mutating/authenticated warning, then timing, rate limit, usage condition, and return. Every sentence earns its place with no redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Despite an output schema existing, the description still states the initial return ({"task_id": ..., "status": "PENDING"}) and covers the async lifecycle, rate limits, and prerequisites. Nothing an agent needs to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the single required "symbol" parameter is fully documented (including an "IMCR" example) in the schema itself. The description adds no syntax or format detail beyond what the schema already provides, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ("Request onboarding of a NOT-yet-covered ticker") and scopes it to symbols not yet covered, immediately distinguishing it from report/listing siblings like list_options and generate_report_for_stock.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly names the trigger condition ("Use only when a symbol is missing from list_options("tickers") / returns no data elsewhere") and routes the agent to the alternative check first. This is a textbook when-to-use rule.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
optimize_portfolioAInspect
Build a risk-optimized portfolio from a non-empty list of tickers.
Scores `symbols` with the multi-signal scorer, LLM-curates, and risk-optimizes.
Rate-limited to 10/hour
per user server-side.
Asynchronous: returns {"task_id": ..., "status": "PENDING", "supported": [...],
"not_supported": [...]}. Poll `task_id` with `get_task_status` until SUCCESS.
| Name | Required | Description | Default |
|---|---|---|---|
| symbols | Yes | Tickers to score and optimize, e.g. ["AAPL", "MSFT", "JNJ"]. | |
| delivery | No | Result channel: "dashboard" (returned via get_task_status) or "email". | dashboard |
| risk_tolerance | No | Which risk profile is marked as recommended; omit for the optimizer default. |
Output Schema
| Name | Required | Description |
|---|---|---|
| status | Yes | PENDING on submission. |
| task_id | Yes | Poll with get_task_status until SUCCESS. |
| supported | No | Tickers that will be scored and optimized. |
| not_supported | No | Tickers outside Flexreport coverage, ignored. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations are thin (readOnlyHint=false, destructiveHint=false), and the description carries the load well: it discloses a server-side rate limit of 10/hour per user and that execution is asynchronous with a PENDING task handle. It does not explain what happens to in-flight tasks or whether the submission itself is billable, but the behavioral picture is substantially better than the annotations alone.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core purpose and no filler sentences; the rate limit and async contract are stated compactly. The hard line breaks mid-sentence ('Rate-limited to 10/hour / per user server-side') hurt readability slightly but nothing is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given an output schema exists, the description need not explain return fields, yet it usefully describes the async PENDING payload and the supported/not_supported lists up front. Combined with rate-limit and polling instructions, the only meaningful omission is any differentiation from `optimize_portfolio_default`.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all three parameters (symbols, delivery, risk_tolerance) are already documented in the schema, including enum choices and default. The description only echoes the scoring/optimization role of `symbols` and adds no syntax or constraint detail beyond minItems that the schema already states.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Build a risk-optimized portfolio') and enumerates the internal pipeline (multi-signal scoring, LLM curation, risk optimization). It distinguishes itself from most siblings, but never contrasts with the obvious sibling `optimize_portfolio_default`, which an agent could easily confuse it with.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives real operational guidance for the async flow ('Poll `task_id` with `get_task_status` until SUCCESS') and implies the input requirement ('non-empty list of tickers'). It does not say when to pick this over `optimize_portfolio_default`, so sibling selection is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
optimize_portfolio_defaultARead-onlyInspect
Build a risk-optimized portfolio from a list of tickers — fast, synchronous, no LLM.
THE DEFAULT optimizer route. Returns the result directly and almost instantly
(no task id, no polling). Reach for `optimize_portfolio` instead only when you
explicitly want the slower LLM-curated variant layered on top of the optimizers.
Symbols are validated against the covered universe; unsupported tickers come back
in `missing`, and in-universe tickers with too little price history come back in
`dropped`.
No auth required (public endpoint).
Synchronous. Returns:
{"status": "OK", # or "SKIPPED"/"EMPTY" when too few usable symbols remain
"holdings": [{"symbol", "source_strategies", "summary", "conviction_level"}, ...],
"optimizer_results": {"mvo": {...weights+diagnostics}, "hrp": {...}, "mcvar": {...}},
"risk_profiles": {"profiles": [...], "recommended": "..."}, # present only when status == "OK"
"dropped": [...], # in-universe but insufficient price history
"missing": [...]} # not in the covered universe
| Name | Required | Description | Default |
|---|---|---|---|
| symbols | Yes | Tickers to optimize, e.g. ["AAPL", "MSFT", "JNJ"] (see list_options("tickers")). | |
| risk_tolerance | No | Which risk profile is marked as recommended; omit for the optimizer default. |
Output Schema
| Name | Required | Description |
|---|---|---|
| reason | No | Why the run was SKIPPED. |
| status | Yes | OK, or SKIPPED / EMPTY when too few usable symbols remain. |
| dropped | No | In-universe tickers with insufficient price history. |
| missing | No | Tickers not in the covered universe. |
| holdings | No | The usable holdings that were optimized. |
| max_weight | No | Per-name weight cap the optimizers applied. |
| risk_profiles | No | {profiles: [{risk_profile, method, description, diagnostics, allocation}], recommended}; present only when status is OK. |
| optimizer_results | No | Per optimizer (mvo, hrp, mcvar): weights plus diagnostics. Empty unless OK. |
| lookback_trading_days | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only supply readOnlyHint, and the description adds substantially beyond that: synchronous execution with no task id or polling, no auth required on a public endpoint, symbol validation against a covered universe, and status semantics (OK/SKIPPED/EMPTY) for degenerate inputs. This is real behavioral disclosure the structured fields do not carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the purpose and the sibling disambiguation in the first two sentences, followed by only the constraints an agent needs. The layout is scannable and no sentence is filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a synchronous, 2-parameter public endpoint, the description covers routing, execution model, auth, and error semantics; with an output schema present it need not have restated the return shape, so nothing required is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3, but the description adds meaning the schema lacks: symbols are validated against a covered universe, with unsupported tickers surfacing in `missing` and low-history tickers in `dropped`. It says nothing extra about `risk_tolerance`, which the schema already documents well.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
"Build a risk-optimized portfolio from a list of tickers" states a specific verb and resource, and the definition explicitly positions itself as "THE DEFAULT optimizer route" versus the `optimize_portfolio` sibling. An agent can distinguish the two tools without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It names the alternative explicitly ("Reach for `optimize_portfolio` instead only when you explicitly want the slower LLM-curated variant") and gives the exact condition that selects it. When-to-use and when-not-to-use are both spelled out.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
predict_earnings_moveARead-onlyInspect
Predict how big a stock's move will be when it next reports earnings. For each symbol, returns
its next earnings date (today or later) and `expected_move`: the expected absolute move of the
reaction session as a log return (0.05 is about 5%; size only, no direction). For context,
`hist_move_mean` / `hist_move_n` give the stock's own average reaction over its past reports and
how many reports that covers. Symbols with no scheduled report come back in
`no_upcoming_earnings_symbols`; uncovered tickers in `not_supported_symbols`.
| Name | Required | Description | Default |
|---|---|---|---|
| symbols | Yes | Tickers to score, e.g. ["AAPL", "NVDA"]. |
Output Schema
| Name | Required | Description |
|---|---|---|
| predictions | Yes | One prediction per covered symbol with a scheduled report. |
| not_supported_symbols | Yes | Requested tickers outside Flexreport coverage. |
| no_upcoming_earnings_symbols | Yes | Covered tickers with no scheduled report. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint, so the description carries most of the burden and does well: it explains the returned fields (`expected_move` units and semantics, `hist_move_mean`/`hist_move_n` scope) and the two partition buckets for no-data symbols. It doesn't mention latency, rate limits, or coverage limits on historical depth, keeping it short of a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core purpose, then scoped precisely around output fields and edge cases in a tight block. Slightly dense with backticked field names, but every sentence carries information and there is no padding.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return-value explanation is optional, yet the description goes further by defining units, direction semantics, historical context fields, and edge-case buckets — everything an agent needs to interpret and route results correctly. No gaps remain for a single-parameter read tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Only one parameter with 100% schema description coverage, so the baseline is already high. The description adds value by clarifying that each symbol returns per-symbol results and what happens to symbols without scheduled earnings, which the schema alone does not convey.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (predict) and resource (post-earnings move) with the exact metric being returned (`expected_move` as a log return, size only, no direction). No sibling tool does anything similar — the closest neighbors are earnings announcements listing (`list_earnings_announcements`) and generic stock data, and this is clearly distinguishable from both.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage context is implied by naming the input (symbols) and outputs, but there is no explicit 'use this when vs. list_earnings_announcements' guidance or exclusions. The description covers behavior thoroughly but never tells the agent when this is the right tool over alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
register_event_subscriptionAInspect
Save a realtime-event filter server-side and get a subscription_id whose
stream resumes where the last read stopped (POST /register-subscription).
For a live-streaming ask, the default is a dashboard (in Claude, an Artifact) that
loops stream_events itself — see stream_events. Register a subscription when the
user wants a saved filter that resumes across sessions.
Returns {subscription_id, filter, cursor, created_at}. `filter` echoes the
normalised filter (topics lower-cased, symbols upper-cased, duplicates dropped);
`cursor` is the position the subscription starts from — only events published
AFTER registration are ever delivered. KEEP the subscription_id: there is no list
endpoint yet, and it is what stream_event_subscription and
delete_event_subscription take.
`topics` / `symbols` as in stream_events: event types and families from
list_options("event_types") plus the stream-only `report_plan` topic; an empty
body listens to everything. Same vocabulary rules — `report_plan` for "stream
full research as it is minted", a family for "everything earnings-related",
symbols for a watchlist. 30 registrations/hour per user; delete what you no
longer need. The stream keeps ~2,000 entries (several days at current volume): a
subscription idle longer than that resumes at the oldest entry and may have
missed events.
Requires auth (your MCP client attaches the OAuth bearer automatically).
| Name | Required | Description | Default |
|---|---|---|---|
| topics | No | Event types or families from list_options("event_types") (e.g. "eps_update", "earnings"), plus the stream-only "report_plan"; case-insensitive. Omit for every topic. | |
| symbols | No | Tickers to listen for (13f_* filer events carry the filer's CIK in the symbol slot). Omit for every symbol. |
Output Schema
| Name | Required | Description |
|---|---|---|
| cursor | No | Stream position the subscription starts from (events after registration). |
| filter | Yes | The normalised filter that was saved. |
| created_at | No | |
| subscription_id | Yes | Keep it: stream_event_subscription and delete_event_subscription take it. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only mark it non-read-only and non-destructive; the description carries the real behavioral load: cursor semantics ('only events published AFTER registration are ever delivered'), a 30 registrations/hour rate limit, the ~2,000-entry retention window and what happens to an idle subscription, plus auth via the MCP client's bearer. That is well beyond what the annotations disclose.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the verb, resource and return value in a single bolded opening sentence, then layers usage, return shape, vocabulary and limits. It is long and slightly repetitive — it restates list_options("event_types") guidance already present in the schema — but nearly every sentence adds operational value rather than padding.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Although an output schema exists, the description still supplies what matters for correct invocation: the return shape, the persistence of subscription_id (no list endpoint), which tools consume it, auth, rate limit, and the resumption/retention caveat. Nothing needed to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds usable semantics: empty body listens to everything, the vocabulary rules (report_plan as 'stream full research as it is minted', a family for 'everything earnings-related', symbols for a watchlist), and the filter-normalisation behaviour (topics lower-cased, symbols upper-cased, duplicates dropped).
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Save a realtime-event filter server-side') and the artifact produced (`subscription_id`), plus the underlying endpoint. It explicitly differentiates itself from the siblings stream_events, stream_event_subscription and delete_event_subscription, so an agent can pick it without opening another schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit alternative and the condition that selects it: 'For a live-streaming ask, the default is a dashboard... that loops stream_events itself — see stream_events. Register a subscription when the user wants a saved filter that resumes across sessions.' When-to-use and when-not-to-use are both stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
run_saved_queryARead-onlyInspect
Re-run a saved request's queries against live data — exactly, or re-aimed at other entities with typed values. No planning, no polling.
The payoff of `save_user_query`: pass a saved row's `queries` array from
`list_saved_queries` and each stored query runs as-is, returning fresh rows
synchronously. Use this INSTEAD of `explore_data_catalogue` whenever a saved row
already covers the question — same SQL, current data, seconds instead of minutes,
and it does not draw on the 20/hour exploration budget.
A full signed URL is accepted in `query_tokens` and unwrapped. For a token
that came from a `get_company_event_web` node rather than a saved row, use
`get_signed_sql_drilldown` — same endpoint, single node, drilldown framing.
`values` slots are substituted deterministically, with no language model in the
loop (~0.5-1.2 s per query). Reach for it whenever you already know the entities —
you usually do, having resolved the tickers or CIKs before calling — and keep
`prompt` for what you cannot type.
- Entity-set slots (type `cik_rows` / `symbol_rows`) take a LIST of {"id",
"name"} objects: [{"id": "0001454027", "name": "Verition Fund Management LLC"}].
A name-only entry ({"id": "", "name": "Walleye Capital"}) is resolved
server-side against the filer registry; a name it cannot resolve comes back as
a 422, never as a guess.
- Pass the SAME dict to every token of a row: each twin picks out the slots it
uses, and keys no twin uses come back as `ignored_values`.
- A slot left out falls back to `prompt`, and then to the value the row was
saved with (reported as `defaulted_parameters`).
`prompt`: a plain `queries` token has no slots and replays unchanged. The backend
maps the wording onto the row's typed slots. A 422 means it could not — fall back
to `explore_data_catalogue` for that question. A prompt-only fill can also DRIFT (a
slot the wording never mentions, a date say, can come back re-aimed), which is the
second reason to prefer `values`: never infer the substituted values from the
wording, read them out of `parameters` and say them back to the user.
`max_rows`: uncapped, a saved row's
`_constituents` companion query returns 7,000-35,000 rows (3-8 MB) and the client
stalls for minutes. A sliced result carries `row_count` (the full count) and
`truncated: true`; say the user is seeing a slice of N rows.
Returns {"queries_run": N, "results": [{"index": i, "format": "table",
"count": <rows returned>, "rows": [...], ...}, ...]}, in the SAME ORDER as
`query_tokens`. A re-aimed replay adds, per result:
`parameters` the values actually substituted (resolved ids and
canonical names)
`defaulted_parameters` slots that kept the saved example ("prior quarter kept
as 2026-03-31")
`ignored_values` keys in `values` this twin does not use
Surface all three: which values were substituted, which kept the saved example,
which were ignored. Rows only — the underlying SQL is never returned, by design.
Describe the results from the row's `metadata.summary`, the substituted
parameters, and the columns, never by asserting what the query does internally.
CITE WHAT YOU PUBLISH: each entry in `results` may carry `_source_*` columns —
`_source_url`, `_source_filed_at`, `_source_document_id`, `_source_citations` —
alongside a `sources` block naming each relation, its grain, and whether it is
`traceable` per "row" or only as a "cohort". That is the provenance of the numbers,
not padding: quote `_source_url` when the user asks where a figure came from, and for anything
you are about to publish — or the moment they ask for the filing, the quote, or
"how do you know" — pass `sources.relations[].relation` plus each row's
identifying columns (the grain AND its date) to `trace_data_sources`, which
resolves them to the source document, the
section, or the verified quote behind the number. `get_document_section` then opens
the exact speaker turn a transcript citation points at.
Each token runs independently: one failure does not stop the rest, and that entry
carries an "error" key instead of rows. A 403 means that token is invalid or
tampered — do not retry it altered; the saved row is dead, so re-run
`explore_data_catalogue`, `save_user_query` a fresh row, and `delete_saved_query`
the old one. A 422 on a re-aimed replay is the mapping failure above (unknown
entity, wrong shape), not a dead row.
A replay returning DIFFERENT rows than when it was saved is normal — it hits live
data. Report what comes back now; never reconcile it against remembered numbers.
Requires auth (your MCP client attaches the OAuth bearer automatically).
| Name | Required | Description | Default |
|---|---|---|---|
| prompt | No | Natural-language fill for slots `values` did not cover, e.g. "the past 8 quarters of sales for KSS". Placeholder tokens only. | |
| values | No | PREFERRED way to re-aim: {slot name: typed value}, keys from the row's `metadata.parameters`, e.g. {"symbol": "KSS"}. Entity-set slots take [{"id", "name"}] lists. Pass the same dict for every token. | |
| max_rows | No | Row cap per query, e.g. 500 — PASS IT ON EVERY REPLAY. | |
| query_tokens | Yes | A saved row's `queries` list (exact replay) or its `query_placeholder` list (re-aiming with values/prompt), verbatim. Max 25. Never construct or edit a token. |
Output Schema
| Name | Required | Description |
|---|---|---|
| results | Yes | One entry per query token, in the same order. |
| queries_run | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=true, and the description goes well beyond that: no planning/polling, exempt from the 20/hour exploration budget, per-token isolation (one failure doesn't stop others), 403 = dead row vs 422 = mapping failure, truncation via row_count/truncated, and prompt-only fills can DRIFT. It also states SQL is never returned and provenance columns may appear. This is unusually rich behavioral disclosure. However, much of it is arguably operational instruction for the caller rather than intrinsic tool behavior, and return-shape detail overlaps the existing output schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core purpose before any elaboration, and each subsequent paragraph covers a distinct concern (tokens/values, prompt, max_rows, return shape, provenance, error handling). It is long and dense, and the return-shape and provenance passages drift into guidance that could be trimmed, but almost every sentence carries actionable information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 4-param tool with an output schema, no behavioral or routing gap remains: the exact-vs-re-aimed distinction, fallback chain, error taxonomy, truncation signaling, staleness expectation, and downstream trace_data_sources handoff are all covered. An agent could call this correctly on the first attempt from the description alone.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% so the baseline is 3, but the description adds real semantics beyond the schema: the same `values` dict must be passed to every token, entity-set slots take {"id","name"} lists with server-side name resolution, unused keys surface as `ignored_values`, and slots fall back to `prompt` then the saved default (`defaulted_parameters`). `max_rows` guidance ("PASS IT ON EVERY REPLAY") is also operational context the schema lacks.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb+resource ("Re-run a saved request's queries against live data") and immediately distinguishes exact replay from re-aimed replay. It names the sibling producing the input (list_saved_queries), the one it complements (save_user_query), and the ones it competes with (explore_data_catalogue, get_signed_sql_drilldown).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit routing: "Use this INSTEAD of explore_data_catalogue whenever a saved row already covers the question," and "For a token that came from a get_company_event_web node ... use get_signed_sql_drilldown." It also states when to prefer `values` over `prompt` ("keep prompt for what you cannot type") and gives explicit fallback paths on 422/403.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
save_user_queryAInspect
Save the queries an exploration already planned, so the request can be replayed instantly — exactly, or re-asked for other entities.
THE POINT: `explore_data_catalogue` is a full validate -> plan -> run pipeline that
re-authors the SQL from scratch on every call (~1-5 min, 20/hour). For a question
the user will ask AGAIN — a recurring check, a dashboard they watch, "my usual
semis screen" — save the tokens that exploration just produced. `run_saved_query`
then re-runs exactly those queries against live data in seconds, with no planning
step and no async job to poll. The backend ALSO authors a PLACEHOLDER twin of each
saved query (its ticker, CIK list, date, interval, and count lifted into typed
slots) plus a `metadata` slot schema naming them, so the same request can later be
re-asked for a different company, filer, or window:
`run_saved_query(query_placeholder, values={"symbol": "KSS"})`.
WHEN TO CALL: once an exploration is done and shown, offer it — say the request can
be re-run exactly or with different values — and save when the user says yes or
clearly implies they will want it again. Do NOT save every exploration by reflex,
and do not save a one-off.
Each query token is opaque ciphertext the server minted around the planned SQL.
NEVER write, guess, or edit one — a token this backend did not mint cannot be
decrypted and fails with 403 at replay time, long after the exploration is gone.
Owner-scoped: the row belongs to the calling user and is invisible to everyone
else. There is NO upsert (unlike `schedule_task`): saving the same request twice
creates a SECOND row. Check `list_saved_queries` first and `delete_saved_query` the
stale one rather than piling up near-duplicates.
Returns {"msg": "Successfully saved query: <user_request>", "id": <row id>,
"placeholder_status": "PENDING" | "NOT_DISPATCHED", "placeholder_id_to_poll"}. `id` is the delete key.
PENDING means the placeholder twins AND the row's `metadata` (its slot schema,
summary, and datasets) are being authored — roughly 10 s to 5 minutes, depending on
the size of the queries. Until they land, `query_placeholder` and `metadata` are
null in `list_saved_queries`, and an exact replay via `queries` works meanwhile.
NOT_DISPATCHED means no twins will be authored for this row: it can be replayed
exactly but not re-aimed.
Requires auth (your MCP client attaches the OAuth bearer automatically).
Rate-limited 100/min.
| Name | Required | Description | Default |
|---|---|---|---|
| query_tokens | Yes | The `query_token` of each exploration `results` entry, passed through EXACTLY as returned (a signed URL is unwrapped). Skip entries with no token. Never write SQL. | |
| user_request | Yes | The request being saved, in the user's own words — the row's only human-readable label, so make it specific ("weekly EPS-revision check on my semis basket"). |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | Saved row id — the delete_saved_query key. |
| msg | Yes | |
| placeholder_status | No | PENDING (twins + metadata being authored) or NOT_DISPATCHED. |
| placeholder_id_to_poll | No | Task id of the placeholder-authoring job. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations: owner-scoping, absence of upsert (duplicate saves create a second row), opaque-ciphertext tokens that fail with 403 if not server-minted, auth requirement, and a 100/min rate limit. It also explains the async placeholder authoring and the PENDING vs NOT_DISPATCHED states, which materially shapes call timing.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Well front-loaded and organized with THE POINT / WHEN TO CALL headers, and nearly every sentence carries information. It is long, but the async-state and token-safety detail justify most of the length; a few clauses could still be tightened.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers the full lifecycle an agent needs: what to save, when, what the backend does next, what the placeholder enables, duplicate handling, and the failure/async states. Nothing necessary for a correct call or a correct follow-up decision is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds real meaning: tokens are opaque server-minted ciphertext that must pass through exactly and never be written or guessed, and user_request is the row's only human-readable label so it should be specific.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (save) and resource (the queries an exploration planned) plus the outcome (exact or re-aimed replay). It clearly distinguishes itself from explore_data_catalogue, run_saved_query, schedule_task, and list_saved_queries by name.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
An explicit WHEN TO CALL block says to offer it once an exploration is done and shown, save on confirmation, and explicitly says NOT to save every exploration or one-offs. It also routes to alternatives (list_saved_queries before saving, delete_saved_query for stale rows).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
save_user_templateAIdempotentInspect
Save the user's PDF format — one template per account, applied automatically to every PDF the backend renders for them from now on.
STEP 2 OF 2 after `draft_user_template`. Two ways to call it:
SIGNED-OFF (the normal path): pass `draft_id` and the `variant_id` the user chose
from the previews. The EXACT treatment they looked at is stored — no second
adaptation pass that could produce something they never saw. `template`,
`template_type` and `anchor` are taken from the draft and may be omitted. A 404
means the draft expired (24h) or the variant does not exist: draft again.
DIRECT (no previews): pass `template` + `template_type` (+ `anchor` for an
add_on) — only when the user explicitly wants to skip the previews. An add_on
saved this way still gets an unreviewed harmonise pass, so prefer the signed-off
path for anything visual. HTML only: markdown is rejected with a 422.
ONE TEMPLATE PER USER — this is an UPSERT: saving replaces whatever was saved
before, with no history. Call `get_user_template` first and confirm with the user
before overwriting an existing format. To change a saved format afterwards, use
`update_user_template` (any field, or none to recompile it as stored).
WHAT CHANGES AFTERWARDS: the backend renders every PDF it builds for this user —
`get_latest_report` renders of fresh plans, `generate_report_for_stock` rebuilds
(standard and custom) and scheduled reports — through the saved format. The template is a blueprint (stylesheet, page chrome, one
pattern per content kind) applied to the document's own content: nothing is
filled in by hand, and no other call changes. When you compose a PDF yourself
from Flexreport data, `get_user_template` returns the markup to lay it out in.
Asynchronous: returns {"task_id", "status": "PENDING", "next_step"}. Poll
`get_task_status(task_id)`; the finished result is {"status": "SAVED",
"template_type", "anchor", "bytes", "patterns": [content kinds the design styles],
"tones": {positive | negative | neutral | accent: css class}, "warnings"}. Tell
the user which content kinds their design styles. A warning "keeping the
previously compiled blueprint" means the new compile was rejected and the
previous blueprint stays in force; the markup itself is still saved. Validation
failures are a 422 with `detail.errors` listing each problem.
Requires auth (your MCP client attaches the OAuth bearer automatically).
Rate-limited 100/min.
| Name | Required | Description | Default |
|---|---|---|---|
| anchor | No | Direct path, add_on only (required there): the section it applies to, e.g. "technical". | |
| draft_id | No | Signed-off path: the draft_id from draft_user_template's finished task. Pass with variant_id. | |
| template | No | Direct path only: the HTML template (markdown is a 422). Omit on the signed-off path — the draft supplies it. | |
| variant_id | No | Signed-off path: the variant_id the user chose from the previews. Pass with draft_id. | |
| template_type | No | Direct path only (required there): "add_on" or "bespoke". |
Output Schema
| Name | Required | Description |
|---|---|---|
| status | Yes | Task state at dispatch, normally "PENDING". |
| changed | No | update_user_template only: the fields that were updated. |
| task_id | Yes | Celery task id; poll it with get_task_status for the result. |
| next_step | No | What the finished task returns. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only establish readOnly=false/idempotent=true/destructive=false; the description goes well beyond that, disclosing the UPSERT-with-no-history overwrite risk, the async return contract, the 404-on-expiry and 422 rejection modes, the 'keeping the previously compiled blueprint' warning semantics, downstream rendering effects, auth, and a rate limit. (Minor tension worth noting: an overwrite with no history is close to the line for `destructiveHint: false`, but the author surfaces the risk explicitly rather than hiding it.)
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Well front-loaded (purpose, then the two call paths) and sectioned into digestible blocks, with no filler sentences. It is long, and the 'WHAT CHANGES AFTERWARDS' paragraph could be tightened, but the length is driven by genuinely useful behavioral detail rather than padding.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a five-parameter upsert with async execution and an existing output schema, the description covers call paths, error modes, the poll-then-read result contract, and downstream effects. An agent has everything needed to call it correctly without opening other tools.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds real meaning: which parameters belong to which call path, that `template`/`template_type`/`anchor` are taken from the draft on the signed-off path, that `anchor` is required only for `add_on`, and that markdown input is a 422. It stops short of full parameter-level detail only because the schema already carries it.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first sentence names the exact verb+resource (save the user's PDF format) and the cardinality rule (one template per account, applied automatically to every PDF the backend renders). It is immediately distinguishable from `draft_user_template`, `update_user_template`, `get_user_template`, and `delete_user_template`, all of which appear as siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit routing: SIGNED-OFF (normal) vs DIRECT (only when skipping previews), names the required parameters for each path, and states the exclusions. It also says to call `get_user_template` first and confirm before overwriting, and to use `update_user_template` to change an existing format afterwards — when-to-use, when-not, and alternatives are all covered.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
schedule_taskAInspect
Save a multi-step WORKFLOW (upsert by name) and attach a recurring cron
schedule for its delivery.
Use this when the user wants a sequence of platform calls delivered ON A
SCHEDULE / repeatedly (e.g. "every weekday morning pull 8-K releases, screen
for cheap large-caps, and email me the overlaps as a table"). For a ONE-OFF
request, call the corresponding tools directly instead.
`steps` (shape in the parameter description): a transform applies its
instruction to the accumulated results of ALL prior steps (e.g. "intersect the
two event sets by symbol and build a table"), and each step's `label` keys its
result. The LAST step's output is what gets delivered, so end table/summary
workflows with a transform.
Allowlisted fetch endpoints (anything else is rejected with a 422 at save
time; `params` takes the same keys as the matching tool):
- POST, JSON-body params: "get-realtime-events" (`list_realtime_events`),
"list-upcoming-earnings-announcements" (`list_earnings_announcements`),
"predict-earnings-announcement-move" ({"symbols": [...]}),
"data-catalogue-exploration" ({"query": "..."}).
- GET, scalar query params only (no lists/dicts): "get-company-snapshot"
(requires {"symbol": "..."}), "get-strategy-performance-summary",
"get-strategy-track-record", "get-strategy-swaps", "get-stock-picks",
"list-tickers", "list-realtime-event-options", "get-sectors",
"get-sub-industries".
- EXPENSIVE — max 2 per workflow, and the cron must use a literal minute and
at most 4 literal hours (no sub-hourly / "*" fields): "screen-stocks"
(`screen_stocks`), "generate-research-report" ({"query": "..."}),
"create-full-report" (a full ~10 min rebuild every run; {"ticker": "..."} for
the symbol's standard report;
add "user_override": true plus the shaping lists `generate_report_for_stock`
takes — financial_items, ratios, as_reported_financial_items, revenue_segment,
technical_analysis_items, estimate_items, institutional_ownership CIKs — for a
custom one; the backend rejects the lists without the switch),
"optimize-symbols", "optimize-portfolio", "list-optimized-stock-picks".
Each user may hold at most 10 active schedules.
Returns `status` 201 (created) or 200 (updated) with `workflow_id` and
`task_name` ("wf:{email}:{name}"), the key that `list_scheduled_tasks` shows
and `delete_scheduled_task` takes.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Lowercase slug and upsert key (no spaces, colons, or uppercase); re-saving the same name updates the workflow and re-attaches its schedule. | |
| steps | Yes | Ordered 1-8 steps; the first must be a fetch. Fetch: {"kind": "fetch", "endpoint": "<allowlisted kebab-case path, no leading slash>", "params": {...}, "label": "..."}. Transform: {"kind": "transform", "instruction": "<=2000 chars, applied to all prior results>", "label": "..."}. `label` is an optional unique lowercase slug (default step_{i}). The last step's output is delivered. | |
| delivery | No | Where each run's output goes. | |
| description | No | Optional human-readable note saved with the workflow. | |
| regular_cron | Yes | Raw 5-field cron expression for when the workflow fires, e.g. "30 6 * * 1-5" (weekdays 06:30); validated server-side. |
Output Schema
| Name | Required | Description |
|---|---|---|
| cron | No | The cron expression attached. |
| name | No | The workflow name (upsert key). |
| status | No | 201 when the workflow was created, 200 when an existing one was updated. |
| scheduled | No | |
| task_name | Yes | "wf:{email}:{name}" — the key list_scheduled_tasks shows and delete_scheduled_task takes. |
| workflow_id | No | Id of the saved workflow definition. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=false and destructiveHint=false; the description far exceeds that bar by disclosing the endpoint allowlist, 422 rejection at save time, which endpoints are EXPENSIVE with a max-2 cap, cron field restrictions for expensive runs, the 10-active-schedule per-user limit, and the 201/200 upsert status semantics.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose and usage before the detail, and the bulk of the length is the endpoint allowlist which genuinely earns its place. It is nevertheless dense and reads more like a manual than a description, with some list entries (e.g. the create-full-report override keys) verbose enough to compress.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a complex, high-stakes scheduling tool with nested-ish step objects, an output schema present, and no destructive annotation, the description covers everything an agent needs: eligibility, endpoint allowlist, constraints, limits, and upsert identity. Return values are covered by the output schema and only briefly echoed.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Even at 100% schema coverage, the description adds vocabulary the schema cannot encode: the allowlisted fetch endpoint names, which take JSON-body vs scalar query params, which are expensive, and the shape/semantics of `steps` (first must be a fetch, transform instruction applies to all prior results, last step is delivered). This is substantive meaning beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource+mechanism: 'Save a multi-step WORKFLOW (upsert by `name`) and attach a recurring cron schedule for its delivery.' It also distinguishes itself from the direct-call alternative and from siblings like delete_scheduled_task/list_scheduled_tasks by naming the upsert key semantics.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit when-to-use ('user wants a sequence of platform calls delivered ON A SCHEDULE / repeatedly') with a concrete example, and an explicit when-not ('For a ONE-OFF request, call the corresponding tools directly instead'). Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
screen_stocksAInspect
Screen stocks by financial growth, sector, sub-industry, market cap, analyst ratings, institutional ownership, country, and price performance.
Discover valid filter values with the list tools named in each parameter's
description before guessing.
Rate-limited to 10/hour
per user server-side.
Asynchronous: returns a task id. Poll it with `get_task_status` until SUCCESS.
| Name | Required | Description | Default |
|---|---|---|---|
| metrics | No | Financial-growth criteria: metric name -> threshold (number) or required flag (bool), e.g. {"revenue_growth": 0.1, "positive_eps": true}. Interpreted by the screener, not enum-validated. | |
| sectors | No | Sector values from list_options("sectors"). | |
| countries | No | Country values from list_options("countries"). | |
| market_cap | No | Market-cap buckets from list_options("market_cap"), e.g. "Small-cap", "Large-cap". | |
| sub_sectors | No | Sub-industry values from list_sub_industries([...]). | |
| analyst_ratings | No | Analyst consensus ratings to keep, e.g. ["Buy", "Strong Buy"]. | |
| price_performance | No | Price-return criteria: window -> minimum return, e.g. {"ytd": 0.1}. | |
| institutional_ownership | No | Investor category -> minimum ownership, keyed by list_options("institutional_investor_types") values, e.g. {"Hedge Fund": 5}. |
Output Schema
| Name | Required | Description |
|---|---|---|
| status | Yes | PENDING on submission. |
| task_id | Yes | Poll with get_task_status until SUCCESS. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds two traits the annotations do not convey: a server-side rate limit of 10/hour per user and asynchronous execution returning a task id that must be polled. These are exactly the operational facts an agent needs to avoid retry storms and to correctly sequence calls.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four short blocks: what it filters, how to obtain valid values, the rate limit, and the async contract. The purpose is front-loaded and every line carries distinct operational value with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers prerequisites, rate limiting, and the async/polling lifecycle, and an output schema exists so return-shape explanation is unnecessary. For an eight-parameter screener, nothing an agent needs to invoke it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and each parameter already names its source list tool, so the description's opening enumeration mostly restates the schema. It adds no threshold syntax or value-format guidance beyond what the schema provides, making the baseline 3 appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (screen) and resource (stocks) and enumerates the eight filter dimensions it accepts, which cleanly separates it from adjacent tools like get_stock_picks or generate_report_for_stock. An agent can tell what this tool does without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a concrete prerequisite workflow: discover valid filter values via the list tools named in each parameter description before guessing, and poll the returned task with get_task_status until SUCCESS. It lacks any explicit when-not or comparison against sibling screening/picks tools, so it stops short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
situateARead-onlyInspect
THE FIRST CALL. What is going on right now — for the market, or for the named symbols — and a ready-made PLAN of the tool calls that answer the user's question. Call it before any other flexreport tool on anything about a company, an event, or "now".
===> Call this FIRST for: "catch me up on X", "what happened / why", "anything
before earnings?", "any earnings / 8-Ks / 13F moves / movers today?", "how is X
trading", and BEFORE aiming explore_data_catalogue, list_realtime_events or a
report tool at a company. Pass the user's question verbatim in `question`: it is
matched by keyword (never an LLM) against EVERY realtime event type — decks/
presentations -> ir_publication, 8-Ks, transcripts, upgrades, gainers/losers, 13F
exits, baskets, predictions, ... — and the plan STARTS at the type the user named.
A question naming only a family ("any earnings today?") walks that family's episode;
one naming neither ("what's going on?") sweeps every episode. Synchronous, public.
situate(symbols=["OKTA"], question="catch me up on OKTA") one or more names (max 5)
situate(question="any earnings events today?") no symbols = the market
situate(question="most significant investor decks today") step 1 = ir_publication
It reads the company event web (what HAPPENED to this company), the event ontology
(what that KIND of event entails, what follows it and how soon, where its payload
lives after the 12h realtime cache, when each table next refreshes) and market
status, and composes them into ONE response:
market exchange, is_open, session
symbols[S] web (newest 12 nodes; full graph via get_company_event_web),
newest_event, episode (the DOMINANT episode in the window — its
anchor and each member arrived | pending | overdue with rate and
expected_by), cache.present / cache.expired (inferred from node
age vs the TTL), freshness[] (per relation: last_refresh_at,
next_run_at, reflects_newest_event), cards (trimmed ontology
cards), deepen (tools the ontology says deepen this event)
universe (no symbols) shape (named_types | family | sweep), asked_types,
the plan order and cards, and event_types: the WHOLE realtime
corpus (type, family, one-line description) so you never guess
plan[] ORDERED tool calls: {step, tool, args, why, auth, sync, optional,
provenance, fallback}. `tool` is an exact tool name and `args`
are valid for it — pass them through unchanged.
skip[] calls that would return nothing or waste a job (an event type
that aged out of the cache, a 10-minute report) — DO NOT make these.
suggest[] calls to make ONLY IF their `when` arises after the plan has run
(explore_data_catalogue lives here, never in plan[]: it is a
multi-minute job, and "the user wants more than the 12h cache
holds" is the situation that earns it).
guidance[] situation-scoped rules: which tables have NOT refreshed since the
event, which followers are overdue, filer-scoped 13F nodes.
HOW TO EXECUTE:
1. Run plan[] in order. `sync=false` steps return a task_id — poll
get_task_status.
2. Never make a call that appears in skip[]; quote its `why` if the user asks.
Make a suggest[] call only when its `when` is true — an empty realtime list
is NOT that condition; say the cache is cold instead.
3. Read guidance[] before writing: an "overdue" follower is "not recorded yet",
not "did not happen"; a relation with reflects_newest_event=false shows the
PRIOR period, never the reaction.
4. Go beyond the plan only for what it did not cover — then get_company_event_web
(full graph, wider window) and get_event_ontology (full card / relation /
family) tell you what to call next.
Skip this tool ONLY for pure enumeration (list_options), an explicit "get me the
existing report" (get_latest_report), or a metric-history question with no event
in it ("Micron EPS growth over 8 quarters" -> explore_data_catalogue).
degraded=true means a source was unavailable (ontology not built, a web errored);
the plan still runs on what remains — follow it, and say what was unknown.
| Name | Required | Description | Default |
|---|---|---|---|
| symbols | No | Tickers to situate (max 5; extras are dropped). Omit for the whole market. | |
| question | No | The user's question VERBATIM; keyword-matched to the realtime event types it names, which decides where the plan starts. | |
| window_days | No | Event-web look-back in days (backend default 7, max 90). |
Output Schema
| Name | Required | Description |
|---|---|---|
| plan | Yes | ORDERED tool calls to execute as-is. |
| skip | Yes | Calls that would return nothing or waste a job — do not make them. |
| as_of | Yes | |
| scope | Yes | symbol (symbols were named) or universe (the market). |
| market | Yes | |
| suggest | Yes | Calls to make only if their `when` arises. |
| symbols | No | Per-symbol blocks (symbol scope only). |
| degraded | Yes | True when a source was unavailable; guidance[] says which. |
| guidance | Yes | Situation-scoped rules to read before writing. |
| universe | No | Market-wide block (universe scope only). |
| ontology_as_of | No | |
| realtime_cache_ttl_hours | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only carry readOnlyHint=true, and the description adds a great deal beyond that: synchronous execution, keyword (never LLM) matching, cache TTL/expiry semantics, sync=false returning a task_id to poll, and degraded=true meaning a source was unavailable. It also defines the operational contract of plan/skip/suggest/guidance, which the annotations cannot express.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the single most important routing fact ('THE FIRST CALL') and organized under clear headers with inline examples. It is long and dense, and some prose re-describes output fields that the output schema already defines, but for a meta-tool of this complexity nearly every sentence carries operational weight.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, yet the description supplies the interpretation layer an agent actually needs: what plan[], skip[], suggest[], and guidance[] mean, how to read an 'overdue' follower, and the degraded path. Nothing required to call it or act on its response is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds real meaning with worked invocations showing no-symbols = whole market and how a question naming a family vs. a specific type changes plan order. It reinforces that question must be passed verbatim, which matters for the keyword matcher.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opening line states a specific verb and resource: it reports what is happening now for the market or named symbols AND returns a ready-made plan of tool calls. It explicitly distinguishes itself from siblings (explore_data_catalogue, list_realtime_events, report tools) and brands itself as 'THE FIRST CALL', so an agent can route to it without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-to-use triggers ('catch me up', 'anything before earnings?') and explicit exclusions ('Skip this tool ONLY for pure enumeration (list_options), an explicit get_latest_report, or a metric-history question'). It names the alternative tool for each exclusion, leaving nothing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
stream_eventsARead-onlyInspect
Listen for realtime events as they publish — a bounded read of the backend's
ad-hoc SSE stream (GET /events), filter passed inline, nothing saved server-side.
DEFAULT DELIVERY — BUILD A DASHBOARD: when the user asks to stream / watch / keep
listening for live events, build a live dashboard (in Claude, an Artifact) whose
page calls this tool in its own loop, carrying `cursor` from read to read, and
renders each event as it lands. One prompt then keeps the stream open with no agent
turn per read. If the page cannot reach this server, run the loop yourself and write
each event into the dashboard's shared store. Stream into chat only when the user
asks for that, or the client cannot render a dashboard.
Returns {"events": [...], "cursor": "<last id seen>", "closed": null | reason,
"elapsed_seconds": n}. Each item in `events` is the same object `list_realtime_events` returns for that
type ({event_type, symbol, payload, published_at, id}) — summary, thesis impact,
significant changes, citations — the moment it publishes, no polling of the 12h
cache. There is NO PDF link on an event: for the research, POST the symbol to
get_latest_report (a fresh plan renders in ~10-20 s; stale/missing -> a
generate_report_for_stock rebuild, ticker only).
THE LOOP: a call returns after `max_events` matched events or `max_wait_seconds`
(cap 55 s), whichever comes first — call it again to keep listening, and ALWAYS
pass the returned `cursor` back in: this stream keeps no state, so without it
the next call starts at "now" and drops whatever published in between. The
cursor advances on heartbeats too (events the filter dropped), so an empty
`events` list with a moved cursor is normal on a quiet tape. Omit `cursor` on
the first call to start at now. For a subscription that resumes by itself, use
register_event_subscription + stream_event_subscription instead.
`topics` (optional, any mix; case-insensitive):
- an event type from list_options("event_types") — eps_update, 8k_release,
transcript_update, ir_publication, biggest_mover, 13f_new, strategy_update, ...
- a family from the same listing — earnings, news, market_movement,
institutional_ownership, analyst_activity, strategy, prediction — which
matches every type in it, including types added later;
- `report_plan` (stream-only): a frame each time a report plan is SAVED
({symbol, event_type, planned_at, queued_at, plan_key}); the next step is
get_latest_report([symbol]), which finds the plan fresh and renders it.
`symbols` (optional): tickers; 13f_* filer events carry the filer's CIK in the
symbol slot. No topics and no symbols = everything. Unknown topic -> 422 with the
allowed lists in `detail`.
`closed` set means the server ended the stream — do not reconnect with that id.
Requires auth (your MCP client attaches the OAuth bearer automatically).
| Name | Required | Description | Default |
|---|---|---|---|
| cursor | No | The `cursor` returned by the previous read; resume after it. Omit to start at now. | |
| topics | No | Event types or families from list_options("event_types") (e.g. "eps_update", "earnings"), plus the stream-only "report_plan"; case-insensitive. Omit for every topic. | |
| symbols | No | Tickers to listen for (13f_* filer events carry the filer's CIK in the symbol slot). Omit for every symbol. | |
| max_events | No | Return after this many matched events (clamped to 1-200). | |
| max_wait_seconds | No | Return after this many seconds even if fewer events arrived (clamped to 1-55). |
Output Schema
| Name | Required | Description |
|---|---|---|
| closed | No | Set when the server ended the stream (e.g. "subscription deleted"); do not reconnect. |
| cursor | No | Last stream id seen (advances on heartbeats too). Pass it back on the next call; null only when no frame carried an id and none was passed in. |
| events | Yes | Matched events in publish order; empty on a quiet tape. A frame whose data was not JSON comes through as {"raw": <text>}. |
| elapsed_seconds | Yes | Wall time this read held the stream open. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint; the description goes much further: bounded read semantics, no server-side state, cursor advances on heartbeats so empty events + moved cursor is normal, closed means server ended the stream and do-not-reconnect, auth required. Does not contradict annotations. Slightly less than 5 because some operational detail (rate limits, exact 422 shape) is only partially covered.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Much of the content is valuable, but structure is dense: multiple distinct topics (delivery pattern, cursor loop, topics, symbols, closed) are packed with bold headers, inner bullet lists, and parentheticals. It works but is not front-loaded in the sense of a single tight opening; the caller must read the full document to extract the loop protocol.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the complexity (bounded SSE read with cursor, 5 optional params, output schema present) the description covers consumption guidance, loop semantics, alternatives, and error behavior. Since an output schema exists, it does not over-explain return shapes while still calling out key fields (events, cursor, closed, elapsed_seconds).
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3. Description adds meaningful semantics beyond schema descriptions: topics can be an event type, a family, or stream-only 'report_plan'; symbols note that 13f_* filer events carry CIK; cursor advances on heartbeats; unknown topic -> 422 with allowed lists. That is real added meaning over schema text.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource: 'Listen for realtime events as they publish — a bounded read of the backend's ad-hoc SSE stream (GET /events)'. Names the sibling alternatives and differentiates: 'For a subscription that resumes by itself, use register_event_subscription + stream_event_subscription instead', and references list_realtime_events as the polling counterpart.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit 'DEFAULT DELIVERY' section tells the agent what to do (build a live dashboard, run the loop) vs when to stream into chat only. Names explicit alternatives ('use register_event_subscription + stream_event_subscription instead'), and specifies cursor handling per call. This is a rare example of explicitly covering when/why.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
stream_event_subscriptionARead-onlyInspect
Read the next events on a saved subscription — a bounded read of
GET /event-subscription/{subscription_id} that resumes from the position saved
when the previous read closed, so repeated calls see every matching event exactly
once with no gap and no replay.
For a live-streaming ask, the default is a dashboard (in Claude, an Artifact) that
loops stream_events with its cursor — see stream_events; a page should prefer that
ad-hoc stream, since a subscription read can stall.
Returns {"events": [...], "cursor": "<last id seen>", "closed": null | reason,
"elapsed_seconds": n} — same shape and event objects as stream_events. A call returns after `max_events`
matched events or `max_wait_seconds` (cap 55 s); call again to keep listening. The
API saves the cursor when this read closes the connection, so the next call resumes
correctly WITHOUT passing `cursor`. Pass `cursor` only to override the saved
position for one connection (e.g. re-read from an earlier frame id); it is not
persisted.
An empty `events` list means nothing matched in the window, not that the
subscription is broken. `closed` = "subscription deleted" means it was removed
mid-stream — do not reconnect. 404 `unknown subscription_id` covers both a missing
id and another user's id (indistinguishable by design).
Acting on what arrives: an `event` item is the full realtime event (use it
directly); to hand over research, get_latest_report([symbol]) first (a fresh plan
renders in ~10-20 s; batch up to 50 symbols per call), and only if it comes back
stale/missing a generate_report_for_stock(ticker) rebuild. A `report_plan` item
means a plan was just saved: get_latest_report([symbol]) renders it fresh.
Requires auth (your MCP client attaches the OAuth bearer automatically).
| Name | Required | Description | Default |
|---|---|---|---|
| cursor | No | Override the saved position for this one connection (not persisted). Omit to resume where the last read stopped. | |
| max_events | No | Return after this many matched events (clamped to 1-200). | |
| subscription_id | Yes | The `subscription_id` returned by register_event_subscription. | |
| max_wait_seconds | No | Return after this many seconds even if fewer events arrived (clamped to 1-55). |
Output Schema
| Name | Required | Description |
|---|---|---|
| closed | No | Set when the server ended the stream (e.g. "subscription deleted"); do not reconnect. |
| cursor | No | Last stream id seen (advances on heartbeats too). Pass it back on the next call; null only when no frame carried an id and none was passed in. |
| events | Yes | Matched events in publish order; empty on a quiet tape. A frame whose data was not JSON comes through as {"raw": <text>}. |
| elapsed_seconds | Yes | Wall time this read held the stream open. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=true; the description carries the real behavioral load — server-side cursor persistence across connections, the 55 s wait cap, exactly-once/no-replay semantics, closed reasons, and the deliberately ambiguous 404. It also states the auth requirement.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core contract and organized into scannable paragraphs, but it runs long and the 'Acting on what arrives' section drifts into downstream-tool guidance (get_latest_report timing, generate_report_for_stock fallback) that belongs closer to those tools.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a resumable streaming read with a 4-param schema, the description covers return shape, timeout behavior, cursor persistence, terminal closed states, error semantics, and auth. Even though an output schema exists, nothing an agent needs to call or loop this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds meaning beyond the schema: cursor is an ephemeral per-connection override that is NOT persisted, while the saved position resumes automatically without passing it. That interplay is the key semantic and it is spelled out.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Read the next events on a saved subscription') and pins the underlying endpoint GET /event-subscription/{subscription_id}. It explicitly distinguishes itself from the sibling stream_events, so an agent can route without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly says when to prefer the alternative ('a page should prefer that ad-hoc stream, since a subscription read can stall') and when to pass cursor vs omit it. It also covers the edge case of not reconnecting after 'subscription deleted' and how to interpret an empty events list.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
trace_data_sourcesARead-onlyInspect
Resolve numbers you are holding back to the documents they were read from — the filing, the section, or the verified quote.
The CITATION rung of the chain. `explore_data_catalogue`, `run_saved_query` and
`get_signed_sql_drilldown` hand back rows; this says where each number CAME FROM.
Reach for it whenever the user asks "where does that come from", "which filing",
"can you cite that", "how do you know" — and unprompted before you publish a figure
they are going to act on.
TWO WAYS IN, and the FIRST is preferred:
1. `relation` + `keys` — `relation` is a name off the result's
`sources.relations[].relation`; `keys` is one JSON object per row you want
traced. Pass EVERY identifying column the row carries — the reported grain
AND the period/date — e.g. [{"symbol": "SNOW", "cik": "0001273087",
"date": "2026-06-30"}]. Extra columns are ignored; a missing one is fatal.
Grain alone is NOT always enough: the join behind a view can need a column
its `grain` does not list (current_institutional_holders_v reports grain
[symbol, cik] but joins on `date` too, and keys without it resolve nothing).
No token and no SQL, so this is the form
that works when you assembled a table across several calls (`run_saved_query`
issues one call per saved token, so a token only ever describes a fragment of
what you ended up with) or filtered the rows yourself. Trace the rows you will
actually cite — a few dozen — not the whole result set.
2. `encrypted_query_token` — a `trace_token` from a `sources` block, or the
original `query_token` / `signed_query_url`, for the "I have a link and
nothing else" case. The URL form is unwrapped automatically. Tokens are minted
server-side only: never construct, guess or edit one, and never pass SQL here.
THREE CITATION GRAINS come back, finest first. Which one answers depends on the
relation and you do not choose it — one surface over several stacks:
- `citations` carrying `quotes` — the passages an analysis row was actually
WRITTEN from, with quotes machine-verified against the section text. The
strongest evidence in the system; quote these verbatim.
- `citations` of kind `transcript_section` — a link to ONE numbered speaker turn
of an earnings call. `get_document_section` fetches that turn's text.
- `documents` — the whole source document (SEC 13F / Form 4 / 8-K / 10-Q / 10-K,
an earnings-call transcript, an IR PDF) a number was read from. The fallback,
and available wherever lineage reaches a document at all.
`providers` names which of those answered, and every relation's traceability is
derived from the live data model — a redefined view re-derives its own on the next
refresh, so trust this response over anything remembered.
READ `traceable` BEFORE YOU WRITE. "row" means each row maps to one document and
may be cited that way. "cohort" means the number is a sum over a SET of filings:
the response carries `cohort` instead of `documents`, only the set can honestly be
cited, and writing "per this filing, hedge funds own 4.1%" off a cohort row is the
exact failure this field exists to prevent. "none" means the lineage reaches no
document — say the number cannot be sourced rather than reaching for a plausible
filing. A `reason` of "no_keys" means a column the join needs was missing
from every key object — nearly always the period/date — not that the number is
unsourced. Add the date and any other identifying column on the row, and re-call.
`column` traces ONE column instead of the whole row — necessary for a YoY or
change relation, where each value column resolves to a DIFFERENT filing (the
result's `sources.relations[].per_column` says which columns work this way).
`resolve_passages=True` fetches the speaker turn or filing section text instead of
just a link — a link is already a citation. `values` and `prompt` re-aim a
placeholder-twin token but cannot change WHICH documents come back for a given set
of rows.
Requires auth (your MCP client attaches the OAuth bearer automatically). A 403 means
the token is invalid or tampered — re-fetch the link rather than retrying an altered
one; a 422 means neither `relation`+`keys` nor `t` arrived in a usable form.
| Name | Required | Description | Default |
|---|---|---|---|
| keys | No | With `relation`: one object per row to trace, carrying EVERY identifying column (the grain AND the period/date), e.g. [{"symbol": "SNOW", "cik": "0001273087", "date": "2026-06-30"}]. A few dozen rows, not the whole set. | |
| column | No | With `relation`: trace ONE value column instead of the row — needed for YoY/change relations (see `sources.relations[].per_column`). | |
| prompt | No | Token form, placeholder twins only: natural-language fill for slots `values` did not cover. | |
| values | No | Token form, placeholder twins only: {slot name: typed value} that re-aims the token deterministically. | |
| relation | No | Preferred form: a relation name from the result's `sources.relations[].relation`. Pass with `keys`. | |
| max_documents | No | Cap on documents returned (server default 50). | |
| resolve_passages | No | relation+keys form: also fetch the passage TEXT behind each citation (capped at 20). Ask for it when you intend to quote, not by reflex. | |
| encrypted_query_token | No | Fallback form: a `trace_token` from a sources block, or the original `query_token` / `signed_query_url`, verbatim. Never construct or edit one; never pass SQL. |
Output Schema
| Name | Required | Description |
|---|---|---|
| mode | No | "documents" when resolved; "recipe"/"none" otherwise. |
| cohort | No | The SET of filings a cohort number sums over. |
| reason | No | Why nothing resolved, e.g. "no_keys" (a join column, usually the date, was missing). |
| relation | No | |
| citations | No | Finer citations: verified quotes or transcript speaker turns. |
| documents | No | Whole source documents (SEC filings, transcripts, IR PDFs). |
| providers | No | Citation providers that answered. |
| traceable | No | "row", "cohort" or "none" — read before writing. |
| trace_token | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the single readOnlyHint: discloses auth requirement and the 403/422 error semantics, that tokens are minted server-side and must never be edited, the server default of 50 documents, the 20-passage cap on resolve_passages, and the `traceable` row/cohort/none contract including the `no_keys` failure mode. This is rich operational context the annotations cannot carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Well front-loaded and headed (CITATION rung, TWO WAYS IN, THREE CITATION GRAINS, READ traceable), so an agent can skim to the decision it needs. It is long for a tool description and partly duplicates the schema, e.g. the keys example and the 'never pass SQL' warning appear in both, which costs a little against 'every sentence earns its place'.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Even though an output schema exists, the description supplies the interpretation an agent actually needs: the three citation grains and their precedence, the meaning of `traceable`, and the per-column vs per-row split. Combined with auth and error-code coverage, nothing needed to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds substantial meaning: pass EVERY identifying column, extra columns ignored, a missing one is fatal, grain alone is insufficient (with a concrete view example), `column` is required for YoY/change relations, and `values`/`prompt` re-aim a token without changing which documents return. That is genuine value beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource — resolving numbers back to the documents they were read from — and immediately differentiates from the row-returning siblings (`explore_data_catalogue`, `run_saved_query`, `get_signed_sql_drilldown`). An agent can tell exactly what this does and does not do without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit trigger phrases ("where does that come from", "can you cite that"), prescribes unprompted use before publishing actionable figures, names the two entry paths and declares `relation`+`keys` preferred with the fallback condition for tokens. It also routes the agent away from misuse (don't construct tokens, don't trace the whole result set, read `traceable` before writing).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_user_templateAIdempotentInspect
Change your saved PDF template — any field, or none to recompile it as stored.
Complements `draft_user_template` (preview), `save_user_template` (create) and
`delete_user_template` (remove). Every argument is optional; a field you omit
keeps its stored value, and the result is compiled into a blueprint again:
- a VISUAL change: draft the new page with `draft_user_template`, show the
previews, then pass the chosen `draft_id` + `variant_id` here (both or
neither);
- a change without previews: pass `template`, `template_type` and/or
`anchor` directly (HTML only — markdown is rejected with a 422);
- NO arguments: recompiles the stored template with the current compiler —
how a saved design picks up an improved compile without resubmitting it.
Async: returns {"task_id", "status": "PENDING", "changed": [the fields that
were updated], "next_step"} — poll `get_task_status` for {"status": "SAVED",
"patterns", "tones", "warnings"}. A 404 means nothing is saved yet (use
`save_user_template` first); a 422 lists validation errors in `detail.errors`.
Requires auth (your MCP client attaches the OAuth bearer automatically).
| Name | Required | Description | Default |
|---|---|---|---|
| anchor | No | New add_on section, e.g. "technical". Omit to keep the stored one. | |
| draft_id | No | Visual change: the draft_id from draft_user_template's finished task. Pass with variant_id. | |
| template | No | New HTML template without previews (markdown is a 422). Omit to keep the stored one. | |
| variant_id | No | Visual change: the variant_id the user chose from the previews. Pass with draft_id. | |
| template_type | No | New type, "add_on" or "bespoke". Omit to keep the stored one. |
Output Schema
| Name | Required | Description |
|---|---|---|
| status | Yes | Task state at dispatch, normally "PENDING". |
| changed | No | update_user_template only: the fields that were updated. |
| task_id | Yes | Celery task id; poll it with get_task_status for the result. |
| next_step | No | What the finished task returns. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=false, idempotentHint=true, and destructiveHint=false, so the mutation profile is known. The description adds real value beyond that — async task_id/PENDING flow, get_task_status polling, 404 = nothing saved, 422 = detail.errors — but partially overlaps the idempotent/stored-value semantics the hints already imply. Strong supplementary context, though the async and error details are the main non-annotation contributions.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the core verb/resource, then uses a clean bulleted structure for the three usage modes, and closes with async/error/auth notes. Every sentence carries routing or behavioral information; no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, yet the description still explains the async return shape and the polling path, plus the 404/422 failure meanings and the automatic OAuth requirement. For a 5-param, all-optional mutation tool this is complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema already documents each parameter including the markdown-422 note and the draft_id/variant_id pairing. The description's added value is framing the parameters into coherent workflows ('both or neither', 'any field or none to recompile'), which contextualizes how the optional fields combine rather than repeating definitions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Change your saved PDF template') and resource, and immediately distinguishes itself from `draft_user_template`, `save_user_template`, and `delete_user_template` by naming each. An agent can route among the four siblings without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides an explicit decision tree: visual change (draft then pass draft_id+variant_id), change without previews (pass template/template_type/anchor), and no-arguments recompile. Each branch states the condition that selects it, leaving nothing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
upgrade_planAInspect
Get a secure link for the user to upgrade or change their Flexreport Finance plan (e.g. to raise their request limit). Returns a checkout link — the user completes payment in their browser. Call this whenever the user asks to upgrade, subscribe, pay for, or change their plan, or when they've hit a usage/quota limit.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| url | No | The browser link; null when it could not be generated. |
| usage | No | Current plan usage (upgrade_plan only, when known). |
| message | Yes | Ready-to-show markdown for the user, including the link when there is one. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=false and destructiveHint=false, so the safety profile is partly covered. The description adds real behavioral context beyond that: it returns a checkout link and the user completes payment in their browser, implying the plan is not changed server-side by this call alone.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences with the action and return value front-loaded and the invocation triggers last. Every sentence carries information; nothing is redundant.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return-value documentation is not required, yet the description still states the key return (a checkout link). For a zero-parameter, non-destructive tool, this is sufficient for an agent to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so the baseline is 4 and there is nothing for the description to disambiguate. No parameter-level detail is needed or missing.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource ('Get a secure link for the user to upgrade or change their ... plan') and clarifies the outcome ('Returns a checkout link'). It is clear on its own, but it never distinguishes itself from the sibling manage_billing, which an agent could reasonably confuse it with.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit triggering conditions: 'Call this whenever the user asks to upgrade, subscribe, pay for, or change their plan, or when they've hit a usage/quota limit.' That is strong when-to-use guidance, but there is no when-not-to-use and no reference to the alternative manage_billing tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
50 tool updates
- First observed
delete_event_subscription - First observed
delete_saved_query - First observed
delete_scheduled_task - First observed
delete_user_template - First observed
detect_intraday_outlier_jumps - First observed
download_pdf_from_url - First observed
draft_user_template - First observed
explore_data_catalogue - First observed
explore_data_coverage - First observed
generate_report_for_stock - First observed
generate_research_report - First observed
get_aftermarket_data - First observed
get_company_event_web - First observed
get_company_snapshot - First observed
get_document_section - First observed
get_event_ontology - First observed
get_latest_report - First observed
get_signed_sql_drilldown - First observed
get_stock_picks - First observed
get_strategy_performance_summary - First observed
get_strategy_swaps - First observed
get_strategy_track_record - First observed
get_task_status - First observed
get_technical_indicator_data - First observed
get_user_template - First observed
is_market_open - First observed
list_available_reports - First observed
list_earnings_announcements - First observed
list_options - First observed
list_realtime_events - First observed
list_saved_queries - First observed
list_scheduled_tasks - First observed
list_sub_industries - First observed
manage_billing - First observed
onboard_symbol - First observed
optimize_portfolio - First observed
optimize_portfolio_default - First observed
predict_earnings_move - First observed
register_event_subscription - First observed
run_saved_query - First observed
save_user_query - First observed
save_user_template - First observed
schedule_task - First observed
screen_stocks - First observed
situate - First observed
stream_event_subscription - First observed
stream_events - First observed
trace_data_sources - First observed
update_user_template - First observed
upgrade_plan
Publisher details
- Operator
- Flexreport Finance · Publisher source
- Operator website
- https://app.flexreportfinapi.com/
- Vendor relationship
- First-party
- Documentation
- https://app.flexreportfinapi.com/mcp
- Trust center
- Not available
- Restrictions
- Requires a Flexreport Finance account (OAuth 2.1 sign-in in the browser; free registration via email or Google). Usage is subject to per-plan quotas and rate limits; higher limits require a paid plan (Stripe checkout). No admin approval, regional limits, or custom OAuth app are needed—clients register dynamically.
Related MCP Servers
- AlicenseAqualityCmaintenanceEnables brand visibility monitoring across major AI platforms like ChatGPT, Claude, Gemini, and Perplexity. It allows users to track visibility scores, analyze competitor data, and receive actionable insights to improve AI-generated brand recommendations.1611 npm1MIT
- AlicenseCqualityBmaintenanceCompetitor Monitor AI - MCP server providing AI-powered tools and automation by MEOK AI Labs117 npm54 PyPIMIT
- AlicenseAqualityCmaintenanceRevnuvo Company Intelligence tells AI agents what changed at a company, with evidence. It observes company websites, technologies, and DNS over time and returns timestamped, confidence-aware changes, signals, and monitoring.9MIT

industrylens-mcpofficial
AlicenseNot gradedqualityBmaintenanceBrowse IndustryLens's published competitive-intelligence reports and head-to-head competitor comparisons from any AI agent — real, source-backed data.MIT
Glama MCP Gateway
Add one secure layer between your agents and this server.