openbanking-mcp
Sends a daily brief of bank account balances and upcoming transactions to Todoist as tasks.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@openbanking-mcpWhat are my balances and upcoming debits?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
openbanking-mcp — read your accounts, and warn BEFORE
The repository is called
openbanking-mcp, the command is calledbankread. This is not an oversight: the repository name says what it is — an MCP server on top of Open Banking — because that's how you find it. The command name says what you do with it, andbankread doctorrolls off the tongue better thanopenbanking-mcp doctor. The configuration paths (~/.config/bankread, keychainbankread-enablebanking) follow the command, not the repository.
Read-only access to bank accounts via PSD2 (AIS license), plus a daily brief to
Todoist. Python 3.11+, zero third-party dependencies: urllib for HTTP, hand-written
JSON-RPC for the MCP server. Runs on the Mac, not in a cloud.
⚠ The data provider is yours to choose — read before starting
This repository was born with a GoCardless Bank Account Data client (formerly Nordigen), which was the obvious free path. Checked on 2026-08-20: this service is closed to new sign-ups and being phased out.
bankreadlib/gocardless.pyis therefore only useful to those who already had an account.The free replacement for personal use is Enable Banking, whose Restricted Production tier gives real production data on only the accounts you connect yourself — which is exactly the use case here, and without a licence to pay for. The Enable Banking client is written (
bankreadlib/enablebanking.py): self-service sign-up by email, authentication via RS256-signed JWT — no dependencies, the standard library is enough (bankreadlib/rs256.py). The roundup of workable solutions for BoursoBank and the three findings that changed the code are indocs/fournisseurs.md.One thing remains that no one can do for you: create the Enable Banking account, declare your bank accounts there, and sign the consent. The application ID and private key are personal — there is nothing to share, and that's where you need to start.
Everything else in the repository is provider-independent.
The problem it solves, and the one it doesn't
BoursoBank already sends "your balance is low". Caisse d'Épargne already sends "money in". Amazon sends "out for delivery", Leboncoin "the seller has confirmed". The information already arrives — it just arrives too late and in the wrong place.
too late: a threshold alert fires AFTER the direct debit. On the morning of the 15th, the taxes have gone through, the account is low, and the alert notes it;
in the wrong place: in the middle of two hundred emails, most of which go unread.
This folder is therefore not going to look for missing information. It does the one thing no one does: the subtraction. Today's balance minus what will hit by the end of the month. Neither the bank nor the tax office can do it — neither one sees the other.
What it doesn't solve: nothing here replaces actually looking at your accounts. A new, never-seen direct debit is invisible to a recurrence detector.
Related MCP server: pocketledger
Read-only, and not out of politeness
The connection goes through the provider's PSD2 / AIS licence (Enable Banking, free Restricted Production tier). AIS is account information aggregation. Payment initiation is a separate licence (PIS), which this token doesn't have and the bank won't grant it. The worst-case scenario of a leak is reading a history, never a money movement. That's the only reason this folder has the right to exist.
Three practical consequences:
the provider credentials live in the macOS keychain, not in a file — a file ends up in a backup tar, an unfortunate
cat, an rsync to a NAS. For Enable Banking, that includes the RSA private key:bankread secrets --setreads it, stores it, and reminds you to delete the downloaded.pem;the bank consent expires — three to six months depending on what the bank grants, and it's the bank's response that is recorded, not our request. Nothing can renew it for you: you have to go back to your bank's site.
doctorwarns at D-14 (not at D-1, where a weekend would be enough to invalidate everything);all of it runs on the Mac. Not in a cloud session, not in a container.
Getting started
See what it does, right away
./bankread demoAn invented account, 400 days of fabricated history, an imaginary balance — and the real detection and real projection running on it. Nothing is written outside a temporary folder.
What the demo shows, and which is the whole point:
2026-08-23 ±3j -890.00 → 394.55 Loyer … [loyer]
2026-08-25 ±3j -412.00 → -17.45 Dgfip Impot … [impots]
2026-08-29 ±3j 2450.00 → 2432.55 Salaire …
⚠ passe sous 300 € le 2026-08-25 (-17.45 €), poussé par « Dgfip Impot Revenu »
(1 motif(s) incertain(s) non comptés — la vraie trajectoire peut être plus basse)The rent still leaves you above the floor; it's the taxes that push you below, five days before the salary. Your bank will tell you on the morning of the 25th. And the last line is the most important: the property tax has only appeared twice in the history, so it's not believed, so it doesn't count — and the projection itself says it's optimistic rather than pretending otherwise.
Install it, or not
Three ways, in order of the commitment they require:
git clone https://github.com/Beennnn/openbanking-mcp && cd openbanking-mcp && ./bankread doctor
uvx --from git+https://github.com/Beennnn/openbanking-mcp bankread doctor # sans rien installer
pipx install git+https://github.com/Beennnn/openbanking-mcp # à demeureThe clone first, and not out of habit: a tool that reads bank accounts is read
before being installed. ./bankread works from the clone, without installing anything at all.
Then, in order
# 0. créer l'application chez le fournisseur : https://enablebanking.com/sign-in/
# Control Panel → API applications → environnement « Production », clé générée.
# L'URL de retour à déclarer est http://127.0.0.1:8788/callback (à l'identique).
# 1. les deux identifiants (le second est le CHEMIN du .pem téléchargé)
bankread secrets --set # ils vont dans le trousseau, pas sur le disque
# 2. trouver sa banque, puis signer le consentement (ouvre le site de la banque)
bankread banks bourso # relève le NOM EXACT que renvoie l'API
bankread link "BoursoBank" # puis, séparément :
bankread link "Caisse d'Epargne"
# 3. vérifier
bankread doctor
bankread project --days 45 --floor 300
# 4. le brief de 7 h 30 → tâches Todoist
launchd/install.sh
launchctl kickstart -k "gui/$(id -u)/com.bankread.brief-quotidien" # essai immédiatThe BoursoBank case, concretely
It's the bank this repository was written against, so here's what to expect
rather than a generality. Another bank will behave differently — and
bankread banks is what's authoritative, not this file:
~90 days of history, no more. MONTHLY recurring items — rent, EDF, monthly tax payments — come out from the first read: three occurrences are enough. Annual ones wait for the registry to accumulate (see above).
Validation goes through the BoursoBank app (PSD2 strong authentication). The
bankread linkflow opens the site, then the phone rings. So you need to have it on hand, and repeat this gesture every 90 days.Don't count on Wicount 360 aggregation. BoursoBank already aggregates the Caisse d'Épargne account and sends alerts on it, but PSD2 gives access to accounts held by the queried bank, not to what it aggregates from elsewhere. The Caisse d'Épargne account therefore needs its own
bankread link, with its own 90-day consent. (To be confirmed at first connection: if external accounts appear in the flow, so much the better.)Joint accounts are chosen in the bank's consent screen. Only check what you really want to read: what's checked goes into the local registry, and the registry doesn't forget.
bankread banks bourso gives the exact name — at Enable Banking a bank is designated
by its NAME and country, not by a technical identifier — and the maximum consent
duration that bank grants. That value is what's authoritative, not this file.
link chains automatically into the golden window retrieval: the full
history is only served within the hour after signing, then the bank falls back to
90 rolling days. Don't interrupt this step — it only replays at the next
renewal, in three to six months.
The commands
| what works, what will break, when. No network calls — a diagnostic that consumes quota is a diagnostic you don't run. |
| the balances, with their age |
| the detected recurring items and their next occurrence |
| the cross: balance minus upcoming recurring items, day by day |
| the latest transactions |
| everything at once, for a script |
| what it looks like, on a FICTITIOUS account — no bank, no sign-up |
| MCP server on stdio, six read tools — for Claude or any other MCP client |
Exit codes: 0 all good, 1 something to look at, 2 hard failure — so launchd and calling scripts can find their way.
Have an AI read the accounts
claude mcp add bankread -s user -- "$PWD/bankread" mcpOr without a clone at all, like any MCP server is distributed:
{
"mcpServers": {
"bankread": {
"command": "uvx",
"args": ["--from", "git+https://github.com/Beennnn/openbanking-mcp", "bankread", "mcp"]
}
}
}MCP is an open protocol and bankreadlib/mcp.py is hand-written JSON-RPC:
no vendor library, no token, no outbound calls. The same server
declares itself the same way in other MCP clients, and bankread json serves what isn't
one. All of it — including how to go without it entirely — is in
docs/integration.md.
Two limits paid in advance, not to rediscover
Four calls per day per account. Most banks cap at four calls per account per day
for background retrieval. Four. It's not a limit you approach, it's a limit you hit
in one morning of debugging. Hence a cache that's not a comfort: without it, the
morning brief fails one day out of two. Hence also --refresh, which is explicit and never the default.
The cap drops when a user is actually in front of the screen, which a PSU header declares to the bank. bankread only sends it if the command has a terminal: the 7:30 AM brief doesn't, so it stays capped. It's a declaration made to a bank, not a performance setting — setting it to "true" from a launchd agent would be a lie.
A short history makes a projection OPTIMISTIC, not incomplete. Not all banks
return thirteen months — BoursoBank returns about 90 days. Below
380 days, an annual recurring item (property tax, insurance, fee) hasn't been
seen twice, so it doesn't exist for the detector, so the announced trajectory
is better than the real one. It's the only place where being wrong costs
money, so upcoming, project, and doctor say it in plain words.
And above all, that's why ledger.py accumulates instead of caching. The
first draft (2026-08-20, morning) kept a snapshot: each read replaced the
previous one. With a 90-day bank, that made an annual due date not
"not yet detected" but undetectable for life — anything beyond the quarter
disappeared from the API and the cache at the same time. The ledger melts each read into
a durable file; after a year of briefs, bankread knows 365 days where the
bank only shows 90, and the property tax appears on its second pass.
bankread doctor shows the countdown.
The deposit rule, applied to a balance
No green line that hasn't been observed.
Every response from read.py carries an etat field:
| what it means |
| read just now, or recently enough to still be true |
| served from cache, with its age in plain text — read it, don't trust it |
| nothing fresh enough to claim anything |
Never a bare balance. A solde: null, etat: "inconnu" is not a zero balance, and
it's the worst possible reading of a missing figure — the MCP tool descriptions
repeat it to the model before it calls, so it doesn't learn it by making a mistake.
Same discipline on predictions: a due date seen twice isn't a due date,
it's a coincidence. It comes out marked confidence: "faible" and doesn't enter the
projection. Three regular passes, that's a fact.
And on inflows: projecting only outflows gives a trajectory that always
dips, so an alarm every day, so no alarm at all after a
week. Salary and benefits are detected by the same path and counted in
the other direction. test_le_salaire_qui_arrive_avant_evite_la_fausse_alerte guards this case.
The 7:30 AM brief
brief/brief.md is the text Claude runs every morning, launched by launchd via
brief/run-brief. It reads Gmail and the bank, and its only useful output is a small
number of Todoist tasks tagged auto-brief.
Silence is a success. A morning with nothing to report produces zero tasks — no
daily summary, no "nothing to report." Only five reasons create a task,
and the notebook ~/.config/bankread/brief-vu.json prevents the same late package from
generating one per day for two weeks.
run-brief passes a CLOSED list of tools to claude --allowedTools. No Gmail
write tool is in it: the brief reads mail, it never replies. And nothing
is left to an authorization prompt, since no one is in front of the screen to
answer at 7:30 AM.
The model called is a replaceable driver (brief/agents/), not a hardcoded call:
BANKREAD_AGENT=aucun brief/run-brief runs the brief without any AI, and the
projection still lands in the journal. Reading accounts has never needed
a model — see docs/integration.md.
launchd/install.sh installs only that agent. An install script that does more
than its name ends up reinstalling something dead, and you spend the evening
figuring out why two copies are running.
Switching providers
The coupling is thin, and it's verified by a test (test_le_contrat_tient_en_deux_methodes):
depends on the provider? | |
| yes — tokens, quotas, HTTP, consent flow |
| it chooses which one to load, and writes the contract as a |
| yes, partially — the linking flow |
| no, and not a single direct import anymore |
To wire in a third provider, all you need is a module exposing these two
methods — the Protocol in provider.py declares them, and provider.charger() makes the
choice:
balances(account_id) -> {"balances": [...]}
transactions(account_id, date_from, date_to) -> {"transactions": {"booked": [...]}}The expected format is that of the Berlin Group: balanceType / balanceAmount for
balances, bookingDate and transactionAmount signed for transactions. If the
provider speaks something else, the translation is paid for in its client and nowhere
else — see enablebanking._operation(), which restores the sign to amounts
that Enable Banking always delivers positive.
Three pitfalls encountered while writing the Enable Banking client, not to be rediscovered:
the sign of amounts is carried next to the amount (
credit_debit_indicator), not in it. Copying it as-is would count every debit as an inflow;the full history only lasts an hour after signing (see above);
the granted consent duration can be shorter than the one requested: it's the bank's response that gets recorded, otherwise
doctorannounces a valid consent two months after its death.
Tests
python3 test_bankread.py51 tests, stdlib only, no network. They mainly check the cases where the code must stay silent: two occurrences don't make a due date, a thirty-hour cache is no longer a balance, you don't project on a balance never observed. A detection that gets the date wrong doesn't crash — it announces taxes on the 12th instead of the 15th, with the same confidence.
What isn't versioned
~/.config/bankread/state.json (linked accounts, tokens, consent dates) and
~/.cache/bankread/ — specific to this machine and this consent. The provider
credentials are nowhere on disk: they're in the macOS keychain,
service bankread-enablebanking (or bankread-gocardless), RSA private key included.
⚠️ ~/.local/share/bankread/ledger/ is separate: it's the register, and it doesn't get
purged. What it contains, the bank can no longer give back — beyond 90 days, it has
forgotten. Deleting it with the cache means starting over with three months of memory. It's
stored in data and not in cache precisely to make that confusion
hard. Accepted trade-off: it's a year of bank transactions in plain text on
disk, in 0600.
Available Tools
6 toolsbanque_comptesB
La liste des comptes liés, leur banque et l'état de leur consentement.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden of behavioral disclosure, but it only states the output contents. It does not mention read-only behavior, required authentication, possible empty results, or any side effects, leaving significant behavioral ambiguity.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single concise sentence that immediately states the tool's output. Every word contributes to the purpose, with no filler or redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter read-only listing tool, the description is reasonably complete: it names the returned entity and key fields. It could be slightly richer by noting when this list is meaningful or how consent state is represented, but the low complexity makes this sufficient.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters and the input schema is fully described, so parameter-level documentation is unnecessary. The baseline of 4 applies because there is nothing for the description to compensate for.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly identifies the tool as returning the list of linked accounts, their bank, and consent status, which differentiates it from siblings like soldes, transactions, or projection. However, it lacks an explicit action verb such as 'List' or 'Retrieve', relying on the noun phrase 'La liste' to convey the operation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no explicit guidance about when to use this tool versus the sibling tools. The intended use is only implied by the word 'comptes', so an agent receives no clear context for selection or exclusion.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
banque_echeancesA
Les opérations qui reviennent (prélèvements ET rentrées), détectées sur l'historique : cadence, montant médian, date du prochain passage. Chacune porte confidence : "sure" (≥3 passages réguliers) ou "faible" (2 passages — une coïncidence possible, à ne pas annoncer comme un fait). annuel_detectable dit si l'historique remonte assez loin pour qu'une échéance annuelle ait pu être vue passer deux fois ; s'il est faux, l'absence de taxe foncière ne prouve RIEN et toute projection est optimiste — le dire, plutôt que conclure que tout va bien. jours_avant_annuel_detectable donne le délai : la banque ne rend que ~90 jours, mais bankread accumule localement, donc ce nombre descend tout seul à chaque lecture.
| Name | Required | Description | Default |
|---|---|---|---|
| compte | No | Identifiant du compte. Omis : le premier compte lié. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It discloses confidence thresholds ('sure' ≥3 passages, 'faible' for 2), explains that low confidence should not be announced as fact, details the annual detectability limitation (absence of tax foncière proves nothing if history is too short), and notes that bankread accumulates locally extending the ~90-day bank window. This is rich behavioral context beyond basic functioning.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is dense but well-structured: it opens with the main output, then explains confidence levels, annual detection, and local accumulation in separate clauses. Every sentence adds value, but the technical details make it somewhat long. It is appropriately sized for the complexity without redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description must convey the return structure. It mentions all key fields (cadence, montant médian, date du prochain passage) and specific metadata (confidence, annuel_detectable, jours_avant_annuel_detectable). It lacks an explicit field list or error conditions, but given the single input parameter and straightforward purpose, the description is sufficiently complete for agent invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% for the single parameter, which is self-explanatory ('Identifiant du compte. Omis : le premier compte lié.'). The description adds no additional parameter details, but does not need to since the schema already covers it. Baseline 3 is appropriate for high coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description explicitly states the tool's function: detecting recurring operations (both debits and credits) from history and providing cadence, median amount, and next occurrence date. This is a specific verb+resource (detect recurring operations) and clearly distinguishes it from siblings like transactions or projection.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies when to use it (when you need recurring operation detection) and adds context about historical depth limits. It does not explicitly name alternatives or exclusions, but the sibling tools are distinct enough that this purpose is unambiguous. A clear context is present without explicit when-not guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
banque_projectionA
LE croisement : solde d'aujourd'hui moins les échéances sûres à venir, déroulé jour par jour. Rend franchissement (quand le solde passe sous le plancher, et quelle échéance l'y pousse), point_bas et le détail des mouvements. C'est ce qui répond à « est-ce que ça passe avant la fin du mois », là où une alerte de seuil bancaire n'avertit qu'après coup. Refuse de projeter sur un solde non observé plutôt que d'inventer une date.
| Name | Required | Description | Default |
|---|---|---|---|
| jours | No | Fenêtre de projection en jours (défaut 45). | |
| compte | No | Identifiant du compte. Omis : le premier compte lié. | |
| plancher | No | Seuil sous lequel alerter, en euros (défaut 0). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the transparency burden. It adds meaningful behavioral detail: the projection is day-by-day, returns specific computed fields, and refuses to project on an unobserved balance rather than fabricate a date. It does not discuss errors, side effects, or permissions, but the read-only projection behavior is well conveyed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four short sentences, front-loaded with the core concept and no filler. Every sentence adds value: computation, outputs, use case/alternative, and a refusal edge case.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description must explain return values; it names the key outputs and covers the main edge case. It could be slightly more explicit about the `point_bas` result and exact output shape, but it is sufficient for a small projection tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description adds useful semantic context by explaining the computation ('today's balance minus certain upcoming due dates, day by day') and the notion of the floor (`franchissement` when balance drops below it), which enriches the schema's minimal field descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly identifies a projection tool: it crosses today's balance with upcoming certain due dates and rolls it out day by day. It names concrete outputs (`franchissement`, `point_bas`, movement details) and distinguishes itself from an after-the-fact bank threshold alert.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly states when to use it: to answer 'will it pass before the end of the month.' It also contrasts itself with a threshold alert that only warns after the fact, though it does not name sibling tools or describe exclusion cases beyond that contrast.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
banque_santeA
État du lien bancaire : secrets présents, comptes liés, jours restants avant expiration du consentement DSP2, quotas d'appels, et registres — la profondeur d'historique réellement accumulée par compte, qui est supérieure à ce que la banque rend aujourd'hui. Aucun appel réseau, donc gratuit en quota. À appeler en premier quand quelque chose paraît manquer, et une fois par semaine pour voir venir le renouvellement à 90 j.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the behavioral transparency burden. It discloses that the tool makes no network call ('Aucun appel réseau, donc gratuit en quota') and that 'registres' contains more history than the bank actually returns. This is valuable, though it doesn't explicitly describe side effects or permissions.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise and well-structured: it front-loads the purpose, lists contents, then provides usage guidance. Every sentence contributes meaningful information without redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter inspection tool with no output schema, the description fully covers what the tool returns and when to invoke it, including the important nuance about 'registres' and the weekly renewal check.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has zero parameters, so there is nothing to explain. The description adds context about what the tool reports, which is sufficient given the lack of parameters.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool provides an overview of the bank link status, enumerating specific contents (secrets, linked accounts, consent expiry, quotas, registres). This distinguishes it from sibling tools that fetch specific data like transactions or balances.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit usage guidance is given: 'À appeler en premier quand quelque chose paraît manquer, et une fois par semaine pour voir venir le renouvellement à 90 j.' It also notes that it makes no network call and is free in quota, helping the agent decide when to use it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
banque_soldesA
Le solde disponible de chaque compte (interimAvailable : opérations en cours déduites). Toute réponse porte etat : "observe" (lu à l'instant), "ancien" (servi du cache, voir age_lisible) ou "inconnu" (rien de fiable — ne jamais présenter cela comme un solde nul ou une panne). Le quota est de 4 lectures par jour et par compte : laisser rafraichir à faux sauf demande explicite d'un chiffre à la seconde.
| Name | Required | Description | Default |
|---|---|---|---|
| compte | No | Identifiant du compte. Omis : le premier compte lié. | |
| rafraichir | No | Forcer un appel réseau. Consomme du quota. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description fully discloses behavior: it explains the 'etat' field values (observe, ancien, inconnu), instructs not to misinterpret 'inconnu' as zero or failure, and mentions the quota and caching behavior. This gives the agent a clear understanding of what to expect and how to handle edge cases.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise, consisting of three sentences that efficiently convey the core functionality, the response's reliability states, and the quota constraint. No unnecessary verbosity; every sentence adds value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description provides essential context about the response, including the 'etat' and 'age_lisible' fields, and the quota behavior. However, it does not detail the full response structure (e.g., balance amount, currency) or specify behavior for multiple accounts, which could be considered a minor gap in completeness.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The description adds significant context beyond the schema: it explains the operational impact of 'rafraichir' (consumes quota, forces network call) and clarifies the default behavior. It also relates the 'etat' field to the parameters, enhancing the schema's basic definitions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states that the tool returns the available balance of each account, with detailed explanation of the 'etat' field. It is distinct from the sibling tools (health, accounts, schedules, transactions, projections) as it specifically targets balances.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit guidance on when to set 'rafraichir' to true versus false, based on the quota and need for real-time data. However, it does not explicitly differentiate when to use this tool over the sibling tools, though the purpose inherently implies it for balance queries.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
banque_transactionsA
Les opérations passées d'un compte, les plus récentes d'abord. Sert à vérifier une échéance annoncée ou à retrouver un achat précis. Toute réponse porte etat : "observe" (lu à l'instant), "ancien" (servi du cache, voir age_lisible) ou "inconnu" (rien de fiable — ne jamais présenter cela comme un solde nul ou une panne).
| Name | Required | Description | Default |
|---|---|---|---|
| jours | No | Profondeur en jours (défaut 30). | |
| compte | No | Identifiant du compte. Omis : le premier compte lié. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Despite no annotations, the description thoroughly explains the 'etat' field, including the distinction between 'observe', 'ancien', and 'inconnu', and warns against misinterpreting 'inconnu' as a zero balance or failure. This provides strong transparency about caching and data reliability.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise and well-structured, using two sentences to cover purpose, usage, and the important 'etat' semantics. Every sentence adds value, with no redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the simplicity of the tool (two optional parameters) and the lack of an output schema, the description adequately covers the essential behavior, including the meaning of the 'etat' field. It doesn't specify all returned transaction fields, but that is often assumed for a transaction list.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema already fully describes both parameters ('jours' as days with default, 'compte' as identifier with fallback). The description adds no additional parameter-specific meaning beyond the schema, so the baseline score of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states that the tool retrieves past transactions for an account, ordered most recent first. It also provides specific use cases like verifying a due date or finding a purchase, which clarifies its purpose. However, it lacks an explicit verb like 'list' or 'get', so it's not maximally direct.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives specific scenarios when to use the tool ('check an announced due date' or 'find a specific purchase'), which serves as guidance. It doesn't explicitly compare to sibling tools, but the context is sufficient for typical use.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
6 tool updates
v1.0.0- First observed
banque_comptes - First observed
banque_echeances - First observed
banque_projection - First observed
banque_sante - First observed
banque_soldes - First observed
banque_transactions
TDQS
Scored across 6 tools
Each tool targets a distinct aspect of banking data: health/status, accounts, balances, recurring operations, transactions, and projections. No two tools overlap in purpose, making selection unambiguous.
All tool names follow the consistent banque_<noun> pattern, clearly indicating the banking domain and the resource each tool addresses. This naming convention is uniform and predictable.
With exactly six tools, the server is well-scoped for its purpose. Each tool covers a necessary function for banking analysis, and the count is within the ideal 3-15 range.
The tool set provides comprehensive coverage of the banking domain: health checks, account listing, balances, recurring payment detection, transaction history, and cash-flow projection. There are no obvious missing capabilities for a read-only banking analytics tool.
Maintenance
Related MCP Connectors
An MCP server that provides read access to your cloud storage providers, bank accounts and more.
MCP server for Modern Treasury — payment orders, transactions, counterparties and ledgers.
MCP server for Codat — companies, connections, invoices, bills and financial statements.
Personal finance for AI agents — onboard, import statements, categorize & budget over MCP.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceMCP server that turns bank transactions into a financial digest including cash-flow forecast, spending breakdown, fee detection, and receipt reconciliation, exposing deterministic engines as JSON-RPC tools.Apache 2.0
- FlicenseNot gradedqualityBmaintenanceMCP server for personal finance management. Enables natural language expense logging, budgeting, recurring charge detection, and statement import with deterministic local calculations.-
- FlicenseNot gradedqualityBmaintenanceMCP server for personal finance via Open Finance, consolidating accounts and cards and answering spending questions with aggregated numbers. Provides tools for category spending, recurring subscriptions, budgets, card bills, and installment forecasts, with data stored locally in an encrypted SQLite database.1-
- AlicenseAqualityCmaintenanceMCP server that reads and annotates Kontist business banking data, including balances, transactions, and tax reserves.7Apache 2.0