# Mexican Tax & Banking (npm · mx-fiscal-mcp-server)

Validate RFC, CURP, CLABE and NSS, read CFDI 4.0 invoices and check their SAT status. No keys.

- Trust score: 83/100 (high trust)
- Change this week: +3
- Registry status: active
- Liveness: live
- Owner verified: no
- Last scored: 2026-09-23

## Components

- npm · `mx-fiscal-mcp-server`: 83/100 (this document), [markdown](https://verifymcp.io/servers/ortamarco-mx-fiscal-mcp-server/mx-fiscal-mcp-server.md), [page](https://verifymcp.io/servers/ortamarco-mx-fiscal-mcp-server/mx-fiscal-mcp-server)

## Channel facts

- Registry: `npm`
- Package: `mx-fiscal-mcp-server`
- Version: `1.0.2`
- Transport: `stdio`

## Trust breakdown

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. Scores are 0–100 per category. Scoring method: https://verifymcp.io/docs/scoring (what has changed: https://verifymcp.io/docs/scoring/changelog)

Scored 2026-09-23.

- **Supply Chain Security**: 98/100
  - No malware found by supply-chain analysis.
  - No known CVEs affecting this package version or its production dependencies.
  - No install/post-install scripts declared.
  - 23 of 76 dependencies flagged as unhealthy.
- **Provenance & Transparency**: 97/100
  - Source repository is publicly reachable at the declared URL.
  - Cryptographically verified build provenance (signed, bound to OrtaMarco/mx-fiscal-mcp-server).
  - Clear OSI-approved license (MIT).
  - Actively maintained (last published 10 days ago).
  - Disclosure check failed: no security disclosure policy was found in the source repository.
- **Schema Quality & AI Usability**: 61/100
  - AI-judged instruction clarity (excellent).
  - Context-footprint check failed: tool/resource definitions use about 4794 tokens (~599/item across 8 items; 8 tools + 0 resources), over budget; trim descriptions and params.
  - Usage-examples check failed: none of the tools include examples.
- **Stability & Change Management**: 40/100
  - Stability observed for 12 of 30 days with no destabilising changes; credit accrues until the full window elapses.
- **Tool Coverage**: 100/100
  - 100% of tools have a non-trivial description (not blank, and not just the tool's name).
  - 100% of tool parameters carry a description.
  - Structured output schemas are declared (100% of tools); any adoption earns full credit.
- **Tool Safety**: 100/100
  - No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.
  - We read all 8 captured tool definition(s), and no name or description among them implies an irreversible operation.
  - An AI judge read all 9 captured unit(s) of tool text and found none that tries to manipulate the model reading it.
- **Capabilities**: 100/100
  - Implements a current MCP spec version (2026-07-28).

## Install

### How do I install the Mexican Tax & Banking MCP server?

Mexican Tax & Banking runs locally as an npm package, launched with npx -y mx-fiscal-mcp-server. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.

### Claude

```bash
claude mcp add ortamarco-mx-fiscal-mcp-server -- npx -y mx-fiscal-mcp-server
```

### Cursor

```json
{
  "mcpServers": {
    "ortamarco-mx-fiscal-mcp-server": {
      "command": "npx",
      "args": [
        "-y",
        "mx-fiscal-mcp-server"
      ]
    }
  }
}
```

### VS Code

```json
{
  "servers": {
    "ortamarco-mx-fiscal-mcp-server": {
      "command": "npx",
      "args": [
        "-y",
        "mx-fiscal-mcp-server"
      ]
    }
  }
}
```

### Codex

```bash
codex mcp add ortamarco-mx-fiscal-mcp-server -- npx -y mx-fiscal-mcp-server
```

### opencode

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "ortamarco-mx-fiscal-mcp-server": {
      "type": "local",
      "command": [
        "npx",
        "-y",
        "mx-fiscal-mcp-server"
      ],
      "enabled": true
    }
  }
}
```

### OpenClaw

```bash
openclaw mcp add ortamarco-mx-fiscal-mcp-server --command npx --arg -y --arg mx-fiscal-mcp-server
```

### Hermes

```yaml
mcp_servers:
  ortamarco-mx-fiscal-mcp-server:
    command: "npx"
    args: ["-y", "mx-fiscal-mcp-server"]
