Documentation Index
Fetch the complete documentation index at: https://docs.moneda.com/llms.txt
Use this file to discover all available pages before exploring further.
@moneda/services exports getAgentTools(userId, email?) — a ready-to-bind tool surface for LLM agents that need to read Moneda data. It packages all 29 read operations the MCP server exposes as provider-agnostic descriptors you wrap in your AI SDK’s tool factory (Anthropic, OpenAI, Gemini, Mastra, Vercel AI SDK, etc.).
Use this when you’re building an in-process agent (support chatbot, internal assistant, background automation). It’s roughly 7–10× cheaper per query than hitting the MCP server over HTTP — the MCP copy stays for external third-party agents that need OAuth + scoped external access.
This is an SDK-level API, not an HTTP endpoint. Import it from
@moneda/services in a Node process that already has a Moneda user ID — typically your support chatbot service or an internal agent worker.Why is it cheaper than MCP?
| Lever | MCP-over-HTTP | Agent Tools |
|---|---|---|
| Tool schema size | 37 multi-paragraph descriptions (~18k tokens) re-sent every turn | 29 terse descriptions (~1.1k tokens), can be prompt-cached |
| Response encoding | JSON (verbose) | TOON (~40% smaller) |
| Response shape | Full service shape with UI coaching fields | Lite projection — drops IDs, raw addresses, derived counts, UI hints |
| Transport | HTTP round-trip per call | In-process function call |
| Path | Cost |
|---|---|
| MCP-over-HTTP | ~$0.34 |
| Agent Tools (no caching) | ~$0.03–0.05 |
Agent Tools (with cache_control on prefix) | ~$0.01–0.02 |
Quick start
What’s in the box
Every descriptor has{ description, parameters, execute }:
description— terse (~30–50 tokens). Your caller is free to prepend agent-coaching on top.parameters— a Zod schema with tight enums so the agent’s guess-space is narrow and tool calls validate more often.execute(args)— returns aPromise<string>. The string is TOON-encoded, with the lite projection +pruneEmptyalready applied.
Available tools
Account & balance:get_balance—{ currency?: "USD"|"EUR"|"CHF" }get_wallet—{}get_transactions— rich filters, see belowget_spending_by_type_group—{ period: "7d"|"30d"|"90d", currency? }get_virtual_accounts—{}get_my_accounts—{}
get_exchange_rate—{ from, to }get_apy_rates—{ currency? }
get_points_balance—{}get_points_activity—{}get_referral_code—{}(requires email; lazily enrolls the user in GrowSurf on first call)get_referees—{}(requires email)
get_contacts—{ search?, limit?, offset? }get_recovery_contacts—{}list_recovery_emails—{ accountId?: string }— ZK email-based account recoveryget_recovery_email—{ id }get_recovery_config—{ accountId? }— accepted emails, total weight, threshold,fullySetflagget_recovery_status—{ accountId? }— most recent recovery snapshot; emails anonymized asa***@domainget_passkeys—{}get_settings—{}
list_notifications—{ cursor?, limit?, filter?: "all" | "unread" }get_unread_notification_count—{}(cheaper thanlist_notificationswhen you only need the count)
search_knowledge—{ query, category?, limit? }get_faq_category—{ slug }get_faq_item—{ id }
list_sub_accounts—{ includeClosed?: boolean }get_sub_account—{ id }get_sub_account_balance—{ id, currency?: "USDC"|"EURC"|"CHFAU" }get_total_wealth—{}(aggregates main account + every live vault)
AGENT_TOOL_NAMES is exported as a const array for allowlisting, analytics, or admin UIs that want to enumerate capabilities without building the full descriptor set.
get_transactions — lite by default, detail: true to opt into full
Returns the compact shape by default — hash, direction, amount, currency, status, date, trimmed counterparty. On a single-hash drill-down (e.g. “why did this transaction fail?”), pass detail: true along with transactionHash to get the full row (typeGroup, category, note, reference, raw counterparty routing, etc.):
Response shape — lite projections
Each tool’sexecute runs the service output through a hand-picked field allowlist (project* in @moneda/services) and then through pruneEmpty before TOON-encoding.
get_walletdropsnetwork,supportedTokens,warning,tip(~76% smaller)get_virtual_accountsdropsminimumTransfer,firstPartyPayments,thirdPartyPayments,capabilityInfo(~78% smaller)get_balancedropssource,notice,snapshotTimestamp; collapses snapshot metadata to an optionalstalefield on the fallback path (~22% live, ~65% on snapshot)get_transactionsdropstypeGroup,type,category,note,reference,exchanged*,received*, raw counterparty routing (~27% list, ~48% single row)get_my_accounts,get_contacts,get_recovery_contacts,get_passkeys,get_points_activity,get_referees,get_referral_code— seelite.tsfor the exact allowlist.
Pair with prompt caching for the real win
The agent-tools descriptor set + your system prompt are cacheable. Wirecache_control on the prefix once and every subsequent conversation turn pays ~10% of the input cost on that portion. For a support chatbot with 3–5 turns, that typically compounds to another 3–5× savings on top of the lite projection.
packages/services/src/agent-tools.ts for the descriptor factory and packages/services/src/lite.ts for the projections.
When to use MCP instead
Use the MCP server when the agent runs in a third-party client (Claude Desktop, ChatGPT over MCP, Cursor) and needs OAuth + scope-gated external access with human-in-the-loop approval for writes. Use Agent Tools (this SDK) when the agent runs in your own process, you already have the authenticateduserId, and you’re paying the tokens yourself. The support chatbot is the canonical use case.