Bullrun
Server Details
Global stock and UCITS ETF research. Free: 700 successful MCP tool calls per rolling 30 days. Pro: CHF 5/month or CHF 50/year for higher usage. Screen stocks, compare fund costs and holdings, and inspect company risks. No account or API key for public research. Plans: https://bull-run.org/pricing. Connect your Bullrun account through OAuth to use Pro.
- Status
- Healthy
- Uptime
- 99.9% over 76 days
- Last Tested
- Transport
- Streamable HTTP · MCP 2025-11-25
- URL
- Repository
- ferinator/bullrun-mcp
- GitHub Stars
- 0
- Server Listing
- Bullrun
TDQS
Scored across 48 tools
Most tools target distinct resource/action combinations, and descriptions explicitly disambiguate difficult pairs such as search_etfs vs screen_etfs, get_portfolio_context vs get_portfolio_analytics, and the three draft-creation tools. Some near-neighbors remain among the ETF snapshot/compare/fund/holdings tools and stock risk/screen/movers tools, but the boundaries are usually recoverable from the descriptions.
Tool names consistently use snake_case verb_noun patterns: compare_*, get_*, search_*, screen_*, create_*, list_*, save_*, find_* and simulate_*. The verb choices are predictable for the action type, with no mixed casing or chaotic naming.
At 48 tools, the surface is very heavy for an agent to navigate even though the domain is broad. Many ETF, macro, risk and portfolio tools could be consolidated into fewer modular tools without losing capability.
The server covers a wide research lifecycle: stock and ETF discovery, screening, fundamentals, valuation, risk, relationships, macro data, portfolio review, portfolio drafting and shortlist saving. Minor gaps remain around shortlist update/removal, live portfolio mutation, and monitoring/alerting, but core research workflows are well supported.
Available Tools
48 toolscompare_company_exposuresCompare shared company exposuresARead-onlyInspect
Compare the cached company relationship graphs of two to five stock tickers. Finds shared suppliers, customers, competitors and partners, including cross-role overlaps, using stable company entity IDs or exact tickers only. Returns directed direct relationships with VERIFIED vs SUGGESTED/NEEDS_REVIEW status, confidence, sole-source flags, disclosed metrics with meaning/unit/period, and primary-source URLs/dates. Shared groups reference the evidence-bearing relationship rows by ID. Missing graphs or edges mean unknown coverage. One cached graph read per company (plus a ticker lookup when the typed ticker has no graph); never starts paid discovery, infers exposure weights or estimates portfolio losses. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| roles | No | Counterparty roles from EACH subject company's point of view; default all four. Suppliers and customers preserve the direction of SUPPLIES_TO. | |
| tickers | Yes | Two to five distinct Bullrun listing tickers, e.g. AAPL, BMW or 6324.T. Use the listing ticker returned by search_stocks. US/European examples: AAPL, BMW, NESN. Most Asian listings keep their exchange suffix (6324.T, 0700.HK); some use bare codes (005930). Native or suffixed forms resolve only when one listing matches; search by company name or ISIN if unsure. Company names are not accepted here. | |
| verifiedOnly | No | Only VERIFIED edges when true. The default also includes SUGGESTED/NEEDS_REVIEW edges, explicitly labelled with their individual confidence and evidence. | |
| limitPerCompany | No | Maximum direct relationships returned per input company. Shared counterparties are prioritized; totals and any truncation are reported. |
Output Schema
| Name | Required | Description |
|---|---|---|
| totals | Yes | |
| tickers | Yes | |
| webPage | No | |
| warnings | Yes | |
| companies | Yes | |
| methodology | Yes | |
| retrievedAt | Yes | |
| platformLink | No | |
| relationships | Yes | |
| requestedRoles | Yes | |
| sharedCounterparties | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds substantial context beyond the read-only annotations: cost profile (one cached graph read per company plus a possible ticker lookup, no paid discovery), evidence statuses (VERIFIED vs SUGGESTED/NEEDS_REVIEW with confidence and sole-source flags), and the critical caveat that missing graphs or edges mean unknown coverage rather than no relationship. That last point is a behavioral trap an agent would otherwise fall into.
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, then layered with cost and evidence caveats; nearly every sentence carries operational weight. It runs long and includes return-format detail that the output schema already provides, which slightly dilutes focus.
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 a read-only tool with a full output schema and complete parameter descriptions, the definition is essentially complete: it covers cost, coverage gaps, evidence labeling and truncation. The return-shape sentence duplicates the output schema rather than adding new information, leaving only minor room for improvement.
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 the constraint that only stable entity IDs or exact tickers are accepted and that results are per-input-company, reinforcing the truncation semantics of limitPerCompany. Minor tension: it mentions entity IDs while the schema accepts only tickers, but overall it adds value over 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 and resource: compare the cached relationship graphs of two to five tickers, finding shared suppliers/customers/competitors/partners. This clearly separates it from single-company siblings like get_company_relationships and from compare_stocks/compare_etfs.
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 clear context for use (cross-ticker shared counterparty analysis, including cross-role overlaps) and important exclusions: it never starts paid discovery, never infers exposure weights or portfolio losses. It does not explicitly name which sibling to use instead for single-company relationship lookups, so routing against alternatives is left partly implicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
compare_etfsCompare ETFsARead-onlyInspect
Return a normalized side-by-side comparison of two to ten ETFs across selected classification, market, fund-data, cost, income, benchmark, price-performance, price-risk, holdings, and optional overlap modules. Include overlap to measure pairwise shared securities and weighted overlap from latest stored holdings, matched by security identity rather than ticker alone; cash, currency and derivatives are excluded. Missing holdings make overlap unavailable, while partial holdings make it a lower bound. Only requested modules run; overlap alone fetches no price history. Leaders are mechanical extrema, not recommendations. Currency, holdings dates and coverage caveats are explicit. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| include | No | Selected comparison modules. overlap is opt-in and returns pairwise shared holdings and weighted overlap from each fund's latest stored snapshot. | |
| tickers | Yes | Two to ten exact Bullrun ETF listing tickers. | |
| topSharedLimit | No | Maximum shared holdings per ETF pair when overlap is requested; does not limit the snapshots used in overlap calculations. | |
| performanceDays | No | Window in calendar days back from each fund's newest close; the start is the last close on or before that day. 365 matches the fund page and the screener's 1-year return. |
Output Schema
| Name | Required | Description |
|---|---|---|
| rows | Yes | |
| leaders | Yes | |
| overlap | No | |
| tickers | Yes | |
| webPage | No | |
| coverage | Yes | |
| warnings | Yes | |
| platformLink | No | |
| requestedModules | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnly/openWorld annotations, the description discloses real behavioral traits: overlap matching by security identity rather than ticker, exclusion of cash/currency/derivatives, missing holdings making overlap unavailable, partial holdings making it a lower bound, and that leaders are mechanical extrema rather than recommendations. These are exactly the caveats an agent needs to interpret results honestly.
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 core purpose is front-loaded in the first sentence and the remaining clauses each carry caveat information. Minor waste: the trailing 'Read-only.' restates the readOnlyHint annotation, and the middle is a dense run of caveat clauses that could be itemized.
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 multi-module comparison tool with an output schema (so return structure needn't be explained), the description covers selection semantics, failure modes, interpretation guidance, and currency/date caveats. Nothing material is missing for correct invocation.
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 semantics the schema lacks — identity-based matching, derivative/cash exclusion, and lower-bound behavior for the overlap module and its stored-snapshot basis. It does not expand on performanceDays or topSharedLimit beyond the already-rich 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 and resource ('normalized side-by-side comparison of two to ten ETFs') and enumerates exactly which modules the comparison spans. An agent can distinguish it from single-fund siblings like get_etf_holdings or get_etf_snapshot and from compare_stocks 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?
Usage is implied by the comparison framing and the note that 'only requested modules run' and 'overlap alone fetches no price history', which helps with module budgeting. However, it never routes the agent against alternatives — it does not say when to prefer this over get_etf_holdings, screen_etfs, or compare_company_exposures, nor any exclusions or prerequisites.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
compare_stocksCompare stocksARead-onlyInspect
Compare two to five stock tickers in one compact structured response: annual fundamentals and growth, quality ratios, stored valuation and Bullrun model context, and measured risk dials. Reports each fiscal year, source date, native quote/reporting currency and missing coverage. No currency conversion, quarterly-to-annual substitution, buy/sell ranking or generated research. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| include | No | Selected compact modules. Fundamentals and quality use the latest usable ANNUAL fiscal year only; valuation includes stored multiples and Bullrun model context; risk includes measured dials. | |
| tickers | Yes | Two to five distinct Bullrun stock tickers, e.g. AAPL, BMW, NESN, 6324.T or 7203. Use the listing ticker returned by search_stocks. US/European examples: AAPL, BMW, NESN. Most Asian listings keep their exchange suffix (6324.T, 0700.HK); some use bare codes (005930). Native or suffixed forms resolve only when one listing matches; search by company name or ISIN if unsure. Company names are not accepted here. |
Output Schema
| Name | Required | Description |
|---|---|---|
| rows | Yes | |
| tickers | Yes | |
| webPage | No | |
| coverage | Yes | |
| warnings | Yes | |
| methodology | Yes | |
| retrievedAt | Yes | |
| platformLink | No | |
| requestedModules | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, destructiveHint=false and openWorldHint=false, so the safety profile is covered. The description adds real behavioral context beyond that: annual-only fiscal years, no FX conversion, native reporting currency, reported missing coverage, and no ranking or generated research. Minor gaps remain around volume/rate limits and pagination, but the disclosure is well above baseline.
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 dense but front-loaded sentences: the capability and response shape come first, then the explicit exclusions. Every clause carries information, though the negation list is packed and could be split for readability. 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?
For a two-parameter, read-only comparison tool with an output schema, the description is nearly sufficient: it defines scope, module contents, currency/period handling and exclusions. It stops short of stating anything about response size or ordering across the compared tickers, which an agent might want to know when comparing five names.
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 `tickers` and `include` are already documented in detail, including ticker format and per-module semantics. The description adds only the ticker count (2-5) and a summary of module contents, which largely restates the schema. Baseline 3 is appropriate when the schema carries the weight.
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 names a specific verb (compare), a bounded resource (two to five stock tickers), and enumerates exactly what the compact response contains (fundamentals, quality, valuation, risk). It also distinguishes itself from nearby siblings like compare_etfs and find_stock_peers by scoping to stock tickers and to a fixed module set.
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 useful negative scoping ('No currency conversion, quarterly-to-annual substitution, buy/sell ranking or generated research'), which implicitly tells the agent when another tool is needed. However, no sibling is named as an alternative and there is no explicit 'use this when you want to compare X across 2-5 names vs. screen_stocks for discovery' guidance, leaving the choice partly to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_portfolio_draftCreate a portfolio draftAInspect
Use when the user wants you to BUILD or PROPOSE a brand-new portfolio for them — e.g. "build me a portfolio", "put together a dividend portfolio", "draft a portfolio of AI stocks", "create a new portfolio for $10k". Generates a REVIEWABLE paper-portfolio draft for the signed-in Bullrun user from a natural-language brief (e.g. "a diversified European dividend portfolio"). Requires OAuth with the write:drafts scope. Available to signed-in free accounts; daily usage limits and portfolio capacity still apply. This is DRAFT-ONLY and never changes any live position: the draft is saved to the user's account and appears in the Bullrun Portfolio tab under "Pending AI drafts", where the user reviews it and explicitly accepts it to create a new portfolio (or discards it). To suggest additions to an EXISTING portfolio instead, use create_position_draft. Tickers are chosen only from Bullrun's priced stock/ETF universe; pass instrumentUniverse for stocks only, ETFs only, or a mix. If the brief is vague, first ask ONE quick round of up to three multiple-choice questions (investing style, region focus, and size), each with a default the user can accept with "just pick for me", then build; skip any dimension the user already specified and do not interrogate across multiple turns.
| Name | Required | Description | Default |
|---|---|---|---|
| prompt | No | What kind of portfolio to draft, e.g. "a defensive dividend portfolio of large EU stocks". Optional: if you omit it, the server collects a quick style/region/size brief from the user directly (a native form on clients that support elicitation; otherwise it asks you to gather those first). | |
| maxPositions | No | Maximum number of holdings (3-20, default 10). | |
| startingCash | No | Starting cash in USD (default 10000). | |
| instrumentUniverse | No | Candidate universe: stocks only, ETFs only, or a mix. Default mix unless the prompt says otherwise. |
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 the OAuth write:drafts scope requirement, free-account availability with daily limits and capacity constraints, and the crucial behavioral trait that the draft never changes live positions but is saved and surfaced under 'Pending AI drafts' for explicit accept/discard. It also bounds ticker selection to Bullrun's priced universe.
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 usage trigger and example phrasings before the behavioral details, which is the right ordering. It is on the long side and repeats the draft-only message ('DRAFT-ONLY', 'never changes any live position'), but nearly every sentence carries operational 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-parameter mutation-ish tool with no output schema, the description covers prerequisites, account limits, side effects, where the result appears, and what the user must do next. Nothing an agent needs to invoke it correctly or set expectations 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: tickers come only from Bullrun's priced stock/ETF universe and instrumentUniverse selects stocks-only, ETFs-only, or a mix. It does not add format detail for maxPositions or startingCash beyond what the schema states, keeping it at a 4 rather than 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 verb and resource ('BUILD or PROPOSE a brand-new portfolio', 'Generates a REVIEWABLE paper-portfolio draft') with example user phrasings. It explicitly distinguishes itself from create_position_draft, which handles additions to an existing portfolio, so an agent can route correctly 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?
Provides explicit when-to-use triggers, names the alternative (create_position_draft) and the condition that selects it, and gives concrete guidance for vague briefs (one round of up to three multiple-choice questions with defaults, skip already-specified dimensions).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_portfolio_from_positionsSave a portfolio from explicit holdingsAInspect
Use when YOU (or the user) have ALREADY decided the exact holdings and want them saved as-is — e.g. after researching and settling on a specific basket with target weights. Persists a REVIEWABLE paper-portfolio draft built from the tickers you supply, sized by weight (percent) or by explicit USD amount. Unlike create_portfolio_draft this does NOT use the LLM and NEVER re-selects tickers: your basket lands exactly as given. Like the other draft tools it is available to signed-in free accounts within daily usage limits and portfolio capacity, and needs OAuth with the write:drafts scope. DRAFT-ONLY: the draft is saved to the user's Bullrun account and appears in the Portfolio tab under "Pending AI drafts", where the user reviews it and explicitly accepts it (creating a NEW portfolio) or discards it — it never changes any live position. Tickers must exist in Bullrun's priced stock/ETF universe; any that cannot be priced are returned in unresolved and skipped (use search_etfs / get_etf_snapshot / screen_stocks / get_stock_metrics to confirm exact tickers first). For a vague brief where the model should pick, use create_portfolio_draft instead.
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | Portfolio name. Default "Custom Portfolio Draft". | |
| cashPct | No | Explicit cash percentage to hold back. Overrides the weight-remainder rule. | |
| positions | Yes | The exact holdings to persist (1-30). Tickers are used verbatim, never re-selected. | |
| startingCash | No | Total portfolio cash in USD. Default 10000 in weight mode; the sum of amounts in amount mode. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations (readOnly=false, destructive=false, openWorld=false) by disclosing the full lifecycle: draft is saved to the Bullrun account, appears under "Pending AI drafts", requires explicit user acceptance to create a NEW portfolio, and never mutates live positions. It also names the OAuth scope (write:drafts) and the free-tier daily limits and portfolio-capacity constraints.
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 triggering condition and the sibling contrast, so the most decision-relevant content lands first. It is a dense block of several long clauses (auth scope, draft lifecycle, ticker resolution) that could be split for scanability, but 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 write tool with no output schema, the description covers the important unknowns: what gets created, where it appears, that it is inert until accepted, and that unpriceable tickers come back in `unresolved` and are skipped. It stops short of describing the rest of the successful response (e.g. the draft identifier), which leaves a minor gap.
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 schema already documents name, cashPct, weights, amounts, and startingCash in detail. The description reinforces the weight-vs-USD sizing choice and adds the universe constraint, but that is largely restatement rather than new parameter meaning — baseline 3 is appropriate when the schema carries the load.
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 — persists a reviewable paper-portfolio draft built from tickers the caller supplies — and immediately contrasts it with create_portfolio_draft ("does NOT use the LLM and NEVER re-selects tickers"). An agent can distinguish this from the vague-brief sibling 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 an explicit trigger condition ("when YOU (or the user) have ALREADY decided the exact holdings"), names the counter-case and the alternative tool ("For a vague brief where the model should pick, use create_portfolio_draft instead"), and even routes ticker verification to search_etfs / screen_stocks first.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_position_draftCreate a position draftAInspect
Use when the user asks what to BUY or ADD to an EXISTING portfolio — e.g. "what should I buy next", "suggest a stock or ETF for my portfolio", "what should I add", "recommend a position", "any ideas to round out my holdings". Generates REVIEWABLE suggested additions for one existing Bullrun portfolio. Requires OAuth with the write:drafts scope. Available to signed-in free accounts; daily usage limits and portfolio capacity still apply. This is DRAFT-ONLY: the suggested position(s) are saved to the user's account and appear in the Bullrun Portfolio tab under Pending AI drafts, where the user reviews and accepts them into the target portfolio or discards them. It never changes live holdings by itself. To draft a whole new portfolio from scratch use create_portfolio_draft; to test whether a specific named ticker fits, use get_portfolio_analytics with candidateTicker. Pass instrumentUniverse for stocks only, ETFs only, or a mix. If it is unclear, first confirm which portfolio (use list_portfolios when the user has more than one) and how many ideas (a single best idea or a few) in ONE quick step; otherwise just build.
| Name | Required | Description | Default |
|---|---|---|---|
| portfolioId | Yes | The Bullrun portfolio id to propose additions for. Use list_portfolios first if unsure. | |
| maxPositions | No | How many suggested additions to save, 1-5. Use 1 for a single-position idea; default 3. | |
| instrumentUniverse | No | Candidate universe: stocks only, ETFs only, or a mix. Default mix. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations by disclosing the OAuth scope (write:drafts), free-account availability, daily usage limits, and portfolio capacity constraints. It also defines the write's actual blast radius: drafts land in Pending AI drafts for review and 'never changes live holdings by itself', which resolves the ambiguity left by readOnlyHint=false with destructiveHint=false.
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 trigger condition and user phrasings before any mechanics, and every later sentence carries a distinct fact (scope, limits, draft semantics, alternatives, clarification rule). It is dense rather than padded, though the length pushes toward the upper bound of what an agent wants to read before a call.
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 non-destructive write with no output schema, the description covers what an agent needs: auth requirements, quota constraints, where the result surfaces, and that the user must explicitly accept it. Return-value detail is unnecessary because the post-call state is described behaviorally (drafts appear under Pending AI drafts).
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 structured fields already carry the parameter meaning. The description still adds intent mapping the schema lacks: 'a single best idea or a few' ties maxPositions to user phrasing, and 'Pass instrumentUniverse for stocks only, ETFs only, or a mix' frames the enum as a decision an agent must make rather than a raw value list.
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 ('Generates REVIEWABLE suggested additions for one existing Bullrun portfolio') with the scope narrowed to additions to an EXISTING portfolio. It explicitly contrasts with create_portfolio_draft and get_portfolio_analytics, so an agent can separate it from the nearest siblings 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?
Opens with 'Use when the user asks what to BUY or ADD...' and supplies four concrete user phrasings that trigger it. It names two alternatives with the conditions that select them (whole new portfolio -> create_portfolio_draft; testing a named ticker -> get_portfolio_analytics) and prescribes a single-step clarification flow with list_portfolios.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
find_stock_peersDiscover comparable stock candidatesARead-onlyInspect
Discover stock comparison candidates for one exact Bullrun ticker using stored industry or sector classification. Discloses the chosen classification, country preference, deterministic selection order, scan cap and issuer/listing exclusions. Excludes the subject, secondary listings and identifiable duplicate issuers/share classes. Returns compact stored multiples/growth plus ready-to-use compare_stocks arguments. Classification peers are not verified competitors or a financial-similarity ranking; no generated peers or paid graph discovery. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum peers. compare_stocks supports the subject plus at most four selected peers. | |
| ticker | Yes | Bullrun equity ticker, e.g. AAPL, BMW or 6324.T. Use the listing ticker returned by search_stocks. US/European examples: AAPL, BMW, NESN. Most Asian listings keep their exchange suffix (6324.T, 0700.HK); some use bare codes (005930). Native or suffixed forms resolve only when one listing matches; search by company name or ISIN if unsure. | |
| matchBy | No | auto uses exact stored industry when present, otherwise sector. It does not silently widen an empty industry result to the entire sector. | auto |
| sameCountryOnly | No | Restrict to the subject's exact stored country. Otherwise same-country candidates are shown first, followed by other countries. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover readOnly/destructive/openWorld, so the bar is lower, yet the description adds real context: deterministic selection order, a scan cap, issuer/listing exclusions, and disclosure of the chosen classification. It stops short of stating result volume or what happens when no industry or sector match exists beyond the matchBy note.
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 scope, exclusions, and caveats in short declarative sentences. It is dense and jargon-heavy ('Bullrun ticker,' 'scan cap,' 'issuer/listing exclusions') for a four-parameter tool, but nearly every clause carries selection-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?
With no output schema, the description still says what comes back: compact stored multiples/growth plus compare_stocks arguments. Combined with the coverage of selection order, exclusions, and classification caveats, an agent has enough to call it correctly and interpret results.
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; the description still adds meaning by framing sameCountryOnly as a preference-with-fallback ordering and matchBy as not widening an empty industry result. The 'compare_stocks supports the subject plus at most four selected peers' note reinforces limit semantics, though it does not restate the 1-10 range.
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: 'Discover stock comparison candidates for one exact Bullrun ticker using stored industry or sector classification.' It is clearly differentiated from the sibling compare_stocks, which it feeds rather than duplicates, and from screen_stocks by being a peer-discovery rather than a filter-scan 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 boundaries: stored classification only, no generated peers, no paid graph discovery, and peers are 'not verified competitors or a financial-similarity ranking.' It also names the downstream step by saying it returns 'ready-to-use compare_stocks arguments,' which routes the agent to the correct sibling for actual comparison.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_capabilitiesGet account capabilitiesARead-onlyInspect
Discover what the connected Bullrun account can do BEFORE attempting an action, so you can plan instead of learning by hitting a 403. Reports whether you are authenticated and as WHICH identity (email + userId), the account's Pro/trial status and why (subscription / trial / admin), the granted OAuth scopes, portfolio usage vs the free/max limits, and a per-tool entitlement map: create_portfolio_from_positions, create_portfolio_draft and create_position_draft (all available to signed-in free accounts, subject to usage limits), and whether another portfolio can be created now. Call this first when a draft/write tool might be gated, or to confirm which account a request will act on. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Although annotations already declare readOnlyHint=true, destructiveHint=false, and openWorldHint=false, the description adds substantial behavioral context beyond them. It explains what the tool reports, why it exists, and which downstream tools may be subject to account entitlements or usage limits.
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 description is front-loaded with the key instruction: call this before attempting an action. It is dense but mostly purposeful; the entitlement list is useful, though the sentence is long and could be structured as a short list for faster scanning.
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-parameter, read-only discovery tool with no output schema, the description is complete enough. It explains what is returned in prose and gives the agent a clear operational reason to call 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?
The tool takes zero parameters, so the baseline is 4. There are no parameter names, enums, or formats to clarify in the description.
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 uses a specific verb and resource: discovering what the connected Bullrun account can do. It clearly enumerates the reported capability categories, including authentication identity, Pro/trial status, OAuth scopes, portfolio usage limits, and per-tool entitlements, making it distinguishable from the sibling tools.
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 timing guidance: call this first before attempting an action, especially when a draft/write tool might be gated. It also states an alternate use case: confirming which account a request will act on, which directly maps to real agent workflows.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_company_data_coverageGet company data availability and freshnessARead-onlyInspect
A cheap stored-data manifest for one exact company: available datasets, latest reporting periods, actual ingestion/computation timestamps where stored, and cached relationship graph status. Call before deeper research when coverage or freshness is uncertain. This reads indexed metadata, not every research endpoint, and never starts enrichment. Availability is not completeness or accuracy. A null stored timestamp means freshness is unknown; a reporting period is not an ingestion date. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| ticker | Yes | Bullrun company ticker, e.g. AAPL, SAP or 6324.T. Use the listing ticker returned by search_stocks. US/European examples: AAPL, BMW, NESN. Most Asian listings keep their exchange suffix (6324.T, 0700.HK); some use bare codes (005930). Native or suffixed forms resolve only when one listing matches; search by company name or ISIN if unsure. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint/openWorldHint=false, but the description adds genuinely new behavioral context: it is cheap, it does not trigger enrichment, availability is not completeness or accuracy, a null timestamp means freshness is unknown, and a reporting period is not an ingestion date. These caveats directly prevent misinterpretation of the returned manifest.
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 resource and its contents, then the usage rule, then caveats. No sentence is filler — each clause either scopes the tool or prevents a specific misreading of its output.
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 no output schema, the description carries the burden of describing returns and does so (datasets, periods, timestamps, graph status), plus it flags freshness/accuracy caveats. Nothing an agent needs to invoke it correctly or interpret 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% and the single ticker parameter is documented in extensive detail (examples, suffix behavior, fallback advice) in the schema itself. The description adds nothing about the ticker beyond 'one exact company', 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 ('cheap stored-data manifest for one exact company') and enumerates exactly what it returns: available datasets, latest reporting periods, ingestion/computation timestamps, cached relationship graph status. It also explicitly delineates itself from deeper research endpoints, so an agent can distinguish it from siblings like get_stock_metrics or get_company_relationships.
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?
'Call before deeper research when coverage or freshness is uncertain' gives a clear triggering condition, and 'never starts enrichment' plus 'reads indexed metadata, not every research endpoint' bound the scope. It stops short of naming specific alternative tools, which keeps it below a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_company_newsGet company news with sources and freshnessAInspect
Get cached company news for one exact Bullrun ticker, newest publication first, with publisher, source URL, publication date and stored-fetch freshness when recorded. Optional since cutoff and limit up to 50; only the newest 50 stored articles are searched. Useful for company headlines and article sources; use get_corporate_calendar for scheduled earnings/dividends and get_earnings_call_transcript for call text. Reading news also registers demand and requests a best-effort background cache refresh; this response does not wait for or confirm a refresh. Cached/empty/stale results do not establish that no new events exist. Does not change portfolios or place trades.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum returned articles, newest publication first. Up to 50 cached source articles are read before cutoff filtering. | |
| since | No | Inclusive publication-time cutoff. YYYY-MM-DD means midnight UTC; timestamps need an explicit Z or UTC offset. Applied to the newest 50 stored articles, not a full historical news archive. | |
| ticker | Yes | Bullrun company ticker, e.g. AAPL, SAP, ABBN or 6324.T. Use the listing ticker returned by search_stocks. US/European examples: AAPL, BMW, NESN. Most Asian listings keep their exchange suffix (6324.T, 0700.HK); some use bare codes (005930). Native or suffixed forms resolve only when one listing matches; search by company name or ISIN if unsure. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations by disclosing a real side effect the annotations only imply via readOnlyHint=false: reading news registers demand and triggers a best-effort background refresh that the response does not wait for or confirm. It also bounds the search scope (only newest 50 stored articles) and states the tool does not modify portfolios or place trades, which is exactly the kind of context an agent needs before treating stale output as truth.
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, scope and ordering, then alternatives, then behavioral caveats. It is dense and long-ish, but every sentence carries operational information (ordering, 50-article cap, refresh behavior, no-write guarantee), 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?
With no output schema, the description still enumerates the returned fields including stored-fetch freshness, and it explains best-effort refresh behavior and the limits of cached/empty results. Nothing an agent needs to call it correctly or interpret an empty 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 description coverage is 100%, so ticker syntax, since cutoff semantics and the limit cap are already fully documented in the schema; the description mostly restates 'since cutoff and limit up to 50'. Baseline 3 applies since the schema carries the parameter burden.
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 ('cached company news for one exact Bullrun ticker') plus ordering ('newest publication first') and returned fields (publisher, source URL, date, freshness). It explicitly separates itself from get_corporate_calendar and get_earnings_call_transcript, 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?
Gives an explicit positive use case ('company headlines and article sources') and names two alternatives with the conditions that select them (scheduled earnings/dividends vs. call text). When-not guidance is also present: cached/empty/stale results do not prove absence of new events.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_company_relationshipsGet company relationship networkARead-onlyInspect
Bullrun's company relationship graph for one stock: named competitors, suppliers, customers and partners, each with its Bullrun ticker when the counterparty is listed, verification status (VERIFIED against a primary filing/source vs search-SUGGESTED), confidence, sole-source flag, quantified dependence where disclosed (e.g. "Cirrus Logic gets 91% of revenue from Apple") and the evidence behind it. Use for supply-chain and second-order risk questions ("who supplies X", "who depends on X", "who competes with X", "which listed companies are exposed if X stumbles"), then call get_company_risk or get_stock_metrics on the counterparties' tickers. Returns only the cached graph and never starts a paid discovery run; a company with no graph yet reports status "none". A missing edge is not proof of no relationship. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| roles | No | Which relationships to return, from this company's point of view. Default: all four. | |
| ticker | Yes | Bullrun ticker, e.g. "AAPL", "SAP", "ASML". Use the listing ticker returned by search_stocks. US/European examples: AAPL, BMW, NESN. Most Asian listings keep their exchange suffix (6324.T, 0700.HK); some use bare codes (005930). Native or suffixed forms resolve only when one listing matches; search by company name or ISIN if unsure. | |
| evidence | No | none = omit evidence sources, keeping counterparties, measurements and evidence counts; sources = source title/URL/type per edge; excerpts = also quoted evidence text. | sources |
| limitPerRole | No | Max counterparties per role, verified and highest-confidence first. | |
| verifiedOnly | No | true = only edges confirmed against a primary source (filing, company release). false also returns search-suggested edges, each labelled with its status and confidence. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the read-only annotation, the description discloses that the tool returns only the cached graph and never starts a paid discovery run, that a company with no graph reports status 'none', and that a missing edge is not proof of no relationship. It also explains verification statuses, confidence, sole-source flags, and quantified dependence evidence, giving the agent important behavioral context.
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 description is front-loaded with the resource and returned fields, then moves to use cases, follow-on calls, caching behavior, and caveats. Despite its length, every sentence adds useful context and there is no obvious 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?
With no output schema, the description sufficiently explains what the graph contains, including relationship roles, tickers, verification status, confidence, dependence metrics, and evidence. It also covers caching behavior, missing-data caveats, and safety context, so an agent has enough information to call and interpret the 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?
Schema description coverage is 100%, so the schema already documents all five parameters in detail, including the roles enum, evidence modes, limitPerRole, and verifiedOnly. The description reinforces the role categories and verification/evidence concepts but does not add parameter-level semantics beyond what the schema already provides.
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 clearly states the resource: Bullrun's company relationship graph for one stock, enumerating competitors, suppliers, customers and partners and the fields returned. It is specific, but it does not explicitly contrast this tool with close siblings such as find_stock_peers or compare_company_exposures; it only names follow-on tools like get_company_risk and get_stock_metrics.
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 provides explicit use cases ('who supplies X', 'who depends on X', 'who competes with X', second-order risk) and names follow-on tools to call on counterparties. It also discloses the cached-only limitation and the 'missing edge is not proof' caveat, but it does not explicitly say when not to use this versus a sibling like find_stock_peers.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_company_riskGet company risk profileARead-onlyInspect
Bullrun's company risk read for one stock: a 0-100 composite risk score and six mechanism dials (market expectation, operating pressure, cash conversion, leverage & coverage, competitive position, concentration) with band (Contained/Normal/Elevated/Stretched/Acute), direction vs the prior reading, the driving input and a plain-English explanation; plus filing-derived risk factors (severity, mechanism, source filing), identified supplier concentration (share of cost base covered, HHI, sole-source count, top supplier share) and recent material events. Use for "how risky is X", "what are the main risks for X", "is X's supply chain concentrated", or before adding a stock to a portfolio. Pair with get_company_relationships for the named competitors/suppliers/customers behind the concentration dial. Bands describe measured strain, never a buy/sell view. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| detail | No | summary = scores, bands, drivers and explanations; full = also every per-input term behind each category score. | summary |
| ticker | Yes | Bullrun ticker, e.g. "AAPL", "ASML", "NESN", "6324.T" or "0700.HK". Use the listing ticker returned by search_stocks. US/European examples: AAPL, BMW, NESN. Most Asian listings keep their exchange suffix (6324.T, 0700.HK); some use bare codes (005930). Native or suffixed forms resolve only when one listing matches; search by company name or ISIN if unsure. | |
| include | No | Modules to return. dials = composite + six mechanism dials (market expectation, operating pressure, cash conversion, leverage, competitive position, concentration); risk_factors = filing-derived risk factors (10-K/annual report) with severity and mechanism; supplier_exposure = identified supplier spend concentration; events = recent restructuring/legal/supply/recall events; headline = latest news headline beside the dials. Default: dials, risk_factors, supplier_exposure. | |
| maxEvents | No | Max recent company events to return, most severe first. | |
| maxRiskFactors | No | Max filing risk factors to return, most severe first. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, destructiveHint=false, openWorldHint=false, so safety is covered; the description adds real non-annotation context: dials have a direction versus the prior reading, risk factors are filing-derived (10-K/annual report), and bands measure strain rather than a buy/sell recommendation. It does not discuss latency, coverage gaps, or what happens when a module has no data, which would be needed for 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?
Effectively one long front-loaded sentence plus three short follow-ups; the core purpose and return contents come first and nothing is wasted. The opening sentence is dense with parenthetical enumerations that could be tightened, costing it the top score.
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, no-output-schema, five-parameter analytics tool the description does the heavy lifting: it names every returned module, the band vocabulary, and the severity/mechanism metadata on risk factors. Missing only edge-case behavior (empty modules, ticker ambiguity handling), which the ticker schema partly covers.
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 each parameter already carries a thorough description, including ticker resolution rules and per-module meanings for 'include'. The prose adds no parameter-level guidance beyond restating the module set, 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?
Opens with a specific verb and resource ('company risk read for one stock') and immediately enumerates the concrete outputs: a 0-100 composite score plus six named mechanism dials with bands, direction, driver and explanation. It is clearly distinguishable from siblings like get_etf_risk, get_risk_movers and get_company_risk_history, none of which are described as a per-stock composite with mechanism dials.
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 trigger phrasings ('how risky is X', 'is X's supply chain concentrated') and a workflow cue ('before adding a stock to a portfolio'), plus an explicit pairing instruction with get_company_relationships. It lacks an explicit when-not-to-use clause (e.g. versus get_company_risk_history for trend-only questions), which keeps it below a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_company_risk_historyGet company risk history and changesARead-onlyInspect
Stored historical company risk category readings and their observed input changes. Shows dates, computation times, formula versions, score changes, changing input coverage and measurement bases. Use for 'how has X's risk changed?' and 'which inputs changed?'. These are retained category scores, not a complete daily series or proof of causation. Missing history is unknown, never a zero risk score. Read-only; does not run risk computation or paid discovery.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Latest stored run dates to return, oldest first; each date carries its change from the previous stored date. Retention and gaps vary. Full detail supports at most six dates. | |
| detail | No | Summary keeps scores, explanations and up to three changed inputs per category; full includes stored input terms and all returned term changes. | summary |
| ticker | Yes | Bullrun company ticker, e.g. AAPL, SAP or 6324.T. Use the listing ticker returned by search_stocks. US/European examples: AAPL, BMW, NESN. Most Asian listings keep their exchange suffix (6324.T, 0700.HK); some use bare codes (005930). Native or suffixed forms resolve only when one listing matches; search by company name or ISIN if unsure. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With annotations already covering read-only and closed-world, the description still adds substantive semantics: missing history means unknown rather than zero risk, gaps and retention vary, scores are not proof of causation. These are interpretation rules an agent cannot get from the annotations or 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 what is returned, then usage, then caveats, then safety in four dense sentences. The mid-sentence enumeration ('changing input coverage and measurement bases') is slightly packed but every sentence carries 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?
There is no output schema, so the description carries the burden of describing results, and it does: dates, computation times, formula versions, score changes, changed inputs. Combined with the missing-data caveat, an agent knows enough to call and interpret 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% and the schema already explains limit (latest stored run dates, max 30), detail (summary vs full), and ticker formats. The description adds no parameter meaning beyond that, 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 ('Stored historical company risk category readings and their observed input changes') and enumerates what the payload contains (dates, computation times, formula versions, score changes). It distinguishes itself from the current-state and timeseries siblings by explicitly saying these are retained category scores, not a complete daily series.
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 user questions this answers ('how has X's risk changed?', 'which inputs changed?') and gives an exclusion ('does not run risk computation or paid discovery'). It stops short of naming the alternatives, e.g. get_company_risk for the current reading or get_risk_movers for cross-company movers, so routing between siblings still requires inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_corporate_calendarGet corporate calendarARead-onlyInspect
Read stored upcoming earnings and ex-dividend dates, plus recent equity listings. Supports ticker/company search and explicit effective windows, market-cap filters, native listing quote currencies, available source metadata and partial coverage. Recent first-trade dates are not confirmed IPOs or an upcoming IPO schedule. Calendar dates and estimates can change; missing events mean unknown coverage, never proof that no event exists. Read-only; at most three calendar requests, plus a ticker lookup when q carries a Yahoo exchange suffix.
| Name | Required | Description | Default |
|---|---|---|---|
| q | No | Optional case-insensitive ticker or company-name contains search, also matched with spaces removed. This is not an exact ticker filter. A Yahoo-style symbol whose listing Bullrun stores in another form (BMW.DE as BMW, 7203.T as 7203) is searched under the stored ticker. A nonblank search widens earnings/ex-dividend to 120 days and listings to 60 months. % and _ act as search wildcards. | |
| days | No | Forward days for earnings and ex-dividend, inclusive of the API server's current date. A nonblank q makes the backend use 120 days regardless of this value. | |
| limit | No | Maximum rows per selected calendar, not an overall result count. A full page may omit other matching events. | |
| include | No | Selected stored calendars: upcoming earnings, upcoming ex-dividend dates, and recent listings (not an upcoming IPO schedule). | |
| minCapUsd | No | Optional minimum market capitalization in USD. Omit to retain API defaults: 50 million for earnings/ex-dividend and zero for listings. Listings with unknown market cap are retained even with a positive floor. | |
| listingMonths | No | Trailing months for recent listings. A nonblank q makes the backend search 60 months regardless of this value. |
Output Schema
| Name | Required | Description |
|---|---|---|
| query | Yes | |
| webPage | No | |
| warnings | Yes | |
| calendars | Yes | |
| methodology | Yes | |
| retrievedAt | Yes | |
| platformLink | No | |
| requestedTypes | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations by disclosing partial coverage, that missing events mean unknown coverage rather than absence, that dates and estimates change, that q silently widens earnings/ex-dividend to 120 days and listings to 60 months, and a request budget of at most three calendar requests plus a ticker lookup. These are real behavioral traits an agent cannot get from the 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?
Dense but front-loaded: purpose first, then caveats, then the request budget. Every sentence carries signal, though the closing sentence about three calendar requests and the Yahoo suffix lookup is compressed to the point of being hard to parse.
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 and full parameter descriptions, the description covers coverage limits, data volatility, and read-only safety. A brief note on how the three calendars interleave in the response would close the remaining gap, but nothing required 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 baseline is 3, but the description adds cross-parameter interaction context (search widening effective windows, native listing quote currencies, source metadata) that the schema does not state. The q-overrides-days behavior is repeated from the schema, but the surrounding effects are 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?
The opening sentence names a specific verb and resource: reading stored upcoming earnings, ex-dividend dates, and recent listings. Scope is clear enough that an agent can tell it apart from price-history or estimates tools. It does not explicitly name the nearest sibling (get_forward_estimates) as an alternative.
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 the tool is read-only and clarifies that listings are not an IPO schedule, which implies when the data is appropriate. However, there is no explicit when-to-use versus alternatives such as get_forward_estimates or get_company_data_coverage, leaving selection to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_country_macroGet country macro profileARead-onlyInspect
One country's macro dashboard from Bullrun's Global Markets warehouse: a 0-100 macro stress score (higher = more stress) built from six pillars - labour (unemployment, its change, youth unemployment), housing (real house prices, price-to-income and price-to-rent vs history), credit (BIS credit-to-GDP gap, household debt service, household credit), fiscal (government debt, fiscal balance), external (current account) and cycle (GDP growth, inflation) - with every input's latest value, period, source (OECD, IMF, BIS, World Bank, Eurostat), its stress contribution and a historyCode for get_macro_history. Use for "how is the German economy doing", "is there a housing bubble in Canada", "macro risks in Italy", or to judge the backdrop for a country's stocks. A thinly covered country returns state "insufficient", never a falsely calm score. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| country | Yes | Country name, e.g. "Germany", "United States" (aliases like US, UK, Korea, Eurozone are understood). Also "Euro Area". |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already carry readOnlyHint/openWorldHint/destructiveHint, yet the description adds genuine behavioral context beyond them: what the score means and its direction (higher = more stress), which upstream sources feed it (OECD, IMF, BIS, World Bank, Eurostat), and a failure-mode guarantee that thinly covered countries return state "insufficient" rather than a misleadingly calm score. That last point is exactly the kind of non-obvious trait an agent needs before interpreting a result.
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 clause is front-loaded on the resource and the stress score, and the closing sentence about the insufficient state is well placed. The long mid-sentence enumeration of all eighteen constituent indicators is dense and could be compressed to pillar names alone without losing routing value, 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?
With no output schema, the description carries the full burden of describing returns and does so thoroughly: latest value, period, source, per-input stress contribution, and a historyCode for follow-up calls, all scoped to the six pillars. An agent knows both what it gets back and how to continue into get_macro_history.
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?
There is a single required parameter with 100% schema description coverage, and the schema already documents alias handling (US, UK, Korea, Eurozone, Euro Area). The description adds nothing about the country argument itself, so this sits at the baseline where the schema does all the work.
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 (a single country's macro dashboard from the Global Markets warehouse) and defines the core artifact precisely: a 0-100 stress score with explicit directionality and six named pillars. It also distinguishes itself from the sibling get_macro_history by naming the historyCode field that feeds it, 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?
Gives concrete triggering questions ("how is the German economy doing", "is there a housing bubble in Canada", "macro risks in Italy") plus a use case (judging a country backdrop for stocks), which is unusually actionable. It hints at the get_macro_history relationship but never states the inverse exclusion or how it differs from get_macro_indicators, so the routing guidance is clear but not exhaustive.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_earnings_call_transcriptGet earnings call transcriptAInspect
Read cached earnings-call paragraphs for one exact Bullrun ticker, optionally filtered by fiscal period or search text. A best-effort free background import collects at most the two latest retained calls from DefeatBeta for supported US listings, with a 24-hour stored-data cooldown; the first read may be empty. Coverage and source publication lag vary. Speaker names and paragraph order are retained; roles and prepared/Q&A section labels may be unavailable. Does not change portfolios or user data.
| Name | Required | Description | Default |
|---|---|---|---|
| search | No | Optional case-insensitive text/speaker search across transcript chunks. | |
| ticker | Yes | Bullrun ticker, e.g. "CRWD", "SPGI", "V". Use the listing ticker returned by search_stocks. US/European examples: AAPL, BMW, NESN. Most Asian listings keep their exchange suffix (6324.T, 0700.HK); some use bare codes (005930). Native or suffixed forms resolve only when one listing matches; search by company name or ISIN if unsure. | |
| maxChunks | No | Maximum speaker-tagged transcript chunks to return. | |
| fiscalYear | No | Optional fiscal year filter. | |
| fiscalQuarter | No | Optional fiscal quarter filter. | |
| maxCharsPerChunk | No | Maximum characters per transcript chunk in the MCP response. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond annotations, it discloses important behavior: cached/imported data, a 24-hour cooldown, possibly empty first reads, variable source and publication lag, retained speaker names and paragraph order, and potentially missing roles or section labels. It also explicitly states that portfolios and user data are not changed, which clarifies the read-only intent despite readOnlyHint=false.
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 purpose is front-loaded in the first sentence, followed by compact caveats about import behavior, data freshness, and output limitations. Every sentence adds useful context and there is 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?
With no output schema, the description does enough to set expectations about returned transcript paragraphs, speaker names, paragraph order, and missing section labels. It could more explicitly describe the return shape or pagination behavior, but it is otherwise complete for a cached transcript 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?
Schema coverage is 100%, so all six parameters are already documented in the input schema with descriptions and bounds. The description only restates that fiscal period and search text are optional filters and does not add syntax or selection guidance beyond the schema, so the baseline score of 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?
The description opens with a specific verb and resource: 'Read cached earnings-call paragraphs for one exact Bullrun ticker,' and immediately clarifies optional fiscal-period and search-text filtering. This is precise enough for an agent to distinguish it from portfolio, stock-metrics, and other sibling tools.
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 useful usage context: the tool reads cached data, a background import may populate up to two recent calls, and the first read may be empty due to a 24-hour cooldown. It does not explicitly name alternatives or when not to use it, but no sibling transcript tool is present, so the missing exclusion guidance is minor.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_etf_exposuresGet ETF exposuresARead-onlyInspect
Calculate sector, country, currency, and broad asset exposure from the latest stored ETF holdings. Sector and country come from the fund provider's own holdings file where it states them (normalized to Bullrun's sector and country names), otherwise from the Bullrun instrument the holding resolves to by ISIN or by symbol with a matching company name. Currency uses the reported holding currency, else an explicitly disclosed estimate from the company's home-market listing or usual country currency. This is a holding quote/listing-currency proxy, not revenue FX exposure, economic currency risk or hedge-adjusted fund exposure. Positions without a classification or currency basis are Unclassified / Not reported. Sector and currency cover all stored rows; country covers securities and excludes cash and derivatives. Coverage states complete bucket weights and any buckets omitted by limitPerType. Broad asset class comes from the normalized fund profile. Factor and thematic look-through are unavailable until dedicated source data exists. Coverage states how much fund weight was classified and how, so partial top-holdings data is never presented as full exposure. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| types | No | ||
| ticker | Yes | Exact Bullrun ETF listing ticker. | |
| limitPerType | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| ticker | Yes | |
| webPage | No | |
| coverage | Yes | |
| warnings | Yes | |
| exposures | Yes | |
| platformLink | No | |
| availableTypes | Yes | |
| notLoadedTypes | No | |
| requestedTypes | Yes | |
| unavailableTypes | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description is unusually rich on behavior beyond the annotations: data provenance (provider holdings file vs. Bullrun instrument resolution by ISIN/symbol+name), fallback rules, exclusions (country excludes cash and derivatives), and unclassified handling. However, it omits how the resolution fallbacks affect the 'Unclassified / Not reported' bucket and gives no sense of freshness/staleness of 'latest stored' holdings, so a 3 rather than 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, but the text is dense and repetitive — two separate sentences begin 'Coverage states...' — and the trailing 'Read-only.' merely restates readOnlyHint=true. Most sentences do carry real information, but the passage would read better 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?
For a tool with an output schema, no return-value prose is required, and the description covers what an agent needs: sources, fallbacks, exclusions, unclassified semantics, coverage caveats that prevent misreading partial top-holdings data as full exposure, and the unsupported factor/thematic types.
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 schema coverage at 33% (only `ticker` documented in-schema), the description compensates well: it explains what each `types` value yields and how each is derived, and it explains that coverage reports 'any buckets omitted by limitPerType.' The ticker's exact-listing requirement is left to the schema, which already covers 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?
States a specific verb and resource: 'Calculate sector, country, currency, and broad asset exposure from the latest stored ETF holdings.' An agent can tell this is the derived-exposure view rather than the raw holdings (get_etf_holdings), though no sibling is named explicitly to sharpen the boundary.
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 usefully rules out factor and thematic look-through ('unavailable until dedicated source data exists'), steering the agent away from invalid `types` values. But there is no explicit guidance on when to pick this over get_etf_holdings, get_etf_risk, or compare_etfs, and no stated prerequisites.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_etf_filter_optionsList ETF filter valuesARead-onlyInspect
List the exact values accepted by the categorical filters on search_etfs and screen_etfs — asset classes, categories, index keys, product/wrapper types, regions, domiciles, currencies, exchanges, and (on request) issuers and focus strings. Those filters match exactly, so a guessed string returns zero rows and looks like "no such ETF exists"; call this first whenever a filter value is not already known to be valid. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum values per facet, 1-1000. Each facet reports its untruncated total. | |
| facets | No | Which facets to return. Defaults to everything except the long tails fundFamilies (~890 issuers) and industries (~650 focus strings) — request those explicitly, ideally with search. | |
| search | No | Case-insensitive substring filter applied to every requested facet, e.g. "ishares" against fundFamilies or "world" against categories. |
Output Schema
| Name | Required | Description |
|---|---|---|
| notes | Yes | |
| facets | Yes | |
| search | Yes | |
| totals | Yes | |
| webPage | No | |
| platformLink | No | |
| truncatedFacets | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish read-only safety, but the description adds important behavioral context beyond them: filter matching is exact, wrong guesses fail silently as zero results, and long-tail facets should be requested explicitly. That directly affects how an agent should 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?
The description is two sentences, front-loaded with what the tool returns and why it matters. Every clause earns its place by naming consumers, failure mode, and call-order guidance.
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 and full schema coverage, the description need not detail return values. It supplies the critical operational context: exact matching, zero-row failure mode, and when to call it before search_etfs or screen_etfs.
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 schema already explains limit, facets, and search in detail. The description reinforces the facet categories and notes that issuers and focus strings are long tails, but it does not add syntax or constraints beyond the structured 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?
The description uses a specific verb and resource: list exact values accepted by categorical filters on search_etfs and screen_etfs. It clearly distinguishes this metadata-listing tool from the sibling search and screening tools that consume those values.
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 guidance: call this first whenever a filter value is not already known to be valid. It also explains why by noting exact-match filtering means guessed strings return zero rows and can be mistaken for no such ETF existing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_etf_fundGet ETF fund by ISINARead-onlyInspect
Resolve one FUND rather than one listing. Given an ISIN (or any venue ticker of the fund) it returns the fund's identity, costs, index, distribution policy, wrapper type and every venue it is listed on with exchange and trading currency. Use this when the user quotes an ISIN, asks "which ticker do I buy on my exchange?", or when several tickers may be the same underlying fund. Ratios are percentage points. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| isin | No | Fund ISIN, e.g. IE00B4L5Y983. The identifier European factsheets and brokers quote. | |
| ticker | No | Any venue listing ticker of the fund, e.g. EUNL.DE or IWDA.L. Resolved to its fund ISIN first. Provide this or isin. |
Output Schema
| Name | Required | Description |
|---|---|---|
| fund | Yes | |
| found | Yes | |
| query | Yes | |
| webPage | No | |
| listings | Yes | |
| warnings | Yes | |
| platformLink | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint/openWorldHint/destructiveHint, so the bar is lower; the description still adds real context by spelling out the resolution path (ticker → fund ISIN) and the unit convention 'Ratios are percentage points.' The trailing 'Read-only' restates the annotation and earns nothing.
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 key differentiator ('Resolve one FUND rather than one listing') is front-loaded, and the remaining sentences move from inputs to outputs to use cases with little waste. The final 'Read-only' is redundant filler against the 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?
An output schema exists and the input schema is fully described, so nothing more is required; the description still previews the payload shape, which helps an agent choose this tool over the ETF snapshot/search siblings. Complete for a read-only lookup.
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 parameters (isin, ticker) are already documented with examples in the schema. The description's 'any venue ticker of the fund' and 'or any venue ticker' framing slightly reinforces the either/or input but adds no format or constraint detail 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 and resource — resolve a FUND (not a listing) from an ISIN or venue ticker — and enumerates exactly what comes back: identity, costs, index, distribution policy, wrapper type, and all venue listings with exchange and currency. That distinction from listing-level siblings (get_etf_snapshot, get_etf_holdings) is made explicit in the first sentence.
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 three concrete trigger conditions (user quotes an ISIN, asks which ticker to buy on their exchange, or several tickers may be the same fund), which is genuinely actionable routing guidance. It does not name alternative tools or state when this is the wrong choice.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_etf_holdingsGet ETF holdingsARead-onlyInspect
Return the latest stored ETF holdings snapshot with opaque cursor pagination. The response reports the provider's stated holdings count, stored row count, covered weight, and whether the stored rows appear complete. Treat isComplete=false or null as partial look-through data. Historical as-of selection will be added when the upstream API exposes it. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum holdings to return on this page, 1-100. | |
| cursor | No | Opaque nextCursor returned by a previous get_etf_holdings call for the same ticker. | |
| ticker | Yes | Exact Bullrun ETF listing ticker, including its exchange suffix when present. |
Output Schema
| Name | Required | Description |
|---|---|---|
| ticker | Yes | |
| webPage | No | |
| asOfDate | Yes | |
| coverage | Yes | |
| holdings | Yes | |
| returned | Yes | |
| nextCursor | Yes | |
| platformLink | No | |
| totalRowsAvailable | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare read-only and closed-world, but the description adds meaningful context beyond them: data is a stored snapshot (not live), pagination is cursor-based, the response exposes provider count vs stored count vs covered weight, and isComplete=false/null means partial coverage. The only omission is any mention of freshness or staleness of the stored snapshot.
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 sentences, front-loaded with what the tool returns. The future-feature sentence about historical as-of selection earns its place by preempting a likely agent assumption, though it 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?
With an output schema present the description needn't enumerate return fields, yet it usefully summarizes the completeness signals an agent must interpret. Combined with 100% schema coverage and read-only annotations, an agent has enough to call it correctly; only explicit sibling routing for historical/exposure use cases 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 ticker, limit, and cursor are fully documented in the schema itself. The description reinforces cursor pagination ('opaque cursor pagination') but adds no format or syntax detail beyond what the schema already provides, 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?
The description gives a specific verb and resource — 'Return the latest stored ETF holdings snapshot' — and the word 'stored' plus 'snapshot' signals this is a persisted holding list rather than the exposure/aggregate views offered by siblings like get_etf_exposures or get_etf_snapshot. It stops short of explicitly contrasting itself with those siblings, so an agent must infer the distinction.
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?
'Treat isComplete=false or null as partial look-through data' and the note that historical as-of selection is not yet available give real usage context. However, there is no explicit statement of when to choose this over get_etf_exposures or get_etf_fund, which are the closest alternatives in the sibling list.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_etf_index_groupCompare funds tracking one indexARead-onlyInspect
Answer "what is the cheapest way to track ?". Returns every fund tracking one index ordered cheapest fee first, deduplicated to one row per FUND rather than per venue listing (a five-venue UCITS fund is one choice, not five) with its listingCount and venues. Defaults to UCITS-buyable domiciles. Omit indexKey to list the available index families. Fees are percentage points and the response states how many funds publish no fee at all, so a "cheapest" claim is never made over silently omitted funds. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum funds (or index families) to return, 1-100. | |
| scope | No | ucits (default) restricts to domiciles a European retail investor can actually buy. all adds US-domiciled trackers, which look cheaper but are not purchasable by EU retail. | ucits |
| currency | No | Keep only funds with a listing trading in this currency (e.g. CHF, EUR, USD, GBP) and name that line. | |
| exchange | No | Keep only funds listed on this venue and name each one's ticker there, e.g. SW (SIX Swiss Exchange), XETRA, LSE, AS, MI. A Swiss investor wanting the SIX line passes SW. | |
| indexKey | No | Normalized index key, e.g. SP500, MSCI_WORLD, NASDAQ100, MSCI_EM, EURO_STOXX_50, TOPIX, FTSE100. Omit to list every index family that has at least one fund. | |
| distributionPolicy | No | Optionally keep only accumulating or only distributing share classes. |
Output Schema
| Name | Required | Description |
|---|---|---|
| mode | Yes | |
| found | Yes | |
| funds | Yes | |
| scope | Yes | |
| webPage | No | |
| coverage | Yes | |
| indexKey | Yes | |
| warnings | Yes | |
| platformLink | No | |
| indexFamilies | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the readOnlyHint annotation by disclosing ordering (cheapest fee first), fund-level deduplication, the listingCount/venues payload, the UCITS-by-default scope, and the data-quality caveat that funds with no published fee are counted and named. This is exactly the kind of caveat that prevents an agent from overclaiming "cheapest". Minor gap: no pagination/limit behavior described in prose, though limit is schema-documented.
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 disambiguating question and the core result shape, and every sentence carries information (ordering, dedup, defaults, fee-omission caveat). Some sentences are long and packed with parentheticals, slightly reducing scanability, but there is 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, so return values need not be enumerated; the description still supplies the crucial shape (fund-level rows, listingCount, venues, fee-omission count) and the default scope behavior. Nothing an agent needs to call this correctly or interpret results honestly 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 schema already explains limit, scope, currency, exchange, indexKey, and distributionPolicy thoroughly (including the SW example for Swiss investors and the SP500/MSCI_WORLD key format). The description only restates the indexKey-omission behavior and defaults, adding no syntax or semantics the schema lacks. 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 (returns every fund tracking one index) plus the exact question it answers, and distinguishes itself from listing-level siblings by emphasizing dedup to one row per FUND rather than per venue listing. An agent can tell this apart from compare_etfs, screen_etfs, or get_etf_fund 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 clear triggering question ("what is the cheapest way to track <index>?") and the indexKey-omission path for discovery, plus the default scope caveat. It does not explicitly name alternatives such as simulate_etf_cost for total-cost analysis or compare_etfs for multi-fund comparison, so the exclusion guidance is implicit rather than stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_etf_riskGet ETF riskARead-onlyInspect
Calculate drawdown, annualized volatility, downside volatility, historical VaR, Sharpe, Sortino and Calmar ratios from stored daily close prices. With benchmarkTicker, also calculates beta, correlation, tracking error, active return and information ratio on aligned dates. Results are price-return risk, not distribution-adjusted total-return risk. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| days | No | Calendar-day lookback for daily close-price risk calculations. | |
| ticker | Yes | Exact Bullrun ETF listing ticker. | |
| benchmarkTicker | No | Optional exact priced benchmark/proxy ticker for beta, correlation, tracking error, active return, and information ratio. | |
| riskFreeRatePct | No | Annual risk-free rate in percentage points for Sharpe, Sortino, and Calmar ratios. |
Output Schema
| Name | Required | Description |
|---|---|---|
| risk | Yes | |
| ticker | Yes | |
| webPage | No | |
| coverage | Yes | |
| warnings | Yes | |
| methodology | Yes | |
| lookbackDays | Yes | |
| platformLink | No | |
| benchmarkRelative | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile, so the description clears the lower bar by adding a substantive methodological caveat: results are price-return risk, not distribution-adjusted total-return risk. It also grounds the computation in 'stored daily close prices' and notes alignment on dates for benchmark metrics. 'Read-only' merely repeats the annotation, which is minor waste rather than a problem.
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, front-loaded with the primary computation and then the benchmark extension. The trailing 'Read-only' duplicates the readOnlyHint annotation and could be dropped, but overall 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?
With an output schema present, return-value explanation is unnecessary, and the description covers inputs' effect, methodology basis, and a key interpretation caveat. It stops short of noting limits of the lookback window or what happens with insufficient history, but it is sufficient for correct invocation.
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 every parameter is already documented (days as calendar-day lookback, riskFreeRatePct as annual percentage points, benchmarkTicker's metric set). The description's only addition is 'on aligned dates' for the benchmark path, which is marginal. Baseline 3 is appropriate given 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?
Opens with a specific verb (Calculate) and names the exact resource and metric set: drawdown, volatility, VaR, Sharpe, Sortino, Calmar. It also distinguishes the benchmark-enabled mode from the base mode, so an agent can tell this apart from sibling tools like get_etf_snapshot or get_company_risk.
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 only conditional guidance is 'With benchmarkTicker, also calculates...', which is really parameter behavior rather than tool selection. There is no statement of when to prefer this over compare_etfs, get_etf_timeseries, or get_portfolio_analytics, and no preconditions (e.g., minimum history) are given.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_etf_snapshotGet ETF snapshotARead-onlyInspect
Fetch a modular snapshot for one exact ETF listing. The include array controls which of identity, classification, market, fund_data (NAV/AUM), costs, income, and benchmark are fetched and returned. Unrequested modules are omitted; requested-but-unavailable modules are named explicitly. Ratios use percentage points. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| ticker | Yes | Exact Bullrun ETF listing ticker, including its exchange suffix when present, e.g. SPY, VWRL.L, or EUNL.DE. | |
| include | No | Only these snapshot modules are fetched and returned. Default: identity, classification, market, costs. |
Output Schema
| Name | Required | Description |
|---|---|---|
| asOf | Yes | |
| found | Yes | |
| ticker | Yes | |
| modules | Yes | |
| webPage | No | |
| dataQuality | Yes | |
| platformLink | No | |
| missingModules | Yes | |
| availableModules | Yes | |
| requestedModules | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover read-only/non-destructive/closed-world, yet the description adds genuinely new behavior: unrequested modules are omitted while requested-but-unavailable modules are named explicitly, and ratios are reported in percentage points. The closing "Read-only." merely restates readOnlyHint=true, so it earns no credit and slightly dilutes the 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?
Four short sentences, front-loaded with the core action and scope, and each sentence adds a distinct fact except the trailing "Read-only." which duplicates the annotation. Slight redundancy keeps it just below the top mark.
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 two-parameter read tool with an output schema, full schema coverage, and annotations covering safety and openness, the description supplies everything else needed: scope, module semantics, omission/availability behavior, and unit conventions for the returned numbers.
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; the description goes beyond it by explaining the include array as a fetch-and-return filter and by stating the percentage-point unit convention, which is data semantics the schema does not carry. Ticker precision is left entirely to the schema example, which is acceptable.
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?
"Fetch a modular snapshot for one exact ETF listing" gives a specific verb and resource, and the word "modular" plus the module list distinguishes it from bulk/comparison siblings. It stops short of naming the adjacent single-ETF siblings (get_etf_fund, get_etf_holdings, get_etf_risk) that an agent would need to choose between.
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 is implied by "one exact ETF listing" (single-entity lookup, not screening/comparison), but there is no explicit when-to-use or when-not-to-use guidance and no alternative named among the many ETF siblings. An agent can infer a rough fit but must still reason about overlap with get_etf_fund and get_etf_exposures.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_etf_timeseriesGet ETF time seriesARead-onlyInspect
Fetch ETF price or price-return history at daily, weekly, or monthly intervals. NAV, true total-return, benchmark, and premium/discount series are returned only when their required source data or an explicit benchmark ticker exists; unavailable requested series are named explicitly and never approximated with price returns. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum recent daily source bars to load before date filtering and interval aggregation. | |
| series | No | Requested series. Unsupported stored series are reported in unavailableSeries rather than synthesized. | |
| ticker | Yes | Exact Bullrun ETF listing ticker. | |
| endDate | No | ||
| interval | No | daily | |
| startDate | No | ||
| benchmarkTicker | No | Exact priced ticker to use when benchmark is requested. A benchmark name alone cannot resolve a price series safely. |
Output Schema
| Name | Required | Description |
|---|---|---|
| series | Yes | |
| ticker | Yes | |
| webPage | No | |
| interval | Yes | |
| metadata | Yes | |
| warnings | Yes | |
| platformLink | No | |
| availableSeries | Yes | |
| requestedSeries | Yes | |
| unavailableSeries | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, so safety is covered. The description still adds real behavioral value: unavailable requested series are named in unavailableSeries and are never silently approximated with price returns, and series availability has prerequisites. Return shape details (e.g. unavailableSeries structure) are left to the 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?
Two dense sentences, front-loaded with the core capability followed by the availability caveat. The trailing 'Read-only.' merely restates the readOnlyHint annotation and is the one sentence that 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?
For a read-only fetch with an output schema (so return values need no prose) and explicit child-series caveats, this is nearly complete. Minor omission is how limit interacts with interval aggregation and date filtering, which matters for a 7-parameter 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?
With 57% schema coverage, the description compensates for the weakest spots: it explains that benchmark requires an explicit priced benchmarkTicker because a benchmark name cannot resolve to a price series, and it clarifies series availability semantics. It says nothing about how limit interacts with interval aggregation or about startDate/endDate beyond their pattern, leaving gaps.
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 ETF price or price-return history') plus the supported intervals, which immediately separates it from snapshot/exposure siblings. It never names a sibling such as get_etf_snapshot or get_stock_price_history to draw the boundary explicitly, so it stops short of a 5.
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 is implied by the name and the series/interval framing, and the description does explain the conditional rule that NAV/total-return/benchmark series only appear when source data or an explicit benchmarkTicker exists. However, it gives no when-to-use vs when-not guidance and never points to an alternative tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_financial_historyGet financial historyARead-onlyInspect
Read historical financial statements for one exact Bullrun ticker, with growth/CAGR consistency checks first, then income, balance sheet, cash flow, per-share metrics, margins and source currency. Defaults to a five-fiscal-year window of annual rows; request years=1-15 and periodType=quarterly or both for more detail. Use for growth consistency, margins, leverage and cash-flow quality; read the period/currency coverage before comparing.
| Name | Required | Description | Default |
|---|---|---|---|
| years | No | Fiscal-year window counting backward from the latest available fiscal year. Default 5; request up to 15 for longer research. | |
| ticker | Yes | The Bullrun ticker. Use the listing ticker returned by search_stocks. US/European examples: AAPL, BMW, NESN. Most Asian listings keep their exchange suffix (6324.T, 0700.HK); some use bare codes (005930). Native or suffixed forms resolve only when one listing matches; search by company name or ISIN if unsure. | |
| periodType | No | Defaults to annual statements with a growth summary. Choose quarterly or both for detailed period research. Annual rows use fiscalQuarter=0. | annual |
| includeEmptyRows | No | Include sparse rows that have no major income statement, balance sheet, cash-flow, or EPS values. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare this is a read-only, non-destructive, closed-world operation. The description adds useful behavioral context beyond that: five-fiscal-year default, years range 1-15, periodType quarterly/both options, ordering of growth checks, and source-currency coverage caveat. Pagination and rate-limit behavior remain unstated.
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 well-formed sentences, front-loaded with the primary action and scope, then defaults and usage. The dense list of statement areas is purposeful and no sentence 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?
With no output schema, the description carries more of the burden and does a solid job outlining the returned statement categories, defaults, period options, and currency coverage. Some response-shape details remain implicit, but an agent has enough 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 schema already documents all four parameters in detail. The description reinforces ticker exactness and mentions years=1-15 and periodType behavior, but it adds little semantic detail beyond the schema's own parameter descriptions.
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 historical financial statements') and adds scope: one exact Bullrun ticker, growth/CAGR checks, income, balance sheet, cash flow, per-share metrics, margins, and source currency. The purpose is clear, but it does not explicitly name or distinguish itself from close siblings such as get_stock_metrics or get_company_data_coverage.
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 usage guidance ('Use for growth consistency, margins, leverage and cash-flow quality') and a practical caveat to check period/currency coverage before comparing. It lacks explicit when-not-to-use guidance or named alternatives, so it falls short of the top score.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_forward_estimatesGet forward estimatesAInspect
Read cached Yahoo analyst consensus revenue/EPS estimates and available EPS revision percentages for one exact Bullrun ticker. A free background refresh checks supported symbols on demand, storing at most one snapshot per day; the first read may be empty. Fiscal periods and source currency are preserved. The configured feed does not provide EBITDA estimates, management guidance or revenue revisions. Forward P/E/PEG context uses the latest annual consensus snapshot only when quote and EPS currency units match. Does not change portfolios or user data.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum estimate rows to return. | |
| ticker | Yes | Bullrun ticker, e.g. "AAPL", "CRWD", "SPGI". Use the listing ticker returned by search_stocks. US/European examples: AAPL, BMW, NESN. Most Asian listings keep their exchange suffix (6324.T, 0700.HK); some use bare codes (005930). Native or suffixed forms resolve only when one listing matches; search by company name or ISIN if unsure. | |
| periodType | No | Return annual estimates, quarterly estimates, or both. | both |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Despite annotations being present, the description adds substantial behavior context: a free on-demand background refresh stores at most one snapshot per day, the first read may be empty, fiscal periods and source currency are preserved, forward P/E/PEG only applies when quote and EPS currency units match, and the tool does not modify portfolios or user data. This also explains the readOnlyHint=false annotation via the snapshot-writing refresh.
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 read operation and kept to four dense sentences, each carrying distinct information (data scope, refresh/staleness, gaps, currency caveat). Slightly over-packed with niche P/E/PEG currency detail, but no sentence is pure 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?
With no output schema, the description does outline the returned content (revenue/EPS estimates, EPS revision percentages, preserved fiscal periods and currency) and warns of empty first reads. It stops short of describing row structure or how annual vs quarterly rows are shaped, but is sufficient to call 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% and the ticker format caveats (suffixed vs bare codes, resolving ambiguous listings) live in the schema itself, so the schema already does the heavy lifting for all three parameters. The description reinforces the 'exact ticker' constraint and period/currency preservation but adds no syntax or constraint detail beyond the schema, matching the baseline for full coverage.
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 cached Yahoo analyst consensus revenue/EPS estimates plus EPS revision percentages) scoped to one exact Bullrun ticker, and explicitly bounds the coverage (no EBITDA, management guidance, or revenue revisions). This distinguishes it from generic fundamentals/valuation siblings without ambiguity.
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 is implied by the resource scope ('one exact Bullrun ticker') and the note that the first read may be empty, but the description never names alternatives such as get_financial_history or get_valuation_model, nor when to prefer this tool over them. The reader must infer routing from the sibling list.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_global_markets_overviewGet global markets overviewARead-onlyInspect
Bullrun's Global Markets dashboard in one call: world equity indices (S&P 500, Nasdaq-100, MSCI World, DAX, FTSE 100, Nikkei, Hang Seng, Nifty...), central-bank policy rates and next rate decisions (Fed, ECB, BoE, BoJ, SNB, BoC), 16 sovereign 10-year yields, 20 FX pairs, oil/gas/gold/copper, headline macro tiles (global GDP growth, inflation, debt/GDP, VIX, DXY, 2s10s curve, US jobless claims), the upcoming economic calendar, market news and the US housing balance. Each row carries a historyCode for get_macro_history. Use for "how are markets doing today", "what's the macro backdrop", "where are rates/yields", "what's on the calendar this week" or a morning briefing. Daily closes, with live intraday index levels while markets are open. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| sections | No | Sections to return. headline = global GDP/inflation/debt, oil, gold, DXY, US 10Y, 2s10s curve, VIX, EUR/USD, Bitcoin, policy-rate average, OECD unemployment, US jobless claims; indices = 19 world equity indices (live intraday level when a market is open); rates = six major central-bank policy rates + upcoming rate decisions; yields = 16 sovereign 10Y yields; currencies = 20 FX pairs; commodities = Brent, WTI, natural gas, gold, copper; calendar = upcoming high-impact economic releases; news = market headlines; us_housing = US housing-market balance (months' supply, inventory, price cuts). Default: everything except news and us_housing. | |
| newsLimit | No | Headlines to return when the news section is requested. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint/destructiveHint=false, so the 'Read-only' tail is partly redundant. Beyond that, the description adds real behavioral context: daily closes with live intraday index levels while markets are open, per-row historyCode for follow-up calls, and the default section set. It does not discuss size/latency of returning everything, which is the main behavioral risk here.
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 claim, then the payload inventory, then use cases and freshness. The opening sentence is very long with embedded parenthetical tickers, but every clause conveys coverage information an agent needs to pick this over a narrower sibling.
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 no output schema, the description must carry the return-value burden, and it does: it names what each of the nine sections contains and the data freshness. Nothing essential for correct invocation is missing given the 0-required-parameter, all-defaults 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?
Schema description coverage is 100% and the `sections` enum is documented in more detail in the schema than in the description, so the schema carries the burden. The description restates the section families and the default omission of news/us_housing, which is mildly useful but largely duplicative; 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?
The description states a specific verb+resource ('Bullrun's Global Markets dashboard in one call') and then enumerates the exact contents — indices, policy rates, 16 sovereign yields, 20 FX pairs, commodities, macro tiles, calendar, news, housing. This is clearly distinguishable from siblings like get_macro_indicators, get_macro_history, or get_country_macro, which each cover a single slice.
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 concrete trigger phrases ('how are markets doing today', 'what's the macro backdrop', 'what's on the calendar this week', morning briefing) and routes drill-down to get_macro_history via the per-row historyCode. No explicit 'when not to use' for the narrow indicator tools, but the 'in one call' framing implies the breadth tradeoff.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_macro_historyGet macro / market historyARead-onlyInspect
Historical time series behind the Global Markets dashboard, often decades long: equity indices, central-bank policy rates, 10-year government bond yields, FX rates, oil/gas/gold/copper, VIX, DXY, the US 2s10s curve, and per-country macro indicators (GDP growth, inflation, unemployment, house prices, credit gap, debt, confidence, macro stress). Address a series by historyCode (from get_global_markets_overview, get_country_macro or get_macro_indicators), by instrument name ("Fed", "Brent", "Germany 10Y", "S&P 500"), or by indicator + country. Returns summary statistics (latest, change over 1M/3M/1Y/5Y, range, where the latest sits in the window) plus resampled points. Use for "how have rates moved since 2022", "plot Brent over 10 years", "is German unemployment rising". Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| to | No | End date YYYY-MM-DD (inclusive). | |
| code | No | Exact series code from another tool's historyCode field (e.g. "CNBC_US10Y", "BIS_CBPOL_US", "UNEMPLOYMENT:Germany", "YAHOO_GSPC"). | |
| from | No | Start date YYYY-MM-DD (inclusive). | |
| country | No | Country for indicator, e.g. "Japan". | |
| interval | No | Resample to end-of-period values. auto = the finest interval that fits maxPoints. | auto |
| indicator | No | Or a per-country macro indicator, together with country (same keys as get_macro_indicators). | |
| maxPoints | No | Upper bound on returned points (auto interval only; an explicit interval is truncated to the most recent maxPoints). | |
| instrument | No | Or a market name: an index ("S&P 500", "DAX", "Nikkei 225"), commodity ("Brent", "Gold"), FX pair ("EUR/USD"), central bank ("Fed", "ECB", "BoE"), 10Y yield ("Germany 10Y", "US 10Y"), or headline series ("VIX", "DXY", "2s10s", "global inflation"). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true / destructiveHint=false, so safety needs no restating; the description instead adds real behavioral context: data can be decades long, output is summary statistics (latest, 1M/3M/1Y/5Y change, range, percentile position) plus resampled points. It does not cover failure modes (e.g., unknown code, conflicting address modes) or date defaults, keeping it below 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 resource and scope, then addressing modes, then return shape, then use cases — a sensible order with no filler sentences. The long comma-separated series enumeration is informative but dense; it slightly crowds the paragraph.
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 no output schema, the description carries the return-value burden and does so (summary stats + resampled points). Combined with a fully documented 8-parameter schema, an agent has enough to call it correctly; only edge-case behavior (default date window, conflicting address params, unknown series) is left unspecified.
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 3 is the floor; the description earns above that by explaining the three mutually alternative addressing modes (code vs. instrument vs. indicator+country) and by pointing to the sibling tools whose historyCode values the `code` param accepts. It does not disambiguate precedence if more than one address mode is supplied.
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 concrete verb+resource ('Historical time series behind the Global Markets dashboard') and enumerates the exact data families covered (policy rates, 10Y yields, FX, commodities, VIX, DXY, 2s10s, per-country macro). It is clearly separable from siblings like get_global_markets_overview and get_macro_indicators, which it names as upstream code sources.
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 three concrete routing rules for addressing a series (historyCode from a named sibling, instrument name, or indicator+country) plus example questions ('how have rates moved since 2022', 'plot Brent over 10 years'). It stops short of explicit when-not-to-use/exclusion guidance versus the snapshot-style siblings, so it lands at a strong 4 rather than 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_macro_indicatorsRank countries by macro indicatorARead-onlyInspect
Cross-country macro comparison from Bullrun's Global Markets warehouse: rank up to ~200 countries on one indicator (GDP growth annual or quarterly, CPI inflation, government debt/GDP, unemployment, youth unemployment, real house-price growth, house price-to-income and price-to-rent vs history, BIS credit-to-GDP gap, household debt service, household credit/GDP, business and consumer confidence, or Bullrun's macro stress score), or compare a named set of countries. Every row has value, period, source and a historyCode for get_macro_history. Use for "fastest growing economies", "highest inflation in Europe", "most indebted G7 government", "where is housing most overvalued", "compare unemployment in Spain, Italy and Greece". Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| order | No | desc = highest value first, asc = lowest first. | desc |
| countries | No | Only these countries (e.g. ["Germany","France","Italy"]); aliases like US/UK understood. Omit for every covered country. | |
| indicator | Yes | Which cross-country indicator: gdp_growth (annual), gdp_growth_quarterly, inflation, government_debt, unemployment, youth_unemployment, real_house_prices, house_price_to_income, house_price_to_rent, credit_gap, household_debt_service, household_credit, business_confidence, consumer_confidence, macro_stress (Bullrun composite). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already carry readOnlyHint/destructiveHint, so the appended "Read-only" adds nothing. What does add value is the disclosed row shape (value, period, source, historyCode), which is essential since there is no output schema, plus the coverage ceiling of ~200 countries. Pagination/limit behavior is not disclosed.
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 scope before the examples, and the closing sentences about row contents and historyCode each earn their place. The long parenthetical indicator list duplicates the enum and inflates the opening sentence, though it does supply natural-language gloss on indicator names.
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 no output schema, the description compensates by naming the returned fields and the historyCode handoff, and it covers all indicator choices. The remaining gap is the limit/pagination parameter, whose default and ceiling are never mentioned in prose, which matters for an agent ranking across ~200 countries.
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 75%; indicator and countries are described in both schema and prose, and the description glosses several enum members more richly than the schema ("real house-price growth", "BIS credit-to-GDP gap", macro_stress as a Bullrun composite). However the limit parameter has no description anywhere, and the description's "up to ~200 countries" conflicts with the schema's max of 250 without explaining the default of 25.
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 — cross-country macro comparison from Bullrun's warehouse, ranking up to ~200 countries on one indicator — and enumerates the indicators so the agent knows the exact scope. The concrete query examples ("fastest growing economies", "highest inflation in Europe") make it unmistakable against siblings like get_country_macro or get_global_markets_overview.
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 is well signalled: the two modes (rank all countries vs. compare a named set) are described, and the user-phrase examples anchor when to reach for it. The handoff to get_macro_history via historyCode is explicit. It stops short of naming the sibling that covers the single-country case (get_country_macro), leaving that boundary to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_operating_kpisGet operating KPIsARead-onlyInspect
Read curated, source-linked operating KPI observations for one exact Bullrun ticker. Coverage is sparse and no automatic KPI feed is configured: do not assume ARR, retention, customer counts or payments metrics are available. Check get_company_data_coverage first. Returns stored fiscal periods, units and source links; company-economics observations are a separate dataset. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum KPI rows to return. | |
| ticker | Yes | Bullrun ticker, e.g. "CRWD", "SNOW", "V". Use the listing ticker returned by search_stocks. US/European examples: AAPL, BMW, NESN. Most Asian listings keep their exchange suffix (6324.T, 0700.HK); some use bare codes (005930). Native or suffixed forms resolve only when one listing matches; search by company name or ISIN if unsure. | |
| category | No | Optional category filter such as SaaS, payments, marketplace, banking, or other domain labels. | |
| metricKey | No | Optional metric key present in stored coverage. No particular business KPI is guaranteed to be available. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds substantial context beyond the readOnlyHint/openWorldHint annotations: coverage is sparse, no automated KPI feed exists, and results carry stored fiscal periods, units and source links. The trailing 'Read-only' merely repeats the annotation, and nothing is said about ordering or empty-result behavior, so it stops 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?
Four short sentences, front-loaded with the operation, then the sparse-coverage caveat, then the prerequisite, then return shape. Only the redundant 'Read-only' tail fails to 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?
With no output schema, the description does the work of describing returns (fiscal periods, units, source links) and sets expectations about sparse coverage and the separate company-economics dataset. Complete enough to call correctly; only minor gaps like empty-result handling 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 description coverage is 100%, so ticker format, category, metricKey and limit are already fully documented in the schema. The description reinforces the ticker exactness requirement but adds no new syntax or constraint information beyond that; 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 ('Read curated, source-linked operating KPI observations') scoped to 'one exact Bullrun ticker', and explicitly separates itself from the 'company-economics observations' dataset. An agent can distinguish it from siblings like get_revenue_breakdown or get_financial_history 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?
Explicitly routes the agent: 'Check get_company_data_coverage first', plus a clear when-NOT clause ('do not assume ARR, retention, customer counts or payments metrics are available'). It names both the prerequisite tool and the excluded dataset, leaving little inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_portfolio_analyticsGet portfolio analyticsARead-onlyInspect
Analyze the signed-in user's portfolio risk, diversification, concentration or a candidate stock/ETF. Returns correlation/covariance, risk contributions, country/sector/currency exposures, proxy factors and stress scenarios. Use portfolioId from list_portfolios; use get_portfolio_context instead for holdings/value and matched/unmatched coverage. Set candidateTicker for correlation and pro-forma volatility; add includeLookThrough=true for direct/ETF underlying overlap in lookThroughFit with separate coverage/warnings. Look-through uses priced positions, independently of the risk-history subset; partial ETF snapshots give a lower bound. Risk math excludes holdings without sufficient price history and renormalizes over those analyzed: report the leading coverage banner and never imply whole-portfolio coverage when holdings were excluded. Requires OAuth read:portfolios and reads only the caller's data. privacyMode=weights_only hides absolute USD amounts; full is the default.
| Name | Required | Description | Default |
|---|---|---|---|
| days | No | Calendar-day lookback for daily USD return analytics. Default 370. | |
| portfolioId | Yes | The portfolio id, as returned by list_portfolios. | |
| privacyMode | No | "full" (default) includes absolute USD amounts; "weights_only" returns only relative figures. | |
| candidateTicker | No | Optional exact Bullrun stock or ETF listing ticker to test as a candidate diversifier, e.g. AAPL, BMW, ABBN, NESN or SPY. Use the stored listing ticker; do not infer exchange suffixes. | |
| candidateWeightPct | No | Optional hypothetical candidate allocation for pro-forma volatility. Default 5 (%). | |
| includeLookThrough | No | Also compare an exact stock or ETF candidate against direct holdings and stored ETF constituents. Requires candidateTicker. Default false: no underlying holdings requests. Look-through has separate priced-position coverage from price-history risk analytics. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint/no-destructive, yet the description adds substantial context beyond them: OAuth scope read:portfolios, caller-scoped data only, exclusion of holdings without sufficient price history plus renormalization, look-through coverage computed independently from the risk-history subset, partial ETF snapshots yielding a lower bound, and a directive to surface the coverage banner. It also discloses the privacyMode effect on absolute USD amounts.
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 alternatives before diving into the coverage caveats, and every sentence carries actionable information. It is dense and reads as a long run-on chain, which slightly slows scanning for an agent parsing it quickly.
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 six-parameter analytics tool with no output schema, the description covers auth, caller scoping, privacy modes, conditional parameters, output field naming (lookThroughFit), and the critical coverage-caveat behavior. An agent has everything needed to call it and to report results honestly.
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 semantic linkage the schema does not state: which parameters drive correlation/pro-forma volatility, that look-through results appear in lookThroughFit with separate coverage/warnings, and that look-through coverage is independent of the risk-history subset. Minor gap: it does not explain the days lookback window semantics beyond what the schema already documents.
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 and a concrete resource set (risk, diversification, concentration, candidate stock/ETF analytics) and enumerates the outputs (correlation/covariance, risk contributions, exposures, stress scenarios). It also explicitly names the sibling it is not (get_portfolio_context for holdings/value), 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?
Gives explicit when-to-use routing (portfolioId from list_portfolios, get_portfolio_context for holdings/value and coverage), conditional parameter guidance ('Set candidateTicker for correlation and pro-forma volatility', 'add includeLookThrough=true for direct/ETF underlying overlap'), and the prerequisite dependency (includeLookThrough requires candidateTicker). 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_portfolio_contextGet portfolio contextARead-onlyInspect
Use when the user asks to look at, review, or analyze THEIR portfolio / holdings / positions — e.g. "analyze my portfolio", "how is my portfolio doing", "what's in my portfolio", "review my holdings", "how am I invested", "what should I improve". Fetches a deep snapshot of ONE of the signed-in user's portfolios: the summary (value, day change, total return), every holding (with position weight %, sector and return) and Bullrun's computed insights (benchmark comparison, concentration, diversification, dividend income). Pass a portfolioId from list_portfolios (call that first if the user hasn't named a portfolio). The response ALWAYS returns the complete holdings list with each position flagged matched/unmatched, plus a coverage summary: holdings that Bullrun can't link to its universe (ETFs, funds, untracked tickers) carry no weight, sector, insight or ML score, so weights/insights/ML below describe ONLY the matched subset. Read the coverage banner (the first text block) and never present matched-only figures as the whole portfolio. For risk/diversification math, correlations, factor exposure, or whether to add a specific stock, use get_portfolio_analytics instead. Requires OAuth (read:portfolios) and returns the caller's own data only. privacyMode defaults to "full" (absolute $ included); "weights_only" returns only relative figures. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| days | No | Insights look-back window in days (default 30). | |
| portfolioId | Yes | The portfolio id, as returned by list_portfolios. | |
| privacyMode | No | "full" (default) includes absolute $; "weights_only" returns only relative figures. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the readOnly/destructive/openWorld annotations: it discloses the OAuth scope (read:portfolios), the caller's-own-data restriction, the privacyMode default and its effect on returned figures, and a non-obvious data-quality behavior — unmatched holdings carry no weight/sector/insight so aggregate figures describe only the matched subset, with an instruction to read the coverage banner and never present matched-only numbers as the whole portfolio.
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 trigger condition and dense throughout — nearly every sentence carries either a routing rule or a data-integrity warning. It is a long single block, and the privacyMode/portfolioId restatements duplicate the schema, which is the only thing keeping 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?
With no output schema, the description carries the burden and does so fully: it lists the response sections, flags the matched/unmatched coverage caveat and banner, states auth requirements and the privacy default, and points to the sibling for analytics. Nothing needed 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 all three parameters are already documented in structured fields. The description largely restates what the schema says (portfolioId as returned by list_portfolios, privacyMode full vs weights_only) and never mentions `days` or its default/look-back meaning, so it adds little parameter-level meaning beyond what the schema provides.
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 a deep snapshot of ONE portfolio — and enumerates exactly what comes back (summary, holdings with weight/sector/return, Bullrun insights). It also names the two siblings it differs from: list_portfolios as the id source and get_portfolio_analytics for risk math, 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?
Gives concrete trigger phrasing ("analyze my portfolio", "how am I invested"), an explicit sequencing prerequisite (pass a portfolioId from list_portfolios, call it first if the user hasn't named a portfolio), and an explicit exclusion with the correct alternative for risk/diversification/correlation/factor questions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_quality_moat_metricsGet quality and moat metricsARead-onlyInspect
Compute annual quality, moat, earnings-quality, and capital-allocation metrics for one exact Bullrun ticker from existing financial statements: ROIC, ROE/ROA, ROIC-vs-supplied-WACC, accruals, cash conversion, capex intensity, dividend payout/growth, diluted share-count changes, and a buyback proxy. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| years | No | How many fiscal years of annual history to evaluate. | |
| ticker | Yes | The Bullrun ticker. Use the listing ticker returned by search_stocks. US/European examples: AAPL, BMW, NESN. Most Asian listings keep their exchange suffix (6324.T, 0700.HK); some use bare codes (005930). Native or suffixed forms resolve only when one listing matches; search by company name or ISIN if unsure. | |
| estimatedWaccPct | No | Optional user-supplied WACC assumption, in percent. When omitted, ROIC-vs-WACC spread is returned as null. | |
| taxRateFallbackPct | No | Fallback tax rate used for NOPAT only when reported tax/pretax data is missing or unusable. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, destructiveHint=false and openWorldHint=false, so the 'Read-only' line is redundant. The one genuinely additive signal is that metrics are derived from already-stored financial statements, though the description says nothing about behavior when statement data is missing or how years of history interact with coverage gaps.
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 verb and resource, then a dense but purposeful metric list; the trailing 'Read-only.' is redundant with annotations. One long sentence is heavy but no clause 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?
With no output schema, the enumerated metric list effectively stands in for a return-value description, which is the right compensation. What remains uncovered is failure behavior for tickers lacking sufficient statement history, but for a scoped read-only compute tool this is close to sufficient.
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 ticker formatting, years bounds, and the WACC/tax-rate fallbacks are already fully documented in the schema. The description reinforces the supplied-WACC dependency ('ROIC-vs-supplied-WACC') but adds no syntax or edge-case meaning beyond it, which is the expected baseline-3 case.
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?
Uses a specific verb ('Compute') plus a named resource ('annual quality, moat, earnings-quality, and capital-allocation metrics') scoped to 'one exact Bullrun ticker', and enumerates the concrete metrics produced. This clearly separates it from siblings like get_stock_metrics (point-in-time ratios) and get_financial_history (raw statements).
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?
Implies the use case ('from existing financial statements' for a single ticker) but never states when to choose this over get_stock_metrics or get_financial_history, nor any prerequisites such as needing statement coverage. Usage is inferable rather than directed.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_revenue_breakdownGet revenue breakdownARead-onlyInspect
Fetch segment, geography, product, customer, or other revenue breakdown rows for one exact Bullrun ticker. Use this to separate cyclical businesses from recurring segments or inspect geographic exposure instead of relying on blended revenue. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum breakdown rows to return. | |
| ticker | Yes | The Bullrun ticker, e.g. "SPGI", "MSFT", "V". Use the listing ticker returned by search_stocks. US/European examples: AAPL, BMW, NESN. Most Asian listings keep their exchange suffix (6324.T, 0700.HK); some use bare codes (005930). Native or suffixed forms resolve only when one listing matches; search by company name or ISIN if unsure. | |
| dimension | No | Breakdown dimension to return, or all dimensions. | all |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, destructiveHint=false and openWorldHint=false, and the description's 'Read-only' merely restates that. The only added behavioral signal is that a single 'exact' ticker scopes the call, with nothing about result shape, periodicity, or how missing breakdown data is handled.
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, front-loaded with what it fetches, followed by the analytical motivation. The trailing 'Read-only.' is a fragment that only duplicates the annotations and is slight 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?
For a simple three-parameter read tool with full schema coverage, the core is covered, but there is no output schema and the description never indicates what a breakdown row contains (values, period, currency, hierarchy). An agent still can't tell what it will get back.
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%, with clearly documented ticker, dimension enum, and limit. The description echoes the dimension list and the 'one exact ticker' constraint but adds no format or semantics 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 (fetch) and resource (revenue breakdown rows) and enumerates the dimensions available, so an agent can tell it apart from a blended-revenue or KPI tool. It does not name a specific sibling, so the differentiation is conceptual rather than explicit.
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?
'Use this to separate cyclical businesses from recurring segments or inspect geographic exposure instead of relying on blended revenue' gives a clear positive trigger and implicitly steers away from blended-revenue tools. No when-not-to-use or prerequisite conditions are stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_risk_moversGet risk moversARead-onlyInspect
Companies whose Bullrun composite risk score crossed into a different band (e.g. Elevated -> Stretched, or Acute -> Stretched) within the last N days, with prior and current score, the move in points, and the input driving the reading. Use for "what got riskier this week", "any risk deteriorations I should know about", or to monitor a watchlist (pass the tickers to get_company_risk afterwards). Band changes, not small score drift, so every row changed a word on the page. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| days | No | Look-back window in days for band changes. | |
| limit | No | ||
| direction | No | Keep only companies whose composite got worse, got better, or both. | all |
| minMarketCapUsd | No | Only companies with at least this market capitalisation in USD, e.g. 1e9 for $1B+. Without it the list is dominated by micro-caps, whose scores move most. | |
| stableBasisOnly | No | true (default) = only real movements. false also includes band changes caused purely by a category starting or stopping scoring (coverage changes, flagged basisChanged). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare read-only and non-destructive behavior, and the description adds useful context beyond that: band-crossing semantics, output fields like prior/current score and driving input, and the distinction between real movements and coverage-driven changes. The final 'Read-only' is redundant with annotations, but the rest adds substantive behavioral detail.
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 core definition is front-loaded, followed by concrete use cases and a useful scope clarification. It is slightly dense and the final 'Read-only' repeats an annotation, but most sentences earn their 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?
With no output schema, the description does a good job naming the returned fields and explaining the band-change concept. It does not cover pagination or limit behavior, but the core filters and output semantics are sufficiently clear 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?
Schema coverage is 80%, so the baseline is 3. The description reinforces the meaning of the days window and the band-change/stable-basis distinction, but it does not add meaning for the limit parameter and largely relies on the schema for the rest.
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 resource and behavior: companies whose Bullrun composite risk score crossed into a different band within the last N days, including prior/current score and the move. It clearly distinguishes this from a general company-risk lookup by emphasizing band changes rather than small score drift.
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 use cases such as 'what got riskier this week' and 'risk deteriorations I should know about,' plus a watchlist workflow that points to get_company_risk afterwards. It also clarifies the key exclusion: band changes, not small score drift.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_stock_metricsGet stock metricsARead-onlyInspect
Fetch a consolidated metrics snapshot for a single stock by ticker: identity (company, exchange, currency, sector, industry, country, ISIN), latest daily price (OHLCV), latest valuation (market cap, P/E, dividend yield, annual dividend per share), the most recent reported financials (revenue, gross/operating income, EBITDA, net income, diluted EPS, free & operating cash flow, total debt, cash, total assets, equity) and a short company description. Prices are in the listing's trading currency; financials in their own sourceCurrency. Use the listing ticker returned by search_stocks. US/European examples: AAPL, BMW, NESN. Most Asian listings keep their exchange suffix (6324.T, 0700.HK); some use bare codes (005930). Native or suffixed forms resolve only when one listing matches; search by company name or ISIN if unsure. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| ticker | Yes | The stock ticker as Bullrun lists it, e.g. "AAPL", "BMW", "NESN", "6324.T", "0700.HK" or "005930". A bare numeric code is resolved when exactly one listing matches. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, so the trailing 'Read-only.' is redundant. Beyond that, the description adds real behavioral context: prices are in the listing's trading currency while financials are in their own sourceCurrency, and native vs. suffixed tickers only resolve when exactly one listing matches. It stops short of mentioning data freshness/delay or the failure mode when a ticker is ambiguous.
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 payload definition, then currency semantics, then ticker resolution rules — a sensible information order. The mid-sentence enumeration of a dozen financial line items is dense but each item is genuinely part of the contract, so it earns its space; the redundant 'Read-only.' is the only clear 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?
There is no output schema, so the description must carry the return contract itself, and it does: identity fields, OHLCV, valuation ratios, the full financial statement subset, plus units/currency for each group. Combined with the ticker-resolution guidance, an agent has everything needed to call it 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?
With 100% schema description coverage the baseline is 3, and the description earns an increment by elaborating the resolution semantics around the single ticker parameter — suffix retention for Asian listings (6324.T, 0700.HK) versus bare codes (005930) and the one-listing-match rule. This meaningfully reduces the chance of a malformed ticker even though it partly restates the 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?
It uses a specific verb ('Fetch a consolidated metrics snapshot') plus a clearly scoped resource (single stock by ticker) and enumerates the exact payload groups: identity, latest OHLCV, valuation, reported financials, description. This is far more specific than a name restatement, though it never explicitly contrasts itself with overlapping siblings such as get_stock_price_history, get_financial_history, or get_valuation_model, so an agent must infer that 'consolidated' means the one-shot bundle.
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?
Strong operational guidance on the input: 'Use the listing ticker returned by search_stocks', concrete US/EU/Asia examples, the exchange-suffix convention, and a fallback ('search by company name or ISIN if unsure'). What it lacks is guidance on when to prefer this snapshot over the sibling history/valuation tools, so the usage half is covered but the alternative-selection half is not.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_stock_price_historyGet stock price history and technical indicatorsARead-onlyIdempotentInspect
Read bounded stored stock OHLCV history, ascending by trade date, as daily, weekly or monthly bars, with close-based price returns/drawdown and optional deterministic SMA, EMA, Wilder RSI and MACD. Useful for price trends, volatility context and technical analysis; use get_stock_metrics for a latest company snapshot. Up to 2600 recent daily source rows; dates filter that bounded window. Provider split/dividend adjustment is unknown: returns are not verified total returns. Missing OHLCV/indicator warm-up remains null; no synthetic sessions, intraday data or live quote claims. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum most-recent DAILY source bars to load before date filtering and aggregation (hard cap 2600). Increase for indicator warm-up or longer history. | |
| ticker | Yes | Bullrun stock ticker, e.g. AAPL, SAP, ABBN, 6324.T or 7203. Use the listing ticker returned by search_stocks. US/European examples: AAPL, BMW, NESN. Most Asian listings keep their exchange suffix (6324.T, 0700.HK); some use bare codes (005930). Native or suffixed forms resolve only when one listing matches; search by company name or ISIN if unsure. | |
| endDate | No | Inclusive last trade date; the API still loads the most recent source bars before this filter. | |
| interval | No | Aggregate stored daily bars. Weekly buckets start Monday; monthly buckets use the calendar month. No intraday or live quotes. | daily |
| rsiPeriod | No | Number of close-to-close changes for Wilder RSI. MACD uses fixed EMA periods 12/26 and signal 9. | |
| startDate | No | Inclusive trade-date cutoff, applied after loading the latest source bars. Cannot page into history older than the source limit. | |
| indicators | No | Optional indicators computed on the selected interval's closes after date filtering. Insufficient warm-up yields null, never a fabricated value. | |
| movingAveragePeriod | No | Observation count for SMA and EMA, in the selected interval. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare read-only, idempotent, non-destructive, closed-world, but the description adds substantive context they cannot carry: the 2600-row bounded source window, that date filters apply only inside that window and cannot page older, that provider split/dividend adjustment is unknown so returns are not verified total returns, and that missing warm-up stays null with no synthetic sessions or intraday/live quotes. These are exactly the caveats an agent needs to avoid over-claiming results.
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 core capability and its scope lead the description, followed by the routing hint and then the caveats, which is the right order. It is dense but nearly every clause carries information; the only mild bloat is the trailing 'Read-only.' which duplicates readOnlyHint and the compound 'no synthetic sessions, intraday data or live quote claims' phrasing.
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 an 8-parameter analytical tool with no output schema, the description covers scope, aggregation semantics, indicator warm-up/nulls, data-adjustment uncertainty, and hard window limits. An agent knows what it will get, what it will not get, and where the boundaries are before calling 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 every parameter including limit, startDate/endDate, interval, indicators, and the period knobs is already documented at the field level; that sets the baseline at 3. The description reinforces the important limit/date interaction ('dates filter that bounded window') and the determinism of indicators, but adds little parameter-level detail the schema does not already supply.
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 bounded stored stock OHLCV history') plus the exact shape of the output (ascending daily/weekly/monthly bars with returns, drawdown, and optional SMA/EMA/RSI/MACD). It explicitly names the sibling it is not ('use get_stock_metrics for a latest company snapshot'), so an agent can route between them 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 a clear use context ('price trends, volatility context and technical analysis') and names one concrete alternative with the condition that selects it (latest snapshot → get_stock_metrics). It stops short of covering adjacent siblings like get_financial_history or get_etf_timeseries, and there is no explicit when-not guidance beyond the snapshot case.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_valuation_modelGet Bullrun valuation modelARead-onlyInspect
Bullrun's proprietary machine-learning valuation and forecast scores for 1-10 stocks, recomputed nightly. Valuation: a LightGBM model predicts the P/E (or price/sales for loss-makers) that companies with similar fundamentals typically command a year out; the gap = typical / current multiple - 1 (positive = trades below its typical multiple), with the implied model-typical P/E, percentile and rank in the scored universe. Forecast: a relative 1-year return-rank signal with percentile. Both on quarterly and on annual financials (annual covers most non-US companies). Use for "is X cheap or expensive", "what's X's fair P/E", "compare valuations of X, Y, Z", or a valuation sanity check before buying. Descriptive context, not a price target or recommendation. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| tickers | Yes | 1-10 Bullrun tickers, e.g. ["AAPL","MSFT"] or ["ASML","SAP","NESN"]. Use the listing ticker returned by search_stocks. US/European examples: AAPL, BMW, NESN. Most Asian listings keep their exchange suffix (6324.T, 0700.HK); some use bare codes (005930). Native or suffixed forms resolve only when one listing matches; search by company name or ISIN if unsure. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover read-only/no-destruction, so the bar is lower, and the description still adds real substance: nightly recompute cadence, the sign convention of the gap ('positive = trades below its typical multiple'), the two financial bases with a non-US coverage caveat, and the descriptive-not-advisory framing. It does not say what happens when a ticker has no score or partial fundamentals, which is the main remaining behavioral gap.
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 most decision-relevant facts (what it is, scope, cadence) are front-loaded, followed by model mechanics and then use cases. It is dense and long-ish, but each block earns its place except the gap-formula detail, which is more than an agent needs to select the 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?
No output schema exists, and the description compensates by enumerating the returned quantities (gap, implied model-typical P/E, percentile, rank in universe, 1-year relative return rank) for both valuation and forecast. For a single-parameter read-only tool with full annotation coverage, nothing needed to call or interpret it 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 tickers parameter already carries a detailed description including suffix handling and search_stocks guidance, so the schema does the heavy lifting. The description only echoes the 1-10 cardinality and adds a note that annual financials cover most non-US companies, which marginally informs which listings resolve. 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?
The description states a specific verb and resource: proprietary ML valuation and forecast scores for 1-10 stocks, recomputed nightly, with the exact model (LightGBM P/E or price/sales) and gap formula spelled out. An agent knows precisely what it gets back. It stops short of naming the nearest sibling (screen_valuation_model, which presumably ranks a universe) or distinguishing itself from get_forward_estimates, so it is clear but not sibling-differentiating.
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 use cases are given in quoted form ('is X cheap or expensive', 'what's X's fair P/E', 'compare valuations of X, Y, Z') plus a negative boundary: 'Descriptive context, not a price target or recommendation.' That is clear context and one exclusion, but no alternative tool is named for the screening/ranking case or for forward-estimate needs.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_portfoliosList my portfoliosARead-onlyInspect
Use when the user refers to THEIR portfolio(s) or holdings — e.g. "my portfolios", "what portfolios do I have", "how are my investments doing", "show my holdings", "my account". Lists the signed-in Bullrun user's virtual portfolios with computed summaries: name, base currency, total value (USD), day change, cost basis and total return, plus position counts. Start here when a portfolio question doesn't name a specific portfolio, then pass a portfolioId to get_portfolio_context or get_portfolio_analytics. Requires connecting this server to a Bullrun account (OAuth, read:portfolios scope) — it returns that user's own data only. privacyMode defaults to "full" (includes absolute $ amounts); pass "weights_only" to hide absolute money and return only relative figures (returns %, counts). Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| privacyMode | No | "full" (default) includes absolute $; "weights_only" hides cash/value/cost-basis and keeps only %. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the readOnly/non-destructive annotations by disclosing the OAuth requirement and read:portfolios scope, that only the authenticated user's own data is returned, and the privacyMode default ('full' returns absolute $ vs 'weights_only' strips cash/value/cost basis). These are material behavioral facts an agent cannot infer 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?
Front-loaded with the 'Use when...' trigger and concrete user phrasings, then routing, then auth/privacy caveats. Each sentence serves a purpose, though the long list of example utterances and the return-field enumeration make it denser than strictly necessary.
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 no output schema, the description compensates by enumerating the returned fields and noting position counts and computed summaries. Combined with the routing guidance, auth requirements, and default privacy behavior, an agent has everything needed to invoke it correctly and interpret the result.
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% for the single privacyMode parameter, but the description adds practical meaning: that the default is 'full' and what 'weights_only' actually hides versus preserves. It does not add example values or caveats beyond that, so it is a modest improvement over the schema rather than a full substitute.
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 ('Lists') and resource ('signed-in Bullrun user's virtual portfolios') and enumerates the computed fields returned (value, day change, cost basis, return, position counts). It is clearly distinguished from siblings like get_portfolio_context and get_portfolio_analytics by positioning itself as the entry point that yields a portfolioId for those tools.
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 triggering situations with concrete example utterances ('my portfolios', 'how are my investments doing'), and gives a routing rule: use this first when no specific portfolio is named, then pass the resulting portfolioId to the context/analytics tools. Alternatives and the condition selecting them are both stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_research_shortlistRead my research shortlistARead-onlyIdempotentInspect
Read the signed-in user's saved Research Shortlist of stock and ETF listing tickers, with dated stored prices. Requires OAuth read:shortlist. Use after the user asks for their saved research queue. Read-only; does not evaluate a screen, schedule monitoring or send notifications.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, destructiveHint=false, and openWorldHint=false. The description adds meaningful context beyond those annotations: OAuth scope requirement read:shortlist, the returned content (tickers with dated stored prices), and behavioral boundaries. It does not discuss empty-state behavior or ordering, keeping it shy 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?
Three sentences, all front-loaded and purposeful: purpose/return content, auth and usage trigger, then exclusions. Nothing is wasted or buried.
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 parameters and no output schema, so the description carries the return-value burden and does so by naming tickers and dated stored prices. Combined with the auth requirement and usage trigger, an agent has enough to invoke the tool 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 has zero parameters, so the baseline is 4. There are no parameter semantics to explain, and the description correctly focuses on purpose, auth, and return content instead.
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: reading the signed-in user's saved Research Shortlist of stock/ETF tickers with dated stored prices. It also distinguishes the tool from save_research_shortlist and screening tools by clarifying that it does not evaluate a screen, schedule monitoring, or send notifications.
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 trigger: 'Use after the user asks for their saved research queue,' and useful exclusions around screening, monitoring, and notifications. It stops short of explicitly naming save_research_shortlist as the write counterpart, so it is strong but not fully complete.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
save_research_shortlistSave research to my shortlistAIdempotentInspect
Add 1-20 exact Bullrun stock or ETF listing tickers to the signed-in user's Research Shortlist when the user asks to save them. Requires OAuth write:shortlist; reconnect if this scope was not granted. Resolve ambiguous names with search_stocks/search_etfs first. Existing entries are retained; repeated saves are idempotent. Each ticker is saved independently and failures are reported alongside successful saves, so retry only failed tickers. Does not create a portfolio, schedule monitoring or send notifications.
| Name | Required | Description | Default |
|---|---|---|---|
| tickers | Yes | Exact listing tickers chosen by the user, e.g. AAPL or EUNL.DE. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations (idempotent, non-destructive, closed-world write), it discloses the required OAuth scope write:shortlist and what to do on a missing scope, that existing entries are retained, and that each ticker is saved independently with partial failures reported so only failed tickers are retried. These are non-obvious traits an agent could not infer from the schema. It stops short of describing the response payload shape, which matters since there is no 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?
Five short sentences, front-loaded with purpose and scope, followed by prerequisites, idempotency, failure semantics and exclusions. Every sentence contributes a distinct, actionable fact 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?
For a single-parameter write tool with no output schema, the description still covers auth requirements, idempotency, merge-vs-replace behavior, partial-failure reporting and retry strategy. Nothing an agent needs to invoke it correctly, or to interpret a mixed success 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% and already enforces minItems 1, maxItems 20, the ticker pattern and an example, so the description's '1-20 exact ... tickers' largely restates it. It does add the constraint that tickers must be exact Bullrun stock or ETF listings resolved via search_stocks/search_etfs, which is semantic guidance the pattern alone cannot 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 (add), resource (Research Shortlist), and precise scope: 1-20 exact listing tickers for the signed-in user. It also explicitly contrasts itself with adjacent capabilities (portfolio creation, monitoring, notifications), so it is separable from siblings like create_portfolio_draft or list_research_shortlist.
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 triggering condition ('when the user asks to save them'), a prerequisite step ('Resolve ambiguous names with search_stocks/search_etfs first'), and explicit exclusions ('Does not create a portfolio, schedule monitoring or send notifications'). An agent knows both when to call it and which siblings to route to instead.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
screen_etfsScreen ETFsARead-onlyInspect
Screen the WHOLE ETF universe by numeric rules and fund attributes in one pass — expense ratio, AUM, yield, trailing returns, volatility, liquidity, top-10 concentration, fund age and holdings count — combined with issuer, index, domicile, UCITS status, distribution policy, currency hedging and constituent look-through (holdingSearch finds funds by what they hold). Prefer this over search_etfs for any "cheapest / largest / best performing / most liquid" question: search_etfs only filters a bounded candidate scan, while this evaluates the full universe and reports evaluatedCount and matchCount. Percentages are percentage points. This full-universe screen is an expensive read, and request limits depend on your connection and plan. Build one precise screen to conserve your allowance. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum ETFs to return, 1-100. | |
| order | No | Sort direction. Nulls always sort last regardless of direction. | desc |
| rules | No | Numeric rules. A fund with no value for a ruled metric never matches that rule. | |
| issuer | No | Substring match on the fund family/issuer, e.g. "iShares", "Amundi", "Vanguard". | |
| region | No | Exact investment-region string. | |
| search | No | Free-text match on ticker, fund name or ISIN. Omit to screen the whole universe. | |
| sortBy | No | Sort field applied to the returned rows. | totalAssets |
| category | No | Exact category string. Call get_etf_filter_options for the valid values; a wrong guess silently returns zero rows. | |
| currency | No | Exact trading currency, e.g. EUR, USD, GBX. | |
| domicile | No | Exact fund domicile, e.g. "Ireland", "Luxembourg", "United States". | |
| exchange | No | Exact listing exchange, e.g. XETRA, LSE, "NYSE ARCA". | |
| indexKey | No | Exact tracked-index key, e.g. SP500, MSCI_WORLD, NASDAQ100. Use get_etf_index_group to compare every fund on one index instead. | |
| strategy | No | Exact strategy classification string. | |
| assetClass | No | Exact asset-class group: EQUITY, FIXED_INCOME, COMMODITY, REAL_ESTATE, MULTI_ASSET, CASH, CURRENCY, DIGITAL_ASSETS, ALTERNATIVES or OTHER. | |
| holdingMode | No | INCLUDES keeps funds holding the constituent. EXCLUDES keeps only funds with a holdings snapshot that confirms absence — funds with no snapshot are dropped, never assumed clean. | INCLUDES |
| productType | No | Exact wrapper type, e.g. UCITS_FUND. | |
| ucitsStatus | No | UCITS restricts to wrappers a European retail investor can actually buy. | |
| holdingSearch | No | Look-through filter: find funds by a CONSTITUENT ticker or company name, e.g. "NVDA" or "NVIDIA". Only funds with a stored holdings snapshot can match. | |
| currencyHedged | No | HEDGED selects funds labelled currency-hedged. NOT_LABELLED_HEDGED selects funds not so labelled — absence of a label is not proof a fund is unhedged. | |
| benchmarkSearch | No | Substring match on the stated benchmark name. | |
| includeSecondary | No | Return every venue listing as its own row. Default false: one row per FUND (by fund ISIN), showing its most liquid listing with the others under otherListings. Use exchange/currency to choose the venue, e.g. exchange "SW" for the SIX line. | |
| marketDevelopment | No | Exact market-development classification, e.g. developed vs emerging. | |
| distributionPolicy | No | Accumulating (reinvests income) or distributing (pays it out) — the usual first cut for a European investor. | |
| holdingMinWeightPct | No | Minimum constituent weight in percentage points for holdingSearch to count as a match. |
Output Schema
| Name | Required | Description |
|---|---|---|
| query | Yes | |
| results | Yes | |
| webPage | No | |
| coverage | Yes | |
| returned | Yes | |
| warnings | Yes | |
| matchCount | Yes | |
| platformLink | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish that the tool is read-only, non-destructive, and closed-world. The description adds valuable behavioral context beyond annotations: the screen is expensive, request limits depend on connection/plan, one precise screen should be built to conserve allowance, and the result reports evaluatedCount and matchCount. It does not detail output shape, but an output schema exists, so this is a minor gap.
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 description is front-loaded with the key differentiator and use case, then adds cost guidance and unit semantics. It is appropriately long for a 24-parameter screening tool, though the long attribute list and final "Read-only" repetition slightly reduce concision.
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 tool's complexity, 24 parameters, 100% schema description coverage, annotations, and an output schema, the description provides the crucial context: full-universe scope, alternative tool distinction, cost implications, and unit conventions. Nothing essential for correct invocation is missing from the description.
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 schema already documents the 24 parameters thoroughly, making 3 the appropriate baseline. The description adds some useful global semantics, especially that percentages are percentage points and that holdingSearch matches funds by constituent holdings, but it does not meaningfully expand on parameter behavior beyond what the schema provides.
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 gives a specific verb and resource: screen the whole ETF universe by numeric rules and fund attributes. It lists the exact metric groups and attribute dimensions, and explicitly distinguishes this tool from search_etfs by full-universe evaluation versus bounded candidate scanning. An agent can identify the tool and its scope 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?
It explicitly says to prefer this over search_etfs for "cheapest / largest / best performing / most liquid" questions and explains why: search_etfs only filters a bounded scan while this evaluates the full universe. It also notes that holdingSearch is a constituent look-through and that building one precise screen conserves allowance. This gives clear when-to-use and alternative selection guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
screen_risk_boardScreen the risk boardARead-onlyInspect
Rank Bullrun's scored stock universe (~9,000 companies) by company risk: the composite risk score or any one mechanism dial (market expectation, operating pressure, cash conversion, leverage, competitive position, concentration), filtered by band, sector, country and dial coverage. Returns ticker, score, band and its meaning, direction and move since the prior reading, and the driving input per row, plus the universe band distribution and how many companies changed band at the last recompute. Use for "which large caps have stretched leverage", "most concentrated supply chains in semiconductors", "calmest German industrials", or "how risky is tech vs utilities" (includeSlices). Drill into a row with get_company_risk. A ranking of readings, not of companies to avoid. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| bands | No | Keep only these bands, e.g. ["STRETCHED","ACUTE"] for the most strained readings or ["CONTAINED"] for the calmest. | |
| limit | No | ||
| offset | No | ||
| sector | No | Exact sector, case-insensitive (e.g. "Technology", "Industrials"). Set includeSlices=true to list the sectors the board covers. | |
| sortBy | No | market_cap = largest companies first (default; a pure score sort surfaces micro-caps); score_desc = most strained first; score_asc = calmest first; worsened / improved = biggest move since the prior reading; coverage = most dials lit; name. | market_cap |
| country | No | Exact country, case-insensitive (e.g. "United States", "Germany"). | |
| mechanism | No | Rank by the composite (OVERALL) or by one mechanism dial: MARKET (drawdown, volatility, liquidity), OPERATING (margin/cost pressure), CASH_CONVERSION (cash vs earnings, capex), LEVERAGE (debt, interest cover, liquidity; CET1 for banks), COMPETITIVE (R&D, margins vs peers, technology transition), CONCENTRATION (supplier, customer, geographic). | OVERALL |
| minDialsLit | No | Coverage floor: only companies with at least this many of the six dials measured. 4+ avoids thinly-measured composites. | |
| includeSlices | No | Also return mean composite risk by sector and by country across the scored universe. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, and the description stays consistent while adding real substance: per-row return fields (ticker, score, band and its meaning, direction, move, driving input), plus universe-level band distribution and band-change counts at the last recompute. The clarification that it ranks readings rather than flagging companies to avoid is behavioral context found nowhere in 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?
Two dense sentences that front-load the ranking scope, followed by returns, use cases, sibling routing and a caveat — well ordered with no filler. Slight deduction for restating 'Read-only', which the annotations already establish, and for the very long mechanism parenthetical.
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 nine optional parameters and no output schema, the description compensates by enumerating the returned row fields and the aggregate payload. Filter dimensions, mechanism semantics, the includeSlices behavior and the drill-down path are all covered, so an agent could call this correctly without further inference.
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 78%, so the schema carries most parameter documentation. The description still adds useful framing — the six dial names grouped as filterable 'dial coverage', the band/sector/country filter set, and a concrete demonstration of includeSlices ('how risky is tech vs utilities') — though it does not explain limit/offset or sortBy 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 (rank), a specific resource (Bullrun's ~9,000-company scored universe) and the ranking basis (composite risk or one of six mechanism dials). It distinguishes itself from get_company_risk by explicitly routing row-level drill-down there, so an agent can separate it from siblings like get_risk_movers and screen_stocks.
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 four concrete query shapes ('which large caps have stretched leverage', 'most concentrated supply chains in semiconductors', 'calmest German industrials', 'how risky is tech vs utilities' with includeSlices) and names the alternative tool for follow-up. It also adds a negative guideline — 'A ranking of readings, not of companies to avoid' — which prevents misuse of the output.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
screen_stocksScreen stocksARead-onlyInspect
Screen the global Bullrun stock universe with the app rule engine using custom fundamental rules or named presets: profitable value, dividend income, growth and cash flow, cash generators, dividend growth. action=list_presets discloses exact thresholds, units, annual lookback and sorting without any backend request. action=run (default) executes one preset or custom rules; running uses the API's metered screening budget. Custom screens support sector/industry/country, listing controls, annual/quarterly lookback, AND/OR rule groups and money units. Presets are mechanical starting points, not recommendations or famous-investor strategies. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| mode | No | Deprecated alias for lookbackMode; kept for compatibility. | |
| limit | No | Maximum stocks to return: custom default 25 (1-100), preset default 20 (1-50). | |
| order | No | Sort direction. Custom default desc; presets use their disclosed order. Nulls always sort last regardless of direction. | |
| rules | No | Fundamental rules. Same groupId means AND; different groupIds mean OR. | |
| action | No | list_presets discloses named screens without any backend request; run executes a preset or custom rules and uses the metered screening budget. | run |
| preset | No | Optional named screen. Presets use disclosed fixed rules/sorting, annual lookback (2-10 years), primary active listings and a default limit of 20 (maximum 50). Omit for custom rules; do not combine with rules or minMarketCap. | |
| sector | No | Exact sector name to filter by, e.g. "Technology", "Healthcare". Omit for all sectors. | |
| sortBy | No | Metric to sort by. Custom default marketCap; presets use their disclosed sorting. revenueGrowth is accepted as an alias for revenueGrowthPct. | |
| country | No | Exact country name to filter by, e.g. "United States", "Germany". Omit for all countries. | |
| periods | No | Deprecated alias for lookback; kept for compatibility. | |
| industry | No | Exact industry name to filter by, e.g. "Software - Infrastructure". Omit for all industries. | |
| lookback | No | How many reporting periods to evaluate (default 3). Growth rules need at least 2 comparable periods; presets require 2-10 annual observations. | |
| countries | No | Exact country names to include. Use this for multi-country screens; it overrides country when provided. | |
| lookbackMode | No | Whether rule evaluation uses annual or quarterly reporting periods. Default annual; presets require annual. | |
| minMarketCap | No | Compatibility shortcut: adds marketCap >= this absolute value to every rule group. | |
| includeInactive | No | Include delisted/inactive tickers with no recent price bar. Default false. | |
| includeSecondary | No | Include secondary cross-listings of the same security. Default false (primary listings only). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes beyond the readOnlyHint annotation by disclosing that action=run consumes a metered screening budget, that list_presets performs no backend request, and that presets are mechanical starting points rather than recommendations or famous-investor strategies. Return shape is not described, but the operationally important traits are 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?
Four sentences, front-loaded with the action and resource, then the mode split, then cost, then scope of custom screens. Dense but every sentence carries usable information; the long compound sentence about custom-screen features is the only mild readability cost.
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 17-param tool with no output schema, the description covers the crucial preset-vs-custom dichotomy, the metering budget and the preset lookback constraints. It does not describe what a run returns (matching tickers plus metric values, sorting behavior), which would help given no output schema exists.
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 all 17 parameters are already documented in detail; baseline is 3. The description adds a high-level summary (sector/industry/country, listing controls, lookback, AND/OR groups, money units) that mirrors the schema but introduces no new syntax or constraints.
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 ('Screen the global Bullrun stock universe') and names the mechanism (app rule engine with custom fundamental rules or named presets). This clearly separates it from siblings like search_stocks (lookup), screen_etfs and screen_valuation_model (different universes).
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 distinguishes action=list_presets (discloses thresholds, no backend request) from action=run (executes, uses metered budget) and tells the agent custom screens vs presets. It lacks a direct 'use search_stocks instead if you want a single company' routing, but the internal mode selection is unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
screen_valuation_modelScreen by Bullrun valuation modelARead-onlyInspect
Rank the whole scored stock universe (market cap >= $100M) by Bullrun's proprietary ML models: the stocks trading furthest below (or above) the P/E or price/sales multiple their fundamentals typically command, or the strongest/weakest relative 1-year forecast signals. Filter by sector, country, exchange and financial-history coverage. Each row has the valuation gap or forecast edge, the model-typical vs current P/E, percentile, rank and data quality. Use for "cheapest stocks vs fundamentals in Europe", "most expensive tech names by the model", "best forecast scores in Japan". The valuation gap is descriptive context, not a return prediction; follow up with get_stock_metrics, get_company_risk and get_quality_moat_metrics before drawing conclusions. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| end | No | top = highest percentile first (valuation: furthest BELOW typical multiple, i.e. cheapest vs fundamentals; forecast: strongest signal). bottom = lowest first (richest vs fundamentals / weakest signal). | top |
| limit | No | ||
| model | No | valuation = P/E gap on quarterly financials (profitable companies); valuation_ps = price/sales gap (covers loss-makers); valuation_annual_1y = P/E gap on annual financials (broader non-US coverage); forecast / forecast_annual_1y = relative 1-year return-rank signal. | valuation |
| sector | No | Exact sector, case-insensitive, e.g. "Technology", "Healthcare", "Financial Services". | |
| country | No | Exact country, case-insensitive, e.g. "United States", "Germany", "Japan". | |
| coverage | No | full = only stocks whose model window (8 quarters / 4 years) is fully populated; limited = the rest. | all |
| exchange | No | Exact exchange code, case-insensitive, e.g. "NASDAQ", "XETRA", "LSE". |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover read-only/destructive/open-world, but the description adds real context: the universe cutoff, what each row returns (valuation gap, model-typical vs current P/E, percentile, rank, data quality), and an explicit caveat that the gap is descriptive context rather than a return prediction. That interpretation constraint materially changes how an agent presents results.
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 verb and universe, and every sentence carries new information (row contents, caveat, follow-ups). It is a dense paragraph that could be segmented for scanability, but there is 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?
With no output schema, the description compensates by naming the returned fields and the universe scope, and it closes the loop with follow-up tools so the agent knows this is a starting point. Nothing needed to invoke 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 86%, so the schema already documents end, model, sector, country, coverage and exchange in detail. The description restates the model families and filter dimensions in prose but adds little syntax or semantics beyond the enum descriptions, 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 (Rank) and resource (the whole scored stock universe, market cap >= $100M) plus the exact ranking basis (Bullrun ML valuation gap or forecast signal). This is unmistakably distinguishable from generic siblings like screen_stocks or get_valuation_model.
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 example queries ('cheapest stocks vs fundamentals in Europe', 'best forecast scores in Japan') and prescribes follow-up tools (get_stock_metrics, get_company_risk, get_quality_moat_metrics). It never states when to prefer screen_stocks or get_valuation_model instead, so no explicit exclusion guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_etfsSearch ETFsARead-onlyInspect
Look up ETFs by name, ticker or ISIN, with classification, listing, index, distribution-policy, AUM, expense-ratio and yield filters. Best for finding a known fund. For ranking questions ("cheapest", "largest", "best performing", "most liquid") prefer screen_etfs, which evaluates the whole universe: here minAum and minYieldTtmPct are applied only to a bounded profile-enriched candidate scan, so do not describe the result as exhaustive when candidateCapReached is true. Use get_etf_snapshot for one listing, get_etf_fund to resolve an ISIN across venues, and get_etf_holdings for constituents. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| focus | No | Exact ETF focus/exposure filter, e.g. Japan, TOPIX, or Equity - Australia. | |
| limit | No | Maximum matching ETFs to return, 1-100. | |
| minAum | No | Minimum assets under management in the profile's reported currency units. | |
| region | No | Exact portfolio or investment-region filter. | |
| search | No | Free-text ETF search by ticker, fund name, or ISIN (e.g. IE00B4L5Y983). Omit for a broad screen. | |
| sortBy | No | Sort field. Relevance preserves Bullrun search ordering. | relevance |
| category | No | Exact broad ETF category/asset-class filter, e.g. Equity, Fixed Income, Commodity, Crypto, or Real Estate. Call get_etf_filter_options for valid values. | |
| currency | No | Exact trading-currency filter. | |
| domicile | No | Exact fund domicile filter. | |
| exchange | No | Exact listing exchange filter. | |
| indexKey | No | Exact tracked-index key, e.g. SP500 or MSCI_WORLD. Use get_etf_index_group to rank every fund on one index by cost. | |
| scanLimit | No | Maximum coarse-search candidates to enrich before applying quantitative filters/sorts, 25-500. | |
| sortDirection | No | desc | |
| minYieldTtmPct | No | Minimum trailing yield in percentage points, e.g. 2 means 2%. | |
| includeInactive | No | ||
| includeSecondary | No | ||
| distributionPolicy | No | Accumulating (reinvests income) or distributing (pays it out). | |
| maxExpenseRatioPct | No | Maximum annual expense ratio in percentage points, e.g. 0.25 means 0.25%. |
Output Schema
| Name | Required | Description |
|---|---|---|
| query | Yes | |
| results | Yes | |
| webPage | No | |
| coverage | Yes | |
| returned | Yes | |
| warnings | Yes | |
| platformLink | No | |
| matchesInScannedCandidates | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint/destructiveHint, but the description adds genuinely non-obvious behavior: minAum and minYieldTtmPct are only applied to a bounded profile-enriched candidate scan, and results are not exhaustive when candidateCapReached is true. That is a real correctness caveat an agent cannot infer from the schema 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?
Four sentences, front-loaded with what it does, then alternative routing, then the exhaustiveness caveat, then sibling pointers. No filler; the trailing 'Read-only' is mildly redundant with annotations but negligible.
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 an 18-parameter optional-filter tool with an output schema, the description supplies the routing and the one behavioral trap (bounded candidate scan). Minor gap: three parameters (includeInactive, includeSecondary, sortDirection) are undocumented in both schema and description, so an agent must guess their effect.
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 83%, so the baseline is 3; the description goes beyond by clarifying the scope of minAum/minYieldTtmPct (bounded candidate scan, not the whole universe) and by framing search as the free-text entry point vs. exact-match facet filters. It does not clarify includeInactive, includeSecondary or sortDirection, which lack schema descriptions.
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 (look up ETFs) plus the lookup keys (name, ticker, ISIN) and the filter families available, so an agent immediately knows this is a known-item lookup with faceted filtering, distinct from the screening and per-fund 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?
Explicitly says 'Best for finding a known fund', names screen_etfs as the alternative for ranking questions with quoted example queries ('cheapest', 'largest'), and routes single-listing, ISIN-resolution and constituents use cases to get_etf_snapshot, get_etf_fund and get_etf_holdings respectively. When-to-use, when-not-to-use and alternatives are all present.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_stocksFind stock tickers and company listingsARead-onlyInspect
Resolve a company name, native ticker, ISIN or exchange-qualified symbol to Bullrun listings before calling exact-ticker research tools. Supports exchange/MIC, country, currency and instrument-type filters. Recognized Yahoo suffixes are checked against compatible stored venues; dots in native share-class tickers are preserved. Returns explicit ambiguous candidates and never picks a listing when alternatives remain. No enrichment or market-data refresh. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum output candidates. A backend scan is capped at 500 candidates per search. | |
| query | Yes | Company/name phrase, exact native ticker (AAPL, BMW, BRK.B), ISIN, EXCHANGE:TICKER, or Yahoo symbol (BMW.DE, NESN.SW). | |
| country | No | Exact stored country name, e.g. Germany or Switzerland. | |
| currency | No | Listing quote currency, e.g. USD, CHF or GBX. GBX and GBP are different quote units. | |
| exchange | No | Stored exchange code or supported MIC, e.g. XETRA/XETR, NASDAQ/XNAS, SW/XSWX. A conflicting prefix is rejected. | |
| quoteType | No | Default stocks, including unclassified equities. ETF/ALL allow other instrument lookup; this does not make stock-only research tools valid for funds. | EQUITY |
| includeInactive | No | Include inactive/retired listings. Returned lifecycle/successor fields must be checked. | |
| includeSecondary | No | Include alternative venue listings. ISIN/name matches across venues require an explicit listing choice. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnlyHint, openWorldHint=false, destructiveHint=false), yet the description adds real behavioral substance: ambiguity handling ('never picks a listing when alternatives remain', 'Returns explicit ambiguous candidates') and venue reconciliation of Yahoo suffixes with share-class dots preserved. These are non-obvious resolution behaviors an agent must anticipate when interpreting results.
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 resolve-then-research framing, and each sentence carries distinct information about resolution semantics or scope limits. The trailing 'Read-only.' duplicates the readOnlyHint annotation and is the one line that doesn't 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?
With eight parameters, no output schema, and a resolution-oriented purpose, the description supplies what the schema cannot: the ambiguity contract, the no-enrichment boundary, venue-suffix handling, and result shape ('explicit ambiguous candidates'). An agent can call this correctly and interpret its output without further 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 description coverage is 100%, so every parameter including country, currency, exchange, quoteType, includeInactive and includeSecondary is already documented, and the description's filter list ('exchange/MIC, country, currency and instrument-type') merely restates it. The one genuine addition beyond the schema is that native share-class ticker dots are preserved. 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 precise verb and resource ('Resolve a company name, native ticker, ISIN or exchange-qualified symbol to Bullrun listings') and explicitly positions itself as a pre-step before 'exact-ticker research tools'. This clearly separates it from screen_stocks (screening) and search_etfs (fund lookup), which an agent can distinguish 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 sequencing rule ('before calling exact-ticker research tools') and a scope exclusion ('No enrichment or market-data refresh'). It also notes that quoteType ETF/ALL 'does not make stock-only research tools valid for funds', steering fund lookups elsewhere. It stops short of naming search_etfs as the direct alternative, so the routing is implied rather than spelled out.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
simulate_etf_costSimulate ETF costARead-onlyInspect
Simulate expense-ratio, assumed bid/ask spread, commissions, and recurring contributions over a holding period. Compares the same gross-return path with and without costs and reports direct charges plus ending-value drag. Taxes, FX, market impact and brokerage-specific fees are excluded unless represented by the inputs. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| years | No | ||
| ticker | Yes | Exact Bullrun ETF listing ticker. | |
| spreadPct | No | Assumed full bid/ask spread in percentage points; each purchase pays half the spread. | |
| expenseRatioPct | No | Optional expense-ratio override in percentage points. Otherwise uses the stored ETF profile value. | |
| initialInvestment | No | ||
| commissionPerTrade | No | ||
| contributionAmount | No | ||
| grossAnnualReturnPct | No | Assumed annual return before ETF and trading costs, in percentage points. Default 0 isolates direct costs. | |
| contributionFrequency | No | monthly |
Output Schema
| Name | Required | Description |
|---|---|---|
| ticker | Yes | |
| results | Yes | |
| webPage | No | |
| warnings | Yes | |
| assumptions | Yes | |
| platformLink | No | |
| costBreakdown | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, so the trailing 'Read-only' adds nothing. However the description does disclose real behavioral content beyond annotations: the exclusions list and the fact that the output reports direct charges plus ending-value drag, telling an agent this is a deterministic no-side-effect what-if model.
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 the exclusion sentence earns its place by preventing misuse of the results. The standalone 'Read-only.' fragment is pure duplication of the readOnlyHint annotation and is the one wasted element.
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 and annotations covering the safety profile, the description need not explain return values, and it goes further by summarizing what the report contains. It is nearly complete for a 9-parameter simulation tool; only the required ticker and default initialInvestment go unmentioned.
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 only 44% across 9 parameters, so the description must carry weight; it does name the cost categories (expense ratio, spread, commissions, contributions, holding period) that map to those inputs, but adds no format, unit, or default detail beyond what the schema already states. The required ticker and initialInvestment are never addressed.
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 (simulate) and a specific resource (ETF cost: expense ratio, spread, commissions, contributions) and describes the comparison method (same gross-return path with and without costs). No sibling tool does simulation, so it is unambiguous against the surrounding screen_etfs/get_etf_* family.
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 clear scope boundaries — what the model does and does not include (taxes, FX, market impact, brokerage-specific fees) — which tells an agent when this tool's answer is and isn't applicable. It never explicitly names an alternative or states a 'use this instead of X' condition, 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.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
16 tool updates
- Changed
compare_company_exposures1 field changed- changed
Input schema / properties / tickers / descriptionPrevious value: -"Two to five distinct Bullrun listing tickers, e.g. AAPL, BMW or 6324.T. Bullrun tickers: US and most European listings use the plain local symbol (AAPL, BMW, NESN, ABBN); most Asian and Indian listings keep their exchange suffix (Tokyo 6324.T, Hong Kong 0700.HK, Shanghai 600519.SS, Shenzhen 000001.SZ, Taiwan 2330.TW, Korea 000100.KS, Singapore D05.SI, India RELIANCE.NS), but some Japanese and Korean large caps are plain codes (Toyota 7203, Samsung 005930). Either form is resolved automatically when exactly one listing matches; use search_stocks to find a ticker by company name or ISIN. Company names are not accepted here."New value: +"Two to five distinct Bullrun listing tickers, e.g. AAPL, BMW or 6324.T. Use the listing ticker returned by search_stocks. US/European examples: AAPL, BMW, NESN. Most Asian listings keep their exchange suffix (6324.T, 0700.HK); some use bare codes (005930). Native or suffixed forms resolve only when one listing matches; search by company name or ISIN if unsure. Company names are not accepted here."
- Changed
compare_stocks1 field changed- changed
Input schema / properties / tickers / descriptionPrevious value: -"Two to five distinct Bullrun stock tickers, e.g. AAPL, BMW, NESN, 6324.T or 7203. Bullrun tickers: US and most European listings use the plain local symbol (AAPL, BMW, NESN, ABBN); most Asian and Indian listings keep their exchange suffix (Tokyo 6324.T, Hong Kong 0700.HK, Shanghai 600519.SS, Shenzhen 000001.SZ, Taiwan 2330.TW, Korea 000100.KS, Singapore D05.SI, India RELIANCE.NS), but some Japanese and Korean large caps are plain codes (Toyota 7203, Samsung 005930). Either form is resolved automatically when exactly one listing matches; use search_stocks to find a ticker by company name or ISIN. Company names are not accepted here."New value: +"Two to five distinct Bullrun stock tickers, e.g. AAPL, BMW, NESN, 6324.T or 7203. Use the listing ticker returned by search_stocks. US/European examples: AAPL, BMW, NESN. Most Asian listings keep their exchange suffix (6324.T, 0700.HK); some use bare codes (005930). Native or suffixed forms resolve only when one listing matches; search by company name or ISIN if unsure. Company names are not accepted here."
- Changed
find_stock_peers1 field changed- changed
Input schema / properties / ticker / descriptionPrevious value: -"Bullrun equity ticker, e.g. AAPL, BMW or 6324.T. Bullrun tickers: US and most European listings use the plain local symbol (AAPL, BMW, NESN, ABBN); most Asian and Indian listings keep their exchange suffix (Tokyo 6324.T, Hong Kong 0700.HK, Shanghai 600519.SS, Shenzhen 000001.SZ, Taiwan 2330.TW, Korea 000100.KS, Singapore D05.SI, India RELIANCE.NS), but some Japanese and Korean large caps are plain codes (Toyota 7203, Samsung 005930). Either form is resolved automatically when exactly one listing matches; use search_stocks to find a ticker by company name or ISIN."New value: +"Bullrun equity ticker, e.g. AAPL, BMW or 6324.T. Use the listing ticker returned by search_stocks. US/European examples: AAPL, BMW, NESN. Most Asian listings keep their exchange suffix (6324.T, 0700.HK); some use bare codes (005930). Native or suffixed forms resolve only when one listing matches; search by company name or ISIN if unsure."
- Changed
get_company_data_coverage1 field changed- changed
Input schema / properties / ticker / descriptionPrevious value: -"Bullrun company ticker, e.g. AAPL, SAP or 6324.T. Bullrun tickers: US and most European listings use the plain local symbol (AAPL, BMW, NESN, ABBN); most Asian and Indian listings keep their exchange suffix (Tokyo 6324.T, Hong Kong 0700.HK, Shanghai 600519.SS, Shenzhen 000001.SZ, Taiwan 2330.TW, Korea 000100.KS, Singapore D05.SI, India RELIANCE.NS), but some Japanese and Korean large caps are plain codes (Toyota 7203, Samsung 005930). Either form is resolved automatically when exactly one listing matches; use search_stocks to find a ticker by company name or ISIN."New value: +"Bullrun company ticker, e.g. AAPL, SAP or 6324.T. Use the listing ticker returned by search_stocks. US/European examples: AAPL, BMW, NESN. Most Asian listings keep their exchange suffix (6324.T, 0700.HK); some use bare codes (005930). Native or suffixed forms resolve only when one listing matches; search by company name or ISIN if unsure."
- Changed
get_company_news1 field changed- changed
Input schema / properties / ticker / descriptionPrevious value: -"Bullrun company ticker, e.g. AAPL, SAP, ABBN or 6324.T. Bullrun tickers: US and most European listings use the plain local symbol (AAPL, BMW, NESN, ABBN); most Asian and Indian listings keep their exchange suffix (Tokyo 6324.T, Hong Kong 0700.HK, Shanghai 600519.SS, Shenzhen 000001.SZ, Taiwan 2330.TW, Korea 000100.KS, Singapore D05.SI, India RELIANCE.NS), but some Japanese and Korean large caps are plain codes (Toyota 7203, Samsung 005930). Either form is resolved automatically when exactly one listing matches; use search_stocks to find a ticker by company name or ISIN."New value: +"Bullrun company ticker, e.g. AAPL, SAP, ABBN or 6324.T. Use the listing ticker returned by search_stocks. US/European examples: AAPL, BMW, NESN. Most Asian listings keep their exchange suffix (6324.T, 0700.HK); some use bare codes (005930). Native or suffixed forms resolve only when one listing matches; search by company name or ISIN if unsure."
- Changed
get_company_relationships2 fields changed- changed
Input schema / properties / evidence / descriptionPrevious value: -"none = counts only; sources = source title/URL/type per edge; excerpts = also the quoted evidence text."New value: +"none = omit evidence sources, keeping counterparties, measurements and evidence counts; sources = source title/URL/type per edge; excerpts = also quoted evidence text." - changed
Input schema / properties / ticker / descriptionPrevious value: -"Bullrun ticker, e.g. \"AAPL\", \"SAP\", \"ASML\". Bullrun tickers: US and most European listings use the plain local symbol (AAPL, BMW, NESN, ABBN); most Asian and Indian listings keep their exchange suffix (Tokyo 6324.T, Hong Kong 0700.HK, Shanghai 600519.SS, Shenzhen 000001.SZ, Taiwan 2330.TW, Korea 000100.KS, Singapore D05.SI, India RELIANCE.NS), but some Japanese and Korean large caps are plain codes (Toyota 7203, Samsung 005930). Either form is resolved automatically when exactly one listing matches; use search_stocks to find a ticker by company name or ISIN."New value: +"Bullrun ticker, e.g. \"AAPL\", \"SAP\", \"ASML\". Use the listing ticker returned by search_stocks. US/European examples: AAPL, BMW, NESN. Most Asian listings keep their exchange suffix (6324.T, 0700.HK); some use bare codes (005930). Native or suffixed forms resolve only when one listing matches; search by company name or ISIN if unsure."
- Changed
get_company_risk1 field changed- changed
Input schema / properties / ticker / descriptionPrevious value: -"Bullrun ticker, e.g. \"AAPL\", \"ASML\", \"NESN\", \"6324.T\" or \"0700.HK\". Bullrun tickers: US and most European listings use the plain local symbol (AAPL, BMW, NESN, ABBN); most Asian and Indian listings keep their exchange suffix (Tokyo 6324.T, Hong Kong 0700.HK, Shanghai 600519.SS, Shenzhen 000001.SZ, Taiwan 2330.TW, Korea 000100.KS, Singapore D05.SI, India RELIANCE.NS), but some Japanese and Korean large caps are plain codes (Toyota 7203, Samsung 005930). Either form is resolved automatically when exactly one listing matches; use search_stocks to find a ticker by company name or ISIN."New value: +"Bullrun ticker, e.g. \"AAPL\", \"ASML\", \"NESN\", \"6324.T\" or \"0700.HK\". Use the listing ticker returned by search_stocks. US/European examples: AAPL, BMW, NESN. Most Asian listings keep their exchange suffix (6324.T, 0700.HK); some use bare codes (005930). Native or suffixed forms resolve only when one listing matches; search by company name or ISIN if unsure."
- Changed
get_company_risk_history1 field changed- changed
Input schema / properties / ticker / descriptionPrevious value: -"Bullrun company ticker, e.g. AAPL, SAP or 6324.T. Bullrun tickers: US and most European listings use the plain local symbol (AAPL, BMW, NESN, ABBN); most Asian and Indian listings keep their exchange suffix (Tokyo 6324.T, Hong Kong 0700.HK, Shanghai 600519.SS, Shenzhen 000001.SZ, Taiwan 2330.TW, Korea 000100.KS, Singapore D05.SI, India RELIANCE.NS), but some Japanese and Korean large caps are plain codes (Toyota 7203, Samsung 005930). Either form is resolved automatically when exactly one listing matches; use search_stocks to find a ticker by company name or ISIN."New value: +"Bullrun company ticker, e.g. AAPL, SAP or 6324.T. Use the listing ticker returned by search_stocks. US/European examples: AAPL, BMW, NESN. Most Asian listings keep their exchange suffix (6324.T, 0700.HK); some use bare codes (005930). Native or suffixed forms resolve only when one listing matches; search by company name or ISIN if unsure."
- Changed
get_earnings_call_transcript1 field changed- changed
Input schema / properties / ticker / descriptionPrevious value: -"Bullrun ticker, e.g. \"CRWD\", \"SPGI\", \"V\". Bullrun tickers: US and most European listings use the plain local symbol (AAPL, BMW, NESN, ABBN); most Asian and Indian listings keep their exchange suffix (Tokyo 6324.T, Hong Kong 0700.HK, Shanghai 600519.SS, Shenzhen 000001.SZ, Taiwan 2330.TW, Korea 000100.KS, Singapore D05.SI, India RELIANCE.NS), but some Japanese and Korean large caps are plain codes (Toyota 7203, Samsung 005930). Either form is resolved automatically when exactly one listing matches; use search_stocks to find a ticker by company name or ISIN."New value: +"Bullrun ticker, e.g. \"CRWD\", \"SPGI\", \"V\". Use the listing ticker returned by search_stocks. US/European examples: AAPL, BMW, NESN. Most Asian listings keep their exchange suffix (6324.T, 0700.HK); some use bare codes (005930). Native or suffixed forms resolve only when one listing matches; search by company name or ISIN if unsure."
- Changed
get_financial_history5 fields changed- changed
Input schema / properties / periodType / defaultPrevious value: -"both"New value: +"annual" - changed
Input schema / properties / periodType / descriptionPrevious value: -"Return annual rows, quarterly rows, or both. Annual rows use fiscalQuarter=0."New value: +"Defaults to annual statements with a growth summary. Choose quarterly or both for detailed period research. Annual rows use fiscalQuarter=0." - changed
Input schema / properties / ticker / descriptionPrevious value: -"The Bullrun ticker. Bullrun tickers: US and most European listings use the plain local symbol (AAPL, BMW, NESN, ABBN); most Asian and Indian listings keep their exchange suffix (Tokyo 6324.T, Hong Kong 0700.HK, Shanghai 600519.SS, Shenzhen 000001.SZ, Taiwan 2330.TW, Korea 000100.KS, Singapore D05.SI, India RELIANCE.NS), but some Japanese and Korean large caps are plain codes (Toyota 7203, Samsung 005930). Either form is resolved automatically when exactly one listing matches; use search_stocks to find a ticker by company name or ISIN."New value: +"The Bullrun ticker. Use the listing ticker returned by search_stocks. US/European examples: AAPL, BMW, NESN. Most Asian listings keep their exchange suffix (6324.T, 0700.HK); some use bare codes (005930). Native or suffixed forms resolve only when one listing matches; search by company name or ISIN if unsure." - changed
Input schema / properties / years / defaultPrevious value: -10New value: +5 - changed
Input schema / properties / years / descriptionPrevious value: -"How many fiscal years of history to return, counting backward from the latest fiscal year available."New value: +"Fiscal-year window counting backward from the latest available fiscal year. Default 5; request up to 15 for longer research."
- Changed
get_forward_estimates1 field changed- changed
Input schema / properties / ticker / descriptionPrevious value: -"Bullrun ticker, e.g. \"AAPL\", \"CRWD\", \"SPGI\". Bullrun tickers: US and most European listings use the plain local symbol (AAPL, BMW, NESN, ABBN); most Asian and Indian listings keep their exchange suffix (Tokyo 6324.T, Hong Kong 0700.HK, Shanghai 600519.SS, Shenzhen 000001.SZ, Taiwan 2330.TW, Korea 000100.KS, Singapore D05.SI, India RELIANCE.NS), but some Japanese and Korean large caps are plain codes (Toyota 7203, Samsung 005930). Either form is resolved automatically when exactly one listing matches; use search_stocks to find a ticker by company name or ISIN."New value: +"Bullrun ticker, e.g. \"AAPL\", \"CRWD\", \"SPGI\". Use the listing ticker returned by search_stocks. US/European examples: AAPL, BMW, NESN. Most Asian listings keep their exchange suffix (6324.T, 0700.HK); some use bare codes (005930). Native or suffixed forms resolve only when one listing matches; search by company name or ISIN if unsure."
- Changed
get_operating_kpis1 field changed- changed
Input schema / properties / ticker / descriptionPrevious value: -"Bullrun ticker, e.g. \"CRWD\", \"SNOW\", \"V\". Bullrun tickers: US and most European listings use the plain local symbol (AAPL, BMW, NESN, ABBN); most Asian and Indian listings keep their exchange suffix (Tokyo 6324.T, Hong Kong 0700.HK, Shanghai 600519.SS, Shenzhen 000001.SZ, Taiwan 2330.TW, Korea 000100.KS, Singapore D05.SI, India RELIANCE.NS), but some Japanese and Korean large caps are plain codes (Toyota 7203, Samsung 005930). Either form is resolved automatically when exactly one listing matches; use search_stocks to find a ticker by company name or ISIN."New value: +"Bullrun ticker, e.g. \"CRWD\", \"SNOW\", \"V\". Use the listing ticker returned by search_stocks. US/European examples: AAPL, BMW, NESN. Most Asian listings keep their exchange suffix (6324.T, 0700.HK); some use bare codes (005930). Native or suffixed forms resolve only when one listing matches; search by company name or ISIN if unsure."
- Changed
get_quality_moat_metrics1 field changed- changed
Input schema / properties / ticker / descriptionPrevious value: -"The Bullrun ticker. Bullrun tickers: US and most European listings use the plain local symbol (AAPL, BMW, NESN, ABBN); most Asian and Indian listings keep their exchange suffix (Tokyo 6324.T, Hong Kong 0700.HK, Shanghai 600519.SS, Shenzhen 000001.SZ, Taiwan 2330.TW, Korea 000100.KS, Singapore D05.SI, India RELIANCE.NS), but some Japanese and Korean large caps are plain codes (Toyota 7203, Samsung 005930). Either form is resolved automatically when exactly one listing matches; use search_stocks to find a ticker by company name or ISIN."New value: +"The Bullrun ticker. Use the listing ticker returned by search_stocks. US/European examples: AAPL, BMW, NESN. Most Asian listings keep their exchange suffix (6324.T, 0700.HK); some use bare codes (005930). Native or suffixed forms resolve only when one listing matches; search by company name or ISIN if unsure."
- Changed
get_revenue_breakdown1 field changed- changed
Input schema / properties / ticker / descriptionPrevious value: -"The Bullrun ticker, e.g. \"SPGI\", \"MSFT\", \"V\". Bullrun tickers: US and most European listings use the plain local symbol (AAPL, BMW, NESN, ABBN); most Asian and Indian listings keep their exchange suffix (Tokyo 6324.T, Hong Kong 0700.HK, Shanghai 600519.SS, Shenzhen 000001.SZ, Taiwan 2330.TW, Korea 000100.KS, Singapore D05.SI, India RELIANCE.NS), but some Japanese and Korean large caps are plain codes (Toyota 7203, Samsung 005930). Either form is resolved automatically when exactly one listing matches; use search_stocks to find a ticker by company name or ISIN."New value: +"The Bullrun ticker, e.g. \"SPGI\", \"MSFT\", \"V\". Use the listing ticker returned by search_stocks. US/European examples: AAPL, BMW, NESN. Most Asian listings keep their exchange suffix (6324.T, 0700.HK); some use bare codes (005930). Native or suffixed forms resolve only when one listing matches; search by company name or ISIN if unsure."
- Changed
get_stock_price_history1 field changed- changed
Input schema / properties / ticker / descriptionPrevious value: -"Bullrun stock ticker, e.g. AAPL, SAP, ABBN, 6324.T or 7203. Bullrun tickers: US and most European listings use the plain local symbol (AAPL, BMW, NESN, ABBN); most Asian and Indian listings keep their exchange suffix (Tokyo 6324.T, Hong Kong 0700.HK, Shanghai 600519.SS, Shenzhen 000001.SZ, Taiwan 2330.TW, Korea 000100.KS, Singapore D05.SI, India RELIANCE.NS), but some Japanese and Korean large caps are plain codes (Toyota 7203, Samsung 005930). Either form is resolved automatically when exactly one listing matches; use search_stocks to find a ticker by company name or ISIN."New value: +"Bullrun stock ticker, e.g. AAPL, SAP, ABBN, 6324.T or 7203. Use the listing ticker returned by search_stocks. US/European examples: AAPL, BMW, NESN. Most Asian listings keep their exchange suffix (6324.T, 0700.HK); some use bare codes (005930). Native or suffixed forms resolve only when one listing matches; search by company name or ISIN if unsure."
- Changed
get_valuation_model1 field changed- changed
Input schema / properties / tickers / descriptionPrevious value: -"1-10 Bullrun tickers, e.g. [\"AAPL\",\"MSFT\"] or [\"ASML\",\"SAP\",\"NESN\"]. Bullrun tickers: US and most European listings use the plain local symbol (AAPL, BMW, NESN, ABBN); most Asian and Indian listings keep their exchange suffix (Tokyo 6324.T, Hong Kong 0700.HK, Shanghai 600519.SS, Shenzhen 000001.SZ, Taiwan 2330.TW, Korea 000100.KS, Singapore D05.SI, India RELIANCE.NS), but some Japanese and Korean large caps are plain codes (Toyota 7203, Samsung 005930). Either form is resolved automatically when exactly one listing matches; use search_stocks to find a ticker by company name or ISIN."New value: +"1-10 Bullrun tickers, e.g. [\"AAPL\",\"MSFT\"] or [\"ASML\",\"SAP\",\"NESN\"]. Use the listing ticker returned by search_stocks. US/European examples: AAPL, BMW, NESN. Most Asian listings keep their exchange suffix (6324.T, 0700.HK); some use bare codes (005930). Native or suffixed forms resolve only when one listing matches; search by company name or ISIN if unsure."
4 tool updates
- Changed
get_etf_exposures9 fields changed- removed
Output schema / properties / availableTypes / items / $refRemoved value: -"#/properties/requestedTypes/items" - added
Output schema / properties / availableTypes / items / enumAdded value: +[ + "sector", + "country", + "currency", + "asset", + "factor", + "thematic" +] - added
Output schema / properties / availableTypes / items / typeAdded value: +"string" - removed
Output schema / properties / notLoadedTypes / items / $refRemoved value: -"#/properties/requestedTypes/items" - added
Output schema / properties / notLoadedTypes / items / enumAdded value: +[ + "sector", + "country", + "currency", + "asset", + "factor", + "thematic" +] - added
Output schema / properties / notLoadedTypes / items / typeAdded value: +"string" - removed
Output schema / properties / unavailableTypes / items / $refRemoved value: -"#/properties/requestedTypes/items" - added
Output schema / properties / unavailableTypes / items / enumAdded value: +[ + "sector", + "country", + "currency", + "asset", + "factor", + "thematic" +] - added
Output schema / properties / unavailableTypes / items / typeAdded value: +"string"
- Changed
get_etf_snapshot6 fields changed- removed
Output schema / properties / availableModules / items / $refRemoved value: -"#/properties/requestedModules/items" - added
Output schema / properties / availableModules / items / enumAdded value: +[ + "identity", + "classification", + "market", + "fund_data", + "costs", + "income", + "benchmark" +] - added
Output schema / properties / availableModules / items / typeAdded value: +"string" - removed
Output schema / properties / missingModules / items / $refRemoved value: -"#/properties/requestedModules/items" - added
Output schema / properties / missingModules / items / enumAdded value: +[ + "identity", + "classification", + "market", + "fund_data", + "costs", + "income", + "benchmark" +] - added
Output schema / properties / missingModules / items / typeAdded value: +"string"
- Changed
get_etf_timeseries6 fields changed- removed
Output schema / properties / availableSeries / items / $refRemoved value: -"#/properties/requestedSeries/items" - added
Output schema / properties / availableSeries / items / enumAdded value: +[ + "price", + "price_return", + "nav", + "total_return", + "benchmark", + "premium_discount" +] - added
Output schema / properties / availableSeries / items / typeAdded value: +"string" - removed
Output schema / properties / unavailableSeries / items / $refRemoved value: -"#/properties/requestedSeries/items" - added
Output schema / properties / unavailableSeries / items / enumAdded value: +[ + "price", + "price_return", + "nav", + "total_return", + "benchmark", + "premium_discount" +] - added
Output schema / properties / unavailableSeries / items / typeAdded value: +"string"
- Changed
get_stock_price_history2 fields changed- removed
Input schema / properties / endDate / $refRemoved value: -"#/properties/startDate" - added
Input schema / properties / endDate / typeAdded value: +"string"
2 tool updates
- Changed
get_company_risk_history2 fields changed- changed
Input schema / properties / limit / defaultPrevious value: -6New value: +3 - changed
Input schema / properties / limit / descriptionPrevious value: -"Latest stored run dates to return, oldest first. Retention and gaps vary. Full detail supports at most six dates."New value: +"Latest stored run dates to return, oldest first; each date carries its change from the previous stored date. Retention and gaps vary. Full detail supports at most six dates."
- Changed
get_earnings_call_transcript1 field changed- changed
Input schema / properties / maxChunks / defaultPrevious value: -80New value: +40
9 tool updates
- Removed
analyze_etf_overlap - Removed
analyze_portfolio_fit - Changed
compare_etfs6 fields changed- added
Input schema / properties / include / descriptionAdded value: +"Selected comparison modules. overlap is opt-in and returns pairwise shared holdings and weighted overlap from each fund's latest stored snapshot." - changed
Input schema / properties / include / items / enumPrevious value: -[ - "classification", - "market", - "fund_data", - "costs", - "income", - "benchmark", - "performance", - "risk", - "holdings" -]New value: +[ + "classification", + "market", + "fund_data", + "costs", + "income", + "benchmark", + "performance", + "risk", + "holdings", + "overlap" +] - changed
Input schema / properties / include / maxItemsPrevious value: -9New value: +10 - added
Input schema / properties / topSharedLimitAdded value: +{ + "default": 20, + "description": "Maximum shared holdings per ETF pair when overlap is requested; does not limit the snapshots used in overlap calculations.", + "maximum": 100, + "minimum": 1, + "type": "integer" +} - added
Output schema / properties / overlapAdded value: +{ + "additionalProperties": false, + "properties": { + "coverage": { + "items": { + "additionalProperties": {}, + "type": "object" + }, + "type": "array" + }, + "methodology": { + "additionalProperties": {}, + "type": "object" + }, + "pairs": { + "items": { + "additionalProperties": {}, + "type": "object" + }, + "type": "array" + }, + "warnings": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "methodology", + "coverage", + "pairs", + "warnings" + ], + "type": "object" +} - changed
Output schema / properties / requestedModules / items / enumPrevious value: -[ - "classification", - "market", - "fund_data", - "costs", - "income", - "benchmark", - "performance", - "risk", - "holdings" -]New value: +[ + "classification", + "market", + "fund_data", + "costs", + "income", + "benchmark", + "performance", + "risk", + "holdings", + "overlap" +]
- Changed
get_portfolio_analytics2 fields changed- changed
Input schema / properties / candidateTicker / descriptionPrevious value: -"Optional exact Bullrun ticker to test as a candidate diversifier - the native local-exchange symbol, e.g. AAPL, BMW, ABBN, NESN (not Yahoo-style suffixes like BMW.DE)."New value: +"Optional exact Bullrun stock or ETF listing ticker to test as a candidate diversifier, e.g. AAPL, BMW, ABBN, NESN or SPY. Use the stored listing ticker; do not infer exchange suffixes." - added
Input schema / properties / includeLookThroughAdded value: +{ + "default": false, + "description": "Also compare an exact stock or ETF candidate against direct holdings and stored ETF constituents. Requires candidateTicker. Default false: no underlying holdings requests. Look-through has separate priced-position coverage from price-history risk analytics.", + "type": "boolean" +}
- Added
list_research_shortlist - Removed
query_etfs - Added
save_research_shortlist - Removed
screen_stock_presets - Changed
screen_stocks13 fields changed- added
Input schema / properties / actionAdded value: +{ + "default": "run", + "description": "list_presets discloses named screens without any backend request; run executes a preset or custom rules and uses the metered screening budget.", + "enum": [ + "list_presets", + "run" + ], + "type": "string" +} - removed
Input schema / properties / limit / defaultRemoved value: -25 - changed
Input schema / properties / limit / descriptionPrevious value: -"Maximum number of stocks to return (1-100)."New value: +"Maximum stocks to return: custom default 25 (1-100), preset default 20 (1-50)." - removed
Input schema / properties / lookback / defaultRemoved value: -3 - changed
Input schema / properties / lookback / descriptionPrevious value: -"How many reporting periods to evaluate. Growth rules need at least 2 comparable periods."New value: +"How many reporting periods to evaluate (default 3). Growth rules need at least 2 comparable periods; presets require 2-10 annual observations." - removed
Input schema / properties / lookbackMode / defaultRemoved value: -"annual" - changed
Input schema / properties / lookbackMode / descriptionPrevious value: -"Whether rule evaluation uses annual or quarterly reporting periods."New value: +"Whether rule evaluation uses annual or quarterly reporting periods. Default annual; presets require annual." - removed
Input schema / properties / order / defaultRemoved value: -"desc" - changed
Input schema / properties / order / descriptionPrevious value: -"Sort direction. Nulls always sort last regardless of direction."New value: +"Sort direction. Custom default desc; presets use their disclosed order. Nulls always sort last regardless of direction." - added
Input schema / properties / presetAdded value: +{ + "description": "Optional named screen. Presets use disclosed fixed rules/sorting, annual lookback (2-10 years), primary active listings and a default limit of 20 (maximum 50). Omit for custom rules; do not combine with rules or minMarketCap.", + "enum": [ + "profitable_value", + "dividend_income", + "growth_and_cashflow", + "cash_generators", + "dividend_growth" + ], + "type": "string" +} - removed
Input schema / properties / rules / defaultRemoved value: -[] - removed
Input schema / properties / sortBy / defaultRemoved value: -"marketCap" - changed
Input schema / properties / sortBy / descriptionPrevious value: -"Metric to sort by. revenueGrowth is accepted as an alias for revenueGrowthPct."New value: +"Metric to sort by. Custom default marketCap; presets use their disclosed sorting. revenueGrowth is accepted as an alias for revenueGrowthPct."
1 tool update
- Changed
get_etf_exposures1 field changed- added
Output schema / properties / notLoadedTypesAdded value: +{ + "items": { + "$ref": "#/properties/requestedTypes/items" + }, + "type": "array" +}
11 tool updates
- Changed
compare_company_exposures1 field changed- changed
Input schema / properties / tickers / descriptionPrevious value: -"Two to five distinct exact Bullrun listing tickers. Names and inferred exchange suffixes are not accepted."New value: +"Two to five distinct Bullrun listing tickers, e.g. AAPL, BMW or 6324.T. Bullrun tickers: US and most European listings use the plain local symbol (AAPL, BMW, NESN, ABBN); most Asian and Indian listings keep their exchange suffix (Tokyo 6324.T, Hong Kong 0700.HK, Shanghai 600519.SS, Shenzhen 000001.SZ, Taiwan 2330.TW, Korea 000100.KS, Singapore D05.SI, India RELIANCE.NS), but some Japanese and Korean large caps are plain codes (Toyota 7203, Samsung 005930). Either form is resolved automatically when exactly one listing matches; use search_stocks to find a ticker by company name or ISIN. Company names are not accepted here."
- Changed
compare_stocks1 field changed- changed
Input schema / properties / tickers / descriptionPrevious value: -"Two to five distinct exact Bullrun stock listing tickers, e.g. AAPL, BMW, NESN or 005930. No fuzzy company names or inferred ticker suffixes."New value: +"Two to five distinct Bullrun stock tickers, e.g. AAPL, BMW, NESN, 6324.T or 7203. Bullrun tickers: US and most European listings use the plain local symbol (AAPL, BMW, NESN, ABBN); most Asian and Indian listings keep their exchange suffix (Tokyo 6324.T, Hong Kong 0700.HK, Shanghai 600519.SS, Shenzhen 000001.SZ, Taiwan 2330.TW, Korea 000100.KS, Singapore D05.SI, India RELIANCE.NS), but some Japanese and Korean large caps are plain codes (Toyota 7203, Samsung 005930). Either form is resolved automatically when exactly one listing matches; use search_stocks to find a ticker by company name or ISIN. Company names are not accepted here."
- Changed
find_stock_peers1 field changed- changed
Input schema / properties / ticker / descriptionPrevious value: -"Exact native Bullrun equity ticker. Use search_stocks first for a company name, ISIN or Yahoo-format symbol."New value: +"Bullrun equity ticker, e.g. AAPL, BMW or 6324.T. Bullrun tickers: US and most European listings use the plain local symbol (AAPL, BMW, NESN, ABBN); most Asian and Indian listings keep their exchange suffix (Tokyo 6324.T, Hong Kong 0700.HK, Shanghai 600519.SS, Shenzhen 000001.SZ, Taiwan 2330.TW, Korea 000100.KS, Singapore D05.SI, India RELIANCE.NS), but some Japanese and Korean large caps are plain codes (Toyota 7203, Samsung 005930). Either form is resolved automatically when exactly one listing matches; use search_stocks to find a ticker by company name or ISIN."
- Changed
get_company_data_coverage1 field changed- changed
Input schema / properties / ticker / descriptionPrevious value: -"Exact native Bullrun company ticker, e.g. AAPL or SAP."New value: +"Bullrun company ticker, e.g. AAPL, SAP or 6324.T. Bullrun tickers: US and most European listings use the plain local symbol (AAPL, BMW, NESN, ABBN); most Asian and Indian listings keep their exchange suffix (Tokyo 6324.T, Hong Kong 0700.HK, Shanghai 600519.SS, Shenzhen 000001.SZ, Taiwan 2330.TW, Korea 000100.KS, Singapore D05.SI, India RELIANCE.NS), but some Japanese and Korean large caps are plain codes (Toyota 7203, Samsung 005930). Either form is resolved automatically when exactly one listing matches; use search_stocks to find a ticker by company name or ISIN."
- Changed
get_company_news1 field changed- changed
Input schema / properties / ticker / descriptionPrevious value: -"Exact native Bullrun company ticker, e.g. AAPL, SAP or ABBN. Resolve the symbol with search_stocks first if uncertain."New value: +"Bullrun company ticker, e.g. AAPL, SAP, ABBN or 6324.T. Bullrun tickers: US and most European listings use the plain local symbol (AAPL, BMW, NESN, ABBN); most Asian and Indian listings keep their exchange suffix (Tokyo 6324.T, Hong Kong 0700.HK, Shanghai 600519.SS, Shenzhen 000001.SZ, Taiwan 2330.TW, Korea 000100.KS, Singapore D05.SI, India RELIANCE.NS), but some Japanese and Korean large caps are plain codes (Toyota 7203, Samsung 005930). Either form is resolved automatically when exactly one listing matches; use search_stocks to find a ticker by company name or ISIN."
- Changed
get_company_risk_history1 field changed- changed
Input schema / properties / ticker / descriptionPrevious value: -"Exact native Bullrun company ticker, e.g. AAPL or SAP."New value: +"Bullrun company ticker, e.g. AAPL, SAP or 6324.T. Bullrun tickers: US and most European listings use the plain local symbol (AAPL, BMW, NESN, ABBN); most Asian and Indian listings keep their exchange suffix (Tokyo 6324.T, Hong Kong 0700.HK, Shanghai 600519.SS, Shenzhen 000001.SZ, Taiwan 2330.TW, Korea 000100.KS, Singapore D05.SI, India RELIANCE.NS), but some Japanese and Korean large caps are plain codes (Toyota 7203, Samsung 005930). Either form is resolved automatically when exactly one listing matches; use search_stocks to find a ticker by company name or ISIN."
- Changed
get_corporate_calendar1 field changed- changed
Input schema / properties / q / descriptionPrevious value: -"Optional case-insensitive ticker or company-name contains search, also matched with spaces removed. This is not an exact ticker filter. A nonblank search widens earnings/ex-dividend to 120 days and listings to 60 months. % and _ act as search wildcards."New value: +"Optional case-insensitive ticker or company-name contains search, also matched with spaces removed. This is not an exact ticker filter. A Yahoo-style symbol whose listing Bullrun stores in another form (BMW.DE as BMW, 7203.T as 7203) is searched under the stored ticker. A nonblank search widens earnings/ex-dividend to 120 days and listings to 60 months. % and _ act as search wildcards."
- Changed
get_earnings_call_transcript1 field changed- changed
Input schema / properties / ticker / descriptionPrevious value: -"The ticker exactly as listed on Bullrun, e.g. \"CRWD\", \"SPGI\", \"V\"."New value: +"Bullrun ticker, e.g. \"CRWD\", \"SPGI\", \"V\". Bullrun tickers: US and most European listings use the plain local symbol (AAPL, BMW, NESN, ABBN); most Asian and Indian listings keep their exchange suffix (Tokyo 6324.T, Hong Kong 0700.HK, Shanghai 600519.SS, Shenzhen 000001.SZ, Taiwan 2330.TW, Korea 000100.KS, Singapore D05.SI, India RELIANCE.NS), but some Japanese and Korean large caps are plain codes (Toyota 7203, Samsung 005930). Either form is resolved automatically when exactly one listing matches; use search_stocks to find a ticker by company name or ISIN."
- Changed
get_forward_estimates1 field changed- changed
Input schema / properties / ticker / descriptionPrevious value: -"The ticker exactly as listed on Bullrun, e.g. \"AAPL\", \"CRWD\", \"SPGI\"."New value: +"Bullrun ticker, e.g. \"AAPL\", \"CRWD\", \"SPGI\". Bullrun tickers: US and most European listings use the plain local symbol (AAPL, BMW, NESN, ABBN); most Asian and Indian listings keep their exchange suffix (Tokyo 6324.T, Hong Kong 0700.HK, Shanghai 600519.SS, Shenzhen 000001.SZ, Taiwan 2330.TW, Korea 000100.KS, Singapore D05.SI, India RELIANCE.NS), but some Japanese and Korean large caps are plain codes (Toyota 7203, Samsung 005930). Either form is resolved automatically when exactly one listing matches; use search_stocks to find a ticker by company name or ISIN."
- Changed
get_operating_kpis1 field changed- changed
Input schema / properties / ticker / descriptionPrevious value: -"The ticker exactly as listed on Bullrun, e.g. \"CRWD\", \"SNOW\", \"V\"."New value: +"Bullrun ticker, e.g. \"CRWD\", \"SNOW\", \"V\". Bullrun tickers: US and most European listings use the plain local symbol (AAPL, BMW, NESN, ABBN); most Asian and Indian listings keep their exchange suffix (Tokyo 6324.T, Hong Kong 0700.HK, Shanghai 600519.SS, Shenzhen 000001.SZ, Taiwan 2330.TW, Korea 000100.KS, Singapore D05.SI, India RELIANCE.NS), but some Japanese and Korean large caps are plain codes (Toyota 7203, Samsung 005930). Either form is resolved automatically when exactly one listing matches; use search_stocks to find a ticker by company name or ISIN."
- Changed
get_stock_price_history1 field changed- changed
Input schema / properties / ticker / descriptionPrevious value: -"Exact native Bullrun stock ticker, e.g. AAPL, SAP or ABBN; find it with search_stocks. Do not append Yahoo exchange suffixes."New value: +"Bullrun stock ticker, e.g. AAPL, SAP, ABBN, 6324.T or 7203. Bullrun tickers: US and most European listings use the plain local symbol (AAPL, BMW, NESN, ABBN); most Asian and Indian listings keep their exchange suffix (Tokyo 6324.T, Hong Kong 0700.HK, Shanghai 600519.SS, Shenzhen 000001.SZ, Taiwan 2330.TW, Korea 000100.KS, Singapore D05.SI, India RELIANCE.NS), but some Japanese and Korean large caps are plain codes (Toyota 7203, Samsung 005930). Either form is resolved automatically when exactly one listing matches; use search_stocks to find a ticker by company name or ISIN."
1 tool update
- Changed
get_operating_kpis1 field changed- changed
Input schema / properties / metricKey / descriptionPrevious value: -"Optional exact metric key to filter, e.g. ARR, NRR, RPO, BILLINGS, PAYMENT_VOLUME."New value: +"Optional metric key present in stored coverage. No particular business KPI is guaranteed to be available."
11 tool updates
- Changed
compare_etfs2 fields changed- changed
Input schema / properties / performanceDays / defaultPrevious value: -370New value: +365 - added
Input schema / properties / performanceDays / descriptionAdded value: +"Window in calendar days back from each fund's newest close; the start is the last close on or before that day. 365 matches the fund page and the screener's 1-year return."
- Changed
get_company_relationships1 field changed- changed
Input schema / properties / ticker / descriptionPrevious value: -"Exact Bullrun ticker, native local-exchange symbol (e.g. \"AAPL\", \"SAP\", \"ASML\"); no Yahoo-style suffixes."New value: +"Bullrun ticker, e.g. \"AAPL\", \"SAP\", \"ASML\". Bullrun tickers: US and most European listings use the plain local symbol (AAPL, BMW, NESN, ABBN); most Asian and Indian listings keep their exchange suffix (Tokyo 6324.T, Hong Kong 0700.HK, Shanghai 600519.SS, Shenzhen 000001.SZ, Taiwan 2330.TW, Korea 000100.KS, Singapore D05.SI, India RELIANCE.NS), but some Japanese and Korean large caps are plain codes (Toyota 7203, Samsung 005930). Either form is resolved automatically when exactly one listing matches; use search_stocks to find a ticker by company name or ISIN."
- Changed
get_company_risk1 field changed- changed
Input schema / properties / ticker / descriptionPrevious value: -"Exact Bullrun ticker, native local-exchange symbol (e.g. \"AAPL\", \"ASML\", \"NESN\", \"005930\"); no Yahoo-style suffixes."New value: +"Bullrun ticker, e.g. \"AAPL\", \"ASML\", \"NESN\", \"6324.T\" or \"0700.HK\". Bullrun tickers: US and most European listings use the plain local symbol (AAPL, BMW, NESN, ABBN); most Asian and Indian listings keep their exchange suffix (Tokyo 6324.T, Hong Kong 0700.HK, Shanghai 600519.SS, Shenzhen 000001.SZ, Taiwan 2330.TW, Korea 000100.KS, Singapore D05.SI, India RELIANCE.NS), but some Japanese and Korean large caps are plain codes (Toyota 7203, Samsung 005930). Either form is resolved automatically when exactly one listing matches; use search_stocks to find a ticker by company name or ISIN."
- Changed
get_etf_index_group2 fields changed- added
Input schema / properties / currencyAdded value: +{ + "description": "Keep only funds with a listing trading in this currency (e.g. CHF, EUR, USD, GBP) and name that line.", + "type": "string" +} - added
Input schema / properties / exchangeAdded value: +{ + "description": "Keep only funds listed on this venue and name each one's ticker there, e.g. SW (SIX Swiss Exchange), XETRA, LSE, AS, MI. A Swiss investor wanting the SIX line passes SW.", + "type": "string" +}
- Changed
get_financial_history1 field changed- changed
Input schema / properties / ticker / descriptionPrevious value: -"The ticker exactly as listed on Bullrun - the native local-exchange symbol, e.g. \"AAPL\", \"BMW\" (not \"BMW.DE\"), \"ABBN\" (not \"ABBN.SW\"), \"NESN\", or a numeric code like \"005930\". Do not append Yahoo-style country suffixes; if a lookup returns nothing, use screen_stocks to find the exact symbol."New value: +"The Bullrun ticker. Bullrun tickers: US and most European listings use the plain local symbol (AAPL, BMW, NESN, ABBN); most Asian and Indian listings keep their exchange suffix (Tokyo 6324.T, Hong Kong 0700.HK, Shanghai 600519.SS, Shenzhen 000001.SZ, Taiwan 2330.TW, Korea 000100.KS, Singapore D05.SI, India RELIANCE.NS), but some Japanese and Korean large caps are plain codes (Toyota 7203, Samsung 005930). Either form is resolved automatically when exactly one listing matches; use search_stocks to find a ticker by company name or ISIN."
- Changed
get_quality_moat_metrics1 field changed- changed
Input schema / properties / ticker / descriptionPrevious value: -"The ticker exactly as listed on Bullrun - the native local-exchange symbol, e.g. \"AAPL\", \"BMW\" (not \"BMW.DE\"), \"ABBN\" (not \"ABBN.SW\"), \"NESN\", or a numeric code like \"005930\". Do not append Yahoo-style country suffixes; if a lookup returns nothing, use screen_stocks to find the exact symbol."New value: +"The Bullrun ticker. Bullrun tickers: US and most European listings use the plain local symbol (AAPL, BMW, NESN, ABBN); most Asian and Indian listings keep their exchange suffix (Tokyo 6324.T, Hong Kong 0700.HK, Shanghai 600519.SS, Shenzhen 000001.SZ, Taiwan 2330.TW, Korea 000100.KS, Singapore D05.SI, India RELIANCE.NS), but some Japanese and Korean large caps are plain codes (Toyota 7203, Samsung 005930). Either form is resolved automatically when exactly one listing matches; use search_stocks to find a ticker by company name or ISIN."
- Changed
get_revenue_breakdown1 field changed- changed
Input schema / properties / ticker / descriptionPrevious value: -"The ticker exactly as listed on Bullrun, e.g. \"SPGI\", \"MSFT\", \"V\"."New value: +"The Bullrun ticker, e.g. \"SPGI\", \"MSFT\", \"V\". Bullrun tickers: US and most European listings use the plain local symbol (AAPL, BMW, NESN, ABBN); most Asian and Indian listings keep their exchange suffix (Tokyo 6324.T, Hong Kong 0700.HK, Shanghai 600519.SS, Shenzhen 000001.SZ, Taiwan 2330.TW, Korea 000100.KS, Singapore D05.SI, India RELIANCE.NS), but some Japanese and Korean large caps are plain codes (Toyota 7203, Samsung 005930). Either form is resolved automatically when exactly one listing matches; use search_stocks to find a ticker by company name or ISIN."
- Changed
get_risk_movers1 field changed- added
Input schema / properties / minMarketCapUsdAdded value: +{ + "description": "Only companies with at least this market capitalisation in USD, e.g. 1e9 for $1B+. Without it the list is dominated by micro-caps, whose scores move most.", + "minimum": 0, + "type": "number" +}
- Changed
get_stock_metrics1 field changed- changed
Input schema / properties / ticker / descriptionPrevious value: -"The stock ticker exactly as listed on Bullrun - the native local-exchange symbol, e.g. \"AAPL\", \"BMW\" (not \"BMW.DE\"), \"ABBN\" (not \"ABBN.SW\"), \"NESN\", or a numeric code like \"005930\". Do not append Yahoo-style country suffixes."New value: +"The stock ticker as Bullrun lists it, e.g. \"AAPL\", \"BMW\", \"NESN\", \"6324.T\", \"0700.HK\" or \"005930\". A bare numeric code is resolved when exactly one listing matches."
- Changed
get_valuation_model1 field changed- changed
Input schema / properties / tickers / descriptionPrevious value: -"1-10 exact Bullrun tickers (native local-exchange symbols, e.g. [\"AAPL\",\"MSFT\"] or [\"ASML\",\"SAP\",\"NESN\"])."New value: +"1-10 Bullrun tickers, e.g. [\"AAPL\",\"MSFT\"] or [\"ASML\",\"SAP\",\"NESN\"]. Bullrun tickers: US and most European listings use the plain local symbol (AAPL, BMW, NESN, ABBN); most Asian and Indian listings keep their exchange suffix (Tokyo 6324.T, Hong Kong 0700.HK, Shanghai 600519.SS, Shenzhen 000001.SZ, Taiwan 2330.TW, Korea 000100.KS, Singapore D05.SI, India RELIANCE.NS), but some Japanese and Korean large caps are plain codes (Toyota 7203, Samsung 005930). Either form is resolved automatically when exactly one listing matches; use search_stocks to find a ticker by company name or ISIN."
- Changed
screen_etfs1 field changed- changed
Input schema / properties / includeSecondary / descriptionPrevious value: -"Include secondary venue listings of the same fund. Default false — one row per fund's primary listing."New value: +"Return every venue listing as its own row. Default false: one row per FUND (by fund ISIN), showing its most liquid listing with the others under otherListings. Use exchange/currency to choose the venue, e.g. exchange \"SW\" for the SIX line."
5 tool updates
- Added
find_stock_peers - Added
get_company_news - Added
get_stock_price_history - Added
screen_stock_presets - Added
search_stocks
4 tool updates
- Added
compare_company_exposures - Added
get_company_data_coverage - Added
get_company_risk_history - Added
get_corporate_calendar
1 tool update
- Added
compare_stocks
14 tool updates
- Changed
analyze_etf_overlap2 fields changed- added
Output schema / properties / platformLinkAdded value: +{ + "additionalProperties": false, + "properties": { + "description": { + "type": "string" + }, + "label": { + "type": "string" + }, + "url": { + "format": "uri", + "type": "string" + } + }, + "required": [ + "label", + "url", + "description" + ], + "type": "object" +} - added
Output schema / properties / webPageAdded value: +{ + "format": "uri", + "type": "string" +}
- Changed
analyze_portfolio_fit2 fields changed- added
Output schema / properties / platformLinkAdded value: +{ + "additionalProperties": false, + "properties": { + "description": { + "type": "string" + }, + "label": { + "type": "string" + }, + "url": { + "format": "uri", + "type": "string" + } + }, + "required": [ + "label", + "url", + "description" + ], + "type": "object" +} - added
Output schema / properties / webPageAdded value: +{ + "format": "uri", + "type": "string" +}
- Changed
compare_etfs2 fields changed- added
Output schema / properties / platformLinkAdded value: +{ + "additionalProperties": false, + "properties": { + "description": { + "type": "string" + }, + "label": { + "type": "string" + }, + "url": { + "format": "uri", + "type": "string" + } + }, + "required": [ + "label", + "url", + "description" + ], + "type": "object" +} - added
Output schema / properties / webPageAdded value: +{ + "format": "uri", + "type": "string" +}
- Changed
get_etf_exposures2 fields changed- added
Output schema / properties / platformLinkAdded value: +{ + "additionalProperties": false, + "properties": { + "description": { + "type": "string" + }, + "label": { + "type": "string" + }, + "url": { + "format": "uri", + "type": "string" + } + }, + "required": [ + "label", + "url", + "description" + ], + "type": "object" +} - added
Output schema / properties / webPageAdded value: +{ + "format": "uri", + "type": "string" +}
- Changed
get_etf_filter_options2 fields changed- added
Output schema / properties / platformLinkAdded value: +{ + "additionalProperties": false, + "properties": { + "description": { + "type": "string" + }, + "label": { + "type": "string" + }, + "url": { + "format": "uri", + "type": "string" + } + }, + "required": [ + "label", + "url", + "description" + ], + "type": "object" +} - added
Output schema / properties / webPageAdded value: +{ + "format": "uri", + "type": "string" +}
- Changed
get_etf_fund2 fields changed- added
Output schema / properties / platformLinkAdded value: +{ + "additionalProperties": false, + "properties": { + "description": { + "type": "string" + }, + "label": { + "type": "string" + }, + "url": { + "format": "uri", + "type": "string" + } + }, + "required": [ + "label", + "url", + "description" + ], + "type": "object" +} - added
Output schema / properties / webPageAdded value: +{ + "format": "uri", + "type": "string" +}
- Changed
get_etf_holdings2 fields changed- added
Output schema / properties / platformLinkAdded value: +{ + "additionalProperties": false, + "properties": { + "description": { + "type": "string" + }, + "label": { + "type": "string" + }, + "url": { + "format": "uri", + "type": "string" + } + }, + "required": [ + "label", + "url", + "description" + ], + "type": "object" +} - added
Output schema / properties / webPageAdded value: +{ + "format": "uri", + "type": "string" +}
- Changed
get_etf_index_group2 fields changed- added
Output schema / properties / platformLinkAdded value: +{ + "additionalProperties": false, + "properties": { + "description": { + "type": "string" + }, + "label": { + "type": "string" + }, + "url": { + "format": "uri", + "type": "string" + } + }, + "required": [ + "label", + "url", + "description" + ], + "type": "object" +} - added
Output schema / properties / webPageAdded value: +{ + "format": "uri", + "type": "string" +}
- Changed
get_etf_risk2 fields changed- added
Output schema / properties / platformLinkAdded value: +{ + "additionalProperties": false, + "properties": { + "description": { + "type": "string" + }, + "label": { + "type": "string" + }, + "url": { + "format": "uri", + "type": "string" + } + }, + "required": [ + "label", + "url", + "description" + ], + "type": "object" +} - added
Output schema / properties / webPageAdded value: +{ + "format": "uri", + "type": "string" +}
- Changed
get_etf_snapshot2 fields changed- added
Output schema / properties / platformLinkAdded value: +{ + "additionalProperties": false, + "properties": { + "description": { + "type": "string" + }, + "label": { + "type": "string" + }, + "url": { + "format": "uri", + "type": "string" + } + }, + "required": [ + "label", + "url", + "description" + ], + "type": "object" +} - added
Output schema / properties / webPageAdded value: +{ + "format": "uri", + "type": "string" +}
- Changed
get_etf_timeseries2 fields changed- added
Output schema / properties / platformLinkAdded value: +{ + "additionalProperties": false, + "properties": { + "description": { + "type": "string" + }, + "label": { + "type": "string" + }, + "url": { + "format": "uri", + "type": "string" + } + }, + "required": [ + "label", + "url", + "description" + ], + "type": "object" +} - added
Output schema / properties / webPageAdded value: +{ + "format": "uri", + "type": "string" +}
- Changed
screen_etfs2 fields changed- added
Output schema / properties / platformLinkAdded value: +{ + "additionalProperties": false, + "properties": { + "description": { + "type": "string" + }, + "label": { + "type": "string" + }, + "url": { + "format": "uri", + "type": "string" + } + }, + "required": [ + "label", + "url", + "description" + ], + "type": "object" +} - added
Output schema / properties / webPageAdded value: +{ + "format": "uri", + "type": "string" +}
- Changed
search_etfs2 fields changed- added
Output schema / properties / platformLinkAdded value: +{ + "additionalProperties": false, + "properties": { + "description": { + "type": "string" + }, + "label": { + "type": "string" + }, + "url": { + "format": "uri", + "type": "string" + } + }, + "required": [ + "label", + "url", + "description" + ], + "type": "object" +} - added
Output schema / properties / webPageAdded value: +{ + "format": "uri", + "type": "string" +}
- Changed
simulate_etf_cost2 fields changed- added
Output schema / properties / platformLinkAdded value: +{ + "additionalProperties": false, + "properties": { + "description": { + "type": "string" + }, + "label": { + "type": "string" + }, + "url": { + "format": "uri", + "type": "string" + } + }, + "required": [ + "label", + "url", + "description" + ], + "type": "object" +} - added
Output schema / properties / webPageAdded value: +{ + "format": "uri", + "type": "string" +}
10 tool updates
- Added
get_company_relationships - Added
get_company_risk - Added
get_country_macro - Added
get_global_markets_overview - Added
get_macro_history - Added
get_macro_indicators - Added
get_risk_movers - Added
get_valuation_model - Added
screen_risk_board - Added
screen_valuation_model
Publisher details
- Operator
- Bullrun — Ferenc Kuntic · Publisher source
- Operator website
- https://bull-run.org · Publisher source
- Vendor relationship
- First-party · Publisher source
- Documentation
- https://github.com/ferinator/bullrun-mcp/blob/main/docs/mcp-connect.md · Publisher source
- Trust center
- Not available
- Restrictions
- Public research needs no account or API key. Free MCP use includes 700 successful tool calls per rolling 30 days, per free account or shared anonymous network. Failed tool calls do not count. Separate data-read safety limits and per-tool pacing can pause use earlier. Bullrun Pro costs CHF 5/month or CHF 50/year. Pro and active trials use a fair-use allowance of 1,000 market-data reads per rolling 5 hours instead of the free tool-call cap; one tool can use several reads. Subscribe at https://bull-run.org/pricing, then connect https://mcp.bull-run.org/account/mcp through OAuth to use your account's allowance. Website screening and manual research retain their existing free allowances. Your AI client's own availability, plan and usage charges are separate. · Publisher source
Related MCP Connectors
Research US-listed companies and funds with the StockPortfolio.pro MCP server. Tools cover SEC filing-grounded financials, filing timelines, company comparisons, watchlist screens, fund profiles, and cited filing questions. Filed figures include their fiscal period and EDGAR source URL; missing filing data is returned as null. Public tools work without authentication; optional API-key or OAuth access is supported. US-listed, USD-reporting companies only. Keyless access includes 3 free AI questions per rolling 30-day window. To get more now, choose the Dev plan ($19.99/month, 200 credits) at https://www.stockportfolio.pro/register?plan=dev, then follow https://www.stockportfolio.pro/docs/api-mcp to connect with OAuth or an API key. Or wait for the free allowance to renew.
SmartMoney77 MCP v0.6.0 — 14 public tools that turn financial questions into exact numbers and citable links. New: historical_investment_return and compare_investments, which compute "what if I had invested" results from real yearly price data. Also compound interest, FIRE number, credit-card payoff, emergency fund, inflation, latte factor, investment fees, cost of waiting, plus discovery/deep-link/share-pack tools for a catalog of calculators in 6 languages (he/en/ar/es/pt/in). Public, no login. Endpoint: https://smartmoney77.com/mcp
One MCP key: prices, fundamentals, SEC filings, insider/13F/congressional trades. 336 tools.
Real SEC, 13F, insider, congress & macro data your AI agent can cite. Hosted MCP, 24 tools.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceServes official, source-attributed financial statements, filings, insider trades, daily prices, screeners, macro series and portfolio backtests for Korean, US, Japanese, Taiwanese and European listed companies, so an AI client can compare peers, run trend and CAN SLIM screens, and trace every figure to its filing. Accessible over MCP from Claude, ChatGPT, Cursor or any client, plus a REST API with the same key and quota.MIT
- AlicenseNot gradedqualityAmaintenanceEnables AI assistants to access and analyze financial data, stock information, company fundamentals, and market insights through 250+ tools covering equities, ETFs, crypto, forex, commodities, economics, and more. Supports dynamic or static toolsets over HTTP/SSE for integration with MCP clients.601 npmApache 2.0
- AlicenseNot gradedqualityAmaintenanceEnables AI assistants to access and analyze financial data, stock information, company fundamentals, and market insights through a standardized MCP interface. It provides 250+ tools across categories such as financial statements, quotes, technical indicators, ETFs, crypto, forex, commodities, economics, and SEC filings.601 npmApache 2.0
- AlicenseNot gradedqualityAmaintenanceEnables AI assistants to access and analyze financial data, stock information, company fundamentals, and market insights through 250+ tools spanning stocks, ETFs, crypto, forex, commodities, and economics. Supports dynamic, static, or full toolset loading over HTTP/SSE for Claude and other MCP clients.601 npmApache 2.0
Glama MCP Gateway
Add one secure layer between your agents and this server.