```

### Netclaw

```json
{
  "McpServers": {
    "ortamarco-mx-fiscal-mcp-server": {
      "Transport": "stdio",
      "Command": "npx",
      "Arguments": [
        "-y",
        "mx-fiscal-mcp-server"
      ]
    }
  }
}
```

### Vellum

```bash
assistant mcp add ortamarco-mx-fiscal-mcp-server -t stdio -c npx -a -y mx-fiscal-mcp-server
```

### Other

```json
{
  "mcpServers": {
    "ortamarco-mx-fiscal-mcp-server": {
      "command": "npx",
      "args": [
        "-y",
        "mx-fiscal-mcp-server"
      ]
    }
  }
}
```

## Changelog

Every change recorded for this component, newest first. Days that predate change tracking, or that we cannot explain, say so: "we were watching and nothing happened" and "we were not watching" are different claims.

### 2026-09-22 (score 83, +1)

No change was recorded against any check on this day. Stability & Change Management went from 33 to 37. That category is still filling its 30-day observation window: 10 days of observed history at the previous scan, 11 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-09-19 (score 82, +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.

### 2026-09-17 (score 81, +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.

### 2026-09-15 (score 80, +1)

No change was recorded against any check on this day. Stability & Change Management went from 10 to 13. That category is still filling its 30-day observation window: 3 days of observed history at the previous scan, 4 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-09-14 (score 79, +15)

- [security improvement] Malware scan: unverified → pass

### 2026-09-13 (score 64, −14)

- [security regression] Malware scan: pass → unverified
- [functional improvement] Stability: unverified → 0.07
- [functional] Package version: 1.0.1 → 1.0.2

### 2026-09-12 (score 78, +26)

- [security improvement] Malware scan: unverified → pass
- [security improvement] Known CVEs: unverified → pass
- [functional improvement] Dependency health: unverified → 0.85

### 2026-09-11 (score 52)

First indexed and scored.

## MCP tools (8)

### `validate_rfc` (~439 tokens)

Validate RFC

Validate a Mexican RFC (Registro Federal de Contribuyentes) — the SAT taxpayer ID — and break it into its parts. Works for both shapes: 13 characters for a persona física (individual) and 12 for a persona moral (company).

The last character is a modulus-11 check digit over the preceding ones, and this checks it. Two SAT-issued generics are special-cased and reported as such:

  \- **XAXX010101000** (público en general) does NOT satisfy the check-digit algorithm — the arithmetic asks for a '4' where the SAT wrote a '0'. It is valid by decree, not by maths, which is exactly why so many home-grown validators wrongly reject invoices to the general public.
  \- **XEXX010101000** (residentes en el extranjero) DOES satisfy it on its own.

The tool reports `is_generic` and `check_digit_satisfied` separately so you never have to conflate the two.

\**Structural validity is not registration.** A well-formed RFC may belong to nobody. Only the SAT can say whether one is registered and active, and this server never asks.

Args:
  \- value (string): the RFC. Spaces, dashes and lower case are normalised away.
  \- response_format ('markdown' | 'json'): output format (default 'markdown').

Returns: { input, normalized, valid, kind, is_generic, generic_note, parts{iniciales, fecha, homoclave, digito}, birth_date, expected_check_digit, check_digit_satisfied, errors[{code, message}], findings[] }.

Example: "Is GODE561231GR8 a valid RFC?" -> validate_rfc(value="GODE561231GR8").

Input parameters:

- `response_format` (string): Output format: 'markdown' for a human-readable summary (default) or 'json' for the full structured payload.
- `value` (string, required): The RFC to validate, e.g. 'GODE561231GR8' (individual) or 'MAB9307148T4' (company).

Output parameters:

- `birth_date` (string|null)
- `check_digit_satisfied` (boolean|null)
- `errors` (array)
- `expected_check_digit` (string|null)
- `findings` (array)
- `generic_note` (string|null)
- `input` (string)
- `is_generic` (boolean)
- `kind` (string|null)
- `normalized` (string)
- `parts`
- `valid` (boolean)

### `validate_curp` (~445 tokens)

Validate CURP

Validate a Mexican CURP (Clave Única de Registro de Población) — the 18-character population ID issued by RENAPO — and decode everything it encodes: birth date, sex, state of birth and the century marker.

The 18th character is a base-37 modulus-10 check digit over the first 17, and this checks it. Two details it gets right that a regex does not:

  \- **The state keys are RENAPO's own.** 'DF' is Ciudad de México, 'MC' is Estado de México, 'NE' means born abroad. They do not match the INEGI or ISO 3166-2:MX codes, so a lookup against those tables silently mislabels people.
  \- **The homoclave character carries the century.** A digit (position 17) means born before 2000; a letter means from 2000 onwards. Without it, positions 5-10 ('99' as a year) are ambiguous.

Names that would spell one of RENAPO's inconvenient words are flagged: a real CURP carries an X in the second position instead.

\**Structural validity is not registration.** Only RENAPO can confirm a CURP belongs to a real person, and this server never asks it.

Args:
  \- value (string): the CURP. Spaces, dashes and lower case are normalised away.
  \- response_format ('markdown' | 'json'): output format (default 'markdown').

Returns: { input, normalized, valid, parts{...}, birth_date, sex, sex_label, state_key, state_name, century_marker, expected_check_digit, errors[{code, message}], findings[] }.

Example: "Decode BOXW310820HNERXN09" -> validate_curp(value="BOXW310820HNERXN09").

Input parameters:

- `response_format` (string): Output format: 'markdown' for a human-readable summary (default) or 'json' for the full structured payload.
- `value` (string, required): The CURP to validate, e.g. 'BOXW310820HNERXN09'.

Output parameters:

- `birth_date` (string|null)
- `century_marker` (string|null)
- `errors` (array)
- `expected_check_digit` (string|null)
- `findings` (array)
- `input` (string)
- `normalized` (string)
- `parts`
- `sex` (string|null)
- `sex_label` (string|null)
- `state_key` (string|null)
- `state_name` (string|null)
- `valid` (boolean)

### `validate_clabe` (~447 tokens)

Validate CLABE

Validate an 18-digit CLABE (Clave Bancaria Estandarizada, Banxico Circular 3/2012) — the account number every SPEI transfer in Mexico is addressed to — and name the bank behind it.

Structure: 3 digits of bank + 3 of plaza (city/branch) + 11 of account + 1 control digit.

\**The control digit is the part everybody gets wrong.** The weights cycle 3-7-1, and each weighted product counts only its last digit (the product modulo 10): 9 × 7 = 63 counts as 3. Implementations that borrow the Luhn habit of adding the product's digits (6 + 3 = 9) compute a different control digit — for the base 09000000000000000 the algorithm gives 7 and the Luhn-style sum gives 1. (Reducing modulo 10 before or after summing gives the same result; that is not where they go wrong.) This uses the correct algorithm.

The bank code is resolved against a curated subset of Banxico's participant catalogue. A code that is not in the subset is reported as unknown rather than given an invented name. The plaza code is reported verbatim: the full plaza catalogue is not bundled, so no city is guessed.

Args:
  \- value (string): the CLABE. Spaces and dashes are normalised away.
  \- response_format ('markdown' | 'json'): output format (default 'markdown').

Returns: { input, normalized, formatted, valid, parts{banco, plaza, cuenta, digito}, bank_code, bank_name, plaza_code, plaza_note, expected_check_digit, errors[{code, message}], findings[] }.

Example: "Which bank is CLABE 012180012345678903?" -> validate_clabe(value="012180012345678903").

Input parameters:

- `response_format` (string): Output format: 'markdown' for a human-readable summary (default) or 'json' for the full structured payload.
- `value` (string, required): The CLABE to validate, e.g. '012180012345678903'.

Output parameters:

- `bank_code` (string|null)
- `bank_name` (string|null)
- `errors` (array)
- `expected_check_digit` (string|null)
- `findings` (array)
- `formatted` (string|null)
- `input` (string)
- `normalized` (string)
- `parts`
- `plaza_code` (string|null)
- `plaza_note` (string|null)
- `valid` (boolean)

### `validate_nss` (~275 tokens)

Validate NSS (IMSS)

Validate an 11-digit NSS (Número de Seguridad Social) issued by the IMSS, and split it into its fields: 2 digits of subdelegación, 2 of the year the holder was registered, 2 of the year of birth, 4 of serial, and a Luhn check digit over the first ten.

The two year fields are informational only. The IMSS has issued numbers whose years do not line up with the holder's records, so a mismatch is not grounds to reject a number — only the check digit is.

Args:
  \- value (string): the NSS. Spaces and dashes are normalised away.
  \- response_format ('markdown' | 'json'): output format (default 'markdown').

Returns: { input, normalized, valid, parts{subdelegacion, anioAlta, anioNacimiento, folio, digito}, expected_check_digit, errors[{code, message}], findings[] }.

Example: "Is 12345678903 a valid NSS?" -> validate_nss(value="12345678903").

Input parameters:

- `response_format` (string): Output format: 'markdown' for a human-readable summary (default) or 'json' for the full structured payload.
- `value` (string, required): The NSS to validate, e.g. '92119624722'.

Output parameters:

- `errors` (array)
- `expected_check_digit` (string|null)
- `findings` (array)
- `input` (string)
- `normalized` (string)
- `parts`
- `valid` (boolean)

### `generate_test_data` (~470 tokens)

Generate Mexican Test Data

Generate structurally valid Mexican identifiers for fixtures, database seeds and demos — generated, not taken from any real record.

For a **person** each record carries a coherent set: the RFC and the CURP are derived from the *same* name, sex, birth date and state, the CLABE's bank code is a real Banxico participant, and the NSS satisfies its Luhn digit. For a **company**, a razón social with a matching persona-moral RFC and a CLABE.

Why generated instead of hand-written: an RFC or CURP typed by hand almost never satisfies its check digit, so it fails the first validation your own code runs, and a seed file full of 'AAAA010101AAA' teaches your tests nothing.

\**These pass validation but are nobody's on purpose.** They are generated from common names, so a CURP or phone number can coincide with a real person's by chance; they are not looked up at the SAT, RENAPO, IMSS or Banxico — do not send them to the SAT's status service or to a PAC.

Args:
  \- kind ('person' | 'company'): what to generate (default 'person').
  \- count (integer 1-100): how many records (default 1).
  \- response_format ('markdown' | 'json'): output format (default 'markdown').

Returns: { kind, count, people[{nombre, apellido_paterno, apellido_materno, sexo, fecha_nacimiento, entidad, entidad_nombre, rfc, curp, clabe, banco, nss, codigo_postal, telefono, email}], companies[{razon_social, rfc, clabe, banco, codigo_postal, fecha_constitucion}], findings[] }.

Example: "Give me 5 fake Mexican customers with valid RFC and CURP" -> generate_test_data(kind="person", count=5).

Input parameters:

- `count` (integer): How many records to generate, 1-100.
- `kind` (string): 'person' for individuals (RFC + CURP + CLABE + NSS), 'company' for personas morales.
- `response_format` (string): Output format: 'markdown' for a human-readable summary (default) or 'json' for the full structured payload.

Output parameters:

- `companies` (array)
- `count` (number)
- `findings` (array)
- `kind` (string)
- `people` (array)

### `parse_cfdi` (~621 tokens)

Parse CFDI 4.0 XML

Turn the XML of a Mexican electronic invoice (CFDI 4.0) into structured JSON: header, issuer, receiver, every line item with its transferred and withheld taxes, the tax totals, and the Timbre Fiscal Digital (UUID, stamp date, SAT certificate number, PAC's RFC) — or `timbre: null` when the document was never stamped.

Three things this does beyond reading attributes:

  1\. **It labels the catalogue codes.** '601' becomes 'General de Ley Personas Morales', 'G03' becomes 'Gastos en general', 'PPD' becomes 'Pago en parcialidades o diferido'. An unknown code is reported as unknown rather than guessed at.
  2\. **It validates both RFCs** (issuer and receiver) with the full modulus-11 check, and flags the SAT generics.
  3\. **It checks the arithmetic**: subtotal − discount + transferred − withheld should equal the declared total. A mismatch is a warning, not a verdict — rounding at the line level is allowed within a centavo.

It walks the document by local element name, so it does not care whether the PAC used the `cfdi:` and `tfd:` prefixes, different ones, or none.

\**What this does NOT do:** it does not verify the digital signature, and it does not ask the SAT anything. A document that parses cleanly can still be cancelled, or have been fabricated wholesale. Use `cfdi_status` for the SAT's own answer.

Args:
  \- xml (string): the CFDI XML.
  \- response_format ('markdown' | 'json'): output format (default 'markdown').

Returns: { version, serie, folio, fecha, tipo(+label), forma_pago(+label), metodo_pago(+label), moneda, tipo_cambio, sub_total, descuento, total, lugar_expedicion, exportacion, condiciones_de_pago, no_certificado, emisor{rfc, nombre, regimen(+label), rfc_valid, rfc_kind, rfc_errors}, receptor{… domicilio, uso(+label)}, conceptos[{descripcion, clave_prod_serv, cantidad, clave_unidad, unidad, valor_unitario, importe, descuento, objeto_imp(+label), traslados[], retenciones[]}], concepto_count, total_trasladados, total_retenidos, stamped, timbre{uuid, fecha_ti…

Input parameters:

- `response_format` (string): Output format: 'markdown' for a human-readable summary (default) or 'json' for the full structured payload.
- `xml` (string, required): The complete CFDI XML as a string, from '<cfdi:Comprobante' (or '<?xml') to the closing tag.

Output parameters:

- `arithmetic` (object)
- `concepto_count` (number)
- `conceptos` (array)
- `conceptos_truncated` (boolean)
- `condiciones_de_pago` (string)
- `descuento` (string)
- `emisor` (object)
- `exportacion` (string)
- `fecha` (string)
- `findings` (array)
- `folio` (string)
- `forma_pago` (string)
- `forma_pago_label` (string|null)
- `lugar_expedicion` (string)
- `metodo_pago` (string)
- `metodo_pago_label` (string|null)
- `moneda` (string)
- `no_certificado` (string)
- `receptor` (object)
- `serie` (string)
- `stamped` (boolean)
- `sub_total` (string)
- `timbre`
- `tipo` (string)
- `tipo_cambio` (string)
- `tipo_label` (string|null)
- `total` (string)
- `total_retenciones_locales` (string)
- `total_retenidos` (string)
- `total_trasladados` (string)
- `total_traslados_locales` (string)
- `version` (string)

### `cfdi_status` (~879 tokens)

CFDI Status at the SAT

Ask the SAT whether an invoice actually exists and is still live. This queries the public `ConsultaCFDIService` SOAP endpoint — the same service the QR code printed on every Mexican invoice points at — so it needs **no credentials, no CSD and no PAC contract**.

Pass either the four values the SAT keys on (issuer RFC, receiver RFC, total, UUID) or the whole `xml`, in which case they are derived from it with the same reader `parse_cfdi` uses. Deriving them from the XML is the more reliable route: the total must be formatted exactly the way the printed-representation spec demands (six decimals, trailing zeros trimmed), and a total written in another format can come back as a spurious 'No Encontrado'.

What comes back, each with its meaning spelled out:

  \- **Estado** — Vigente / Cancelado / No Encontrado.
  \- **EsCancelable** — whether the issuer can cancel it unilaterally, needs the receiver's approval, or cannot cancel it at all.
  \- **EstatusCancelacion** — whether a cancellation is in progress, was accepted, was rejected, or lapsed.
  \- **ValidacionEFOS** — whether the issuer, and any third-party RFC the invoice was issued on behalf of (*a cuenta de terceros*), appears on the SAT's definitive 69-B list of companies that invoice simulated operations. Read with the code table the SAT documents (service documentation v1.4, section 3): 100, 101 and 104 put the issuer on the list; 102 and 103 mean the issuer is NOT on it but a third-party RFC 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` of the third parties; an empty field or an undocumented code is `unknown`, with the raw code kept in `validacion_efos`.
  \- **CodigoEstatus** — the service's own result code.

