Are you the author? Sign in to claim
Model Context Protocol (MCP) server for ELSTER (German tax portal). Submit UStVA, prepare EUER/ESt, sync inbox + history
A Model Context Protocol (MCP) server that lets Claude (or any MCP-capable client) drive the German tax portal ELSTER via Puppeteer.
English
Deutsch
Practical safeguards built into the tool
elster_ustva_confirm — it requires an explicit second call after elster_ustva_start has paused at AWAITING_CONFIRM. Nothing is sent without that second confirmation.| Tool | What it does | Submits? |
|---|---|---|
elster_login_test | Verifies your certificate + password can log in | No |
elster_config_show | Shows the loaded config (secrets redacted) | No |
elster_kennziffern_list | Returns the supported UStVA Kennziffern with descriptions | No |
elster_ustva_generate_xml | Generates a UStVA XML snapshot (archive only) | No |
elster_ustva_detect_reverse_charge | Detects §13b reverse-charge suppliers | No |
elster_ustva_start | Logs in, fills, runs Prüfung, then pauses for confirmation | Pauses |
elster_ustva_confirm | Clicks "Absenden" after you reviewed | Yes |
elster_eur_start | Fills Anlage EÜR up to Prüfung, then "Speichern und Verlassen" | No |
elster_est_start | Opens ESt 1 A, fills basics, runs Prüfung, keeps browser open 30 min | No |
elster_sync_history | Reads "Übermittelte Formulare" (optionally with PDFs) | No |
elster_sync_inbox | Reads ELSTER inbox (optionally with PDFs) | No |
elster_session_status / _list / _cancel | Session management | No |
.pfx) — get it from https://www.elster.de → "Mein ELSTER" → "Mein Benutzerkonto" → "Zertifikat verlängern"git clone https://github.com/YOUR_USERNAME/elster-mcp-server.git
cd elster-mcp-server
npm install
npm run build
Puppeteer will install a bundled Chromium on first install (~150 MB).
cp config.example.json config.json
$EDITOR config.json
All keys in config.json can be overridden by environment variables
(ELSTER_PFX_PATH, ELSTER_PASSWORD, ELSTER_TAX_NUMBER,
ELSTER_STATE_CODE, ELSTER_NAME, ELSTER_FIRST_NAME, ELSTER_STREET,
ELSTER_HOUSE_NUMBER, ELSTER_ZIP, ELSTER_CITY, ELSTER_COUNTRY,
ELSTER_DOWNLOAD_DIR, ELSTER_SCREENSHOT_DIR, ELSTER_HEADLESS,
ELSTER_EST_SKIP_EUR). Env vars win over the file.
You can also point the loader at a different config file via
ELSTER_CONFIG_PATH=/path/to/your/config.json.
The two-digit stateCode for your Finanzamt is published by ELSTER —
look up the current value in the official ELSTER documentation.
Add your §13b UStG suppliers under ustva.reverseChargeSuppliers in
config.json. Patterns are case-insensitive regexes matched against the
voucher's contactName or description. Example entry:
{ "pattern": "your-supplier\\s+ireland", "region": "EU", "name": "Your Supplier Ireland" }
Add to ~/Library/Application Support/Claude/claude_desktop_config.json
(macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):
{
"mcpServers": {
"elster": {
"command": "node",
"args": ["/absolute/path/to/elster-mcp-server/dist/index.js"],
"env": {
"ELSTER_CONFIG_PATH": "/absolute/path/to/elster-mcp-server/config.json"
}
}
}
}
See examples/claude_desktop_config.json for the template.
Run the server in stdio mode:
node dist/index.js
Then connect via your client's MCP transport.
1. elster_login_test → { ok: true }
2. elster_kennziffern_list → reference for valid codes
3. elster_ustva_start({ → { sessionId: "ustva-..." }
year: 2026,
period: "Q1",
report: { "81": 12000, "86": 300, "66": 1845.30 }
})
4. elster_session_status({ sessionId }) → poll until status == AWAITING_CONFIRM
(open the screenshot at screenshotPath to verify)
5. elster_ustva_confirm({ sessionId }) → { success: true, ticket: "..." }
1. elster_login_test
2. elster_eur_start({
year: 2025,
data: {
betriebseinnahmen: 50000,
fahrzeugkosten: 1200,
afa: 800,
homeOffice: 1260
}
})
3. elster_session_status (poll until SAVED or AWAITING_REVIEW)
4. open the ELSTER portal in your browser → "Meine Formulare" → review the draft → submit manually
.env, config.json, or .pfx. They are gitignored by default.ELSTER_HEADLESS=false once to watch the first run and confirm everything is wired correctly.ELSTER_HEADLESS=false
and check the screenshots written to ./screenshots/.PRs welcome. The most useful additions are:
report schema validator for elster_ustva_*When opening an issue, please run with ELSTER_HEADLESS=false and attach the
screenshot under ./screenshots/ that shows the failure.
Run Claude Code as an MCP server so any agent can delegate coding tasks to it
Browser automation using accessibility snapshots instead of screenshots
Google's universal MCP server supporting PostgreSQL, MySQL, MongoDB, Redis, and 10+ databases
Official GitHub integration for repos, issues, PRs, and CI/CD workflows