MCP Reference
This page is a complete reference for the Bancadia MCP server — every JSON-RPC method it accepts, the two tools it currently routes, and every error it can return. It's written to be equally useful to a human integrating by hand and to an AI agent parsing this page to decide how to call the server.
In short: everything happens through a single endpoint — https://mcp.bancadia.com/. Most calls are a POST whose JSON-RPC method field determines behavior; the same endpoint also accepts GET (a standalone server-push stream) and DELETE (session termination) — see Session management below.
Transport
Every JSON-RPC interaction is sent as POST to https://mcp.bancadia.com/ (root path, trailing slash) with Content-Type: application/json and Accept: application/json, text/event-stream. The server may respond with either a plain application/json body (the common case, and the only mode documented in detail below) or a text/event-stream response carrying the same JSON-RPC object as a single SSE event — spec-compliant clients may request the latter by default, but no tool here emits intermediate progress events, so the two modes are equivalent in practice.
method | Auth required | Session required | Description |
|---|---|---|---|
| initialize | No | No — this call creates the session | MCP lifecycle handshake — protocol/capability negotiation. Must be called first; every other method depends on the session it issues. |
| tools/list | No | Yes | Returns the manifest of callable tools with their JSON Schema. |
| tools/call | Yes (Bearer) | Yes | Invokes a tool by name with arguments. |
| notifications/* | n/a | Yes | Client→server notifications (e.g. notifications/initialized). Any request that omits id entirely is treated as a notification. |
Any other method value, or an unrecognized tool name passed to tools/call, returns a JSON-RPC error with HTTP status 404 and code -32601.
Calling initializefirst is now required. It's the only method that doesn't need an Mcp-Session-Id header — every other method (including notifications) does, since initialize is what issues that session ID in the first place. A request that skips straight to tools/list or tools/call without ever calling initialize fails with 400. See Session management below for the full lifecycle.
Session management
A session is created only by a successful initialize call, returned via the Mcp-Session-Id response header. Every subsequent request on the MCP endpoint — tools/list, tools/call, notifications, GET, DELETE — must echo that same value back as an Mcp-Session-Id request header:
Mcp-Session-Id: 7e93bc81-b832-4c8b-9834-1bac55106e22
Sessions idle-expire after ~30 minutes of inactivity by default (a sliding window — every valid request resets the clock). This is a housekeeping window, not a held-open connection: each call is an ordinary independent HTTP request, and nothing stays open for 30 minutes.
A request missing the Mcp-Session-Id header (on any method other than initialize) gets 400. A request whose session has expired, or was never valid, gets 404 — call initialize again to get a new session. This is the expected, normal way a long-idle client resumes, not an error state to alarm on. See Errors below for the exact status/code combinations.
A client that wants to end its session immediately (e.g. explicit logout) rather than waiting for idle expiry can send DELETE — see below.
Authentication
tools/call requires a bearer token in the Authorization header. Tokens are obtained by registering at bancadia.com/developer/signup.
Authorization: Bearer bcd_YOUR_TOKEN_HERE
A missing header, a header without the Bearer prefix, or an unknown/revoked token all return HTTP 401 with JSON-RPC error code -32001:
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32001,
"message": "Unauthorized. Register at bancadia.com/developer/signup to obtain an API token."
}
}initialize and tools/list do not require a token.
Rate limiting
Successful tools/call requests are subject to a per-token sliding-window rate limit (100 requests / 60s by default). Rate-limit headers are present on every tools/call response, success or 429 — never on initialize, tools/list, /health, or /.well-known/mcp, since only tools/call is rate-limited.
| Header | Description |
|---|---|
| X-RateLimit-Limit | Max requests allowed in the current window |
| X-RateLimit-Remaining | Requests remaining in the current window |
| X-RateLimit-Reset | Unix timestamp (seconds) when the window resets |
Exceeding the limit returns HTTP 429 with JSON-RPC error code -32029:
{
"jsonrpc": "2.0",
"id": 1,
"error": { "code": -32029, "message": "Rate limit exceeded." }
}initialize
The standard MCP lifecycle handshake, and now the mandatory first call — no auth required, but every other method depends on the Mcp-Session-Id it issues. See Session management above.
Request
{
"jsonrpc": "2.0",
"id": 0,
"method": "initialize",
"params": {
"protocolVersion": "2025-06-18",
"capabilities": {},
"clientInfo": { "name": "example-client", "version": "1.0.0" }
}
}Response
{
"jsonrpc": "2.0",
"id": 0,
"result": {
"protocolVersion": "2025-06-18",
"capabilities": { "tools": {} },
"serverInfo": { "name": "Bancadia MCP", "version": "2.0.0" }
}
}The HTTP response also carries an Mcp-Session-Id header — save it, you must send it back on every subsequent request:
Mcp-Session-Id: 7e93bc81-b832-4c8b-9834-1bac55106e22
protocolVersionin the response is the client's requested version if this server supports it (currently 2025-06-18, 2025-03-26, or 2024-11-05), otherwise it falls back to the latest version this server supports rather than rejecting the request. capabilities only ever advertises tools — no resources, prompts, logging, or sampling, and the tool set is static per deployment (no tools.listChanged notifications).
MCP clients typically follow a successful initialize with a notifications/initialized notification — see below.
tools/list
Returns the manifest of callable tools, each with a JSON Schema inputSchema describing its arguments. No bearer token required, but the Mcp-Session-Id from your last initialize call is. Currently returns exactly two tools.
Request
POST https://mcp.bancadia.com/
Content-Type: application/json
Mcp-Session-Id: 7e93bc81-b832-4c8b-9834-1bac55106e22
{ "jsonrpc": "2.0", "id": 1, "method": "tools/list" }Response
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"tools": [
{
"name": "query_business_checking",
"description": "Query the Bancadia registry for business checking account products using compound filter criteria. Returns active, verified listings from financial institutions. Optionally accepts target_industries/target_business_profiles to soft-rank results toward listings built for a given business type or stage — non-matching but eligible listings are still returned, just ranked lower.",
"inputSchema": {
"type": "object",
"properties": {
"monthly_fee_max": { "type": "number", "description": "Maximum monthly fee" },
"minimum_opening_deposit_max": { "type": "number", "description": "Maximum minimum opening deposit" },
"entity_types_accepted": { "type": "array", "items": { "type": "string" }, "description": "Returns listings accepting all specified entity types (e.g. llc, s_corp)" },
"available_states": { "type": "array", "items": { "type": "string" }, "description": "Returns listings available in all specified states" },
"target_industries": { "type": "array", "items": { "type": "string", "enum": ["ecommerce", "retail_storefront", "restaurant_food_service", "content_creator_solopreneur", "professional_services", "real_estate", "healthcare_practice", "construction_trades", "trucking_logistics", "agriculture", "saas_tech", "nonprofit", "small_business_digital_first"] }, "description": "Soft-ranks results toward listings built for these business types. Does not exclude non-matching but otherwise-eligible listings." },
"target_business_profiles": { "type": "array", "items": { "type": "string", "enum": ["early_stage_startup", "vc_backed", "bootstrapped_solopreneur", "established_smb", "high_growth", "side_hustle"] }, "description": "Soft-ranks results toward listings built for this business stage/shape. Does not exclude non-matching but otherwise-eligible listings." },
"insurance_type": { "type": "string", "enum": ["fdic", "ncua", "uninsured"], "description": "Deposit insurance type" },
"cash_deposit_available": { "type": "boolean", "description": "Whether cash deposits are supported" },
"sub_accounts_supported": { "type": "boolean", "description": "Whether sub-accounts are supported" },
"free_transactions_min": { "type": "number", "description": "Minimum free transactions per month" },
"rtp_supported": { "type": "boolean", "description": "Whether real-time payments (any rail) are supported at all" },
"rtp_network": { "type": "string", "enum": ["fednow", "rtp_network", "both", "none"], "description": "Which real-time payment rail is supported" },
"accounting_integration_available": { "type": "boolean", "description": "Whether the account connects to any accounting software (e.g. QuickBooks, Xero)" },
"tax_integration_available": { "type": "boolean", "description": "Whether the account connects to any tax-prep or tax-filing software/service" },
"expense_integration_available": { "type": "boolean", "description": "Whether the account connects to any expense/spend-management software" },
"interest_bearing": { "type": "boolean", "description": "Whether the account earns interest" },
"apy_min": { "type": "number", "description": "Minimum APY (inclusive), for interest-bearing accounts" }
},
"additionalProperties": false
}
},
{
"name": "get_business_checking_listing",
"description": "Get full detail on one specific business checking listing, including gotcha fees (business_deposit_fees, e.g. overdraft, NSF, dormancy) and feature narrative (business_deposit_account_features) not returned by query_business_checking's broad list results. Fees/features that apply to only one plan tier (e.g. a Standard/Plus/Premier ladder) are nested under that tier in plan_tiers[].fees / plan_tiers[].features; tier-agnostic ones are in the top-level general_fees / general_features. Use this as a follow-up after query_business_checking to dig deeper on one listing the caller already identified by its listing_slug.",
"inputSchema": {
"type": "object",
"properties": {
"listing_slug": { "type": "string", "description": "The stable public identifier for the listing, as returned by query_business_checking" }
},
"required": ["listing_slug"],
"additionalProperties": false
}
}
]
}
}A handful of other tool names — query_hysa, query_personal_savings, query_personal_checking, query_personal_cd, query_business_savings, query_business_cd — existed historically and may still be referenced in older material, but they are not currently routed. They don't appear in tools/list or /.well-known/mcp, and calling any of them returns the -32601 Unknown tool error described below. query_business_checking and get_business_checking_listing are the only tools available today.
notifications/initialized and other notifications
Per JSON-RPC 2.0, a request that omits id entirely is a notification and never receives a response body — the server acknowledges it with an empty HTTP 202. This applies to any id-less request, not just notifications/initialized (e.g. notifications/cancelled is handled identically). If your client sends this after a successful initialize, expect a bare 202 with no JSON body — don't try to parse one.
Like every method except initialize, notifications must also include the Mcp-Session-Id header from your last initialize call — omitting it returns 400 instead of 202.
// Request (no "id" field, session header required)
POST https://mcp.bancadia.com/
Content-Type: application/json
Mcp-Session-Id: 7e93bc81-b832-4c8b-9834-1bac55106e22
{ "jsonrpc": "2.0", "method": "notifications/initialized" }
// Response: HTTP 202, empty bodytools/call — query_business_checking
Queries active, verified business checking account listings using compound filter criteria. Requires a bearer token and a valid Mcp-Session-Id header from your last initialize call.
When a user asks to "dig deeper" or "tell me more" about one named result from this tool, prefer calling get_business_checking_listing with that result's listing_slugrather than re-running this broader query — it's cheaper and returns strictly more detail than this tool provides. See below.
Arguments
All filters are optional and combine with AND semantics — every filter you supply must match for a listing to be returned. Array filters (entity_types_accepted, available_states) require every requested value to be present on a listing (i.e. "all of", not "any of"). Unrecognized argument names are rejected (additionalProperties: false).
Two exceptions to that AND-and-exclude model: target_industries and target_business_profiles are soft-rankingsignals, not filters — a listing that doesn't match either one is still returned as long as it passes every other (real, hard) filter. Matching listings are simply reordered ahead of non-matching ones; nothing is excluded on account of these two arguments. See the worked example below the response fields.
| Parameter | Type | Description |
|---|---|---|
| monthly_fee_max | number | Maximum monthly fee. |
| minimum_opening_deposit_max | number | Maximum minimum opening deposit. |
| entity_types_accepted | string[] | Returns listings accepting all specified entity types. Valid values: llc, s_corp, c_corp, sole_prop, partnership, nonprofit. Not enforced server-side — unrecognized values simply never match. |
| available_states | string[] | Returns listings available in all specified states (two-letter codes). A listing whose available_states includes the literal value ALL always matches, regardless of which states are requested. |
| target_industries | string[] | Soft-ranking, not a filter — see the note above. Reorders matching listings ahead of non-matching ones; never excludes. Valid values: ecommerce, retail_storefront, restaurant_food_service, content_creator_solopreneur, professional_services, real_estate, healthcare_practice, construction_trades, trucking_logistics, agriculture, saas_tech, nonprofit, small_business_digital_first. |
| target_business_profiles | string[] | Soft-ranking, not a filter — see the note above. Reorders matching listings ahead of non-matching ones; never excludes. Valid values: early_stage_startup, vc_backed, bootstrapped_solopreneur, established_smb, high_growth, side_hustle. |
| insurance_type | string | Deposit insurance type. One of fdic, ncua, uninsured. |
| cash_deposit_available | boolean | Whether cash deposits are supported. |
| sub_accounts_supported | boolean | Whether sub-accounts are supported. |
| free_transactions_min | number | Minimum free transactions per month. |
| rtp_supported | boolean | Whether real-time payments (any rail) are supported at all. |
| rtp_network | string | Which real-time payment rail is supported. One of fednow, rtp_network, both, none. |
| accounting_integration_available | boolean | Whether the account connects to any accounting software (e.g. QuickBooks, Xero). Category-level only — specific products aren’t filterable. |
| tax_integration_available | boolean | Whether the account connects to any tax-prep or tax-filing software/service. |
| expense_integration_available | boolean | Whether the account connects to any expense/spend-management software. |
| interest_bearing | boolean | Whether the account earns interest. |
| apy_min | number | Minimum APY (inclusive), for interest-bearing accounts. |
Request
POST https://mcp.bancadia.com/
Authorization: Bearer bcd_YOUR_TOKEN_HERE
Content-Type: application/json
Mcp-Session-Id: 7e93bc81-b832-4c8b-9834-1bac55106e22
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "query_business_checking",
"arguments": {
"monthly_fee_max": 0,
"rtp_supported": true,
"rtp_network": "both",
"accounting_integration_available": true,
"entity_types_accepted": ["llc", "s_corp"],
"available_states": ["CA", "NY"],
"target_industries": ["professional_services"]
}
}
}Response
Per the MCP spec, results are wrapped in a content: [{ type: "text", text: "<json-string>" }] block rather than returned as native JSON. text is a JSON-encoded string — your client must JSON.parse(text) to get the actual array of results.
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "[{\"listing_slug\":\"example-bank-business-checking-pro\",\"institution_name\":\"Example Bank\",\"institution\":{\"display_name\":\"Example Bank\",\"website_url\":\"https://examplebank.com\",\"logo_url\":\"https://examplebank.com/logo.png\",\"institution_type\":\"regional_bank\",\"support_email\":\"[email protected]\"},\"product_name\":\"Business Checking Pro\",\"monthly_fee\":0,\"monthly_fee_waiver_condition\":null,\"minimum_opening_deposit\":0,\"entity_types_accepted\":[\"llc\",\"s_corp\"],\"available_states\":[\"ALL\"],\"target_industries\":[\"professional_services\"],\"target_business_profiles\":[\"established_smb\"],\"insurance_type\":\"fdic\",\"free_transactions_per_month\":100,\"cash_deposit_available\":true,\"cash_deposit_fee_per_100\":2.5,\"monthly_cash_deposit_limit\":5000,\"sub_accounts_supported\":true,\"rtp_supported\":true,\"rtp_network\":\"both\",\"accounting_integration_available\":true,\"tax_integration_available\":false,\"expense_integration_available\":true,\"interest_bearing\":true,\"apy\":1.25,\"apy_tiers\":null,\"outgoing_domestic_wire_fee\":15,\"incoming_domestic_wire_fee\":0,\"outgoing_international_wire_fee\":45,\"incoming_international_wire_fee\":15,\"multicurrency_support\":false,\"free_domestic_wires_per_month\":2,\"per_transaction_fee_after_limit\":0.5,\"atm_fee_reimbursement\":true,\"atm_fee_reimbursement_limit\":10,\"atm_network\":\"Allpoint\",\"overdraft_protection_available\":true,\"overdraft_line_of_credit_available\":false,\"daily_debit_limit\":5000,\"ach_debit_block_available\":true,\"positive_pay_available\":true,\"remote_deposit_capture\":true,\"bill_pay_available\":true,\"check_writing_available\":true,\"corporate_card_available\":true,\"virtual_cards_available\":true,\"physical_debit_card_available\":true,\"plan_tiers\":[{\"plan_name\":\"Standard\",\"monthly_fee\":0,\"monthly_fee_waiver_condition\":null,\"apy\":1.25,\"apy_max_balance_eligible\":null,\"apy_condition\":null,\"is_default\":true,\"sort_order\":0}],\"promotions\":[{\"bonus_amount\":300,\"condition_description\":\"Deposit $2,500 within 30 days\",\"minimum_deposit\":2500,\"expiry_date\":null,\"promo_url\":\"https://example.com/promo\"}],\"application_url\":\"https://example.com/apply\",\"last_modified\":\"2026-01-01T00:00:00Z\",\"is_verified\":true}]"
}
]
}
}JSON.parse(text)yields an array of results (empty array if nothing matched, or if the underlying query errored — errors are not surfaced to the caller). The wire format above is intentionally compact — here's that same content[0].text, decoded and pretty-printed for readability:
[
{
"listing_slug": "example-bank-business-checking-pro",
"institution_name": "Example Bank",
"institution": {
"display_name": "Example Bank",
"website_url": "https://examplebank.com",
"logo_url": "https://examplebank.com/logo.png",
"institution_type": "regional_bank",
"support_email": "[email protected]"
},
"product_name": "Business Checking Pro",
"monthly_fee": 0,
"monthly_fee_waiver_condition": null,
"minimum_opening_deposit": 0,
"entity_types_accepted": ["llc", "s_corp"],
"available_states": ["ALL"],
"target_industries": ["professional_services"],
"target_business_profiles": ["established_smb"],
"insurance_type": "fdic",
"free_transactions_per_month": 100,
"cash_deposit_available": true,
"cash_deposit_fee_per_100": 2.5,
"monthly_cash_deposit_limit": 5000,
"sub_accounts_supported": true,
"rtp_supported": true,
"rtp_network": "both",
"accounting_integration_available": true,
"tax_integration_available": false,
"expense_integration_available": true,
"interest_bearing": true,
"apy": 1.25,
"apy_tiers": null,
"outgoing_domestic_wire_fee": 15,
"incoming_domestic_wire_fee": 0,
"outgoing_international_wire_fee": 45,
"incoming_international_wire_fee": 15,
"multicurrency_support": false,
"free_domestic_wires_per_month": 2,
"per_transaction_fee_after_limit": 0.5,
"atm_fee_reimbursement": true,
"atm_fee_reimbursement_limit": 10,
"atm_network": "Allpoint",
"overdraft_protection_available": true,
"overdraft_line_of_credit_available": false,
"daily_debit_limit": 5000,
"ach_debit_block_available": true,
"positive_pay_available": true,
"remote_deposit_capture": true,
"bill_pay_available": true,
"check_writing_available": true,
"corporate_card_available": true,
"virtual_cards_available": true,
"physical_debit_card_available": true,
"plan_tiers": [
{
"plan_name": "Standard",
"monthly_fee": 0,
"monthly_fee_waiver_condition": null,
"apy": 1.25,
"apy_max_balance_eligible": null,
"apy_condition": null,
"is_default": true,
"sort_order": 0
}
],
"promotions": [
{
"bonus_amount": 300,
"condition_description": "Deposit $2,500 within 30 days",
"minimum_deposit": 2500,
"expiry_date": null,
"promo_url": "https://example.com/promo"
}
],
"application_url": "https://example.com/apply",
"last_modified": "2026-01-01T00:00:00Z",
"is_verified": true
}
]Each result object has this shape:
| Parameter | Type | Description |
|---|---|---|
| institution_name | string | null | Name of the financial institution. Kept for backward compatibility — see the nested institution object below for more detail. |
| institution | object | null | Nested detail on the institution — see the Institutionshape below. Null only if the listing's institution join unexpectedly failed to resolve. |
| product_name | string | Name of the product. |
| listing_slug | string | Stable, public identifier for this listing (e.g. found-business-checking) — pass this to get_business_checking_listing for a follow-up query on this specific result. |
| monthly_fee | number | Base monthly fee in USD. |
| monthly_fee_waiver_condition | string | null | Condition to waive the monthly fee, if any. |
| minimum_opening_deposit | number | Minimum deposit required to open. |
| entity_types_accepted | string[] | Enum values from entity_type_enum (llc, s_corp, c_corp, sole_prop, partnership, nonprofit). |
| available_states | string[] | ["ALL"] indicates nationwide availability. |
| target_industries | string[] | Which industry_vertical segment(s) this listing is tagged with — a soft-ranking signal only, not an eligibility requirement. Empty array [] for an untagged listing, never null. |
| target_business_profiles | string[] | Which business_profile segment(s) this listing is tagged with — a soft-ranking signal only, not an eligibility requirement. Empty array [] for an untagged listing, never null. |
| insurance_type | string | One of fdic, ncua, uninsured. |
| free_transactions_per_month | integer | null | Free transactions included per month. |
| cash_deposit_available | boolean | null | Whether cash deposits are supported. |
| sub_accounts_supported | boolean | null | Whether sub-accounts are supported. |
| rtp_supported | boolean | null | Whether real-time payments (any rail) are supported. |
| rtp_network | string | null | One of fednow, rtp_network, both, none; null when rtp_supported is false. |
| accounting_integration_available | boolean | null | Connects to accounting software. |
| tax_integration_available | boolean | null | Connects to tax-prep/filing software. |
| expense_integration_available | boolean | null | Connects to expense/spend-management software. |
| interest_bearing | boolean | null | Whether the account earns interest. |
| apy | number | null | Best available APY for indexing — mirrors the highest APY across plan_tiers if the product has multiple. |
| apy_tiers | object | null | Canonical balance-tiered rate schema — see ApyTiers below. Only populated when interest_bearing is true and the rate varies by balance; null for flat-rate or non-interest accounts. The flat apy field above always holds the best available rate regardless of this structure. |
| outgoing_domestic_wire_fee | number | null | Fee for outgoing domestic wires. |
| incoming_domestic_wire_fee | number | null | Fee for incoming domestic wires. |
| incoming_international_wire_fee | number | null | Fee for incoming international wires. |
| outgoing_international_wire_fee | number | null | Fee for outgoing international wires. |
| multicurrency_support | boolean | null | Whether the account supports holding or transacting in multiple currencies. |
| cash_deposit_fee_per_100 | number | null | Fee charged per $100 of cash deposited. |
| monthly_cash_deposit_limit | number | null | Monthly cash deposit limit before fees or restrictions apply. |
| free_domestic_wires_per_month | integer | null | Number of domestic wires included free per month. |
| per_transaction_fee_after_limit | number | null | Fee per transaction once the included free-transaction limit is exceeded. |
| atm_fee_reimbursement | boolean | null | Whether out-of-network ATM fees are reimbursed. |
| atm_fee_reimbursement_limit | number | null | Monthly cap on reimbursed ATM fees, if reimbursement is offered. |
| atm_network | string | null | Name of the fee-free ATM network, if any. |
| overdraft_protection_available | boolean | null | Whether overdraft protection (e.g. linked-account transfer) is available. |
| overdraft_line_of_credit_available | boolean | null | Whether an overdraft line of credit is available. |
| daily_debit_limit | number | null | Daily debit card spending limit. |
| ach_debit_block_available | boolean | null | Whether ACH debit blocking is available. |
| positive_pay_available | boolean | null | Whether positive pay fraud protection is available. |
| remote_deposit_capture | boolean | null | Whether remote (mobile/desktop) check deposit is available. |
| bill_pay_available | boolean | null | Whether bill pay is available. |
| check_writing_available | boolean | null | Whether paper check writing is available. |
| corporate_card_available | boolean | null | Whether corporate charge/credit cards are available. |
| virtual_cards_available | boolean | null | Whether virtual debit/charge cards are available. |
| physical_debit_card_available | boolean | null | Whether a physical debit card is available. |
| plan_tiers | PlanTier[] | One row per paid subscription plan (e.g. a Bluevine-style Standard/Plus/Premier ladder) whose pricing/APY differs from the listing's flat default. Empty array for products with a single, unconditional pricing tier. See PlanTier below — note that its features and fees arrays are only present in get_business_checking_listing's response, not here. |
| promotions | Promotion[] | One-to-many welcome/bonus offers for this listing. Empty array if none. See Promotion below. |
| application_url | string (uri) | Where to apply for this product. |
| last_modified | string (date-time) | When the listing was last updated. |
| is_verified | boolean | Whether this listing has been verified by Bancadia. |
All of the fields above besides the identifiers, flags with an explicit default, and plan_tiers/promotions are nullable — nullmeans "not applicable / not populated for this listing," the same convention already used by fields like apy and rtp_network. Most of these are not filterable — this section only covers what each result object includes, not what you can query on. target_industries/target_business_profilesare the one exception: they're both a response field and a request argument (see Arguments above), because the request-side values are used to soft-rank, and the response echoes back what a listing is actually tagged with.
Worked example: calling with { "target_industries": ["content_creator_solopreneur"] } ranks listings tagged content_creator_solopreneurfirst, followed by listings tagged with zero matching industries, in the same relative (monthly-fee-ascending) order they'd have appeared in without the argument. A listing that's eligible but simply hasn't been tagged with that industry is not removed from the results — it just ranks lower. This is why target_industries/target_business_profiles are documented separately from the "every filter must match" semantics that govern every other argument on this tool.
Institution
The nested object at institution on every result.
| Parameter | Type | Description |
|---|---|---|
| display_name | string | null | Institution’s public-facing name. |
| website_url | string (uri) | null | Institution’s marketing website. |
| logo_url | string (uri) | null | Institution’s logo image. |
| institution_type | string | One of national_bank, regional_bank, community_bank, credit_union, neobank, fintech. |
| support_email | string (email) | null | Institution’s support contact address. |
PlanTier
One row per paid subscription plan whose pricing or APY differs from the listing's flat default (e.g. a Standard/Plus/Premier ladder). At most one tier per listing has is_default: true — that tier's values seed the listing's flat monthly_fee / apy fields above.
| Parameter | Type | Description |
|---|---|---|
| plan_name | string | Display name of the plan (e.g. "Standard", "Plus"). |
| monthly_fee | number | Monthly fee for this plan. |
| monthly_fee_waiver_condition | string | null | Condition to waive this plan’s monthly fee, if any. |
| apy | number | null | APY on this plan, or null if this plan does not earn interest. |
| apy_max_balance_eligible | number | null | Maximum balance eligible to earn interest on this plan; null = no cap. |
| apy_condition | string | null | Activity/eligibility requirement to earn this plan’s stated APY. |
| is_default | boolean | Marks the plan whose values seed the listing’s flat monthly_fee / apy fields. At most one true per listing. |
| sort_order | integer | Display order, cheapest to priciest (0 = cheapest). |
| features | Feature[] | Feature rows scoped to this plan tier only. Tier-agnostic features are returned separately in general_features. Only present in get_business_checking_listing's response — absent from query_business_checking's plan_tiers. |
| fees | AdditionalFee[] | Fee rows scoped to this plan tier only. Tier-agnostic fees are returned separately in general_fees. Only present in get_business_checking_listing's response — absent from query_business_checking's plan_tiers. |
Promotion
One-to-many welcome/bonus offers for this listing. Empty array if none.
| Parameter | Type | Description |
|---|---|---|
| bonus_amount | integer | Dollar amount of the bonus. |
| condition_description | string | Human-readable description of how to earn the bonus. |
| minimum_deposit | integer | null | Minimum deposit required to qualify, if any. |
| expiry_date | string (date) | null | Date the promotion expires, if any. |
| promo_url | string (uri) | null | Link with more detail on the promotion, if any. |
ApyTiers
The shape of apy_tiers when populated — a canonical balance-tiered rate schema (bancadia-db migration 037, sharing its contract with migration 034) enforced across every business checking listing that has one, not a per-listing free-form shape. Object or null; null for flat-rate or non-interest accounts, or when the rate doesn't vary by balance.
| Parameter | Type | Description |
|---|---|---|
| effective_date | string (date) | Date this rate schedule took effect. |
| relationship_condition | string | null | Qualifying criteria for the relationship rate, or null if this product has no relationship rate. |
| tiers | ApyTier[] | The balance ladder itself — one or more ApyTier objects, ordered from lowest to highest min_balance. See ApyTier below. |
ApyTier (each element of tiers)
One balance band and the rate(s) that apply within it.
| Parameter | Type | Description |
|---|---|---|
| min_balance | integer | Whole-dollar amount — the lower bound of this tier, inclusive. |
| max_balance | integer | null | Whole-dollar amount — the upper bound of this tier, inclusive. Null = no upper bound (this is the top tier). |
| standard | { interest_rate: number, apy: number } | The rate every customer in this balance tier earns. Both interest_rate and apy are decimals (e.g. 0.0130 = 1.30%) — kept as two separate fields because compounding frequency makes them differ slightly. |
| relationship | { interest_rate: number, apy: number } | A higher rate available to customers who meet the relationship_condition above (e.g. holding a linked account, or a minimum combined relationship balance). Omitted entirely from this tier's object — not present as null — when the product has no relationship rate for this tier. |
Putting it together, a fully populated apy_tiers looks like this:
{
"effective_date": "2026-01-01",
"relationship_condition": "Maintain a linked Bancadia Business Checking account",
"tiers": [
{
"min_balance": 0,
"max_balance": 24999,
"standard": { "interest_rate": 0.0100, "apy": 0.0100 },
"relationship": { "interest_rate": 0.0130, "apy": 0.0130 }
},
{
"min_balance": 25000,
"max_balance": null,
"standard": { "interest_rate": 0.0150, "apy": 0.0151 },
"relationship": { "interest_rate": 0.0180, "apy": 0.0182 }
}
]
}In this example, a customer with a $10,000 balance who doesn't meet the relationship condition earns 1.00% APY; a customer with $30,000 who does meet it earns 1.82% APY. If a product has no relationship rate at all, every tier simply omits the relationship key and relationship_condition is null. The flat apyfield on the base result always mirrors the single best (highest) rate across this whole structure, for indexing — it's redundant with apy_tiers, not a separate figure.
tools/call — get_business_checking_listing
Returns full detail on a single business checking listing. Same auth and session requirements as query_business_checking — a bearer token and a valid Mcp-Session-Id header from your last initialize call. Rate limiting and every error code behave identically to query_business_checking too — nothing special about this tool on that front.
This is the tool to call for follow-up questions like "tell me more about X" or "what are the gotcha fees on X" after a query_business_checking result — pass the listing_slug from that result rather than re-running the broader query. It returns everything query_business_checking returns for a listing, plus general_fees and general_features — the two one-to-many tables (business_deposit_fees, business_deposit_account_features) deliberately excluded from query_business_checking's broader list response to keep multi-listing payloads bounded in size. general_fees/general_features hold only the rows with no plan_tier_id— fees or features scoped to one specific plan tier (e.g. a sub-account limit that only applies on the "Plus" plan) are nested instead under that tier, as plan_tiers[].fees / plan_tiers[].features (see the PlanTiershape above). Returns an empty array (not an error) if the slug doesn't match an active listing.
Arguments
| Parameter | Type | Description |
|---|---|---|
| listing_slug | string | The stable public identifier for the listing (e.g. found-business-checking), as returned by query_business_checking. Not the internal database id, which is never exposed. Unrecognized argument names are rejected (additionalProperties: false). |
Request
POST https://mcp.bancadia.com/
Authorization: Bearer bcd_YOUR_TOKEN_HERE
Content-Type: application/json
Mcp-Session-Id: 7e93bc81-b832-4c8b-9834-1bac55106e22
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "get_business_checking_listing",
"arguments": { "listing_slug": "found-business-checking" }
}
}Response
Same envelope as every other tool — JSON.parse(result.content[0].text) yields an array with either one element (a match was found) or zero elements (no active listing has that listing_slug, or the argument was missing/malformed). There is no dedicated "not found" error — an empty array covers both cases.
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "[{\"listing_slug\":\"example-bank-business-checking-pro\",\"institution_name\":\"Example Bank\",\"institution\":{\"display_name\":\"Example Bank\",\"website_url\":\"https://examplebank.com\",\"logo_url\":\"https://examplebank.com/logo.png\",\"institution_type\":\"regional_bank\",\"support_email\":\"[email protected]\"},\"product_name\":\"Business Checking Pro\",\"monthly_fee\":0,\"monthly_fee_waiver_condition\":null,\"minimum_opening_deposit\":0,\"entity_types_accepted\":[\"llc\",\"s_corp\"],\"available_states\":[\"ALL\"],\"target_industries\":[\"professional_services\"],\"target_business_profiles\":[\"established_smb\"],\"insurance_type\":\"fdic\",\"free_transactions_per_month\":100,\"cash_deposit_available\":true,\"cash_deposit_fee_per_100\":2.5,\"monthly_cash_deposit_limit\":5000,\"sub_accounts_supported\":true,\"rtp_supported\":true,\"rtp_network\":\"both\",\"accounting_integration_available\":true,\"tax_integration_available\":false,\"expense_integration_available\":true,\"interest_bearing\":true,\"apy\":1.25,\"apy_tiers\":null,\"outgoing_domestic_wire_fee\":15,\"incoming_domestic_wire_fee\":0,\"outgoing_international_wire_fee\":45,\"incoming_international_wire_fee\":15,\"multicurrency_support\":false,\"free_domestic_wires_per_month\":2,\"per_transaction_fee_after_limit\":0.5,\"atm_fee_reimbursement\":true,\"atm_fee_reimbursement_limit\":10,\"atm_network\":\"Allpoint\",\"overdraft_protection_available\":true,\"overdraft_line_of_credit_available\":false,\"daily_debit_limit\":5000,\"ach_debit_block_available\":true,\"positive_pay_available\":true,\"remote_deposit_capture\":true,\"bill_pay_available\":true,\"check_writing_available\":true,\"corporate_card_available\":true,\"virtual_cards_available\":true,\"physical_debit_card_available\":true,\"plan_tiers\":[{\"plan_name\":\"Standard\",\"monthly_fee\":0,\"monthly_fee_waiver_condition\":null,\"apy\":1.25,\"apy_max_balance_eligible\":null,\"apy_condition\":null,\"is_default\":true,\"sort_order\":0,\"features\":[],\"fees\":[]},{\"plan_name\":\"Plus\",\"monthly_fee\":15,\"monthly_fee_waiver_condition\":\"Waived with $10,000 average daily balance\",\"apy\":1.75,\"apy_max_balance_eligible\":null,\"apy_condition\":null,\"is_default\":false,\"sort_order\":1,\"features\":[{\"category\":\"account_management\",\"description\":\"Maximum number of sub-accounts included with this plan.\",\"value\":10}],\"fees\":[]}],\"promotions\":[{\"bonus_amount\":300,\"condition_description\":\"Deposit $2,500 within 30 days\",\"minimum_deposit\":2500,\"expiry_date\":null,\"promo_url\":\"https://example.com/promo\"}],\"application_url\":\"https://example.com/apply\",\"last_modified\":\"2026-01-01T00:00:00Z\",\"is_verified\":true,\"general_fees\":[{\"fee_type\":\"overdraft\",\"amount\":35,\"amount_description\":null,\"eligibility_criteria\":null,\"tiers\":null,\"waivable\":false,\"waiver_condition\":null}],\"general_features\":[{\"category\":\"cash_handling\",\"description\":\"Free cash deposits up to $2,000/mo\",\"value\":2000},{\"category\":\"fraud_protection\",\"description\":\"Instant card freeze\",\"value\":null}]}]"
}
]
}
}The wire format above is intentionally compact — here's that same content[0].text, decoded and pretty-printed for readability:
[
{
"listing_slug": "example-bank-business-checking-pro",
"institution_name": "Example Bank",
"institution": {
"display_name": "Example Bank",
"website_url": "https://examplebank.com",
"logo_url": "https://examplebank.com/logo.png",
"institution_type": "regional_bank",
"support_email": "[email protected]"
},
"product_name": "Business Checking Pro",
"monthly_fee": 0,
"monthly_fee_waiver_condition": null,
"minimum_opening_deposit": 0,
"entity_types_accepted": ["llc", "s_corp"],
"available_states": ["ALL"],
"target_industries": ["professional_services"],
"target_business_profiles": ["established_smb"],
"insurance_type": "fdic",
"free_transactions_per_month": 100,
"cash_deposit_available": true,
"cash_deposit_fee_per_100": 2.5,
"monthly_cash_deposit_limit": 5000,
"sub_accounts_supported": true,
"rtp_supported": true,
"rtp_network": "both",
"accounting_integration_available": true,
"tax_integration_available": false,
"expense_integration_available": true,
"interest_bearing": true,
"apy": 1.25,
"apy_tiers": null,
"outgoing_domestic_wire_fee": 15,
"incoming_domestic_wire_fee": 0,
"outgoing_international_wire_fee": 45,
"incoming_international_wire_fee": 15,
"multicurrency_support": false,
"free_domestic_wires_per_month": 2,
"per_transaction_fee_after_limit": 0.5,
"atm_fee_reimbursement": true,
"atm_fee_reimbursement_limit": 10,
"atm_network": "Allpoint",
"overdraft_protection_available": true,
"overdraft_line_of_credit_available": false,
"daily_debit_limit": 5000,
"ach_debit_block_available": true,
"positive_pay_available": true,
"remote_deposit_capture": true,
"bill_pay_available": true,
"check_writing_available": true,
"corporate_card_available": true,
"virtual_cards_available": true,
"physical_debit_card_available": true,
"plan_tiers": [
{
"plan_name": "Standard",
"monthly_fee": 0,
"monthly_fee_waiver_condition": null,
"apy": 1.25,
"apy_max_balance_eligible": null,
"apy_condition": null,
"is_default": true,
"sort_order": 0,
"features": [],
"fees": []
},
{
"plan_name": "Plus",
"monthly_fee": 15,
"monthly_fee_waiver_condition": "Waived with $10,000 average daily balance",
"apy": 1.75,
"apy_max_balance_eligible": null,
"apy_condition": null,
"is_default": false,
"sort_order": 1,
"features": [
{
"category": "account_management",
"description": "Maximum number of sub-accounts included with this plan.",
"value": 10
}
],
"fees": []
}
],
"promotions": [
{
"bonus_amount": 300,
"condition_description": "Deposit $2,500 within 30 days",
"minimum_deposit": 2500,
"expiry_date": null,
"promo_url": "https://example.com/promo"
}
],
"application_url": "https://example.com/apply",
"last_modified": "2026-01-01T00:00:00Z",
"is_verified": true,
"general_fees": [
{
"fee_type": "overdraft",
"amount": 35,
"amount_description": null,
"eligibility_criteria": null,
"tiers": null,
"waivable": false,
"waiver_condition": null
}
],
"general_features": [
{
"category": "cash_handling",
"description": "Free cash deposits up to $2,000/mo",
"value": 2000
},
{
"category": "fraud_protection",
"description": "Instant card freeze",
"value": null
}
]
}
]Note in the decoded example above that the "Standard" tier has empty fees/featuresarrays while "Plus" has a tier-scoped feature, and the account-wide overdraft fee and two account-wide features are surfaced separately in general_fees / general_features rather than under any one tier. Each result object has this shape:
| Parameter | Type | Description |
|---|---|---|
| listing_slug | string | Stable, public identifier for this listing — the same value you passed in as the listing_slug argument. |
| institution_name | string | null | Name of the financial institution. Kept for backward compatibility — see the nested institution object below for more detail. |
| institution | Institution | null | Nested detail on the institution — see Institutionbelow. Null only if the listing's institution join unexpectedly failed to resolve. |
| product_name | string | Name of the product. |
| monthly_fee | number | Base monthly fee in USD. |
| monthly_fee_waiver_condition | string | null | Condition to waive the monthly fee, if any. |
| minimum_opening_deposit | number | Minimum deposit required to open. |
| entity_types_accepted | string[] | Enum values from entity_type_enum (llc, s_corp, c_corp, sole_prop, partnership, nonprofit). |
| available_states | string[] | ["ALL"] indicates nationwide availability. |
| target_industries | string[] | Which industry_vertical segment(s) this listing is tagged with — a soft-ranking signal only, not an eligibility requirement. Empty array [] for an untagged listing, never null. |
| target_business_profiles | string[] | Which business_profile segment(s) this listing is tagged with — a soft-ranking signal only, not an eligibility requirement. Empty array [] for an untagged listing, never null. |
| insurance_type | string | One of fdic, ncua, uninsured. |
| free_transactions_per_month | integer | null | Free transactions included per month. |
| cash_deposit_available | boolean | null | Whether cash deposits are supported. |
| cash_deposit_fee_per_100 | number | null | Fee charged per $100 of cash deposited, above monthly_cash_deposit_limit (if any). |
| monthly_cash_deposit_limit | number | null | Amount of cash deposits per month before cash_deposit_fee_per_100 applies. Null = no limit. |
| sub_accounts_supported | boolean | null | Whether sub-accounts are supported. |
| rtp_supported | boolean | null | Whether real-time payments (any rail) are supported. |
| rtp_network | string | null | One of fednow, rtp_network, both, none; null when rtp_supported is false. |
| accounting_integration_available | boolean | null | Connects to accounting software. |
| tax_integration_available | boolean | null | Connects to tax-prep/filing software. |
| expense_integration_available | boolean | null | Connects to expense/spend-management software. |
| interest_bearing | boolean | null | Whether the account earns interest. |
| apy | number | null | Best available APY for indexing — mirrors the highest APY across plan_tiers if the product has multiple. |
| apy_tiers | ApyTiers | null | Canonical balance-tiered rate schema — see ApyTiers below. Only populated when interest_bearing is true and the rate varies by balance; null for flat-rate or non-interest accounts. |
| outgoing_domestic_wire_fee | number | null | Fee for outgoing domestic wires. |
| incoming_domestic_wire_fee | number | null | Fee for incoming domestic wires. |
| outgoing_international_wire_fee | number | null | Fee for outgoing international wires. |
| incoming_international_wire_fee | number | null | Fee for incoming international wires. |
| multicurrency_support | boolean | null | Whether the account supports holding or transacting in multiple currencies. |
| free_domestic_wires_per_month | integer | null | Number of domestic wires included free per month. |
| per_transaction_fee_after_limit | number | null | Fee per transaction once the included free-transaction limit is exceeded. |
| atm_fee_reimbursement | boolean | null | Whether out-of-network ATM fees are reimbursed. |
| atm_fee_reimbursement_limit | number | null | Monthly cap on reimbursed ATM fees, if reimbursement is offered. |
| atm_network | string | null | Name of the fee-free ATM network, if any. |
| overdraft_protection_available | boolean | null | Whether overdraft protection (e.g. linked-account transfer) is available. |
| overdraft_line_of_credit_available | boolean | null | Whether an overdraft line of credit is available. |
| daily_debit_limit | number | null | Daily debit card spending limit. |
| ach_debit_block_available | boolean | null | Whether ACH debit blocking is available. |
| positive_pay_available | boolean | null | Whether positive pay fraud protection is available. |
| remote_deposit_capture | boolean | null | Whether remote (mobile/desktop) check deposit is available. |
| bill_pay_available | boolean | null | Whether bill pay is available. |
| check_writing_available | boolean | null | Whether paper check writing is available. |
| corporate_card_available | boolean | null | Whether corporate charge/credit cards are available. |
| virtual_cards_available | boolean | null | Whether virtual debit/charge cards are available. |
| physical_debit_card_available | boolean | null | Whether a physical debit card is available. |
| plan_tiers | PlanTier[] | One row per paid subscription plan (e.g. a Bluevine-style Standard/Plus/Premier ladder). Empty array for products with a single, unconditional pricing tier. See PlanTier below — unlike query_business_checking, each tier here includes its own features and fees arrays. |
| promotions | Promotion[] | One-to-many welcome/bonus offers for this listing. Empty array if none. See Promotion below. |
| application_url | string (uri) | Where to apply for this product. |
| last_modified | string (date-time) | When the listing was last updated. |
| is_verified | boolean | Whether this listing has been verified by Bancadia. |
| general_fees | AdditionalFee[] | Fees with no plan_tier_id — apply account-wide rather than to one specific plan tier. See AdditionalFee below, including the override note — a tier-specific fee of the same fee_type in plan_tiers[].feessupersedes the matching row here for that plan, it doesn't add to it. Not present in query_business_checking's response. |
| general_features | Feature[] | Features with no plan_tier_id — apply account-wide rather than to one specific plan tier. See Feature below. Not present in query_business_checking's response. |
Institution
The nested object at institution. Identical shape to the Institution documented under query_business_checking above.
| Parameter | Type | Description |
|---|---|---|
| display_name | string | null | Institution’s public-facing name. |
| website_url | string (uri) | null | Institution’s marketing website. |
| logo_url | string (uri) | null | Institution’s logo image. |
| institution_type | string | One of national_bank, regional_bank, community_bank, credit_union, neobank, fintech. |
| support_email | string (email) | null | Institution’s support contact address. |
PlanTier
One row per paid subscription plan whose pricing or APY differs from the listing's flat default (e.g. a Standard/Plus/Premier ladder). At most one tier per listing has is_default: true — that tier's values seed the listing's flat monthly_fee / apy fields above. Unlike query_business_checking, every tier here carries its own features and feesarrays (both may be empty, as with the "Standard" tier in the example above).
| Parameter | Type | Description |
|---|---|---|
| plan_name | string | Display name of the plan (e.g. "Standard", "Plus"). |
| monthly_fee | number | Monthly fee for this plan. |
| monthly_fee_waiver_condition | string | null | Condition to waive this plan’s monthly fee, if any. |
| apy | number | null | APY on this plan, or null if this plan does not earn interest. |
| apy_max_balance_eligible | number | null | Maximum balance eligible to earn interest on this plan; null = no cap. |
| apy_condition | string | null | Activity/eligibility requirement to earn this plan’s stated APY. |
| is_default | boolean | Marks the plan whose values seed the listing’s flat monthly_fee / apy fields. At most one true per listing. |
| sort_order | integer | Display order, cheapest to priciest (0 = cheapest). |
| features | Feature[] | Feature rows scoped to this plan tier only (rows from business_deposit_account_features whose plan_tier_id matches this tier). Tier-agnostic features are returned separately in the top-level general_features. See Feature below. |
| fees | AdditionalFee[] | Fee rows scoped to this plan tier only (rows from business_deposit_fees whose plan_tier_id matches this tier). A row here overrides — rather than adds to — any row of the same fee_type in the top-level general_fees; see the override note under AdditionalFee below. |
Promotion
One-to-many welcome/bonus offers for this listing. Empty array if none. Identical shape to the Promotion documented under query_business_checking above.
| Parameter | Type | Description |
|---|---|---|
| bonus_amount | integer | Dollar amount of the bonus. |
| condition_description | string | Human-readable description of how to earn the bonus. |
| minimum_deposit | integer | null | Minimum deposit required to qualify, if any. |
| expiry_date | string (date) | null | Date the promotion expires, if any. |
| promo_url | string (uri) | null | Link with more detail on the promotion, if any. |
ApyTiers
The shape of apy_tiers when populated — a canonical balance-tiered rate schema (bancadia-db migration 037, sharing its contract with migration 034) enforced across every business checking listing that has one, not a per-listing free-form shape. Object or null; null for flat-rate or non-interest accounts, or when the rate doesn't vary by balance. Identical shape to the ApyTiers documented under query_business_checking above.
| Parameter | Type | Description |
|---|---|---|
| effective_date | string (date) | Date this rate schedule took effect. |
| relationship_condition | string | null | Qualifying criteria for the relationship rate, or null if this product has no relationship rate. |
| tiers | ApyTier[] | The balance ladder itself — one or more ApyTier objects, ordered from lowest to highest min_balance. See ApyTier below. |
ApyTier (each element of tiers)
One balance band and the rate(s) that apply within it.
| Parameter | Type | Description |
|---|---|---|
| min_balance | integer | Whole-dollar amount — the lower bound of this tier, inclusive. |
| max_balance | integer | null | Whole-dollar amount — the upper bound of this tier, inclusive. Null = no upper bound (this is the top tier). |
| standard | { interest_rate: number, apy: number } | The rate every customer in this balance tier earns. Both interest_rate and apy are decimals (e.g. 0.0130 = 1.30%) — kept as two separate fields because compounding frequency makes them differ slightly. |
| relationship | { interest_rate: number, apy: number } | A higher rate available to customers who meet the relationship_condition above (e.g. holding a linked account, or a minimum combined relationship balance). Omitted entirely from this tier's object — not present as null — when the product has no relationship rate for this tier. |
Putting it together, a fully populated apy_tiers looks like this:
{
"effective_date": "2026-01-01",
"relationship_condition": "Maintain a linked Bancadia Business Checking account",
"tiers": [
{
"min_balance": 0,
"max_balance": 24999,
"standard": { "interest_rate": 0.0100, "apy": 0.0100 },
"relationship": { "interest_rate": 0.0130, "apy": 0.0130 }
},
{
"min_balance": 25000,
"max_balance": null,
"standard": { "interest_rate": 0.0150, "apy": 0.0151 },
"relationship": { "interest_rate": 0.0180, "apy": 0.0182 }
}
]
}In this example, a customer with a $10,000 balance who doesn't meet the relationship condition earns 1.00% APY; a customer with $30,000 who does meet it earns 1.82% APY. If a product has no relationship rate at all, every tier simply omits the relationship key and relationship_condition is null. The flat apyfield on the base result always mirrors the single best (highest) rate across this whole structure, for indexing — it's redundant with apy_tiers, not a separate figure.
AdditionalFee
One row from business_deposit_fees, only for fee_type values that have no dedicated flat column on the top-level result shape (e.g. overdraft, non_sufficient_funds, dormancy — not wire_domestic_outgoing etc., which are already covered by outgoing_domestic_wire_fee and friends above; this split avoids the same fee ever being represented twice by two sources that could disagree). This is the shape of both the top-level general_fees array and every plan_tiers[].fees array.
Plan-tier fees override, they don't add. If the same fee_type appears both in the top-level general_fees (a row with no plan_tier_id) and in one specific tier's plan_tiers[].fees, the tier-specific row is that plan's effective fee for that fee_type — it supersedes the general one rather than stacking with it. To find what a given plan actually pays for a fee_type: look for it in that plan's plan_tiers[].fees first; only fall back to general_feesif it's not there. This API does not pre-resolve that for you — it returns both rows as-is, so a caller that naively sums or lists every fee it sees will double-count any overridden ones. (This mirrors the resolution contract documented on business_deposit_fees.plan_tier_id in bancadia-db migration 040 — e.g. a plan that discounts wire fees is modeled as one override row for that plan, not an additional fee.)
| Parameter | Type | Description |
|---|---|---|
| fee_type | string | One of monthly_maintenance, overdraft, non_sufficient_funds, account_opening, account_closing, minimum_balance, excess_transaction, atm_foreign, paper_statement, dormancy, returned_item, stop_payment, card_replacement, foreign_transaction, other. |
| amount | number | null | Flat fee amount in USD, if applicable — the standard/lowest rate when tiers is populated. |
| amount_description | string | null | Free-text description of the amount, used when the fee isn’t a simple flat number. |
| eligibility_criteria | string | null | Free-text description of when this fee applies. |
| tiers | FeeVariant[] | null | Populated only when a single fee_type has multiple rates that differ by channel or condition (e.g. online vs. branch wire fees) — not a balance-tiered structure like ApyTiers above, despite the similar name. Null if the fee is a single flat amount. See FeeVariant below. |
| waivable | boolean | Whether this fee can be waived. |
| waiver_condition | string | null | Condition under which the fee is waived, if waivable. |
FeeVariant (each element of tiers)
One rate variant for a fee that differs by channel or condition (bancadia-db migration 032's canonical schema for business_deposit_fees.tiers — every listing that populates this field follows the same fixed shape).
| Parameter | Type | Description |
|---|---|---|
| channel | string | How/where the transaction is initiated, e.g. "online", "branch", "waived". |
| amount | number | Fee in dollars for this channel. |
| description | string | Human-readable condition or context for this variant. |
Example — an outgoing domestic wire fee that's cheaper online and waived when sent by a banker on the caller's behalf:
[
{ "channel": "online", "amount": 25.00, "description": "Via online banking or mobile app" },
{ "channel": "branch", "amount": 35.00, "description": "With the help of a banker" },
{ "channel": "waived", "amount": 0.00, "description": "If originally sent via a banker referral" }
]Feature
One row from business_deposit_account_features — narrative/marketing feature callouts, richer than the raw booleans on the top-level result shape, sorted by display order. This is the shape of both the top-level general_features array and every plan_tiers[].features array.
Unlike AdditionalFee, plan-tier features are additive, not an override— a feature row scoped to one plan tier is an extra fact about that plan (e.g. a Premier-only capability, or that plan's specific sub-account limit via value), not a replacement for some general-features row of the same description. There is no fallback to resolve here: a plan's full feature set is simply general_features plus that plan's own plan_tiers[].features, taken together (per bancadia-db migration 041).
| Parameter | Type | Description |
|---|---|---|
| category | string | One of payment_rails, cash_handling, cards_and_atm, online_banking, fraud_protection, account_management, platform_integrations, other. |
| description | string | Human-readable description of the feature. |
| value | number | null | Nullable quantified value for the feature (e.g. a dollar limit or a count). |
GET — standalone SSE stream
GET https://mcp.bancadia.com/ with Accept: text/event-stream and a valid Mcp-Session-Id header opens a stream for messages the server initiates outside of a specific tools/call response (e.g. a future progress or sampling push). No tool currently sends anything on it — the stream exists so that MCP client libraries which open it unconditionally after initialize don't fail.
The server sends periodic keep-alive pingevents and closes the stream itself after roughly a minute; well-behaved clients reconnect automatically. This is handled by spec-compliant client libraries, if at all — if you're integrating by hand (Option B in the Quickstart), you never need to call this.
GET without an Accept: text/event-stream header returns 405 with no body.
DELETE — session termination
A client that's done with a session (e.g. the user closes a chat or tab) can end it immediately rather than waiting for idle expiry:
DELETE https://mcp.bancadia.com/ Mcp-Session-Id: 7e93bc81-b832-4c8b-9834-1bac55106e22
Returns 204 No Content with an empty body. This is a courtesy, not something a caller must remember to do — an unterminated session simply idle-expires (see Session management above).
Errors
| HTTP status | JSON-RPC code | Meaning |
|---|---|---|
| 400 | -32600 | Missing Mcp-Session-Id header on any request other than initialize, or an MCP-Protocol-Versionheader value this server doesn't support. No JSON-RPC body if the request was a notification (no id). |
| 401 | -32001 | Unauthorized — missing, malformed, or unknown/revoked bearer token on tools/call. |
| 403 | — | The Originrequest header is present but not on the server's allowlist. No JSON-RPC body — a plain text/empty response. Only relevant to browser-based callers; curl/SDK/CLI clients don't send Origin and are unaffected in practice. |
| 404 | -32601 | Unknown method (anything other than initialize, tools/list, tools/call) or unknown/unrouted tool name passed to tools/call. |
| 404 | -32600 | Different case, same status. The Mcp-Session-Id header doesn't match a known, unexpired session. Call initialize again to get a new one — this is the normal way a long-idle client resumes, not an error state to alarm on. |
| 405 | — | GET request whose Accept header doesn't include text/event-stream. No body. |
| 429 | -32029 | Per-token rate limit exceeded. |
The two 404 rows share an HTTP status but mean different things and need different fixes — fix the tool/method name for -32601, re-initialize for -32600. 403 and 405 are also worth noting specially: unlike every other error case here, they return no JSON-RPC body at all — just a bare HTTP status with a plain-text or empty body. A client that assumes every non-2xx response has a parseable error.code will break on these two.
Example — missing session header, and an unknown/expired session (both an id-bearing request would get):
// 400 — missing Mcp-Session-Id
{ "jsonrpc": "2.0", "id": 1, "error": { "code": -32600, "message": "Missing Mcp-Session-Id header." } }
// 404 — unknown/expired session
{ "jsonrpc": "2.0", "id": 1, "error": { "code": -32600, "message": "Session not found or expired. Re-initialize." } }Example — calling an unrouted or unknown tool name:
{
"jsonrpc": "2.0",
"id": 1,
"error": { "code": -32601, "message": "Unknown tool: query_hysa" }
}Discovery & health endpoints
Two unauthenticated GET endpoints exist alongside the JSON-RPC endpoint:
| Parameter | Type | Description |
|---|---|---|
| GET /health | — | Liveness check. Returns { "status": "ok" }. |
| GET /.well-known/mcp | — | Public discovery document — advertises the JSON-RPC endpoint URL and a summary (name + description, no inputSchema) of every currently-routed tool. Useful for agents that discover capabilities by URL convention rather than a JSON-RPC handshake. Bancadia's main site mirrors this at bancadia.com/.well-known/mcp. |