\**Fail-soft by design.** The SAT publishes no SLA and no status page, and the endpoint does go down; its documentation states capacity for up to 2 million queries per hour and asks callers not to raise their query vol…

Input parameters:

- `response_format` (string): Output format: 'markdown' for a human-readable summary (default) or 'json' for the full structured payload.
- `rfc_emisor` (string): Issuer's RFC. Required unless `xml` is given.
- `rfc_receptor` (string): Receiver's RFC. Required unless `xml` is given.
- `total` (string): Invoice total exactly as written in the XML, e.g. '1160.00'. Required unless `xml` is given.
- `uuid` (string): The fiscal folio (UUID) from the Timbre Fiscal Digital. Required unless `xml` is given.
- `xml` (string): The complete CFDI XML. When given, the four query fields are derived from it and any values passed alongside are ignored.

Output parameters:

- `attempts` (number)
- `available` (boolean)
- `elapsed_ms` (number)
- `endpoint` (string)
- `expression` (string)
- `findings` (array)
- `source` (string)
- `status`
- `unavailable_reason` (string|null)

### `sat_catalog_lookup` (~603 tokens)

SAT Catalogue Lookup

Look up the code tables a CFDI is written in, without downloading the SAT's spreadsheet. Nine catalogues, all bundled — this tool never touches the network.

  \- `regimen_fiscal` (c_RegimenFiscal) — tax regime of issuer and receiver
  \- `uso_cfdi` (c_UsoCFDI) — what the receiver does with the invoice
  \- `forma_pago` (c_FormaPago) — cash, transfer, card, …
  \- `metodo_pago` (c_MetodoPago) — PUE vs PPD
  \- `tipo_comprobante` (c_TipoDeComprobante) — I/E/T/N/P
  \- `objeto_imp` (c_ObjetoImp) — whether a line item is subject to tax (CFDI 4.0)
  \- `impuestos` (c_Impuesto) — ISR / IVA / IEPS
  \- `bancos_clabe` — Banxico participants by the first three CLABE digits
  \- `estados_curp` — RENAPO's state keys for CURP positions 12-13

