Tools¶
The anafpy[mcp] extra ships a local stdio MCP server that wraps the typed
clients as tools for Claude (Desktop, Code, Cowork). It runs on your own machine:
tool calls use your own tokens, and downloaded files land on your own filesystem.
The setup walkthrough gets you from zero to a working connection.
The server is read-first: everything that only looks things up is freely callable, and everything that files anything with ANAF — e-Factura and e-Transport alike — is gated behind an explicit human confirmation.
Public lookups — no login needed¶
These ride ANAF's public no-auth services, so they work even before the certificate login (and with no OAuth credentials configured at all):
| Tool | What it does |
|---|---|
anaf_lookup_taxpayers |
Verify partners by CUI/CIF: name, address, VAT status, TVA la încasare, split-VAT, inactive flag — in bulk if you like |
anaf_lookup_efactura_register |
RO e-Factura register membership |
anaf_lookup_farmers |
Farmers' register (RegAgric) |
anaf_lookup_cult_entities |
Religious-entities register (RegCult) |
anaf_financial_statement |
A company's filed financial statements (bilanț) for a year |
efactura_validate |
ANAF's authoritative server-side invoice validation (CIUS-RO / BR-RO) — validates only, files nothing |
Exchange rates — no login needed¶
The one tool that does not query ANAF. Romanian filings are in lei, so a foreign-currency invoice needs converting before its value can be declared — this is where that figure comes from, instead of Claude doing the arithmetic or recalling a rate.
| Tool | What it does |
|---|---|
bnr_fx_rate |
The official BNR reference rate for a currency on a date, and amounts converted to RON at it |
BNR publishes once per banking day, just after 13:00, so a weekend, a holiday
or an early-morning call answers with the last published day. The result
always carries rate_date (the day the rate is from) next to requested_date,
and flags the difference — so the rate's real date is what reaches you.
The ANAF session¶
| Tool | What it does |
|---|---|
auth_status |
Reports whether the stored ANAF login is valid, and when the tokens expire |
auth_login |
Runs the one-time OAuth login: opens your browser on ANAF's certificate page, catches the redirect on a local listener, and stores the tokens — needs your explicit go-ahead (confirm=true), one attempt per call |
auth_login is needed at first setup and again roughly yearly, when the
refresh token expires. Claude never sees your PIN or the certificate — that
step happens entirely in your browser, exactly as in anafpy auth login,
which remains the terminal equivalent (and additionally offers paste mode and
a TLS certificate of your own). Expect the browser's one-time "connection is
not private" warning at localhost — the setup walkthrough
explains why it is harmless.
e-Factura — inbox, plus two-step gated filing¶
Read tools, freely callable:
| Tool | What it does |
|---|---|
efactura_list_messages |
List received/sent messages for a date window |
efactura_download |
Download a message as an easy-to-read flat view; optionally save the signed ZIP (save_zip_as) and/or ANAF's official PDF rendering (save_pdf_as) to paths you name |
efactura_get_status |
An upload's processing state (ok/nok), with the download id when accepted |
Saved artifacts go to disk, never into the conversation — that's what powers
batch flows like "export last month's invoices as <date> - <partner>.pdf". An
existing file is never silently replaced: a name collision is refused and
reported, and only an explicit overwrite=true replaces it. The PDF is also
available as the MCP resource anafmsg://<message_id>/pdf.
Filing uses the same prepare → confirm → submit gate as e-Transport, with two ways in:
| Tool | What it does |
|---|---|
efactura_prepare |
Gate ready-made UBL XML your invoicing software produced — the strongly recommended path when you have such software (its ledger, not ANAF's SPV, is your durable record: SPV purges messages after ~60 days); the bytes go to ANAF verbatim |
efactura_prepare_invoice |
Compose a complete CIUS-RO invoice or credit note from structured fields — no XML and no invoicing software needed; totals and the VAT breakdown are computed, and local_findings reports anafpy's translated rule check (informational — ANAF stays authoritative) |
efactura_submit |
File a prepared document; returns the upload id for efactura_get_status |
e-Transport — reads plus two-step gated filing¶
Read tools, freely callable:
| Tool | What it does |
|---|---|
etransport_list |
Recent notifications for a CIF |
etransport_get_status |
An upload's processing status |
etransport_lookup |
Active declarations / UIT lookups |
etransport_uit_card |
Render a filed declaration's UIT as the driver card — a phone-shaped PDF written to a caller-given path — plus the plain-text message to send with it. Prints ANAF's data_exp_uit when you have one, otherwise the OUG 41/2022 window derived from the transport date, marked as an estimate |
etransport_uit_details |
Render the whole filing as the A4 detail document (goods table, caller's observations), written to a caller-given path; same validity treatment as the card |
etransport_nomenclature |
The XSD code lists (counties, border points, customs offices, operation types, …) plus the UN/ECE unit codes — names are accepted anywhere a coded field is; operation types also carry the UIT's validity in calendar days |
Filing is split prepare → confirm → submit, and nothing reaches ANAF without your explicit approval:
| Tool | What it does |
|---|---|
etransport_prepare_declaration |
Compose a new declaration (or a correction, via correction_of_uit) from structured fields; the preview states the validity window the issued UIT would carry, while the transport date can still be changed |
etransport_prepare_deletion |
Compose a UIT deletion |
etransport_prepare_confirmation |
Compose an arrival confirmation |
etransport_prepare_vehicle_change |
Compose a vehicle change |
etransport_prepare |
Same gate, for ready-made XML you already have |
etransport_submit |
File a prepared document |
Every prepare* — e-Factura and e-Transport — returns a human-readable preview
plus a confirmation token cryptographically bound to the exact document
bytes and the CIF being filed for. The matching *_submit files only when given
that token and confirm=true, and each token is single-use — so a
non-idempotent upload can never be repeated on one approval, and any mangling of
the document between prepare and submit fails closed.
SPV — the taxpayer's mailbox, read-only¶
The spv_* tools read SPV (Spațiul Privat Virtual) — receipts, decisions,
notifications — and request official reports. They authenticate with your
qualified certificate, not the OAuth application, and are read-only by
design: no declaration submission of any kind.
Pick a certificate once (spv_list_certificates / spv_select_certificate,
or anafpy spv certs + anafpy spv select), then establish a session either
by asking Claude to log in (spv_login — gated on your explicit approval,
because it fires your token/2FA prompt) or by running anafpy spv login
in a terminal. Sessions idle out in under an hour; the tools then ask for a
fresh login rather than failing obscurely.
| Tool | What it does |
|---|---|
spv_list_certificates |
Certificates usable for SPV in the OS key store (Keychain / CertStore), token and cloud-HSM ones included |
spv_select_certificate |
Persist which certificate the SPV login uses |
spv_login |
Establish a fresh SPV session — requires your explicit approval (confirm=true) since it fires your certificate PIN/2FA |
spv_status |
Session smoke test; reports the certificate's CNP/serial and authorized_cuis — every CUI/CNP it has SPV rights for |
spv_lista_mesaje |
Inbox messages from the last N days, filterable by CUI and message kind, paged |
spv_descarca |
Download one message's PDF to a path you name (never into context; existing files never replaced without overwrite) |
spv_nomenclature |
The SPV code lists: every report type spv_cerere accepts, each with a plain-language description of what it contains (so "my VAT return for March" finds D300 without you knowing the code) and its per-type parameters, and ANAF's fixed reason (motiv) list for income certificates — Claude maps your stated purpose onto the exact wording ANAF prints on the certificate |
spv_cerere |
Request a report — VECTOR FISCAL, Obligatii de plata, Istoric declaratii, the D1xx/D3xx duplicates, Duplicat Recipisa, Adeverinte Venit, … Parameters are validated per report type before anything is sent; identical same-day repeats are deduped |
spv_asteapta_raport |
Wait for a requested report to land in the inbox and save its PDF; a pending answer just means "call again later" |
Like the e-Factura PDF, a message's document is also available as the MCP
resource spvmsg://<mesaj_id>/pdf — a disk-free path for hosts with resource
UX. It needs an active SPV session (a resource read can't ask for a login);
spv_descarca remains the save-to-disk path.
Declarations — author, validate, render, sign, file, track¶
Prepare tax declarations — any form ANAF's validator covers, with hands-on
completion guides for the common SME declarations (D100, D101, D112, D205,
D212, D300, D301, D390, D394, D406, D700, D710) — entirely on your machine:
ANAF's own DUKIntegrator validates and renders the official PDF, and your
qualified certificate signs it. Filing the signed PDF is automated too, on
ANAF's declaration portal (the same one behind anaf.ro → Depunere declarații).
Two things to know before using it: filing goes to the production portal —
declarations have no test environment, so every submission is a real filing —
and it is an opt-out feature (ANAFPY_DECLARATII_UPLOAD=off removes the
filing tools and Claude guides you through manual portal filing instead).
The portal login is deliberately a separate step from submitting: it fires
your certificate PIN/2FA once (like spv_login), and the session it
establishes is probed — without any 2FA — before anything is uploaded.
The authoring tools need DUKIntegrator + Java — declaratie_duk_install
provisions DUK itself into ~/.anafpy/duk-dist (an explicit ANAFPY_DUK_DIR
wins over the managed install) — and signing needs your qualified certificate in
the platform key store (macOS Keychain or the Windows certificate store); the
status/recipisa tools ride ANAF's public StareD112 service and need no
configuration and no login at all.
| Tool | What it does |
|---|---|
declaratie_validate |
Validate a declaration with ANAF's own DUKIntegrator (authoritative); returns its findings verbatim — the compose→validate→fix loop. Missing DUK/Java configuration is a tool error, not an invalid-document result |
declaratie_render |
Render the official multi-page PDF (XML embedded) directly to a path you name; validates first, so a failure writes no PDF. Missing DUK/Java configuration is a tool error |
declaratie_sign |
Sign a rendered PDF with your qualified certificate — requires your explicit approval (confirm=true) since it fires your PIN/2FA prompt; failures come back as signed=false + guidance |
declaratie_nr_evid |
Compose the 23-char nr_evid payment-evidence number for the self-assessed forms — form= D300 (needs tip_decont), D100/D710 (need cod_oblig + scadenta), D101 (adds in_liquidation), D301 (takes mijl_trans). It has a check digit — never compute it by hand |
declaratie_duk_install |
Install or update DUKIntegrator from ANAF's official update feed — no manual download. Named forms install exactly those validators; a bare call converges the common preinstall set plus everything already installed. HTTPS-pinned to static.anaf.ro, manifest-audited, safe to repeat; the ~91 MB D406T archive downloads only when that form is named |
declaratie_duk_status |
The DUKIntegrator install: directory, Java version, and installed-vs-current validator versions (CLI-mode DUK does not auto-update — declaratie_duk_install refreshes it); the current feed is still returned before DUK is installed. Each form's state keeps current / stale / not installed / not in feed (D406T) apart, and stale flags only the ones an update would fix |
declaratie_portal_status |
Probe whether the filing-portal session is still alive (they die after ~10 idle minutes) — a plain page fetch, never fires your PIN/2FA |
declaratie_portal_login |
Log in to the filing portal with the selected certificate — requires your explicit approval (confirm=true) since it fires your PIN/2FA prompt; deliberately outside the submit flow, so one login serves the whole filing |
declaratie_prepare |
STEP 1 of filing: reads the signed PDF and returns a confirmation token bound to its exact bytes (plus a local heads-up if no embedded signature is detected). Nothing is filed |
declaratie_submit |
STEP 2: uploads the signed PDF to the production portal — requires the prepare token and your explicit confirm=true, probes the session before spending the single-use token, and returns the portal's verdict with the upload index (feed it to declaratie_status / declaratie_recipisa) |
declaratie_status |
Check a filed declaration's processing state by upload index + CUI — returns the client-layer DeclarationStatusList directly, containing all the CUI's filings from the last 3 months (max 200). Config/network/input failures return the same typed shape with found=false and message |
declaratie_recipisa |
Save the digitally signed recipisa (filing receipt) PDF to a path you name — available only ~60 days from filing, so archive it |
Resources and prompts¶
The compiled ANAF API reference is served as
read-only MCP resources — URIs mirror the file tree without the .md suffix
(the D300 completion guide is anafref://declaratii/forms/d300, the form
inventory anafref://declaratii/forms/README) — and the
workflow skills as MCP prompts.
Configuration¶
Configuration is environment-only, set in the MCP client's server entry:
| Variable | Meaning |
|---|---|
ANAFPY_CLIENT_ID / ANAFPY_CLIENT_SECRET |
Your ANAF OAuth application. Optional — without them the server still starts and serves the public anaf_* lookups and efactura_validate; the authenticated tools explain how to enable themselves |
ANAFPY_CIF |
Default fiscal code (digits only) used when the conversation doesn't say otherwise |
ANAFPY_ENV |
prod (default) or test — ANAF's TEST environment for practicing |
ANAFPY_TOKEN_STORE_BACKEND |
keyring (default, OS credential store) or file for headless/Docker hosts |
ANAFPY_TOKEN_STORE |
Token file path for the file backend (default ~/.anafpy/tokens.json) |
ANAFPY_REDIRECT_URI |
OAuth callback URL the auth_login browser flow listens on — must exactly match a Callback URL registered on your ANAF application (default https://localhost:9002/callback, the URL the setup guide registers; anafpy auth login reads the same variable and default) |
ANAFPY_DOCS_DIR |
ANAF reference served as resources (defaults to the repo's docs/anaf-reference/ when present, else the copy packaged in the wheel) |
ANAFPY_SKILLS_DIR |
Workflow skills served as prompts (defaults to the repo's plugins/anafpy-workflows/skills/ when present, else the copy packaged in the wheel) |
ANAFPY_SPV_SESSION |
SPV cookie-session store written by anafpy spv login (default ~/.anafpy/spv-session.json) |
ANAFPY_SPV_IDENTITY_FILE |
Persisted SPV certificate selection (default ~/.anafpy/spv-identity.json) |
ANAFPY_DUK_DIR |
An extracted DUKIntegrator dist/ folder; overrides the managed install that declaratie_duk_install maintains at ~/.anafpy/duk-dist |
ANAFPY_DUK_JAVA |
The java binary DUKIntegrator runs under (optional; falls back to java on PATH, then to JAVA_HOME) |
ANAFPY_SIGN_IDENTITY |
Certificate to sign declarations with — the Keychain identity name on macOS, the SHA-1 thumbprint on Windows (optional; falls back to the persisted SPV certificate selection) |
ANAFPY_DECLARATII_UPLOAD |
Set to off to opt out of automated declaration filing — the portal tools (declaratie_portal_*, declaratie_prepare, declaratie_submit) are then not served and Claude guides manual filing instead (default: on) |
ANAFPY_CURL |
The curl program the SPV and declaration-portal certificate logins run (optional). Set it only to work around a broken one — see the setup guide's troubleshooting table. It outranks everything below |
ANAFPY_BUNDLED_CURL |
Set by the Windows extension to the curl it ships, and preferred over the computer's own (which is the one that breaks there). Not a setting to fill in yourself; without it the OS curl is used — /usr/bin/curl on macOS, System32\curl.exe on Windows |
All three interactive logins are exposed as tools with the same contract —
your explicit go-ahead per attempt, one attempt per call, failure reported as
guidance rather than an error, and the sensitive step out-of-band: auth_login
drives the OAuth browser login (the certificate happens in your browser), while
spv_login and declaratie_portal_login drive the certificate logins whose
human gate is your PIN/2FA approval. Beyond the login, the server only reads
and headlessly refreshes the token store the login wrote.