tripletex-mcp-server 1.0.0

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.
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { z } from "zod";
5
+ import { TripletexClient } from "./tripletex-client.js";
6
+ const server = new McpServer({ name: "tripletex-mcp-server", version: "1.0.0" });
7
+ function getClient() {
8
+ const token = process.env.TRIPLETEX_SESSION_TOKEN;
9
+ if (!token)
10
+ throw new Error("TRIPLETEX_SESSION_TOKEN is required. Create one at tripletex.no → Company settings → API access.");
11
+ return new TripletexClient(token);
12
+ }
13
+ function json(data) { return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] }; }
14
+ server.tool("list_invoices", "List invoices.", { invoiceDateFrom: z.string().optional(), invoiceDateTo: z.string().optional(), count: z.string().optional() }, async (p) => json(await getClient().listInvoices(p)));
15
+ server.tool("get_invoice", "Get invoice details.", { id: z.string() }, async ({ id }) => json(await getClient().getInvoice(id)));
16
+ server.tool("send_invoice", "Send invoice via email.", { id: z.string(), sendType: z.string().optional().describe("EMAIL or EHF") }, async ({ id, sendType }) => json(await getClient().sendInvoice(id, sendType)));
17
+ server.tool("list_customers", "Search customers.", { name: z.string().optional(), count: z.string().optional() }, async (p) => json(await getClient().listCustomers(p)));
18
+ server.tool("get_customer", "Get customer details.", { id: z.string() }, async ({ id }) => json(await getClient().getCustomer(id)));
19
+ server.tool("create_customer", "Create a customer.", {
20
+ name: z.string(), email: z.string().optional(), organizationNumber: z.string().optional(), phone: z.string().optional(),
21
+ address: z.string().optional(), postalCode: z.string().optional(), city: z.string().optional(),
22
+ }, async ({ name, email, organizationNumber, phone, address, postalCode, city }) => json(await getClient().createCustomer({ name, email, organizationNumber, phoneNumber: phone, postalAddress: address ? { addressLine1: address, postalCode, city } : undefined })));
23
+ server.tool("list_suppliers", "List suppliers.", { count: z.string().optional() }, async (p) => json(await getClient().listSuppliers(p)));
24
+ server.tool("list_supplier_invoices", "List supplier invoices.", { invoiceDateFrom: z.string().optional(), count: z.string().optional() }, async (p) => json(await getClient().listSupplierInvoices(p)));
25
+ server.tool("list_ledger_entries", "List ledger postings.", { dateFrom: z.string().optional(), dateTo: z.string().optional(), count: z.string().optional() }, async (p) => json(await getClient().listLedgerEntries(p)));
26
+ server.tool("create_voucher", "Create a journal voucher.", {
27
+ date: z.string(), description: z.string().optional(),
28
+ postings: z.array(z.object({ accountId: z.number(), amount: z.number(), description: z.string().optional() })),
29
+ }, async ({ date, description, postings }) => json(await getClient().createVoucher({ date, description, postings: postings.map(p => ({ account: { id: p.accountId }, amount: p.amount, description: p.description })) })));
30
+ server.tool("list_accounts", "Get chart of accounts.", { count: z.string().optional() }, async (p) => json(await getClient().listAccounts(p)));
31
+ server.tool("list_projects", "List projects.", { count: z.string().optional() }, async (p) => json(await getClient().listProjects(p)));
32
+ server.tool("list_employees", "List employees.", { count: z.string().optional() }, async (p) => json(await getClient().listEmployees(p)));
33
+ server.tool("list_products", "List products.", { count: z.string().optional() }, async (p) => json(await getClient().listProducts(p)));
34
+ server.tool("get_company_info", "Get company info.", {}, async () => json(await getClient().getCompany()));
35
+ async function main() { await server.connect(new StdioServerTransport()); }
36
+ main().catch((e) => { console.error("Server error:", e); process.exit(1); });
@@ -0,0 +1,83 @@
1
+ export declare class TripletexClient {
2
+ private sessionToken;
3
+ constructor(sessionToken: string);
4
+ private request;
5
+ listInvoices(params?: {
6
+ invoiceDateFrom?: string;
7
+ invoiceDateTo?: string;
8
+ from?: string;
9
+ count?: string;
10
+ }): Promise<unknown>;
11
+ getInvoice(id: string): Promise<unknown>;
12
+ createInvoice(invoice: {
13
+ invoiceDate: string;
14
+ invoiceDueDate: string;
15
+ orders: Array<{
16
+ id: number;
17
+ }>;
18
+ }): Promise<unknown>;
19
+ sendInvoice(id: string, sendType?: string): Promise<unknown>;
20
+ listCustomers(params?: {
21
+ name?: string;
22
+ from?: string;
23
+ count?: string;
24
+ }): Promise<unknown>;
25
+ getCustomer(id: string): Promise<unknown>;
26
+ createCustomer(c: {
27
+ name: string;
28
+ email?: string;
29
+ organizationNumber?: string;
30
+ phoneNumber?: string;
31
+ postalAddress?: {
32
+ addressLine1?: string;
33
+ postalCode?: string;
34
+ city?: string;
35
+ country?: {
36
+ id?: number;
37
+ };
38
+ };
39
+ }): Promise<unknown>;
40
+ listSuppliers(params?: {
41
+ from?: string;
42
+ count?: string;
43
+ }): Promise<unknown>;
44
+ listSupplierInvoices(params?: {
45
+ from?: string;
46
+ count?: string;
47
+ invoiceDateFrom?: string;
48
+ }): Promise<unknown>;
49
+ listLedgerEntries(params?: {
50
+ dateFrom?: string;
51
+ dateTo?: string;
52
+ from?: string;
53
+ count?: string;
54
+ }): Promise<unknown>;
55
+ createVoucher(v: {
56
+ date: string;
57
+ description?: string;
58
+ postings: Array<{
59
+ account: {
60
+ id: number;
61
+ };
62
+ amount: number;
63
+ description?: string;
64
+ }>;
65
+ }): Promise<unknown>;
66
+ listAccounts(params?: {
67
+ from?: string;
68
+ count?: string;
69
+ }): Promise<unknown>;
70
+ listProjects(params?: {
71
+ from?: string;
72
+ count?: string;
73
+ }): Promise<unknown>;
74
+ listEmployees(params?: {
75
+ from?: string;
76
+ count?: string;
77
+ }): Promise<unknown>;
78
+ getCompany(): Promise<unknown>;
79
+ listProducts(params?: {
80
+ from?: string;
81
+ count?: string;
82
+ }): Promise<unknown>;
83
+ }
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Tripletex REST API client (Norwegian ERP/accounting).
3
+ * API docs: https://tripletex.no/v2-docs
4
+ * Auth: Basic auth with sessionToken (0:sessionToken)
5
+ */
6
+ const BASE_URL = "https://tripletex.no/v2";
7
+ export class TripletexClient {
8
+ sessionToken;
9
+ constructor(sessionToken) {
10
+ this.sessionToken = sessionToken;
11
+ }
12
+ async request(method, path, body, params) {
13
+ const url = new URL(`${BASE_URL}${path}`);
14
+ if (params)
15
+ for (const [k, v] of Object.entries(params)) {
16
+ if (v)
17
+ url.searchParams.set(k, v);
18
+ }
19
+ const res = await fetch(url.toString(), {
20
+ method, headers: { Authorization: `Basic ${Buffer.from(`0:${this.sessionToken}`).toString("base64")}`, "Content-Type": "application/json", Accept: "application/json" },
21
+ body: body ? JSON.stringify(body) : undefined,
22
+ });
23
+ if (!res.ok)
24
+ throw new Error(`Tripletex API error ${res.status}: ${await res.text()}`);
25
+ return res.json();
26
+ }
27
+ async listInvoices(params) { return this.request("GET", "/invoice", undefined, params); }
28
+ async getInvoice(id) { return this.request("GET", `/invoice/${id}`); }
29
+ async createInvoice(invoice) { return this.request("POST", "/invoice", invoice); }
30
+ async sendInvoice(id, sendType = "EMAIL") { return this.request("PUT", `/invoice/${id}/:send`, { sendType }); }
31
+ async listCustomers(params) { return this.request("GET", "/customer", undefined, params); }
32
+ async getCustomer(id) { return this.request("GET", `/customer/${id}`); }
33
+ async createCustomer(c) { return this.request("POST", "/customer", c); }
34
+ async listSuppliers(params) { return this.request("GET", "/supplier", undefined, params); }
35
+ async listSupplierInvoices(params) { return this.request("GET", "/supplierInvoice", undefined, params); }
36
+ async listLedgerEntries(params) { return this.request("GET", "/ledger/posting", undefined, params); }
37
+ async createVoucher(v) { return this.request("POST", "/ledger/voucher", v); }
38
+ async listAccounts(params) { return this.request("GET", "/ledger/account", undefined, params); }
39
+ async listProjects(params) { return this.request("GET", "/project", undefined, params); }
40
+ async listEmployees(params) { return this.request("GET", "/employee", undefined, params); }
41
+ async getCompany() { return this.request("GET", "/company"); }
42
+ async listProducts(params) { return this.request("GET", "/product", undefined, params); }
43
+ }
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "tripletex-mcp-server",
3
+ "version": "1.0.0",
4
+ "description": "MCP server for Tripletex — Norwegian ERP and accounting platform. Manage invoices, customers, employees, projects, and more via AI agents.",
5
+ "main": "dist/index.js",
6
+ "bin": {
7
+ "tripletex-mcp-server": "dist/index.js"
8
+ },
9
+ "scripts": {
10
+ "build": "tsc",
11
+ "start": "node dist/index.js"
12
+ },
13
+ "keywords": [
14
+ "mcp",
15
+ "tripletex",
16
+ "accounting",
17
+ "erp",
18
+ "norway",
19
+ "norwegian",
20
+ "regnskap",
21
+ "model-context-protocol"
22
+ ],
23
+ "author": "Viggo Johansson",
24
+ "license": "MIT",
25
+ "type": "module",
26
+ "dependencies": {
27
+ "@modelcontextprotocol/sdk": "^1.29.0",
28
+ "zod": "^4.3.6"
29
+ },
30
+ "devDependencies": {
31
+ "@types/node": "^25.5.0",
32
+ "typescript": "^6.0.2"
33
+ }
34
+ }
package/src/index.ts ADDED
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { z } from "zod";
5
+ import { TripletexClient } from "./tripletex-client.js";
6
+
7
+ const server = new McpServer({ name: "tripletex-mcp-server", version: "1.0.0" });
8
+ function getClient(): TripletexClient {
9
+ const token = process.env.TRIPLETEX_SESSION_TOKEN;
10
+ if (!token) throw new Error("TRIPLETEX_SESSION_TOKEN is required. Create one at tripletex.no → Company settings → API access.");
11
+ return new TripletexClient(token);
12
+ }
13
+ function json(data: unknown) { return { content: [{ type: "text" as const, text: JSON.stringify(data, null, 2) }] }; }
14
+
15
+ server.tool("list_invoices", "List invoices.", { invoiceDateFrom: z.string().optional(), invoiceDateTo: z.string().optional(), count: z.string().optional() }, async (p) => json(await getClient().listInvoices(p)));
16
+ server.tool("get_invoice", "Get invoice details.", { id: z.string() }, async ({ id }) => json(await getClient().getInvoice(id)));
17
+ server.tool("send_invoice", "Send invoice via email.", { id: z.string(), sendType: z.string().optional().describe("EMAIL or EHF") }, async ({ id, sendType }) => json(await getClient().sendInvoice(id, sendType)));
18
+ server.tool("list_customers", "Search customers.", { name: z.string().optional(), count: z.string().optional() }, async (p) => json(await getClient().listCustomers(p)));
19
+ server.tool("get_customer", "Get customer details.", { id: z.string() }, async ({ id }) => json(await getClient().getCustomer(id)));
20
+ server.tool("create_customer", "Create a customer.", {
21
+ name: z.string(), email: z.string().optional(), organizationNumber: z.string().optional(), phone: z.string().optional(),
22
+ address: z.string().optional(), postalCode: z.string().optional(), city: z.string().optional(),
23
+ }, async ({ name, email, organizationNumber, phone, address, postalCode, city }) => json(await getClient().createCustomer({ name, email, organizationNumber, phoneNumber: phone, postalAddress: address ? { addressLine1: address, postalCode, city } : undefined })));
24
+ server.tool("list_suppliers", "List suppliers.", { count: z.string().optional() }, async (p) => json(await getClient().listSuppliers(p)));
25
+ server.tool("list_supplier_invoices", "List supplier invoices.", { invoiceDateFrom: z.string().optional(), count: z.string().optional() }, async (p) => json(await getClient().listSupplierInvoices(p)));
26
+ server.tool("list_ledger_entries", "List ledger postings.", { dateFrom: z.string().optional(), dateTo: z.string().optional(), count: z.string().optional() }, async (p) => json(await getClient().listLedgerEntries(p)));
27
+ server.tool("create_voucher", "Create a journal voucher.", {
28
+ date: z.string(), description: z.string().optional(),
29
+ postings: z.array(z.object({ accountId: z.number(), amount: z.number(), description: z.string().optional() })),
30
+ }, async ({ date, description, postings }) => json(await getClient().createVoucher({ date, description, postings: postings.map(p => ({ account: { id: p.accountId }, amount: p.amount, description: p.description })) })));
31
+ server.tool("list_accounts", "Get chart of accounts.", { count: z.string().optional() }, async (p) => json(await getClient().listAccounts(p)));
32
+ server.tool("list_projects", "List projects.", { count: z.string().optional() }, async (p) => json(await getClient().listProjects(p)));
33
+ server.tool("list_employees", "List employees.", { count: z.string().optional() }, async (p) => json(await getClient().listEmployees(p)));
34
+ server.tool("list_products", "List products.", { count: z.string().optional() }, async (p) => json(await getClient().listProducts(p)));
35
+ server.tool("get_company_info", "Get company info.", {}, async () => json(await getClient().getCompany()));
36
+
37
+ async function main() { await server.connect(new StdioServerTransport()); }
38
+ main().catch((e) => { console.error("Server error:", e); process.exit(1); });
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Tripletex REST API client (Norwegian ERP/accounting).
3
+ * API docs: https://tripletex.no/v2-docs
4
+ * Auth: Basic auth with sessionToken (0:sessionToken)
5
+ */
6
+ const BASE_URL = "https://tripletex.no/v2";
7
+
8
+ export class TripletexClient {
9
+ constructor(private sessionToken: string) {}
10
+
11
+ private async request<T>(method: string, path: string, body?: unknown, params?: Record<string, string>): Promise<T> {
12
+ const url = new URL(`${BASE_URL}${path}`);
13
+ if (params) for (const [k, v] of Object.entries(params)) { if (v) url.searchParams.set(k, v); }
14
+ const res = await fetch(url.toString(), {
15
+ method, headers: { Authorization: `Basic ${Buffer.from(`0:${this.sessionToken}`).toString("base64")}`, "Content-Type": "application/json", Accept: "application/json" },
16
+ body: body ? JSON.stringify(body) : undefined,
17
+ });
18
+ if (!res.ok) throw new Error(`Tripletex API error ${res.status}: ${await res.text()}`);
19
+ return res.json() as Promise<T>;
20
+ }
21
+
22
+ async listInvoices(params?: { invoiceDateFrom?: string; invoiceDateTo?: string; from?: string; count?: string }) { return this.request<unknown>("GET", "/invoice", undefined, params); }
23
+ async getInvoice(id: string) { return this.request<unknown>("GET", `/invoice/${id}`); }
24
+ async createInvoice(invoice: { invoiceDate: string; invoiceDueDate: string; orders: Array<{ id: number }> }) { return this.request<unknown>("POST", "/invoice", invoice); }
25
+ async sendInvoice(id: string, sendType: string = "EMAIL") { return this.request<unknown>("PUT", `/invoice/${id}/:send`, { sendType }); }
26
+
27
+ async listCustomers(params?: { name?: string; from?: string; count?: string }) { return this.request<unknown>("GET", "/customer", undefined, params); }
28
+ async getCustomer(id: string) { return this.request<unknown>("GET", `/customer/${id}`); }
29
+ async createCustomer(c: { name: string; email?: string; organizationNumber?: string; phoneNumber?: string; postalAddress?: { addressLine1?: string; postalCode?: string; city?: string; country?: { id?: number } } }) { return this.request<unknown>("POST", "/customer", c); }
30
+
31
+ async listSuppliers(params?: { from?: string; count?: string }) { return this.request<unknown>("GET", "/supplier", undefined, params); }
32
+ async listSupplierInvoices(params?: { from?: string; count?: string; invoiceDateFrom?: string }) { return this.request<unknown>("GET", "/supplierInvoice", undefined, params); }
33
+
34
+ async listLedgerEntries(params?: { dateFrom?: string; dateTo?: string; from?: string; count?: string }) { return this.request<unknown>("GET", "/ledger/posting", undefined, params); }
35
+ async createVoucher(v: { date: string; description?: string; postings: Array<{ account: { id: number }; amount: number; description?: string }> }) { return this.request<unknown>("POST", "/ledger/voucher", v); }
36
+ async listAccounts(params?: { from?: string; count?: string }) { return this.request<unknown>("GET", "/ledger/account", undefined, params); }
37
+
38
+ async listProjects(params?: { from?: string; count?: string }) { return this.request<unknown>("GET", "/project", undefined, params); }
39
+ async listEmployees(params?: { from?: string; count?: string }) { return this.request<unknown>("GET", "/employee", undefined, params); }
40
+ async getCompany() { return this.request<unknown>("GET", "/company"); }
41
+ async listProducts(params?: { from?: string; count?: string }) { return this.request<unknown>("GET", "/product", undefined, params); }
42
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,15 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "Node16",
5
+ "moduleResolution": "Node16",
6
+ "outDir": "dist",
7
+ "rootDir": "src",
8
+ "strict": true,
9
+ "esModuleInterop": true,
10
+ "skipLibCheck": true,
11
+ "declaration": true,
12
+ "types": ["node"]
13
+ },
14
+ "include": ["src/**/*"]
15
+ }