With no `query` you get the whole catalogue. With one, an exact code match wins (leading zeros are ignored, so '1' finds '01'); failing that it falls back to a case- and accent-insensitive substring search over both code and label, so 'confianza' finds 626 and 'oaxaca' finds OC.

Two honesty notes carried in the output: the bank list is a curated subset of Banxico's participant catalogue rather than the whole thing, and the CURP state keys are RENAPO's own — they do **not** match INEGI or ISO 3166-2:MX codes.

Args:
  \- catalog (enum): one of regimen_fiscal, uso_cfdi, forma_pago, metodo_pago, tipo_comprobante, objeto_imp, impuestos, bancos_clabe, estados_curp.
  \- query (string, optional): an exact code, or text to search for.
  \- response_format ('markdown' | 'json'): output format (default 'markdown').

Returns: { catalog, official_name, authority, description, used_in, query, match_type, total_entries, match_count, entries[{code, label}], truncated, notes[] }.

Example: "What does UsoCFDI G03 mean?" -> sat_catalog_lookup(catalog="uso_cfdi", query="G03").

Input parameters:

- `catalog` (string, required): Which catalogue to read.
- `query` (string): An exact code ('626', 'G03', '012') or free text to search ('confianza', 'BBVA', 'Oaxaca'). Omit for the whole catalogue.
- `response_format` (string): Output format: 'markdown' for a human-readable summary (default) or 'json' for the full structured payload.

