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
- Uptime
- 100.0% over the last 24 hours
- OAuth
- Works in Glama
- Last Tested
- Transport
- Streamable HTTP · MCP 2025-11-25
- URL
- Repository
- khapham7165/whereitgoes-mcp
- GitHub Stars
- 1
- Server Listing
- WhereItGoes MCP server
- ChatGPT
- –
- Claude
- –
TDQS
Scored across 15 tools
Most tools target distinct analytical questions, and descriptions actively disambiguate by cross-referencing siblings (e.g. get_changes says 'for profit use get_performance, for money in and out use get_money_flows'). However, the read side has a dense cluster of overlapping financial-reporting tools (get_changes, get_movements, get_trading_activity, get_performance, get_money_flows, get_income, get_fees) that an agent could easily misselect without parsing long descriptions.
The dominant pattern is get_* for reads, with list_profiles and two write tools breaking it. The bigger inconsistency is semantic: set_target_allocation and propose_alert_change behave identically (both return an approval link and do not apply), yet one is named 'set' and the other 'propose', which is misleading.
15 tools is well within a healthy range for a portfolio analytics server, and each earns its place by covering a distinct analytical dimension (performance, risk, fees, income, flows, movements, alerts, targets). No obvious redundancy or padding.
The read surface is thorough (portfolio, performance, risk, fees, income, flows, movements, trading, connections, alerts, targets) and both write domains (alerts, target allocation) have propose-based lifecycle coverage. Gaps are deliberate but real: no way to add exchanges/wallets, no sync trigger, no notification inbox, and partial fee/gas coverage.
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.
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.
Inputs: profile. Returns: error, alerts, message, profile, +5 more
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.
Inputs: period, profile. Returns: error, notes, events, window, +10 more
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". When nothing is connected yet, the answer says so (data_status "nothing_connected") with the app links to add a wallet address or an exchange API key; pass those to the user.
Inputs: view (required), profile. Returns: view, error, message, profile, +8 more
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.
Inputs: bucket, period, profile. Returns: error, notes, bucket, byType, +18 more
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.
Inputs: view (required), bucket, period, profile. Returns: view, error, message, profile, +7 more
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.
Inputs: view (required), bucket, period, profile. Returns: fiat, view, error, message, +9 more
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.
Inputs: q, kind, asset, limit, +5 more. Returns: error, items, total, message, +12 more
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.
Inputs: view (required), slim, limit, quote, +2 more. Returns: pnl, view, error, history, +8 more
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. A new account may have nothing connected: the answer is then data_status "nothing_connected" with a link to add a wallet address or exchange in the app, not a $0 portfolio.
Inputs: view (required), profile. Returns: view, error, message, profile, +8 more
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.
Inputs: view (required), period, profile, benchmark. Returns: view, error, score, message, +7 more
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.
Inputs: profile. Returns: set, error, message, profile, +5 more
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.
Inputs: view (required), profile. Returns: view, error, message, profile, +7 more
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.
Inputs: no named parameters. Returns: error, items, active, message, +6 more
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.
Inputs: action (required), op, kind, note, +8 more. Returns: error, title, status, message, +9 more
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.
Inputs: dim (required), rows (required), profile. Returns: error, title, status, message, +9 more
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
Related MCP Connectors
Connect your portfolio to Claude, ChatGPT, or Codex to analyze it and make smarter investments.
Read-only access to your own bank, card and brokerage accounts for Claude, ChatGPT and other AI agents: balances, transactions, spending, subscriptions, cashflow and investment holdings. It can never move money.
Read-only crypto and traditional portfolio: holdings, PNL, FIFO tax figures and market data.
Personal finance, bank account, and shared memory connector for Claude, ChatGPT, Gemini Spark & more
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.