MCP server for Mexican tax and banking data — validate RFC, CURP, CLABE and NSS, read CFDI 4.0 invoices, query the SAT status service and look up SAT catalogues. Read-only, no API keys required.
- ✓Open-source license (MIT)
- ✓Actively maintained (<30d)
- ✓Clear description
- ✓Topics declared
- ✓Documented (README)
claude mcp add mx-fiscal -- npx -y mx-fiscal-mcp-server{
"mcpServers": {
"mx-fiscal": {
"command": "npx",
"args": ["-y", "mx-fiscal-mcp-server"],
"env": {
"MCP_AUTH_TOKEN": "<mcp_auth_token>"
}
}
}
}MCP_AUTH_TOKENMCP Servers overview
# mx-fiscal-mcp-server
> An [MCP](https://modelcontextprotocol.io) server that gives an AI agent **Mexican tax and banking** capabilities — validate RFC, CURP, CLABE and NSS with real check digits, read a CFDI 4.0 invoice, ask the SAT whether it is still live, and look up the SAT's code tables. **No API keys, no CSD certificate, no PAC contract.**
[](https://github.com/OrtaMarco/mx-fiscal-mcp-server/actions/workflows/ci.yml)
[](https://www.npmjs.com/package/mx-fiscal-mcp-server)
[](https://modelcontextprotocol.io)
[](https://www.typescriptlang.org/)
[](./LICENSE)
Ask Claude *"read this invoice and tell me whether it's still valid"* and it parses
the XML, labels every SAT code, checks both RFCs and the arithmetic, and queries
the SAT's public status service — instead of you opening three web tools.
```
> Read this CFDI and check it at the SAT
parse_cfdi(xml="<cfdi:Comprobante …>")
CFDI A-1042 — 1160.00 MXN
✅ Stamped · version 4.0 · Ingreso
Emisor: TES150312DX2 ✅ 601 — General de Ley Personas Morales
Receptor: PELJ900521DK2 ✅ G03 — Gastos en general
✅ Totals add up: subtotal − discount + transferred − withheld = total
cfdi_status(xml="<cfdi:Comprobante …>")
CFDI status — Vigente
✅ The invoice exists in the SAT's records and has not been cancelled.
Es cancelable: Cancelable con aceptación
EFOS: returned 200 — the issuer is NOT on the SAT's definitive 69-B list.
```
---
## Why this exists
Mexican electronic invoicing has two halves, and only one of them was served.
**Building and stamping** a CFDI needs a CSD certificate and a contract with a PAC.
That half already has tooling — [`mcp-cfdi-mx`](https://github.com/cmendezs/mcp-cfdi-mx)
(Python) does it, and this server deliberately does not compete with it.
**Reading** is the other half, and it needs nothing: the check-digit algorithms are
public, the SAT's catalogues are public, and the invoice status service behind the QR
code on every printed invoice is public and unauthenticated. Yet an agent asked to
validate an RFC will happily invent a regex that rejects `XAXX010101000` — the RFC of
every invoice issued to the general public — because that one does not satisfy its own
check digit. This server is the read half, done carefully.
The arithmetic comes from [`mx-identifiers`](https://github.com/OrtaMarco/mx-identifiers)
(MIT, zero dependencies, 101 tests against public vectors); the CFDI reader is ported
from the tool running at [ortamarco.me](https://ortamarco.me/en/tools/cfdi-viewer/);
the SOAP envelope was read out of [`nodecfdi/sat-estado-cfdi`](https://github.com/nodecfdi/sat-estado-cfdi)
rather than guessed. It is the third of three read-only, key-free MCP servers alongside
[`domain-security-mcp-server`](https://github.com/OrtaMarco/domain-security-mcp-server)
and [`seo-geo-mcp-server`](https://github.com/OrtaMarco/seo-geo-mcp-server).
## Tools
### Identifiers
| Tool | What it does |
|---|---|
| `validate_rfc` | RFC for individuals (13 chars) and companies (12), full modulus-11 check digit, parsed fields, birth/incorporation date. Flags the SAT generics and says which of them satisfies the arithmetic |
| `validate_curp` | 18-character CURP with the base-37 check digit; decodes birth date, sex, state (RENAPO keys, *not* INEGI/ISO) and the century marker |
| `validate_clabe` | 18-digit CLABE with the correct 3-7-1 control digit — each weighted product counts only its **last digit** (`9 × 7 = 63` counts `3`), not the Luhn-style sum of its digits (`6 + 3 = 9`) many implementations copy — plus the Banxico bank and the plaza code |
| `validate_nss` | 11-digit IMSS number with its Luhn digit, split into subdelegación / registration year / birth year / serial |
| `generate_test_data` ⭐ | 1-100 coherent fake people or companies: the RFC and CURP derive from the same name and birth date, the CLABE's bank is a real participant, every check digit holds |
### CFDI
| Tool | What it does |
|---|---|
| `parse_cfdi` ⭐ | CFDI 4.0 XML → JSON: header, issuer, receiver, every line item with transferred and withheld taxes, tax totals, and the Timbre Fiscal Digital (or `null`). Labels every catalogue code, validates both RFCs, checks the totals arithmetic. Walks the document by local name, so any PAC's namespace prefixes work |
| `cfdi_status` ⭐ | Queries the SAT's public `ConsultaCFDIService` SOAP endpoint: Estado, EsCancelable, EstatusCancelación and ValidaciónEFOS, each with its meaning in plain words. Takes the four key fields **or** the whole XML. Fail-soft: 10 s timeout, one retry, `available: false` on failure — never an exception |
### Catalogues
| Tool | What it does |
|---|---|
| `sat_catalog_lookup` | Nine bundled code tables — `regimen_fiscal`, `uso_cfdi`, `forma_pago`, `metodo_pago`, `tipo_comprobante`, `objeto_imp`, `impuestos`, `bancos_clabe`, `estados_curp` — by exact code (leading zeros ignored) or accent-insensitive text search. Never touches the network |
Every tool is **read-only**, declares an `outputSchema` and returns `structuredContent`
(validated by the SDK) alongside human-readable Markdown (default) or JSON
(`response_format="json"`).
## Honesty notes
These are surfaced in the tool output, not buried here:
- **Structurally valid is not registered.** A check digit that adds up says the string
is well-formed and nothing more. Only the SAT can say an RFC is registered; only
RENAPO that a CURP belongs to a person. This server never asks either, and its
wording never implies it did.
- **`XAXX010101000` does not satisfy its own check digit.** The SAT assigned the
general-public RFC by decree and the modulus-11 algorithm asks for a `4` where the
SAT wrote a `0`. `XEXX010101000` (foreign residents) *does* satisfy it. The tools
report `is_generic` and `check_digit_satisfied` as separate fields rather than
collapsing both into "valid".
- **Reading a CFDI is not verifying it.** `parse_cfdi` does not check the digital
signature. A perfectly parseable invoice can be cancelled, or fabricated wholesale.
- **An unreachable SAT is not an invalid invoice.** The status endpoint publishes no
SLA and no status page, and it goes down. Its documentation states capacity for up to
2 million queries per hour and asks callers not to raise their query volume, since
every query reads the SAT's transactional databases. `cfdi_status` degrades to
`available: false` with the reason — a statement about the SAT, never about the
document.
- **The bank list is a subset.** `bancos_clabe` carries the main Banxico participants,
not the full catalogue; an unknown code is reported as unknown rather than given an
invented name. The plaza catalogue is not bundled at all, so the plaza code is
returned verbatim.
- **EFOS codes are read from the SAT's own table.** The SAT documents `ValidacionEFOS`
in its [*Documentación del Servicio de Consulta de CFDI* v1.4](http://omawww.sat.gob.mx/tramitesyservicios/Paginas/documentos/Documentacion_WS_Consulta_CFDI_v1.4.pdf),
section 3: `100`, `101` and `104` put the **issuer** on the definitive 69-B list;
`102` and `103` mean the issuer is **not** on it but a third-party RFC the invoice was
issued on behalf of (*a cuenta de terceros*) is; `200` and `201` mean the issuer is not
on it (`201`: nor any third party). `efos_state` speaks of the issuer only, and
`efos_third_party_state` (`listed` / `not_listed` / `not_reported` / `unknown`) of the
third parties. An empty field or an undocumented code is reported as `unknown` with
the raw code kept in `validacion_efos`, never as "listed". Versions up to 1.0.1
reported `102` and `103` as an issuer on the list; 1.0.2 fixes it.
## Protocol
Built on the **v2 MCP SDK**, so it speaks the **2026-07-28** revision (`server/discover`,
no `initialize`, per-request `_meta` envelope) **and still serves 2025-era clients** —
Claude Desktop, Claude Code and Cursor — from the same server factory. The entry points
own the era decision: `serveStdio(factory)` on stdio, `createMcpHandler(factory)` over
HTTP with the default `legacy: 'stateless'`. There is no session state and no
`Mcp-Session-Id` in either direction. `npm run smoke` exercises every tool on **both**
eras and asserts the negotiated era of each connection.
Because the tool list is a compile-time constant, `tools/list` and `server/discover`
advertise a real one-hour `ttlMs` with `cacheScope: 'public'` on 2026-era connections
instead of the SDK's conservative `ttlMs: 0`.
## Install
Requires **Node.js 20+**. Nothing to clone — every MCP client can run it with `npx`.
## Use it with Claude Code
```bash
claude mcp add mx-fiscal -- npx -y mx-fiscal-mcp-server
```
## Use it with Claude Desktop or Cursor
Add to `claude_desktop_config.json` (or `~/.cursor/mcp.json`) — see [`examples/`](./examples/claude_desktop_config.json):
```json
{
"mcpServers": {
"mx-fiscal": {
"command": "npx",
"args": ["-y", "mx-fiscal-mcp-server"]
}
}
}
```
On Windows use `"command": "cmd"` with `"args": ["/c", "npx", "-y", "mx-fiscal-mcp-server"]`.
Restart the client, then ask: *"Generate 10 Mexican customers with valid RFC and CURP for my seed file."*
## Self-host (HTTP transport)
The same server speaks stateless **Streamable HTTP** for remote or multi-client use.
```bash
TRANSPORT=http npx -y mx-fiscal-mcp-server
# POST JSON-RPC to http://127.0.0.1:3000/mcp · health at /healthz
```
It is **safe by default**: it binds to `127.0.0.1` and only accepts `localhost`
`Host` and `Origin` headers, which blocks DNS-rebinding attacks from a web page.
To expose it — for example behind Coolify or Traefik — opt in explicitly:
| Variable | Default What people ask about mx-fiscal-mcp-server
What is OrtaMarco/mx-fiscal-mcp-server?
+
OrtaMarco/mx-fiscal-mcp-server is mcp servers for the Claude AI ecosystem. MCP server for Mexican tax and banking data — validate RFC, CURP, CLABE and NSS, read CFDI 4.0 invoices, query the SAT status service and look up SAT catalogues. Read-only, no API keys required. It has 0 GitHub stars and its last recorded update is dated 2026-09-13.
How do I install mx-fiscal-mcp-server?
+
You can install mx-fiscal-mcp-server by cloning the repository (https://github.com/OrtaMarco/mx-fiscal-mcp-server) or following the README instructions on GitHub. ClaudeWave also provides quick install blocks on this page.
Is OrtaMarco/mx-fiscal-mcp-server safe to use?
+
Our security agent has analyzed OrtaMarco/mx-fiscal-mcp-server and assigned a Trust Score of 95/100 (tier: Verified). See the full breakdown of passed checks and flags on this page.
Who maintains OrtaMarco/mx-fiscal-mcp-server?
+
OrtaMarco/mx-fiscal-mcp-server is maintained by OrtaMarco. The last recorded GitHub activity is dated 2026-09-13, with 0 open issues.
Are there alternatives to mx-fiscal-mcp-server?
+
Yes. On ClaudeWave you can browse similar mcp servers at /categories/mcp, sorted by popularity or recent activity.
Deploy mx-fiscal-mcp-server to your cloud
Ship this repo to production in minutes. Each platform spins up its own environment with editable env vars.
Maintain this repo? Add a badge to your README
Drop the badge into your GitHub README to show it's tracked on ClaudeWave. Each badge links back to this page and reflects the live Trust Score.
[](https://claudewave.com/repo/ortamarco-mx-fiscal-mcp-server)<a href="https://claudewave.com/repo/ortamarco-mx-fiscal-mcp-server"><img src="https://claudewave.com/api/badge/ortamarco-mx-fiscal-mcp-server" alt="Featured on ClaudeWave: OrtaMarco/mx-fiscal-mcp-server" width="320" height="64" /></a>More MCP Servers
Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.
User-friendly AI Interface (Supports Ollama, OpenAI API, ...)
An open-source AI agent that brings the power of Gemini directly into your terminal.
Real-time global intelligence dashboard. AI-powered news aggregation, geopolitical monitoring, and infrastructure tracking in a unified situational awareness interface
🕷️ An adaptive Web Scraping framework that handles everything from a single request to a full-scale crawl!
The fastest path to AI-powered full stack observability, even for lean teams.