Emerald
NPM · EMERALD-MCP
The database under the chat: a local SQLite file a model asks for rows, not notes to re-read.
Available components
Last scanned (2 hours ago)
Scores higher than 34% of npm servers
Category Databases
How this component scores in each security and reliability category. Every signal is checked automatically from public evidence about the published package, including repeated runs of it in an isolated sandbox, and we only credit what we can confirm. How we score → Why this is hard to score →
Supply Chain Security100
- No malware found by supply-chain analysis.Pass
- No known CVEs affecting this package version or its production dependencies.Pass
- No install/post-install scripts declared.Pass
- No production dependencies, so there is no dependency health to assess. View diagnostics → Pass
Provenance & Transparency23
- Repository presence not verified: we could not reach the forge to check. This is a gap on our side, not a finding about the repository. View diagnostics → Unverified
- Provenance check failed: no build-provenance attestation is published. See how to fix → View diagnostics → Fail
- Clear OSI-approved license (AGPL-3.0-only).Pass
- Actively maintained (last published 1 days ago).Pass
- Publishes a security disclosure policy (SECURITY.md).Pass
Schema Quality & AI Usability35
- 0% of prompts and resources have a non-trivial description (not blank, and not just the item's name).Fail
- AI-judged instruction clarity (good).Pass
- Context-footprint check failed: tool/resource definitions use about 26594 tokens (~309/item across 86 items; 85 tools + 1 resources), over budget; trim descriptions and params. See how to fix → Fail
- Usage-examples check failed: none of the tools include examples. See how to fix → Fail
Stability & Change Management57
- Stability observed for 17 of 30 days with no destabilising changes; credit accrues until the full window elapses.Partial
Tool Coverage100
- 100% of tools have a non-trivial description (not blank, and not just the tool's name).Pass
- 100% of tool parameters carry a description.Pass
Tool Safety100
- No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.Pass
- All 3 tool(s) whose name or description implies an irreversible operation declare an MCP destructiveHint annotation.Pass
- An AI judge read all 87 captured unit(s) of tool text and found none that tries to manipulate the model reading it.Pass
Capabilities100
- Implements a supported MCP spec version (2025-11-25); the latest is 2026-07-28.Pass
- Supports UI / widget rendering.Pass
Every change we have recorded for this component, newest first. Security-relevant changes are always shown. ▲ marks a change for the better, ▼ a change for the worse; unmarked changes are neutral.
- 5 Nov 26 −4
- Provenance: pass → unverified ▼ security
- 4 Nov 26 +26
- Malware scan: unverified → pass ▲ security
- Known CVEs: unverified → pass ▲ security
- Dependency health: unverified → pass ▲ functional
- 3 Nov 26 −25
- Malware scan: pass → unverified ▼ security
- Known CVEs: pass → unverified ▼ security
- Dependency health: pass → unverified ▼ functional
- Package version: 0.2.0 → 0.3.0 functional
- 31 Oct 26 +1
No change was recorded against any check on this day. Stability & Change Management went from 37 to 40. That category is still filling its 30-day observation window: 11 days of observed history at the previous scan, 12 at this one. The score rises as the window fills, whether or not the server changes.
- 29 Oct 26 +1
No change was recorded against any check on this day. Stability & Change Management went from 30 to 33. That category is still filling its 30-day observation window: 9 days of observed history at the previous scan, 10 at this one. The score rises as the window fills, whether or not the server changes.
- 27 Oct 26 +1
No change was recorded against any check on this day. Stability & Change Management went from 23 to 27. That category is still filling its 30-day observation window: 7 days of observed history at the previous scan, 8 at this one. The score rises as the window fills, whether or not the server changes.
- 25 Oct 26 +1
No change was recorded against any check on this day. Stability & Change Management went from 17 to 20. That category is still filling its 30-day observation window: 5 days of observed history at the previous scan, 6 at this one. The score rises as the window fills, whether or not the server changes.
- 24 Oct 26 +26
- Malware scan: unverified → pass ▲ security
- Known CVEs: unverified → pass ▲ security
- Dependency health: unverified → pass ▲ functional
Diagnostic detail from the automated scan of this channel: what the scanner observed at each step, so you can see exactly where a check passed or failed. It is informational only and never changes the trust score.
Captured 5 Nov 2026 · Analysed npm/emerald-mcp@0.3.0
Provenance No attestation
The registry publishes no build provenance for this version, so there is nothing to verify.
| Result | No attestation |
|---|---|
| Ecosystem | npm |
Background: How many MCP packages publish verified provenance →
Dependencies 0 packages
| Packages resolved | 0 |
|---|---|
| Tree resolution | Complete |
Background: SBOMs and build attestations, explained →
The tools this component advertises to a client, with an estimated token cost for each. Expand a tool to see its parameters and schema. The per-tool counts are indicative and are not scored directly; the schema's total context footprint is one signal in Schema Quality & AI Usability. A tool's description is untrusted text the model reads on every call, which is what makes this list a security surface and not just an inventory: how tool poisoning works →
record_fund_readings Record fund balances from a report ~234
Transcribe what a pension, hishtalmut, provident or managers’-insurance report says into the document — **several readings in one call**. Each entry names a fund by fund_id or by name, and carries one reading: the balance and its date, plus whatever else the report printed. A name that matches no fund creates it, once per batch, so four quarterly reports for one fund are four entries naming the same fund. **Leave out anything the report did not state** — an empty field means "not stated", and a 0 would be read as a stated zero. **Dry-runs by default**: it returns what it would write and writes nothing until called again with commit true. The document is copied to a timestamped .bak first. Editing a fund or correcting a reading already written is app-only.
| Name | Type | Req | Description |
|---|---|---|---|
| commit | boolean | – | Default false. False previews the batch; true writes it. |
| path | string | yes | Absolute path to a .emd file on this machine. |
| readings | array | yes | One entry per reading. Up to 60 in a call. |
No output schema declared.
No examples provided.
record_holding_readings Record what a statement says a holding is worth ~299
Write what a statement printed each holding was worth on a day — **a list in one call**. Transcribed, never fetched: there is no price feed. `value` is the worth as printed, in major units; `quantity`, `cost_basis` and `price` are optional and each is a check: the cost against what the rows that name the holding put in by that day, the quantity against their quantities, quantity × `price` against the value (a price printed in agorot is divided by 100 first — the check catches it when it is not). An account’s own cash holding takes a value only, checked against the account’s running balance. A goal fed by the holding is then worth its latest reading, with what went in beside it, and the difference is growth. The same figures for the same day again change nothing; other figures for a day that has a reading are refused unless `correct: true`; `remove: true` takes a day’s reading away. Holdings and their ids are listed by `savings`. **Dry-runs by default**; the document is copied to a timestamped .bak first.
| Name | Type | Req | Description |
|---|---|---|---|
| commit | boolean | – | Default false. False previews; true writes. |
| path | string | yes | Absolute path to a .emd file on this machine. |
| readings | array | yes | One entry per holding and day. Up to 200 in a call. |
No output schema declared.
No examples provided.
record_holdings_statement Record a statement of an account with holdings ~653
Write what a broker’s (or any account with holdings’) statement printed — **the whole file in one call**: its movements onto the account, and its holdings table as dated readings. **You read the file** — a PDF, usually — and send what it printed; nothing here parses it. Each row is the **value date**, the description as printed, the signed `amount` (a buy negative, a deposit or a sale positive; a fee printed in its own column is already inside the amount), and `cash_after`, the cash balance the statement printed after it. A buy or a sale also names the `holding` and the `quantity` (bought positive, sold negative). **The balances are a check**: each must be the one before it plus the row, and the batch is refused at the first that is not — a misread figure. **They are also each row’s key** (date, amount, balance after), so an overlapping file — a half-year export repeating the months — adds only what is new, and the same file again adds nothing. A row of amount 0 naming no holding (the broker’s tax bookkeeping) is left out. `holdings` is the holdings table: per holding its `value`, and when printed its `quantity`, `cost_basis` and `price` (one unit, in major units — a price printed in agorot is divided by 100); `cash` is the cash line. Each is checked: the cost against what the holding’s rows put in by `as_of`, the quantity against theirs, quantity × price against the value, and the cash against the account’s rows. Holdings are named by id or name (`savings` lists them); a name the place does not have is made there. **Dry-runs by default**; the document is copied to a timestamped .bak first.
| Name | Type | Req | Description |
|---|---|---|---|
| account_id | string | – | The account with holdings. Or `new_account`. |
| as_of | string | yes | The day the holdings table is for, YYYY-MM-DD. |
| cash | number | – | The cash line of the holdings table, in major units. |
| commit | boolean | – | Default false. False previews; true writes. |
| currency | string | – | Defaults to the document’s currency. |
| file | string | yes | Absolute path to the statement file you read. Hashed, so the same file is known again. |
| from | string | – | The first day of the period the statement printed, when it printed one. |
| holdings | array | – | The holdings table, one entry per holding but the cash. Up to 100. |
| new_account | string | – | Instead of `account_id`: the name of the account to make, e.g. the broker’s name. |
| path | string | yes | Absolute path to a .emd file on this machine. |
| place | string | – | The place on Net worth that names the account, when it names none yet — by id or name; made when new. Defaults to one with the account’s name. |
| rows | array | – | Every movement, in the order printed. Up to 400. |
No output schema declared.
No examples provided.
record_paychecks Record paychecks ~214
Write paychecks into the document — **several in one call**, one entry per paycheck. Each needs the salary month, the payment date, gross and net; an itemization is optional, and each of its lines names a deduction type by id from `paychecks`. Read a paycheck PDF or photo yourself and this is where what it says goes. **Dry-runs by default**: it returns what it would record, including whether each paycheck’s itemization reconciles to its net, and writes nothing until called again with commit true. Nothing here deduplicates — a second paycheck for a salary month is allowed, because a 13th salary is exactly that. The document is copied to a timestamped .bak before anything is written.
| Name | Type | Req | Description |
|---|---|---|---|
| commit | boolean | – | Default false. False previews the batch; true writes it. |
| path | string | yes | Absolute path to a .emd file on this machine. |
| paychecks | array | yes | One entry per paycheck. Up to 60 in a call. |
No output schema declared.
No examples provided.
record_units Add or correct a unit of measure, or set the currency ~291
Teach this document a unit it does not know — `slice`, `IU`, a tablespoon that is 20 ml in this kitchen. A unit is what a declared column says its figures are in and what a claim's `in` converts into, so a conversion the document cannot make is a conversion this fixes. **The engine converts inside a dimension and never across one**: grams to kilograms is arithmetic, millilitres to grams needs a density, and a density is a column of the format rather than a unit. A symbol the document already has is corrected — its factor and its note, never what it measures. `currency` sets the document’s currency — what a new amount on a screen starts in; a row still names its own. `week_starts_on` is what `this week` counts from (Monday). `formats` lists them. Returns the diff and writes nothing until `commit: true`.
| Name | Type | Req | Description |
|---|---|---|---|
| commit | boolean | – | Write it. Omit or false for the dry run. |
| currency | string | – | The document’s currency, a three-letter code: `ILS`. |
| path | string | yes | Absolute path to a .emd file on this machine. |
| units | array | – | One object per unit. Up to 64 in a call; none for a setting alone. |
| week_starts_on | string | – | A day by name: `sunday`. |
No output schema declared.
No examples provided.
savings Savings ~111
Goals and where the money is: net worth — the one figure Overview shows, with its parts (in the bank, in accounts with holdings, locked, pension and hishtalmut funds, owed) — each goal balance broken into the four ways money got there, and the monthly expense figure the emergency-fund target is measured against. Open goals by default.
| Name | Type | Req | Description |
|---|---|---|---|
| include_closed | boolean | – | Include closed goals. Default false. |
| path | string | yes | Absolute path to a .emd file on this machine. |
No output schema declared.
No examples provided.
search_document Search the whole document ~175
Every row of every format, and the rest of the file, that holds any of `terms`: each hit by format, row and column, columns searched as shown. One call where `format_rows`’ `search` is one a format. Or `denylist`, a `--replace-text` file: the scan before a document is shared — hits only, a term named by its line, and the file’s bytes checked for a deleted value. Reads only.
| Name | Type | Req | Description |
|---|---|---|---|
| denylist | string | – | Instead of `terms`: a denylist’s absolute path, `literal==>x` or `regex:pattern==>x` a line. |
| path | string | yes | Absolute path to a .emd file on this machine. |
| terms | array | – | Words or phrases, any case, up to 50. |
No output schema declared.
No examples provided.
set_card_payers Say which bank rows pay a card ~190
Say that a bank merchant pays a credit card — **a list in one call**. Give the bank `transaction_id` and the `card_account_id` it pays (ids from `document_info`); omit the card to take the answer back. This is *This pays a card* on a Transactions row and on a By merchant row. Optionally `counts` says whether those bank rows count in the totals: false leaves them out, because the card’s own rows already hold that money. **Dry-runs by default**; commit with `commit: true` once the user has said yes.
| Name | Type | Req | Description |
|---|---|---|---|
| commit | boolean | – | Default false. False previews and writes nothing; true makes the change. |
| path | string | yes | Absolute path to a .emd file on this machine. |
| payments | array | yes | One entry per bank merchant. Up to 200 in a call. |
No output schema declared.
No examples provided.
set_cushion Set the cushion ~304
Set the cushion. **What is in the bank** is the latest statement balance of the bank accounts that count — **every bank account and cash, until `accounts` unticks it**; **each goal saved in one of them holds its part** (its deposits into that account’s own cash holding), and **the cushion is what is left**, against a target of `months` of bills plus the Plan `buckets` (Groceries, say) counted beside the bills. No goal is the cushion and setting it makes none. Goals holding more than an account, or than the whole, is a failed check, never shrunk to fit. Every answer ends with the split as it stands. Wealth › Net worth and Plan both show it. **Dry-runs by default**; the document is copied to a timestamped .bak first.
| Name | Type | Req | Description |
|---|---|---|---|
| accounts | array | – | Bank accounts whose balance counts toward what is in the bank, or stops counting. A card or an account with holdings never counts. |
| buckets | array | – | Plan buckets to count in the cushion, or to stop counting. Ids or names from `plans`. |
| commit | boolean | – | Default false. False previews; true writes. |
| months | number | – | How many months of bills, above 0 and at most 24, to two places. e.g. 3. |
| path | string | yes | Absolute path to a .emd file on this machine. |
No output schema declared.
No examples provided.
set_deduction_types Make, rename, order and remove deduction types, and say what each counts as and pays into ~477
Everything the deduction types screen does, for **several types in one call**: **make** a type (its name, what the paycheck calls it, its kind), **rename** one, change its kind, **remove** one, put the list in **order**, and say what each type **counts as** (out of net, saving — the two flags every paycheck figure turns on) and what it **pays into** — a fund or a goal for a saving line, a debt (a payroll loan) for a loan repayment. **This link is how a fund finds its paycheck lines**: a pension line is a deposit into a fund only because its type names the fund, and `funds` checks those deposits against the fund’s own report. A new type starts as its kind’s guess, and a kind change carries the flags along while they are still the guess; one that differs is shown as set by hand, and `guess` puts it back. One destination per type — naming one clears the others, and `pays_into: null` links nothing. Refused by name: a target of the wrong kind (a fund or a goal takes a line that counts as saving, a debt a loan repayment), a name another type has, and removing a built-in type, a type a stored paycheck line names, or one another row links to. Types and their ids are listed by `paychecks`; funds by `funds`, goals by `savings`, debts by `debts`. **Dry-runs by default**; the batch applies whole or not at all, and the document is copied to a timestamped .bak first.
| Name | Type | Req | Description |
|---|---|---|---|
| commit | boolean | – | Default false. False previews; true writes. |
| order | array | – | Types by id or by name — the names they will have after this call, new ones included. These come first in the list, in this order, and the rest follow as they are. |
| path | string | yes | Absolute path to a .emd file on this machine. |
| types | array | – | One entry per deduction type, up to 60 in a call. With `type` it changes or removes that type; without it, it makes a new one, which needs `name` and `kind`. |
No output schema declared.
No examples provided.
set_excluded_from_totals Leave rows out of the totals, or count them again ~225
Leave transactions out of every total — **a list of ids in one call** — or count them again with `excluded: false`. A row left out stays in the ledger and is shown marked; it is simply not summed. This is what the Transactions screen’s row menu does: a card bill the bank statement shows as one charge is the same money as the card statement’s rows, and counting both doubles the month. **Dry-runs by default** and says how much it would take off the totals; commit with `commit: true` after the user has said yes. The document is copied to a timestamped .bak first. Ids come from `transactions`.
| Name | Type | Req | Description |
|---|---|---|---|
| commit | boolean | – | Default false. False previews and writes nothing; true makes the change. |
| excluded | boolean | – | Default true: leave them out. False counts them in the totals again. |
| path | string | yes | Absolute path to a .emd file on this machine. |
| transaction_ids | array | yes | Up to 2000 transaction ids, from `transactions`. |
No output schema declared.
No examples provided.
set_fixed_expense_roles Say what each bill does to a plan ~197
For each bill, per plan: `net` (comes out of net pay before the split), `split` (is one share of the split, drawn on the bar) or `ignore` (this plan leaves it out). **A list in one call.** A bill the paycheck already took (a pension deduction) is outside the choice and refused. An expense with no choice made is ignored. This is the Plan screen’s switch on every row. **Dry-runs by default**: it shows each change and writes nothing until `commit: true`; the document is copied to a timestamped .bak first. Ids come from `plans`.
| Name | Type | Req | Description |
|---|---|---|---|
| commit | boolean | – | Default false. False previews; true writes. |
| path | string | yes | Absolute path to a .emd file on this machine. |
| roles | array | yes | One entry per bill and plan. Up to 100 in a call. |
No output schema declared.
No examples provided.
set_goal_amounts Set what goes toward goals and debts each month ~143
Set the monthly amount toward a goal, or the extra on a debt: the Plan bucket for it, in the default plan. The difference comes from (or goes back to) Plan's Everything else, as on the Goals and Debts screens; a goal or debt with no bucket gets one. **Dry-runs by default**; the document is copied to a timestamped .bak first.
| Name | Type | Req | Description |
|---|---|---|---|
| amounts | array | yes | One entry per goal or debt. Up to 60 in a call. |
| commit | boolean | – | Default false. False previews; true writes. |
| path | string | yes | Absolute path to a .emd file on this machine. |
No output schema declared.
No examples provided.
set_goal_deposit_categories Point goals at their deposits ~429
Say what feeds each goal, **several in one call**. **One feed per goal, never both**, so nothing counts twice: either a **Money moved category** — a transaction categorized under it is a deposit into the goal, read from the bank — or, with `from_holding: true`, **the rows that name its default holding**: every buy or sale of that holding inside an account that holds things (`set_transaction_holdings`) is a deposit, and the bank transfer that brought the cash there feeds nothing — or, with `from_transfers: true`, **the confirmed transfers into the bank or cash account whose own Cash is its default holding**: each transfer pair (`answer_transfers`) arriving there is a deposit and one leaving it a withdrawal, after its Was already there; off unless asked, since a main account takes transfers that are not for a goal. A broker’s cash is no such feed. Categorizing is the only step, and a row re-categorized elsewhere takes its deposit with it. One goal per category, per holding and per account; the category must be a Money moved one (a transfer or a saving, not a spending category), and the goal needs a default holding for the money to sit in: `default_holding` sets it, in the same entry or on its own, as the Goals form’s "Where is the money?" does. `category: null` stops either feed, and removes the deposits it had derived. Money you set aside by hand (`record_deposits`) and what was already there are never touched. `savings` shows what a holding’s rows put in, against the cost basis a reading printed. **Dry-runs by default**; the document is copied to a timestamped .bak first.
| Name | Type | Req | Description |
|---|---|---|---|
| commit | boolean | – | Default false. False previews the batch; true writes it. |
| goals | array | yes | One entry per goal. Up to 60 in a call. |
| path | string | yes | Absolute path to a .emd file on this machine. |
No output schema declared.
No examples provided.
set_no_pay_months Say a month had no pay ~153
Says months had no pay — between jobs, unpaid leave — so no paycheck is missing for them: Home stops asking "No paycheck for …" and `paychecks` stops listing them as gaps. `no_pay: false` takes it back. Stores the answer only; no paycheck and no figure. **Dry-runs by default**; the document is copied to a timestamped .bak first.
| Name | Type | Req | Description |
|---|---|---|---|
| commit | boolean | – | Default false. False previews; true writes. |
| months | array | yes | Salary months, as YYYY-MM. |
| no_pay | boolean | – | Default true. False takes the answer back. |
| path | string | yes | Absolute path to a .emd file on this machine. |
No output schema declared.
No examples provided.
set_opening_balances Set accounts' opening balances ~180
Say what each bank or cash account **held before its first statement**, and the day that stands for everything before — **several in one call**. A document cannot read this off a file. The answer shows the check it buys: opening, plus what the statements moved since, has to equal the balance the last statement ended on, and the row says by how much when it does not. `clear: true` forgets one. A credit card has none. **Dry-runs by default**; the document is copied to a timestamped .bak first.
| Name | Type | Req | Description |
|---|---|---|---|
| accounts | array | yes | One entry per account. Up to 30 in a call. |
| commit | boolean | – | Default false. False previews the batch; true writes it. |
| path | string | yes | Absolute path to a .emd file on this machine. |
No output schema declared.
No examples provided.
set_place_accounts Name the account a place’s money is shown by ~296
Say which account each place on Net worth is — the bank account, the broker, the savings account whose statements show its money — **several in one call**. A place *links* to an account and is not merged with it: a deposit or cash at home has no statements and names none (`account: null` takes a link away). A card cannot be named, and an account is named by one place at most. The account gets its own cash holding in the place, made with the link — or `cash_holding` picks one already there, such as the holding goal deposits already land in. Unlinking keeps the holding. A bank account or cash has a place named as it and its own cash from the moment it is made; naming it from another place moves it there while its own place holds nothing. A place that names one account is not re-pointed to another in one call: set it to `null` first. Nothing here moves a figure. Places and holdings are listed by `savings`; accounts by `document_info`. **Dry-runs by default**; the document is copied to a timestamped .bak first.
| Name | Type | Req | Description |
|---|---|---|---|
| commit | boolean | – | Default false. False previews; true writes. |
| links | array | yes | One entry per place. Up to 60 in a call. |
| path | string | yes | Absolute path to a .emd file on this machine. |
No output schema declared.
No examples provided.
set_plan Create, change or delete plans ~373
What the Plan screen does to a plan — **a list of entries in one call**. Per entry: `plan_id` for an existing plan, or `create: true` with `name` (and `copy_of`, a plan id, to start from its sizes and its choices for the bills); then any of `name`, `make_default`, `basis` ({kind: LAST_PAYCHECK | AVERAGE_LAST_N | SPECIFIC_PAYCHECK | CUSTOM_AMOUNT, amount, months, paycheck_id}) — a bonus month is a plan whose basis is an amount — and `buckets`, **the plan’s whole list of buckets** as the screen’s bar has it: each {bucket_id (existing) or name (new), points_at: {kind: goal | debt | category | fund | account | none, id}, mode: percent | amount | rest, percent (0-100), amount (major units), locked}. A bucket is for one thing, and a bucket sized “rest” takes what is left after the others and the bills that are part of the split; at most one. Or, alone, `delete: true` (the default plan too; another becomes the default), or `remove_buckets` to take buckets out and hand each share to its right. What each bill does to a plan is `set_fixed_expense_roles`. **Dry-runs by default**; `commit: true` writes. The document is copied to a timestamped .bak first. Ids come from `plans`.
| Name | Type | Req | Description |
|---|---|---|---|
| commit | boolean | – | Default false. False previews; true writes. |
| path | string | yes | Absolute path to a .emd file on this machine. |
| plans | array | yes | One entry per plan. Up to 100 in a call. |
No output schema declared.
No examples provided.
set_transaction_holdings Say what a transaction’s cash turned into ~237
Name the holding a transaction bought or sold, and how much of it — **a list in one call**. Such a row is cash turning into a holding inside one account (a broker buying a fund, a savings account opening a deposit): it counts in neither came in, went out nor moved, and the holding’s quantity is the sum of its rows’ quantities. `quantity` is a count of the thing, never money — bought is positive, sold negative, up to six places. `holding: null` clears both. The holding must sit at a place that names the row’s own account, or at one that names none, and is never an account’s own cash. Holdings and their ids are listed by `savings`; transaction ids by `transactions`. **Dry-runs by default**; the document is copied to a timestamped .bak first.
| Name | Type | Req | Description |
|---|---|---|---|
| commit | boolean | – | Default false. False previews; true writes. |
| path | string | yes | Absolute path to a .emd file on this machine. |
| rows | array | yes | One entry per transaction. Up to 500 in a call. |
No output schema declared.
No examples provided.
set_transaction_notes Add, edit or clear notes on transactions ~140
Write the note on a transaction — **a list in one call**. An empty `note` clears it. This is the row menu’s *Add a note*: a line about one charge that is worth remembering. **Dry-runs by default**; commit with `commit: true` after the user has seen the table. Ids come from `transactions`.
| Name | Type | Req | Description |
|---|---|---|---|
| commit | boolean | – | Default false. False previews and writes nothing; true makes the change. |
| notes | array | yes | One entry per transaction. Up to 2000 in a call. |
| path | string | yes | Absolute path to a .emd file on this machine. |
No output schema declared.
No examples provided.
settle_set_aside Is it still set aside? ~191
Answer, for a goal, whether money **set aside** (promised to it but still inside the bank) is still there. A set-aside amount nobody has confirmed for more than 90 days is the one that is asked about; `goal_projection` lists them. `still_there: true` records today against them so they are not asked about again for 90 days. `false` withdraws them from the goal, with the reason written, so the balance stops counting money that is gone. Several goals in one call. **Dry-runs by default**; the document is copied to a timestamped .bak first.
| Name | Type | Req | Description |
|---|---|---|---|
| commit | boolean | – | Default false. False previews; true writes. |
| goals | array | yes | One entry per goal. Up to 60 in a call. |
| path | string | yes | Absolute path to a .emd file on this machine. |
No output schema declared.
No examples provided.
show_format A declared format’s rows, drawn as the app draws them ~443
Shows the person one declared format as the app draws it — its table, its list (one line per row, a tick, grouped as `arrange_views view:list` says), or its board, roadmap or ready-to-start list when the format has one; or the agenda, every dated format’s rows from today; or a dashboard (no `format`: the document’s) — in the conversation, in a client that draws MCP Apps; the answer’s first line says whether this client said it draws them. Call it when they ask to see a format, or some of its rows: `match` and `search` filter exactly as `format_rows` does, and the view draws only those rows and says it is filtered. The text answer names every row the view shows, with its state or lane. The page is a read-only copy, drawn again as the file changes. Reads the file; never modifies it.
| Name | Type | Req | Description |
|---|---|---|---|
| columns | object | – | Columns its lines draw, by format: `{unit:[title,state]}`. A roadmap’s `match` takes `unit.state`. |
| format | string | – | The declared format, by name. `formats` lists them. The agenda takes none. |
| match | object | – | Column name to the value it must equal. Text and enum columns match without regard to case; money or a quantity, a range: `10..50 ILS`. A list is any of them (`[planned, in_progress]`; a list column… |
| path | string | yes | Absolute path to a .emd file on this machine. |
| search | string | – | A substring, in every column as shown but yes/no. |
| view | string | – | table, board, list, roadmap, ready, agenda (default table), dashboard, or a saved view’s name. |
No output schema declared.
No examples provided.
skip_merchants Skip merchants for now, or put them back ~174
Set merchants aside in the By merchant queue — **a list in one call** — or put them back with `skip: false`. "I do not know what this is" is a real answer to a cryptic bank transfer; a skip writes nothing to any transaction. Names are the normalized ones `uncategorized_merchants` prints. **Dry-runs by default**; commit with `commit: true`.
| Name | Type | Req | Description |
|---|---|---|---|
| commit | boolean | – | Default false. False previews and writes nothing; true makes the change. |
| merchants | array | yes | Normalized merchant names, exactly as `uncategorized_merchants` printed them. |
| path | string | yes | Absolute path to a .emd file on this machine. |
| skip | boolean | – | Default true: set them aside. False puts them back in the queue. |
No output schema declared.
No examples provided.
start_here What to start from ~116
Call first. Answers the questions this document’s own views say a session starts from — what is ready to start, what is open, the latest entries — each with the `format_rows` call that lists it whole; then what a row of each format looks like, enough to write one; and where new work begins: `formats`, then `read_onto_format` (files or a folder of notes) or `declare_format`. Read-only.
| Name | Type | Req | Description |
|---|---|---|---|
| path | string | yes | Absolute path to a .emd file on this machine. |
No output schema declared.
No examples provided.
statement_preview Look at a statement file ~236
Read a card or bank statement (.xlsx, .xls, .csv) and report what is in it: which sheet, where the header row is, what each column looks like and what the app guesses it is, the first rows verbatim, and whether a reader already recognises these columns. Changes nothing — call this before import_statement so the user can confirm the columns. **The user maps the columns; the app only guesses**, so show them this and ask.
| Name | Type | Req | Description |
|---|---|---|---|
| amount_convention | string | – | One of SIGNED_SINGLE, POSITIVE_IS_CHARGE, SEPARATE_DEBIT_CREDIT. Read from the roles when omitted. |
| columns | object | – | Try columns without importing: column number → role. |
| file | string | yes | Absolute path to the statement file. One of .xlsx, .xls, .csv. |
| header_row | number | – | Force the header row number, when the guess is wrong. |
| path | string | yes | Absolute path to a .emd file on this machine. |
| sheet | string | – | Which sheet, when the file has more than one. Defaults to the first. |
No output schema declared.
No examples provided.
store_document_as Store a document as text or as SQLite bytes ~122
Writes the document again as `text` (diffs in git) or as `sqlite` bytes, and every later write keeps that shape — the app’s Save as text. Refused when the text would not carry it — a document keeping the ledger, for one. Writes nothing until `commit: true`.
| Name | Type | Req | Description |
|---|---|---|---|
| as | string | yes | How the file is stored from now on. |
| commit | boolean | – | Write it. Omit or false for the dry run. |
| path | string | yes | Absolute path to a .emd file on this machine. |
No output schema declared.
No examples provided.
suggest_goal_amounts Suggest a split ~174
Suggest each goal's monthly amount: goals by nearest date (no kind of goal goes first), each taking what gets it there on its date until what Plan has for goals runs out (what they take now plus what is left after every bucket). A goal with no date is sized as a year of what is missing; a reached, target-less or paused goal gets nothing. The preview is the suggestion; `commit: true` writes it through the same rule a typed amount on Goals uses, so the rest of the split moves with it. **Dry-runs by default**; the document is copied to a timestamped .bak first.
| Name | Type | Req | Description |
|---|---|---|---|
| commit | boolean | – | Default false. False shows the suggestion; true writes it. |
| path | string | yes | Absolute path to a .emd file on this machine. |
No output schema declared.
No examples provided.
supersede_reading Take back what one file wrote ~203
Take back the rows one file wrote onto a declared format — **exactly those rows and no others**. Called with no `reading`, it lists every file read onto the format with when, and how many rows each still has. **Dry-runs by default** and writes nothing until `commit: true`. **The reader is kept** (forgetting one is `readers`), so supersede → correct the file → read it again is one call each. This is how a file read twice stops being two copies; a file is matched by its bytes, never row by row.
| Name | Type | Req | Description |
|---|---|---|---|
| commit | boolean | – | Do it. Omit or false for the dry run. |
| format | string | yes | The declared format, by name. |
| path | string | yes | Absolute path to a .emd file on this machine. |
| reading | string | – | The reading to take back, by id. Omit to list what this format has read. |
No output schema declared.
No examples provided.
track_fixed_expenses Track recurring charges as bills ~248
Turn recurring charges into tracked bills — **several in one call**. An entry either names a `merchant` from fixed_expense_candidates, in which case the charge, cadence and category come from the detector unless overridden, or gives a `name` and an `expected_amount` for a bill the ledger cannot see, like an annual premium paid by standing order elsewhere. **Dry-runs by default**: it returns what it would track and writes nothing until called again with commit true. Confirming the same merchant twice updates the row already covering it rather than adding a second. The document is copied to a timestamped .bak before anything is written.
| Name | Type | Req | Description |
|---|---|---|---|
| commit | boolean | – | Default false. False previews the batch; true writes it. |
| ending_at | string | – | The newest month of that window, as YYYY-MM. Default this month. |
| expenses | array | yes | One entry per bill. Up to 100 in a call. |
| path | string | yes | Absolute path to a .emd file on this machine. |
| window_months | number | – | The lookback used to re-find the candidates, matching the one you listed them with. Default 3. |
No output schema declared.
No examples provided.
transactions Transactions ~372
A filtered page of the ledger, plus the totals over every matching row — not just the page. Filter by date range, account, category, uncategorized-only, merchant search and amount bounds; sort by date, charge date, merchant, category or amount. Use this to answer "what did I spend at X" and to show the evidence behind any figure.
| Name | Type | Req | Description |
|---|---|---|---|
| account_id | string | – | Restrict to one account. Ids come from `accounts` in `document_info`. |
| category_id | string | – | Restrict to one category. Ids come from `category_tree`. |
| direction | string | – | ASC or DESC. Default DESC. |
| from | string | – | Inclusive start of the charge-date range, as YYYY-MM-DD. |
| include_subcategories | boolean | – | Read `category_id` as a parent and include its children. Default false, matching the app own picker, where choosing Utilities means Utilities. |
| limit | number | – | Rows to return. Default 50, maximum 500. |
| max | number | – | Largest amount, by magnitude, in major units of the document currency. |
| min | number | – | Smallest amount, by magnitude, in major units of the document currency. 200 matches a 200 refund as well as a 200 charge. |
| path | string | yes | Absolute path to a .emd file on this machine. |
| search | string | – | Matched against the merchant as written, the normalized merchant, and the provider label. |
| sort | string | – | One of DATE, CHARGED, MERCHANT, CATEGORY, AMOUNT. Default DATE. |
| to | string | – | Inclusive end of the charge-date range, as YYYY-MM-DD. |
| uncategorized | boolean | – | Only rows with no category. Overrides `category_id`. |
No output schema declared.
No examples provided.
transfers Transfers between the person’s own accounts ~109
Lists the transfers between two of the person’s own accounts that imports have found: a row leaving one account and the same amount arriving in another within a few days. Undecided ones by default; `answer` reads the transfers or the rows that are not one. An answered transfer is neither income nor spending. `answer_transfers` answers them.
| Name | Type | Req | Description |
|---|---|---|---|
| answer | string | – | Which to list. Default undecided. |
| path | string | yes | Absolute path to a .emd file on this machine. |
No output schema declared.
No examples provided.
uncategorized_merchants Uncategorized merchants ~242
The uncategorized backlog, grouped by merchant: how many rows each merchant has, and what the user has already categorized other rows of the same merchant under. Ordered by the largest single-currency outflow, which is not printed. Start a "help me categorize" conversation here.
| Name | Type | Req | Description |
|---|---|---|---|
| account_id | string | – | Restrict to one account. Ids come from `accounts` in `document_info`. |
| from | string | – | Inclusive start of the charge-date range, as YYYY-MM-DD. |
| include_amounts | boolean | – | Print what each merchant adds up to. Off by default: the backlog is already ordered by it, and naming a category needs the merchant rather than the sum. Ask for it only when the user wants the spendi… |
| limit | number | – | Merchants to return. Default 50, maximum 500. |
| path | string | yes | Absolute path to a .emd file on this machine. |
| search | string | – | Matched against the merchant as written, the normalized merchant, and the provider label. |
| to | string | – | Inclusive end of the charge-date range, as YYYY-MM-DD. |
No output schema declared.
No examples provided.
update_account Rename an account or set its last 4 digits ~191
Give an account a real name and the last 4 digits of its card or number. The digits are what matches an imported statement to the right account, and what identifies a card charge on a bank statement, so they are worth asking for. Account ids come from document_info.
| Name | Type | Req | Description |
|---|---|---|---|
| account_id | string | yes | The account to change. |
| kind | string | – | One of CREDIT_CARD, BANK, CASH, HOLDINGS, if it was created as the wrong one. HOLDINGS is an account with holdings — a broker, a savings account; `set_place_accounts` then names it from the place its… |
| last4 | string | – | The last four digits, as digits. |
| name | string | – | A name the user will recognise, e.g. "Cal – Visa 1234". |
| path | string | yes | Absolute path to a .emd file on this machine. |
No output schema declared.
No examples provided.
update_format_rows Correct rows of a declared format ~285
Change columns of rows already stored — **a list of edits in one call**. Each names its row by `id` or by `where` (`{ref: "INV-0042"}`, which survives another writer; a text document renews ids on every write), and the `values` to change. `expect` (`{state: "planned"}`) refuses the batch unless the row still holds that, so two sessions cannot both take one row. Every column not named is left exactly as it was, which is the difference between this and the app: `#/formats/<name>` shows a person every column and writes every column, and this corrects three of thirty across a batch. A required column cannot be emptied. A `link` value may be the name of the row it points at, or a unique column of it (`course: {notion_id: "a1b2"}`), as in `record_format_rows`. Returns the before-and-after and writes nothing until `commit: true`.
| Name | Type | Req | Description |
|---|---|---|---|
| commit | boolean | – | Write it. Omit or false for the dry run. |
| edits | array | yes | One entry per row. Up to 200 in a call. |
| format | string | yes | The declared format, by name. |
| path | string | yes | Absolute path to a .emd file on this machine. |
No output schema declared.
No examples provided.
year_summary Year summary ~110
One year already added up: income, expenses, balance and savings rate; averages over the complete months only; the best and worst month by balance; a month-by-month table where a month with no data reads as nothing rather than as zero; and what the paychecks say about gross, tax and payroll savings. Defaults to the current year.
| Name | Type | Req | Description |
|---|---|---|---|
| path | string | yes | Absolute path to a .emd file on this machine. |
| year | number | – | Four-digit year. Defaults to the current year. |
No output schema declared.
No examples provided.
How do I install the Emerald MCP server?
Emerald runs locally as an npm package, launched with npx -y emerald-mcp. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.
npm · emerald-mcp
claude mcp add kfireliyahu-emerald -- npx -y emerald-mcp
What is the Emerald MCP server?
Emerald is an MCP server listed in the public MCP registry as io.github.kfireliyahu/emerald. The database under the chat: a local SQLite file a model asks for rows, not notes to re-read. This page covers its npm package (emerald-mcp).
Is the Emerald MCP server safe to use?
Emerald scores 67 out of 100 on VerifyMCP. We found no known CVEs affecting it as of 5 November 2026. It declares no install or post-install scripts. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.
What tools does the Emerald MCP server expose?
Emerald exposes 85 tools: formats, declare_format, connect_formats, extend_format, delete_format, and 80 more. Their descriptions and schemas cost roughly 22,653 tokens of context every time the server is loaded.
Is the Emerald MCP server still maintained?
Emerald is still listed as active in the MCP registry. We last reached this channel on 5 November 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.
What licence is the Emerald MCP server under?
Emerald declares the AGPL-3.0-only licence, which is OSI-approved. That covers the source only, and says nothing about the cost of any service it calls.