trackmcp
Back to directory

POP | Electronic Invoicing for Europe

0 stars TypeScriptOthers Updated Aug 11, 2026

Documentation

pop-mcp

MCP (Model Context Protocol) server for POP — enabling LLMs to generate, submit, and manage Italian e-invoices (FatturaPA/SdI), Peppol, KSeF, ZUGFeRD/Factur-X, and PDF invoices directly from AI assistants.

> npm: `@getpopapi/pop-mcp` · Remote: `https://mcp.popapi.io/mcp`

License: MIT
Node.js

Remote MCP (HTTP) — fastest way to get started

Don't want to install anything? `pop-mcp` runs as a hosted, multi-tenant MCP server at:

code
https://mcp.popapi.io/mcp

Head to popapi.io to grab a license key, then point any MCP-speaking client at

that URL with your key as a Bearer token. No local install, no `POP_API_KEY` env var, no build step

— this is the recommended way to try `pop-mcp` for most people. Use the local stdio setup below only

if you specifically need a Claude Desktop config running a process on your own machine.

How it works

This endpoint speaks MCP 2026-07-28, which is fully stateless: there is no `initialize`

handshake and no session to open or track. Every request is self-contained — it names its own

protocol version and capabilities — and the server answers it independently. Because of that,

this is a multi-tenant endpoint: it never reads a fixed `POP_API_KEY` from its own environment.

Every request must carry your own POP license key as a Bearer token:

code
Authorization: Bearer

A missing or malformed `Authorization` header returns a `401` with `error_code: "unauthorized_user"`

before any POP API call is made. An invalid-but-well-formed key is passed straight through to POP's

API and surfaces whatever error POP returns (`unauthorized_user`, `insufficient_level`, etc.) — the

server does not re-validate keys itself.

Any modern MCP HTTP client can connect: Claude (remote connector), the OpenAI Responses API, n8n,

MCP Inspector, or a custom integration — not

just Claude Desktop. All invoice, status, advanced, and onboarding tools are available; onboarding

tools use their own `onboarding_token` per call and don't require the Bearer key.

Example with curl

Discover the server's supported protocol versions and capabilities (optional — clients can also

just call `tools/list` or `tools/call` directly and handle a version-negotiation error inline):

bash
curl -X POST https://mcp.popapi.io/mcp \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer your_license_key_here" \
  -H "MCP-Protocol-Version: 2026-07-28" \
  -H "Mcp-Method: server/discover" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "server/discover",
    "params": { "_meta": { "io.modelcontextprotocol/protocolVersion": "2026-07-28", "io.modelcontextprotocol/clientCapabilities": {} } }
  }'

List the available tools — every request is self-contained, so `_meta` (protocol version + client

capabilities) travels on every call, not just the first one:

bash
curl -X POST https://mcp.popapi.io/mcp \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer your_license_key_here" \
  -H "MCP-Protocol-Version: 2026-07-28" \
  -H "Mcp-Method: tools/list" \
  -d '{
    "jsonrpc": "2.0",
    "id": 2,
    "method": "tools/list",
    "params": { "_meta": { "io.modelcontextprotocol/protocolVersion": "2026-07-28", "io.modelcontextprotocol/clientCapabilities": {} } }
  }'

The tool catalog is identical for every license key, so `tools/list` and `server/discover`

responses carry a one-hour public cache hint (`ttlMs: 3600000, cacheScope: "public"`) — clients and

gateways may cache them across tenants.

> `MCP-Protocol-Version` and `Mcp-Method` are required on every request (per SEP-2243), and must

> match the body's `_meta.protocolVersion` and `method` exactly, or the server rejects the request

> with a `400` and JSON-RPC error `-32020` (`HeaderMismatch`). `tools/call` requests additionally

> require an `Mcp-Name` header matching `params.name`.

Example with MCP Inspector

bash
npx @modelcontextprotocol/inspector

Configure it to connect to `https://mcp.popapi.io/mcp` with header

`Authorization: Bearer `.

This endpoint runs as a Vercel serverless function (`api/mcp.ts` → `src/mcpHandler.ts`). To run it

locally: `npx vercel dev` (requires `vercel link` to the project first).


What is POP?

POP is a cloud service for electronic invoice generation and delivery, supporting:

  • 🇮🇹 Italian e-invoicing (FatturaPA/SdI) — compliant with D.Lgs. 127/2015
  • 🇪🇺 Peppol — pan-European cross-border B2B invoicing (UBL 2.1)
  • 📄 PDF invoices — branded, with email delivery
  • Validation — fiscal codes, VAT numbers, document pre-submission checks
  • 🗄️ Preservation — Italian legal archival (conservazione sostitutiva)