Output parameters:

- `authority` (string)
- `catalog` (string)
- `description` (string)
- `entries` (array)
- `match_count` (number)
- `match_type` (string)
- `notes` (array)
- `official_name` (string)
- `query` (string|null)
- `total_entries` (number)
- `truncated` (boolean)
- `used_in` (string)

## Diagnostics

Captured diagnostic sections: Provenance, Dependencies. The full working is on the page: https://verifymcp.io/servers/ortamarco-mx-fiscal-mcp-server/mx-fiscal-mcp-server#diagnostics

## Score history

- 2026-09-23: 83
- 2026-09-22: 83
- 2026-09-21: 82
- 2026-09-20: 82
- 2026-09-19: 82
- 2026-09-18: 81
- 2026-09-17: 81
- 2026-09-16: 80
- 2026-09-15: 80
- 2026-09-14: 79
- 2026-09-13: 64
- 2026-09-12: 78
- 2026-09-11: 52

## Common questions

### What is the Mexican Tax & Banking MCP server?

Mexican Tax & Banking is an MCP server listed in the public MCP registry as io.github.OrtaMarco/mx-fiscal-mcp-server. Validate RFC, CURP, CLABE and NSS, read CFDI 4.0 invoices and check their SAT status. No keys. This page covers its npm package (mx-fiscal-mcp-server).

