Banking Assistant (Metabind demo)
Demo personal-finance MCP App: spending, subscriptions, and net worth as interactive UI.
Should I use this
Quality & Safety
Based on automated analysis of tool definitions and protocol compliance.
Context Cost
This is the approximate number of tokens consumed each time the server's tools are loaded into a model's context. Higher counts reduce the attention available for other tasks.
Install
One-Click Install
Add this to your `claude_desktop_config.json` file:
{
"mcpServers": {
"banking-assistant": {
"url": "https://mcp.metabind.ai/IgJH0BzIn4LlfnCbcDc7/projects/GLbHk5i3GLlIYcF63XFl"
}
}
}Remote endpoints
https://mcp.metabind.ai/IgJH0BzIn4LlfnCbcDc7/projects/GLbHk5i3GLlIYcF63XFlstreamable-httpWhat it can do
Tool inventory
Tools (9)
🟢get_net_worth(summary, period, groupBy, endDate, startDate)
Net worth history + account balances. Numbers to reason with — to display, use net_worth_trend.
Input Schema
{
"type": "object",
"properties": {
"summary": {
"type": "boolean",
"description": "Omit the `points` series and return only the headline figures and accounts. Use this when you want the numbers to comment on rather than to chart — it is a fraction of the size of a full result.",
"default": false
},
"period": {
"description": "How far back the trend goes. Ignored when startDate/endDate are given.",
"default": "1y",
"type": "string",
"enum": [
"7d",
"30d",
"mtd",
"lastMonth",
"3mo",
"6mo",
"ytd",
"1y",
"all"
]
},
"groupBy": {
"description": "Granularity of the returned series. Each point carries that period's CLOSING balance. 'auto' picks a readable granularity for the span; set it explicitly to compare periods against each other — 'year' over a two-year range gives one point per year, 'month' gives one per month.",
"default": "auto",
"type": "string",
"enum": [
"auto",
"day",
"week",
"month",
"quarter",
"year"
]
},
"endDate": {
"type": "string",
"description": "Range end, YYYY-MM-DD. Defaults to today."
},
"startDate": {
"type": "string",
"description": "Range start, YYYY-MM-DD. Defaults to a year before endDate."
}
},
"additionalProperties": false
}Output Schema
{
"type": "object",
"properties": {
"change_pct": {
"type": "number"
},
"income": {
"type": "number"
},
"periodLabel": {
"type": "string"
},
"period": {
"type": "string"
},
"endDate": {
"type": "string"
},
"saved": {
"type": "number"
},
"change": {
"type": "number"
},
"start": {
"type": "number"
},
"groupBy": {
"type": "string"
},
"points": {
"type": "array",
"items": {
"type": "object",
"properties": {
"value": {
"type": "number"
},
"full": {
"type": "string"
},
"label": {
"type": "string"
}
},
"additionalProperties": false
}
},
"current": {
"type": "number"
},
"spending": {
"type": "number"
},
"accounts": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"balance": {
"type": "number"
},
"type": {
"type": "string"
}
},
"additionalProperties": false
}
},
"startDate": {
"type": "string"
}
},
"additionalProperties": false
}🟢get_spending_breakdown(summary, period)
Categorized spending + prior-period comparison. Numbers to reason with — to display, use spending_breakdown.
Input Schema
{
"type": "object",
"properties": {
"summary": {
"type": "boolean",
"description": "Drop each category's top_merchants list and return only the headline totals and per-category amounts. Use this when you want the numbers to comment on rather than to chart.",
"default": false
},
"period": {
"description": "Spending window.",
"default": "mtd",
"type": "string",
"enum": [
"7d",
"30d",
"mtd",
"lastMonth",
"3mo",
"6mo",
"ytd",
"1y",
"all"
]
}
},
"additionalProperties": false
}Output Schema
{
"type": "object",
"properties": {
"total_spend": {
"type": "number"
},
"periodLabel": {
"type": "string"
},
"total_income": {
"type": "number"
},
"period": {
"type": "string"
},
"comparison": {
"type": "object",
"properties": {
"prev_period_spend": {
"type": "number"
},
"change_pct": {
"type": "number"
}
},
"additionalProperties": false
},
"groups": {
"type": "array",
"items": {
"type": "object",
"properties": {
"amount": {
"type": "number"
},
"change_vs_prev_pct": {
"type": "number"
},
"icon": {
"type": "string"
},
"transaction_count": {
"type": "integer"
},
"name": {
"type": "string"
},
"change_vs_prev": {
"type": "number"
},
"top_merchants": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"amount": {
"type": "number"
}
},
"additionalProperties": false
}
},
"pct_of_total": {
"type": "number"
}
},
"additionalProperties": false
}
},
"net": {
"type": "number"
}
},
"additionalProperties": false
}🟢get_subscriptions(status)
Recurring-charge detection. Numbers to reason with — to display, use the subscriptions card.
Input Schema
{
"type": "object",
"properties": {
"status": {
"description": "Which subscriptions to include.",
"default": "active",
"type": "string",
"enum": [
"active",
"all"
]
}
},
"additionalProperties": false
}Output Schema
{
"type": "object",
"properties": {
"count": {
"type": "integer"
},
"subscriptions": {
"type": "array",
"items": {
"type": "object",
"properties": {
"next_charge": {
"type": "string"
},
"amount": {
"type": "number"
},
"is_new": {
"type": "boolean"
},
"price_change_pct": {
"type": "number"
},
"name": {
"type": "string"
},
"category": {
"type": "string"
},
"cadence": {
"type": "string"
},
"status": {
"type": "string"
},
"monthly_equiv": {
"type": "number"
}
},
"additionalProperties": false
}
},
"total_monthly": {
"type": "number"
},
"new_count": {
"type": "integer"
}
},
"additionalProperties": false
}🟢get_transactions(period, endDate, limit, merchant, sort, ...)
Raw transactions by category or merchant, ~12 months of history. Numbers to reason with — to display, use transaction_list.
Input Schema
{
"type": "object",
"properties": {
"period": {
"description": "Time window. Ignored when startDate/endDate are given. The feed covers ~25 months, so a 1y window has a full prior year to compare against.",
"default": "mtd",
"type": "string",
"enum": [
"7d",
"30d",
"mtd",
"lastMonth",
"3mo",
"6mo",
"ytd",
"1y",
"all"
]
},
"endDate": {
"type": "string",
"description": "Window end, YYYY-MM-DD. Defaults to today."
},
"limit": {
"maximum": 200,
"description": "Max transactions to return. Pass 0 for totals and counts only — much cheaper when you need the figures to reason with rather than to list.",
"default": 20,
"type": "integer",
"minimum": 0
},
"merchant": {
"type": "string",
"description": "Single store or brand to filter by, e.g. 'Whole Foods', 'Netflix', 'Shell'. Combine with category to narrow further."
},
"sort": {
"description": "'recent' is newest-first and is what a plain list wants. Use 'largest' for \"my biggest transactions\" — a window can hold hundreds of rows, so date order buries them.",
"default": "recent",
"type": "string",
"enum": [
"recent",
"largest"
]
},
"category": {
"type": "string",
"description": "Category or plain term to filter by, e.g. 'Food & Dining', 'restaurants', 'rent', 'gas', 'income'. A merchant name here is resolved as a merchant. Omit or leave empty for all categories."
},
"startDate": {
"type": "string",
"description": "Window start, YYYY-MM-DD. Defaults to 30 days before endDate."
}
},
"additionalProperties": false
}Output Schema
{
"type": "object",
"properties": {
"total_spent": {
"type": "number"
},
"periodLabel": {
"type": "string"
},
"shown": {
"type": "integer"
},
"standouts": {
"type": "array",
"items": {
"type": "object",
"properties": {
"typical": {
"type": "number"
},
"date": {
"type": "string"
},
"merchant": {
"type": "string"
},
"amount": {
"type": "number"
},
"category": {
"type": "string"
},
"vs_typical_pct": {
"type": "number"
}
},
"additionalProperties": false
}
},
"count": {
"type": "integer"
},
"change_vs_prev_pct": {
"type": "number"
},
"transactions": {
"type": "array",
"items": {
"type": "object",
"properties": {
"date": {
"type": "string"
},
"amount": {
"type": "number"
},
"vs_typical_pct": {
"type": "number"
},
"merchant": {
"type": "string"
},
"category": {
"type": "string"
},
"items": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"total": {
"type": "number"
},
"price": {
"type": "number"
},
"qty": {
"type": "integer"
}
},
"additionalProperties": false
}
},
"account": {
"type": "string"
}
},
"additionalProperties": false
}
},
"category": {
"type": "string"
},
"top_items": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"total": {
"type": "number"
},
"qty": {
"type": "integer"
}
},
"additionalProperties": false
}
}
},
"additionalProperties": false
}🟢net_worth_trend(nextSteps, note, period, chartStyle, endDate, ...)
Render net_worth_trend: Net worth: current total, change over the period, a trend chart, and the account balances behind it. It loads its own data. To compare periods against each other pass chartStyle:'bar' plus groupBy ('year' for this-year-vs-last-year, 'month' for month-by-month) — each bar is that period's closing balance.
Input Schema
{
"type": "object",
"properties": {
"nextSteps": {
"type": "array",
"description": "One short follow-up the user might ask next, in the form icon|question — 'calendar|Show me last month'. Phrase the question the way the user would say it, and take the icon from the table in the app instructions; any other name renders blank. Always supply 2-3. The card itself ignores them.",
"items": {
"type": "string"
}
},
"note": {
"type": "string",
"description": "Usually omit this. Optional one-line insight rendered inside the card. Only pass it when you ALREADY have the figures in hand from a call you made for another reason — never make an extra tool call just to write a note, because that round trip delays the card itself. When you do add one, say something the card does not already show (what drove a change, what to watch), in one sentence, and never guess a number.",
"default": ""
},
"period": {
"type": "string",
"description": "Window: 7d, 30d, mtd (this month so far), lastMonth (the whole previous calendar month), 3mo, 6mo, ytd, 1y or all. Ignored when startDate/endDate are given. Defaults to 1y.",
"default": ""
},
"chartStyle": {
"description": "'bar' compares periods against each other as closing balances; 'line' is the continuous history.",
"default": "line",
"type": "string",
"enum": [
"line",
"bar"
]
},
"endDate": {
"type": "string",
"default": ""
},
"groupBy": {
"description": "One bar/point per period, carrying that period's closing balance. Set it to compare periods: 'year' for \"this year vs last year\", 'month' for \"month by month\", 'quarter' for \"by quarter\". Leave auto for a plain trend.",
"default": "auto",
"type": "string",
"enum": [
"auto",
"day",
"week",
"month",
"quarter",
"year"
]
},
"startDate": {
"type": "string",
"default": ""
}
},
"description": "Net worth: current total, change over the period, a trend chart, and the account balances behind it. It loads its own data. To compare periods against each other pass chartStyle:'bar' plus groupBy ('year' for this-year-vs-last-year, 'month' for month-by-month) — each bar is that period's closing balance."
}🟢spending_breakdown(nextSteps, note, highlight, period, drillPrompt)
Render spending_breakdown: Spending split by category for a period: a composition bar plus a ranked category list. It loads its own data — pass the period alone for the whole picture, which is what a broad 'where did my money go' question wants. Use highlight only on a follow-up about particular categories; it dims everything else, so on an opening question it hides most of the answer.
Input Schema
{
"type": "object",
"properties": {
"nextSteps": {
"type": "array",
"description": "One short follow-up the user might ask next, in the form icon|question — 'calendar|Show me last month'. Phrase the question the way the user would say it, and take the icon from the table in the app instructions; any other name renders blank. Always supply 2-3. The card itself ignores them.",
"items": {
"type": "string"
}
},
"note": {
"type": "string",
"description": "Usually omit this. Optional one-line insight rendered inside the card. Only pass it when you ALREADY have the figures in hand from a call you made for another reason — never make an extra tool call just to write a note, because that round trip delays the card itself. When you do add one, say something the card does not already show (what drove a change, what to watch), in one sentence, and never guess a number.",
"default": ""
},
"highlight": {
"type": "array",
"description": "OMIT THIS unless the user asked about specific categories. Leaving it empty is the normal, correct view: the whole picture, nothing dimmed. A broad opening question — 'where did my money go', 'show me my spending', 'how did I do this month' — wants the whole picture, so pass period alone. Only emphasise on a FOLLOW-UP that is genuinely about particular categories ('what should I cut', 'is dining out of hand', 'why is it higher than last month'), where you name them: ['Food & Dining','Subscriptions']. Everything else then dims and the hero reports their combined total. Matching is forgiving ('dining' finds 'Food & Dining').",
"items": {
"type": "string"
}
},
"period": {
"type": "string",
"description": "Window: 7d, 30d, mtd (this month so far), lastMonth (the whole previous calendar month), 3mo, 6mo, ytd, 1y or all.",
"default": "mtd"
},
"drillPrompt": {
"type": "string",
"description": "What tapping a category should ask, when the question had an angle worth carrying. Write it as the user would say it and put {category} where the name goes: 'Show me the odd {category} transactions', 'Where can I cut back on {category}?'. Set it when the card answers something pointed — unusual spending, what to cut, why something moved — so the follow-up inherits that instead of resetting to a plain list. Omit it for a broad 'where did my money go', where a plain list is what a tap should give.",
"default": ""
}
},
"description": "Spending split by category for a period: a composition bar plus a ranked category list. It loads its own data — pass the period alone for the whole picture, which is what a broad 'where did my money go' question wants. Use highlight only on a follow-up about particular categories; it dims everything else, so on an opening question it hides most of the answer."
}🟢subscriptions(nextSteps, note, view, views, status)
Render subscriptions: Recurring charges: total monthly cost and a row per subscription with its cadence, next charge date, and New / price-increase flags. It loads its own data.
Input Schema
{
"type": "object",
"properties": {
"nextSteps": {
"type": "array",
"description": "One short follow-up the user might ask next, in the form icon|question — 'calendar|Show me last month'. Phrase the question the way the user would say it, and take the icon from the table in the app instructions; any other name renders blank. Always supply 2-3. The card itself ignores them.",
"items": {
"type": "string"
}
},
"note": {
"type": "string",
"description": "Usually omit this. Optional one-line insight rendered inside the card. Only pass it when you ALREADY have the figures in hand from a call you made for another reason — never make an extra tool call just to write a note, because that round trip delays the card itself. When you do add one, say something the card does not already show (what drove a change, what to watch), in one sentence, and never guess a number.",
"default": ""
},
"view": {
"description": "Which cut to open on. 'all' is every recurring charge, biggest first — the answer to 'what am I paying for'. 'repriced' is only the ones whose price moved, which is what 'which went up' asks. 'new' is only the recently started. 'unusual' is both of those together, for a general 'anything odd'. Match the cut to the question: a price question answered with the full list makes the user hunt for the answer. The header keeps reporting the full count, so narrowing hides nothing.",
"default": "all",
"type": "string",
"enum": [
"all",
"unusual",
"new",
"repriced"
]
},
"views": {
"type": "array",
"items": {
"type": "string",
"enum": [
"all",
"unusual",
"new",
"repriced"
]
},
"description": "Which cuts to offer as segments. Omit and the card offers All alongside whichever cut you opened on. Pair the specific cut with 'all' so the user can get back to the full picture — ['all','repriced'] for a price question, ['all','new'] for a what's-new one."
},
"status": {
"description": "'active' lists current subscriptions; 'all' also includes recently cancelled ones.",
"default": "active",
"type": "string",
"enum": [
"active",
"all"
]
}
},
"description": "Recurring charges: total monthly cost and a row per subscription with its cadence, next charge date, and New / price-increase flags. It loads its own data."
}🟢transaction_list(nextSteps, note, view, period, endDate, ...)
Render transaction_list: Individual purchases for a category or a merchant: the window total plus the matching transactions. It loads its own data. Plain terms like 'restaurants', 'groceries' or 'gas' resolve to categories; omit both filters for all spending. Do NOT use this when the user asks how much they spent over the last 3, 6 or 12 months — that is a period comparison, so use trend_card with chartStyle:'bar' instead.
Input Schema
{
"type": "object",
"properties": {
"nextSteps": {
"type": "array",
"description": "One short follow-up the user might ask next, in the form icon|question — 'calendar|Show me last month'. Phrase the question the way the user would say it, and take the icon from the table in the app instructions; any other name renders blank. Always supply 2-3. The card itself ignores them.",
"items": {
"type": "string"
}
},
"note": {
"type": "string",
"description": "Usually omit this. Optional one-line insight rendered inside the card. Only pass it when you ALREADY have the figures in hand from a call you made for another reason — never make an extra tool call just to write a note, because that round trip delays the card itself. When you do add one, say something the card does not already show (what drove a change, what to watch), in one sentence, and never guess a number.",
"default": ""
},
"view": {
"description": "Which cut of the window to open on. 'recent' is newest-first, the plain list. 'largest' leads with the biggest charges. 'unusual' shows only the charges well above what that merchant or category normally costs — this is the answer to \"anything odd this month\", not a spending breakdown. The user can switch between the offered cuts on the card without asking again, so pick the one that answers the question and leave the rest to them. Use `views` to change which cuts are offered.",
"default": "recent",
"type": "string",
"enum": [
"recent",
"largest",
"unusual"
]
},
"period": {
"type": "string",
"description": "Window: 7d, 30d, mtd (this month so far), lastMonth (the whole previous calendar month), 3mo, 6mo, ytd, 1y or all. Ignored when startDate/endDate are given. Defaults to mtd.",
"default": ""
},
"endDate": {
"type": "string",
"description": "Window end, YYYY-MM-DD.",
"default": ""
},
"limit": {
"description": "Max transactions to load. Raise past the default 20 only if the user wants the full list.",
"default": 0,
"type": "integer"
},
"merchant": {
"type": "string",
"description": "Single store or brand, e.g. 'Whole Foods', 'Netflix'.",
"default": ""
},
"category": {
"type": "string",
"description": "Category or plain term, e.g. 'Food & Dining', 'restaurants', 'rent', 'gas'. Omit for all categories.",
"default": ""
},
"views": {
"type": "array",
"description": "Which cuts to offer as segments on the card. Omit for all three, which is usually right — the user can then explore without asking again. Narrow it only when a cut would be meaningless for what was asked: a single-merchant list has little to call unusual, and a one-week window has little to rank. Listing a single cut drops the control entirely and renders a plain list, so use that when the question has exactly one sensible answer.",
"items": {
"type": "string",
"enum": [
"recent",
"largest",
"unusual"
]
}
},
"startDate": {
"type": "string",
"description": "Window start, YYYY-MM-DD.",
"default": ""
}
},
"description": "Individual purchases for a category or a merchant: the window total plus the matching transactions. It loads its own data. Plain terms like 'restaurants', 'groceries' or 'gas' resolve to categories; omit both filters for all spending. Do NOT use this when the user asks how much they spent over the last 3, 6 or 12 months — that is a period comparison, so use trend_card with chartStyle:'bar' instead."
}🟢trend_card(change_pct, note, periodLabel, change, start, ...)
Render trend_card: Any metric over time that has no dedicated card — one category's spend by month, a series you computed. Points are {label, value} in display order. Set upIsGood=false for cost-like metrics. Use chartStyle:'bar' whenever the user compares periods — month by month, or over the last 3/6/12 months; give each point a `series` name (repeating the label once per series) to stack them with a legend. Pass `items` to list the composition behind the number.
Input Schema
{
"type": "object",
"properties": {
"change_pct": {
"type": "number",
"default": 0
},
"note": {
"type": "string",
"description": "Usually omit this. Optional one-line insight rendered inside the card. Only pass it when you ALREADY have the figures in hand from a call you made for another reason — never make an extra tool call just to write a note, because that round trip delays the card itself. When you do add one, say something the card does not already show (what drove a change, what to watch), in one sentence, and never guess a number.",
"default": ""
},
"periodLabel": {
"type": "string",
"default": "Past 12 months"
},
"change": {
"type": "number",
"description": "The change over the period, in the same unit as `current`. Send it together with `start` whenever you have them: the card leads with this figure, and left out it has to work back from `change_pct`, which is close but not the real number.",
"default": 0
},
"start": {
"type": "number",
"default": 0
},
"valueFormat": {
"description": "How the hero value and change are formatted.",
"default": "currency",
"type": "string",
"enum": [
"currency",
"number"
]
},
"upIsGood": {
"type": "boolean",
"description": "false for cost-like metrics: an increase renders red, a decrease green.",
"default": true
},
"title": {
"type": "string",
"default": "Trend"
},
"points": {
"type": "array",
"items": {
"type": "object",
"properties": {
"value": {
"type": "number"
},
"series": {
"type": "string"
},
"label": {
"type": "string"
}
}
}
},
"nextSteps": {
"type": "array",
"items": {
"type": "string"
},
"description": "One short follow-up the user might ask next, in the form icon|question — 'calendar|Show me last month'. Phrase the question the way the user would say it, and take the icon from the table in the app instructions; any other name renders blank. Always supply 2-3. The card itself ignores them."
},
"current": {
"type": "number",
"default": 0
},
"chartStyle": {
"description": "'bar' draws discrete bars on a labelled x axis — better for comparing periods against each other, and the only style that stacks series. 'line' is the continuous trend.",
"default": "line",
"type": "string",
"enum": [
"line",
"bar"
]
},
"valueSuffix": {
"type": "string",
"description": "Optional unit appended to values, e.g. ' subs' or '/mo'.",
"default": ""
},
"items": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"detail": {
"type": "string"
},
"color": {
"type": "string"
},
"value": {
"type": "number"
},
"prompts": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"description": "Optional rows under the chart — the composition behind the number (accounts behind a net worth, categories behind a month's spend). Each is { name, detail, value, color?, prompts? }. `color` is a named colour for the dot ('blue', 'green', …); omit it and rows are coloured in order. `prompts` are follow-up questions offered when the row is tapped — each string is shown as the menu label AND sent to the assistant verbatim, so keep them short and self-contained ('How has my Brokerage changed?', not 'changed?'). OMIT `prompts` unless a row needs something its name cannot imply: left out, the card builds its own drill-down from `name`, which saves you writing the same sentence once per row."
}
},
"description": "Any metric over time that has no dedicated card — one category's spend by month, a series you computed. Points are {label, value} in display order. Set upIsGood=false for cost-like metrics. Use chartStyle:'bar' whenever the user compares periods — month by month, or over the last 3/6/12 months; give each point a `series` name (repeating the label once per series) to stack them with a legend. Pass `items` to list the composition behind the number."
}Community
Evidence