POHODA MCP Server
MCP server for POHODA (Stormware) accounting software. Manage invoices, stock, orders, bank documents, warehouse, and accounting from any MCP-compatible client.
48 tools covering all major POHODA agendas via mServer XML API, including PDF printing and a raw XML escape hatch. Every tool's XML is checked against Stormware's official XSD schema.
Requirements
- Node.js 22+
- POHODA with mServer enabled and running
- mServer user credentials with XML communication rights
Installation
git clone https://github.com/hlebtkachenko/pohoda-mcp.git
cd pohoda-mcp
npm ci
npm run build
Configuration
Cursor
~/.cursor/mcp.json
{
"mcpServers": {
"pohoda": {
"command": "node",
"args": ["/path/to/pohoda-mcp/dist/index.js"],
"env": {
"POHODA_URL": "http://localhost:444",
"POHODA_USERNAME": "<your-username>",
"POHODA_PASSWORD": "<your-password>",
"POHODA_ICO": "<your-company-ico>"
}
}
}
}
Claude Desktop
claude_desktop_config.json (location)
{
"mcpServers": {
"pohoda": {
"command": "node",
"args": ["/path/to/pohoda-mcp/dist/index.js"],
"env": {
"POHODA_URL": "http://localhost:444",
"POHODA_USERNAME": "<your-username>",
"POHODA_PASSWORD": "<your-password>",
"POHODA_ICO": "<your-company-ico>"
}
}
}
}
Claude Code
.mcp.json in your project root, or ~/.claude.json globally:
{
"mcpServers": {
"pohoda": {
"command": "node",
"args": ["/path/to/pohoda-mcp/dist/index.js"],
"env": {
"POHODA_URL": "http://localhost:444",
"POHODA_USERNAME": "<your-username>",
"POHODA_PASSWORD": "<your-password>",
"POHODA_ICO": "<your-company-ico>"
}
}
}
}
Any MCP client (stdio)
The server uses stdio transport. Point your MCP client to:
node /path/to/pohoda-mcp/dist/index.js
With environment variables set for authentication (see below).
Environment Variables
Read-only mode
With POHODA_READ_ONLY=true the create, update, delete, print and raw XML tools are not registered, and the client refuses to send anything but list requests. Use it to try the server against a real POHODA without risk. Any value other than true or false stops startup.
Write results
A write fails when POHODA reports an error at any level (response pack, item, document response or import detail); every error is listed with its errno, and warnings are shown on success too. When POHODA changes a value you sent (errno 603: replaced by a default, e.g. an unknown předkontace, normalised or truncated), create invoice, voucher, bank and internal document, and create or update address, start their answer with Created (ID …), but POHODA did not apply values you set: … naming each field and value; the record still exists, so the result is not an error. Fields you did not send that POHODA filled itself are listed in one POHODA filled defaults for: … line. Update and delete report "no record matched, or unconfirmed" when POHODA does not confirm the action. A write is never resent. When its answer is lost (timeout, connection dropped while reading, HTTP 5xx, or a 200 that is not a POHODA responsePack), the result says the outcome is unknown, so check with a list tool before trying again. When the connection is refused, nothing was sent and the result says Not sent: POHODA mServer is not running or not reachable at <url>; start mServer (on a remote host: scripts/mserver/pohoda-mserver start <config> <port>, see Run mServer on demand) and retry.
A list fails when the list element itself is in state error (its note is shown) and when mServer answers 200 with something other than a responsePack, so neither looks like an empty list.
Booking fields
pohoda_create_invoice, pohoda_create_voucher, pohoda_create_bank and pohoda_create_internal_doc accept optional booking fields. Every field is optional; an omitted field is not sent and POHODA applies its default. Reference fields take the POHODA abbreviation (sent as typ:ids); number series, bank accounts, cash registers, centres and activities come from pohoda_list_settings, VAT classifications from pohoda_list_vat, contracts from pohoda_list_contracts; předkontace abbreviations have no list tool, take them from POHODA.
Line items on all four accept payVAT and the item-level accounting, classificationVAT, classificationKVDPH, centre, activity and contract.
mServer autostart (Windows)
With POHODA_EXE_PATH and POHODA_CONFIG_NAME set, the server checks on the first tool call whether mServer answers, and if not runs Pohoda.exe /HTTP start "<config>" and waits up to 30 s. On shutdown it stops mServer again, but only if it started it.
Run mServer on demand (POHODA on a remote Windows host)
When POHODA runs on another Windows machine, scripts/mserver/ starts mServer there over SSH only when you need it, tunnels its port to your machine, and stops it after a set time without XML requests. Stormware advises against running mServer as a Windows service or keeping it running all the time: a running mServer blocks backups and database maintenance of that company in other POHODA windows. These scripts use Task Scheduler start and stop, as Stormware recommends. The scripts are not in the npm package; take them from this repository.
Prerequisites
- A POHODA user with rights to the XML communication.
- An mServer configuration per company, created in POHODA: Účetní jednotky → Databáze → POHODA mServer. Note each configuration's name and port.
- OpenSSH Server on the Windows host with key login, logging in as the Windows user who runs POHODA or as an administrator. Windows PowerShell 5.1 as the SSH shell works.
- That Windows user signed in on the host (a locked screen is fine): mServer starts in their desktop session, next to their own POHODA window, and shows its monitoring window there.
Install (once, on the Windows host)
-
Copy
scripts/mserver/windows/to the host. -
In an elevated Windows PowerShell, from that folder:
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass -Force .\Install-MServerTasks.ps1 -Config '<config>','<config2>' -User 'pohoda-host\<windows-user>'-Userdefaults to the current user; set it when you run the installer as a different administrator. Other options:-IdleMinutes(default 60),-PohodaExe(defaultC:\Program Files (x86)\STORMWARE\POHODA\Pohoda.exe),-LogDir(defaultC:\ProgramData\STORMWARE\POHODA\Log\HTTP).
This registers, per configuration, the tasks POHODA mServer start <config> and POHODA mServer stop <config> (running Pohoda.exe /HTTP start|stop "<config>" as that user), and one task POHODA mServer idle stop. -Config lists every configuration: running the installer again replaces all POHODA mServer * tasks with the new set. The idle script lives in C:\ProgramData\pohoda-mcp, writable only by SYSTEM and Administrators; the installer stops if that folder is a junction or owned by anyone else, since SYSTEM runs the script inside.
Use (macOS or Linux)
scripts/mserver/pohoda-mserver needs bash and ssh. Set POHODA_SSH_HOST to an ssh host alias with key login:
export POHODA_SSH_HOST=pohoda-host
scripts/mserver/pohoda-mserver start <config> <port>
scripts/mserver/pohoda-mserver status <config> <port>
scripts/mserver/pohoda-mserver stop <config> <port>
start runs the start task (unless the port already listens), waits up to 60 s for the port, and opens an ssh tunnel from 127.0.0.1:<port> to the host. Then point the MCP server at the tunnel: POHODA_URL=http://127.0.0.1:<port>. Set POHODA_LOCAL_PORT to use a different local port. stop runs the stop task and closes the tunnel. status shows whether the remote port listens and whether the tunnel is open. Exit codes: 0 ok, 1 remote command failed, 2 usage, 3 mServer not listening, 4 tunnel failed or closed, 5 host unreachable. State (tunnel control socket, watcher PID and log) lives in ${XDG_STATE_HOME:-~/.local/state}/pohoda-mserver/.
Idle stop
The task POHODA mServer idle stop runs every 5 minutes as SYSTEM. It reads the tail of each configuration's mServer log (<LogDir>\<config>.log); the last POST /xml request or the last server start counts as activity, GET /status does not. A running configuration idle for -IdleMinutes or longer is stopped through its stop task, and the action is written to C:\ProgramData\pohoda-mcp\idle-stop.log. On your machine, start leaves a watcher that checks every 5 minutes whether the remote port still listens and closes the tunnel once it does not, so the host is left alone. To change the minutes, run the installer again with the same -Config and a new -IdleMinutes.
Uninstall
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass -Force
.\Install-MServerTasks.ps1 -Uninstall
This removes every POHODA mServer * task. The folder C:\ProgramData\pohoda-mcp (idle script and its log) stays; remove it by hand if you no longer need it.
Tools
System (4)
Print (1)
Address Book (4)
Invoices (2)
POHODA's XML API cannot update or delete invoices, cash vouchers, bank documents, internal documents or contracts: their XSDs have no actionType. These agendas are create-only through this server; make corrections in POHODA itself.
Orders (3)
Offers (2)
Enquiries (2)
Contracts (2)
Bank Documents (2)
Cash Vouchers (2)
Internal Documents (2)
Stock / Inventory (5)
Warehouse Documents (8)
Production & Service (4)
Reports (4)
Settings (1)
Resources
Docker
docker build -t pohoda-mcp .
docker run --rm -i \
-e POHODA_URL=http://host.docker.internal:444 \
-e POHODA_USERNAME=<your-username> \
-e POHODA_PASSWORD=<your-password> \
-e POHODA_ICO=<your-company-ico> \
pohoda-mcp
Multi-stage build, runs as non-root node user.
Security
- Credentials via environment variables only
STW-AuthorizationBasic auth per POHODA mServer specificationSTW-Application: pohoda-mcpheader for audit trail in POHODA monitoringSTW-Check-Duplicityheader support to prevent duplicate imports- XML escaping handled by xmlbuilder2 for all user-provided values
- Path traversal prevention for file downloads (normalize + reject
..prefixed paths) - Input validation via Zod on all tool parameters
Development
npm test # build + unit and end-to-end tests against a fake mServer
npm run check:xsd # validate every tool's XML against the official XSD (needs xmllint and internet on first run)
Code layout and design notes: ARCHITECTURE.md.
POHODA mServer Setup
- Open POHODA → Settings → mServer
- Create a new mServer configuration
- Set the listening port (default: 444)
- Start the mServer
- Ensure the user has XML communication rights (Settings → Access Rights → File → Data Communication)
For internet access, use HTTPS or VPN. mServer is primarily designed for local network use.
Tech Stack
- TypeScript 7
@modelcontextprotocol/sdk- Zod (schema validation)
- xmlbuilder2 (XML generation)
- fast-xml-parser (XML parsing)
- iconv-lite (Windows-1250 encoding)
- Native
fetch
API Reference
Credits
pohoda_print, pohoda_raw_xml, mServer autostart and the enum resources follow ideas from dg/pohoda-mcp.