feat(registry): add Bank Statement Sheet MCP server (#1472)

* feat(registry): add Bank Statement Sheet MCP server

An MCP server that converts PDF bank statements into transaction data
which arrives with a pass/fail reconciliation verdict. Each file is
checked against its own printed figures — balance continuity where the
bank prints a running balance, footing against the statement's control
totals where it does not. Below the threshold the rows are withheld and
an agent has to ask for them explicitly.

Covers the path the bank import does not: CAMT.053 and CSV are
supported, the PDF itself has no way in.

Verified against the sandbox 2026-08-07: 14 of 14 transactions imported
under Bankfil, Inkomster 35 500 kr and Utgifter −23 540,86 kr to the öre,
zero warnings and zero skipped rows on the semicolon + comma-decimal CSV.

Writes nothing to accounted and requests no scopes. First-time
contributor, so the author profile is added in the same PR.

npm run validate:registry: 21 entries, 3 authors, 0 failures.

Signed-off-by: alimpolat <alimpolat@users.noreply.github.com>

* fix(registry): correct two claims and drop prose em dashes

Addresses the CodeRabbit review on #1472.

The verdict did not survive where the entry said it did. It claimed the
per-row marker "overlever" decomposition into vouchers, which reads as
the verdict persisting into accounted. It does not: the flag exists only
in the MCP response, and nothing imported carries it. Now says so, and
says the reader must have seen the verdict before importing rather than
expect to find it in the books afterwards.

"Den kor inte lokalt" was wrong about the wrong thing. The MCP server
does run locally over stdio; it is the conversion that is remote. The
sentence now separates the local stdio process from the EU API, keeping
the server-side engine, thin MIT client and EU data location intact.

Em and en dashes removed from both files per the repo's coding
guidelines. Five occurrences, not the three flagged.

Not taken: pinning the install command to @0.1.0. Pinning would leave
every installed copy on the first release with no path to fixes; the
version field records what was verified, and the body already dates it.

npm run validate:registry: 21 entries, 3 authors, 0 failures.

Signed-off-by: alimpolat <alimpolat@users.noreply.github.com>

---------

Signed-off-by: alimpolat <alimpolat@users.noreply.github.com>
Co-authored-by: alimpolat <alimpolat@users.noreply.github.com>
This commit is contained in:
Alim Polat
2026-08-10 15:23:52 +02:00
committed by GitHub
co-authored by alimpolat
parent 0d0415e19c
commit 6821568523
2 changed files with 156 additions and 0 deletions
+19
View File
@@ -0,0 +1,19 @@
---
handle: "alimpolat"
name: "Alim Polat"
kind: "founder"
bio: "Bygger bankstatementsheet.com: PDF-kontoutdrag till Excel, CSV och OFX, avstämt mot utdragets egna tryckta siffror innan något lämnar systemet."
url: "https://bankstatementsheet.com"
location: "Stockholm"
joinedAt: "2026-08-08"
---
Jag bygger bankstatementsheet.com från Stockholm. Produkten gör en sak: läser ett
PDF-kontoutdrag och kontrollräknar resultatet mot utdragets egna siffror innan
det går vidare.
Anledningen till att avstämningen är hela poängen och inte en detalj: fel som ser
rimliga ut är värre än fel som syns. En extraktion som tappar en rad ger dig ett
tal som ser ut som ett saldo, och det upptäcks först vid bokslutet. Därför är
domen alltid med i svaret, och därför hålls raderna tillbaka när den inte går
ihop.
@@ -0,0 +1,137 @@
---
title: "Bank Statement Sheet MCP-server"
description: "MCP-server som läser PDF-kontoutdrag och lämnar tillbaka transaktionerna tillsammans med en avstämningsdom. Varje konvertering kontrollräknas mot utdragets egna tryckta siffror: löpande saldo där banken skriver ut ett, kontosummor där den inte gör det. Går det inte ihop hålls raderna tillbaka helt och en agent måste be om dem explicit. Tänkt som steget före bankimporten: CSV:n som kommer ut läses in under Bankfil."
slug: "bank-statement-sheet-mcp"
kind: "mcp"
author: "alimpolat"
status: "beta"
lang: "sv"
personas: ["developer", "byra", "finance"]
publishedAt: "2026-08-08"
updatedAt: "2026-08-08"
installCommand: "npx -y bank-statement-sheet-mcp"
externalUrl: "https://bankstatementsheet.com"
version: "0.1.0"
requiresWriteScope: false
related: ["gnubok-mcp"]
ogImageEyebrow: "MCP-server"
faq:
- q: "Vad gör den som en vanlig PDF-extraktion inte gör?"
a: "Den kontrollräknar. Där utdraget skriver ut ett löpande saldo kontrolleras varje angränsande radpar: saldo plus belopp ska bli föregående saldo. Där det inte finns något saldo summeras raderna mot utdragets egna kontosummor. Domen följer med i svaret, och under tröskeln lämnas inga rader ut."
- q: "Skriver den något till accounted?"
a: "Nej. Servern anropar inga accounted-verktyg och behöver inga scopes. Den producerar en fil som du själv läser in under Bankfil. Kedjan mot gnubok_create_voucher är nästa steg och är inte byggd."
- q: "Var hamnar min PDF?"
a: "Den laddas upp över HTTPS till Bank Statement Sheets API, som kör i EU. Filen behandlas i minnet, uppladdningsposter raderas inom 24 timmar och transaktioner sparas inte permanent. Vill du inte att en fil lämnar maskinen ska du inte skicka in den."
- q: "Vad kostar det?"
a: "Utan API-nyckel gäller gratisnivån: 5 konverteringar per månad, Excel och CSV. Med nyckel gäller samma plan och dagliga sidgräns som kontot den tillhör. Nyckeln skapas på bankstatementsheet.com/dashboard."
- q: "Hur vet jag att den funkar mot accounted?"
a: "Testat mot sandlådan 2026-08-07: 14 av 14 transaktioner in under Bankfil, inkomster 35 500 kr och utgifter −23 540,86 kr på öret. Med semikolon som avgränsare och kommadecimal blev det noll varningar och noll överhoppade rader."
---
## Vad den gör
Servern tar en sökväg till ett PDF-kontoutdrag och returnerar transaktionerna
plus en dom om huruvida siffrorna går ihop. Ett anrop räcker: uppladdning,
avstämning, rader och eventuella filer i samma svar.
Poängen är inte extraktionen. Poängen är att du får veta när extraktionen är fel,
innan raderna används till något. Ett utdrag där en rad tappats bort ger tal som
ser rimliga ut, och det upptäcks först långt senare.
## Avstämningen
Två metoder, och vilken som används beror på utdraget:
| Metod | När | Vad som kontrolleras |
|---|---|---|
| `balance-continuity` | Banken skriver ut ett löpande saldo | För varje angränsande radpar ska saldo plus belopp bli föregående saldo. Minst 99 procent av paren måste stämma. |
| `control-total` | Inget saldo per rad | Raderna summeras mot utdragets egna kontosummor: ingående saldo, in, ut, utgående saldo. |
Domen gäller **filen**, inte enskilda rader. Varje rad i MCP-svaret bär med sig
filens dom, så att en agent som delar upp raderna inte tappar bort den på vägen.
Det är vidarebefordran av filens dom, inte en kontroll per rad.
Men domen lever bara i MCP-svaret. Så fort raderna skrivs till en fil finns ingen
markering kvar per rad, och ingenting som importeras till accounted bär med sig
domen. Den som läser in filen måste alltså ha sett domen innan, inte förvänta sig
att hitta den i bokföringen efteråt.
Går det inte ihop är `transactions` satt till null. Raderna finns kvar, men en
agent måste be om dem explicit med `include_unverified_rows`, och det syns i
transkriptet. Det är avsiktligt: en agent som skickar vidare det den fick ska
inte kunna råka skicka vidare något overifierat.
På vårt referensutdrag från Handelsbanken på 16 sidor går 742 av 742 kontroller
ihop. Det är ett resultat på ett utdrag, inte en träffsäkerhetssiffra, och
Handelsbanken är den enda bank vi publicerar en siffra för.
## Installera
Kräver Node 20 eller senare. Servern är stdio.
```json
{
"mcpServers": {
"bank-statement-sheet": {
"command": "npx",
"args": ["-y", "bank-statement-sheet-mcp"],
"env": {
"BSS_API_KEY": "bss_live_..."
}
}
}
}
```
`BSS_API_KEY` är valfri. Utan nyckel körs gratisnivån, som är fullt fungerande
för att prova. Nyckel skapas på bankstatementsheet.com/dashboard.
Vill du se den köra utan att skicka in egna bankdata finns ett påhittat
exempelutdrag inbyggt: sätt `use_demo_statement` till true.
## Verktygen
| Verktyg | Vad det gör |
|---|---|
| `convert_bank_statement` | PDF in, dom plus rader plus valfria filer ut, i ett anrop. |
| `export_conversion` | Skriver en tidigare konvertering till fil i ett annat format. |
| `check_account_status` | Vilken nivå och kvot anropet faktiskt körs på. |
`check_account_status` finns för ett specifikt fel: en felstavad nyckel som tyst
degraderas till anonym ger en server som verkar fungera tills kvoten tar slut
utan förklaring. Kör den en gång per session.
## Så använder du den mot accounted idag
Manuellt, och det är värt att vara tydlig med:
1. Konvertera utdraget. Be om CSV med semikolon och kommadecimal. Det är vad
svenska importer läser utan varningar.
2. Kontrollera domen. Är den `unverified` ska filen inte läsas in.
3. Läs in CSV:n under Bankfil i accounted.
4. Godkänn de stagade transaktionerna som vanligt.
Steg 3 är en människa som flyttar en fil mellan två produkter. Det är hela
integrationen i dagsläget.
## Vad den inte gör
- **Den skriver inget till accounted.** Inga accounted-verktyg anropas, inga
scopes begärs, ingenting stagas åt dig. Kedjan mot `gnubok_create_voucher` är
nästa steg och är inte byggd.
- **Konverteringen sker inte lokalt.** Själva MCP-servern kör på din maskin över
stdio, men den är en tunn HTTP-klient under MIT: PDF:en laddas upp till ett API
i EU, och motorn ligger kvar på serversidan.
- **Den läser inte från URL.** Bara lokala sökvägar, och bara inom en
tillåten katalog. En agent som blivit promptinjicerad ska inte kunna be
servern ladda upp en godtycklig fil från din disk.
- **Den producerar ingen SIE och ingen CAMT.053.** Excel, CSV, JSON, OFX och
Fortnox-CSV är vad som finns. PDF till CAMT.053 vore en rakare väg in än CSV,
särskilt för utländska banker, men är inte byggt.
## En ärlig begränsning
Versionen är 0.1.0 och publicerades 2026-08-08. Den är verifierad mot
produktion och mot accounteds sandlåda, men den har inga externa användare än.
Hittar du något som inte stämmer vill jag gärna veta det. Det är hela
anledningen till att domen finns med i svaret istället för i marknadsföringen.