Skip to main content
Glama
README.md
# Italy Invoice MCP ๐Ÿ‡ฎ๐Ÿ‡น โ€” How can my AI agent issue a FatturaPA fattura elettronica in Italy?

<!-- install-cta -->
## Use it in 60 seconds

Paste this into your MCP client config (Claude Desktop, Cursor, Windsurf, or any MCP-capable agent):

```json
{
  "mcpServers": {
    "italy-invoice": {
      "type": "http",
      "url": "https://inv-it.wishpool.app/mcp"
    }
  }
}
```

Nothing to install. Credentials, when you need them, travel as HTTP headers on each request and are never stored โ€” see the [threat model](https://mcp.wishpool.app/trust).

### Or run it yourself

Would you rather not send production credentials to a server you do not control? Deploy this identical code to your own account and point your agent at your own URL:

[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/junter1989k-ai/italy-invoice-mcp)

```bash
git clone https://github.com/junter1989k-ai/italy-invoice-mcp && cd italy-invoice-mcp && npx vercel --prod
```

MIT-licensed. Self-hosting removes us from the picture entirely, at no cost and with no loss of function.

---

Remote MCP server that lets any AI agent issue **Italy FatturaPA electronic invoices** (fattura elettronica) and transmit them to the national **SdI** (Sistema di Interscambio) via **Invoicetronic**. It builds **FatturaPA FPR12** XML (Agenzia delle Entrate v1.2 schema) and sends it under the merchant's own Invoicetronic API key. Stateless, bring-your-own credentials, never stores anything.

**Live endpoint:** `https://inv-it.wishpool.app/mcp` ยท Registry: `app.wishpool/italy-invoice-mcp`

## Quick start

```json
{
  "mcpServers": {
    "italy-invoice": {
      "type": "http",
      "url": "https://inv-it.wishpool.app/mcp",
      "headers": {
        "x-invoicetronic-key": "ik_test_<your Invoicetronic key>"
      }
    }
  }
}
```

Sign up at **invoicetronic.com** for a free `ik_test_` sandbox key (no fiscal effect). An `ik_live_` key transmits real invoices to the SdI โ€” the **base URL is the same**, the key prefix selects the environment. Authentication is HTTP Basic with the key as the username (empty password). Your key stays with you and travels per-request; this server never stores it.

## Tools

| Tool | What it does |
|---|---|
| `create_invoice` | Build a FatturaPA FPR12 invoice from seller + buyer (P.IVA / Codice Fiscale, address) and line items (description, net unit price, IVA rate 22/10/5/4, quantity), then transmit to the SdI via Invoicetronic. Returns `send_id` + computed IVA totals (`imponibile`, `imposta`, `totale`). |
| `query_invoice` | Poll SdI status by `send_id`: `SENT` (Inviato), `DELIVERED` (Consegnato), `REJECTED` (Scartato), `NOT_DELIVERED` (ImpossibilitaDiRecapito), or `PROCESSING` (no notification yet). |

Amounts are in EUR. Italian IVA rates: **22** (ordinaria), **10**, **5**, **4** (ridotte). Seller/buyer identified by **Partita IVA** and/or **Codice Fiscale**.

**No cancel at the SdI level** โ€” to reverse an invoice you issue a credit note (nota di credito, `TipoDocumento` TD04) as a new invoice. Zero-rated / exempt IVA (needs a `Natura` code) is out of scope in v1.

Owner policy guardrails ride optional headers (`x-agentpay-max-amount`, `x-agentpay-approval-above`, `x-agentpay-allowed-tools`) โ€” set by the human owner in client config; the agent cannot relax them.

## IVA math (deterministic)

Per line `PrezzoTotale = round2(quantity ร— unit_price)`; grouped by rate into `DatiRiepilogo` (`ImponibileImporto`, `Imposta = round2(imponibile ร— rate / 100)`); document total `ImportoTotaleDocumento = imponibile + imposta`. Examples:

- `100 + 50` both @22% โ†’ imponibile **150.00** / imposta **33.00** / totale **183.00**
- `200 @22% + 100 @10%` โ†’ imponibile **300.00** / imposta **54.00** (44 + 10) / totale **354.00**
- `2ร—50 @22% + 3ร—10 @10% + 1ร—25 @4%` โ†’ imponibile **155.00** / imposta **26.00** (22 + 3 + 1) / totale **181.00**

## Endpoints wrapped (Invoicetronic REST)

- Base: `https://api.invoicetronic.com/v1` (single base URL; auth = HTTP Basic, username = API key, empty password)
- Send: `POST /send` โ€” JSON `{ file_name, payload (base64 FatturaPA XML), encoding: "base64", meta_data }` โ†’ `{ id, ... }`
- Query: `GET /update?send_id={id}` โ€” SdI notification history (`state`: Inviato / Consegnato / Scartato / ImpossibilitaDiRecapito)
- Pre-flight validation: `POST /send` may reply `422 Unprocessable Entity` for a FatturaPA rule violation
- (Inbound `GET /receive` exists for received invoices; not wrapped as a tool in v1.)

## Develop

```bash
node test/serve.js   # local server on :3234
node test/e2e.js     # IVA math + FatturaPA XML structure + protocol + validation + policy + fake-key live probe
```

## Safety

Pure stateless translation layer over the Invoicetronic REST API (which wraps the national SdI). The API key travels per-request in a header, nothing is stored, and funds are never touched โ€” this issues tax invoices, it does not move money. [Privacy policy](https://inv-it.wishpool.app/privacy).

## Sister servers

Local invoices, one family: Mexico CFDI (inv-mx) ยท Romania e-Factura (inv-ro) ยท Brazil NF-e (inv-br) ยท Chile DTE (inv-cl) ยท India GST (inv-in). Local payments in 81 countries: [mcp.wishpool.app](https://mcp.wishpool.app).

MIT licensed.

Maintenance

ActivityMaintained
ResponsivenessSyncing