Skip to main content
Glama
cwvedvik

Tripletex MCP Server

by cwvedvik
README.md
# Tripletex MCP Server

En open source [MCP-server](https://modelcontextprotocol.io/) som lar AI-assistenter (Claude, Cursor, osv.) jobbe direkte mot Tripletex sitt regnskapssystem.
Se hvordan du installerer repo og kobler på under.

**Foretrekker du en ferdigkonfigurert MCP-løsning?** Prøv: [Regnskapsagent.no](https://regnskapsagent.no/)

Bygd og vedlikeholdt av [CWV Ventures AS](https://cwv.no).

## Trenger du hjelp til implementering?
Kontakt meg på carl@cwv.no.

## I korte trekk

- **56 MCP-verktøy** dekker ordre, faktura, leverandørfaktura, bilag, hovedbok, rapporter, prosjekt, timer, HR og reiseregning.
- **18 regnskapsflyter (skills)** — norsk-språklige steg-for-steg-guider som aktiveres via MCP-prompts.
- **Tynn, presis proxy over Tripletex v2** — feltnavn matcher API-ets DTO-er verbatim, slik at LLM-en får riktig feedback og kan selvkorrigere.
- **Automatisk autentisering** — consumer + employee token byttes til kortlevd session token, caches til midnatt CET og fornyes ved 401.
- **Stdio transport** per MCP-spesifikasjonen; kan kobles på Claude Desktop, Cursor, eller andre MCP-klienter.

## Arkitektur

MCP-serveren er delt i tre lag: tynn proxy (`tripletex-client.ts`), body-byggere (`tripletex-transform.ts`) og 56 tool-registreringer + 18 skills (`tripletex-tools.ts`, `skills/`). LLM-klienten snakker med serveren over stdio; serveren snakker med Tripletex v2 over HTTPS.

```mermaid
flowchart LR
  Client["MCP-klient<br/>(Claude / Cursor / Regnskapsagent)"]

  subgraph Server["tripletex-mcp (stdio-server)"]
    direction TB
    Entry["index.ts<br/>bootstrap + McpServer"]
    Tools["tripletex-tools.ts<br/>56 server.tool(...)"]
    Skills["skills/*.ts<br/>18 MCP prompts"]
    Resource["Resource<br/>tripletex://skills"]
    Transform["tripletex-transform.ts<br/>body-byggere"]
    HttpClient["TripletexClient<br/>auth + HTTP + retry"]
  end

  API["Tripletex v2 REST<br/>tripletex.no/v2"]

  Client -- "stdio / JSON-RPC" --> Entry
  Entry --> Tools
  Entry --> Skills
  Skills --> Resource
  Tools --> Transform
  Tools --> HttpClient
  Transform --> HttpClient
  HttpClient -- "Basic Auth + session token" --> API
```

**Hvor hver ting lever:**

| Fil | Ansvar |
|---|---|
| [src/index.ts](src/index.ts) | Stdio-bootstrap, `McpServer`-instans, kobler klient til tools. |
| [src/tripletex-tools.ts](src/tripletex-tools.ts) | Alle 56 `server.tool(...)`-registreringer med Zod-schemas og korte agent-instruksjoner. |
| [src/tripletex-transform.ts](src/tripletex-transform.ts) | Rene funksjoner som bygger Tripletex-JSON fra MCP-input (f.eks. `buildOrderBody`, `buildSupplierInvoiceVoucherBody`). |
| [src/tripletex-client.ts](src/tripletex-client.ts) | Autentisering, session-caching, `fetch`-wrapper, 401-retry, multipart-opplasting. |
| [src/skills/](src/skills/) | 18 regnskapsflyter som MCP prompts, pluss ressursen `tripletex://skills`. |

### Autentiseringsflyt

Tripletex bruker ikke én API-nøkkel — applikasjonen identifiseres med **consumer token**, brukeren med **employee token**, og hvert faktisk API-kall signeres med en kortlevd **session token**. MCP-serveren håndterer hele vekslingen transparent:

```mermaid
sequenceDiagram
  participant MCP as MCP-tool (f.eks. create_invoice)
  participant C as TripletexClient
  participant TT as Tripletex v2

  MCP->>C: client.post("/invoice", body)
  C->>C: ensureSession()

  alt Ingen gyldig session
    C->>TT: PUT /token/session/:create<br/>(consumer + employee token)
    TT-->>C: { token, expiresAt = i morgen }
    C->>C: cache session
  end

  C->>TT: POST /invoice<br/>Authorization: Basic 0:sessionToken
  alt 401 Unauthorized
    C->>C: session = null
    C->>TT: PUT /token/session/:create (ny)
    TT-->>C: ny session
    C->>TT: POST /invoice (retry)
  end
  TT-->>C: 200 OK + JSON
  C-->>MCP: parsed response
```

## Hva kan den gjøre?

**56 MCP-verktøy** fordelt på 9 kategorier (per **v2.4.0**, synket med [Regnskapsagent](https://regnskapsagent.no)-MCP):

| Kategori | Antall | Dekker |
|---|---:|---|
| Ordrer & utgående faktura | 7 | Søk/opprett ordre, fakturering, søk fakturaer |
| Leverandørfaktura | 8 | Søk, godkjenning, oppdater posteringer, bilagsmottak |
| Kunder & leverandører | 7 | Søk, opprett, oppdater på begge sider |
| Produkter | 2 | Søk og opprett produkt |
| Bilag & hovedbok | 10 | Kontoplan, MVA, bilagstyper, bilag, vedlegg, hovedbok |
| Rapporter | 1 | Saldobalanse |
| Prosjekt, time & HR | 7 | Prosjekt, aktivitet, timer, ansatt, avdeling |
| Reise & kjøregodtgjørelse | 12 | Reiseregning, kjøring, km-satser, kostnader, approval |
| Utility | 2 | `whoami`, `search_employees` |

<details>
<summary><strong>Vis full liste over alle 56 verktøy</strong></summary>

| Kategori | Verktøy | Beskrivelse |
|---|---|---|
| **Ordrer & utgående faktura** | `search_orders` | Søk ordrer (åpne/lukkede, abonnement m.m.) |
| | `get_order` | Hent én ordre |
| | `create_order` | Opprett ordre |
| | `invoice_order` | Fakturer ordre |
| | `create_invoice` | Ordre + faktura i ett steg |
| | `search_invoices` | Søk utgående fakturaer (datointervall) |
| | `get_invoice` | Hent én faktura |
| **Leverandørfaktura** | `search_supplier_invoices` | Søk registrerte leverandørfakturaer |
| | `get_supplier_invoice` | Hent én leverandørfaktura |
| | `get_supplier_invoices_for_approval` | Liste til godkjenning |
| | `approve_supplier_invoice` | Godkjenn |
| | `reject_supplier_invoice` | Avvis |
| | `update_supplier_invoice_postings` | Oppdater posteringer på leverandørbilag |
| | `create_supplier_invoice` | Opprett leverandørbilag til bilagsmottak (`POST /ledger/voucher`, m.fl.) |
| | `get_voucher_inbox_count` | Antall i bilagsmottak |
| **Kunder & leverandører** | `search_customers` | Søk kunder |
| | `create_customer` | Opprett kunde |
| | `update_customer` | Oppdater kunde |
| | `search_suppliers` | Søk leverandører |
| | `create_supplier` | Opprett leverandør |
| | `get_supplier` | Hent leverandør |
| | `update_supplier` | Oppdater leverandør |
| **Produkter** | `search_products` | Søk produkter |
| | `create_product` | Opprett produkt |
| **Bilag & hovedbok** | `search_accounts` | Søk kontoplan |
| | `search_vat_types` | MVA-typer |
| | `search_voucher_types` | Bilagstyper |
| | `search_vouchers` | Søk bilag |
| | `get_voucher` | Hent bilag |
| | `create_voucher` | Opprett bilag |
| | `send_voucher_to_ledger` | Send bilag til bokføring |
| | `attach_voucher_document` | Vedlegg dokument (Base64) til bilag |
| | `import_ledger_voucher_document` | Importer bilag fra fil |
| | `search_ledger_postings` | Søk hovedboksposteringer |
| **Rapporter** | `get_balance_sheet` | Saldobalanse for periode |
| **Prosjekt & time** | `search_projects` | Søk prosjekter |
| | `search_activities` | Søk aktiviteter |
| | `search_time_entries` | Søk timeføringer |
| | `create_time_entry` | Logg timer |
| | `create_project` | Opprett prosjekt |
| | `create_department` | Opprett avdeling |
| **HR** | `create_employee` | Opprett ansatt |
| **Reise & kjøregodtgjørelse** | `search_travel_expenses` | Søk reiseregninger |
| | `get_travel_expense` | Hent reiseregning |
| | `create_travel_expense` | Opprett reiseregning |
| | `create_mileage_allowance` | Kjøregodtgjørelse |
| | `search_mileage_allowances` | Søk kjøregodtgjørelser |
| | `search_mileage_rates` | km-satser |
| | `search_mileage_rate_categories` | Satskategorier |
| | `deliver_travel_expense` | Lever til godkjenning |
| | `approve_travel_expense` | Godkjenn |
| | `create_travel_expense_cost` | Kostnad (parkering, bom, …) |
| | `search_travel_expense_cost_categories` | Kostnadskategorier |
| | `search_travel_expense_payment_types` | Betalingstyper |
| **Utility** | `whoami` | Sesjon / selskap |
| | `search_employees` | Søk ansatte |

</details>

## Skills (regnskapsflyter)

I tillegg til verktøyene eksponerer serveren **18 regnskapsflyter** som MCP prompts — norsk-språklige playbooks som hjelper LLM-en å kjøre vanlige operasjoner i riktig rekkefølge, med korrekt MVA-håndtering og validering underveis. Flyter er indeksert som ressursen `tripletex://skills` slik at klienten kan slå opp triggere automatisk.

| Tier | Skill-id | Flyt | Typiske triggere |
|---|---|---|---|
| Core | `create-invoice` | Opprett utgående faktura med korrekt MVA | faktura, invoice, fakturere, utgående faktura |
| Core | `post-voucher` | Bilagsføring med debet/kredit og NS 4102-kontoplan | bilag, voucher, bokføring, postering |
| Core | `register-supplier-invoice` | Registrer leverandørfaktura (inkl. bilagsmottak) | leverandørfaktura, inngående faktura, bilagsmottak |
| Core | `customer-management` | Søk, opprett og oppdater kunder | kunde, ny kunde, kundeoppslag |
| Common | `time-to-invoice` | Konverter loggede timer til faktura | timer til faktura, fakturere timer |
| Common | `credit-note` | Utsted kreditnota på eksisterende faktura | kreditnota, kreditere, tilbakebetaling faktura |
| Common | `balance-check` | Saldobalanse og kontooversikt for periode | saldobalanse, kontooversikt, periode avslutning |
| Common | `create-product` | Opprett produkt for ordre/faktura | produkt, vare, tjeneste |
| Common | `register-payment` | Registrer innbetaling/utbetaling | betaling, innbetaling, utbetaling |
| Common | `create-employee` | Onboard ansatt med norske krav | ansatt, ny ansatt, onboarding |
| Common | `create-project` | Opprett prosjekt for timer/fakturering | prosjekt, nytt prosjekt |
| Common | `create-departments` | Opprett avdeling/kostnadssted | avdeling, department, kostnadssted |
| Advanced | `run-payroll` | Lønnskjøring med skatt og arbeidsgiveravgift | lønn, payroll, lønnsberegning |
| Advanced | `year-end-closing` | Årsoppgjør etter norsk regnskapslov | årsoppgjør, årsregnskap, årsavslutning |
| Advanced | `month-end-closing` | Månedsslutt og MVA-oppgjør | månedsslutt, mva-oppgjør, terminoppgave |
| Advanced | `bank-reconciliation` | Bankavstemming mot konto 1920 | bankavstemming, avstemming, bankbalanse |
| Advanced | `travel-expense` | Reiseregning og kjøregodtgjørelse | reiseregning, diett, kjøregodtgjørelse |
| Advanced | `receipt-expense` | Utlegg / kvittering mot konto 2930 | utlegg, kvittering, refusjon |

Full kildekode for hver flyt ligger i [src/skills/](src/skills/). Registry og ressurs-definisjon: [src/skills/registry.ts](src/skills/registry.ts).

## Kom i gang

### 1. Hent API-nøkler fra Tripletex

Du trenger to tokens:

- **Consumer token** — søk om produksjonstilgang via [developer.tripletex.no](https://developer.tripletex.no). Godkjenning tar typisk 2–3 uker. For testing kan du opprette en gratis testkonto med egne tokens.
- **Employee token** — opprettes i Tripletex under **Innstillinger → Integrasjoner → API-tilgang** av en bruker med admin-rettigheter.

### 2. Installer

```bash
git clone https://github.com/cwv-ventures/tripletex-mcp.git
cd tripletex-mcp
npm install
npm run build
```

### 3. Koble til Claude Desktop

Legg til følgende i Claude Desktop sin konfigurasjonsfil:

**macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
**Linux:** `~/.config/claude-desktop/claude_desktop_config.json`

```json
{
  "mcpServers": {
    "tripletex": {
      "command": "node",
      "args": ["/absolutt/sti/til/tripletex-mcp/dist/index.js"],
      "env": {
        "TRIPLETEX_CONSUMER_TOKEN": "din-consumer-token",
        "TRIPLETEX_EMPLOYEE_TOKEN": "din-employee-token"
      }
    }
  }
}
```

### 4. Testmiljø

For å bruke Tripletex sitt testmiljø (`api-test.tripletex.tech`) istedenfor produksjon, legg til:

```json
"TRIPLETEX_ENV": "test"
```

i `env`-blokken.

## Hvordan autentisering fungerer

Serveren håndterer alt automatisk:

1. Ved første kall opprettes en session token via `PUT /v2/token/session/:create`
2. Session token fornyes automatisk når den utløper (midnatt CET)
3. Alle API-kall bruker Basic Auth med brukernavn `0` og session token som passord

Du trenger ikke tenke på dette — bare sett consumer og employee token som miljøvariabler. Se [autentiseringsflyten](#autentiseringsflyt) over for detaljer.

## Eksempler på bruk

Når MCP-serveren er koblet til Claude, kan du si ting som:

> "Logg 7.5 timer på prosjekt Konsulentbistand i dag"

Claude finner prosjektet, velger riktig aktivitet, og oppretter timeoppføringen.

> "Vis alle fakturaer til Nordvik Bygg fra mars 2026"

Claude søker kunder, finner riktig ID, og henter fakturaene.

> "Opprett ny kunde Havbruk Nord AS med org.nr 912 345 678"

Claude oppretter kunden direkte i Tripletex.

> "Hvilke bilag ble ført forrige uke?"

Claude søker bilag med datofilter og viser en oversikt.

> "Registrer kjøring fra Oslo til Drammen i dag, 42 km, personbil"

Claude slår opp satskategori for personbil, oppretter en reiseregning, legger til kjøregodtgjørelse med riktig sats, og rapporterer totalbeløp.

> "Jeg kjørte til Ski i dag, 48 km. Hadde 85 kr i bompenger og 120 kr parkering"

Claude oppretter reiseregning med kjøregodtgjørelse pluss kostnadsrader for bompenger og parkering.

## Kvalitetssikring

Dette er en fakta-orientert oversikt over hvordan serveren er bygget — tenkt som referanse for fagpersoner og ledelse.

- **PRD-samsvar mot Tripletex v2.** Tynn proxy, ingen felt-aliaser: `count` (ikke `quantity`), `unitPriceExcludingVatCurrency`/`unitPriceIncludingVatCurrency`, `isPrioritizeAmountsIncludingVat`, `vendorInvoiceNumber`, `amountGross`/`amountGrossCurrency`, `termOfPayment`, og action-endepunkter med kolon-prefiks (`:invoice`, `:sendToLedger`, `:deliver`, `:approve`). Referanser wrappes til `{ id: N }` i transform-laget — utad eksponeres bare `customerId`, `vatTypeId`, osv.
- **Eksklusive to-datoer er dokumentert** i tool-beskrivelsene for `search_supplier_invoices`, `search_vouchers` m.fl. slik at LLM-en unngår den klassiske av-for-én-feilen.
- **Feilhåndtering for LLM self-correction.** Alle Tripletex-feil returneres rått som JSON `{ httpStatus, tripletexResponse }`, ikke som kastede exceptions. LLM-en ser validation-meldinger direkte og kan rette kallet uten menneskelig intervensjon.
- **Autentisering.** Consumer + employee token byttes til en session token som caches til midnatt CET. 401 trigger automatisk fornyelse og én retry. Begge tokens leses fra miljøvariabler (`TRIPLETEX_CONSUMER_TOKEN`, `TRIPLETEX_EMPLOYEE_TOKEN`).
- **Domenekunnskap isolert fra tool-laget.** Forretningsregler som «balanserende kredittpost på konto 2400 for leverandørfaktura» ligger i [src/tripletex-transform.ts](src/tripletex-transform.ts), ikke spredt utover tool-definisjonene.
- **Multi-tenant klar.** `TripletexClient` har både env-basert konstruktør (stdio MCP) og `TripletexClientOptions` for programmatisk bruk — samme kodebase brukes av den hostede Regnskapsagent-MCP-en.
- **Typesikkerhet.** TypeScript `strict` + `Node16` modulmodus. Alle tool-inputs er definert med Zod-schemas og ender som typede argumenter i handlerne.
- **Multipart-opplasting** (`attach_voucher_document`, `import_ledger_voucher_document`) validerer Base64 og håndhever 8 MB-grense før nettkall — beskytter både klient og Tripletex.
- **Optimistisk låsing** på `send_voucher_to_ledger` via `version`-parameter, for å hindre race conditions ved parallell bokføring.
- **Versjon er pinnet** til `2.4.0` i både [src/index.ts](src/index.ts) og [package.json](package.json).
- **Transport** er stdio per MCP-spesifikasjonen; SDK `@modelcontextprotocol/sdk ^1.12.1`.

### Kjent scope (roadmap)

- Ingen automatiserte tester ennå — transform-funksjonene i [src/tripletex-transform.ts](src/tripletex-transform.ts) er første kandidater for enhetstester.
- Ingen eksplisitt 429/backoff-logikk (Tripletex har 5000 req/time; dagens retry dekker kun 401).
- `count`-parameter cappes ikke eksplisitt mot Tripletex' maks (1000).
- Ingen `CHANGELOG.md` — endringer spores i git-historikken.

## Teknisk

- **Arkitektonisk referanse:** [docs/PRD-Tripletex-MCP-Rebuild.md](docs/PRD-Tripletex-MCP-Rebuild.md) — mål-API, DTO-tabeller, feltmapping mot Tripletex v2.
- **Tool-registreringer:** [src/tripletex-tools.ts](src/tripletex-tools.ts) — alle 56 `server.tool(...)`, delt oppsett med Regnskapsagent via `registerAllTools(server, client)`.
- **MCP skills (prompts):** [src/skills/](src/skills/) + ressursen `tripletex://skills`.
- **Runtime:** Node.js 18+
- **Språk:** TypeScript (strict)
- **Avhengigheter:** `@modelcontextprotocol/sdk ^1.12.1`, `zod ^4`
- **Transport:** stdio (standard MCP-protokoll)
- **API:** Tripletex REST API v2 (`tripletex.no/v2` / `api-test.tripletex.tech/v2`)

## Bidra

Pull requests er velkomne! Åpne gjerne et issue hvis du har forslag til nye verktøy eller forbedringer.

## Testing

Tests use [Vitest](https://vitest.dev/) and focus first on the pure transform functions in `src/tripletex-transform.ts` — request-body builders that mirror the Tripletex v2 DTO shapes exactly.

### Commands

- `npm test` — run the full test suite once
- `npm run test:watch` — watch mode, re-run on file change
- `npm run test:coverage` — run with coverage report (V8 provider, HTML + LCOV output in `coverage/`)

### Scope

The current suite covers every exported function in `src/tripletex-transform.ts`:

- `transformOrderLine`
- `buildOrderBody`
- `transformVoucherPosting`
- `buildSupplierInvoiceVoucherBody` — including the balancing-credit invariant (sum of `amountGross` across all postings equals zero)
- `wrapPostingsForSupplierInvoiceUpdate`

Client-level tests (auth, retries, HTTP transport) are intentionally deferred — those require mocking the Tripletex API and live in a follow-up. See `tests/README.md` for contributor conventions.

### CI

GitHub Actions runs typecheck, tests, and build on every pull request and push to `main`. See `.github/workflows/test.yml`.

## Lisens

MIT — se [LICENSE](LICENSE) for detaljer.