WhereItGoes
Server Details
Read-only access to your own crypto portfolio across 11+ exchanges and 20+ chains: holdings, full history, FIFO cost basis and P&L, fees and income. Ask Claude or ChatGPT about your portfolio; the connector can never trade, move funds or act as a login.
- Status
- Healthy
- OAuth
- Works in Glama
- Last Tested
- Transport
- Streamable HTTP · MCP 2025-11-25
- URL
- Repository
- khapham7165/whereitgoes-mcp
- GitHub Stars
- 0
- Server Listing
- WhereItGoes MCP server
TDQS
Scored across 15 tools
Most tools have clearly distinct analytical purposes, and the descriptions explicitly cross-reference when to use one versus another. However, portfolio health/risk scoring appears in both get_portfolio overview and get_risk score, and several analytics tools (get_changes, get_performance, get_movements) require careful reading to avoid selecting the wrong lens.
All tool names use a clear snake_case verb_noun pattern: get_* and list_* for reads, propose_* and set_* for changes. The few verb choices reflect intentional semantics rather than inconsistent style.
At 15 tools, the surface is well-scoped for a broad crypto portfolio analytics server. The use of multi-view tools (portfolio, performance, risk, money flows) consolidates many related operations without bloating the count.
The server covers a wide read surface and includes proposal workflows for alerts and target allocation. Minor gaps remain around adding/removing exchange or wallet connections and managing profiles, which are documented as app-side but still limit end-to-end agent workflows.
Available Tools
15 toolsget_alertsConfigured price and value alertsARead-onlyIdempotentInspect
List the alerts the user has set up: for each, its kind (asset_price, asset_pct, portfolio_value, portfolio_pct, holding_value, holding_weight), subject, above or below threshold, a readable label, whether it is enabled, once or recurring, delivery channels, cooldown and when it last fired. An account with none returns an empty list. This is the configuration, not a notification inbox. Use for "what alerts do I have set", "did my BTC alert fire", and before propose_alert_change, whose update and delete take the id from here. To create, edit or delete an alert use propose_alert_change. For current prices use get_portfolio.
| Name | Required | Description | Default |
|---|---|---|---|
| profile | No | Which portfolio to read, for accounts with more than one: its id, or its name (exact, case-insensitive, e.g. "Trading"). Omit to read this connection's default portfolio; every answer names the portfolio it read in `profile`. An unknown or shared name returns profile_not_found or profile_ambiguous listing the real ones, and list_profiles shows them up front. |
Output Schema
| Name | Required | Description |
|---|---|---|
| error | No | Present ONLY when the call was refused instead of answered: upgrade_required (Pro plan needed), not_found, profile_not_found, profile_ambiguous, invalid_arguments, write_not_permitted. No data fields come with it; read `message` to the user rather than retrying the same call. |
| alerts | No | |
| message | No | Plain-language explanation that accompanies `error` or a proposed change. |
| profile | No | The portfolio these figures belong to (absent on list_profiles). |
| source_url | No | Link to the page in the WhereItGoes app that shows this data. |
| upgrade_url | No | Where the user can upgrade, on an upgrade_required refusal. |
| stock_assets | No | Present when the answer mentions Binance Stocks shares (EQ_<ticker>): they are US stocks, not crypto. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent, non-destructive, closed-world, so the safety profile is covered. The description adds genuine behavioral context beyond that: empty list for accounts with no alerts, and the config-vs-notification distinction that prevents misuse. The field enumeration is partly redundant with the output schema, keeping it from a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action, then use cases, then alternatives — a logical order with no filler. The single field-enumeration sentence is long and slightly heavy, but each clause (kinds, threshold direction, channels, cooldown) 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?
With a rich output schema and read-only annotations, the description covers what an agent still needs: what the data represents, when to reach for it, and which siblings handle the mutations. The only gap is that it never mentions multi-portfolio scoping, leaving that entirely to the 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 schema fully explains the single `profile` parameter, including error modes and defaults, so the baseline of 3 applies. The description says nothing about profile selection or that answers are scoped to one portfolio, adding no meaning beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("List the alerts the user has set up") and immediately enumerates the returned fields and alert kinds. It also draws an explicit boundary — "This is the configuration, not a notification inbox" — which separates it from any notification-style sibling.
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 concrete query phrasings it answers ("what alerts do I have set", "did my BTC alert fire") plus a sequencing rule: use it before propose_alert_change, which consumes the `id` from here. It also routes create/edit/delete to propose_alert_change and current prices to get_portfolio, so alternatives are explicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_changesWhat changed: ranked notable eventsARead-onlyIdempotentInspect
Detect what changed over period and rank it, most significant first: the biggest USD flows, allocation shifts, drawdowns, newly seen sources and reconciliation to-dos, each USD-valued, with countsByType counting everything detected before the list was capped. Built for short windows such as last_7d or last_30d; omitting period scans all time. Use for "what changed", "anything unusual", "notable moves this week". It reports events, not totals: for profit over the same period use get_performance, for money in and out use get_money_flows.
| Name | Required | Description | Default |
|---|---|---|---|
| period | No | Time window ending now: last_24h, last_7d, last_30d, last_90d, ytd (since 1 January UTC) or all. Omit for all time. | |
| profile | No | Which portfolio to read, for accounts with more than one: its id, or its name (exact, case-insensitive, e.g. "Trading"). Omit to read this connection's default portfolio; every answer names the portfolio it read in `profile`. An unknown or shared name returns profile_not_found or profile_ambiguous listing the real ones, and list_profiles shows them up front. |
Output Schema
| Name | Required | Description |
|---|---|---|
| error | No | Present ONLY when the call was refused instead of answered: upgrade_required (Pro plan needed), not_found, profile_not_found, profile_ambiguous, invalid_arguments, write_not_permitted. No data fields come with it; read `message` to the user rather than retrying the same call. |
| notes | No | |
| events | No | Ranked, most significant first. |
| window | No | The time window these figures cover. |
| message | No | Plain-language explanation that accompanies `error` or a proposed change. |
| profile | No | The portfolio these figures belong to (absent on list_profiles). |
| truncated | No | Present only when a list was longer than the 200-row cap and was cut: list field name -> {total, kept, keep, from, to}. A `<field>_note` string beside that list says the same in words. Never present a cut list as complete. |
| source_url | No | Link to the page in the WhereItGoes app that shows this data. |
| events_note | No | Present only when `events` was cut; says how many rows were kept and which. |
| upgrade_url | No | Where the user can upgrade, on an upgrade_required refusal. |
| countsByType | No | Events detected per type before the list was capped. |
| stock_assets | No | Present when the answer mentions Binance Stocks shares (EQ_<ticker>): they are US stocks, not crypto. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive), and the description adds real behavioral detail beyond them: results are ranked most-significant-first, the list is capped while `countsByType` counts everything detected before the cap, and every item is USD-valued. That cap-vs-count distinction is exactly the kind of nuance 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?
The action and ranking behavior are front-loaded in the first clause, followed by window guidance and then sibling routing. Three dense sentences with no filler; each carries distinct information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers what is detected, how it is ordered, what the cap does to the list versus the counts, and where to go for totals — with an output schema available to carry return shapes. An agent has everything needed to call this correctly and interpret the response.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the enum documents every window, so the schema already does the heavy lifting. The description still adds choice guidance the schema lacks — that short windows are the intended use and that omitting `period` scans all time — though it says nothing about the `profile` parameter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb+resource ("Detect what changed over `period` and rank it") and enumerates the event classes it returns (USD flows, allocation shifts, drawdowns, new sources, reconciliation to-dos). It explicitly marks itself as an event reporter, not a totals tool, so an agent can distinguish it from get_performance and get_money_flows 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 explicit positive triggers ("what changed", "anything unusual", "notable moves this week") plus a window recommendation ("Built for short windows such as last_7d or last_30d"). It also names the alternatives and the condition that selects them: get_performance for profit, get_money_flows for money in and out.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_connectionsConnected exchanges, tracked wallets and sync statusARead-onlyIdempotentInspect
List where the portfolio's data comes from, in one of three views. exchanges: every exchange and data source the app supports, with configured true on the ones the user connected (count only those) and a masked key hint, never the key. wallets: the watch-only on-chain addresses tracked, with label, wallet family, chains scanned and whether enabled, plus the EVM chains this app can read (balanceOnly where history is unavailable). sync_status: whether a sync of this portfolio is running or queued right now, and its queue position. No view takes a window. They hold no balances (get_portfolio holdings carry a per-venue split), do not test live connectivity, and cannot start a sync, which runs automatically and from the WhereItGoes app; for when the last sync finished use get_portfolio (recent_change, lastSyncAt). Use for "which exchanges am I connected to", "is my Base address tracked", "is it still syncing".
| Name | Required | Description | Default |
|---|---|---|---|
| view | Yes | Which view to read: exchanges (supported and connected exchanges); wallets (tracked on-chain addresses); sync_status (is a sync running or queued now). Each view takes only the arguments the description lists for it. | |
| profile | No | Which portfolio to read, for accounts with more than one: its id, or its name (exact, case-insensitive, e.g. "Trading"). Omit to read this connection's default portfolio; every answer names the portfolio it read in `profile`. An unknown or shared name returns profile_not_found or profile_ambiguous listing the real ones, and list_profiles shows them up front. |
Output Schema
| Name | Required | Description |
|---|---|---|
| view | No | Which view answered; its data is under the key of the same name. |
| error | No | Present ONLY when the call was refused instead of answered: upgrade_required (Pro plan needed), not_found, profile_not_found, profile_ambiguous, invalid_arguments, write_not_permitted. No data fields come with it; read `message` to the user rather than retrying the same call. |
| message | No | Plain-language explanation that accompanies `error` or a proposed change. |
| profile | No | The portfolio these figures belong to (absent on list_profiles). |
| wallets | No | Present when view = "wallets". |
| exchanges | No | Present when view = "exchanges". |
| source_url | No | Link to the page in the WhereItGoes app that shows this data. |
| sync_status | No | Present when view = "sync_status". |
| upgrade_url | No | Where the user can upgrade, on an upgrade_required refusal. |
| stock_assets | No | Present when the answer mentions Binance Stocks shares (EQ_<ticker>): they are US stocks, not crypto. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the read-only/idempotent annotations, the description discloses important behavioral details: exchanges returns only configured=true connections and a masked key hint, never the key; wallets includes balanceOnly where history is unavailable; sync_status reports running/queued state and queue position; and syncs run automatically outside this tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is dense but front-loaded: purpose, view details, exclusions, sibling routing, and use-case examples appear in a logical order. Every sentence carries actionable information for selecting or invoking 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?
An output schema exists, so return-value details need not be repeated. The description covers all three views, the absence of windowing, the absence of balances, sync limitations, and sibling alternatives, leaving no important usage 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 coverage is 100%, so the view enum and profile parameter are already well documented. The description adds meaningful semantics to each view beyond the schema, such as configured flags, masked key hints, wallet family/chains, and balanceOnly behavior, though it does not add much to the profile parameter 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?
The description opens with a specific verb and resource: 'List where the portfolio's data comes from, in one of three views.' It immediately names and distinguishes the three views, and clearly separates the tool from get_portfolio by noting that these views hold no balances.
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 usage scenarios ('which exchanges am I connected to', 'is my Base address tracked', 'is it still syncing') and explicit exclusions: no window, no balances, no live connectivity test, no starting a sync. It also routes the agent to get_portfolio for last-sync timestamps.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_feesFees paid, by venue, asset and typeARead-onlyIdempotentInspect
Total the fees paid over period (omit for all time), each valued in USD on the day it was paid: trading, on-chain gas, withdrawal and fiat-spread fees, as totalUsd plus breakdowns by venue (with the effective trading-fee rate in basis points), by asset and by type, each largest first, and a series per bucket (month by default, or day or week), oldest first. Use for "what am I paying in fees", "which exchange costs me the most". Coverage is partial by nature (gas on EVM token transfers and contract calls, some chains, and swap slippage are not tracked), and partial plus notes say what was left out. For fees as one line of overall profit use get_performance; for single fee-bearing events use get_movements.
| Name | Required | Description | Default |
|---|---|---|---|
| bucket | No | Granularity of the fee series. Defaults to month. | |
| period | No | Time window ending now: last_24h, last_7d, last_30d, last_90d, ytd (since 1 January UTC) or all. Omit for all time. | |
| profile | No | Which portfolio to read, for accounts with more than one: its id, or its name (exact, case-insensitive, e.g. "Trading"). Omit to read this connection's default portfolio; every answer names the portfolio it read in `profile`. An unknown or shared name returns profile_not_found or profile_ambiguous listing the real ones, and list_profiles shows them up front. |
Output Schema
| Name | Required | Description |
|---|---|---|
| error | No | Present ONLY when the call was refused instead of answered: upgrade_required (Pro plan needed), not_found, profile_not_found, profile_ambiguous, invalid_arguments, write_not_permitted. No data fields come with it; read `message` to the user rather than retrying the same call. |
| notes | No | What the coverage leaves out. |
| bucket | No | |
| byType | No | Largest first. |
| points | No | Oldest bucket first. |
| window | No | The time window these figures cover. |
| byAsset | No | Largest first. |
| byVenue | No | Largest first. |
| message | No | Plain-language explanation that accompanies `error` or a proposed change. |
| partial | No | true when some fees could not be valued or are not tracked. |
| profile | No | The portfolio these figures belong to (absent on list_profiles). |
| feeCount | No | Fee-bearing events counted. |
| totalUsd | No | All fees in the window, USD, each valued on the day paid. |
| avgFeeUsd | No | |
| truncated | No | Present only when a list was longer than the 200-row cap and was cut: list field name -> {total, kept, keep, from, to}. A `<field>_note` string beside that list says the same in words. Never present a cut list as complete. |
| source_url | No | Link to the page in the WhereItGoes app that shows this data. |
| points_note | No | Present only when `points` was cut; says how many rows were kept and which. |
| upgrade_url | No | Where the user can upgrade, on an upgrade_required refusal. |
| stock_assets | No | Present when the answer mentions Binance Stocks shares (EQ_<ticker>): they are US stocks, not crypto. |
| unpricedAssets | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations, the description adds crucial behavioral context, such as the partial coverage of the data (e.g., slippage not tracked), the precise valuation method (USD on the day it was paid), and the aggregation rules (largest first, oldest first).
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 appropriately dense for the tool's complexity. It follows a logical structure: definition -> calculation -> output details -> limitations -> alternatives, ensuring every sentence delivers essential 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?
Given the complexity of multi-metric fee aggregation across different chains/assets, the description is remarkably complete. It addresses limitations, output formatting (bucket structure), and data accuracy constraints, leaving the agent with minimal need to seek external documentation.
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?
While the schema coverage is 100%, the description adds significant semantic value by defining the scope of the fee calculation, detailing the inclusion of the 'effective trading-fee rate in basis points,' and explaining the time constraints of the period parameter ('Omit for all time').
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 purpose is exceptionally clear, specifying that the tool totals various fee types (trading, gas, withdrawal, fiat-spread) and outlines the resulting breakdown (venue, asset, type) and valuation (USD on the day paid). It clearly distinguishes its function from 'get_performance' and 'get_movements'.
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 guidance is provided using direct user-facing questions ('what am I paying in fees,' 'which exchange costs me the most'). It also explicitly routes the agent to `get_performance` and `get_movements` for specific, alternative financial queries.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_incomeIncome received: staking, lending, rewards, airdropsARead-onlyIdempotentInspect
Total the income the portfolio received (yield, staking, lending, rewards, airdrops) over period (omit for all time), each payment valued in USD on the day it arrived, in one of two views. by_category: totals per category (staking, lending, defi, rewards, airdrop, other), topSources largest first, and a monthly series. by_asset: per bucket (week by default, or day or month), oldest first, the USD each asset paid, with topAssets largest first; bucket applies to this view only and by_category refuses it. Futures P&L is excluded because it is a trading result, and unpricedAssets lists what could not be valued. A series longer than 200 buckets keeps the most recent 200 and says so in truncated, so use week or month for long periods. Use for "how much did staking pay me this year", "which coin has paid me the most". For the individual payments use get_movements with kind INCOME; for income as one line of overall profit use get_performance.
| Name | Required | Description | Default |
|---|---|---|---|
| view | Yes | Which view to read: by_category (totals per income category); by_asset (series of income per asset). Each view takes only the arguments the description lists for it. | |
| bucket | No | by_asset only. Granularity of the series. Defaults to week. | |
| period | No | Time window ending now: last_24h, last_7d, last_30d, last_90d, ytd (since 1 January UTC) or all. Omit for all time. | |
| profile | No | Which portfolio to read, for accounts with more than one: its id, or its name (exact, case-insensitive, e.g. "Trading"). Omit to read this connection's default portfolio; every answer names the portfolio it read in `profile`. An unknown or shared name returns profile_not_found or profile_ambiguous listing the real ones, and list_profiles shows them up front. |
Output Schema
| Name | Required | Description |
|---|---|---|
| view | No | Which view answered; its data is under the key of the same name. |
| error | No | Present ONLY when the call was refused instead of answered: upgrade_required (Pro plan needed), not_found, profile_not_found, profile_ambiguous, invalid_arguments, write_not_permitted. No data fields come with it; read `message` to the user rather than retrying the same call. |
| message | No | Plain-language explanation that accompanies `error` or a proposed change. |
| profile | No | The portfolio these figures belong to (absent on list_profiles). |
| by_asset | No | Present when view = "by_asset". |
| source_url | No | Link to the page in the WhereItGoes app that shows this data. |
| by_category | No | Present when view = "by_category". |
| upgrade_url | No | Where the user can upgrade, on an upgrade_required refusal. |
| stock_assets | No | Present when the answer mentions Binance Stocks shares (EQ_<ticker>): they are US stocks, not crypto. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
It discloses several key operational behaviors not in the schema: the valuation method (USD on arrival), the exclusion of Futures P&L, and the truncation rule (keeping the 200 most recent buckets and flagging them). This is highly valuable 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 necessarily long due to the tool's complexity, but it is perfectly structured. It starts with a definition, moves through operational details, handles exclusions, and finishes with specific use cases and sibling routing, making maximum use of the space.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the complexity of the two distinct calculation modes and the time-series constraints (truncation/period options), the description is highly complete. It provides all necessary information for an agent to choose the right parameters and invoke the tool safely and accurately.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Although the schema coverage is 100%, the description adds critical semantic constraints. For example, it explains that `bucket` is only applicable to the `by_asset` view, clarifying which parameters are conditional based on the choice of `view`.
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 explicitly defines the resource (portfolio income) and the scope of that income (yield, staking, lending, rewards, airdrops). It clearly articulates the difference between the two main views—category-based vs. asset-based—distinguishing its purpose well.
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 specific, actionable use cases ('how much did staking pay me this year') and, critically, routes the user to the correct sibling tools (`get_movements`, `get_performance`) based on their specific need, leaving zero ambiguity about alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_money_flowsMoney in and out: USD flows, deposits, transfers, fiatARead-onlyIdempotentInspect
Summarise money entering and leaving the portfolio, in one of four views. capital_flow: deposits and withdrawals per bucket (month by default, or week) over period (omit for all time), in USD split by asset and valued on the day they moved, oldest bucket first; moves between the user's own accounts, Earn shuffles and cancelled withdrawals are excluded, so this is capital genuinely entering or leaving. deposits: exchange deposits, newest first, with what is settled about each one's cost basis (manual_cost, transfer_id when matched to the user's own withdrawal, reconciliation classification); exchange deposits only, spam hidden. transfers: withdrawals matched to the deposit that landed on another of the user's own accounts, most recently matched first, both legs in full. fiat: per local fiat currency (e.g. VND, KRW), all-time fiat spent buying crypto and received selling it, net invested and volume-weighted rates, in that currency, not USD. period and bucket apply to capital_flow only; other views refuse them. Lists return at most 200 rows. Use for "how much did I deposit each month", "which deposits need a cost basis", "did my BTC arrive in my wallet". For single events in native units use get_movements.
| Name | Required | Description | Default |
|---|---|---|---|
| view | Yes | Which view to read: capital_flow (USD deposited and withdrawn per bucket); deposits (exchange deposits and their cost-basis status); transfers (matched moves between own accounts); fiat (fiat in and out per local currency). Each view takes only the arguments the description lists for it. | |
| bucket | No | capital_flow only. Granularity of the series. Defaults to month. | |
| period | No | Time window ending now: last_24h, last_7d, last_30d, last_90d, ytd (since 1 January UTC) or all. Omit for all time. | |
| profile | No | Which portfolio to read, for accounts with more than one: its id, or its name (exact, case-insensitive, e.g. "Trading"). Omit to read this connection's default portfolio; every answer names the portfolio it read in `profile`. An unknown or shared name returns profile_not_found or profile_ambiguous listing the real ones, and list_profiles shows them up front. |
Output Schema
| Name | Required | Description |
|---|---|---|
| fiat | No | Present when view = "fiat". |
| view | No | Which view answered; its data is under the key of the same name. |
| error | No | Present ONLY when the call was refused instead of answered: upgrade_required (Pro plan needed), not_found, profile_not_found, profile_ambiguous, invalid_arguments, write_not_permitted. No data fields come with it; read `message` to the user rather than retrying the same call. |
| message | No | Plain-language explanation that accompanies `error` or a proposed change. |
| profile | No | The portfolio these figures belong to (absent on list_profiles). |
| deposits | No | Present when view = "deposits". |
| transfers | No | Present when view = "transfers". |
| source_url | No | Link to the page in the WhereItGoes app that shows this data. |
| upgrade_url | No | Where the user can upgrade, on an upgrade_required refusal. |
| capital_flow | No | Present when view = "capital_flow". |
| stock_assets | No | Present when the answer mentions Binance Stocks shares (EQ_<ticker>): they are US stocks, not crypto. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive), so the bar is lower, yet the description adds substantial behavioral context: exclusions (own-account moves, Earn shuffles, cancelled withdrawals), spam hiding in deposits, the 200-row list cap, and refusal behavior for inapplicable parameters. It also notes capital_flow values assets on the day they moved and orders oldest bucket first, which the annotations cannot convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded and each view gets a compact clause with no filler. The definition is long and delivered as one dense run-on paragraph, which makes scanning harder than it needs to be; a little structure (or a break between view descriptions and usage examples) would help, but 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?
An output schema exists, so return values need not be explained, yet the description still conveys what each view returns (settled cost basis, reconciliation classification, both legs of matched transfers, volume-weighted rates). Combined with the 200-row limit, exclusion rules, and view-specific parameter constraints, an agent has everything needed to invoke 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 itself documents the enum values, but the description adds cross-parameter semantics the schema only partially captures: period and bucket apply to capital_flow only and other views refuse them, bucket defaults to month, period may be omitted for all time, and fiat is reported in local currency rather than USD. It does not, however, add much detail about the profile parameter beyond what the schema already says.
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 ('Summarise money entering and leaving the portfolio') and then enumerates all four views with the exact content of each (capital_flow deposits/withdrawals per bucket in USD, deposits with cost-basis status, matched transfers, fiat per local currency). It explicitly distinguishes itself from the sibling get_movements for single events in native units, so an agent can route correctly 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 example questions that map to specific views ('how much did I deposit each month', 'which deposits need a cost basis', 'did my BTC arrive in my wallet'), and names the alternative tool (get_movements) with the condition that selects it. It also states which parameters each view accepts and that other views refuse them, which is precisely the guidance needed to pick a view.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_movementsSearch the money-movement ledgerARead-onlyIdempotentInspect
Search the raw money-movement ledger, newest first: deposits, withdrawals, internal transfers, income and trades, each with venue, source, status, its amount in NATIVE token units and value_usd (its USD value on the day; null if unpriced). Filters combine with AND: kind picks the event type; asset, venue and source take comma-separated lists; status must be copied from countsByStatus (venue-native, case-sensitive); q is a substring search over asset, transaction id, status and address fragments; period bounds the time (omit for all time). limit (default 100, max 200) caps the rows returned while total still counts every match; there is no paging, so narrow the filters to reach older rows. The countsBySource / countsByVenue / countsByStatus facets list the filter values this account actually has. Use to find individual events, e.g. "my BTC withdrawals from Binance this year". For dollar totals of money in and out use get_money_flows; for income totals use get_income.
| Name | Required | Description | Default |
|---|---|---|---|
| q | No | Case-insensitive substring search over asset, transaction id, status and stored details such as an address fragment. | |
| kind | No | INFLOW = deposit, OUTFLOW = withdrawal, TRANSFER = between the user's own accounts, INCOME = yield, staking or airdrop, TRADE = a buy or sell. Omit for every kind. | |
| asset | No | Asset ticker, e.g. "BTC"; comma-separate for several ("BTC,ETH"). Case-insensitive. | |
| limit | No | How many of the newest matching rows to return, 1-200. Defaults to 100. | |
| venue | No | Venue name as it appears in countsByVenue, e.g. "binance"; comma-separate for several. | |
| period | No | Time window ending now: last_24h, last_7d, last_30d, last_90d, ytd (since 1 January UTC) or all. Omit for all time. | |
| source | No | Source label as it appears in countsBySource, e.g. "deposit" or "staking"; comma-separate for several. | |
| status | No | Status exactly as it appears in countsByStatus, e.g. "SUCCESS" or "2". | |
| profile | No | Which portfolio to read, for accounts with more than one: its id, or its name (exact, case-insensitive, e.g. "Trading"). Omit to read this connection's default portfolio; every answer names the portfolio it read in `profile`. An unknown or shared name returns profile_not_found or profile_ambiguous listing the real ones, and list_profiles shows them up front. |
Output Schema
| Name | Required | Description |
|---|---|---|
| error | No | Present ONLY when the call was refused instead of answered: upgrade_required (Pro plan needed), not_found, profile_not_found, profile_ambiguous, invalid_arguments, write_not_permitted. No data fields come with it; read `message` to the user rather than retrying the same call. |
| items | No | Newest first, at most `limit` rows. |
| total | No | Every row matching the filters, before `limit`. |
| message | No | Plain-language explanation that accompanies `error` or a proposed change. |
| profile | No | The portfolio these figures belong to (absent on list_profiles). |
| truncated | No | Present only when a list was longer than the 200-row cap and was cut: list field name -> {total, kept, keep, from, to}. A `<field>_note` string beside that list says the same in words. Never present a cut list as complete. |
| hiddenSpam | No | Rows hidden because they were marked spam. |
| items_note | No | Present only when `items` was cut; says how many rows were kept and which. |
| source_url | No | Link to the page in the WhereItGoes app that shows this data. |
| upgrade_url | No | Where the user can upgrade, on an upgrade_required refusal. |
| stock_assets | No | Present when the answer mentions Binance Stocks shares (EQ_<ticker>): they are US stocks, not crypto. |
| countsByVenue | No | |
| countsBySource | No | |
| countsByStatus | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark this as a safe read-only, idempotent tool, but the description adds substantive behavior: newest-first ordering, limit caps returned rows while total counts all matches, no paging, status must come from countsByStatus, omitted period means all time, and value_usd may be null when unpriced. These are operationally important constraints that are not conveyed by annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but appropriately dense for a nine-parameter query tool. It front-loads purpose, return shape, filter semantics, paging limitation, facet guidance, and sibling alternatives 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 an output schema, full schema descriptions, and annotations covering safety, the description supplies the missing operational context: paging behavior, facet-derived filter values, native vs USD amounts, and when to prefer aggregate siblings. Nothing an agent needs to invoke this tool correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, but the description still adds cross-parameter meaning beyond the schema: filters combine with AND, asset/venue/source accept comma-separated lists, q searches over asset, transaction id, status and address fragments, period bounds time, and limit has no paging workaround. It also directs the agent to use countsByStatus and facet counts for valid filter values.
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: "Search the raw money-movement ledger". It enumerates the event types returned and explicitly distinguishes this tool from get_money_flows and get_income, so an agent can select it without opening sibling 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?
It gives an explicit use case ("find individual events, e.g. my BTC withdrawals from Binance this year") and names the alternatives for aggregate queries: get_money_flows for dollar totals and get_income for income totals. It also explains that filters must be narrowed because there is no paging.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_performanceProfit and loss, daily value history, results per pairARead-onlyIdempotentInspect
Measure how the portfolio performed, in one of three views. pnl: TRUE profit and loss over period with the user's own deposits and withdrawals stripped out: realized vs unrealized, net flows, income, fees, top gainers and losers, and a plain-English explanation. history: the daily series over period, oldest first: total value, net capital in, cost basis and cash in and out per UTC day. realized_by_pair: all-time realized FIFO profit ranked by trading pair, best first. Arguments apply per view, and a call that sets one its view does not take is refused: period (pnl, history; omit for all time); slim (history: true drops the per-asset breakdown, recommended unless composition is needed); limit and quote (realized_by_pair: the limit best AND limit worst pairs quoted in quote, defaults 20 and USDT, never summed across quote currencies). All values are USD end-of-day marks, not live quotes: never report pnl.endValue as the current value (get_portfolio has it). A history longer than 200 days is sampled evenly, always keeping the first and the latest day, and says so in truncated; pick a shorter period for every day. For buy and sell totals use get_trading_activity; for single trades use get_movements.
| Name | Required | Description | Default |
|---|---|---|---|
| slim | No | history only. true returns the daily totals alone; false or omitted adds a USD value and a quantity for every asset on every day. | |
| view | Yes | Which view to read: pnl (true profit and loss over period); history (daily value series over period); realized_by_pair (all-time realized profit per trading pair). Each view takes only the arguments the description lists for it. | |
| limit | No | realized_by_pair only. How many best AND how many worst pairs to return, 1-100; up to twice this many rows come back. Defaults to 20. | |
| quote | No | realized_by_pair only. Quote currency whose pairs to rank, e.g. "USDT" for BTCUSDT. Defaults to USDT. | |
| period | No | Time window ending now: last_24h, last_7d, last_30d, last_90d, ytd (since 1 January UTC) or all. Omit for all time. | |
| profile | No | Which portfolio to read, for accounts with more than one: its id, or its name (exact, case-insensitive, e.g. "Trading"). Omit to read this connection's default portfolio; every answer names the portfolio it read in `profile`. An unknown or shared name returns profile_not_found or profile_ambiguous listing the real ones, and list_profiles shows them up front. |
Output Schema
| Name | Required | Description |
|---|---|---|
| pnl | No | Present when view = "pnl". |
| view | No | Which view answered; its data is under the key of the same name. |
| error | No | Present ONLY when the call was refused instead of answered: upgrade_required (Pro plan needed), not_found, profile_not_found, profile_ambiguous, invalid_arguments, write_not_permitted. No data fields come with it; read `message` to the user rather than retrying the same call. |
| history | No | Present when view = "history". |
| message | No | Plain-language explanation that accompanies `error` or a proposed change. |
| profile | No | The portfolio these figures belong to (absent on list_profiles). |
| source_url | No | Link to the page in the WhereItGoes app that shows this data. |
| upgrade_url | No | Where the user can upgrade, on an upgrade_required refusal. |
| stock_assets | No | Present when the answer mentions Binance Stocks shares (EQ_<ticker>): they are US stocks, not crypto. |
| realized_by_pair | No | Present when view = "realized_by_pair". |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations already establish a safe read-only, idempotent profile, but the description adds substantial behavioral context beyond them: values are USD end-of-day marks rather than live quotes, pnl.endValue must not be reported as current value, calls with arguments not accepted by the chosen view are refused, and history over 200 days is evenly sampled with first and latest day kept and a `truncated` flag set. Those are exactly the traits an agent needs to avoid misreporting 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 three views are front-loaded before the per-view argument rules and caveats, and essentially every sentence carries operational information. It is dense and long-sentenced, but the density is justified by the six parameters and three modes; little could be removed without losing a constraint.
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, three-mode read tool this is complete: it covers view selection, per-view arguments, truncation/sampling behavior, end-of-day valuation semantics, profile targeting, and redirection to sibling tools, while the existing output schema handles return shape. An agent has everything needed to call 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?
With 100% schema coverage the baseline is 3; the description goes further by stating cross-parameter rules the schema cannot express: arguments apply per view, mismatched arguments are refused, `period` omitted means all time, `slim` is recommended unless composition is needed, and `limit` returns that many best AND worst pairs that are 'never summed across quote currencies'. These constraints add real meaning beyond the per-field 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?
Opens with a specific verb and resource ('Measure how the portfolio performed') and enumerates the three distinct views with their exact contents (realized vs unrealized, daily series, all-time FIFO per pair). It explicitly routes away from siblings get_portfolio, get_trading_activity, and get_movements, so an agent can select it 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?
Names the condition that selects each view and which arguments apply to each, states that invalid argument/view combinations are refused, and gives explicit alternatives for adjacent needs ('for buy and sell totals use get_trading_activity; for single trades use get_movements'). It even states which tool holds the current value (get_portfolio), leaving nothing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_portfolioPortfolio overview, holdings and recent changeARead-onlyIdempotentInspect
Read the portfolio as it stands now, in one of three views. overview: a whole-portfolio summary (live total value, allocation by asset, class, venue and chain, concentration, stablecoin and self-custody shares, 30-day true P&L, drift from the target allocation, what BTC and ETH did, and on a Pro plan risk, a 0-100 health score and ranked findings, which a free plan gets empty and named in gated); start here for open questions such as "how am I doing". holdings: every asset held with quantity, USD price and value, weight, 24h change, FIFO average cost, unrealized and realized P&L and a per-venue split, largest first, plus totalUsdt; use for "what do I hold", "my net worth". recent_change: 24h, 7d and 30d change in % and USD, lifetime net capital and cash in and out, and lastSyncAt. No view takes a window: holdings come from the last computed snapshot (asOf), recent_change is null until daily history exists, and overview's P&L is an end-of-day 30-day figure. For profit over another period use get_performance; for drawdown and volatility use get_risk. The answer is nested under the key named after the view.
| Name | Required | Description | Default |
|---|---|---|---|
| view | Yes | Which view to read: overview (whole-portfolio summary, start here); holdings (every asset held, largest first); recent_change (24h, 7d and 30d change and last sync). Each view takes only the arguments the description lists for it. | |
| profile | No | Which portfolio to read, for accounts with more than one: its id, or its name (exact, case-insensitive, e.g. "Trading"). Omit to read this connection's default portfolio; every answer names the portfolio it read in `profile`. An unknown or shared name returns profile_not_found or profile_ambiguous listing the real ones, and list_profiles shows them up front. |
Output Schema
| Name | Required | Description |
|---|---|---|
| view | No | Which view answered; its data is under the key of the same name. |
| error | No | Present ONLY when the call was refused instead of answered: upgrade_required (Pro plan needed), not_found, profile_not_found, profile_ambiguous, invalid_arguments, write_not_permitted. No data fields come with it; read `message` to the user rather than retrying the same call. |
| message | No | Plain-language explanation that accompanies `error` or a proposed change. |
| profile | No | The portfolio these figures belong to (absent on list_profiles). |
| holdings | No | Present when view = "holdings". |
| overview | No | Present when view = "overview". |
| source_url | No | Link to the page in the WhereItGoes app that shows this data. |
| upgrade_url | No | Where the user can upgrade, on an upgrade_required refusal. |
| stock_assets | No | Present when the answer mentions Binance Stocks shares (EQ_<ticker>): they are US stocks, not crypto. |
| recent_change | No | Present when view = "recent_change". |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive), and the description still adds non-obvious behavior: no view accepts a time window, holdings come from the last computed snapshot with `asOf`, recent_change is null until daily history exists, overview P&L is an end-of-day 30-day figure, and Pro-only fields come back empty and named in `gated`. That gating disclosure is exactly the kind of context 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 core action and the three views in an explicit label-colon structure, which scans well. The overview enumeration is a very long comma chain and the opening is one dense multi-clause sentence, but almost every clause carries decision-relevant information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-param tool with full schema coverage, annotations, and an output schema, the description covers everything the schema cannot: which view to pick for which question, what data window backs each view, null-timing caveats, plan gating, and which siblings handle other time periods and risk. Nothing material is left to 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 100%, so baseline is 3; the description goes further by defining what each `view` value actually returns and noting that the response is nested under a key named after the view. It does not elaborate on `profile` beyond what the schema already says, which keeps it just above baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("Read the portfolio as it stands now") and immediately enumerates the three views with concrete contents for each. Sibling tools are named explicitly, so an agent can tell this apart from get_performance and get_risk 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 the entry point ("start here for open questions such as 'how am I doing'"), per-view triggers ("use for 'what do I hold', 'my net worth'"), and explicit routing to alternatives ("For profit over another period use get_performance; for drawdown and volatility use get_risk"). When-not guidance is implied by the alternative routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_riskRisk metrics and portfolio health score (Pro)ARead-onlyIdempotentInspect
Assess portfolio risk, in one of two views; both need a Pro plan, and a free account gets an upgrade_required answer, not an error. metrics: measured risk over period (omit for full history): max drawdown in % and USD with peak and trough days, annualized volatility and return, Sharpe, and return, beta and correlation against benchmark (BTC by default, or ETH). Drawdown is flow-honest, so a withdrawal is not counted as a loss, and a metric is null when the window holds too few daily returns. score: a 0-100 structural health rating with a band (resilient, solid, fragile, concentrated), pillar sub-scores (diversification, custody, liquidity, quality, volatility, hygiene, target drift) and what moved since the last reading; it scores structure, never returns, over a fixed 30 days, so it takes no period or benchmark and refuses them. A pillar that cannot be measured yet is listed in excluded, not scored zero. Use metrics for "what was my worst drawdown", "do I just track bitcoin"; score for "how healthy is my portfolio". For profit use get_performance.
| Name | Required | Description | Default |
|---|---|---|---|
| view | Yes | Which view to read: metrics (drawdown, volatility, Sharpe, beta over period); score (0-100 health score, fixed 30 days). Each view takes only the arguments the description lists for it. | |
| period | No | Time window ending now: last_24h, last_7d, last_30d, last_90d, ytd (since 1 January UTC) or all. Omit for all time. | |
| profile | No | Which portfolio to read, for accounts with more than one: its id, or its name (exact, case-insensitive, e.g. "Trading"). Omit to read this connection's default portfolio; every answer names the portfolio it read in `profile`. An unknown or shared name returns profile_not_found or profile_ambiguous listing the real ones, and list_profiles shows them up front. | |
| benchmark | No | metrics only. Asset to measure beta, correlation and excess return against. Defaults to BTC. |
Output Schema
| Name | Required | Description |
|---|---|---|
| view | No | Which view answered; its data is under the key of the same name. |
| error | No | Present ONLY when the call was refused instead of answered: upgrade_required (Pro plan needed), not_found, profile_not_found, profile_ambiguous, invalid_arguments, write_not_permitted. No data fields come with it; read `message` to the user rather than retrying the same call. |
| score | No | Present when view = "score". |
| message | No | Plain-language explanation that accompanies `error` or a proposed change. |
| metrics | No | Present when view = "metrics". |
| profile | No | The portfolio these figures belong to (absent on list_profiles). |
| source_url | No | Link to the page in the WhereItGoes app that shows this data. |
| upgrade_url | No | Where the user can upgrade, on an upgrade_required refusal. |
| stock_assets | No | Present when the answer mentions Binance Stocks shares (EQ_<ticker>): they are US stocks, not crypto. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish it as a safe read, and the description goes well beyond: Pro-plan gating returns upgrade_required rather than an error, drawdown is flow-honest to withdrawals, metrics are null when the window has too few returns, the score uses a fixed 30 days and never scores returns, and unmeasurable pillars land in `excluded` instead of zero. These are exactly the behavioral facts an agent needs to interpret output correctly.
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 purpose, plan gating and the view split, then example phrasings and the sibling redirect - good ordering with no filler. Minor flaw: the phrase "annualized volatility and return, Sharpe, and return, beta" duplicates "return" and slightly muddies the metric list.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 4-param tool with an output schema, the description covers everything the structured fields don't: plan gating, view arg-compatibility, null/exclusion semantics, and the fixed 30-day window. Return shapes are left to the output schema, which is correct, and nothing needed to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is already 100%, but the description adds cross-parameter semantics the schema cannot: omitting `period` means full history, `benchmark` defaults to BTC, and the two params are valid only under `view=metrics`. That per-view applicability is real added value beyond the enum lists.
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 ("Assess portfolio risk") and immediately splits into two named views with their exact contents (drawdown/volatility/Sharpe/beta vs 0-100 structural score with pillars). It also explicitly routes away from get_performance, so an agent can distinguish it from the nearest sibling 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 concrete selection criteria: metrics for "what was my worst drawdown" / "do I just track bitcoin", score for "how healthy is my portfolio". Adds a hard routing rule ("For profit use get_performance") and states when args are refused (score refuses period/benchmark).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_target_allocationTarget allocation planARead-onlyIdempotentInspect
Read the user's target allocation: the plan they MEANT to hold, as set.rows of {subject, targetPct, bandPct} largest first, or set: null if they never set one. set.dim names the axis: "asset" means each subject is a ticker (BTC), "sector" means each is one of our sector names (Layer 1, DeFi, Stablecoins). bandPct is the tolerance in percentage POINTS, so a 40% target with a 5-point band is on plan anywhere from 35% to 45%. Use for "what is my target allocation", "what was my plan", and before set_target_allocation so an edit starts from the real plan. This is the INTENTION only: for what they actually hold against it, read the drift in get_portfolio (overview), which scores the two together.
| Name | Required | Description | Default |
|---|---|---|---|
| profile | No | Which portfolio to read, for accounts with more than one: its id, or its name (exact, case-insensitive, e.g. "Trading"). Omit to read this connection's default portfolio; every answer names the portfolio it read in `profile`. An unknown or shared name returns profile_not_found or profile_ambiguous listing the real ones, and list_profiles shows them up front. |
Output Schema
| Name | Required | Description |
|---|---|---|
| set | No | null when no target allocation is set. |
| error | No | Present ONLY when the call was refused instead of answered: upgrade_required (Pro plan needed), not_found, profile_not_found, profile_ambiguous, invalid_arguments, write_not_permitted. No data fields come with it; read `message` to the user rather than retrying the same call. |
| message | No | Plain-language explanation that accompanies `error` or a proposed change. |
| profile | No | The portfolio these figures belong to (absent on list_profiles). |
| source_url | No | Link to the page in the WhereItGoes app that shows this data. |
| upgrade_url | No | Where the user can upgrade, on an upgrade_required refusal. |
| stock_assets | No | Present when the answer mentions Binance Stocks shares (EQ_<ticker>): they are US stocks, not crypto. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare the safe read-only, idempotent profile, but the description adds important behavior beyond them: it defines the returned `set.rows` shape, explains that `set: null` means no plan was ever set, and clarifies that bandPct is expressed in percentage points rather than percent. Those details materially affect how an agent interprets the 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 description is front-loaded with the core definition, then layers output shape, dimension semantics, band semantics, and usage routing in a compact sequence. Despite its length, every sentence adds operational meaning 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?
Although an output schema exists, the description preemptively explains the semantically important return values (`set.rows`, `set: null`, `set.dim`, and `bandPct`) that an agent would otherwise have to infer. Combined with its read-only annotations and complete parameter schema, nothing needed to call or interpret this tool 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?
There is only one parameter, `profile`, and its schema description is already complete, covering name, id, default behavior, and error cases. The tool description adds no further guidance about the parameter itself, so the baseline of 3 is appropriate given full schema 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?
The description states a precise verb and resource: reading the user's target allocation, defined as the intended plan rather than actual holdings. It explicitly distinguishes this from get_portfolio drift and from set_target_allocation, so an agent can select it without opening sibling 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?
It names concrete triggering questions such as "what is my target allocation" and "what was my plan", and says to call it before set_target_allocation so edits start from the real plan. It also routes actual-holdings comparison to get_portfolio, giving both when-to-use and an explicit alternative.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_trading_activityLifetime trade totals per asset and daily activity calendarARead-onlyIdempotentInspect
Read trading activity over the whole history (no window), in one of two views. asset_totals: for every asset traded, one row per asset and quote currency with quantity bought and sold, amount spent and received in that quote, trade count and first and last trade time, largest buy volume first; these are raw sums, not profit, and there is no asset filter, so pick the row you need. calendar: per UTC day with any activity, counts of trades, deposits, withdrawals and income events, trade volume in USD and realized and unrealized P&L, oldest first, plus all-time totals and the active years; past 200 active days the most recent 200 are kept and truncated says so, while totals always cover everything. Use for "how much ETH have I bought in total", "my busiest days". For realized profit per pair use get_performance; for the individual trades use get_movements with kind TRADE.
| Name | Required | Description | Default |
|---|---|---|---|
| view | Yes | Which view to read: asset_totals (lifetime buy and sell sums per asset); calendar (per-day activity counts and P&L). Each view takes only the arguments the description lists for it. | |
| profile | No | Which portfolio to read, for accounts with more than one: its id, or its name (exact, case-insensitive, e.g. "Trading"). Omit to read this connection's default portfolio; every answer names the portfolio it read in `profile`. An unknown or shared name returns profile_not_found or profile_ambiguous listing the real ones, and list_profiles shows them up front. |
Output Schema
| Name | Required | Description |
|---|---|---|
| view | No | Which view answered; its data is under the key of the same name. |
| error | No | Present ONLY when the call was refused instead of answered: upgrade_required (Pro plan needed), not_found, profile_not_found, profile_ambiguous, invalid_arguments, write_not_permitted. No data fields come with it; read `message` to the user rather than retrying the same call. |
| message | No | Plain-language explanation that accompanies `error` or a proposed change. |
| profile | No | The portfolio these figures belong to (absent on list_profiles). |
| calendar | No | Present when view = "calendar". |
| source_url | No | Link to the page in the WhereItGoes app that shows this data. |
| upgrade_url | No | Where the user can upgrade, on an upgrade_required refusal. |
| asset_totals | No | Present when view = "asset_totals". |
| stock_assets | No | Present when the answer mentions Binance Stocks shares (EQ_<ticker>): they are US stocks, not crypto. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare read-only, idempotent, non-destructive behavior, but the description adds substantial context: sums are raw not profit, there is no asset filter, ordering differs per view, the calendar is UTC-based, and past 200 active days results are truncated while totals remain complete. This is rich behavioral disclosure beyond the annotations, though it doesn't mention pagination or auth needs.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Despite covering two views, return columns, ordering, truncation, and alternatives, the description is dense and front-loaded with the view names as clear anchors. Every sentence carries operational information with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-view read tool with an output schema, the description covers everything an agent needs to choose a view and understand its scope: what rows appear, what ordering applies, what the truncation caveat means, and where totals come from. Nothing material is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description meaningfully elaborates the view parameter beyond the schema's one-line summaries—detailing the columns, ordering, truncation flag, and totals behavior for each view. This added meaning directly helps an agent choose and interpret the view parameter.
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 trading activity over the whole history') and immediately enumerates the two views it offers. It explicitly distinguishes itself from siblings by naming get_performance for realized profit per pair and get_movements with kind TRADE for individual trades.
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 example queries ('how much ETH have I bought in total', 'my busiest days') and names the alternative tools with the exact conditions that select them. The choice between views is framed by what each view answers, leaving no inference needed.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_profilesPortfolios on this accountARead-onlyIdempotentInspect
List the portfolios on this account (id, name, and how many exchanges and wallets each holds), plus which one is active in the app. Call this FIRST when the user names a portfolio ("what is in my trading account") so you can pass its name or id as the profile argument of another tool. Takes no arguments; an account with one portfolio needs none of this, because every tool reads the connection's default portfolio when profile is omitted.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| error | No | Present ONLY when the call was refused instead of answered: upgrade_required (Pro plan needed), not_found, profile_not_found, profile_ambiguous, invalid_arguments, write_not_permitted. No data fields come with it; read `message` to the user rather than retrying the same call. |
| items | No | |
| active | No | Id of the portfolio active in the app. |
| message | No | Plain-language explanation that accompanies `error` or a proposed change. |
| profile | No | The portfolio these figures belong to (absent on list_profiles). |
| source_url | No | Link to the page in the WhereItGoes app that shows this data. |
| upgrade_url | No | Where the user can upgrade, on an upgrade_required refusal. |
| stock_assets | No | Present when the answer mentions Binance Stocks shares (EQ_<ticker>): they are US stocks, not crypto. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare read-only, idempotent, non-destructive behavior, and the description adds important operational context about default-portfolio resolution when `profile` is omitted. It does not need to explain return values because an output schema exists, though it could have noted any auth or rate-limit 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?
The description is front-loaded with the purpose, then usage, then the no-argument/default behavior. Every sentence adds concrete value with no repetition or 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 an output schema, rich read-only annotations, and zero parameters, the description supplies everything an agent needs: what is listed, when to call it first, and why single-portfolio accounts can skip 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. The description reinforces this by saying it takes no arguments and by explaining how its result feeds the `profile` parameter of other tools.
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: list the portfolios on this account. It also states the returned fields (id, name, exchange/wallet counts, active portfolio), making its purpose clear relative to deeper single-portfolio tools like get_portfolio.
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 call this FIRST when the user names a portfolio and explains why: to obtain the name or id for another tool's `profile` argument. It also states when it is unnecessary: single-portfolio accounts can omit `profile` because other tools use the connection default.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
propose_alert_changePropose creating, editing or deleting an alert (user approves)ADestructiveInspect
Propose a change to the user's price and value alerts: create a new one, edit one, or delete one, picked by action. Use this when the user asks to be told when something happens ("alert me if BTC drops below 60k", "email me when my portfolio passes 100k") or to change or remove an alert; to see which alerts exist, and their ids, call get_alerts instead, and always call it before an update or delete. This does NOT take effect when you call it: it returns a link the user has to open and approve in their own browser, so tell them to open it rather than saying it is done. Alerts are a Pro feature: an account without Pro gets upgrade_required, and a connection the user did not grant "propose changes" gets write_not_permitted; read either out and stop. Arguments by action. create: kind, op, threshold, plus subject for the asset kinds, optional repeat, cooldownSec, channels, note. update: alertId plus only the fields to change (op, threshold, enabled, repeat, cooldownSec, channels, note); kind and subject cannot be edited, so delete and re-create instead. delete: alertId only. An argument the action does not take is refused, not ignored.
| Name | Required | Description | Default |
|---|---|---|---|
| op | No | Fire when the watched value goes above or below the threshold. | |
| kind | No | create only. What the alert watches: asset_price (one asset's USD price), asset_pct (one asset's 24h % change), portfolio_value (total USD value), portfolio_pct (portfolio 24h % change), holding_value (USD value of the user's position in one asset), holding_weight (one asset's share of the portfolio, %). | |
| note | No | A short note shown with the alert, up to 200 characters. On update, an empty string clears it. | |
| action | Yes | create a new alert, update an existing one (by alertId), or delete one (by alertId). | |
| repeat | No | once (default): fire one time, then pause. recurring: fire every time the level is crossed again, no more often than cooldownSec. | |
| alertId | No | update and delete only: the `id` of the alert, exactly as get_alerts returns it. | |
| enabled | No | update only: false pauses the alert, true turns it back on. | |
| profile | No | Which portfolio to read, for accounts with more than one: its id, or its name (exact, case-insensitive, e.g. "Trading"). Omit to read this connection's default portfolio; every answer names the portfolio it read in `profile`. An unknown or shared name returns profile_not_found or profile_ambiguous listing the real ones, and list_profiles shows them up front. | |
| subject | No | create only, and required for asset_price, asset_pct, holding_value and holding_weight: the ticker, e.g. BTC. Omit for the portfolio kinds. | |
| channels | No | Where it is delivered. ["inapp"] (default) shows it in the app's notifications; ["inapp", "email"] also emails the user (the app's "Also email me" option). | |
| threshold | No | The trigger level, in the kind's unit: USD for asset_price, portfolio_value and holding_value (greater than 0); percent for asset_pct and portfolio_pct (signed, so -10 means a 10% drop); percent of the portfolio, 0 to 100, for holding_weight. | |
| cooldownSec | No | recurring alerts: minimum seconds between two notifications, 60 to 604800. Omit for the default (1 hour, or 6 hours for the % and allocation kinds). |
Output Schema
| Name | Required | Description |
|---|---|---|
| error | No | Present ONLY when the call was refused instead of answered: upgrade_required (Pro plan needed), not_found, profile_not_found, profile_ambiguous, invalid_arguments, write_not_permitted. No data fields come with it; read `message` to the user rather than retrying the same call. |
| title | No | What the change does. |
| status | No | Always this: nothing has been applied yet. |
| message | No | Plain-language explanation that accompanies `error` or a proposed change. |
| preview | No | Courtesy diff; the authoritative one is on the confirm page. |
| profile | No | The portfolio these figures belong to (absent on list_profiles). |
| expires_at | No | When the link stops working, epoch ms. |
| source_url | No | Link to the page in the WhereItGoes app that shows this data. |
| confirm_url | No | The link the user must open and approve; tell them to open it. |
| upgrade_url | No | Where the user can upgrade, on an upgrade_required refusal. |
| stock_assets | No | Present when the answer mentions Binance Stocks shares (EQ_<ticker>): they are US stocks, not crypto. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations by disclosing the core trait that this is a proposal, not an execution: it returns a link the user must approve, and the agent must not claim the change is done. It also names two concrete failure modes (upgrade_required for non-Pro, write_not_permitted for unpermitted connections), the requirement to surface them and stop, and that extraneous arguments are refused rather than ignored. Consistent with destructiveHint=true and non-idempotent.
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, then approval semantics, then errors, then a clearly labeled 'Arguments by action' block. Dense but every sentence carries an operational fact (approval flow, Pro gate, permission error, immutability); nothing is padding.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
A 12-parameter, destructive-annotated mutation tool with an output schema; the description still supplies what schema and annotations cannot – the deferred-approval return behavior, the two named error codes, and the action-to-parameter mapping. An agent has everything needed to call it and to interpret the result correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3; the description adds genuine action-conditional structure that the schema only partially encodes – the per-action argument matrix (create/update/delete), the fact that kind and subject are immutable on update and require delete-then-recreate, and that update takes only the changed fields. It stops short of restating units/enums, which the schema already handles well.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('propose a change to the user's price and value alerts') and enumerates the three actions selected by `action`. It also names the sibling tool get_alerts for the read path, so an agent can distinguish it without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit triggers with example utterances ('alert me if BTC drops below 60k'), names the alternative for listing alerts, and makes an unconditional prerequisite of calling get_alerts before any update or delete. When-not guidance is implicit in the read path being redirected to get_alerts.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_target_allocationPropose a target allocation change (user approves)ADestructiveInspect
Propose a change to the user's target allocation - the plan they mean to hold. This REPLACES the whole plan: send every target you want to keep, not just the ones you are changing, because any subject you omit is deleted. Send an empty rows to delete the plan entirely. dim must be "asset" (subjects are tickers) or "sector" (subjects are our sector names - call get_target_allocation first if you are unsure which axis their plan uses). This does NOT take effect when you call it: it returns a link the user has to open and approve themselves, so tell them to open it. Read get_target_allocation first so you are editing their real plan rather than guessing at it.
| Name | Required | Description | Default |
|---|---|---|---|
| dim | Yes | Which axis the plan is on. Every subject must belong to this axis. | |
| rows | Yes | The COMPLETE plan. Anything omitted is removed. | |
| profile | No | Which portfolio to read, for accounts with more than one: its id, or its name (exact, case-insensitive, e.g. "Trading"). Omit to read this connection's default portfolio; every answer names the portfolio it read in `profile`. An unknown or shared name returns profile_not_found or profile_ambiguous listing the real ones, and list_profiles shows them up front. |
Output Schema
| Name | Required | Description |
|---|---|---|
| error | No | Present ONLY when the call was refused instead of answered: upgrade_required (Pro plan needed), not_found, profile_not_found, profile_ambiguous, invalid_arguments, write_not_permitted. No data fields come with it; read `message` to the user rather than retrying the same call. |
| title | No | What the change does. |
| status | No | Always this: nothing has been applied yet. |
| message | No | Plain-language explanation that accompanies `error` or a proposed change. |
| preview | No | Courtesy diff; the authoritative one is on the confirm page. |
| profile | No | The portfolio these figures belong to (absent on list_profiles). |
| expires_at | No | When the link stops working, epoch ms. |
| source_url | No | Link to the page in the WhereItGoes app that shows this data. |
| confirm_url | No | The link the user must open and approve; tell them to open it. |
| upgrade_url | No | Where the user can upgrade, on an upgrade_required refusal. |
| stock_assets | No | Present when the answer mentions Binance Stocks shares (EQ_<ticker>): they are US stocks, not crypto. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare destructiveHint=true and idempotentHint=false, and the description earns credit beyond that: it explains exactly what gets destroyed (omitted subjects are deleted, empty rows wipes the plan) and that nothing takes effect until the user approves the link. That approval-gate behavior is not visible in any structured field.
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 replace-all warning and the capitalised REPLACES / COMPLETE phrasing is well placed. Slightly redundant: the 'read get_target_allocation first' instruction appears twice, once mid-paragraph and again at the end.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers everything an agent needs on a destructive, approval-gated write: replacement semantics, deletion path, axis constraint, the approval link return, and the read-before-write prerequisite. An output schema exists, so no obligation to detail return values, yet it still names the link.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3, but the description adds real semantic value on `dim` by explaining what the subjects are on each axis and how to resolve uncertainty, and frames `rows` as a full replacement rather than a patch. It adds little on `profile` or `bandPct`, which the schema already handles well.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Propose a change to the user's target allocation') and immediately defines the concept ('the plan they mean to hold'). It also distinguishes itself from the read-side sibling by naming get_target_allocation as the prerequisite.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit when-to-use guidance: read get_target_allocation first, call it to discover which axis the plan uses if unsure, send every target you want to keep, send empty `rows` to delete. It also names the required follow-up action (tell the user to open the returned link).
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.
33 tool updates
- Removed
get_activity_calendar - Changed
get_alerts1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": true, + "properties": { + "alerts": { + "items": { + "additionalProperties": true, + "properties": { + "channels": { + "items": { + "type": "string" + }, + "type": "array" + }, + "cooldownSec": { + "type": "number" + }, + "enabled": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "kind": { + "description": "asset_price, asset_pct, portfolio_value, portfolio_pct, holding_value or holding_weight.", + "type": "string" + }, + "label": { + "description": "Readable summary of the rule.", + "type": "string" + }, + "lastFiredAt": { + "description": "Last trigger, epoch ms.", + "type": [ + "number", + "null" + ] + }, + "op": { + "description": "above or below.", + "type": "string" + }, + "repeat": { + "description": "once or recurring.", + "type": "string" + }, + "subject": { + "description": "Asset the alert watches; null for whole-portfolio kinds.", + "type": [ + "string", + "null" + ] + }, + "threshold": { + "description": "Trigger level, in the kind's unit (USD or percent).", + "type": "number" + } + }, + "required": [ + "id", + "kind", + "subject", + "op", + "threshold", + "label", + "enabled", + "repeat", + "cooldownSec", + "channels", + "lastFiredAt" + ], + "type": "object" + }, + "type": "array" + }, + "error": { + "description": "Present ONLY when the call was refused instead of answered: upgrade_required (Pro plan needed), not_found, profile_not_found, profile_ambiguous, invalid_arguments, write_not_permitted. No data fields come with it; read `message` to the user rather than retrying the same call.", + "type": "string" + }, + "message": { + "description": "Plain-language explanation that accompanies `error` or a proposed change.", + "type": "string" + }, + "profile": { + "additionalProperties": true, + "description": "The portfolio these figures belong to (absent on list_profiles).", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "id", + "name" + ], + "type": "object" + }, + "source_url": { + "description": "Link to the page in the WhereItGoes app that shows this data.", + "type": "string" + }, + "stock_assets": { + "additionalProperties": true, + "description": "Present when the answer mentions Binance Stocks shares (EQ_<ticker>): they are US stocks, not crypto.", + "properties": { + "assets": { + "items": { + "additionalProperties": true, + "properties": { + "asset": { + "type": "string" + }, + "ticker": { + "type": "string" + } + }, + "required": [ + "asset", + "ticker" + ], + "type": "object" + }, + "type": "array" + }, + "note": { + "type": "string" + } + }, + "required": [ + "note", + "assets" + ], + "type": "object" + }, + "upgrade_url": { + "description": "Where the user can upgrade, on an upgrade_required refusal.", + "type": "string" + } + }, + "type": "object" +}
- Removed
get_asset_trade_stats - Removed
get_capital_flow - Changed
get_changes2 fields changed- changed
Input schema / properties / period / descriptionPrevious value: -"Time window ending now: last_24h (today / since yesterday), last_7d, last_30d, last_90d, ytd (since 1 January UTC), or all. Omit for all time."New value: +"Time window ending now: last_24h, last_7d, last_30d, last_90d, ytd (since 1 January UTC) or all. Omit for all time." - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": true, + "properties": { + "countsByType": { + "additionalProperties": { + "type": "number" + }, + "description": "Events detected per type before the list was capped.", + "type": "object" + }, + "error": { + "description": "Present ONLY when the call was refused instead of answered: upgrade_required (Pro plan needed), not_found, profile_not_found, profile_ambiguous, invalid_arguments, write_not_permitted. No data fields come with it; read `message` to the user rather than retrying the same call.", + "type": "string" + }, + "events": { + "description": "Ranked, most significant first.", + "items": { + "additionalProperties": true, + "properties": { + "amountUsd": { + "description": "USD size, when the event is a valued flow.", + "type": "string" + }, + "asset": { + "type": "string" + }, + "day": { + "description": "UTC day, YYYY-MM-DD.", + "type": "string" + }, + "detail": { + "type": "string" + }, + "magnitudePct": { + "type": "string" + }, + "severity": { + "enum": [ + "info", + "warn" + ], + "type": "string" + }, + "title": { + "type": "string" + }, + "type": { + "enum": [ + "flow", + "allocation", + "drawdown", + "new_source", + "reconciliation" + ], + "type": "string" + }, + "venue": { + "type": "string" + } + }, + "required": [ + "type", + "severity", + "day", + "title", + "detail" + ], + "type": "object" + }, + "type": "array" + }, + "events_note": { + "description": "Present only when `events` was cut; says how many rows were kept and which.", + "type": "string" + }, + "message": { + "description": "Plain-language explanation that accompanies `error` or a proposed change.", + "type": "string" + }, + "notes": { + "items": { + "type": "string" + }, + "type": "array" + }, + "profile": { + "additionalProperties": true, + "description": "The portfolio these figures belong to (absent on list_profiles).", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "id", + "name" + ], + "type": "object" + }, + "source_url": { + "description": "Link to the page in the WhereItGoes app that shows this data.", + "type": "string" + }, + "stock_assets": { + "additionalProperties": true, + "description": "Present when the answer mentions Binance Stocks shares (EQ_<ticker>): they are US stocks, not crypto.", + "properties": { + "assets": { + "items": { + "additionalProperties": true, + "properties": { + "asset": { + "type": "string" + }, + "ticker": { + "type": "string" + } + }, + "required": [ + "asset", + "ticker" + ], + "type": "object" + }, + "type": "array" + }, + "note": { + "type": "string" + } + }, + "required": [ + "note", + "assets" + ], + "type": "object" + }, + "truncated": { + "additionalProperties": { + "additionalProperties": true, + "properties": { + "from": { + "description": "Day or bucket of the first kept row, for a dated series.", + "type": "string" + }, + "keep": { + "description": "Which rows survived the cut.", + "enum": [ + "first", + "most_recent", + "evenly_spaced", + "best_and_worst" + ], + "type": "string" + }, + "kept": { + "description": "Rows returned.", + "type": "number" + }, + "to": { + "description": "Day or bucket of the last kept row, for a dated series.", + "type": "string" + }, + "total": { + "description": "Rows the full answer had.", + "type": "number" + } + }, + "required": [ + "total", + "kept", + "keep" + ], + "type": "object" + }, + "description": "Present only when a list was longer than the 200-row cap and was cut: list field name -> {total, kept, keep, from, to}. A `<field>_note` string beside that list says the same in words. Never present a cut list as complete.", + "type": "object" + }, + "upgrade_url": { + "description": "Where the user can upgrade, on an upgrade_required refusal.", + "type": "string" + }, + "window": { + "additionalProperties": true, + "description": "The time window these figures cover.", + "properties": { + "from": { + "description": "Window start, epoch ms; null = from the first record.", + "type": [ + "number", + "null" + ] + }, + "fromDay": { + "description": "First UTC day covered, YYYY-MM-DD.", + "type": [ + "string", + "null" + ] + }, + "to": { + "description": "Window end, epoch ms; null = now.", + "type": [ + "number", + "null" + ] + }, + "toDay": { + "description": "Last UTC day covered, YYYY-MM-DD.", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "from", + "to", + "fromDay", + "toDay" + ], + "type": "object" + } + }, + "type": "object" +}
- Added
get_connections - Removed
get_dashboard - Removed
get_deposits - Changed
get_fees3 fields changed- changed
Input schema / properties / bucket / descriptionPrevious value: -"Granularity of the fee time series. Defaults to month."New value: +"Granularity of the fee series. Defaults to month." - changed
Input schema / properties / period / descriptionPrevious value: -"Time window ending now: last_24h (today / since yesterday), last_7d, last_30d, last_90d, ytd (since 1 January UTC), or all. Omit for all time."New value: +"Time window ending now: last_24h, last_7d, last_30d, last_90d, ytd (since 1 January UTC) or all. Omit for all time." - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": true, + "properties": { + "avgFeeUsd": { + "type": "string" + }, + "bucket": { + "enum": [ + "day", + "week", + "month" + ], + "type": "string" + }, + "byAsset": { + "description": "Largest first.", + "items": { + "additionalProperties": true, + "properties": { + "asset": { + "type": "string" + }, + "count": { + "type": "number" + }, + "qty": { + "description": "Native units.", + "type": "string" + }, + "usd": { + "type": "string" + } + }, + "required": [ + "asset", + "usd", + "qty", + "count" + ], + "type": "object" + }, + "type": "array" + }, + "byType": { + "description": "Largest first.", + "items": { + "additionalProperties": true, + "properties": { + "count": { + "type": "number" + }, + "type": { + "enum": [ + "trading", + "network", + "withdrawal", + "fiat", + "other" + ], + "type": "string" + }, + "usd": { + "type": "string" + } + }, + "required": [ + "type", + "usd", + "count" + ], + "type": "object" + }, + "type": "array" + }, + "byVenue": { + "description": "Largest first.", + "items": { + "additionalProperties": true, + "properties": { + "count": { + "type": "number" + }, + "rateBps": { + "description": "Trading fees / traded volume, basis points.", + "type": [ + "number", + "null" + ] + }, + "tradedVolumeUsd": { + "type": "string" + }, + "usd": { + "type": "string" + }, + "venue": { + "type": "string" + } + }, + "required": [ + "venue", + "usd", + "count", + "tradedVolumeUsd", + "rateBps" + ], + "type": "object" + }, + "type": "array" + }, + "error": { + "description": "Present ONLY when the call was refused instead of answered: upgrade_required (Pro plan needed), not_found, profile_not_found, profile_ambiguous, invalid_arguments, write_not_permitted. No data fields come with it; read `message` to the user rather than retrying the same call.", + "type": "string" + }, + "feeCount": { + "description": "Fee-bearing events counted.", + "type": "number" + }, + "message": { + "description": "Plain-language explanation that accompanies `error` or a proposed change.", + "type": "string" + }, + "notes": { + "description": "What the coverage leaves out.", + "items": { + "type": "string" + }, + "type": "array" + }, + "partial": { + "description": "true when some fees could not be valued or are not tracked.", + "type": "boolean" + }, + "points": { + "description": "Oldest bucket first.", + "items": { + "additionalProperties": true, + "properties": { + "byType": { + "additionalProperties": { + "type": "string" + }, + "description": "fee type -> USD in the bucket.", + "type": "object" + }, + "rateBps": { + "type": [ + "number", + "null" + ] + }, + "t": { + "type": "string" + }, + "tradedVolumeUsd": { + "type": "string" + } + }, + "required": [ + "t", + "byType", + "tradedVolumeUsd", + "rateBps" + ], + "type": "object" + }, + "type": "array" + }, + "points_note": { + "description": "Present only when `points` was cut; says how many rows were kept and which.", + "type": "string" + }, + "profile": { + "additionalProperties": true, + "description": "The portfolio these figures belong to (absent on list_profiles).", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "id", + "name" + ], + "type": "object" + }, + "source_url": { + "description": "Link to the page in the WhereItGoes app that shows this data.", + "type": "string" + }, + "stock_assets": { + "additionalProperties": true, + "description": "Present when the answer mentions Binance Stocks shares (EQ_<ticker>): they are US stocks, not crypto.", + "properties": { + "assets": { + "items": { + "additionalProperties": true, + "properties": { + "asset": { + "type": "string" + }, + "ticker": { + "type": "string" + } + }, + "required": [ + "asset", + "ticker" + ], + "type": "object" + }, + "type": "array" + }, + "note": { + "type": "string" + } + }, + "required": [ + "note", + "assets" + ], + "type": "object" + }, + "totalUsd": { + "description": "All fees in the window, USD, each valued on the day paid.", + "type": "string" + }, + "truncated": { + "additionalProperties": { + "additionalProperties": true, + "properties": { + "from": { + "description": "Day or bucket of the first kept row, for a dated series.", + "type": "string" + }, + "keep": { + "description": "Which rows survived the cut.", + "enum": [ + "first", + "most_recent", + "evenly_spaced", + "best_and_worst" + ], + "type": "string" + }, + "kept": { + "description": "Rows returned.", + "type": "number" + }, + "to": { + "description": "Day or bucket of the last kept row, for a dated series.", + "type": "string" + }, + "total": { + "description": "Rows the full answer had.", + "type": "number" + } + }, + "required": [ + "total", + "kept", + "keep" + ], + "type": "object" + }, + "description": "Present only when a list was longer than the 200-row cap and was cut: list field name -> {total, kept, keep, from, to}. A `<field>_note` string beside that list says the same in words. Never present a cut list as complete.", + "type": "object" + }, + "unpricedAssets": { + "items": { + "type": "string" + }, + "type": "array" + }, + "upgrade_url": { + "description": "Where the user can upgrade, on an upgrade_required refusal.", + "type": "string" + }, + "window": { + "additionalProperties": true, + "description": "The time window these figures cover.", + "properties": { + "from": { + "description": "Window start, epoch ms; null = from the first record.", + "type": [ + "number", + "null" + ] + }, + "fromDay": { + "description": "First UTC day covered, YYYY-MM-DD.", + "type": [ + "string", + "null" + ] + }, + "to": { + "description": "Window end, epoch ms; null = now.", + "type": [ + "number", + "null" + ] + }, + "toDay": { + "description": "Last UTC day covered, YYYY-MM-DD.", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "from", + "to", + "fromDay", + "toDay" + ], + "type": "object" + } + }, + "type": "object" +}
- Removed
get_fiat_stats - Added
get_income - Removed
get_income_by_source - Removed
get_income_timeseries - Added
get_money_flows - Changed
get_movements5 fields changed- changed
Input schema / properties / kind / descriptionPrevious value: -"INFLOW = deposit, OUTFLOW = withdrawal, TRANSFER = a move between the user's own accounts, INCOME = yield, staking or airdrop, TRADE = a buy or sell. Omit for every kind."New value: +"INFLOW = deposit, OUTFLOW = withdrawal, TRANSFER = between the user's own accounts, INCOME = yield, staking or airdrop, TRADE = a buy or sell. Omit for every kind." - changed
Input schema / properties / period / descriptionPrevious value: -"Time window ending now: last_24h (today / since yesterday), last_7d, last_30d, last_90d, ytd (since 1 January UTC), or all. Omit for all time."New value: +"Time window ending now: last_24h, last_7d, last_30d, last_90d, ytd (since 1 January UTC) or all. Omit for all time." - changed
Input schema / properties / q / descriptionPrevious value: -"Free-text substring search (case-insensitive) over asset, transaction id, status and stored details such as an address fragment."New value: +"Case-insensitive substring search over asset, transaction id, status and stored details such as an address fragment." - changed
Input schema / properties / status / descriptionPrevious value: -"Status exactly as it appears in countsByStatus. Venue-native and case-sensitive (\"SUCCESS\", \"2\"), so copy it from the facet rather than guessing."New value: +"Status exactly as it appears in countsByStatus, e.g. \"SUCCESS\" or \"2\"." - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": true, + "properties": { + "countsBySource": { + "items": { + "additionalProperties": true, + "properties": { + "n": { + "type": "number" + }, + "source": { + "type": "string" + } + }, + "required": [ + "source", + "n" + ], + "type": "object" + }, + "type": "array" + }, + "countsByStatus": { + "items": { + "additionalProperties": true, + "properties": { + "n": { + "type": "number" + }, + "source": { + "type": "string" + }, + "status": { + "type": "string" + }, + "venue": { + "type": "string" + } + }, + "required": [ + "venue", + "source", + "status", + "n" + ], + "type": "object" + }, + "type": "array" + }, + "countsByVenue": { + "items": { + "additionalProperties": true, + "properties": { + "display": { + "type": "string" + }, + "n": { + "type": "number" + }, + "venue": { + "type": "string" + } + }, + "required": [ + "venue", + "n", + "display" + ], + "type": "object" + }, + "type": "array" + }, + "error": { + "description": "Present ONLY when the call was refused instead of answered: upgrade_required (Pro plan needed), not_found, profile_not_found, profile_ambiguous, invalid_arguments, write_not_permitted. No data fields come with it; read `message` to the user rather than retrying the same call.", + "type": "string" + }, + "hiddenSpam": { + "description": "Rows hidden because they were marked spam.", + "type": "number" + }, + "items": { + "description": "Newest first, at most `limit` rows.", + "items": { + "additionalProperties": true, + "properties": { + "base_amount": { + "description": "Amount of base_asset, NATIVE token units as a decimal string (not USD).", + "type": [ + "string", + "null" + ] + }, + "base_asset": { + "description": "Asset moved.", + "type": [ + "string", + "null" + ] + }, + "executed_at": { + "description": "When it happened, epoch ms.", + "type": "number" + }, + "fee": { + "description": "Fee charged, native units of fee_asset.", + "type": [ + "string", + "null" + ] + }, + "fee_asset": { + "description": "Asset the fee was charged in.", + "type": [ + "string", + "null" + ] + }, + "id": { + "description": "Stable row id, e.g. \"cex:123\" or \"wallet:456\".", + "type": "string" + }, + "kind": { + "description": "INFLOW (deposit), OUTFLOW (withdrawal), TRANSFER (between own accounts), INCOME, or TRADE.", + "type": "string" + }, + "quote_amount": { + "description": "Second leg amount, native units.", + "type": [ + "string", + "null" + ] + }, + "quote_asset": { + "description": "Second leg asset, for trades.", + "type": [ + "string", + "null" + ] + }, + "source": { + "description": "Venue-native source label, e.g. \"deposit\", \"withdraw\", \"staking\".", + "type": "string" + }, + "status": { + "description": "Venue-native status, case-sensitive.", + "type": [ + "string", + "null" + ] + }, + "value_usd": { + "description": "USD value on the day it happened; null when unpriced.", + "type": [ + "string", + "null" + ] + }, + "venue": { + "description": "Exchange or wallet venue the row came from.", + "type": "string" + } + }, + "required": [ + "id", + "venue", + "source", + "kind", + "base_asset", + "base_amount", + "quote_asset", + "quote_amount", + "fee", + "fee_asset", + "status", + "executed_at", + "value_usd" + ], + "type": "object" + }, + "type": "array" + }, + "items_note": { + "description": "Present only when `items` was cut; says how many rows were kept and which.", + "type": "string" + }, + "message": { + "description": "Plain-language explanation that accompanies `error` or a proposed change.", + "type": "string" + }, + "profile": { + "additionalProperties": true, + "description": "The portfolio these figures belong to (absent on list_profiles).", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "id", + "name" + ], + "type": "object" + }, + "source_url": { + "description": "Link to the page in the WhereItGoes app that shows this data.", + "type": "string" + }, + "stock_assets": { + "additionalProperties": true, + "description": "Present when the answer mentions Binance Stocks shares (EQ_<ticker>): they are US stocks, not crypto.", + "properties": { + "assets": { + "items": { + "additionalProperties": true, + "properties": { + "asset": { + "type": "string" + }, + "ticker": { + "type": "string" + } + }, + "required": [ + "asset", + "ticker" + ], + "type": "object" + }, + "type": "array" + }, + "note": { + "type": "string" + } + }, + "required": [ + "note", + "assets" + ], + "type": "object" + }, + "total": { + "description": "Every row matching the filters, before `limit`.", + "type": "number" + }, + "truncated": { + "additionalProperties": { + "additionalProperties": true, + "properties": { + "from": { + "description": "Day or bucket of the first kept row, for a dated series.", + "type": "string" + }, + "keep": { + "description": "Which rows survived the cut.", + "enum": [ + "first", + "most_recent", + "evenly_spaced", + "best_and_worst" + ], + "type": "string" + }, + "kept": { + "description": "Rows returned.", + "type": "number" + }, + "to": { + "description": "Day or bucket of the last kept row, for a dated series.", + "type": "string" + }, + "total": { + "description": "Rows the full answer had.", + "type": "number" + } + }, + "required": [ + "total", + "kept", + "keep" + ], + "type": "object" + }, + "description": "Present only when a list was longer than the 200-row cap and was cut: list field name -> {total, kept, keep, from, to}. A `<field>_note` string beside that list says the same in words. Never present a cut list as complete.", + "type": "object" + }, + "upgrade_url": { + "description": "Where the user can upgrade, on an upgrade_required refusal.", + "type": "string" + } + }, + "type": "object" +}
- Added
get_performance - Removed
get_pnl_by_symbol - Removed
get_pnl_overview - Changed
get_portfolio3 fields changed- added
Input schema / properties / viewAdded value: +{ + "description": "Which view to read: overview (whole-portfolio summary, start here); holdings (every asset held, largest first); recent_change (24h, 7d and 30d change and last sync). Each view takes only the arguments the description lists for it.", + "enum": [ + "overview", + "holdings", + "recent_change" + ], + "type": "string" +} - added
Input schema / requiredAdded value: +[ + "view" +] - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": true, + "properties": { + "error": { + "description": "Present ONLY when the call was refused instead of answered: upgrade_required (Pro plan needed), not_found, profile_not_found, profile_ambiguous, invalid_arguments, write_not_permitted. No data fields come with it; read `message` to the user rather than retrying the same call.", + "type": "string" + }, + "holdings": { + "additionalProperties": true, + "description": "Present when view = \"holdings\".", + "properties": { + "asOf": { + "description": "When the holdings snapshot was computed, epoch ms (not a live quote).", + "type": [ + "number", + "null" + ] + }, + "assets": { + "description": "One row per asset, largest USD value first.", + "items": { + "additionalProperties": true, + "properties": { + "asset": { + "description": "Asset key, e.g. \"BTC\".", + "type": "string" + }, + "byVenue": { + "description": "Where the asset is held.", + "items": { + "additionalProperties": true, + "properties": { + "displayName": { + "type": "string" + }, + "qty": { + "description": "Quantity at this venue, native units.", + "type": "string" + }, + "type": { + "type": "string" + }, + "valueUsdt": { + "description": "USD value at this venue.", + "type": [ + "string", + "null" + ] + }, + "venue": { + "type": "string" + } + }, + "required": [ + "venue", + "displayName", + "type", + "qty", + "valueUsdt" + ], + "type": "object" + }, + "type": "array" + }, + "fifoAvgCost": { + "description": "FIFO average cost per unit, USD.", + "type": [ + "string", + "null" + ] + }, + "priceChangePct24h": { + "description": "Signed 24h price change, percent.", + "type": [ + "string", + "null" + ] + }, + "priceUsdt": { + "description": "USD price used for the valuation.", + "type": [ + "string", + "null" + ] + }, + "realizedPnlUsdt": { + "description": "Realized FIFO P&L to date, USD.", + "type": [ + "string", + "null" + ] + }, + "sector": { + "type": [ + "string", + "null" + ] + }, + "total": { + "description": "Quantity held across every venue, native units.", + "type": "string" + }, + "trades": { + "description": "Trades recorded for the asset.", + "type": "number" + }, + "unknownCostQty": { + "description": "Quantity with no known cost basis (excluded from avg cost and unrealized).", + "type": [ + "string", + "null" + ] + }, + "unrealizedAbs": { + "description": "Unrealized P&L on the open quantity, USD.", + "type": [ + "string", + "null" + ] + }, + "unrealizedPct": { + "description": "Unrealized P&L, percent.", + "type": [ + "string", + "null" + ] + }, + "valueChange24hUsdt": { + "description": "USD value change over 24h.", + "type": [ + "string", + "null" + ] + }, + "valueUsdt": { + "description": "USD value; null when unpriced.", + "type": [ + "string", + "null" + ] + }, + "weightPct": { + "description": "Share of totalUsdt, percent.", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "asset", + "total", + "priceUsdt", + "priceChangePct24h", + "valueUsdt", + "valueChange24hUsdt", + "weightPct", + "fifoAvgCost", + "unknownCostQty", + "unrealizedAbs", + "unrealizedPct", + "realizedPnlUsdt", + "trades", + "byVenue" + ], + "type": "object" + }, + "type": "array" + }, + "assets_note": { + "description": "Present only when `assets` was cut; says how many rows were kept and which.", + "type": "string" + }, + "regrouping": { + "description": "true while a recompute for a changed grouping setting is in flight.", + "type": "boolean" + }, + "totalUsdt": { + "description": "Whole portfolio value in USD, decimal string with 2 decimals.", + "type": "string" + }, + "truncated": { + "additionalProperties": { + "additionalProperties": true, + "properties": { + "from": { + "description": "Day or bucket of the first kept row, for a dated series.", + "type": "string" + }, + "keep": { + "description": "Which rows survived the cut.", + "enum": [ + "first", + "most_recent", + "evenly_spaced", + "best_and_worst" + ], + "type": "string" + }, + "kept": { + "description": "Rows returned.", + "type": "number" + }, + "to": { + "description": "Day or bucket of the last kept row, for a dated series.", + "type": "string" + }, + "total": { + "description": "Rows the full answer had.", + "type": "number" + } + }, + "required": [ + "total", + "kept", + "keep" + ], + "type": "object" + }, + "description": "Present only when a list was longer than the 200-row cap and was cut: list field name -> {total, kept, keep, from, to}. A `<field>_note` string beside that list says the same in words. Never present a cut list as complete.", + "type": "object" + } + }, + "type": "object" + }, + "message": { + "description": "Plain-language explanation that accompanies `error` or a proposed change.", + "type": "string" + }, + "overview": { + "additionalProperties": true, + "description": "Present when view = \"overview\".", + "properties": { + "allocation": { + "additionalProperties": true, + "properties": { + "byAsset": { + "description": "Largest first, at most 12; the rest are counted in `truncated.assets`.", + "items": { + "additionalProperties": true, + "properties": { + "asset": { + "type": "string" + }, + "name": { + "type": "string" + }, + "pct": { + "description": "Share of total value, percent.", + "type": "number" + }, + "priceChangePct24h": { + "description": "24h price change, percent.", + "type": [ + "number", + "null" + ] + }, + "valueUsd": { + "description": "USD value.", + "type": "number" + } + }, + "required": [ + "asset", + "name", + "pct", + "valueUsd", + "priceChangePct24h" + ], + "type": "object" + }, + "type": "array" + }, + "byChain": { + "items": { + "additionalProperties": true, + "properties": { + "name": { + "type": "string" + }, + "pct": { + "type": "number" + }, + "valueUsd": { + "type": "number" + } + }, + "required": [ + "name", + "pct", + "valueUsd" + ], + "type": "object" + }, + "type": "array" + }, + "byClass": { + "items": { + "additionalProperties": true, + "properties": { + "name": { + "type": "string" + }, + "pct": { + "type": "number" + }, + "valueUsd": { + "type": "number" + } + }, + "required": [ + "name", + "pct", + "valueUsd" + ], + "type": "object" + }, + "type": "array" + }, + "byVenue": { + "items": { + "additionalProperties": true, + "properties": { + "name": { + "type": "string" + }, + "pct": { + "type": "number" + }, + "valueUsd": { + "type": "number" + } + }, + "required": [ + "name", + "pct", + "valueUsd" + ], + "type": "object" + }, + "type": "array" + }, + "truncated": { + "additionalProperties": true, + "description": "How many assets, venues and chains were left out of the lists above.", + "properties": { + "assets": { + "type": "number" + }, + "chains": { + "type": "number" + }, + "venues": { + "type": "number" + } + }, + "required": [ + "assets", + "venues", + "chains" + ], + "type": "object" + } + }, + "required": [ + "byAsset", + "byClass", + "byVenue", + "byChain", + "truncated" + ], + "type": "object" + }, + "asOf": { + "description": "When this overview was assembled, epoch ms.", + "type": "number" + }, + "candidates": { + "description": "Ranked findings, most severe first. Pro only: empty on a free plan.", + "items": { + "additionalProperties": true, + "properties": { + "ruleId": { + "type": "string" + }, + "severity": { + "type": "string" + }, + "statement": { + "type": "string" + } + }, + "required": [ + "ruleId", + "severity", + "statement" + ], + "type": "object" + }, + "type": "array" + }, + "concentration": { + "additionalProperties": true, + "properties": { + "hhi": { + "description": "Herfindahl index of the weights, 0-10000.", + "type": "number" + }, + "top1Pct": { + "type": "number" + }, + "top3Pct": { + "type": "number" + }, + "topName": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "hhi", + "top1Pct", + "top3Pct", + "topName" + ], + "type": "object" + }, + "degraded": { + "description": "Blocks that failed to compute this time.", + "items": { + "type": "string" + }, + "type": "array" + }, + "flags": { + "additionalProperties": true, + "properties": { + "cexPct": { + "description": "Share held on exchanges, percent.", + "type": "number" + }, + "dustCount": { + "type": "number" + }, + "selfCustodyPct": { + "description": "Share held in self-custody wallets, percent.", + "type": "number" + }, + "stablecoinPct": { + "type": "number" + }, + "stockPct": { + "type": "number" + }, + "unpricedCount": { + "type": "number" + }, + "volatilePct": { + "type": "number" + } + }, + "required": [ + "stablecoinPct", + "volatilePct", + "stockPct", + "cexPct", + "selfCustodyPct", + "dustCount", + "unpricedCount" + ], + "type": "object" + }, + "gated": { + "description": "Blocks withheld because the account is not on a Pro plan.", + "items": { + "type": "string" + }, + "type": "array" + }, + "market": { + "anyOf": [ + { + "additionalProperties": true, + "properties": { + "windowDays": { + "type": "number" + } + }, + "required": [ + "windowDays" + ], + "type": "object" + }, + { + "type": "null" + } + ], + "description": "What BTC and ETH did over the same window, plus the fear and greed reading." + }, + "performance": { + "anyOf": [ + { + "additionalProperties": true, + "properties": { + "feesUsd": { + "type": [ + "number", + "null" + ] + }, + "incomeUsd": { + "type": [ + "number", + "null" + ] + }, + "netFlowsUsd": { + "description": "Deposits minus withdrawals over the 30 days, USD.", + "type": [ + "number", + "null" + ] + }, + "realizedUsd": { + "type": [ + "number", + "null" + ] + }, + "topGainers": { + "items": { + "additionalProperties": true, + "properties": { + "asset": { + "type": "string" + }, + "pnlUsd": { + "type": "number" + } + }, + "required": [ + "asset", + "pnlUsd" + ], + "type": "object" + }, + "type": "array" + }, + "topLosers": { + "items": { + "additionalProperties": true, + "properties": { + "asset": { + "type": "string" + }, + "pnlUsd": { + "type": "number" + } + }, + "required": [ + "asset", + "pnlUsd" + ], + "type": "object" + }, + "type": "array" + }, + "truePnlPct": { + "description": "Same as a percent.", + "type": [ + "number", + "null" + ] + }, + "truePnlUsd": { + "description": "Profit over the 30 days with deposits and withdrawals stripped out, USD.", + "type": [ + "number", + "null" + ] + }, + "unrealizedUsd": { + "type": [ + "number", + "null" + ] + }, + "valuedThroughDay": { + "description": "UTC day the figures are valued through (end-of-day, not live).", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "valuedThroughDay", + "truePnlUsd", + "truePnlPct", + "netFlowsUsd", + "realizedUsd", + "unrealizedUsd", + "incomeUsd", + "feesUsd", + "topGainers", + "topLosers" + ], + "type": "object" + }, + { + "type": "null" + } + ] + }, + "period": { + "additionalProperties": true, + "description": "The fixed 30-day window the performance and market blocks cover.", + "properties": { + "from": { + "type": [ + "number", + "null" + ] + }, + "label": { + "type": "string" + }, + "to": { + "type": [ + "number", + "null" + ] + } + }, + "required": [ + "label", + "from", + "to" + ], + "type": "object" + }, + "risk": { + "anyOf": [ + { + "additionalProperties": true, + "properties": { + "annualizedVolPct": { + "type": [ + "number", + "null" + ] + }, + "maxDrawdownPct": { + "type": [ + "number", + "null" + ] + }, + "sharpe": { + "type": [ + "number", + "null" + ] + } + }, + "required": [ + "annualizedVolPct", + "maxDrawdownPct", + "sharpe" + ], + "type": "object" + }, + { + "type": "null" + } + ], + "description": "Pro only: null on a free plan (see `gated`)." + }, + "score": { + "anyOf": [ + { + "additionalProperties": true, + "properties": { + "band": { + "type": "string" + }, + "score": { + "description": "0-100.", + "type": "number" + } + }, + "required": [ + "score", + "band" + ], + "type": "object" + }, + { + "type": "null" + } + ], + "description": "Pro only: null on a free plan (see `gated`)." + }, + "targets": { + "anyOf": [ + { + "additionalProperties": true, + "properties": { + "dim": { + "type": "string" + }, + "rows": { + "items": { + "additionalProperties": true, + "properties": { + "actualPct": { + "type": "number" + }, + "bandPct": { + "type": "number" + }, + "deltaUsd": { + "description": "Signed USD to reach target: + sell this much, - buy this much.", + "type": "number" + }, + "driftPct": { + "description": "Signed percentage points: + overweight, - underweight.", + "type": "number" + }, + "inBand": { + "type": "boolean" + }, + "subject": { + "type": "string" + }, + "targetPct": { + "type": "number" + } + }, + "required": [ + "subject", + "targetPct", + "actualPct", + "driftPct", + "bandPct", + "inBand", + "deltaUsd" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "dim", + "rows" + ], + "type": "object" + }, + { + "type": "null" + } + ], + "description": "Drift from the target allocation; null when no target is set." + }, + "totals": { + "additionalProperties": true, + "properties": { + "assetCount": { + "description": "Number of priced holdings.", + "type": "number" + }, + "valueUsd": { + "description": "Live total portfolio value, USD.", + "type": "number" + } + }, + "required": [ + "valueUsd", + "assetCount" + ], + "type": "object" + } + }, + "type": "object" + }, + "profile": { + "additionalProperties": true, + "description": "The portfolio these figures belong to (absent on list_profiles).", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "id", + "name" + ], + "type": "object" + }, + "recent_change": { + "additionalProperties": true, + "description": "Present when view = \"recent_change\".", + "properties": { + "cashDeployedUsdt": { + "description": "Lifetime fiat cash put in, USD.", + "type": [ + "string", + "null" + ] + }, + "cashWithdrawnUsdt": { + "description": "Lifetime fiat cash taken out, USD.", + "type": [ + "string", + "null" + ] + }, + "change24hPct": { + "description": "Portfolio value change over 24h, percent; null until daily history exists.", + "type": [ + "string", + "null" + ] + }, + "change24hUsdt": { + "description": "Same in USD.", + "type": [ + "string", + "null" + ] + }, + "change30dPct": { + "type": [ + "string", + "null" + ] + }, + "change30dUsdt": { + "type": [ + "string", + "null" + ] + }, + "change7dPct": { + "type": [ + "string", + "null" + ] + }, + "change7dUsdt": { + "type": [ + "string", + "null" + ] + }, + "costBasisUsdt": { + "description": "Cost basis of current holdings, USD.", + "type": [ + "string", + "null" + ] + }, + "lastSyncAt": { + "description": "When the last sync finished, epoch ms.", + "type": [ + "number", + "null" + ] + }, + "lastSyncMode": { + "type": [ + "string", + "null" + ] + }, + "netCapitalUsdt": { + "description": "Lifetime net capital put in, USD.", + "type": [ + "string", + "null" + ] + }, + "totalMovements": { + "description": "Deposits, withdrawals, transfers and income on record.", + "type": "number" + }, + "totalTrades": { + "description": "Trades on record.", + "type": "number" + } + }, + "type": "object" + }, + "source_url": { + "description": "Link to the page in the WhereItGoes app that shows this data.", + "type": "string" + }, + "stock_assets": { + "additionalProperties": true, + "description": "Present when the answer mentions Binance Stocks shares (EQ_<ticker>): they are US stocks, not crypto.", + "properties": { + "assets": { + "items": { + "additionalProperties": true, + "properties": { + "asset": { + "type": "string" + }, + "ticker": { + "type": "string" + } + }, + "required": [ + "asset", + "ticker" + ], + "type": "object" + }, + "type": "array" + }, + "note": { + "type": "string" + } + }, + "required": [ + "note", + "assets" + ], + "type": "object" + }, + "upgrade_url": { + "description": "Where the user can upgrade, on an upgrade_required refusal.", + "type": "string" + }, + "view": { + "description": "Which view answered; its data is under the key of the same name.", + "enum": [ + "overview", + "holdings", + "recent_change" + ], + "type": "string" + } + }, + "type": "object" +}
- Removed
get_portfolio_history - Removed
get_portfolio_score - Removed
get_portfolio_snapshot - Added
get_risk - Removed
get_risk_metrics - Removed
get_sync_status - Changed
get_target_allocation1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": true, + "properties": { + "error": { + "description": "Present ONLY when the call was refused instead of answered: upgrade_required (Pro plan needed), not_found, profile_not_found, profile_ambiguous, invalid_arguments, write_not_permitted. No data fields come with it; read `message` to the user rather than retrying the same call.", + "type": "string" + }, + "message": { + "description": "Plain-language explanation that accompanies `error` or a proposed change.", + "type": "string" + }, + "profile": { + "additionalProperties": true, + "description": "The portfolio these figures belong to (absent on list_profiles).", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "id", + "name" + ], + "type": "object" + }, + "set": { + "anyOf": [ + { + "additionalProperties": true, + "properties": { + "dim": { + "description": "Axis of the plan: \"asset\" (subjects are tickers), \"sector\" (subjects are sector names) or \"class\".", + "type": "string" + }, + "rows": { + "description": "Largest target first.", + "items": { + "additionalProperties": true, + "properties": { + "bandPct": { + "description": "Tolerance in percentage POINTS either side.", + "type": "number" + }, + "subject": { + "type": "string" + }, + "targetPct": { + "description": "Target share, percent.", + "type": "number" + } + }, + "required": [ + "subject", + "targetPct", + "bandPct" + ], + "type": "object" + }, + "type": "array" + }, + "updatedAt": { + "description": "Epoch ms.", + "type": "number" + } + }, + "required": [ + "dim", + "rows", + "updatedAt" + ], + "type": "object" + }, + { + "type": "null" + } + ], + "description": "null when no target allocation is set." + }, + "source_url": { + "description": "Link to the page in the WhereItGoes app that shows this data.", + "type": "string" + }, + "stock_assets": { + "additionalProperties": true, + "description": "Present when the answer mentions Binance Stocks shares (EQ_<ticker>): they are US stocks, not crypto.", + "properties": { + "assets": { + "items": { + "additionalProperties": true, + "properties": { + "asset": { + "type": "string" + }, + "ticker": { + "type": "string" + } + }, + "required": [ + "asset", + "ticker" + ], + "type": "object" + }, + "type": "array" + }, + "note": { + "type": "string" + } + }, + "required": [ + "note", + "assets" + ], + "type": "object" + }, + "upgrade_url": { + "description": "Where the user can upgrade, on an upgrade_required refusal.", + "type": "string" + } + }, + "type": "object" +}
- Added
get_trading_activity - Removed
get_transfers - Removed
get_venues - Removed
get_wallets - Changed
list_profiles1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": true, + "properties": { + "active": { + "description": "Id of the portfolio active in the app.", + "type": [ + "string", + "null" + ] + }, + "error": { + "description": "Present ONLY when the call was refused instead of answered: upgrade_required (Pro plan needed), not_found, profile_not_found, profile_ambiguous, invalid_arguments, write_not_permitted. No data fields come with it; read `message` to the user rather than retrying the same call.", + "type": "string" + }, + "items": { + "items": { + "additionalProperties": true, + "properties": { + "exchangeCount": { + "type": "number" + }, + "id": { + "description": "Pass as the `profile` argument.", + "type": "string" + }, + "name": { + "description": "Pass as the `profile` argument.", + "type": "string" + }, + "walletCount": { + "type": "number" + } + }, + "required": [ + "id", + "name", + "exchangeCount", + "walletCount" + ], + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "Plain-language explanation that accompanies `error` or a proposed change.", + "type": "string" + }, + "profile": { + "additionalProperties": true, + "description": "The portfolio these figures belong to (absent on list_profiles).", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "id", + "name" + ], + "type": "object" + }, + "source_url": { + "description": "Link to the page in the WhereItGoes app that shows this data.", + "type": "string" + }, + "stock_assets": { + "additionalProperties": true, + "description": "Present when the answer mentions Binance Stocks shares (EQ_<ticker>): they are US stocks, not crypto.", + "properties": { + "assets": { + "items": { + "additionalProperties": true, + "properties": { + "asset": { + "type": "string" + }, + "ticker": { + "type": "string" + } + }, + "required": [ + "asset", + "ticker" + ], + "type": "object" + }, + "type": "array" + }, + "note": { + "type": "string" + } + }, + "required": [ + "note", + "assets" + ], + "type": "object" + }, + "upgrade_url": { + "description": "Where the user can upgrade, on an upgrade_required refusal.", + "type": "string" + } + }, + "type": "object" +}
- Added
propose_alert_change - Changed
set_target_allocation1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": true, + "properties": { + "confirm_url": { + "description": "The link the user must open and approve; tell them to open it.", + "type": "string" + }, + "error": { + "description": "Present ONLY when the call was refused instead of answered: upgrade_required (Pro plan needed), not_found, profile_not_found, profile_ambiguous, invalid_arguments, write_not_permitted. No data fields come with it; read `message` to the user rather than retrying the same call.", + "type": "string" + }, + "expires_at": { + "description": "When the link stops working, epoch ms.", + "type": "number" + }, + "message": { + "description": "Plain-language explanation that accompanies `error` or a proposed change.", + "type": "string" + }, + "preview": { + "description": "Courtesy diff; the authoritative one is on the confirm page.", + "items": { + "additionalProperties": true, + "properties": { + "after": { + "type": [ + "string", + "null" + ] + }, + "before": { + "type": [ + "string", + "null" + ] + }, + "kind": { + "enum": [ + "add", + "remove", + "change", + "same" + ], + "type": "string" + }, + "label": { + "type": "string" + } + }, + "required": [ + "label", + "before", + "after", + "kind" + ], + "type": "object" + }, + "type": "array" + }, + "profile": { + "additionalProperties": true, + "description": "The portfolio these figures belong to (absent on list_profiles).", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "id", + "name" + ], + "type": "object" + }, + "source_url": { + "description": "Link to the page in the WhereItGoes app that shows this data.", + "type": "string" + }, + "status": { + "const": "confirmation_required", + "description": "Always this: nothing has been applied yet.", + "type": "string" + }, + "stock_assets": { + "additionalProperties": true, + "description": "Present when the answer mentions Binance Stocks shares (EQ_<ticker>): they are US stocks, not crypto.", + "properties": { + "assets": { + "items": { + "additionalProperties": true, + "properties": { + "asset": { + "type": "string" + }, + "ticker": { + "type": "string" + } + }, + "required": [ + "asset", + "ticker" + ], + "type": "object" + }, + "type": "array" + }, + "note": { + "type": "string" + } + }, + "required": [ + "note", + "assets" + ], + "type": "object" + }, + "title": { + "description": "What the change does.", + "type": "string" + }, + "upgrade_url": { + "description": "Where the user can upgrade, on an upgrade_required refusal.", + "type": "string" + } + }, + "type": "object" +}
25 tool updates
- Changed
get_activity_calendar1 field changed- changed
Input schema / properties / profile / descriptionPrevious value: -"Which portfolio to read, by name or id, for accounts that have more than one. Omit to use this connection's default. Call list_profiles first if the user names a portfolio you have not seen."New value: +"Which portfolio to read, for accounts with more than one: its id, or its name (exact, case-insensitive, e.g. \"Trading\"). Omit to read this connection's default portfolio; every answer names the portfolio it read in `profile`. An unknown or shared name returns profile_not_found or profile_ambiguous listing the real ones, and list_profiles shows them up front."
- Changed
get_alerts1 field changed- changed
Input schema / properties / profile / descriptionPrevious value: -"Which portfolio to read, by name or id, for accounts that have more than one. Omit to use this connection's default. Call list_profiles first if the user names a portfolio you have not seen."New value: +"Which portfolio to read, for accounts with more than one: its id, or its name (exact, case-insensitive, e.g. \"Trading\"). Omit to read this connection's default portfolio; every answer names the portfolio it read in `profile`. An unknown or shared name returns profile_not_found or profile_ambiguous listing the real ones, and list_profiles shows them up front."
- Changed
get_asset_trade_stats1 field changed- changed
Input schema / properties / profile / descriptionPrevious value: -"Which portfolio to read, by name or id, for accounts that have more than one. Omit to use this connection's default. Call list_profiles first if the user names a portfolio you have not seen."New value: +"Which portfolio to read, for accounts with more than one: its id, or its name (exact, case-insensitive, e.g. \"Trading\"). Omit to read this connection's default portfolio; every answer names the portfolio it read in `profile`. An unknown or shared name returns profile_not_found or profile_ambiguous listing the real ones, and list_profiles shows them up front."
- Changed
get_capital_flow3 fields changed- changed
Input schema / properties / bucket / descriptionPrevious value: -"Time bucket. Defaults to month."New value: +"Granularity of the series. Defaults to month." - changed
Input schema / properties / period / descriptionPrevious value: -"Time window. \"last_24h\" for today/since-yesterday, \"all\" for full history. Defaults to the endpoint's own default (usually last 30 days)."New value: +"Time window ending now: last_24h (today / since yesterday), last_7d, last_30d, last_90d, ytd (since 1 January UTC), or all. Omit for all time." - changed
Input schema / properties / profile / descriptionPrevious value: -"Which portfolio to read, by name or id, for accounts that have more than one. Omit to use this connection's default. Call list_profiles first if the user names a portfolio you have not seen."New value: +"Which portfolio to read, for accounts with more than one: its id, or its name (exact, case-insensitive, e.g. \"Trading\"). Omit to read this connection's default portfolio; every answer names the portfolio it read in `profile`. An unknown or shared name returns profile_not_found or profile_ambiguous listing the real ones, and list_profiles shows them up front."
- Changed
get_changes2 fields changed- changed
Input schema / properties / period / descriptionPrevious value: -"Time window. \"last_24h\" for today/since-yesterday, \"all\" for full history. Defaults to the endpoint's own default (usually last 30 days)."New value: +"Time window ending now: last_24h (today / since yesterday), last_7d, last_30d, last_90d, ytd (since 1 January UTC), or all. Omit for all time." - changed
Input schema / properties / profile / descriptionPrevious value: -"Which portfolio to read, by name or id, for accounts that have more than one. Omit to use this connection's default. Call list_profiles first if the user names a portfolio you have not seen."New value: +"Which portfolio to read, for accounts with more than one: its id, or its name (exact, case-insensitive, e.g. \"Trading\"). Omit to read this connection's default portfolio; every answer names the portfolio it read in `profile`. An unknown or shared name returns profile_not_found or profile_ambiguous listing the real ones, and list_profiles shows them up front."
- Changed
get_dashboard1 field changed- changed
Input schema / properties / profile / descriptionPrevious value: -"Which portfolio to read, by name or id, for accounts that have more than one. Omit to use this connection's default. Call list_profiles first if the user names a portfolio you have not seen."New value: +"Which portfolio to read, for accounts with more than one: its id, or its name (exact, case-insensitive, e.g. \"Trading\"). Omit to read this connection's default portfolio; every answer names the portfolio it read in `profile`. An unknown or shared name returns profile_not_found or profile_ambiguous listing the real ones, and list_profiles shows them up front."
- Changed
get_deposits1 field changed- changed
Input schema / properties / profile / descriptionPrevious value: -"Which portfolio to read, by name or id, for accounts that have more than one. Omit to use this connection's default. Call list_profiles first if the user names a portfolio you have not seen."New value: +"Which portfolio to read, for accounts with more than one: its id, or its name (exact, case-insensitive, e.g. \"Trading\"). Omit to read this connection's default portfolio; every answer names the portfolio it read in `profile`. An unknown or shared name returns profile_not_found or profile_ambiguous listing the real ones, and list_profiles shows them up front."
- Changed
get_fees3 fields changed- changed
Input schema / properties / bucket / descriptionPrevious value: -"Time bucket for the fee series."New value: +"Granularity of the fee time series. Defaults to month." - changed
Input schema / properties / period / descriptionPrevious value: -"Time window. \"last_24h\" for today/since-yesterday, \"all\" for full history. Defaults to the endpoint's own default (usually last 30 days)."New value: +"Time window ending now: last_24h (today / since yesterday), last_7d, last_30d, last_90d, ytd (since 1 January UTC), or all. Omit for all time." - changed
Input schema / properties / profile / descriptionPrevious value: -"Which portfolio to read, by name or id, for accounts that have more than one. Omit to use this connection's default. Call list_profiles first if the user names a portfolio you have not seen."New value: +"Which portfolio to read, for accounts with more than one: its id, or its name (exact, case-insensitive, e.g. \"Trading\"). Omit to read this connection's default portfolio; every answer names the portfolio it read in `profile`. An unknown or shared name returns profile_not_found or profile_ambiguous listing the real ones, and list_profiles shows them up front."
- Changed
get_fiat_stats1 field changed- changed
Input schema / properties / profile / descriptionPrevious value: -"Which portfolio to read, by name or id, for accounts that have more than one. Omit to use this connection's default. Call list_profiles first if the user names a portfolio you have not seen."New value: +"Which portfolio to read, for accounts with more than one: its id, or its name (exact, case-insensitive, e.g. \"Trading\"). Omit to read this connection's default portfolio; every answer names the portfolio it read in `profile`. An unknown or shared name returns profile_not_found or profile_ambiguous listing the real ones, and list_profiles shows them up front."
- Changed
get_income_by_source2 fields changed- changed
Input schema / properties / period / descriptionPrevious value: -"Time window. \"last_24h\" for today/since-yesterday, \"all\" for full history. Defaults to the endpoint's own default (usually last 30 days)."New value: +"Time window ending now: last_24h (today / since yesterday), last_7d, last_30d, last_90d, ytd (since 1 January UTC), or all. Omit for all time." - changed
Input schema / properties / profile / descriptionPrevious value: -"Which portfolio to read, by name or id, for accounts that have more than one. Omit to use this connection's default. Call list_profiles first if the user names a portfolio you have not seen."New value: +"Which portfolio to read, for accounts with more than one: its id, or its name (exact, case-insensitive, e.g. \"Trading\"). Omit to read this connection's default portfolio; every answer names the portfolio it read in `profile`. An unknown or shared name returns profile_not_found or profile_ambiguous listing the real ones, and list_profiles shows them up front."
- Changed
get_income_timeseries3 fields changed- changed
Input schema / properties / bucket / descriptionPrevious value: -"Time bucket. Defaults to month."New value: +"Granularity of the series. Defaults to week." - changed
Input schema / properties / period / descriptionPrevious value: -"Time window. \"last_24h\" for today/since-yesterday, \"all\" for full history. Defaults to the endpoint's own default (usually last 30 days)."New value: +"Time window ending now: last_24h (today / since yesterday), last_7d, last_30d, last_90d, ytd (since 1 January UTC), or all. Omit for all time." - changed
Input schema / properties / profile / descriptionPrevious value: -"Which portfolio to read, by name or id, for accounts that have more than one. Omit to use this connection's default. Call list_profiles first if the user names a portfolio you have not seen."New value: +"Which portfolio to read, for accounts with more than one: its id, or its name (exact, case-insensitive, e.g. \"Trading\"). Omit to read this connection's default portfolio; every answer names the portfolio it read in `profile`. An unknown or shared name returns profile_not_found or profile_ambiguous listing the real ones, and list_profiles shows them up front."
- Changed
get_movements9 fields changed- changed
Input schema / properties / asset / descriptionPrevious value: -"Filter to one asset ticker, e.g. \"BTC\"."New value: +"Asset ticker, e.g. \"BTC\"; comma-separate for several (\"BTC,ETH\"). Case-insensitive." - changed
Input schema / properties / kind / descriptionPrevious value: -"INFLOW = deposit, OUTFLOW = withdrawal."New value: +"INFLOW = deposit, OUTFLOW = withdrawal, TRANSFER = a move between the user's own accounts, INCOME = yield, staking or airdrop, TRADE = a buy or sell. Omit for every kind." - changed
Input schema / properties / limit / descriptionPrevious value: -"Maximum rows to return (capped at 200)."New value: +"How many of the newest matching rows to return, 1-200. Defaults to 100." - changed
Input schema / properties / period / descriptionPrevious value: -"Time window. \"last_24h\" for today/since-yesterday, \"all\" for full history. Defaults to the endpoint's own default (usually last 30 days)."New value: +"Time window ending now: last_24h (today / since yesterday), last_7d, last_30d, last_90d, ytd (since 1 January UTC), or all. Omit for all time." - changed
Input schema / properties / profile / descriptionPrevious value: -"Which portfolio to read, by name or id, for accounts that have more than one. Omit to use this connection's default. Call list_profiles first if the user names a portfolio you have not seen."New value: +"Which portfolio to read, for accounts with more than one: its id, or its name (exact, case-insensitive, e.g. \"Trading\"). Omit to read this connection's default portfolio; every answer names the portfolio it read in `profile`. An unknown or shared name returns profile_not_found or profile_ambiguous listing the real ones, and list_profiles shows them up front." - changed
Input schema / properties / q / descriptionPrevious value: -"Free-text search over the ledger."New value: +"Free-text substring search (case-insensitive) over asset, transaction id, status and stored details such as an address fragment." - changed
Input schema / properties / source / descriptionPrevious value: -"Filter to one source label."New value: +"Source label as it appears in countsBySource, e.g. \"deposit\" or \"staking\"; comma-separate for several." - changed
Input schema / properties / status / descriptionPrevious value: -"Filter by movement status."New value: +"Status exactly as it appears in countsByStatus. Venue-native and case-sensitive (\"SUCCESS\", \"2\"), so copy it from the facet rather than guessing." - changed
Input schema / properties / venue / descriptionPrevious value: -"Filter to one venue, e.g. \"binance\"."New value: +"Venue name as it appears in countsByVenue, e.g. \"binance\"; comma-separate for several."
- Changed
get_pnl_by_symbol4 fields changed- changed
Input schema / properties / limit / descriptionPrevious value: -"Maximum rows to return (capped at 200)."New value: +"How many of the best AND how many of the worst pairs to return, 1-100. Up to twice this many rows come back, best first; with fewer pairs than that, every pair comes back. Defaults to 20 (the 20 best and the 20 worst)." - changed
Input schema / properties / limit / maximumPrevious value: -200New value: +100 - changed
Input schema / properties / profile / descriptionPrevious value: -"Which portfolio to read, by name or id, for accounts that have more than one. Omit to use this connection's default. Call list_profiles first if the user names a portfolio you have not seen."New value: +"Which portfolio to read, for accounts with more than one: its id, or its name (exact, case-insensitive, e.g. \"Trading\"). Omit to read this connection's default portfolio; every answer names the portfolio it read in `profile`. An unknown or shared name returns profile_not_found or profile_ambiguous listing the real ones, and list_profiles shows them up front." - changed
Input schema / properties / quote / descriptionPrevious value: -"Quote currency to report in, e.g. \"USDT\"."New value: +"Quote currency whose pairs to rank, e.g. \"USDT\" for BTCUSDT and ETHUSDT. Defaults to USDT."
- Changed
get_pnl_overview2 fields changed- changed
Input schema / properties / period / descriptionPrevious value: -"Time window. \"last_24h\" for today/since-yesterday, \"all\" for full history. Defaults to the endpoint's own default (usually last 30 days)."New value: +"Time window ending now: last_24h (today / since yesterday), last_7d, last_30d, last_90d, ytd (since 1 January UTC), or all. Omit for all time." - changed
Input schema / properties / profile / descriptionPrevious value: -"Which portfolio to read, by name or id, for accounts that have more than one. Omit to use this connection's default. Call list_profiles first if the user names a portfolio you have not seen."New value: +"Which portfolio to read, for accounts with more than one: its id, or its name (exact, case-insensitive, e.g. \"Trading\"). Omit to read this connection's default portfolio; every answer names the portfolio it read in `profile`. An unknown or shared name returns profile_not_found or profile_ambiguous listing the real ones, and list_profiles shows them up front."
- Changed
get_portfolio1 field changed- changed
Input schema / properties / profile / descriptionPrevious value: -"Which portfolio to read, by name or id, for accounts that have more than one. Omit to use this connection's default. Call list_profiles first if the user names a portfolio you have not seen."New value: +"Which portfolio to read, for accounts with more than one: its id, or its name (exact, case-insensitive, e.g. \"Trading\"). Omit to read this connection's default portfolio; every answer names the portfolio it read in `profile`. An unknown or shared name returns profile_not_found or profile_ambiguous listing the real ones, and list_profiles shows them up front."
- Changed
get_portfolio_history3 fields changed- changed
Input schema / properties / period / descriptionPrevious value: -"Time window. \"last_24h\" for today/since-yesterday, \"all\" for full history. Defaults to the endpoint's own default (usually last 30 days)."New value: +"Time window ending now: last_24h (today / since yesterday), last_7d, last_30d, last_90d, ytd (since 1 January UTC), or all. Omit for all time." - changed
Input schema / properties / profile / descriptionPrevious value: -"Which portfolio to read, by name or id, for accounts that have more than one. Omit to use this connection's default. Call list_profiles first if the user names a portfolio you have not seen."New value: +"Which portfolio to read, for accounts with more than one: its id, or its name (exact, case-insensitive, e.g. \"Trading\"). Omit to read this connection's default portfolio; every answer names the portfolio it read in `profile`. An unknown or shared name returns profile_not_found or profile_ambiguous listing the real ones, and list_profiles shows them up front." - changed
Input schema / properties / slim / descriptionPrevious value: -"true (recommended) drops the per-asset breakdown and returns only the daily totals."New value: +"true (recommended) returns only the daily totals; false or omitted adds byAsset values and quantities for every asset on every day."
- Changed
get_portfolio_score2 fields changed- removed
Input schema / properties / periodRemoved value: -{ - "description": "Time window. \"last_24h\" for today/since-yesterday, \"all\" for full history. Defaults to the endpoint's own default (usually last 30 days).", - "enum": [ - "last_24h", - "last_7d", - "last_30d", - "last_90d", - "ytd", - "all" - ], - "type": "string" -} - changed
Input schema / properties / profile / descriptionPrevious value: -"Which portfolio to read, by name or id, for accounts that have more than one. Omit to use this connection's default. Call list_profiles first if the user names a portfolio you have not seen."New value: +"Which portfolio to read, for accounts with more than one: its id, or its name (exact, case-insensitive, e.g. \"Trading\"). Omit to read this connection's default portfolio; every answer names the portfolio it read in `profile`. An unknown or shared name returns profile_not_found or profile_ambiguous listing the real ones, and list_profiles shows them up front."
- Changed
get_portfolio_snapshot1 field changed- changed
Input schema / properties / profile / descriptionPrevious value: -"Which portfolio to read, by name or id, for accounts that have more than one. Omit to use this connection's default. Call list_profiles first if the user names a portfolio you have not seen."New value: +"Which portfolio to read, for accounts with more than one: its id, or its name (exact, case-insensitive, e.g. \"Trading\"). Omit to read this connection's default portfolio; every answer names the portfolio it read in `profile`. An unknown or shared name returns profile_not_found or profile_ambiguous listing the real ones, and list_profiles shows them up front."
- Changed
get_risk_metrics3 fields changed- changed
Input schema / properties / benchmark / descriptionPrevious value: -"Benchmark for beta and correlation. Defaults to BTC."New value: +"Asset to measure beta, correlation and excess return against. Defaults to BTC." - changed
Input schema / properties / period / descriptionPrevious value: -"Time window. \"last_24h\" for today/since-yesterday, \"all\" for full history. Defaults to the endpoint's own default (usually last 30 days)."New value: +"Time window ending now: last_24h (today / since yesterday), last_7d, last_30d, last_90d, ytd (since 1 January UTC), or all. Omit for all time." - changed
Input schema / properties / profile / descriptionPrevious value: -"Which portfolio to read, by name or id, for accounts that have more than one. Omit to use this connection's default. Call list_profiles first if the user names a portfolio you have not seen."New value: +"Which portfolio to read, for accounts with more than one: its id, or its name (exact, case-insensitive, e.g. \"Trading\"). Omit to read this connection's default portfolio; every answer names the portfolio it read in `profile`. An unknown or shared name returns profile_not_found or profile_ambiguous listing the real ones, and list_profiles shows them up front."
- Changed
get_sync_status1 field changed- changed
Input schema / properties / profile / descriptionPrevious value: -"Which portfolio to read, by name or id, for accounts that have more than one. Omit to use this connection's default. Call list_profiles first if the user names a portfolio you have not seen."New value: +"Which portfolio to read, for accounts with more than one: its id, or its name (exact, case-insensitive, e.g. \"Trading\"). Omit to read this connection's default portfolio; every answer names the portfolio it read in `profile`. An unknown or shared name returns profile_not_found or profile_ambiguous listing the real ones, and list_profiles shows them up front."
- Changed
get_target_allocation1 field changed- changed
Input schema / properties / profile / descriptionPrevious value: -"Which portfolio to read, by name or id, for accounts that have more than one. Omit to use this connection's default. Call list_profiles first if the user names a portfolio you have not seen."New value: +"Which portfolio to read, for accounts with more than one: its id, or its name (exact, case-insensitive, e.g. \"Trading\"). Omit to read this connection's default portfolio; every answer names the portfolio it read in `profile`. An unknown or shared name returns profile_not_found or profile_ambiguous listing the real ones, and list_profiles shows them up front."
- Changed
get_transfers1 field changed- changed
Input schema / properties / profile / descriptionPrevious value: -"Which portfolio to read, by name or id, for accounts that have more than one. Omit to use this connection's default. Call list_profiles first if the user names a portfolio you have not seen."New value: +"Which portfolio to read, for accounts with more than one: its id, or its name (exact, case-insensitive, e.g. \"Trading\"). Omit to read this connection's default portfolio; every answer names the portfolio it read in `profile`. An unknown or shared name returns profile_not_found or profile_ambiguous listing the real ones, and list_profiles shows them up front."
- Changed
get_venues1 field changed- changed
Input schema / properties / profile / descriptionPrevious value: -"Which portfolio to read, by name or id, for accounts that have more than one. Omit to use this connection's default. Call list_profiles first if the user names a portfolio you have not seen."New value: +"Which portfolio to read, for accounts with more than one: its id, or its name (exact, case-insensitive, e.g. \"Trading\"). Omit to read this connection's default portfolio; every answer names the portfolio it read in `profile`. An unknown or shared name returns profile_not_found or profile_ambiguous listing the real ones, and list_profiles shows them up front."
- Changed
get_wallets1 field changed- changed
Input schema / properties / profile / descriptionPrevious value: -"Which portfolio to read, by name or id, for accounts that have more than one. Omit to use this connection's default. Call list_profiles first if the user names a portfolio you have not seen."New value: +"Which portfolio to read, for accounts with more than one: its id, or its name (exact, case-insensitive, e.g. \"Trading\"). Omit to read this connection's default portfolio; every answer names the portfolio it read in `profile`. An unknown or shared name returns profile_not_found or profile_ambiguous listing the real ones, and list_profiles shows them up front."
- Changed
set_target_allocation1 field changed- changed
Input schema / properties / profile / descriptionPrevious value: -"Which portfolio to read, by name or id, for accounts that have more than one. Omit to use this connection's default. Call list_profiles first if the user names a portfolio you have not seen."New value: +"Which portfolio to read, for accounts with more than one: its id, or its name (exact, case-insensitive, e.g. \"Trading\"). Omit to read this connection's default portfolio; every answer names the portfolio it read in `profile`. An unknown or shared name returns profile_not_found or profile_ambiguous listing the real ones, and list_profiles shows them up front."
26 tool updates
- First observed
get_activity_calendar - First observed
get_alerts - First observed
get_asset_trade_stats - First observed
get_capital_flow - First observed
get_changes - First observed
get_dashboard - First observed
get_deposits - First observed
get_fees - First observed
get_fiat_stats - First observed
get_income_by_source - First observed
get_income_timeseries - First observed
get_movements - First observed
get_pnl_by_symbol - First observed
get_pnl_overview - First observed
get_portfolio - First observed
get_portfolio_history - First observed
get_portfolio_score - First observed
get_portfolio_snapshot - First observed
get_risk_metrics - First observed
get_sync_status - First observed
get_target_allocation - First observed
get_transfers - First observed
get_venues - First observed
get_wallets - First observed
list_profiles - First observed
set_target_allocation
Publisher details
- Operator
- WhereItGoes
- Operator website
- https://whereitgoes.money
- Vendor relationship
- First-party
- Documentation
- https://whereitgoes.money/connect-ai · Publisher source
- Trust center
- Not available
- Restrictions
- Requires a free WhereItGoes account (sign in with Google or a wallet). Read-only; one optional propose-only tool needs a separate consent scope.
Related MCP Connectors
Connect your portfolio to Claude, ChatGPT, or Codex to analyze it and make smarter investments.
Read-only crypto and traditional portfolio: holdings, PNL, FIFO tax figures and market data.
- Era ContextOAuthapp.era
Personal finance, bank account, and shared memory connector for Claude, ChatGPT, Gemini Spark & more
Ask your AI about your own accounts, debts, budgets and goals. OAuth sign-in, read-only by default.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceTransforms Claude AI into a personal crypto portfolio analyst, enabling wallet analysis, AI-powered recommendations, and portfolio tracking across 8+ blockchains through natural conversation.MIT
- AlicenseAqualityDmaintenanceConnects Claude Desktop to crypto and brokerage portfolio data via Coinbase and SnapTrade, providing read-only tools to inspect accounts, holdings, prices, and provider health.5MIT
- AlicenseNot gradedqualityDmaintenanceCost basis tracking, capital gains calculation, and 1099-DA reconciliation for Claude, built on top of the Crypto Portfolio MCP data layer.MIT
- AlicenseNot gradedqualityBmaintenanceRead-only INDmoney portfolio access for Claude — Indian stocks, mutual funds, US stocks, gold, credit cards, loans, and Experian credit score. OTP browser login with AES-256-GCM encrypted sessions.MIT
Glama MCP Gateway
Add one secure layer between your agents and this server.