### Is the Mexican Tax & Banking MCP server safe to use?

Mexican Tax & Banking scores 83 out of 100 on VerifyMCP. We found no known CVEs affecting it as of 23 September 2026. It declares no install or post-install scripts. Its build provenance is signed and verified. 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 Mexican Tax & Banking MCP server expose?

Mexican Tax & Banking exposes 8 tools: validate_rfc, validate_curp, validate_clabe, validate_nss, generate_test_data, and 3 more. Their descriptions and schemas cost roughly 4,179 tokens of context every time the server is loaded.

### Is the Mexican Tax & Banking MCP server still maintained?

Mexican Tax & Banking is still listed as active in the MCP registry. We last reached this channel on 23 September 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 Mexican Tax & Banking MCP server under?

Mexican Tax & Banking declares the MIT licence, which is OSI-approved. That covers the source only, and says nothing about the cost of any service it calls.

## Links

- npm package: https://www.npmjs.com/package/mx-fiscal-mcp-server
- Socket report: https://socket.dev/npm/package/mx-fiscal-mcp-server
- Repository: https://github.com/OrtaMarco/mx-fiscal-mcp-server
- Changelog RSS feed: https://verifymcp.io/servers/ortamarco-mx-fiscal-mcp-server/mx-fiscal-mcp-server.xml
- Changelog JSON feed: https://verifymcp.io/servers/ortamarco-mx-fiscal-mcp-server/mx-fiscal-mcp-server.json
- HTML version of this page: https://verifymcp.io/servers/ortamarco-mx-fiscal-mcp-server/mx-fiscal-mcp-server
