| name | carta-portfolio-query |
| description | Query cap table data across multiple companies, or fetch detailed per-company data (stakeholders, grants, SAFEs, 409A). Use for portfolio-wide analysis, comparing companies, finding patterns, or when detailed tabular data is needed beyond a visual summary. Do NOT use for market benchmark statistics or cap structure patterns โ use carta-market-benchmarks instead. Do NOT use for portfolio health alerts or red flags โ use carta-portfolio-alerts instead. |
| allowed-tools | ["mcp__carta__fetch","mcp__carta__list_contexts","mcp__carta__set_context","mcp__carta__list_accounts","mcp__carta__cap_table_chart","AskUserQuestion"] |
Portfolio Query
Fetch and present cap table data for a single company or across multiple companies.
Routing โ Visual Summary vs. Detailed Data
For single-company cap table overview/summary/snapshot requests, use the cap_table_chart MCP tool directly. It renders an interactive stacked bar chart in desktop clients (Cowork) or an ASCII chart in terminal clients (Claude Code).
cap_table_chart(corporation_id=<id>)
Route to cap_table_chart when the user asks for:
- Cap table overview, summary, or snapshot
- Ownership distribution or breakdown (visual)
- Share class breakdown or equity structure
- Fully diluted share counts or amount raised by share class
- Board deck equity overview
cap_table_chart also accepts as_of_date for point-in-time snapshots (see Point-in-time snapshots below).
After cap_table_chart renders, do NOT duplicate its content. The tool returns two things: a chart_data object rendered as an interactive stacked bar chart in MCP App clients (Claude Desktop, Cowork), and a _terminal_fallback ASCII string for terminal clients (Claude Code) where the interactive view can't render.
What you MUST NOT do in any client:
- Emit a markdown-style share class table (pipe-delimited headers with alignment rows) on top of the chart. This is the core duplication regression โ in MCP App clients, the user sees the chart AND a redundant table stacked underneath; in terminal, it competes with the ASCII fallback. Just don't.
- Restate summary numbers the chart already shows (total outstanding, total FD, total raised) as bullet points or highlighted bold lines.
- Render stakeholder or option-pool tables in text โ those are for the fallback/detailed path below, not when you've routed to the chart.
What terminal clients DO need: either the tool's _terminal_fallback surfaced verbatim, or a brief ASCII bar chart of equivalent shape. Pick one, once. Don't do both.
Your text response alongside cap_table_chart should be 2โ3 sentences of commentary highlighting something notable โ e.g. unusually large option pool, concentrated ownership, zero-outstanding classes โ plus an optional single-sentence next-step offer. In MCP App clients that's the whole response. In terminal clients, prefix it with the one ASCII rendering.
Stay in this skill (use fetch below) when:
- Multi-company queries or portfolio-wide comparisons
- Detailed stakeholder listings or specific holder data
- Specific data points (409A, SAFEs, grants, convertible notes)
- The user explicitly asks for tables or raw numbers
When to Use
- "Show me cap tables for all my portfolio companies"
- "Which companies have SAFEs outstanding?"
- "Compare option pool sizes across my portfolio"
- "Show me detailed grant data for Acme Corp"
Prerequisites
- Single company: resolve
corporation_id from list_accounts
- Multi-company: loop all
corporation_pk accounts from list_accounts
Data Retrieval
Portfolio Enumeration
Call list_accounts to get all accessible entities. Filter to corporation_pk: accounts. Extract up to 20 numeric corporation IDs. If more than 20 companies, ask the user to narrow scope.
Per-Company Commands
Call the relevant command for each company depending on the query:
Command Reference
| Data | Command |
|---|
| 409A valuations | fetch("cap_table:get:409a_valuations", {"corporation_id": corporation_id}) |
| SAFEs & convertible notes | fetch("cap_table:get:convertible_notes", {"corporation_id": corporation_id}) |
| Cap table by share class | fetch("cap_table:get:cap_table_by_share_class", {"corporation_id": corporation_id}) |
| Option grants | fetch("cap_table:list:grants", {"corporation_id": corporation_id}) |
| RSU grants | fetch("cap_table:list:rsus", {"corporation_id": corporation_id}) |
| SAR grants | fetch("cap_table:list:sars", {"corporation_id": corporation_id}) |
| CBU grants | fetch("cap_table:list:cbus", {"corporation_id": corporation_id}) |
| Search grants by name | fetch("cap_table:list:grants", {"corporation_id": corporation_id, "detail": "full", "search": "Jane Doe"}) |
| Top N holders by shares | fetch("cap_table:list:rsus", {"corporation_id": corporation_id, "ordering": "-quantity", "page_size": "20"}) |
Detail mode: The gateway now defaults all list commands to detail=summary automatically. You do not need to pass "detail": "summary" or "summary": "true" โ summary mode is the default. Summary returns aggregate data (count, totals, type/status breakdowns) and is orders of magnitude faster for companies with 1,000+ grants. For individual grant-level records (e.g. searching by name, paginating through results), pass "detail": "full" with "page_size": "25". See the "Search grants by name" row above for an example.
Ordering & top-N queries: Grant/RSU/SAR/CBU list commands support server-side ordering. Use -quantity for descending (top holders), quantity for ascending. Combine with page_size to get only the top N records without fetching everything. Always use ordering+page_size for "top N" or "largest" queries โ never fetch all records and sort client-side, especially for companies with 1,000+ grants. Available ordering fields: quantity, remaining_shares, exercised_shares, issue_date, stakeholder_name, grant_number.
Point-in-time snapshots
cap_table:get:cap_table_by_share_class, cap_table:get:cap_table_by_stakeholder, and the cap_table_chart tool accept an optional as_of_date param. When provided, they return the cap table as of that date instead of live data. Pass ISO (YYYY-MM-DD) or MM/DD/YYYY:
fetch("cap_table:get:cap_table_by_share_class", {"corporation_id": corporation_id, "as_of_date": "2026-03-31"})
cap_table_chart(corporation_id=<id>, as_of_date="2026-03-31")
Use as_of_date whenever the user's question is anchored to a specific date ("as of Q1 close", "on 3/31", "at fiscal year end"). If the user doesn't specify a date, omit the param โ the API defaults to today.
Limitations: future dates are accepted only for companies enrolled in future-dated cap tables; dates before incorporation are rejected. Other cap-table commands (grants, SAFEs, convertibles, 409A, rounds) do not yet support as_of_date โ live data only for those.
Single-Company Detailed View
When the user needs detailed tabular data beyond the visual summary (e.g. stakeholder-level holdings, specific share counts), fetch both views:
fetch("cap_table:get:cap_table_by_share_class", {"corporation_id": corporation_id})
fetch("cap_table:get:cap_table_by_stakeholder", {"corporation_id": corporation_id, "detail": "full"})
Key Fields
From list_accounts:
id: format corporation_pk:<id> โ extract the number for company-level commands
accountType: "company" accounts work with all commands; "portfolio" and "investment firm" are organizations, not companies
name: company display name
Workflow
Step 1 โ Get Accounts
Call list_accounts to get all accessible entities.
Step 2 โ Filter Accounts
Filter to the relevant account type (company, fund, investment firm, law firm, portfolio). Extract corporation_id from each account's id field (strip the corporation_pk: or organization_pk: prefix).
Step 3 โ Fetch Data (parallel)
Issue ALL fetch calls for ALL companies in a single response โ do NOT loop company-by-company. The fetch tool has readOnlyHint=true, so parallel calls execute concurrently.
For example, to compare option pools across 5 companies, issue all 5 fetch calls at once:
fetch("cap_table:get:cap_table_by_share_class", {"corporation_id": 1})
fetch("cap_table:get:cap_table_by_share_class", {"corporation_id": 2})
fetch("cap_table:get:cap_table_by_share_class", {"corporation_id": 3})
... (all companies)
Step 4 โ Aggregate and Present
Aggregate and present the results.
Single-Company Presentation
DO NOT use this section if you called cap_table_chart. The MCP App tool renders its own visual (interactive in desktop clients, ASCII _terminal_fallback in terminal clients) โ your job is then limited to 2โ3 sentences of commentary, per the Routing section above. Re-rendering tables and bar charts on top of the chart tool's output produces duplicate, clashing content in the user's view.
Use this section only when:
- The user explicitly asked for detailed raw numbers / tables / specific share counts that the chart doesn't expose, OR
cap_table_chart is unavailable in the current client (rare โ the tool provides its own terminal fallback), OR
- The request is multi-company (per-company chart calls are too noisy; a cross-company table is clearer).
In those cases only, present in this order:
- Summary line: total outstanding shares, total fully diluted shares, total cash raised
- Share class table: share class name, outstanding shares, outstanding %, FD shares, FD %, cash raised
- Option pool: authorized vs issued/outstanding, available shares and %
- Top stakeholders table: name, outstanding shares, outstanding %, FD %, cash raised
- ASCII bar chart (fallback only โ
cap_table_chart already renders a better one when called)
ASCII bar chart recipe (fallback only):
- Collect each stakeholder's fully diluted % (or outstanding % if FD not available)
- Find the max value โ that stakeholder gets 40 โ blocks
- All others:
bar_width = round(pct / max_pct * 40), minimum 1 block
- Left-align labels in a fixed-width column (pad to the longest label length + 2 spaces)
- Immediately after the label padding, place the โ blocks โ no spaces between label and blocks
- After the blocks, one space then the percentage
Example:
Ownership (Fully Diluted)
Option Pool โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ 71.8%
Lead Investor โโโโโโโโ 7.8%
Founder A โโโโ 4.0%
Founder B โโโโ 3.9%
Other Investor โโโ 2.6%
Others โโโโ 9.9%
Example: Find Expiring 409As
1. list_accounts โ get all corporation_pk accounts
2. Issue ALL fetch calls in a single response (parallel):
fetch("cap_table:get:409a_valuations", {"corporation_id": 1})
fetch("cap_table:get:409a_valuations", {"corporation_id": 2})
... (all companies at once)
3. For each result, check if the most recent expiration_date is within 90 days of today
4. Present:
| Company | Current FMV | Effective | Expires | Days Left |
|---|
| Acme Corp | $12.61 | Apr 25, 2024 | Apr 24, 2025 | 37 |
| Beta Inc | $5.00 | Jan 15, 2024 | Jan 14, 2025 | EXPIRED |
Example: Portfolio Option Pool Health
1. list_accounts โ get all corporation_pk accounts
2. Issue ALL fetch calls in a single response (parallel):
fetch("cap_table:get:cap_table_by_share_class", {"corporation_id": 1})
fetch("cap_table:get:cap_table_by_share_class", {"corporation_id": 2})
... (all companies at once)
3. Extract option plan available_ownership percentage
4. Flag companies with available pool < 5%
Gates
Required inputs: None โ portfolio enumeration is automatic.
AI computation: Yes โ cross-company comparisons, red flag detection, and health assessments are AI-derived when querying multiple companies.
Trigger the AI computation gate (see carta-interaction-reference ยง6.2) before outputting any cross-company analysis or health assessments.
Subagent prohibition: Not applicable.
Presentation
Format: Tables with company names; single-company queries include an ASCII bar chart (see Workflow).
BLUF lead: For single-company: lead with total outstanding shares, fully diluted count, and total cash raised. For multi-company: lead with count summary ("3 of 12 companies need attention").
Sort order: Multi-company results sorted by urgency/severity (most critical first). Single-company tables sorted by FD % descending.
Date format: MMM d, yyyy (e.g. "Jan 15, 2026").
- Always show company name alongside the data
- Group results: "needs attention" vs "healthy"
- Include a count summary: "3 of 12 companies need attention"
Caveats
- Portfolio data reflects separate API calls per company, not a single atomic snapshot. Even with
as_of_date, each company's fetch is independent โ state can diverge if data changes mid-loop.
- Companies with restricted permissions may have incomplete data
- Rate limit: maximum 20 companies per invocation โ don't call 50+ companies at once; ask the user to narrow down if the list is large
- Only
corporation_pk accounts work with company-level commands (cap table, grants, SAFEs, valuations). organization_pk accounts are portfolios/firms.
- Some companies may return errors (permissions, setup state) โ skip them gracefully and note which ones failed