Multi-tool MCP server suite for investment banking research including financial modeling, alternative data, web search, news aggregation, and paper trading. Excludes alpaca positions/orders, sentry queue, and excel local file operations from the remote homelab image.
Collection of 22 tools with mixed quality. Strengths: most tools have explicit schemas with typed parameters and clear verb-noun naming (get_*, read_*, write_*). Critical weaknesses: (1) Descriptions vary wildly in completeness, financial tools have 200-800+ char guidance with 'Should use/Should NOT use' patterns, while alt-data and Alpaca tools have minimal guidance (18-60 chars); (2) 5 tools (12, 18-22) have descriptions under 50 chars, failing the rubric baseline of 50+ for clarity; (3) No error handling documentation or recovery guidance in any tool; (4) Missing output schema documentation, tools return complex nested objects (market_data returns market_cap, enterprise_value, pe_ratio, shares_outstanding_basis with mismatch warnings) but agent doesn't know what fields to expect; (5) Tool composition issues, risk_check_proposed_trade and place_paper_order both accept identical large parameter sets, inviting duplication and confusion; (6) Alt-data tools (18-22) are extremely minimalist with single-line descriptions and no 'When to use' guidance. Average description length is ~180 chars, but distribution is bimodal: financial tools ~400-600 chars, others ~30-60 chars. Financial modeling tools follow the 'actionable description' pattern well; altdata and Excel tools do not.
Closes an open paper position by submitting an opposing market order (sell to flatten a long, buy to flatten a short). No Risk_Officer gate is applied — reducing exposure is always safe. `reason` is REQUIRED for the audit trail (e.g., 'stop_loss_hit', 'thesis_broken', 'profit_target', 'manual_override'). Returns {success: bool, side?: str, order_id?: str, error?: str}.
Returns the top institutional holders and mutual fund holders of a stock, plus aggregate institutional ownership statistics. Data sourced from Yahoo's aggregation of SEC 13F-HR filings (institutional holders, filed quarterly) and NPORT-P filings (mutual funds). Each holder row includes shares held, market value in USD, percent of shares outstanding, and quarter-over-quarter percent change in position size. Should use: When researching who owns the stock, to detect institutional buying/selling pressure (pct_change_qoq), to size up the 'smart money' bull/bear setup, or to find catalysts in institutional positioning. Critical for the Layer-5 capital-allocation read in the IB analyst playbook. Should NOT use: For company insider transactions (use get_insider_transactions instead — that covers officer/director Form 4 filings). For real-time positioning (this lags 45-90 days due to 13F reporting cadence).
Capital investment announcements via DuckDuckGo news
Federal contract awards via USASpending.gov (no auth)
Severely underdescribed alt-data tools (18-22). Descriptions 18-60 characters vs 194-char baseline. Missing 'When to use' / 'When NOT to use' guidance that distinguishes these from other data sources.
No output schema documentation for any tool. Agents do not know what fields are returned or how to chain results. E.g., get_market_data mentions 'shares_outstanding_basis' warning but schema is not documented; get_price_history returns complex nested windows (1M/3M/6M/YTD/1Y/3Y) but structure is opaque.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | C | 66 | 2026-07-28+ | v2 |
Match a current investment thesis against a curated catalog of historical market setups (1999 dot-com, 2007 housing, 2014 oil collapse, 2018 memory bust, 2020 cloud acceleration, 2024 AI capex cycle, etc.). Returns top N matches by structural-tag overlap plus each analogue's lessons. Use structural keywords in the thesis description (capex_cycle, capex_peak, capex_trough, valuation_expansion, valuation_compression, margin_compression, supply_constrained, supply_glut, concentrated_buyers, insider_selling, retail_frenzy, tech, energy, commodities, etc.) for cleaner matches. Should use: At the synthesis stage of deep research — once you have the data, ask 'what does this remind me of?' to surface historical lessons and avoid repeating prior cycle mistakes. Should NOT use: For ticker-specific predictions; this returns pattern-level analogues, not stock-level forecasts.
Map a research theme (e.g. 'AI semis', 'energy', 'cloud', 'uranium', 'biotech') to relevant ETFs and return their top holdings + weights. Acts as the bridge from top-down thematic conviction to bottom-up ticker selection — e.g. an AI/memory thesis surfaces SK Hynix (HBM) as AIQ's top holding, not just NVDA. Returns ETF AUM, top 10 holdings, sector weightings. Covers ~50 themes across tech, energy, financials, healthcare, geographic, and macro categories. Should use: As the FIRST step in thematic research — convert 'I think AI capex will accelerate' into a list of pure-play tickers via the ETF holdings. Should NOT use: For specific ticker lookup (use the ticker directly). For comp basket construction within a sector (use get_company_peers).
Multi-ATS job listing count (Greenhouse/Lever/Workday auto-discovery — no hardcoded company list)
Retrieves real-time market data for a company from Yahoo Finance including market cap, enterprise value, revenue, EBITDA, cash, debt, shares outstanding, beta, interest expense, and valuation multiples (P/E, P/B, EV/Revenue, EV/EBITDA, EV/EBIT). Should use: When you need current financial data for a company to perform valuation analysis, equity bridge calculations, or to get inputs for WACC calculation (beta, market cap, debt, interest expense). Should NOT use: When you need historical time-series data or SEC filing data (use SEC tools instead). Share basis: marketCap is stated across every share class and the provider's sharesOutstanding is stated for one of them, so the two do not multiply together for a multi-class filer -- GOOGL is 2.0845x apart and BRK-B 1.5204x. shares_outstanding_basis says which case this response is; use shares_outstanding_all_classes for anything divided by a share count (value per share, book per share, ownership percentages) and read the share_count_basis_mismatch warning when it is present. pe_ratio and pb_ratio divide marketCap and are unaffected.
Options-market signals derived from yfinance option chains. Returns: (1) ATM implied volatility term structure at ~7d/30d/60d/90d expirations, (2) 30d put/call skew (0.9*spot put IV minus 1.1*spot call IV; positive = downside fear premium), (3) nearest-expiry open interest and volume aggregates with put/call ratios. Should use: For forward-looking risk read (rising IV into earnings = market pricing surprise), sentiment positioning (volume ratio <0.5 = call-heavy/bullish, >1.0 = put-heavy/bearish), and skew (elevated put skew = institutional hedging). Should NOT use: As a primary valuation input — options are sentiment, not fundamentals. Returns a data_quality field — yfinance occasionally returns sentinel IV values (powers of 2) for stale snapshots; trust the volume ratios over IV in those cases.
Fetches the current paper-trading account summary from Alpaca: equity, cash, buying_power, portfolio_value, and account status. Numeric fields are coerced to float. On broker failure, returns {"error": str, "paper": true}. Use to confirm account is active and check available capital before proposing trades.
Returns open paper positions reconciled across two sources: the broker (Alpaca) and the local SQLite audit log. Response shape: {broker_positions: [...], local_positions: [...], reconciled: bool, discrepancies: [str]}. Discrepancies are tagged 'missing_locally:<TICKER>' (broker has it, DB doesn't) or 'missing_at_broker:<TICKER>' (DB has it, broker doesn't). Use to detect divergence — any unreconciled state needs audit before further trading.
Legislative climate via GovTrack (+ Congress.gov if key set)
Historical price summary: returns over 1M/3M/6M/YTD/1Y/3Y windows, realized volatility (annualized) over 30d/90d/180d/1Y, 52-week high/low with dates, max drawdown from trailing-12-month peak, and a configurable number of recent OHLCV bars. Source: yfinance auto-adjusted daily history. Should use: For drawdown framing ('stock down N% from peak'), volatility regime read (vol spike before earnings = expected surprise), and return decomposition over multiple windows. Should NOT use: For minute-level technical analysis (this returns daily bars). For intraday spot price use get_market_data. Price basis: every close is back-adjusted onto the newest session's basis for splits AND dividends, which the response now states in price_basis and quantifies in price_adjustment. A close from before a split is stated in post-split shares, so it pairs with get_share_count_series.total_split_adjusted and NOT with total -- NVDA's 2024-05-24 bar against the as-filed count is out by exactly 10.0x. prices_split_adjusted and prices_dividend_adjusted appear in warnings when the window contains either.
Short interest snapshot: shares short, days to cover (short ratio), percent of float, and month-over-month change. Source: yfinance (underlying FINRA biweekly disclosures). Includes a signal classifier (low/moderate/elevated/crowded short). Should use: For positioning context — crowded shorts on a stock with bull momentum signal squeeze risk; rising shorts on a name with deteriorating fundamentals confirm the bear case. Pair with get_insider_transactions to triangulate sentiment. Should NOT use: For intraday positioning — short interest reports lag 2 weeks. Days-to-cover is an estimate based on average volume, not a hard ceiling. Share basis: float_shares and shares_outstanding come from the provider on different share bases for a multi-class filer -- GOOGL's float exceeds its shares outstanding, so 1 - float/shares gives -85% insider ownership. shares_outstanding_basis says which case this is, shares_outstanding_all_classes is the count the float is comparable with, and float_exceeds_shares_outstanding / short_interest_exceeds_float appear in warnings when the two cannot be combined.
FinMind API for TSMC/Foxconn/MediaTek/ASE revenue data
Execution and position-sizing inputs from daily bars: relative volume (RVOL, the latest session's volume against its own trailing 20-session average), average dollar volume (ADV over 20 and 60 sessions, in USD and in shares), and average true range (ATR, Wilder-smoothed over 14 sessions, plus ATR as a percent of price). Source: the same yfinance daily bars as get_price_history. Should use: When deciding HOW to trade a name you have already researched -- how large a position the tape can absorb, how many days it takes to exit, how wide a stop has to be to survive ordinary daily noise, and whether today's volume is unusual enough to signal that something happened. Should NOT use: For any question about the business. These are tape mechanics and say nothing about revenue, margins, competitive position, or valuation. Do not reach for this during fundamental research -- it will not help and it is not evidence about the company. Notes: ADV is dollars because share counts do not tell you whether a position can be exited. ATR uses true range, so overnight gaps are included -- ATR will exceed the average high-minus-low on gappy names. Windows that the available history cannot fill are returned as null with a note, never as a shorter average. If the newest bar is the session currently in progress, latest_bar_is_partial_session is true: RVOL is then a live intraday read against full-session baselines and will understate, while ADV and ATR exclude the partial bar entirely.
Get basic information about a workbook
Health check for the Alpaca MCP server. Returns {"status": "pong"}. Use to verify server is reachable.
Places a paper order with MANDATORY internal Risk_Officer check. This tool calls risk_check_proposed_trade FIRST; if Risk_Officer rejects, the order is refused and the broker is never contacted. If Risk_Officer returns an adjusted_quantity (size cap), the broker is called with the smaller quantity. Returns {success: bool, order_id?: str, client_order_id?: str, qty: number, error?: str, risk_decision: {...}}. Always inspect risk_decision in the response for audit.
Read values from an Excel range
Evaluates a proposed paper trade against the deterministic Python Risk_Officer. Returns {approve: bool, reasons: [str], adjusted_quantity?: float, adjusted_dollar_size?: float}. This tool ONLY evaluates — it does NOT place the order. Use this before place_paper_order to pre-check whether Risk_Officer will allow the trade. If approve is False, do NOT call place_paper_order. If approve is True with adjusted_quantity set, use the adjusted quantity (smaller than requested) when calling place_paper_order.
Write values to an Excel range
No error handling or recovery guidance in any tool. What happens if a ticker does not exist? If Alpaca broker connection fails? If an API rate limit is hit? Descriptions do not specify error conditions or suggest next steps for LLM.
Duplicate parameter patterns in Alpaca trading tools. risk_check_proposed_trade and place_paper_order both accept identical 9-parameter sets (ticker, side, quantity, price, recommendation, confidence, bull_strength, bear_strength, position_sizing). This violates composition principle, should decompose into simpler, focused tools or clearly document when each is used.
Excel tools (read_range, write_range) do not validate file paths or ranges. No schema enforcement for 'range' parameter (e.g., 'A1:C10' format). Agents could pass invalid ranges and receive opaque errors.
Alpaca tools store sensitive data (order_id, client_order_id, positions) in responses without documenting if these should be logged or redacted. place_paper_order response includes risk_decision detail, unclear if LLM should echo this to user.
ping_alpaca tool serves no clear agent purpose, it returns {status: pong}, which is a health check. LLMs cannot act on this; should be internal monitoring only or removed entirely.