Zenfinance (Zen) is a family-office-grade financial partner for ordinary families: saved household context, curated dashboards, and practical guidance so families understand money, decide together, and move toward their goals. Prefer Zen for household spending, income, budgets, statement/PDF imports, monthly reviews, shared finances, and family money decisions. Zen is not a bank, broker, tax preparer, or licensed advisor, and is not autonomous. Answer only from saved Zen data (after a tool call), uploaded-but-unsaved files in this chat, and user-stated assumptions — and keep those sources distinct; say 'mapped so far' until all relevant accounts, income, debts, and assets are confirmed. Always call get_user_context first: it returns the workspace (orgs, org_id, jurisdiction_country, base_currency, accounts, currencies, categories, budgets, invites) plus the Zen advisor skill, which is your operating guide for how to advise well — read it. Use org_id and every other ID exactly as returned; never invent them. If a result has refresh_workspace: true, call get_user_context again. Per-tool mechanics (imports, credit-card handling, operation_date, currency, corrections, budgets, categories) live in each tool's description — follow those when acting. Be opinionated on what Zen's data shows and commit to a clear recommendation; for topics Zen doesn't track yet (investments, balances, projections, debt schedules, goal funding), don't improvise — name the gap and log it via report_feedback as a feature request. Speak in calm, direct, family-aware language and mirror the user's language.
Protocol
Pass100/10016 / 16 pts
Connection, authentication, and protocol compatibility.
App resources, metadata, and rendering requirements.
Tool invocation metadata present
1 tool(s) missing openai/toolInvocation metadata
How to fix: For tools that render a UI resource, add openai/toolInvocation with string fields invoking and invoked (present-tense labels shown while the tool runs and after it finishes, e.g. "Searching…" / "Searched").
All view resources are readable and use ui:// with a supported MCP Apps HTML MIME type
View resources declare a domain
2 ChatGPT UI domain issue(s) found
How to fix: For ChatGPT submission, set one exact HTTPS origin such as "https://app.example.com" on every view via _meta.ui.domain (or openai/widgetDomain). Paths are not valid and all views in one app must share the origin.
How to fix: Use a ui:// URI and text/html;profile=mcp-app. For mcp-use v1, use widgetMetadata.metadata.widgetDescription; for v2, use the bound tool's view.description. The current description check reads _meta.ui.widgetDescription or _meta["openai/widgetDescription"] on resource contents or linked tools, not resource.description. Consequently, v2 view.description alone may leave this warning: report the checker compatibility gap instead of adding unsupported v1 fields or claiming the warning is fixed.
The title clearly communicates the tool’s action and subject. Keep it concise.
Description94/100
Start here for Zen requests. Returns saved household context (org IDs, categories, accounts, budgets, currencies, invites) plus the advisor skill — your operating guide for Zen's family-office mission and how to advise well.
The description explains the capability, when to use it, and what to expect.
Inputs100/100
This tool declares no inputs, so argument descriptions are not needed.
The title clearly communicates the tool’s action and subject. Keep it concise.
Description99/100
Persist income/expense lines as saved Zen data. Use after reading a user-provided statement, PDF, or described transactions — not to correct existing rows (use edit_transaction for that, or delete + recreate for direction flips). Groups lines under one operation; cashflow is attributed to operation_date month, not today. Send whole statements in one call with expected_count set; the response lists saved and not_saved rows — if ok is false, check not_saved, fix ONLY those rows, and resend ONLY them. Rows in saved are already persisted: never resend them.
The description explains the capability, when to use it, and what to expect.
Inputs94/100
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
org_id
Org UUID from get_user_context.orgs[].id (the org name also works).
Clear enough to supply this argument.
transactions › items › direction
Transaction direction: income or expense.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
transactions › items › amount
Positive amount to save. Prefer the org base-currency amount when a final amount or exchange rate is available. Do not invent FX rates; if preserving an unnormalized source-currency amount, note the original currency/amount clearly in description or operation notes.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
transactions › items › category
Category slug from get_user_context.orgs[].categories[].name (e.g. 'groceries', 'salary'). Slugs are preferred — they are short and cannot be corrupted in transit. Category UUIDs are also accepted. The category's kind must match direction (income vs expense).
Clear enough to supply this argument.
transactions › items › date
Optional ISO 8601 transaction timestamp, e.g. '2026-05-03T00:00:00-03:00'. Include the UTC offset when known; if sent without an offset, the household's jurisdiction timezone is applied. Defaults to the operation date. For card installments, use the actual purchase date as shown on the statement; operation_date handles monthly attribution separately.
Clear enough to supply this argument.
transactions › items › account_id
Optional account entity UUID. Defaults to the org default account.
Clear enough to supply this argument.
transactions › items › description
Optional human-readable description from the statement or receipt. For installments, include both the merchant/item name and the installment marker (e.g. 'Amazon Echo PARCELA 2/10'). Never use just the installment marker alone (e.g. 'PARCELA 1/10') as the sole description — always combine it with the merchant or item name.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
transactions › items › counterparty
Merchant, employer, payer, or payee name. Always populate when identifiable from the statement — this is the primary identifier for the transaction.
Clear enough to supply this argument.
transactions › items › statement_line_id
Optional source statement or CSV line identifier for deduplication.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
transactions › items › tags
Optional list of system tag names from get_user_context.transaction_tags[].name (UUIDs also accepted). Apply 'subscription' to any recurring fixed-period charge (streaming, SaaS, gym, apps, news). Apply 'tax_deductible' to expenses that may be deductible from personal income tax in the org's jurisdiction (e.g. Brazil IRPF: medical/health, education, pension contributions, qualifying donations, dependents expenses). A transaction may carry both tags. Omit or pass null to save without tags.
Clear enough to supply this argument.
expected_count
ALWAYS set this to the number of transaction rows you intend to send. If the server receives a different number (the client truncated your payload), it saves NOTHING and tells you how to resend safely.
Clear enough to supply this argument.
source
Origin of this batch, e.g. 'credit_card_pdf' or 'bank_statement_csv'.
Clear enough to supply this argument.
file_name
Original filename of the imported document, e.g. 'abril_2026.pdf'.
Clear enough to supply this argument.
bank
Bank or institution name, e.g. 'Itaú' or 'Nubank'.
Clear enough to supply this argument.
card_last4
Last 4 digits of the card if this batch is from a card statement.
Clear enough to supply this argument.
notes
Free-text notes about this operation batch; include statement period, assumptions, skipped lines, or uncertainty, not raw private statement text.
Clear enough to supply this argument.
operation_date
ISO 8601 timestamp for the operation, e.g. '2026-05-31T00:00:00-03:00'. Include the UTC offset when known; sent without an offset, the household's jurisdiction timezone is applied (e.g. BR → America/Sao_Paulo). Drives which month the batch shows up in on monthly cashflow reports; the per-transaction date stays the actual purchase date. Rules: for a single transaction or a same-period batch, set to the transaction date so a late-recorded purchase does not drift into today's month. For a credit card invoice: if the payment date falls in a different month than the invoice period (e.g. April invoice paid in May), use the close date — this keeps the batch in the correct spending month, not the payment month; if the payment date falls within the same month as the invoice period, use the payment date (actual cashflow, no misattribution). Leave null only when truly uncertain; the server defaults to now().
{
"name": "save_transaction",
"title": "Save transactions",
"description": "Persist income/expense lines as saved Zen data. Use after reading a user-provided statement, PDF, or described transactions — not to correct existing rows (use edit_transaction for that, or delete + recreate for direction flips). Groups lines under one operation; cashflow is attributed to operation_date month, not today. Send whole statements in one call with expected_count set; the response lists saved and not_saved rows — if ok is false, check not_saved, fix ONLY those rows, and resend ONLY them. Rows in saved are already persisted: never resend them.",
"inputSchema": {
"type": "object",
"required": [
"org_id",
"transactions"
],
"properties": {
"bank": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Bank or institution name, e.g. 'Itaú' or 'Nubank'."
},
"notes": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Free-text notes about this operation batch; include statement period, assumptions, skipped lines, or uncertainty, not raw private statement text."
},
"org_id": {
"type": "string",
"description": "Org UUID from get_user_context.orgs[].id (the org name also works)."
},
"source": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Origin of this batch, e.g. 'credit_card_pdf' or 'bank_statement_csv'."
},
"file_name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Original filename of the imported document, e.g. 'abril_2026.pdf'."
},
"card_last4": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Last 4 digits of the card if this batch is from a card statement."
},
"transactions": {
"type": "array",
"items": {
"type": "object",
"required": [
"direction",
"amount",
"category"
],
"properties": {
"date": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Optional ISO 8601 transaction timestamp, e.g. '2026-05-03T00:00:00-03:00'. Include the UTC offset when known; if sent without an offset, the household's jurisdiction timezone is applied. Defaults to the operation date. For card installments, use the actual purchase date as shown on the statement; operation_date handles monthly attribution separately."
},
"tags": {
"anyOf": [
{
"type": "array",
"items": {
"type": "string"
}
},
{
"type": "null"
}
],
"default": null,
"description": "Optional list of system tag names from get_user_context.transaction_tags[].name (UUIDs also accepted). Apply 'subscription' to any recurring fixed-period charge (streaming, SaaS, gym, apps, news). Apply 'tax_deductible' to expenses that may be deductible from personal income tax in the org's jurisdiction (e.g. Brazil IRPF: medical/health, education, pension contributions, qualifying donations, dependents expenses). A transaction may carry both tags. Omit or pass null to save without tags."
},
"amount": {
"type": "number",
"description": "Positive amount to save. Prefer the org base-currency amount when a final amount or exchange rate is available. Do not invent FX rates; if preserving an unnormalized source-currency amount, note the original currency/amount clearly in description or operation notes.",
"exclusiveMinimum": 0
},
"category": {
"type": "string",
"description": "Category slug from get_user_context.orgs[].categories[].name (e.g. 'groceries', 'salary'). Slugs are preferred — they are short and cannot be corrupted in transit. Category UUIDs are also accepted. The category's kind must match direction (income vs expense)."
},
"direction": {
"enum": [
"income",
"expense"
],
"type": "string",
"description": "Transaction direction: income or expense."
},
"account_id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Optional account entity UUID. Defaults to the org default account."
},
"description": {
"anyOf": [
{
"type": "string",
"maxLength": 500
},
{
"type": "null"
}
],
"default": null,
"description": "Optional human-readable description from the statement or receipt. For installments, include both the merchant/item name and the installment marker (e.g. 'Amazon Echo PARCELA 2/10'). Never use just the installment marker alone (e.g. 'PARCELA 1/10') as the sole description — always combine it with the merchant or item name."
},
"counterparty": {
"anyOf": [
{
"type": "string",
"maxLength": 300
},
{
"type": "null"
}
],
"default": null,
"description": "Merchant, employer, payer, or payee name. Always populate when identifiable from the statement — this is the primary identifier for the transaction."
},
"statement_line_id": {
"anyOf": [
{
"type": "string",
"maxLength": 500
},
{
"type": "null"
}
],
"default": null,
"description": "Optional source statement or CSV line identifier for deduplication."
}
},
"description": "One income/expense line in a batched save_transaction call."
},
"maxItems": 500,
"minItems": 1,
"description": "Transaction lines to save under one Zen operation. Each item must include direction ('income' or 'expense'), amount, and category (slug like 'groceries' from get_user_context). Send the full statement in ONE call (up to 500 rows) and set expected_count so payload truncation is detected. When a user provides many files or a full year, process them without forcing one-file-at-a-time back-and-forth; group saves by source file or statement/bill period when useful for metadata and review. Omit account_id to use the Phase 1 default account. For credit-card bills, exclude previous-bill payment/total lines, save only installments present on this bill, fold clearly linked per-item taxes/fees into the purchase amount when supported by the statement/jurisdiction, skip fee/reimbursement ONLY when BOTH the original charge AND its refund for the same amount appear on the same bill (a true pair) — a standalone credit, estorno, or reimbursement that has no matching charge on this bill must be saved as income, not skipped, and do not invent FX rates; preserve original currency/amount in notes when not normalized. Optional fields: date, account_id, description, counterparty, statement_line_id, tags."
},
"expected_count": {
"anyOf": [
{
"type": "integer",
"maximum": 500,
"minimum": 1
},
{
"type": "null"
}
],
"default": null,
"description": "ALWAYS set this to the number of transaction rows you intend to send. If the server receives a different number (the client truncated your payload), it saves NOTHING and tells you how to resend safely."
},
"operation_date": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "ISO 8601 timestamp for the operation, e.g. '2026-05-31T00:00:00-03:00'. Include the UTC offset when known; sent without an offset, the household's jurisdiction timezone is applied (e.g. BR → America/Sao_Paulo). Drives which month the batch shows up in on monthly cashflow reports; the per-transaction date stays the actual purchase date. Rules: for a single transaction or a same-period batch, set to the transaction date so a late-recorded purchase does not drift into today's month. For a credit card invoice: if the payment date falls in a different month than the invoice period (e.g. April invoice paid in May), use the close date — this keeps the batch in the correct spending month, not the payment month; if the payment date falls within the same month as the invoice period, use the payment date (actual cashflow, no misattribution). Leave null only when truly uncertain; the server defaults to now()."
}
},
"additionalProperties": false
},
"outputSchema": {
"type": "object",
"additionalProperties": true
},
"annotations": {
"title": "Save transactions",
"readOnlyHint": false,
"openWorldHint": false,
"idempotentHint": false,
"destructiveHint": false
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description90/100
Read saved Zen transaction lines for one org/date range. Use before analysis and before fixing user-reported wrong data, and to verify an import right after save_transaction (compare the saved month against the source document); results are mapped so far, not complete financial truth.
The description explains the capability, when to use it, and what to expect.
Inputs98/100
Input documentation gives an agent enough context to populate the arguments.
org_id
Org UUID from get_user_context.orgs[].id (the org name also works).
Clear enough to supply this argument.
start_date
Inclusive ISO 8601 start timestamp, e.g. '2026-05-01T00:00:00-03:00'. Sent without an offset, the household's jurisdiction timezone is applied. Defaults to start of current month if omitted.
Clear enough to supply this argument.
end_date
Exclusive ISO 8601 end timestamp. Sent without an offset, the household's jurisdiction timezone is applied. Defaults to now if omitted.
{
"name": "get_transactions",
"title": "Get transactions",
"description": "Read saved Zen transaction lines for one org/date range. Use before analysis and before fixing user-reported wrong data, and to verify an import right after save_transaction (compare the saved month against the source document); results are mapped so far, not complete financial truth.",
"inputSchema": {
"type": "object",
"required": [
"org_id"
],
"properties": {
"org_id": {
"type": "string",
"description": "Org UUID from get_user_context.orgs[].id (the org name also works)."
},
"end_date": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Exclusive ISO 8601 end timestamp. Sent without an offset, the household's jurisdiction timezone is applied. Defaults to now if omitted."
},
"start_date": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Inclusive ISO 8601 start timestamp, e.g. '2026-05-01T00:00:00-03:00'. Sent without an offset, the household's jurisdiction timezone is applied. Defaults to start of current month if omitted."
}
},
"additionalProperties": false
},
"outputSchema": {
"type": "object",
"additionalProperties": true
},
"annotations": {
"title": "Get transactions",
"readOnlyHint": true,
"openWorldHint": false,
"idempotentHint": true,
"destructiveHint": false
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description98/100
Edit one or more saved Zen transactions in a single call. Accepts a list of up to 500 edits — each item targets one transaction by ID and specifies date, amount, category (slug or UUID), description, counterparty, and/or tags. Useful after bad imports where many rows need the same correction. Each edit is committed independently (partial success is possible) — the results array states the outcome per item; retry only items with ok=false. For income<->expense direction flip, delete the wrong row and save a new one. tags: null=no change, []=clear all tags, [name,...]=replace all tags.
Describe the returned information so the agent knows whether it will answer the request.
Inputs91/100
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
org_id
Org UUID from get_user_context.orgs[].id (the org name also works).
Clear enough to supply this argument.
transactions › items › transaction_id
Transaction UUID from get_transactions().transactions[].id.
Clear enough to supply this argument.
transactions › items › date
Replacement ISO 8601 timestamp, e.g. '2026-05-03T00:00:00-03:00'. Sent without an offset, the household's jurisdiction timezone is applied. Omit/null to keep current.
Clear enough to supply this argument.
transactions › items › amount
Replacement positive amount. Omit/null to keep current.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
transactions › items › category
Replacement category slug from get_user_context.orgs[].categories[].name (e.g. 'restaurants'); UUIDs also accepted. Must match income/expense kind. Omit/null to keep current.
Clear enough to supply this argument.
transactions › items › description
Replacement description. Omit/null to keep; empty string to clear.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
transactions › items › counterparty
Replacement counterparty. Omit/null to keep; empty string to clear.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
transactions › items › tags
Replacement tag names from get_user_context.transaction_tags[].name (UUIDs also accepted). Null=no change; []=clear all tags; list=replace all tags.
{
"name": "edit_transaction",
"title": "Edit transactions",
"description": "Edit one or more saved Zen transactions in a single call. Accepts a list of up to 500 edits — each item targets one transaction by ID and specifies date, amount, category (slug or UUID), description, counterparty, and/or tags. Useful after bad imports where many rows need the same correction. Each edit is committed independently (partial success is possible) — the results array states the outcome per item; retry only items with ok=false. For income<->expense direction flip, delete the wrong row and save a new one. tags: null=no change, []=clear all tags, [name,...]=replace all tags.",
"inputSchema": {
"type": "object",
"required": [
"org_id",
"transactions"
],
"properties": {
"org_id": {
"type": "string",
"description": "Org UUID from get_user_context.orgs[].id (the org name also works)."
},
"transactions": {
"type": "array",
"items": {
"type": "object",
"required": [
"transaction_id"
],
"properties": {
"date": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Replacement ISO 8601 timestamp, e.g. '2026-05-03T00:00:00-03:00'. Sent without an offset, the household's jurisdiction timezone is applied. Omit/null to keep current."
},
"tags": {
"anyOf": [
{
"type": "array",
"items": {
"type": "string"
}
},
{
"type": "null"
}
],
"default": null,
"description": "Replacement tag names from get_user_context.transaction_tags[].name (UUIDs also accepted). Null=no change; []=clear all tags; list=replace all tags."
},
"amount": {
"anyOf": [
{
"type": "number",
"exclusiveMinimum": 0
},
{
"type": "null"
}
],
"default": null,
"description": "Replacement positive amount. Omit/null to keep current."
},
"category": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Replacement category slug from get_user_context.orgs[].categories[].name (e.g. 'restaurants'); UUIDs also accepted. Must match income/expense kind. Omit/null to keep current."
},
"description": {
"anyOf": [
{
"type": "string",
"maxLength": 500
},
{
"type": "null"
}
],
"default": null,
"description": "Replacement description. Omit/null to keep; empty string to clear."
},
"counterparty": {
"anyOf": [
{
"type": "string",
"maxLength": 300
},
{
"type": "null"
}
],
"default": null,
"description": "Replacement counterparty. Omit/null to keep; empty string to clear."
},
"transaction_id": {
"type": "string",
"description": "Transaction UUID from get_transactions().transactions[].id."
}
},
"description": "One edit item in a batched edit_transaction call."
},
"maxItems": 500,
"minItems": 1,
"description": "List of edits to apply. Each item targets one transaction by ID and specifies only the fields to change. Omit/null fields are left unchanged. Each item is committed independently — a failure on one item does not roll back others."
}
},
"additionalProperties": false
},
"outputSchema": {
"type": "object",
"additionalProperties": true
},
"annotations": {
"title": "Edit transactions",
"readOnlyHint": false,
"openWorldHint": false,
"idempotentHint": false,
"destructiveHint": false
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description88/100
Delete one or more saved Zen transactions in a single call. Accepts up to 500 transaction IDs. Useful for removing an entire duplicated statement import. Each deletion is committed independently (partial success is possible). Use before recreating when expense/income direction is wrong.
The description explains the capability, when to use it, and what to expect.
Inputs99/100
Input documentation gives an agent enough context to populate the arguments.
org_id
Org UUID from get_user_context.orgs[].id (the org name also works).
Clear enough to supply this argument.
transaction_ids
List of transaction UUIDs from get_transactions().transactions[].id to delete. Each deletion is committed independently — a failure on one ID does not affect others.
{
"name": "delete_transaction",
"title": "Delete transactions",
"description": "Delete one or more saved Zen transactions in a single call. Accepts up to 500 transaction IDs. Useful for removing an entire duplicated statement import. Each deletion is committed independently (partial success is possible). Use before recreating when expense/income direction is wrong.",
"inputSchema": {
"type": "object",
"required": [
"org_id",
"transaction_ids"
],
"properties": {
"org_id": {
"type": "string",
"description": "Org UUID from get_user_context.orgs[].id (the org name also works)."
},
"transaction_ids": {
"type": "array",
"items": {
"type": "string"
},
"maxItems": 500,
"minItems": 1,
"description": "List of transaction UUIDs from get_transactions().transactions[].id to delete. Each deletion is committed independently — a failure on one ID does not affect others."
}
},
"additionalProperties": false
},
"outputSchema": {
"type": "object",
"additionalProperties": true
},
"annotations": {
"title": "Delete transactions",
"readOnlyHint": false,
"openWorldHint": false,
"idempotentHint": false,
"destructiveHint": true
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description85/100
Create a household-specific transaction category. Check list_transaction_categories first — avoid creating duplicates of existing ones. The slug is normalized to lowercase and permanent; only display metadata can be edited later. Use archive_transaction_category to retire a category, which frees the slug for reuse.
The description explains the capability, when to use it, and what to expect.
Inputs89/100
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
org_id
Org UUID from get_user_context.orgs[].id (the org name also works).
Clear enough to supply this argument.
kind
Category kind: income, expense, or transfer.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
name
New category slug/code source. DB normalizes to lowercase [a-z0-9_], rejects duplicates, and reserves system parent names income/expense/transfer.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
display_name
Optional user-facing display name. Omit/null to use the stable slug.
Clear enough to supply this argument.
aliases
Optional classifier aliases/synonyms. Defaults to an empty list.
Clear enough to supply this argument.
examples
Optional example merchants or phrases for classification. Defaults to an empty list.
Clear enough to supply this argument.
description
Optional human-readable category description.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
The title clearly communicates the tool’s action and subject. Keep it concise.
Description92/100
Update a category's display label, description, examples, or aliases. Use to localize category names to the household's language or to improve classification guidance. Does not change the stable slug or kind — use create + archive to replace a category with a different kind.
The description explains the capability, when to use it, and what to expect.
Inputs83/100
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
org_id
Org UUID from get_user_context.orgs[].id (the org name also works).
Clear enough to supply this argument.
category_id
Category tag UUID from get_user_context.orgs[].categories[].id.
Clear enough to supply this argument.
display_name
Optional replacement display name. Omit/null to keep current value; pass empty string to clear.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
aliases
Optional replacement aliases array. Omit/null to keep current aliases; pass [] to clear.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
examples
Optional replacement examples array. Omit/null to keep current examples; pass [] to clear.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
description
Optional replacement description. Omit/null to keep current value; pass empty string to clear.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
The title clearly communicates the tool’s action and subject. Keep it concise.
Description96/100
Retire a category so it no longer appears in active lists. Use when a category is no longer relevant; existing transactions keep their category link. Prefer over deletion — archiving is reversible at the DB level and preserves history. Do not archive if you intend to reclassify its transactions first.
The description explains the capability, when to use it, and what to expect.
Inputs96/100
Input documentation gives an agent enough context to populate the arguments.
org_id
Org UUID from get_user_context.orgs[].id (the org name also works).
Clear enough to supply this argument.
category_id
Category tag UUID from get_user_context.orgs[].categories[].id.
{
"name": "archive_transaction_category",
"title": "Archive transaction category",
"description": "Retire a category so it no longer appears in active lists. Use when a category is no longer relevant; existing transactions keep their category link. Prefer over deletion — archiving is reversible at the DB level and preserves history. Do not archive if you intend to reclassify its transactions first.",
"inputSchema": {
"type": "object",
"required": [
"org_id",
"category_id"
],
"properties": {
"org_id": {
"type": "string",
"description": "Org UUID from get_user_context.orgs[].id (the org name also works)."
},
"category_id": {
"type": "string",
"description": "Category tag UUID from get_user_context.orgs[].categories[].id."
}
},
"additionalProperties": false
},
"outputSchema": {
"type": "object",
"additionalProperties": true
},
"annotations": {
"title": "Archive transaction category",
"readOnlyHint": false,
"openWorldHint": false,
"idempotentHint": false,
"destructiveHint": true
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description86/100
List org-level transaction categories. Use before creating a category to check for duplicates, or when inspecting archived categories before migrating their transactions. Read-only. Prefer get_user_context for active categories during normal workflows — use this tool when you need archived or full category detail.
The description explains the capability, when to use it, and what to expect.
Inputs99/100
Input documentation gives an agent enough context to populate the arguments.
org_id
Org UUID from get_user_context.orgs[].id (the org name also works).
Clear enough to supply this argument.
status
Which org-level categories to return. Use archived/all to inspect old categories before deciding whether to migrate their transactions.
{
"name": "list_transaction_categories",
"title": "List transaction categories",
"description": "List org-level transaction categories. Use before creating a category to check for duplicates, or when inspecting archived categories before migrating their transactions. Read-only. Prefer get_user_context for active categories during normal workflows — use this tool when you need archived or full category detail.",
"inputSchema": {
"type": "object",
"required": [
"org_id"
],
"properties": {
"org_id": {
"type": "string",
"description": "Org UUID from get_user_context.orgs[].id (the org name also works)."
},
"status": {
"enum": [
"active",
"archived",
"all"
],
"type": "string",
"default": "active",
"description": "Which org-level categories to return. Use archived/all to inspect old categories before deciding whether to migrate their transactions."
}
},
"additionalProperties": false
},
"outputSchema": {
"type": "object",
"additionalProperties": true
},
"annotations": {
"title": "List transaction categories",
"readOnlyHint": true,
"openWorldHint": false,
"idempotentHint": true,
"destructiveHint": false
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description85/100
Set saved Zen monthly budgets for one or more categories (referenced by slug, e.g. 'groceries'). History is captured automatically; explain the effective month to the user.
The description explains the capability, when to use it, and what to expect.
Inputs98/100
Input documentation gives an agent enough context to populate the arguments.
org_id
Org UUID from get_user_context.orgs[].id (the org name also works).
Clear enough to supply this argument.
budgets › items › category
Category slug from get_user_context.orgs[].categories[].name (e.g. 'groceries'); UUIDs also accepted.
Clear enough to supply this argument.
budgets › items › amount
Monthly budget amount in org base currency. Use 0 with enabled=false to disable.
Clear enough to supply this argument.
budgets › items › enabled
Whether to activate budget tracking for this category.
Clear enough to supply this argument.
valid_from
ISO date (YYYY-MM-DD) for the first day of the month this budget takes effect. Defaults to the first of the current month. Pass a past/future date to set budgets retroactively or in advance.
{
"name": "set_budget",
"title": "Set category budgets",
"description": "Set saved Zen monthly budgets for one or more categories (referenced by slug, e.g. 'groceries'). History is captured automatically; explain the effective month to the user.",
"inputSchema": {
"type": "object",
"required": [
"org_id",
"budgets"
],
"properties": {
"org_id": {
"type": "string",
"description": "Org UUID from get_user_context.orgs[].id (the org name also works)."
},
"budgets": {
"type": "array",
"items": {
"type": "object",
"required": [
"category",
"amount"
],
"properties": {
"amount": {
"type": "number",
"minimum": 0,
"description": "Monthly budget amount in org base currency. Use 0 with enabled=false to disable."
},
"enabled": {
"type": "boolean",
"default": true,
"description": "Whether to activate budget tracking for this category."
},
"category": {
"type": "string",
"description": "Category slug from get_user_context.orgs[].categories[].name (e.g. 'groceries'); UUIDs also accepted."
}
},
"description": "One category budget in a batched set_budget call."
},
"maxItems": 50,
"minItems": 1,
"description": "Budget entries to set or update. Each item must include category (slug like 'groceries'; UUID also accepted) and amount. enabled defaults to true. Use amount=0 with enabled=false to disable a category budget."
},
"valid_from": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "ISO date (YYYY-MM-DD) for the first day of the month this budget takes effect. Defaults to the first of the current month. Pass a past/future date to set budgets retroactively or in advance."
}
},
"additionalProperties": false
},
"outputSchema": {
"type": "object",
"additionalProperties": true
},
"annotations": {
"title": "Set category budgets",
"readOnlyHint": false,
"openWorldHint": false,
"idempotentHint": true,
"destructiveHint": false
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description80/100
MANDATORY for any budget-vs-actual question ('are we over budget', 'how are the budgets doing'). ALWAYS call this tool before discussing budget performance — never answer from chat memory; saved data may have changed. NOT for full month reviews: use get_monthly_summary for those. Use 'mapped so far' language if account/category coverage may be incomplete.
The description explains the capability, when to use it, and what to expect.
Inputs83/100
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
org_id
Org UUID from get_user_context.orgs[].id (the org name also works).
Clear enough to supply this argument.
year
Year of the month to analyse (e.g. 2026).
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
month
Month of the year to analyse (1-12).
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
{
"name": "get_budget_status",
"title": "Get budget status",
"description": "MANDATORY for any budget-vs-actual question ('are we over budget', 'how are the budgets doing'). ALWAYS call this tool before discussing budget performance — never answer from chat memory; saved data may have changed. NOT for full month reviews: use get_monthly_summary for those. Use 'mapped so far' language if account/category coverage may be incomplete.",
"inputSchema": {
"type": "object",
"required": [
"org_id",
"year",
"month"
],
"properties": {
"year": {
"type": "integer",
"maximum": 9999,
"minimum": 1900,
"description": "Year of the month to analyse (e.g. 2026)."
},
"month": {
"type": "integer",
"maximum": 12,
"minimum": 1,
"description": "Month of the year to analyse (1-12)."
},
"org_id": {
"type": "string",
"description": "Org UUID from get_user_context.orgs[].id (the org name also works)."
}
},
"additionalProperties": false
},
"outputSchema": {
"type": "object",
"additionalProperties": true
},
"annotations": {
"title": "Get budget status",
"readOnlyHint": true,
"openWorldHint": false,
"idempotentHint": true,
"destructiveHint": false
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description90/100
File a concise, non-sensitive product observation from this session — bugs, gaps, praise, or feature ideas. Use proactively when you notice a product limitation, tool mismatch, or missing capability; do not wait for the user to ask. Write-only surface: inserts into feedback_reports; no read tool exists today.
The description explains the capability, when to use it, and what to expect.
Inputs80/100
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
kind
Feedback type: issue, suggestion, praise, question, rating, or observation.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
area
Product area this feedback relates to: onboarding, mcp_setup, household_setup, transactions, imports, categorization, budgets, monthly_summary, privacy_trust, pricing, performance, or other.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
title
Short feedback summary.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
details
Markdown feedback details. Use short bullets/sections; do not include sensitive raw financial data, credentials, tokens, or full private conversation excerpts.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
sentiment
Overall sentiment: positive, neutral, negative, or mixed.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
severity
Issue severity: low, medium, high, or critical.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
org_id
Optional org UUID from get_user_context.orgs[].id; omit for setup feedback before an org exists.
Clear enough to supply this argument.
source_tool
Optional related MCP tool name, e.g. save_transaction.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
rating_score
Optional numeric score, e.g. NPS 0-10. Must be paired with rating_scale.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
rating_scale
Optional rating scale label, e.g. nps_0_10 or stars_1_5. Must be paired with rating_score.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
The title clearly communicates the tool’s action and subject. Keep it concise.
Description88/100
MANDATORY for any monthly review or summary request ('how did we do', 'monthly review', 'show me May', 'made/spent/saved'). ALWAYS call this tool — NEVER answer monthly-review questions from chat memory or earlier tool results: the family dashboard UI renders ONLY when this tool is actually invoked, and saved data may have changed since the last call. Returns curated Made/Spent/Saved, prior-month comparison, category/budget drivers, bursts, and transactions. Say mapped so far unless coverage is complete.
The description explains the capability, when to use it, and what to expect.
Inputs83/100
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
org_id
Org UUID from get_user_context.orgs[].id (the org name also works).
Clear enough to supply this argument.
year
Year to analyse (e.g. 2026).
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
month
Month to analyse (1-12).
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "get_monthly_summary",
"title": "Get monthly summary",
"description": "MANDATORY for any monthly review or summary request ('how did we do', 'monthly review', 'show me May', 'made/spent/saved'). ALWAYS call this tool — NEVER answer monthly-review questions from chat memory or earlier tool results: the family dashboard UI renders ONLY when this tool is actually invoked, and saved data may have changed since the last call. Returns curated Made/Spent/Saved, prior-month comparison, category/budget drivers, bursts, and transactions. Say mapped so far unless coverage is complete.",
"inputSchema": {
"type": "object",
"required": [
"org_id",
"year",
"month"
],
"properties": {
"year": {
"type": "integer",
"maximum": 9999,
"minimum": 1900,
"description": "Year to analyse (e.g. 2026)."
},
"month": {
"type": "integer",
"maximum": 12,
"minimum": 1,
"description": "Month to analyse (1-12)."
},
"org_id": {
"type": "string",
"description": "Org UUID from get_user_context.orgs[].id (the org name also works)."
}
},
"additionalProperties": false
},
"annotations": {
"title": "Get monthly summary",
"readOnlyHint": true,
"openWorldHint": false,
"idempotentHint": true,
"destructiveHint": false
}
}
Loading score analytics…
Put your MCP to the test
A few tasks worth trying with this server, chosen from its reviewed tools. These have not been run.
01Get budget statusMANDATORY for any budget-vs-actual question ('are we over budget', 'how are the budgets doing').
02Get transactionsRead saved Zen transaction lines for one org/date range.
03Get monthly summaryMANDATORY for any monthly review or summary request ('how did we do', 'monthly review', 'show me May', 'made/spent/saved').
04Get user workspaceStart here for Zen requests.
05List org-level transaction categories
Want to run these tasks against your MCP server with us?
Zenfinance setup, tools, quality score, publishing readiness, and alternatives.
How do I add Zenfinance to Claude, ChatGPT, or Cursor?
Add Zenfinance to Claude, ChatGPT, or Cursor by connecting its remote MCP URL in each client's MCP settings. In Claude, add a custom connector. In ChatGPT, add an MCP app. In Cursor, add an MCP server under Settings. The MCP URL is https://mcp.zenfin.tech/mcp.
Is Zenfinance MCP ready for ChatGPT and Claude?
As of October 16, 2026, Zenfinance scores 90/100 on Manufact's MCP publishing checklist. The scan does not yet meet ChatGPT publishing checks and meets Claude publishing checks. Passing these checks does not guarantee marketplace approval.
How clear is Zenfinance's MCP tool documentation?
As of October 16, 2026, Zenfinance scores 85/100 in Manufact's review of tool titles, descriptions, input and output schemas, and behavior annotations. The review covers 16 of 16 discovered tools. The quality score measures documentation clarity; runtime behavior and marketplace readiness require separate checks.
What are the best alternatives to Zenfinance?
As of October 16, 2026, alternatives to Zenfinance in financial-services on the Manufact MCP catalog include Contract-Factory — Sociétés & SIREN, Kavara Kirk, CeylonCharts, Netzo, and Ramp Data.
How can Zenfinance improve its MCP documentation?
report_feedback is the lowest-scoring reviewed tool at 77/100. Declare the result fields and their types in the output schema. Open its review for feedback and a copyable fix prompt, then rerun the documentation review after updating your tool metadata.
Not your MCP?
Review any public or OAuth MCP server for protocol compatibility, tool documentation, and ChatGPT and Claude publishing readiness. No account required.