uol-mcp 0.0.0-stage → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/CHANGELOG.md +62 -0
  2. package/LICENSE +21 -0
  3. package/README.cs.md +143 -0
  4. package/README.md +281 -2
  5. package/dist/config.js +244 -0
  6. package/dist/config.js.map +1 -0
  7. package/dist/domain/audit.js +23 -0
  8. package/dist/domain/audit.js.map +1 -0
  9. package/dist/domain/bank.js +39 -0
  10. package/dist/domain/bank.js.map +1 -0
  11. package/dist/domain/company.js +12 -0
  12. package/dist/domain/company.js.map +1 -0
  13. package/dist/domain/contact-names.js +79 -0
  14. package/dist/domain/contact-names.js.map +1 -0
  15. package/dist/domain/files.js +36 -0
  16. package/dist/domain/files.js.map +1 -0
  17. package/dist/domain/ledger.js +92 -0
  18. package/dist/domain/ledger.js.map +1 -0
  19. package/dist/domain/paging.js +17 -0
  20. package/dist/domain/paging.js.map +1 -0
  21. package/dist/domain/receivables.js +109 -0
  22. package/dist/domain/receivables.js.map +1 -0
  23. package/dist/domain/uploads.js +60 -0
  24. package/dist/domain/uploads.js.map +1 -0
  25. package/dist/domain/vat.js +109 -0
  26. package/dist/domain/vat.js.map +1 -0
  27. package/dist/http.js +168 -0
  28. package/dist/http.js.map +1 -0
  29. package/dist/index.js +128 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/instructions.js +16 -0
  32. package/dist/instructions.js.map +1 -0
  33. package/dist/prompts.js +60 -0
  34. package/dist/prompts.js.map +1 -0
  35. package/dist/resources.js +57 -0
  36. package/dist/resources.js.map +1 -0
  37. package/dist/server.js +103 -0
  38. package/dist/server.js.map +1 -0
  39. package/dist/tools/accounts.js +33 -0
  40. package/dist/tools/accounts.js.map +1 -0
  41. package/dist/tools/banking.js +105 -0
  42. package/dist/tools/banking.js.map +1 -0
  43. package/dist/tools/company.js +96 -0
  44. package/dist/tools/company.js.map +1 -0
  45. package/dist/tools/contacts.js +131 -0
  46. package/dist/tools/contacts.js.map +1 -0
  47. package/dist/tools/context.js +82 -0
  48. package/dist/tools/context.js.map +1 -0
  49. package/dist/tools/destructive.js +96 -0
  50. package/dist/tools/destructive.js.map +1 -0
  51. package/dist/tools/documents.js +124 -0
  52. package/dist/tools/documents.js.map +1 -0
  53. package/dist/tools/files.js +20 -0
  54. package/dist/tools/files.js.map +1 -0
  55. package/dist/tools/insights.js +270 -0
  56. package/dist/tools/insights.js.map +1 -0
  57. package/dist/tools/invoices.js +329 -0
  58. package/dist/tools/invoices.js.map +1 -0
  59. package/dist/tools/ledger.js +138 -0
  60. package/dist/tools/ledger.js.map +1 -0
  61. package/dist/tools/raw.js +47 -0
  62. package/dist/tools/raw.js.map +1 -0
  63. package/dist/tools/receivables.js +84 -0
  64. package/dist/tools/receivables.js.map +1 -0
  65. package/dist/tools/schemas.js +41 -0
  66. package/dist/tools/schemas.js.map +1 -0
  67. package/dist/tools/warehouse.js +181 -0
  68. package/dist/tools/warehouse.js.map +1 -0
  69. package/dist/tools/write-support.js +34 -0
  70. package/dist/tools/write-support.js.map +1 -0
  71. package/dist/tools/writes-documents.js +117 -0
  72. package/dist/tools/writes-documents.js.map +1 -0
  73. package/dist/tools/writes-records.js +324 -0
  74. package/dist/tools/writes-records.js.map +1 -0
  75. package/dist/tools/writes.js +291 -0
  76. package/dist/tools/writes.js.map +1 -0
  77. package/dist/uol/client.js +61 -0
  78. package/dist/uol/client.js.map +1 -0
  79. package/dist/uol/errors.js +50 -0
  80. package/dist/uol/errors.js.map +1 -0
  81. package/dist/uol/http.js +213 -0
  82. package/dist/uol/http.js.map +1 -0
  83. package/dist/uol/normalize.js +117 -0
  84. package/dist/uol/normalize.js.map +1 -0
  85. package/dist/uol/rate-limit.js +55 -0
  86. package/dist/uol/rate-limit.js.map +1 -0
  87. package/package.json +57 -4
