InvoiceXML
Cumplimiento global de facturación electrónica: Factur-X, Peppol UBL, CII y más
Documentación
InvoiceXML MCP Server
Un servidor de Model Context Protocol que expone la API de InvoiceXML a agentes de IA. Cubre Factur-X, ZUGFeRD, XRechnung, UBL / CII y Peppol BIS Billing 3.0.
El mismo código base se ejecuta en dos formas de despliegue, seleccionadas al inicio mediante una variable de entorno:
| Modo | Quién lo ejecuta | Autenticación |
|---|---|---|
| Autohospedado | Tú, en tu propia máquina o servidor | Una única clave de API en env o appsettings.json |
| Hospedado | InvoiceXML, en su propia infraestructura | OAuth 2.1 + Registro dinámico de clientes contra invoicexml.com |
Ambos ejecutan el mismo binario; solo difiere la configuración. El repositorio es independiente de la plataforma: no sabe nada sobre dónde ni cómo lo alojas.
Arquitectura
+----------------------+ ProjectReference +----------------------+
| InvoiceXml.Mcp.Core | -------------------> | InvoiceXml.Mcp.Host |
| (SDK: client+tools) | | (the deployable) |
+----------------------+ +----------------------+
InvoiceXml.Mcp.Core es un SDK pequeño e independiente del transporte:
IInvoiceXmlClient— cliente tipado sobre la API REST públicaHttpInvoiceXmlClient— la única implementación; consume unHttpClientdeIHttpClientFactoryInvoiceXmlClientOptions— URL base, tiempo de espera (sin autenticación)AddInvoiceXmlMcpCore(IServiceCollection, IConfiguration)— punto de entrada de DI; devuelve elIHttpClientBuilderpara que el host adjunte la autenticación comoDelegatingHandler
El SDK nunca ve credenciales. El host las aplica a través de la canalización HTTP. Esa costura es lo que permite que un solo código base sirva para ambos modos de despliegue.
InvoiceXml.Mcp.Host es una aplicación ASP.NET Core 10:
- Lee
Mcp:AuthMode(ApiKeyoOAuth) al inicio - Conecta el
DelegatingHandlercorrespondiente al cliente HTTP de Core medianteAddHostAuth(...) - Sirve el endpoint MCP en
POST /, una página de bienvenida amigable enGET /y/health
Añadir un nuevo modo de autenticación = una rama en AuthExtensions.cs más una pequeña carpeta en Auth/<Mode>/. Añadir una nueva herramienta = una clase [McpServerTool]. Nada más cambia.
Estructura del repositorio
invoicexml-mcp/
├── src/
│ ├── InvoiceXml.Mcp.Core/ # the SDK: client, models, tools
│ │ ├── Enums/ Interfaces/ Models/ Options/ Services/ Tools/ Extensions/
│ └── InvoiceXml.Mcp.Host/ # the deployable host
│ ├── Auth/{ApiKey,OAuth}/ # the two auth modes
│ ├── Configuration/
│ ├── Program.cs
│ └── appsettings.json # safe defaults, no secrets
├── tests/
│ ├── InvoiceXml.Mcp.Core.Tests/
│ └── InvoiceXml.Mcp.Host.Tests/
├── Directory.Build.props # repo-wide MSBuild defaults
├── Directory.Packages.props # Central Package Management
├── global.json # pins the .NET SDK
└── InvoiceXml.Mcp.slnx
Ejecución local
Necesitas un SDK de .NET 10 y una clave de API de InvoiceXML.
# 1. Provide your API key (pick one):
# A. dotnet user-secrets (recommended — kept outside the repo)
dotnet user-secrets --project src/InvoiceXml.Mcp.Host set "Mcp:ApiKey:Value" "your-key"
# B. environment variable
$env:INVOICEXML_API_KEY = "your-key"
# 2. Run
dotnet run --project src/InvoiceXml.Mcp.Host
GET http://localhost:5004/ muestra una página de bienvenida en el navegador; el endpoint MCP es POST http://localhost:5004/; GET /health devuelve { "status": "ok" }.
Configuración
{
// Required in OAuth mode. The public origin where this MCP server is reachable.
// Used in the protected-resource metadata response.
"McpUri": "https://mcp.example.com",
"InvoiceXml": {
"BaseUrl": "https://api.invoicexml.com", // override for staging / local
"Timeout": "00:01:40"
},
"Mcp": {
"AuthMode": "ApiKey", // "ApiKey" | "OAuth"
"ApiKey": {
"Value": "" // ApiKey mode: NEVER commit a real key
},
"OAuth": {
"AuthorizationServer": "https://invoicexml.com",
"ScopesSupported": [ "api_token.read" ]
},
"FileInput": { // limits for the URL-fetch input mode
"MaxFileSizeBytes": 5242880,
"FetchTimeout": "00:00:30"
}
}
}
Equivalentes de variables de entorno (doble guion bajo = anidación):
| Variable | Se asigna a |
|---|---|
INVOICEXML_API_KEY | Mcp:ApiKey:Value (alias amigable) |
Mcp__ApiKey__Value | Mcp:ApiKey:Value |
Mcp__AuthMode | Mcp:AuthMode (ApiKey o OAuth) |
Mcp__OAuth__AuthorizationServer | Mcp:OAuth:AuthorizationServer |
McpUri | McpUri (nivel raíz) |
InvoiceXml__BaseUrl | InvoiceXml:BaseUrl |
Modo OAuth
Cuando Mcp:AuthMode=OAuth, el host deja de aceptar una clave de API estática y en su lugar:
- Devuelve 401 con
WWW-Authenticate: Bearer resource_metadata="…"para cualquierPOST /que no tenga token Bearer. - Sirve
GET /.well-known/oauth-protected-resourceapuntando a los clientes MCP haciainvoicexml.comcomo servidor de autorización. - Reenvía el token Bearer entrante tal cual en cada llamada saliente a la API de InvoiceXML (la API es la fuente de verdad para la validez del token; el servidor MCP no valida tokens localmente).
La secuencia que realiza un cliente MCP:
client → MCP POST / → 401 + resource_metadata
client → /.well-known/oauth-protected-resource → { authorization_servers: [invoicexml.com] }
client → invoicexml.com/.well-known/oauth-authorization-server
→ { authorize, token, register endpoints }
client → invoicexml.com/oauth/register → client_id + client_secret (DCR)
client → invoicexml.com/oauth/authorize → user consents, gets code
client → invoicexml.com/oauth/token → access_token (= user's API key)
client → MCP POST / + Authorization: Bearer → 200, tool call flows through
Despliegue
El host es una aplicación ASP.NET Core estándar: ejecútala como ejecutes servicios .NET (systemd, un contenedor, un PaaS, etc.; el repositorio no prescribe uno):
dotnet publish src/InvoiceXml.Mcp.Host -c Release -o ./publish
# then run ./publish/InvoiceXml.Mcp.Host on your host
Configura mediante variables de entorno en el host (nunca confirmes secretos):
ASPNETCORE_ENVIRONMENT=ProductionMcp__AuthMode=ApiKey(oOAuth)Mcp__ApiKey__Value=…/INVOICEXML_API_KEY=…(modo ApiKey)McpUri=https://your-public-urlyMcp__OAuth__AuthorizationServer=https://invoicexml.com(modo OAuth)
Termina TLS en tu proxy inverso / balanceador de carga y reenvía al puerto HTTP del host. El servidor no tiene estado, por lo que puedes ejecutar varias instancias detrás de un balanceador de carga.
Licencia
MIT — consulta LICENSE.