Tools Available (11 total)

Invoice Creation

ToolEndpointPlan
`pop_create_sdi_invoice`POST `/create-xml`Any
`pop_create_peppol_invoice`POST `/create-ubl`Any (Basic+ to submit)
`pop_create_pdf_invoice`POST `/create-pdf`Any (Basic+ for email)
`pop_create_ksef_invoice`POST `/create-ksef-xml`Any (KSeF setup for provider submission)
`pop_create_zugferd_invoice`POST `/create-zugferd`Any
`pop_sync_zoho_document`POST `/integration/zoho/sync`Zoho connector required

Status & Retrieval

ToolEndpointPlan
`pop_get_invoice_status`POST `/sdi/document-notifications`Any
`pop_get_peppol_document`POST `/peppol/document-get`Basic+
`pop_get_sdi_document`POST `/sdi/document-get`Basic+

Validation & Advanced SdI

ToolEndpointPlan
`pop_verify_sdi_document`POST `/sdi/document-verify`Basic+
`pop_preserve_document`POST `/sdi/document-preserve`Basic+

Prerequisites

  • Node.js >= 20
  • A POP license key
  • For SdI/Peppol submission: active integration on your POP account (Basic/Growth plan)

Authentication

Get Your License Key

> New to POP? Visit popapi.io to create your account and get your license key.

API-only users can activate their account and obtain a `license_key` with this flow:

1. Open https://popapi.io/otp-login/

2. Enter your email address

3. Receive a one-time password (OTP) by email and enter it

4. Complete the configuration wizard

5. Open https://popapi.io/Account > API

6. Copy the default generated `license_key`

Key Management

  • Your account includes one default `license_key`, visible under Account > API
  • You can generate additional keys linked to the same account from that same page
  • Every `license_key` must be treated as a secret credential — do not commit it to source control

1. Get your `license_key`

2. Test it with `GET /account-profile`

3. Send one document-generation request with a real payload

4. Add optional delivery integrations only after local generation works


Installation

bash
npm install -g @getpopapi/pop-mcp

From Source

bash
git clone https://github.com/getpopapi/pop-mcp
cd pop-mcp
npm install
npm run build

Configuration

Set your POP license key as an environment variable:

bash
export POP_API_KEY=your_license_key_here

Optional — use the staging environment:

bash
export POP_ENVIRONMENT=staging

Claude Desktop Setup

Add to your `claude_desktop_config.json`:

If installed from npm:

json
{
  "mcpServers": {
    "pop": {
      "command": "pop-mcp",
      "env": {
        "POP_API_KEY": "your_license_key_here"
      }
    }
  }
}

If running from source:

json
{
  "mcpServers": {
    "pop": {
      "command": "node",
      "args": ["/path/to/pop-mcp/dist/cli.js"],
      "env": {
        "POP_API_KEY": "your_license_key_here"
      }
    }
  }
}

Config file locations:

  • macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
  • Windows: `%APPDATA%\Claude\claude_desktop_config.json`
  • Linux: `~/.config/Claude/claude_desktop_config.json`

Tool Reference

The `license_key` is always injected automatically from `POP_API_KEY` — never pass it manually.

`pop_create_sdi_invoice`

Generate an Italian FatturaPA XML document. Optionally submit it to the SdI (Sistema di Interscambio).

MCP inputs:

ParameterTypeRequiredDescription
`data`objectFull invoice data (see Invoice Data Structure)
`submit_to_sdi`booleanSet `true` to submit to SdI. Requires Basic+ plan with active SdI integration. Default: `false`
`integration`objectOverride integration config. Overrides `submit_to_sdi` if set.
`environment`stringTarget environment (e.g. `"sandbox"`)

Integration options for `integration.use`:

  • `"sdi-via-pop"` or `"sdi"` — Submit via POP SdI
  • `"pop-to-webhook"` — Deliver to a webhook (requires `id`)
  • `"fatture-in-cloud"` — Deliver to Fatture in Cloud

API payload sent:

json
{
  "license_key": "YOUR_LICENSE_KEY",
  "user_agent": "pop-mcp",
  "user_agent_version": "1.0.0",
  "data": { "...invoice fields..." },
  "integration": { "use": "sdi-via-pop", "action": "create" }
}

> `integration` is omitted when `submit_to_sdi` is `false` and no override is provided (XML-only generation).


`pop_create_peppol_invoice`

Generate a Peppol UBL 2.1 document. Optionally submit it to the Peppol network.

MCP inputs:

ParameterTypeRequiredDescription
`data`objectFull invoice data. `customer_type` must be `"company"` or `"freelance"`
`submit_to_peppol`booleanSet `true` to submit to the Peppol network. Requires Basic+ plan. Default: `false`
`integration`objectOverride integration config
`environment`stringTarget environment

Integration options for `integration.use`:

  • `"peppol-via-pop"` or `"peppol"` — Submit via POP Peppol
  • `"pop-to-webhook"` — Deliver to a webhook (requires `id`)

API payload sent:

json
{
  "license_key": "YOUR_LICENSE_KEY",
  "user_agent": "pop-mcp",
  "user_agent_version": "1.0.0",
  "data": { "...invoice fields..." },
  "integration": { "use": "peppol-via-pop", "action": "create" }
}

`pop_create_pdf_invoice`

Generate a branded PDF invoice. Optionally email it to up to 3 recipients.

MCP inputs:

ParameterTypeRequiredDescription
`data`objectInvoice data. Must include `data.pdf` for PDF-specific settings
`send_email`booleanSet `true` to email the PDF (requires `data.pdf.email_invoice`, Basic+ plan). Default: `false`
`environment`stringTarget environment

`data.pdf` fields:

FieldDescription
`doc_type_title`Title shown on document (e.g. `"Invoice"`, `"Receipt"`)
`logo_url`Company logo URL (HTTPS)
`head.store_info_address`Supplier address string in header
`head.billing[]`Customer billing address array
`head.shipping[]`Shipping address array (optional)
`email_invoice.to`Up to 3 recipient email addresses
`email_invoice.from`Reply-to address
`footer_text`Custom footer message
`total_tax`Total tax amount as string

API payload sent:

json
{
  "license_key": "YOUR_LICENSE_KEY",
  "user_agent": "pop-mcp",
  "user_agent_version": "1.0.0",
  "data": {
    "...invoice fields...",
    "pdf": {
      "doc_type_title": "Invoice",
      "logo_url": "https://example.com/logo.png",
      "head": { "store_info_address": "Via Roma 1, 00100 Roma IT", "billing": [] },
      "total_tax": "22.00",
      "email_invoice": { "to": ["customer@example.com"] }
    }
  }
}

`pop_create_ksef_invoice`

Generate a Polish KSeF FA(3) XML invoice or credit note. Optionally submit it through a configured KSeF provider integration.

MCP inputs:

ParameterTypeRequiredDescription
`data`objectFull invoice data for KSeF FA(3) generation
`integration`objectOptional KSeF provider submission config: `{ use: "ksef" \"ksef-via-pop", action }`
`environment`stringTarget environment (e.g. `"sandbox"`)

