
Security News
Lovable’s OJ Rewrites Vite’s Dev Server in Rust as AI Lowers the Cost of Forking Open Source
Lovable’s OJ rewrites Vite’s dev server in Rust, reducing memory use and preview times as AI lowers the cost of open source reimplementation.
@kontor-mcp/server
Advanced tools
Kontor MCP server — sovereign e-invoice tools for AI agents over stdio and Streamable HTTP
Sovereign MCP server for German/EU e-invoices (XRechnung, ZUGFeRD/Factur-X, EN 16931): parse, validate and explain — 100 % offline, no Java, no network.
| Tool | Purpose |
|---|---|
parse_invoice | Detect format (UBL/CII · EN 16931 · XRechnung version/variant · ZUGFeRD profile) and return the EN 16931 semantic model |
validate_invoice | XSD + official EN 16931 / XRechnung Schematron with the KoSIT scenario model → valid / valid_with_warnings / invalid, findings with DE/EN explanations and fix hints |
audit_invoice | One call for AP: parse + validate + Kontor plausibility (totals recomputed, VAT rates, IBAN, Leitweg-ID check digits, dates, known_invoice_numbers duplicates) → header facts, VAT breakdown, verdict, grouped findings, accept / review / reject with rationale |
generate_invoice | Structured data → compliant XRechnung 3.0 (UBL) or, with target: zugferd-pdf, a ZUGFeRD 2.3 / Factur-X PDF/A-3 (zugferd_profile EN16931 / BASIC / EXTENDED, embedded factur-x.xml, veraPDF- and Mustang-verified): decimal-safe amounts/VAT/totals, internal validation (fail-honest valid — for PDFs the XML is read back out of the file first), deterministic auto-fixes reported, optional output_path (.xml / .pdf, never overwrites unless overwrite=true), otherwise pdf_base64 |
convert_invoice | extract-xml (ZUGFeRD PDF → XML), xrechnung-ubl / cii via the semantic model with post-validation and an honest lossReport, html-preview (self-contained HTML, no scripts/assets); optional output_path |
check_obligations | Offline decision tree over the German mandate (§ 14 / § 27 Abs. 38 UStG, UStDV §§ 33/34/34a, E-RechV): issuer/receiver × B2B/B2G/B2C, transition 2026 → 2027 (€800k) → 2028, exemptions, formats, Leitweg-ID — with primary sources, lastVerified and a non-advice disclaimer |
list_capabilities | Introspection: formats/profiles, bundled standard versions, KB stats, code lists, legal lastVerified, tools/resources/prompts, sovereignty statement |
explain_rule | Explain a rule id such as BR-DE-15 (official text, explanation, affected BTs, fix hint); unknown ids get suggestions |
Every document tool accepts either file_path (absolute; .xml/.pdf; ≤ 20 MB, KONTOR_MAX_FILE_MB) or content_base64 (+ optional content_type), and lang: "de" | "en" (default de).
Resources: kontor://samples/{name} — bundled sample invoices (valid-xrechnung-ubl.xml, valid-xrechnung-cii.xml, broken-missing-buyer-reference.xml, valid-zugferd-en16931.pdf, generated-zugferd-en16931.pdf).
claude_desktop_config.json (Settings → Developer → Edit Config):
{
"mcpServers": {
"kontor": {
"command": "npx",
"args": ["-y", "@kontor-mcp/server"]
}
}
}
From a local checkout (before the npm publish):
{
"mcpServers": {
"kontor": {
"command": "node",
"args": ["/absolute/path/to/kontor-mcp/packages/server/dist/bin.js"]
}
}
}
Use an absolute path to node (which node) if Desktop cannot find it — it launches servers with a minimal PATH. Quit Desktop fully (⌘Q) and reopen; the config is read at launch. Logs: ~/Library/Logs/Claude/mcp-server-kontor.log.
Restart Claude Desktop, attach an invoice (or + → Add from kontor → broken-missing-buyer-reference.xml) and ask "Ist diese Rechnung gültig?".
All tools are offline and stateless; all except generate_invoice / convert_invoice (which may write a file when output_path is given) are read-only (readOnlyHint), so it is safe to set them to Always allow under Settings → Connectors → kontor; on first use Desktop shows a "Needs approval" prompt otherwise.
PDFs: Desktop does not hand attached PDF bytes to the server, so reference ZUGFeRD/Factur-X PDFs by local path instead: "Was steht in dieser Rechnung? /path/to/invoice.pdf". XML attachments work either way (the model re-sends them as content_base64).
claude mcp add kontor -- node /absolute/path/to/kontor-mcp/packages/server/dist/bin.js
npx @modelcontextprotocol/inspector@latest node packages/server/dist/bin.js
# or headless:
npx @modelcontextprotocol/inspector@latest --cli node packages/server/dist/bin.js --method tools/list
The same server over HTTP (MCP Streamable HTTP, endpoint /mcp) for remote agents, Docker and clients that cannot hand attachment bytes to a stdio server:
KONTOR_TRANSPORT=http KONTOR_AUTH_TOKEN="$(openssl rand -hex 24)" node packages/server/dist/bin.js
# → [kontor-mcp] kontor-mcp 0.9.0 listening on http://127.0.0.1:3333/mcp (auth: bearer, origins: localhost)
npx @modelcontextprotocol/inspector@latest --cli http://127.0.0.1:3333/mcp --transport http \
--header "Authorization: Bearer $KONTOR_AUTH_TOKEN" --method tools/list
| Variable | Default | Meaning |
|---|---|---|
KONTOR_TRANSPORT | stdio | stdio or http |
KONTOR_PORT | 3333 | TCP port (0 = ephemeral) |
KONTOR_BIND | 127.0.0.1 | Bind address. Loopback (127.0.0.1, localhost, ::1) enables Host-header / DNS-rebinding protection |
KONTOR_AUTH_TOKEN | — | Bearer token (≥ 16 chars), compared in constant time. Required in HTTP mode |
KONTOR_ALLOW_NO_AUTH | — | 1 runs without a token — only honoured on a loopback bind (local experiments) |
KONTOR_ALLOWED_ORIGINS | — | Comma-separated browser origins allowed in addition to `http(s)://localhost |
KONTOR_ALLOWED_HOSTS | — | Comma-separated hostnames accepted in the Host header besides loopback (behind a reverse proxy / in a container). On a loopback bind only loopback hosts pass; on 0.0.0.0 without this list the Host header is not checked and the token is the guard |
KONTOR_MAX_SESSIONS | 100 | Concurrent MCP sessions; beyond it new initialize requests get 503 + Retry-After |
KONTOR_SESSION_IDLE_MINUTES | 30 | Sessions without a request for this long are closed (clients that never DELETE) |
KONTOR_MAX_FILE_MB | 20 | Also sizes the JSON body cap (content_base64 inflates by 4/3) |
Behaviour: one MCP session per client (Mcp-Session-Id, UUID), DELETE /mcp ends it, unknown ids → 404; GET /healthz (unauthenticated) returns { ok, name, version, sessions } for container health checks; SIGINT/SIGTERM close all sessions, then the listener. Wrong or missing token → 401 with WWW-Authenticate: Bearer. There is no TLS in the server — terminate it in your reverse proxy (Caddy, nginx, Traefik) and forward to the loopback port; see SECURITY.md.
The image (Dockerfile at the repo root; multi-stage, node:22-alpine, runs as node, ~70 MB, linux/amd64 + linux/arm64) defaults to KONTOR_TRANSPORT=http, KONTOR_BIND=0.0.0.0, port 3333 and refuses to start without KONTOR_AUTH_TOKEN. A HEALTHCHECK polls /healthz. The samples ship at /app/samples/; mount your own invoices read-only (-v ./invoices:/data:ro) and reference them as /data/<file>.
docker build -t kontor-mcp .
docker run -d --name kontor -p 127.0.0.1:3333:3333 -e KONTOR_AUTH_TOKEN="$(openssl rand -hex 24)" -v "$PWD/invoices:/data:ro" kontor-mcp
docker run -i --rm -e KONTOR_TRANSPORT=stdio kontor-mcp # stdio inside a container also works
docker-compose.yml is a hardened example (loopback-published port, read_only, cap_drop: ALL, no-new-privileges, token from .env). CI builds both platforms and runs an Inspector-over-HTTP smoke test against the image on every push.
Stateless; nothing is stored or transmitted; invoice contents are never logged (see PRD NFR-2/NFR-5/NFR-6). Findings are formal/technical checks, not tax or legal advice.
| URI / name | What |
|---|---|
kontor://samples/{name} | Sample invoices (UBL, CII, ZUGFeRD PDF, one broken) |
kontor://reference/rules | Rule knowledge-base index (all EN 16931 / XRechnung rule ids, severity, curated flag) |
kontor://reference/codelists/{list} | units, vat-categories, payment-means, eas, vatex, invoice-types, currencies, countries, allowance-reasons, charge-reasons, identifier-schemes, mime-types, vat-point-date-codes — official code values with DE/EN names for the common ones |
kontor://reference/cheatsheet | One-page EN 16931 / XRechnung / ZUGFeRD orientation incl. the German mandate timeline (Markdown) |
prompt audit-incoming-invoice | Run audit_invoice and present a decision-ready AP summary |
prompt draft-supplier-rejection | Draft (never send) a German rejection e-mail citing the concrete rule violations |
prompt create-invoice-interview | Interview for the minimal XRechnung field set, then generate_invoice |
FAQs
Kontor MCP server — sovereign e-invoice tools for AI agents over stdio and Streamable HTTP
The npm package @kontor-mcp/server receives a total of 20 weekly downloads. As such, @kontor-mcp/server popularity was classified as not popular.
We found that @kontor-mcp/server demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Security News
Lovable’s OJ rewrites Vite’s dev server in Rust, reducing memory use and preview times as AI lowers the cost of open source reimplementation.

Security News
It has been one year since Shai-Hulud made its first appearance on npm.

Research
/Security News
Operators behind PolinRider used a compromised GitHub account to plant malware in four development versions of a Packagist package with 700,000+ downloads.