@frihet/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.
- package/LICENSE +21 -0
- package/README.md +271 -0
- package/dist/client.d.ts +71 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +225 -0
- package/dist/client.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +52 -0
- package/dist/index.js.map +1 -0
- package/dist/tools/clients.d.ts +7 -0
- package/dist/tools/clients.d.ts.map +1 -0
- package/dist/tools/clients.js +128 -0
- package/dist/tools/clients.js.map +1 -0
- package/dist/tools/expenses.d.ts +7 -0
- package/dist/tools/expenses.d.ts.map +1 -0
- package/dist/tools/expenses.js +126 -0
- package/dist/tools/expenses.js.map +1 -0
- package/dist/tools/invoices.d.ts +7 -0
- package/dist/tools/invoices.d.ts.map +1 -0
- package/dist/tools/invoices.js +185 -0
- package/dist/tools/invoices.js.map +1 -0
- package/dist/tools/products.d.ts +7 -0
- package/dist/tools/products.d.ts.map +1 -0
- package/dist/tools/products.js +127 -0
- package/dist/tools/products.js.map +1 -0
- package/dist/tools/quotes.d.ts +7 -0
- package/dist/tools/quotes.d.ts.map +1 -0
- package/dist/tools/quotes.js +134 -0
- package/dist/tools/quotes.js.map +1 -0
- package/dist/tools/shared.d.ts +23 -0
- package/dist/tools/shared.d.ts.map +1 -0
- package/dist/tools/shared.js +60 -0
- package/dist/tools/shared.js.map +1 -0
- package/dist/tools/webhooks.d.ts +7 -0
- package/dist/tools/webhooks.d.ts.map +1 -0
- package/dist/tools/webhooks.js +123 -0
- package/dist/tools/webhooks.js.map +1 -0
- package/dist/types.d.ts +110 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/package.json +60 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 BRTHLS
|
|
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.md
ADDED
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="./assets/banner.svg" alt="frihet-mcp" width="100%"/>
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<strong>The first AI-native MCP server for a Spanish ERP.</strong><br/>
|
|
7
|
+
<em>El primer servidor MCP nativo para un ERP espanol.</em>
|
|
8
|
+
</p>
|
|
9
|
+
|
|
10
|
+
<p align="center">
|
|
11
|
+
<a href="https://www.npmjs.com/package/@frihet/mcp-server"><img src="https://img.shields.io/npm/v/@frihet/mcp-server?style=flat&color=18181b&labelColor=09090b" alt="npm"></a>
|
|
12
|
+
<a href="https://github.com/berthelius/frihet-mcp/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-18181b?style=flat&labelColor=09090b" alt="license"></a>
|
|
13
|
+
<a href="https://smithery.ai/server/@frihet/mcp-server"><img src="https://img.shields.io/badge/smithery-listed-18181b?style=flat&labelColor=09090b" alt="smithery"></a>
|
|
14
|
+
<a href="https://frihet.io"><img src="https://img.shields.io/badge/frihet.io-ERP-18181b?style=flat&labelColor=09090b" alt="frihet"></a>
|
|
15
|
+
</p>
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## What is this
|
|
20
|
+
|
|
21
|
+
An MCP server that connects your AI assistant to [Frihet ERP](https://frihet.io). Create invoices by talking. Query expenses in natural language. Manage your entire business from your IDE.
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
You: "Create an invoice for TechStart SL, 40 hours of consulting at 75 EUR/hour, due March 1st"
|
|
25
|
+
Claude: Done. Invoice INV-2026-089 created. Total: 3,000.00 EUR + 21% IVA = 3,630.00 EUR.
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
31 tools. 6 resources. Zero boilerplate.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Install
|
|
33
|
+
|
|
34
|
+
One line. Pick your tool.
|
|
35
|
+
|
|
36
|
+
### Claude Code / Claude Desktop
|
|
37
|
+
|
|
38
|
+
```json
|
|
39
|
+
{
|
|
40
|
+
"mcpServers": {
|
|
41
|
+
"frihet": {
|
|
42
|
+
"command": "npx",
|
|
43
|
+
"args": ["-y", "@frihet/mcp-server"],
|
|
44
|
+
"env": {
|
|
45
|
+
"FRIHET_API_KEY": "fri_your_key_here"
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
| Tool | Config file |
|
|
53
|
+
|------|------------|
|
|
54
|
+
| Claude Code | `~/.claude/mcp.json` |
|
|
55
|
+
| Claude Desktop | `~/Library/Application Support/Claude/claude_desktop_config.json` |
|
|
56
|
+
| Cursor | `.cursor/mcp.json` or `~/.cursor/mcp.json` |
|
|
57
|
+
| Windsurf | `~/.windsurf/mcp.json` |
|
|
58
|
+
| Cline | VS Code settings or `.cline/mcp.json` |
|
|
59
|
+
| Codex CLI | `~/.codex/config.toml` (MCP section) |
|
|
60
|
+
|
|
61
|
+
The JSON config is identical for all tools. Only the file path changes.
|
|
62
|
+
|
|
63
|
+
### Get your API key
|
|
64
|
+
|
|
65
|
+
1. Log into [app.frihet.io](https://app.frihet.io)
|
|
66
|
+
2. Go to **Settings > API**
|
|
67
|
+
3. Click **Create API key**
|
|
68
|
+
4. Copy the key (starts with `fri_`) -- it's only shown once
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## What you can do
|
|
73
|
+
|
|
74
|
+
Talk to your ERP. These are real prompts, not marketing copy.
|
|
75
|
+
|
|
76
|
+
### Invoicing
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
"Show me all unpaid invoices"
|
|
80
|
+
"Create an invoice for Acme SL with 10h of consulting at 95/hour"
|
|
81
|
+
"Mark invoice abc123 as paid"
|
|
82
|
+
"How much has ClientName been invoiced this year?"
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Expenses
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
"Log a 59.99 EUR expense for Adobe Creative Cloud, category: software, tax-deductible"
|
|
89
|
+
"List all expenses from January"
|
|
90
|
+
"What did I spend on travel last quarter?"
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Clients
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
"Add a new client: TechStart SL, NIF B12345678, email admin@techstart.es"
|
|
97
|
+
"Show me all my clients"
|
|
98
|
+
"Update ClientName's address to Calle Mayor 1, Madrid 28001"
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Quotes
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
"Create a quote for Design Studio: logo design (2000 EUR) + brand guidelines (3500 EUR)"
|
|
105
|
+
"Show me all pending quotes"
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Webhooks
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
"Set up a webhook to notify https://my-app.com/hook when invoices are paid"
|
|
112
|
+
"List all my active webhooks"
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## Tools reference
|
|
118
|
+
|
|
119
|
+
### Invoices / Facturas
|
|
120
|
+
|
|
121
|
+
| Tool | What it does |
|
|
122
|
+
|------|-------------|
|
|
123
|
+
| `list_invoices` | List invoices with pagination |
|
|
124
|
+
| `get_invoice` | Get full invoice details by ID |
|
|
125
|
+
| `create_invoice` | Create a new invoice with line items |
|
|
126
|
+
| `update_invoice` | Update any invoice field |
|
|
127
|
+
| `delete_invoice` | Permanently delete an invoice |
|
|
128
|
+
| `search_invoices` | Find invoices by client name |
|
|
129
|
+
|
|
130
|
+
### Expenses / Gastos
|
|
131
|
+
|
|
132
|
+
| Tool | What it does |
|
|
133
|
+
|------|-------------|
|
|
134
|
+
| `list_expenses` | List expenses with pagination |
|
|
135
|
+
| `get_expense` | Get expense details |
|
|
136
|
+
| `create_expense` | Record a new expense |
|
|
137
|
+
| `update_expense` | Modify an expense |
|
|
138
|
+
| `delete_expense` | Delete an expense |
|
|
139
|
+
|
|
140
|
+
### Clients / Clientes
|
|
141
|
+
|
|
142
|
+
| Tool | What it does |
|
|
143
|
+
|------|-------------|
|
|
144
|
+
| `list_clients` | List all clients |
|
|
145
|
+
| `get_client` | Get client details |
|
|
146
|
+
| `create_client` | Register a new client |
|
|
147
|
+
| `update_client` | Update client info |
|
|
148
|
+
| `delete_client` | Remove a client |
|
|
149
|
+
|
|
150
|
+
### Products / Productos
|
|
151
|
+
|
|
152
|
+
| Tool | What it does |
|
|
153
|
+
|------|-------------|
|
|
154
|
+
| `list_products` | List products and services |
|
|
155
|
+
| `get_product` | Get product details |
|
|
156
|
+
| `create_product` | Add a product or service |
|
|
157
|
+
| `update_product` | Update pricing or details |
|
|
158
|
+
| `delete_product` | Remove a product |
|
|
159
|
+
|
|
160
|
+
### Quotes / Presupuestos
|
|
161
|
+
|
|
162
|
+
| Tool | What it does |
|
|
163
|
+
|------|-------------|
|
|
164
|
+
| `list_quotes` | List all quotes |
|
|
165
|
+
| `get_quote` | Get quote details |
|
|
166
|
+
| `create_quote` | Draft a new quote |
|
|
167
|
+
| `update_quote` | Modify a quote |
|
|
168
|
+
| `delete_quote` | Delete a quote |
|
|
169
|
+
|
|
170
|
+
### Webhooks
|
|
171
|
+
|
|
172
|
+
| Tool | What it does |
|
|
173
|
+
|------|-------------|
|
|
174
|
+
| `list_webhooks` | List configured webhooks |
|
|
175
|
+
| `get_webhook` | Get webhook details |
|
|
176
|
+
| `create_webhook` | Register a new webhook endpoint |
|
|
177
|
+
| `update_webhook` | Modify events or URL |
|
|
178
|
+
| `delete_webhook` | Remove a webhook |
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## How it works
|
|
183
|
+
|
|
184
|
+
```
|
|
185
|
+
Your AI assistant frihet-mcp Frihet API
|
|
186
|
+
| | |
|
|
187
|
+
|-- "create invoice" --> | |
|
|
188
|
+
| |-- POST /invoices ->|
|
|
189
|
+
| |<-- 201 Created ----|
|
|
190
|
+
|<-- "Invoice created" --| |
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
The MCP server translates natural language tool calls into REST API requests. It handles authentication, rate limiting (automatic retry on 429), pagination, and error mapping. You just talk.
|
|
194
|
+
|
|
195
|
+
### Environment variables
|
|
196
|
+
|
|
197
|
+
| Variable | Required | Default |
|
|
198
|
+
|----------|----------|---------|
|
|
199
|
+
| `FRIHET_API_KEY` | Yes | -- |
|
|
200
|
+
| `FRIHET_API_URL` | No | `https://api.frihet.io/v1` |
|
|
201
|
+
|
|
202
|
+
`FRIHET_API_URL` is useful if you self-host or want to point to a staging environment.
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## API limits
|
|
207
|
+
|
|
208
|
+
| Limit | Value |
|
|
209
|
+
|-------|-------|
|
|
210
|
+
| Requests per minute | 100 per API key |
|
|
211
|
+
| Results per page | 100 max (50 default) |
|
|
212
|
+
| Request body | 1 MB max |
|
|
213
|
+
| Webhook payload | 100 KB max |
|
|
214
|
+
| Webhooks per account | 20 max |
|
|
215
|
+
|
|
216
|
+
Rate limiting is handled automatically with exponential backoff. You don't need to think about it.
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## Development
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
git clone https://github.com/berthelius/frihet-mcp.git
|
|
224
|
+
cd frihet-mcp
|
|
225
|
+
npm install
|
|
226
|
+
npm run build
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
Run locally:
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
FRIHET_API_KEY=fri_xxx node dist/index.js
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Test with the [MCP Inspector](https://modelcontextprotocol.io/docs/tools/inspector):
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
npx @modelcontextprotocol/inspector node dist/index.js
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## Why Frihet MCP
|
|
244
|
+
|
|
245
|
+
| | Frihet | Holded | Billin | Quipu | Anfix |
|
|
246
|
+
|---|:---:|:---:|:---:|:---:|:---:|
|
|
247
|
+
| Official MCP server | **Yes** | No (third-party) | No | No | No |
|
|
248
|
+
| Claude / Cursor / Windsurf | **Yes** | No | No | No | No |
|
|
249
|
+
| Public REST API | **Yes** | Yes | Limited | Yes | No |
|
|
250
|
+
| Webhooks with HMAC verification | **Yes** | No | No | No | No |
|
|
251
|
+
| AI assistant built-in | **Yes** | No | No | No | No |
|
|
252
|
+
| Open source tooling | **Yes** | No | No | No | No |
|
|
253
|
+
|
|
254
|
+
No other Spanish ERP has an official MCP server. Frihet is first.
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
## Links
|
|
259
|
+
|
|
260
|
+
- [Frihet ERP](https://frihet.io) -- The product
|
|
261
|
+
- [API documentation](https://docs.frihet.io/desarrolladores/api-rest) -- REST API reference
|
|
262
|
+
- [Webhook documentation](https://docs.frihet.io/desarrolladores/webhooks) -- Events, signatures, retries
|
|
263
|
+
- [MCP specification](https://modelcontextprotocol.io) -- The protocol
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
## License
|
|
268
|
+
|
|
269
|
+
MIT. See [LICENSE](./LICENSE).
|
|
270
|
+
|
|
271
|
+
Built by [BRTHLS](https://brthls.com).
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP client wrapping the Frihet ERP REST API.
|
|
3
|
+
*
|
|
4
|
+
* Handles authentication, pagination, rate-limit retries, and error mapping.
|
|
5
|
+
*/
|
|
6
|
+
import type { PaginatedResponse } from "./types.js";
|
|
7
|
+
export declare class FrihetApiError extends Error {
|
|
8
|
+
readonly statusCode: number;
|
|
9
|
+
readonly errorCode: string;
|
|
10
|
+
constructor(statusCode: number, errorCode: string, message?: string);
|
|
11
|
+
}
|
|
12
|
+
export declare class FrihetClient {
|
|
13
|
+
private readonly apiKey;
|
|
14
|
+
private readonly baseUrl;
|
|
15
|
+
constructor(apiKey: string, baseUrl?: string);
|
|
16
|
+
private request;
|
|
17
|
+
private sleep;
|
|
18
|
+
listInvoices(params?: {
|
|
19
|
+
limit?: number;
|
|
20
|
+
offset?: number;
|
|
21
|
+
}): Promise<PaginatedResponse<Record<string, unknown>>>;
|
|
22
|
+
getInvoice(id: string): Promise<Record<string, unknown>>;
|
|
23
|
+
createInvoice(data: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
24
|
+
updateInvoice(id: string, data: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
25
|
+
deleteInvoice(id: string): Promise<void>;
|
|
26
|
+
searchInvoices(clientName: string, params?: {
|
|
27
|
+
limit?: number;
|
|
28
|
+
offset?: number;
|
|
29
|
+
}): Promise<PaginatedResponse<Record<string, unknown>>>;
|
|
30
|
+
listExpenses(params?: {
|
|
31
|
+
limit?: number;
|
|
32
|
+
offset?: number;
|
|
33
|
+
}): Promise<PaginatedResponse<Record<string, unknown>>>;
|
|
34
|
+
getExpense(id: string): Promise<Record<string, unknown>>;
|
|
35
|
+
createExpense(data: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
36
|
+
updateExpense(id: string, data: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
37
|
+
deleteExpense(id: string): Promise<void>;
|
|
38
|
+
listClients(params?: {
|
|
39
|
+
limit?: number;
|
|
40
|
+
offset?: number;
|
|
41
|
+
}): Promise<PaginatedResponse<Record<string, unknown>>>;
|
|
42
|
+
getClient(id: string): Promise<Record<string, unknown>>;
|
|
43
|
+
createClient(data: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
44
|
+
updateClient(id: string, data: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
45
|
+
deleteClient(id: string): Promise<void>;
|
|
46
|
+
listProducts(params?: {
|
|
47
|
+
limit?: number;
|
|
48
|
+
offset?: number;
|
|
49
|
+
}): Promise<PaginatedResponse<Record<string, unknown>>>;
|
|
50
|
+
getProduct(id: string): Promise<Record<string, unknown>>;
|
|
51
|
+
createProduct(data: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
52
|
+
updateProduct(id: string, data: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
53
|
+
deleteProduct(id: string): Promise<void>;
|
|
54
|
+
listQuotes(params?: {
|
|
55
|
+
limit?: number;
|
|
56
|
+
offset?: number;
|
|
57
|
+
}): Promise<PaginatedResponse<Record<string, unknown>>>;
|
|
58
|
+
getQuote(id: string): Promise<Record<string, unknown>>;
|
|
59
|
+
createQuote(data: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
60
|
+
updateQuote(id: string, data: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
61
|
+
deleteQuote(id: string): Promise<void>;
|
|
62
|
+
listWebhooks(params?: {
|
|
63
|
+
limit?: number;
|
|
64
|
+
offset?: number;
|
|
65
|
+
}): Promise<PaginatedResponse<Record<string, unknown>>>;
|
|
66
|
+
getWebhook(id: string): Promise<Record<string, unknown>>;
|
|
67
|
+
createWebhook(data: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
68
|
+
updateWebhook(id: string, data: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
69
|
+
deleteWebhook(id: string): Promise<void>;
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP client wrapping the Frihet ERP REST API.
|
|
3
|
+
*
|
|
4
|
+
* Handles authentication, pagination, rate-limit retries, and error mapping.
|
|
5
|
+
*/
|
|
6
|
+
const BASE_URL = "https://api.frihet.io/v1";
|
|
7
|
+
const MAX_RETRIES = 3;
|
|
8
|
+
const DEFAULT_RETRY_DELAY_MS = 1000;
|
|
9
|
+
const REQUEST_TIMEOUT_MS = 30000;
|
|
10
|
+
export class FrihetApiError extends Error {
|
|
11
|
+
statusCode;
|
|
12
|
+
errorCode;
|
|
13
|
+
constructor(statusCode, errorCode, message) {
|
|
14
|
+
super(message ?? errorCode);
|
|
15
|
+
this.statusCode = statusCode;
|
|
16
|
+
this.errorCode = errorCode;
|
|
17
|
+
this.name = "FrihetApiError";
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export class FrihetClient {
|
|
21
|
+
apiKey;
|
|
22
|
+
baseUrl;
|
|
23
|
+
constructor(apiKey, baseUrl) {
|
|
24
|
+
if (!apiKey) {
|
|
25
|
+
throw new Error("FRIHET_API_KEY is required. Set it as an environment variable or pass it to the constructor.");
|
|
26
|
+
}
|
|
27
|
+
this.apiKey = apiKey;
|
|
28
|
+
this.baseUrl = baseUrl ?? BASE_URL;
|
|
29
|
+
}
|
|
30
|
+
// ------------------------------------------------------------------ HTTP
|
|
31
|
+
// ------------------------------------------------------------------
|
|
32
|
+
async request(method, path, body, query, retryCount = 0) {
|
|
33
|
+
const url = new URL(`${this.baseUrl}${path}`);
|
|
34
|
+
if (query) {
|
|
35
|
+
for (const [key, value] of Object.entries(query)) {
|
|
36
|
+
if (value !== undefined) {
|
|
37
|
+
url.searchParams.set(key, String(value));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
const headers = {
|
|
42
|
+
"X-API-Key": this.apiKey,
|
|
43
|
+
"Content-Type": "application/json",
|
|
44
|
+
Accept: "application/json",
|
|
45
|
+
};
|
|
46
|
+
const controller = new AbortController();
|
|
47
|
+
const timeoutId = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
48
|
+
let response;
|
|
49
|
+
try {
|
|
50
|
+
response = await fetch(url.toString(), {
|
|
51
|
+
method,
|
|
52
|
+
headers,
|
|
53
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
54
|
+
signal: controller.signal,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
59
|
+
throw new FrihetApiError(408, "request_timeout", `Request timed out after ${REQUEST_TIMEOUT_MS / 1000} seconds`);
|
|
60
|
+
}
|
|
61
|
+
throw error;
|
|
62
|
+
}
|
|
63
|
+
finally {
|
|
64
|
+
clearTimeout(timeoutId);
|
|
65
|
+
}
|
|
66
|
+
// Rate limit handling
|
|
67
|
+
if (response.status === 429) {
|
|
68
|
+
if (retryCount >= MAX_RETRIES) {
|
|
69
|
+
throw new FrihetApiError(429, "rate_limit_exceeded", "Rate limit exceeded after multiple retries. Please try again later.");
|
|
70
|
+
}
|
|
71
|
+
const retryAfter = response.headers.get("Retry-After");
|
|
72
|
+
const delayMs = retryAfter
|
|
73
|
+
? parseInt(retryAfter, 10) * 1000
|
|
74
|
+
: DEFAULT_RETRY_DELAY_MS * Math.pow(2, retryCount);
|
|
75
|
+
await this.sleep(delayMs);
|
|
76
|
+
return this.request(method, path, body, query, retryCount + 1);
|
|
77
|
+
}
|
|
78
|
+
// Error responses
|
|
79
|
+
if (!response.ok) {
|
|
80
|
+
let errorBody;
|
|
81
|
+
try {
|
|
82
|
+
errorBody = (await response.json());
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
errorBody = {
|
|
86
|
+
error: `http_${response.status}`,
|
|
87
|
+
message: response.statusText,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
throw new FrihetApiError(response.status, errorBody.error, errorBody.message ?? errorBody.error);
|
|
91
|
+
}
|
|
92
|
+
// 204 No Content (e.g. DELETE)
|
|
93
|
+
if (response.status === 204) {
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
96
|
+
return (await response.json());
|
|
97
|
+
}
|
|
98
|
+
sleep(ms) {
|
|
99
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
100
|
+
}
|
|
101
|
+
// ---------------------------------------------------------------- Public
|
|
102
|
+
// ----------------------------------------------------------------
|
|
103
|
+
// Invoices
|
|
104
|
+
async listInvoices(params) {
|
|
105
|
+
return this.request("GET", "/invoices", undefined, {
|
|
106
|
+
limit: params?.limit,
|
|
107
|
+
offset: params?.offset,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
async getInvoice(id) {
|
|
111
|
+
return this.request("GET", `/invoices/${encodeURIComponent(id)}`);
|
|
112
|
+
}
|
|
113
|
+
async createInvoice(data) {
|
|
114
|
+
return this.request("POST", "/invoices", data);
|
|
115
|
+
}
|
|
116
|
+
async updateInvoice(id, data) {
|
|
117
|
+
return this.request("PUT", `/invoices/${encodeURIComponent(id)}`, data);
|
|
118
|
+
}
|
|
119
|
+
async deleteInvoice(id) {
|
|
120
|
+
return this.request("DELETE", `/invoices/${encodeURIComponent(id)}`);
|
|
121
|
+
}
|
|
122
|
+
async searchInvoices(clientName, params) {
|
|
123
|
+
return this.request("GET", "/invoices", undefined, {
|
|
124
|
+
clientName,
|
|
125
|
+
limit: params?.limit,
|
|
126
|
+
offset: params?.offset,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
// Expenses
|
|
130
|
+
async listExpenses(params) {
|
|
131
|
+
return this.request("GET", "/expenses", undefined, {
|
|
132
|
+
limit: params?.limit,
|
|
133
|
+
offset: params?.offset,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
async getExpense(id) {
|
|
137
|
+
return this.request("GET", `/expenses/${encodeURIComponent(id)}`);
|
|
138
|
+
}
|
|
139
|
+
async createExpense(data) {
|
|
140
|
+
return this.request("POST", "/expenses", data);
|
|
141
|
+
}
|
|
142
|
+
async updateExpense(id, data) {
|
|
143
|
+
return this.request("PUT", `/expenses/${encodeURIComponent(id)}`, data);
|
|
144
|
+
}
|
|
145
|
+
async deleteExpense(id) {
|
|
146
|
+
return this.request("DELETE", `/expenses/${encodeURIComponent(id)}`);
|
|
147
|
+
}
|
|
148
|
+
// Clients
|
|
149
|
+
async listClients(params) {
|
|
150
|
+
return this.request("GET", "/clients", undefined, {
|
|
151
|
+
limit: params?.limit,
|
|
152
|
+
offset: params?.offset,
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
async getClient(id) {
|
|
156
|
+
return this.request("GET", `/clients/${encodeURIComponent(id)}`);
|
|
157
|
+
}
|
|
158
|
+
async createClient(data) {
|
|
159
|
+
return this.request("POST", "/clients", data);
|
|
160
|
+
}
|
|
161
|
+
async updateClient(id, data) {
|
|
162
|
+
return this.request("PUT", `/clients/${encodeURIComponent(id)}`, data);
|
|
163
|
+
}
|
|
164
|
+
async deleteClient(id) {
|
|
165
|
+
return this.request("DELETE", `/clients/${encodeURIComponent(id)}`);
|
|
166
|
+
}
|
|
167
|
+
// Products
|
|
168
|
+
async listProducts(params) {
|
|
169
|
+
return this.request("GET", "/products", undefined, {
|
|
170
|
+
limit: params?.limit,
|
|
171
|
+
offset: params?.offset,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
async getProduct(id) {
|
|
175
|
+
return this.request("GET", `/products/${encodeURIComponent(id)}`);
|
|
176
|
+
}
|
|
177
|
+
async createProduct(data) {
|
|
178
|
+
return this.request("POST", "/products", data);
|
|
179
|
+
}
|
|
180
|
+
async updateProduct(id, data) {
|
|
181
|
+
return this.request("PUT", `/products/${encodeURIComponent(id)}`, data);
|
|
182
|
+
}
|
|
183
|
+
async deleteProduct(id) {
|
|
184
|
+
return this.request("DELETE", `/products/${encodeURIComponent(id)}`);
|
|
185
|
+
}
|
|
186
|
+
// Quotes
|
|
187
|
+
async listQuotes(params) {
|
|
188
|
+
return this.request("GET", "/quotes", undefined, {
|
|
189
|
+
limit: params?.limit,
|
|
190
|
+
offset: params?.offset,
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
async getQuote(id) {
|
|
194
|
+
return this.request("GET", `/quotes/${encodeURIComponent(id)}`);
|
|
195
|
+
}
|
|
196
|
+
async createQuote(data) {
|
|
197
|
+
return this.request("POST", "/quotes", data);
|
|
198
|
+
}
|
|
199
|
+
async updateQuote(id, data) {
|
|
200
|
+
return this.request("PUT", `/quotes/${encodeURIComponent(id)}`, data);
|
|
201
|
+
}
|
|
202
|
+
async deleteQuote(id) {
|
|
203
|
+
return this.request("DELETE", `/quotes/${encodeURIComponent(id)}`);
|
|
204
|
+
}
|
|
205
|
+
// Webhooks
|
|
206
|
+
async listWebhooks(params) {
|
|
207
|
+
return this.request("GET", "/webhooks", undefined, {
|
|
208
|
+
limit: params?.limit,
|
|
209
|
+
offset: params?.offset,
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
async getWebhook(id) {
|
|
213
|
+
return this.request("GET", `/webhooks/${encodeURIComponent(id)}`);
|
|
214
|
+
}
|
|
215
|
+
async createWebhook(data) {
|
|
216
|
+
return this.request("POST", "/webhooks", data);
|
|
217
|
+
}
|
|
218
|
+
async updateWebhook(id, data) {
|
|
219
|
+
return this.request("PUT", `/webhooks/${encodeURIComponent(id)}`, data);
|
|
220
|
+
}
|
|
221
|
+
async deleteWebhook(id) {
|
|
222
|
+
return this.request("DELETE", `/webhooks/${encodeURIComponent(id)}`);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Frihet MCP Server
|
|
4
|
+
*
|
|
5
|
+
* Model Context Protocol server for Frihet ERP.
|
|
6
|
+
* Provides AI-powered access to invoices, expenses, clients, products, quotes, and webhooks.
|
|
7
|
+
*
|
|
8
|
+
* Authentication: Set the FRIHET_API_KEY environment variable with your Frihet API key.
|
|
9
|
+
* Transport: stdio (designed for CLI tools like Claude Code, Cursor, Windsurf).
|
|
10
|
+
*/
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;GAQG"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Frihet MCP Server
|
|
4
|
+
*
|
|
5
|
+
* Model Context Protocol server for Frihet ERP.
|
|
6
|
+
* Provides AI-powered access to invoices, expenses, clients, products, quotes, and webhooks.
|
|
7
|
+
*
|
|
8
|
+
* Authentication: Set the FRIHET_API_KEY environment variable with your Frihet API key.
|
|
9
|
+
* Transport: stdio (designed for CLI tools like Claude Code, Cursor, Windsurf).
|
|
10
|
+
*/
|
|
11
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
12
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
13
|
+
import { FrihetClient } from "./client.js";
|
|
14
|
+
import { registerInvoiceTools } from "./tools/invoices.js";
|
|
15
|
+
import { registerExpenseTools } from "./tools/expenses.js";
|
|
16
|
+
import { registerClientTools } from "./tools/clients.js";
|
|
17
|
+
import { registerProductTools } from "./tools/products.js";
|
|
18
|
+
import { registerQuoteTools } from "./tools/quotes.js";
|
|
19
|
+
import { registerWebhookTools } from "./tools/webhooks.js";
|
|
20
|
+
function main() {
|
|
21
|
+
const apiKey = process.env.FRIHET_API_KEY;
|
|
22
|
+
if (!apiKey) {
|
|
23
|
+
console.error("Error: FRIHET_API_KEY environment variable is required.\n" +
|
|
24
|
+
"Set it in your MCP configuration or export it in your shell.\n\n" +
|
|
25
|
+
"Example:\n" +
|
|
26
|
+
' export FRIHET_API_KEY="fri_your_api_key_here"\n');
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
const baseUrl = process.env.FRIHET_API_URL;
|
|
30
|
+
const client = new FrihetClient(apiKey, baseUrl);
|
|
31
|
+
const server = new McpServer({
|
|
32
|
+
name: "frihet-erp",
|
|
33
|
+
version: "1.0.0",
|
|
34
|
+
});
|
|
35
|
+
// Register all tools
|
|
36
|
+
registerInvoiceTools(server, client);
|
|
37
|
+
registerExpenseTools(server, client);
|
|
38
|
+
registerClientTools(server, client);
|
|
39
|
+
registerProductTools(server, client);
|
|
40
|
+
registerQuoteTools(server, client);
|
|
41
|
+
registerWebhookTools(server, client);
|
|
42
|
+
// Connect via stdio transport
|
|
43
|
+
const transport = new StdioServerTransport();
|
|
44
|
+
server.connect(transport).then(() => {
|
|
45
|
+
console.error("Frihet MCP server running on stdio");
|
|
46
|
+
}).catch((error) => {
|
|
47
|
+
console.error("Failed to start Frihet MCP server:", error);
|
|
48
|
+
process.exit(1);
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
main();
|
|
52
|
+
//# sourceMappingURL=index.js.map
|