Domain rules specific to KSeF:

  • Poland only — `transfer_lender.personal_data.tax_id_vat.country_id` must be `"PL"` with a 10-digit NIP as `id_code`
  • `customer_type` must be `"company"` or `"freelance"` (no private individuals)
  • `nature` is always required at the top level for KSeF (unlike SdI/Peppol, where it's only required at 0% VAT) — reuses the same SdI nature codes (`N1`, `N2.1`, `N2.2`, `N3.1`, `N3.2`, `N4`, ...) to derive KSeF's internal fiscal variant
  • `transmitter_data` is not used (SdI-only concept)
  • `payment_data.payment_details` only accepts `MP01`, `MP02`/`MP03`, `MP05`, `MP08` — other payment method codes are rejected at generation time
  • Base XML generation is available on any plan; provider submission via `integration.use: "ksef"` requires a Basic+ plan and the supplier already enrolled as a KSeF legal entity in the POP dashboard

API payload sent:

json
{
  "license_key": "YOUR_LICENSE_KEY",
  "user_agent": "pop-mcp",
  "user_agent_version": "1.0.0",
  "data": { "...invoice fields...", "nature": "N1" },
  "integration": { "use": "ksef", "action": "create" }
}

> `integration` is omitted entirely for local XML-only generation (no provider submission).

Returns: raw FA(3) XML (`application/xml`) for local generation, or JSON (with a UUID) when submitted through a provider integration.


`pop_create_zugferd_invoice`

Generate a ZUGFeRD/Factur-X document package: a visual PDF, an EN16931 CII XML, and a hybrid PDF/A-3 with the XML embedded.

MCP inputs:

ParameterTypeRequiredDescription
`data`objectFull invoice data for ZUGFeRD/Factur-X generation
`environment`stringTarget environment (e.g. `"sandbox"`)

This tool has no `integration` parameter — ZUGFeRD generation is local only, with no submit/delivery step.

API payload sent:

json
{
  "license_key": "YOUR_LICENSE_KEY",
  "user_agent": "pop-mcp",
  "user_agent_version": "1.0.0",
  "data": { "...invoice fields..." }
}

Returns: JSON with generation metadata and three Base64-encoded attachments:

json
{
  "success": true,
  "data": {
    "valid": true,
    "profile": "EN16931",
    "attachments": {
      "pdf": { "filename": "...", "mime": "application/pdf", "content_base64": "..." },
      "xml": { "filename": "...", "mime": "application/xml", "content_base64": "..." },
      "hybrid_pdf": { "filename": "...", "mime": "application/pdf", "content_base64": "..." }
    },
    "validation": { "...": "..." },
    "errors": [],
    "warnings": []
  }
}

`pop_get_invoice_status`

Retrieve the SdI processing status and notifications for a submitted invoice.

MCP inputs:

ParameterTypeRequiredDescription
`uuid`string (UUID)Invoice UUID returned by `pop_create_sdi_invoice` when `submit_to_sdi=true`
`response_format``"markdown"` \`"json"`Output format. Default: `"markdown"`
`environment`stringTarget environment

API payload sent:

json
{
  "license_key": "YOUR_LICENSE_KEY",
  "integration": { "uuid": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" }
}

SdI notification statuses: `pending` · `accepted` · `rejected` · `delivery`

> SdI processing is asynchronous and can take minutes to hours. Retry if no notifications are returned yet.


`pop_get_peppol_document`

Retrieve a Peppol document from the network by UUID.

MCP inputs:

ParameterTypeRequiredDescription
`uuid`string (UUID)Peppol document UUID from `pop_create_peppol_invoice`
`zone`string (2 chars)Country code of the Peppol access point (e.g. `"BE"` for Belgium). Required for some regions.
`response_format``"markdown"` \`"json"`Output format. Default: `"markdown"`
`environment`stringTarget environment

API payload sent:

json
{
  "license_key": "YOUR_LICENSE_KEY",
  "integration": { "uuid": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "zone": "IT" }
}

> `zone` is omitted from the payload if not provided.


`pop_get_sdi_document`

Retrieve an archived SdI (FatturaPA) document from POP storage by UUID.

MCP inputs:

ParameterTypeRequiredDescription
`uuid`string (UUID)SdI document UUID
`response_format``"markdown"` \`"json"`Output format. Default: `"markdown"`
`environment`stringTarget environment

API payload sent:

json
{
  "license_key": "YOUR_LICENSE_KEY",
  "integration": { "uuid": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" }
}

Requires: Basic+ plan with active SdI integration.


`pop_verify_sdi_document`

Validate an SdI XML document for compliance before submission. Does not submit the document.

MCP inputs:

ParameterTypeRequiredDescription
`xml_base64`stringThe SdI XML document encoded as a Base64 string
`environment`stringTarget environment

API payload sent:

json
{
  "license_key": "YOUR_LICENSE_KEY",
  "skip_business_check": true,
  "integration": { "xml": "" }
}

Validation checks performed: XML schema conformance · fiscal code format · VAT number validity · required field presence · amount consistency

Requires: Basic+ plan with active SdI integration and registered business.


`pop_preserve_document`

Archive an SdI document in certified long-term digital storage (conservazione sostitutiva). Italian law requires invoices to be preserved for 10 years.

MCP inputs:

ParameterTypeRequiredDescription
`uuid`string (UUID)UUID of the SdI document to archive
`environment`stringTarget environment

API payload sent:

json
{
  "license_key": "YOUR_LICENSE_KEY",
  "integration": { "uuid": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" }
}

> Important: Only call this tool when `pop_get_invoice_status` returns status `RC` (Ricevuta di Consegna) or `MC` (Mancata Consegna). Do not call for statuses `NS`, `EC`, `SE`, or `DT`.

Requires: Basic+ plan with active SdI integration.


Usage Examples

Generate a Simple Italian Invoice (XML Only)

Ask your AI assistant:

> "Create a FatturaPA invoice for 1000€ + 22% VAT to Rossi SRL (VAT IT12345678901, Milan). My company is Bianchi SRL (VAT IT98765432109, Rome), using payment method bank transfer to IBAN IT60X0542811101000000123456."

Submit Invoice to SdI

> "Create and submit to SdI an invoice #45 for consulting services, 500€ + 22% VAT to customer Mario Rossi (fiscal code RSSMRA80A01H501U) in Rome."

Check Invoice Status After Submission

> "What's the status of SdI invoice with UUID abc123-def456-...?"

Generate PDF with Email Delivery

> "Create a PDF invoice for order #123 and email it to customer@example.com."

Verify SdI Document Before Sending

> "Verify SdI document with UUID abc123-... for compliance before submission."


Plan Requirements

FeatureFreeBasic/GrowthPro
XML generation (local)
PDF generation
SdI submission
Peppol submission
PDF email delivery
SdI document verification
Document preservation

Testing

MCP Inspector (Interactive)

bash
npm run inspector
# or
npx @modelcontextprotocol/inspector dist/cli.js

Quick Smoke Test

bash
POP_API_KEY=your_key node -e "
import('./dist/cli.js').catch(e => {
  if (e.message.includes('stdin')) process.exit(0);
  console.error(e); process.exit(1);
});
"

Test Tool Schema Listing

bash
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' | POP_API_KEY=test node dist/cli.js

Development

bash
# Run with auto-reload
npm run dev

# Build
npm run build

# Clean build artifacts
npm run clean

Invoice Data Structure

The `data` parameter for invoice creation follows the FatturaPA structure:

code
data
├── id                    Invoice/order ID (numeric)
├── filename              Output filename without extension (e.g. 'IT99900088876_00009')
├── type                  "invoice" | "credit_note"
├── version               "FPR12" | "FPA12"
├── sdi_type              7-char SDI code ('0000000' for private individuals)
├── customer_type         "private" | "company" | "freelance" | "pa"
├── nature                VAT exemption code (required when rate is 0%, e.g. 'N2.1', 'N6.1')
├── transmitter_data
│   ├── transmitter_id    { country_id, id_code }
│   ├── progressive       Transmission progressive ID (e.g. '00001')
│   ├── transmitter_format  "FPR12" | "FPA12"
│   ├── sdi_code          7-char code
│   ├── transmitter_contact { phone, email }
│   └── recipient_pec     PEC email (alternative to sdi_code)
├── transfer_lender       Supplier/seller
│   ├── personal_data     { tax_id_vat: { country_id, id_code, tax_regime }, company_name }
│   ├── place             { address, zip_code, city, province_id, country_id }
│   └── contact           { phone, email }
├── transferee_client     Customer/buyer
│   ├── personal_data     { tax_id_vat, tax_id_code (fiscal code for IT private), company_name }
│   └── place             { address, zip_code, city, province_id, country_id }
├── invoice_body
│   ├── general_data      { doc_type (TD01|TD04), date (YYYY-MM-DD), invoice_number, currency }
│   └── total_document_amount
├── order_items[]
│   ├── description, quantity, unit
│   ├── unit_price, total_price
│   ├── rate              VAT rate as string (e.g. '22.00')
│   ├── total_tax         VAT amount (number)
│   └── item_type         "product" | "shipping" | "fee"
├── payment_data
│   ├── terms_payment     TP01 (instalment) | TP02 (full) | TP03 (advance)
│   ├── payment_details   MP01 (Cash) | MP02 (Check) | MP05 (Bank Transfer) | MP08 (Credit Card) | ...
│   ├── payment_amount
│   ├── beneficiary       Required for MP05 (bank transfer)
│   ├── financial_institution  Required for MP05
│   └── iban              Required for MP05
├── purchase_order_data   (optional) { id, date }
├── connected_invoice_data[]  (required for credit notes) { id, date }
├── overrides             (optional) { language, bollo_force_apply }
└── pdf                   (only for pop_create_pdf_invoice)
    ├── doc_type_title
    ├── logo_url
    ├── head              { store_info_address, billing[], shipping[] }
    ├── total_tax
    ├── email_invoice     { to[] (max 3), from }
    └── footer_text

Error Reference

Error CodeMeaningSolution
`unauthorized_user`Invalid license keyCheck `POP_API_KEY`
`insufficient_level`Plan too lowUpgrade POP plan
`business_not_registered`No business profileRegister on popapi.io
`integration_inactive`SdI/Peppol not enabledActivate on popapi.io
`pop_api_email_limit`>3 email recipientsReduce to max 3
`pop_api_email_not_allowed`Plan doesn't allow emailUpgrade to Basic+


License

MIT © getpopapi

Frequently asked questions

What is pop-mcp?

pop-mcp is POP | Electronic Invoicing for Europe

How do I install pop-mcp?

Open the GitHub repository and follow its README. Most MCP servers are added to your client's MCP config, then called by your agent.

Is pop-mcp open source?

Yes — it is hosted on GitHub at https://github.com/getpopapi/pop-mcp.

Related MCP tools

Run your own MCP server? See who uses it and what to fix.

Measure it with TrackMCP