package/CHANGELOG.md ADDED
@@ -0,0 +1,62 @@
1
+ # Changelog
2
+
3
+ All notable changes to uol-mcp. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
4
+ and the project uses [Semantic Versioning](https://semver.org/).
5
+
6
+ ## [Unreleased]
7
+
8
+ ## [0.4.1] — 2026-11-05
9
+
10
+ ### Security
11
+
12
+ - Ids are validated before they go into a URL path. `..` used to pass, so
13
+ `untag_uploaded_document(tag_id="..")` became `DELETE /uploaded_documents/<id>/` — a tag removal
14
+ that deleted the whole document.
15
+ - The HTTP server no longer reads `file_path` uploads from its own disk unless `UOL_UPLOAD_DIRS` is set
16
+ explicitly; remote callers send `content_base64`.
17
+ - Download file names built from ids are sanitised too; downloads never replace an existing file
18
+ (a taken name gets a ` (1)` suffix) and are saved readable by the owner only.
19
+ - An invalid `UOL_PROFILES_FILE` is reported without quoting the file, which could contain a token.
20
+ - The Docker image no longer ships npm, yarn and corepack (the server needs only node), and the base
21
+ image is pinned by digest.
22
+ - Release workflow hardened: publishing waits for approval on the `release` environment, actions are
23
+ pinned to commit SHAs, jobs with publishing rights don't run dependency install scripts, the
24
+ `mcp-publisher` download is checked against its release checksum, and an existing release asset is
25
+ never overwritten.
26
+ - CI scans: `npm audit`, Trivy (image), CodeQL, dependency review on pull requests, Dependabot.
27
+
28
+ ### Fixed
29
+
30
+ - Supplier and customer names were missing on long invoice lists: names were looked up one contact
31
+ at a time, at most 15 per call. Long lists now read the contact list first.
32
+ - `get_business_snapshot` lists sections that were read only partly in `incomplete`, and
33
+ `get_bank_balances` returns `truncated`, as the other summaries already did.
34
+
35
+ ## [0.4.0] — 2026-11-05
36
+
37
+ First public release (0.1–0.3 were internal milestones).
38
+
39
+ ### Added
40
+
41
+ - **Read tools** (default): company, codebooks, sales and purchase invoices with payment status,
42
+ receivables with totals per currency, PDF / ISDOC export, contacts, uploaded documents, `api_get`.
43
+ - **Insights**: financial overview from the general ledger, VAT per filing period, bank balances, and a
44
+ one-call business snapshot.
45
+ - **Optional toolsets** (`UOL_TOOLSETS`): `ledger`, `banking`, `warehouse`.
46
+ - **Writes** (`UOL_ACCESS=write`): document upload, sales invoices (draft by default, idempotent),
47
+ purchase invoices, contacts, payment demands, the uploaded-document workflow; every write supports
48
+ `dry_run` and can be recorded in `UOL_AUDIT_LOG`.
49
+ - **Destructive tools** (`UOL_ACCESS=full`): delete a draft, storno / back to draft, `api_request`.
50
+ - **Several companies**: `UOL_ACCOUNTS` (all in the client config) or `UOL_PROFILES_FILE`;
51
+ `list_accounts` and an `account` argument on every tool.
52
+ - Czech prompts (`monthly_review`, `vat_check`, `overdue_followup`, `process_inbox`) and the
53
+ `uol://guide` / `uol://company` resources.
54
+ - Streamable HTTP transport: single-tenant with a bearer token, or pass-through with per-request
55
+ credentials.
56
+ - `uol-mcp doctor` checks the configuration (every account).
57
+ - Distribution: npm, GHCR image (amd64 / arm64), Claude Desktop extension (`.mcpb`), MCP Registry
58
+ (`eu.humblecode/uol`).
59
+
60
+ [Unreleased]: https://github.com/jakubbegera/uol-mcp/compare/v0.4.1...HEAD
61
+ [0.4.1]: https://github.com/jakubbegera/uol-mcp/compare/v0.4.0...v0.4.1
62
+ [0.4.0]: https://github.com/jakubbegera/uol-mcp/releases/tag/v0.4.0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Jakub Begera
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.cs.md ADDED
@@ -0,0 +1,143 @@
1
+ # uol-mcp — návod
2
+
3
+ Napojení [UOL Účetnictví](https://www.uol.cz) na AI asistenty (Claude, Cursor a další klienty
4
+ s podporou [MCP](https://modelcontextprotocol.io)). Asistent pak umí odpovídat nad vaším účetnictvím:
5
+ vydané a přijaté faktury, kdo vám dluží, nahrané doklady, kontakty.
6
+
7
+ > **Neoficiální projekt.** Není spojený s UOL a.s. Komunikuje s veřejným
8
+ > [UOL REST API](https://api.uol.cz/) pomocí vašeho vlastního API tokenu.
9
+
10
+ [English](README.md)
11
+
12
+ **Stav:** verze 0.4, ve výchozím stavu pouze čtení, zápis lze zapnout. Změny jednotlivých verzí
13
+ popisuje [CHANGELOG.md](CHANGELOG.md).
14
+
15
+ ## Co umí
16
+
17
+ - **Přehled firmy jedním dotazem:** tento a minulý měsíc, DPH, pohledávky, doklady ke zpracování
18
+ a zůstatky na účtech.
19
+ - **Tržby, náklady a zisk:** po měsících z hlavní knihy, stejně jako dashboard UOL, včetně
20
+ největších nákladových a výnosových účtů.
21
+ - **DPH:** za zdaňovací období, k zaplacení nebo nadměrný odpočet, termín podání; u neuzavřeného
22
+ období jako odhad z faktur.
23
+ - **Zůstatky na účtech:** podle účtů a měn (UOL eviduje měsíční počáteční stavy, ne aktuální zůstatek).
24
+ - **Faktury:** hledání vydaných i přijatých faktur, detail s položkami a DPH, stav úhrady
25
+ u vydaných faktur.
26
+ - **Pohledávky:** kdo vám dluží, kolik a jak dlouho po splatnosti, součty podle měn.
27
+ - **Export:** PDF nebo ISDOC vydané faktury uložené na disk.
28
+ - **Kontakty:** odběratelé a dodavatelé podle názvu, IČO nebo DIČ, s adresami a bankovními účty.
29
+ - **Nahrané doklady:** co čeká na zpracování, stažení původního souboru.
30
+ - **Číselníky:** měny, střediska, zakázky, ceníky, vlastní bankovní účty a další.
31
+
32
+ Připravené postupy (v klientech jako příkazy s lomítkem): `monthly_review` (měsíční přehled),
33
+ `vat_check` (kontrola DPH), `overdue_followup` (návrhy upomínek, nic neodesílá) a `process_inbox`
34
+ (projde nahrané doklady).
35
+
36
+ Příklady otázek:
37
+
38
+ - „Jak si letos stojíme?“
39
+ - „Kolik zaplatím DPH za tento kvartál?“
40
+ - „Na čem nejvíc utrácíme?“
41
+ - „Kdo mi dluží víc než 30 dní?“
42
+ - „Je faktura 2026000123 zaplacená?“
43
+ - „Kolik jsme letos fakturovali firmě Alza?“
44
+ - „Stáhni mi PDF poslední vydané faktury.“
45
+ - „Které nahrané doklady ještě účetní nezpracovala?“
46
+
47
+ ## Jak získat API token
48
+
49
+ 1. Otevřete v UOL stránku API tokenů (adresa `/api_tokens` na vaší instanci, např.
50
+ `https://firma.ucetnictvi.uol.cz/api_tokens`) a vytvořte token.
51
+ 2. Uživatel musí mít oprávnění **REST API**. Doporučujeme samostatného uživatele jen s právy,
52
+ která má asistent mít.
53
+
54
+ Název instance (tenant) je první část vaší adresy UOL: `https://firma.ucetnictvi.uol.cz` → `firma`.
55
+
56
+ Chcete si to nejdřív vyzkoušet? S `UOL_TENANT=demo` se použije veřejná DEMO firma od UOL,
57
+ token není potřeba.
58
+
59
+ ## Nastavení v Claude Desktop
60
+
61
+ Nastavení → Developer → Edit Config a doplňte:
62
+
63
+ ```json
64
+ {
65
+ "mcpServers": {
66
+ "uol": {
67
+ "command": "npx",
68
+ "args": ["-y", "uol-mcp"],
69
+ "env": {
70
+ "UOL_TENANT": "firma",
71
+ "UOL_EMAIL": "vas@email.cz",
72
+ "UOL_TOKEN": "vas-token"
73
+ }
74
+ }
75
+ }
76
+ }
77
+ ```
78
+
79
+ Po restartu Claude Desktop zkuste: „Jaké jsou údaje naší firmy v UOL?“
80
+
81
+ Ostatní klienty (Claude Code, Cursor, VS Code), Docker, HTTP server a všechny proměnné prostředí
82
+ popisuje [anglické README](README.md#configuration).
83
+
84
+ ## Zápis (volitelný)
85
+
86
+ S `UOL_ACCESS=write` (v Claude Desktop rozšíření pole „Access“ = `write`) asistent umí navíc:
87
+
88
+ - **nahrát doklad** (PDF) účetní do UOL, a to jen ze složek Stažené soubory, Plocha a Dokumenty
89
+ (nebo ze složek v `UOL_UPLOAD_DIRS`);
90
+ - **vystavit fakturu** existujícímu kontaktu, standardně jako koncept;
91
+ - **upravit nebo vystavit koncept faktury**; už vystavenou fakturu UOL měnit nedovolí;
92
+ - **zaevidovat přijatou fakturu**, **založit nebo upravit kontakt** (s kontrolou duplicitního IČO);
93
+ - **vytvořit upomínku** k neuhrazeným fakturám jednoho odběratele (nic se neodesílá);
94
+ - **zpracovat nahrané doklady**: označit jako zpracované, spárovat s fakturou, přidat štítek.
95
+
96
+ S `UOL_ACCESS=full` navíc smazání konceptu faktury, storno nebo vrácení vystavené faktury do konceptu
97
+ a obecný zápis do libovolného endpointu.
98
+
99
+ Před každým zápisem si asistent nechá vše ukázat nanečisto a klient vás požádá o souhlas.
100
+ Opakované vytvoření stejné faktury nevznikne dvakrát.
101
+
102
+ ## Více firem (pro účetní)
103
+
104
+ Jeden server obslouží víc klientských firem. Účty vyjmenujete v `UOL_ACCOUNTS` a každému dáte
105
+ vlastní proměnné, vše přímo v konfiguraci klienta:
106
+
107
+ ```json
108
+ "env": {
109
+ "UOL_ACCOUNTS": "firma,novak",
110
+ "UOL_ACCOUNT_FIRMA_TENANT": "firma",
111
+ "UOL_ACCOUNT_FIRMA_EMAIL": "vas@email.cz",
112
+ "UOL_ACCOUNT_FIRMA_TOKEN": "token-firmy",
113
+ "UOL_ACCOUNT_NOVAK_TENANT": "novak",
114
+ "UOL_ACCOUNT_NOVAK_EMAIL": "vas@email.cz",
115
+ "UOL_ACCOUNT_NOVAK_TOKEN": "token-novaka",
116
+ "UOL_ACCOUNT_NOVAK_LABEL": "Novák s.r.o."
117
+ }
118
+ ```
119
+
120
+ Výchozí je první účet. Asistent pak u každého dotazu ví, které firmy se týká, třeba „Kdo dluží firmě
121
+ Novák?“. Tokeny nemusí být v konfiguraci napsané přímo: s 1Password CLI stačí odkazy `op://…`
122
+ a server spustit přes `op run`. Stejné nastavení jde mít i v souboru (`UOL_PROFILES_FILE`), viz
123
+ [anglické README](README.md#several-companies).
124
+
125
+ ## Soukromí a bezpečnost
126
+
127
+ - Bez `UOL_ACCESS=write` server data jen čte. Text uvnitř faktur, poznámek a dokladů je pro
128
+ asistenta jen data: před schválením zápisu si zkontrolujte, co navrhuje.
129
+ - Vše, co nástroje vrátí, dostane AI model, který váš klient používá. Účetnictví obsahuje osobní
130
+ údaje kontaktů a zaměstnanců; zvolte si takový tarif, s jehož podmínkami souhlasíte.
131
+ - Přihlašovací údaje se posílají jen na `https://*.uol.cz` a nikdy se nezapisují do logů.
132
+ - Stažené soubory se ukládají jen do složky `UOL_DOWNLOAD_DIR` (výchozí `~/Downloads/uol-mcp`),
133
+ čitelné jen pro vás, a nikdy nepřepíšou existující soubor.
134
+
135
+ ## Zapojte se
136
+
137
+ Příspěvky jsou vítané: chyby, zvláštnosti API, nové nástroje i úpravy dokumentace. Postup popisuje
138
+ [CONTRIBUTING.md](CONTRIBUTING.md) (anglicky). Bezpečnostní problémy prosím hlaste neveřejně podle
139
+ [SECURITY.md](SECURITY.md).
140
+
141
+ ## Licence
142
+
143
+ [MIT](LICENSE)
package/README.md CHANGED
@@ -1,3 +1,282 @@
1
- # Temporary Holding Version
1
+ # uol-mcp
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ [Model Context Protocol](https://modelcontextprotocol.io) server for
4
+ [UOL Účetnictví](https://www.uol.cz) — ask Claude, Cursor or any other MCP client about your
5
+ bookkeeping: issued and received invoices, who owes you money, uploaded documents, contacts.
6
+
7
+ > **Unofficial.** Not affiliated with or endorsed by UOL a.s. It talks to the public
8
+ > [UOL REST API](https://api.uol.cz/) with your own API token.
9
+
10
+ [Česky](README.cs.md)
11
+
12
+ **Status:** v0.4 — read-only by default, opt-in writes. What changed: [CHANGELOG.md](CHANGELOG.md).
13
+
14
+ ## What it can do
15
+
16
+ | Tool | Answers |
17
+ |---|---|
18
+ | `get_business_snapshot` | How the company is doing, in one call: this month vs last, VAT, receivables, documents to process, bank |
19
+ | `get_financial_overview` | Revenue, expenses and profit per month from the general ledger, largest accounts |
20
+ | `get_vat_overview` | VAT per filing period: to pay or excess deduction, due date, final or estimate |
21
+ | `get_bank_balances` | Bank balances per account and currency (UOL keeps monthly snapshots) |
22
+ | `get_company` | Company name, IČO, DIČ, address, VAT filing period; doubles as a connection check |
23
+ | `search_sales_invoices`, `get_sales_invoice` | Issued invoices with line items, VAT and payment status |
24
+ | `search_purchase_invoices`, `get_purchase_invoice` | Received invoices |
25
+ | `list_receivables` | Who owes you, how much, how long overdue — totals per currency |
26
+ | `export_sales_invoice` | PDF or ISDOC of an issued invoice, saved to disk (ISDOC is also returned as XML) |
27
+ | `search_contacts`, `get_contact` | Customers and suppliers by name, IČO or DIČ, with addresses and bank accounts |
28
+ | `list_uploaded_documents`, `get_uploaded_document`, `download_uploaded_document` | Documents uploaded for the accountant, their state and files |
29
+ | `list_codebook` | Currencies, departments, contracts, price lists, own bank accounts, … |
30
+ | `api_get` | Read-only GET of any other `/v1/…` endpoint |
31
+
32
+ Example questions: *"Jak si letos stojíme?"*, *"Kolik zaplatím DPH za tento kvartál?"*,
33
+ *"Kdo mi dluží víc než 30 dní?"*, *"Je faktura 2026000123 zaplacená?"*,
34
+ *"Na čem nejvíc utrácíme?"*, *"Stáhni mi PDF poslední vydané faktury."*
35
+
36
+ More read tools are available as opt-in toolsets (`UOL_TOOLSETS`): `ledger` (general-ledger postings, internal
37
+ documents), `banking` (bank movements, petty-cash documents) and `warehouse` (products, stock levels, orders).
38
+
39
+ Ready-made prompts (slash commands in most clients): `monthly_review`, `vat_check`,
40
+ `overdue_followup` (drafts reminders, sends nothing), `process_inbox`. The `uol://guide` resource
41
+ explains the domain to the model.
42
+
43
+ The server knows the API's quirks: invoice status `valid` means *draft*, payment status exists only
44
+ for issued invoices, credit notes come with positive amounts, revenue and expenses have to be read
45
+ from the ledger (excluding year-end closing entries), purchase invoices ignore issue-date filters,
46
+ files have three different download shapes, and the rate limit (30 requests / 10 s) is respected
47
+ client-side. See [docs/DESIGN.md](docs/DESIGN.md).
48
+
49
+ ## Getting an API token
50
+
51
+ 1. Open the API tokens page of your UOL tenant (path `/api_tokens`, e.g.
52
+ `https://firma.ucetnictvi.uol.cz/api_tokens`) and create a token.
53
+ 2. The UOL user needs the **REST API** permission. A dedicated user with only the rights you want
54
+ the assistant to have is a good idea.
55
+
56
+ Your tenant is the first part of your UOL address: `https://firma.ucetnictvi.uol.cz` → `firma`.
57
+
58
+ Want to try it first? `UOL_TENANT=demo` uses UOL's public DEMO company, no token needed.
59
+
60
+ ## Configuration
61
+
62
+ | Variable | Meaning |
63
+ |---|---|
64
+ | `UOL_TENANT` | `demo`, your tenant name (`firma`), a host prefix (`firma.sandbox`) or the full `https://….uol.cz` URL |
65
+ | `UOL_EMAIL` | E-mail you log into UOL with |
66
+ | `UOL_TOKEN` | API token |
67
+ | `UOL_DOWNLOAD_DIR` | Where exported and downloaded files go (default `~/Downloads/uol-mcp`) |
68
+ | `UOL_TOOLSETS` | Comma-separated: `core`, `insights` (these two are the default), `ledger`, `banking`, `warehouse`, or `all` |
69
+ | `UOL_ACCESS` | `read` (default), `write` or `full` — see [Writing](#writing-opt-in) |
70
+ | `UOL_ACCOUNTS`, `UOL_DEFAULT_ACCOUNT` | Several companies in one server — see [Several companies](#several-companies) |
71
+ | `UOL_PROFILES_FILE` | The same from a JSON file |
72
+ | `UOL_UPLOAD_DIRS` | Folders `upload_document` may read from (default `~/Downloads`, `~/Desktop`, `~/Documents`; `:`-separated, `;` on Windows). The HTTP server has no default: without this variable it accepts only `content_base64` |
73
+ | `UOL_AUDIT_LOG` | File that records every write as a JSON line |
74
+ | `UOL_TIMEOUT_MS` | Timeout of one UOL request (default `30000`) |
75
+ | `UOL_DEBUG` | `1` logs requests to stderr (never credentials) |
76
+
77
+ ### Claude Desktop
78
+
79
+ Settings → Developer → Edit Config, then add:
80
+
81
+ ```json
82
+ {
83
+ "mcpServers": {
84
+ "uol": {
85
+ "command": "npx",
86
+ "args": ["-y", "uol-mcp"],
87
+ "env": {
88
+ "UOL_TENANT": "firma",
89
+ "UOL_EMAIL": "you@example.com",
90
+ "UOL_TOKEN": "your-token"
91
+ }
92
+ }
93
+ }
94
+ }
95
+ ```
96
+
97
+ ### Claude Code
98
+
99
+ ```bash
100
+ claude mcp add uol -e UOL_TENANT=firma -e UOL_EMAIL=you@example.com -e UOL_TOKEN=your-token -- npx -y uol-mcp
101
+ ```
102
+
103
+ ### Cursor / VS Code
104
+
105
+ Cursor (`.cursor/mcp.json`) uses the same `mcpServers` block as Claude Desktop. VS Code
106
+ (`.vscode/mcp.json`):
107
+
108
+ ```json
109
+ {
110
+ "servers": {
111
+ "uol": {
112
+ "type": "stdio",
113
+ "command": "npx",
114
+ "args": ["-y", "uol-mcp"],
115
+ "env": { "UOL_TENANT": "firma", "UOL_EMAIL": "you@example.com", "UOL_TOKEN": "your-token" }
116
+ }
117
+ }
118
+ }
119
+ ```
120
+
121
+ ### Docker
122
+
123
+ ```bash
124
+ docker run -i --rm -e UOL_TENANT=firma -e UOL_EMAIL=you@example.com -e UOL_TOKEN=your-token -v "$HOME/Downloads/uol-mcp:/data" ghcr.io/jakubbegera/uol-mcp
125
+ ```
126
+
127
+ Exported and downloaded files are written to `/data` inside the container; the `-v` mount keeps them.
128
+ In an MCP client config, use `docker` as the command and the rest as `args`.
129
+
130
+ ### Claude Desktop extension
131
+
132
+ Each release ships `uol-mcp.mcpb`. Open it to install, then fill in tenant, e-mail and token in the
133
+ form; the token is stored as a secret. `bash scripts/build-mcpb.sh` builds the bundle from source.
134
+
135
+ ### HTTP server (self-hosting)
136
+
137
+ ```bash
138
+ MCP_TRANSPORT=http MCP_AUTH_TOKEN=change-me UOL_TENANT=firma UOL_EMAIL=you@example.com UOL_TOKEN=your-token npx -y uol-mcp
139
+ ```
140
+
141
+ The endpoint is `http://127.0.0.1:3000/mcp` (`HOST`, `PORT` to change; `/health` for probes).
142
+ Two modes:
143
+
144
+ - **One tenant**: UOL credentials in the server's env. Clients must send `Authorization: Bearer
145
+ <MCP_AUTH_TOKEN>`; the server refuses to start without the token.
146
+ - **Pass-through**: no UOL credentials in the env. Each client sends its own `X-UOL-Tenant`,
147
+ `X-UOL-Email` and `X-UOL-Token` headers with every request; the server stores nothing.
148
+ `MCP_AUTH_TOKEN` is optional.
149
+
150
+ Over HTTP, exported invoices and downloaded documents come back inside the tool result instead of
151
+ being saved on the server, and `upload_document` takes the file as `content_base64` — it reads no
152
+ paths on the server unless `UOL_UPLOAD_DIRS` is set. In Docker, bind to all interfaces and publish the
153
+ port: `docker run -p 3000:3000 -e MCP_TRANSPORT=http -e HOST=0.0.0.0 -e MCP_ALLOWED_HOSTS=mcp.example.com …`.
154
+
155
+ | Variable | Meaning |
156
+ |---|---|
157
+ | `MCP_TRANSPORT` | `http` starts the HTTP server (same as `--http`) |
158
+ | `HOST`, `PORT` | Bind address, default `127.0.0.1:3000` |
159
+ | `MCP_AUTH_TOKEN` | Bearer token clients must send; required in one-tenant mode, recommended in pass-through |
160
+ | `MCP_ALLOWED_HOSTS` | Accepted `Host` names (comma-separated) when not bound to localhost |
161
+ | `MCP_ALLOWED_ORIGINS` | Browser origins allowed to call the endpoint (none by default) |
162
+
163
+ The server speaks plain HTTP: anywhere beyond localhost, put it behind a reverse proxy that
164
+ terminates TLS, and use a long random `MCP_AUTH_TOKEN`.
165
+
166
+ ### Check the setup
167
+
168
+ ```bash
169
+ UOL_TENANT=firma UOL_EMAIL=you@example.com UOL_TOKEN=your-token npx -y uol-mcp doctor
170
+ ```
171
+
172
+ ## Writing (opt-in)
173
+
174
+ With `UOL_ACCESS=write` these tools appear:
175
+
176
+ | Tool | Does |
177
+ |---|---|
178
+ | `upload_document` | Uploads a PDF to UOL's document inbox for the accountant (only from `UOL_UPLOAD_DIRS`) |
179
+ | `create_sales_invoice` | Creates an issued invoice for an existing contact — a draft unless `issue: true` |
180
+ | `update_sales_invoice` | Changes or issues a draft invoice (UOL doesn't allow editing issued ones) |
181
+ | `create_purchase_invoice` | Books a received invoice from an existing supplier |
182
+ | `create_contact`, `update_contact` | Adds or changes a customer / supplier (refuses a duplicate IČO) |
183
+ | `create_payment_demand` | Creates a payment demand (upomínka) for unpaid invoices of one customer — never sends it |
184
+ | `mark_document_processed`, `pair_uploaded_document`, `tag_uploaded_document`, `untag_uploaded_document` | The accountant's inbox: state, link to the booked record, tags |
185
+
186
+ `UOL_ACCESS=full` adds `delete_sales_invoice` (drafts only), `repair_sales_invoice` (storno or back to
187
+ draft for issued invoices) and `api_request` (a raw write to any endpoint).
188
+
189
+ Invoice lines need a UOL product (`list_codebook` with `kind: products` lists them). Every write
190
+ supports `dry_run` (shows exactly what would be sent), creates are safe to retry
191
+ (idempotency key), and the tools are marked so clients ask you before running them. Set
192
+ `UOL_AUDIT_LOG` to keep a record of every write.
193
+
194
+ ## Several companies
195
+
196
+ Accountants with several clients on UOL can serve them all from one server. List the accounts in
197
+ `UOL_ACCOUNTS` and give each one its own variables (name upper-cased, `-` becomes `_`):
198
+
199
+ ```json
200
+ "env": {
201
+ "UOL_ACCOUNTS": "firma,novak",
202
+ "UOL_ACCOUNT_FIRMA_TENANT": "firma",
203
+ "UOL_ACCOUNT_FIRMA_EMAIL": "ja@firma.cz",
204
+ "UOL_ACCOUNT_FIRMA_TOKEN": "op://Private/UOL firma/credential",
205
+ "UOL_ACCOUNT_NOVAK_TENANT": "novak",
206
+ "UOL_ACCOUNT_NOVAK_EMAIL": "ja@firma.cz",
207
+ "UOL_ACCOUNT_NOVAK_TOKEN": "op://Private/UOL novak/credential",
208
+ "UOL_ACCOUNT_NOVAK_LABEL": "Novák s.r.o."
209
+ }
210
+ ```
211
+
212
+ The first account is the default (or set `UOL_DEFAULT_ACCOUNT`). With the 1Password CLI, start the
213
+ server as `op run -- node …/dist/index.js` and the `op://` references are replaced by the tokens at
214
+ startup — nothing secret sits in the config. `uol-mcp doctor` checks every account.
215
+
216
+ Alternatively, point `UOL_PROFILES_FILE` at a JSON file:
217
+
218
+ ```json
219
+ {
220
+ "default": "firma",
221
+ "accounts": {
222
+ "firma": { "tenant": "firma", "email": "ja@firma.cz", "token_env": "UOL_TOKEN_FIRMA" },
223
+ "novak": { "tenant": "novak", "email": "ja@firma.cz", "token_env": "UOL_TOKEN_NOVAK", "label": "Novák s.r.o." }
224
+ }
225
+ }
226
+ ```
227
+
228
+ `token_env` names an environment variable holding the token, so the file needs no secrets (an inline
229
+ `token` works too; keep such a file `chmod 600`). The server then offers `list_accounts`, and every tool
230
+ takes an `account` argument — *"Kdo dluží firmě Novák?"* goes to the right tenant. Each account keeps
231
+ its own rate limit.
232
+
233
+ ## Privacy and safety
234
+
235
+ - Read-only unless you set `UOL_ACCESS=write`. Text inside invoices, notes and documents is treated
236
+ as data: review what the assistant proposes to write before you approve it.
237
+ - Whatever the tools return goes to the AI model your client uses. Accounting data contains personal
238
+ data of your contacts and employees — use a plan whose terms you are comfortable with.
239
+ - Credentials are used only for `https://*.uol.cz` and are never written to logs or tool output.
240
+ - Downloaded files are saved under `UOL_DOWNLOAD_DIR` only, readable by the owner, and never replace an existing file (a taken name gets a ` (1)` suffix).
241
+
242
+ ## From source
243
+
244
+ Requires Node.js 22+.
245
+
246
+ ```bash
247
+ git clone https://github.com/jakubbegera/uol-mcp.git
248
+ cd uol-mcp
249
+ npm install
250
+ npm run build
251
+ ```
252
+
253
+ Then point your client at `node /path/to/uol-mcp/dist/index.js` instead of `npx -y uol-mcp`.
254
+
255
+ ## Development
256
+
257
+ ```bash
258
+ npm test # unit + MCP-level tests against recorded DEMO responses
259
+ npm run typecheck
260
+ npm run smoke # calls every tool against the live DEMO tenant
261
+ npm run record-fixtures # refreshes test/fixtures/demo from the DEMO tenant
262
+ bash scripts/build-mcpb.sh # builds build/uol-mcp.mcpb
263
+ docker build -t uol-mcp .
264
+ ```
265
+
266
+ CI runs the type check, tests, `npm audit`, a Trivy scan of the Docker image, CodeQL and, on pull
267
+ requests, dependency review; Dependabot keeps dependencies, actions and the base image current.
268
+
269
+ Releases are cut by pushing a `v*` tag; after a maintainer approves the `release` environment,
270
+ `.github/workflows/release.yml` publishes to npm, GHCR, the GitHub release (MCPB bundle) and the MCP
271
+ Registry.
272
+
273
+ Design notes, API facts and the roadmap are in [docs/DESIGN.md](docs/DESIGN.md).
274
+
275
+ ## Contributing
276
+
277
+ Contributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md). Report security problems
278
+ privately as described in [SECURITY.md](SECURITY.md).
279
+
280
+ ## License
281
+
282
+ [MIT](LICENSE)