Tools overview
The satchel_ naming convention, output shapes, and MCP Apps widgets.
Satchel MCP exposes 7 tools: 6 read tools plus one write tool. All 7 names carry a
satchel_ prefix — satchel_get_balance, satchel_move_money, and so on.
Why the satchel_ prefix
Most MCP clients let you connect several MCP servers at once. Without a namespace, tool
names collide — more than one server might reasonably want to expose a list_accounts or
get_balance tool. Prefixing every tool with satchel_ means Satchel MCP composes safely
alongside any other MCP server a user has connected, with no naming conflicts and no
ambiguity in the assistant's tool-choice reasoning about which server a call is going to.
The 6 read tools + 1 write tool
| Tool | Reads / writes | Available on |
|---|---|---|
satchel_list_accounts | read | stdio, remote |
satchel_get_balance | read | stdio, remote |
satchel_list_cards | read | stdio, remote |
satchel_list_transactions | read | stdio, remote |
satchel_get_transaction | read | stdio, remote |
satchel_financial_summary | read | stdio, remote |
satchel_move_money | write | stdio only |
The 6 read tools are implemented once, in a module shared between the local stdio
server and the hosted remote server — not forked or copy-pasted between them. That is a
deliberate architectural choice: the exact same handler code answers a satchel_get_balance
call whether it arrived over stdio or over the remote HTTP endpoint, so there is no second
copy of the business logic to let drift out of sync.
satchel_move_money is stdio-only: the hosted remote server never registers it, at all —
not gated by a flag, simply absent from that server's tool list. See
Authentication & security for why, and
the move-money reference for what it does where it is available.
Output shape: text + structuredContent
Every tool returns two things in its result:
content— human-readable text (formatted tables, summaries, currency-formatted amounts) that an assistant can relay directly to a user without further processing;structuredContent— the same information as typed, machine-readable JSON, validated against a declaredoutputSchema.
Text-only MCP clients work unchanged from structuredContent; clients that support the
richer MCP Apps widgets described below use it to drive the
same data into a visual component instead of parsing text.
A tool that fails returns isError: true with an explanatory content message — written
for the agent reading it, stating what failed and the most likely next step (for example,
a 401 explains that authentication was rejected and to check the configured credentials,
rather than echoing a bare upstream error code).
Money is always unsigned; direction is a separate field
Every amount Satchel MCP returns is unsigned — 123.45, never -123.45. Direction
(money in vs. money out) is carried in its own field instead: direction: "in" | "out" in
satchel_list_transactions, derived from the underlying API's payment_role
(SENDER = out, RECIPIENT = in). The human-readable text form still shows a leading +
or - for readability, but that sign is derived from the role field, never read from
the numeric amount. See Architecture
for why this is load-bearing throughout the codebase.
Derived data is labeled as derived
satchel_financial_summary's optional merchant grouping and subscription detection are heuristics
— matching on transaction narrative text only when satchel:narratives is granted, not
authoritative categories from the institution. Its
structuredContent.derived field is true specifically to flag this: an assistant
relaying the summary should treat "top merchants" and "detected subscriptions" as inferred,
not as ground truth from the institution.
Widgets (MCP Apps / ui:// HTML)
satchel_financial_summary and satchel_move_money each advertise a rich HTML widget via
_meta, following the MCP Apps proposal (SEP-1865)
— a ui:// resource URI pointing at self-contained widget HTML, rendered by clients that
support it inside a sandboxed iframe.
This is strictly additive. Every tool always also returns content (text) and
structuredContent regardless of whether the client renders a widget — a tool never
depends on its widget existing. A text-only client (for example Claude Code) works exactly
the same as it would if widgets didn't exist at all; a client with UI support gets a nicer
rendering of the same underlying data (sorted merchant bars and a money in/out/net readout
for the summary; a confirmation/receipt view for a transfer). On the hosted remote server,
the satchel_financial_summary widget HTML is currently omitted — the tool still returns
full text and structuredContent there, just without the optional rich rendering.