@codespar/mcp-alegra 0.1.0 → 0.2.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.
package/README.md CHANGED
@@ -25,19 +25,29 @@ npx tsx packages/colombia/alegra/src/index.ts --http
25
25
  | `MCP_HTTP` | No | Set to `"true"` to enable HTTP transport |
26
26
  | `MCP_PORT` | No | HTTP port (default: 3000) |
27
27
 
28
- ## Tools
28
+ ## Tools (20)
29
29
 
30
- | Tool | Description |
31
- |------|-------------|
30
+ | Tool | Purpose |
31
+ |---|---|
32
32
  | `create_invoice` | Create an invoice |
33
33
  | `get_invoice` | Get invoice details by ID |
34
34
  | `list_invoices` | List invoices |
35
- | `create_contact` | Create a contact (customer/supplier) |
35
+ | `void_invoice` | Void/cancel an invoice |
36
+ | `get_invoice_pdf` | Get invoice PDF download URL |
37
+ | `send_invoice` | Email an invoice to one or more recipients |
38
+ | `create_contact` | Create a contact (customer or supplier) |
39
+ | `update_contact` | Update an existing contact |
40
+ | `delete_contact` | Delete a contact |
36
41
  | `list_contacts` | List contacts |
37
- | `create_item` | Create a product/service item |
42
+ | `create_item` | Create a product or service item |
43
+ | `update_item` | Update an existing item |
38
44
  | `list_items` | List products and services |
39
45
  | `list_payments` | List payments |
46
+ | `get_payment` | Get payment by ID |
40
47
  | `create_payment` | Record a payment |
48
+ | `void_payment` | Void/annul a payment |
49
+ | `list_categories` | List item categories (chart of accounts) |
50
+ | `list_bank_accounts` | List bank accounts |
41
51
  | `get_company` | Get company profile and settings |
42
52
 
43
53
  ## Auth
package/dist/index.d.ts CHANGED
@@ -6,12 +6,22 @@
6
6
  * - create_invoice: Create an invoice
7
7
  * - get_invoice: Get invoice by ID
8
8
  * - list_invoices: List invoices
9
+ * - void_invoice: Void/cancel an invoice
10
+ * - get_invoice_pdf: Get invoice PDF URL
11
+ * - send_invoice: Email an invoice to a contact
9
12
  * - create_contact: Create a contact (customer/supplier)
13
+ * - update_contact: Update an existing contact
14
+ * - delete_contact: Delete a contact
10
15
  * - list_contacts: List contacts
11
16
  * - create_item: Create a product/service item
17
+ * - update_item: Update an existing item
12
18
  * - list_items: List items
13
19
  * - list_payments: List payments
20
+ * - get_payment: Get payment by ID
14
21
  * - create_payment: Record a payment
22
+ * - void_payment: Void a payment
23
+ * - list_categories: List item categories (chart of accounts)
24
+ * - list_bank_accounts: List bank accounts
15
25
  * - get_company: Get company profile information
16
26
  *
17
27
  * Environment:
package/dist/index.js CHANGED
@@ -6,12 +6,22 @@
6
6
  * - create_invoice: Create an invoice
7
7
  * - get_invoice: Get invoice by ID
8
8
  * - list_invoices: List invoices
9
+ * - void_invoice: Void/cancel an invoice
10
+ * - get_invoice_pdf: Get invoice PDF URL
11
+ * - send_invoice: Email an invoice to a contact
9
12
  * - create_contact: Create a contact (customer/supplier)
13
+ * - update_contact: Update an existing contact
14
+ * - delete_contact: Delete a contact
10
15
  * - list_contacts: List contacts
11
16
  * - create_item: Create a product/service item
17
+ * - update_item: Update an existing item
12
18
  * - list_items: List items
13
19
  * - list_payments: List payments
20
+ * - get_payment: Get payment by ID
14
21
  * - create_payment: Record a payment
22
+ * - void_payment: Void a payment
23
+ * - list_categories: List item categories (chart of accounts)
24
+ * - list_bank_accounts: List bank accounts
15
25
  * - get_company: Get company profile information
16
26
  *
17
27
  * Environment:
@@ -43,7 +53,7 @@ async function alegraRequest(method, path, body) {
43
53
  }
44
54
  return res.json();
45
55
  }
46
- const server = new Server({ name: "mcp-alegra", version: "0.1.0" }, { capabilities: { tools: {} } });
56
+ const server = new Server({ name: "mcp-alegra", version: "0.2.1" }, { capabilities: { tools: {} } });
47
57
  server.setRequestHandler(ListToolsRequestSchema, async () => ({
48
58
  tools: [
49
59
  {
@@ -113,6 +123,53 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
113
123
  },
114
124
  },
115
125
  },
126
+ {
127
+ name: "void_invoice",
128
+ description: "Void/cancel an invoice",
129
+ inputSchema: {
130
+ type: "object",
131
+ properties: {
132
+ invoiceId: { type: "number", description: "Invoice ID" },
133
+ reason: { type: "string", description: "Reason for void/annulment" },
134
+ },
135
+ required: ["invoiceId"],
136
+ },
137
+ },
138
+ {
139
+ name: "get_invoice_pdf",
140
+ description: "Get invoice PDF download URL",
141
+ inputSchema: {
142
+ type: "object",
143
+ properties: {
144
+ invoiceId: { type: "number", description: "Invoice ID" },
145
+ },
146
+ required: ["invoiceId"],
147
+ },
148
+ },
149
+ {
150
+ name: "send_invoice",
151
+ description: "Email an invoice to one or more recipients",
152
+ inputSchema: {
153
+ type: "object",
154
+ properties: {
155
+ invoiceId: { type: "number", description: "Invoice ID" },
156
+ emails: {
157
+ type: "array",
158
+ description: "Recipient email addresses",
159
+ items: { type: "string" },
160
+ },
161
+ cc: {
162
+ type: "array",
163
+ description: "CC recipients",
164
+ items: { type: "string" },
165
+ },
166
+ subject: { type: "string", description: "Email subject" },
167
+ body: { type: "string", description: "Email body/message" },
168
+ send_copy_to_user: { type: "boolean", description: "Send a copy to the account user" },
169
+ },
170
+ required: ["invoiceId", "emails"],
171
+ },
172
+ },
116
173
  {
117
174
  name: "create_contact",
118
175
  description: "Create a contact (customer or supplier)",
@@ -132,6 +189,37 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
132
189
  required: ["name"],
133
190
  },
134
191
  },
192
+ {
193
+ name: "update_contact",
194
+ description: "Update an existing contact",
195
+ inputSchema: {
196
+ type: "object",
197
+ properties: {
198
+ contactId: { type: "number", description: "Contact ID" },
199
+ name: { type: "string", description: "Contact name" },
200
+ identification: { type: "string", description: "Tax ID" },
201
+ email: { type: "string", description: "Email address" },
202
+ phone_primary: { type: "string", description: "Primary phone" },
203
+ address: { type: "string", description: "Address" },
204
+ city: { type: "string", description: "City" },
205
+ department: { type: "string", description: "Department/state" },
206
+ type: { type: "string", description: "Contact type (client, provider)" },
207
+ regime: { type: "string", description: "Tax regime" },
208
+ },
209
+ required: ["contactId"],
210
+ },
211
+ },
212
+ {
213
+ name: "delete_contact",
214
+ description: "Delete a contact",
215
+ inputSchema: {
216
+ type: "object",
217
+ properties: {
218
+ contactId: { type: "number", description: "Contact ID" },
219
+ },
220
+ required: ["contactId"],
221
+ },
222
+ },
135
223
  {
136
224
  name: "list_contacts",
137
225
  description: "List contacts",
@@ -175,6 +263,28 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
175
263
  required: ["name", "price"],
176
264
  },
177
265
  },
266
+ {
267
+ name: "update_item",
268
+ description: "Update an existing item",
269
+ inputSchema: {
270
+ type: "object",
271
+ properties: {
272
+ itemId: { type: "number", description: "Item ID" },
273
+ name: { type: "string", description: "Item name" },
274
+ description: { type: "string", description: "Description" },
275
+ reference: { type: "string", description: "Reference/SKU code" },
276
+ price: { type: "number", description: "Price" },
277
+ category: { type: "number", description: "Category ID" },
278
+ tax: {
279
+ type: "array",
280
+ description: "Tax IDs",
281
+ items: { type: "number" },
282
+ },
283
+ type: { type: "string", description: "Item type (product, service, kit)" },
284
+ },
285
+ required: ["itemId"],
286
+ },
287
+ },
178
288
  {
179
289
  name: "list_items",
180
290
  description: "List products and services",
@@ -201,6 +311,15 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
201
311
  },
202
312
  },
203
313
  },
314
+ {
315
+ name: "get_payment",
316
+ description: "Get payment by ID",
317
+ inputSchema: {
318
+ type: "object",
319
+ properties: { paymentId: { type: "number", description: "Payment ID" } },
320
+ required: ["paymentId"],
321
+ },
322
+ },
204
323
  {
205
324
  name: "create_payment",
206
325
  description: "Record a payment",
@@ -229,6 +348,41 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
229
348
  required: ["date", "amount"],
230
349
  },
231
350
  },
351
+ {
352
+ name: "void_payment",
353
+ description: "Void/annul a payment",
354
+ inputSchema: {
355
+ type: "object",
356
+ properties: {
357
+ paymentId: { type: "number", description: "Payment ID" },
358
+ },
359
+ required: ["paymentId"],
360
+ },
361
+ },
362
+ {
363
+ name: "list_categories",
364
+ description: "List item categories (chart of accounts)",
365
+ inputSchema: {
366
+ type: "object",
367
+ properties: {
368
+ start: { type: "number", description: "Offset for pagination" },
369
+ limit: { type: "number", description: "Results limit" },
370
+ query: { type: "string", description: "Search query" },
371
+ },
372
+ },
373
+ },
374
+ {
375
+ name: "list_bank_accounts",
376
+ description: "List bank accounts",
377
+ inputSchema: {
378
+ type: "object",
379
+ properties: {
380
+ start: { type: "number", description: "Offset for pagination" },
381
+ limit: { type: "number", description: "Results limit" },
382
+ type: { type: "string", description: "Filter by account type" },
383
+ },
384
+ },
385
+ },
232
386
  {
233
387
  name: "get_company",
234
388
  description: "Get company profile and settings",
@@ -275,6 +429,26 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
275
429
  params.set("client", String(args.client_id));
276
430
  return { content: [{ type: "text", text: JSON.stringify(await alegraRequest("GET", `/invoices?${params}`), null, 2) }] };
277
431
  }
432
+ case "void_invoice": {
433
+ const payload = { status: "void" };
434
+ if (args?.reason)
435
+ payload.reason = args.reason;
436
+ return { content: [{ type: "text", text: JSON.stringify(await alegraRequest("PUT", `/invoices/${args?.invoiceId}/void`, payload), null, 2) }] };
437
+ }
438
+ case "get_invoice_pdf":
439
+ return { content: [{ type: "text", text: JSON.stringify(await alegraRequest("GET", `/invoices/${args?.invoiceId}/pdf`), null, 2) }] };
440
+ case "send_invoice": {
441
+ const payload = { emails: args?.emails };
442
+ if (args?.cc)
443
+ payload.copyTo = args.cc;
444
+ if (args?.subject)
445
+ payload.subject = args.subject;
446
+ if (args?.body)
447
+ payload.body = args.body;
448
+ if (args?.send_copy_to_user !== undefined)
449
+ payload.sendCopyToUser = args.send_copy_to_user;
450
+ return { content: [{ type: "text", text: JSON.stringify(await alegraRequest("POST", `/invoices/${args?.invoiceId}/email`, payload), null, 2) }] };
451
+ }
278
452
  case "create_contact": {
279
453
  const payload = { name: args?.name };
280
454
  if (args?.identification)
@@ -295,6 +469,30 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
295
469
  payload.regime = args.regime;
296
470
  return { content: [{ type: "text", text: JSON.stringify(await alegraRequest("POST", "/contacts", payload), null, 2) }] };
297
471
  }
472
+ case "update_contact": {
473
+ const payload = {};
474
+ if (args?.name)
475
+ payload.name = args.name;
476
+ if (args?.identification)
477
+ payload.identification = args.identification;
478
+ if (args?.email)
479
+ payload.email = args.email;
480
+ if (args?.phone_primary)
481
+ payload.phonePrimary = args.phone_primary;
482
+ if (args?.address)
483
+ payload.address = { address: args.address };
484
+ if (args?.city)
485
+ payload.address = { ...payload.address, city: args.city };
486
+ if (args?.department)
487
+ payload.address = { ...payload.address, department: args.department };
488
+ if (args?.type)
489
+ payload.type = args.type;
490
+ if (args?.regime)
491
+ payload.regime = args.regime;
492
+ return { content: [{ type: "text", text: JSON.stringify(await alegraRequest("PUT", `/contacts/${args?.contactId}`, payload), null, 2) }] };
493
+ }
494
+ case "delete_contact":
495
+ return { content: [{ type: "text", text: JSON.stringify(await alegraRequest("DELETE", `/contacts/${args?.contactId}`), null, 2) }] };
298
496
  case "list_contacts": {
299
497
  const params = new URLSearchParams();
300
498
  if (args?.start)
@@ -326,6 +524,24 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
326
524
  payload.type = args.type;
327
525
  return { content: [{ type: "text", text: JSON.stringify(await alegraRequest("POST", "/items", payload), null, 2) }] };
328
526
  }
527
+ case "update_item": {
528
+ const payload = {};
529
+ if (args?.name)
530
+ payload.name = args.name;
531
+ if (args?.description)
532
+ payload.description = args.description;
533
+ if (args?.reference)
534
+ payload.reference = args.reference;
535
+ if (args?.price !== undefined)
536
+ payload.price = [{ price: args.price }];
537
+ if (args?.category)
538
+ payload.category = { id: args.category };
539
+ if (args?.tax)
540
+ payload.tax = args.tax;
541
+ if (args?.type)
542
+ payload.type = args.type;
543
+ return { content: [{ type: "text", text: JSON.stringify(await alegraRequest("PUT", `/items/${args?.itemId}`, payload), null, 2) }] };
544
+ }
329
545
  case "list_items": {
330
546
  const params = new URLSearchParams();
331
547
  if (args?.start)
@@ -350,6 +566,8 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
350
566
  params.set("date_end", args.date_to);
351
567
  return { content: [{ type: "text", text: JSON.stringify(await alegraRequest("GET", `/payments?${params}`), null, 2) }] };
352
568
  }
569
+ case "get_payment":
570
+ return { content: [{ type: "text", text: JSON.stringify(await alegraRequest("GET", `/payments/${args?.paymentId}`), null, 2) }] };
353
571
  case "create_payment": {
354
572
  const payload = {
355
573
  date: args?.date,
@@ -367,6 +585,28 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
367
585
  payload.observations = args.observations;
368
586
  return { content: [{ type: "text", text: JSON.stringify(await alegraRequest("POST", "/payments", payload), null, 2) }] };
369
587
  }
588
+ case "void_payment":
589
+ return { content: [{ type: "text", text: JSON.stringify(await alegraRequest("PUT", `/payments/${args?.paymentId}/void`, { status: "void" }), null, 2) }] };
590
+ case "list_categories": {
591
+ const params = new URLSearchParams();
592
+ if (args?.start)
593
+ params.set("start", String(args.start));
594
+ if (args?.limit)
595
+ params.set("limit", String(args.limit));
596
+ if (args?.query)
597
+ params.set("query", args.query);
598
+ return { content: [{ type: "text", text: JSON.stringify(await alegraRequest("GET", `/categories?${params}`), null, 2) }] };
599
+ }
600
+ case "list_bank_accounts": {
601
+ const params = new URLSearchParams();
602
+ if (args?.start)
603
+ params.set("start", String(args.start));
604
+ if (args?.limit)
605
+ params.set("limit", String(args.limit));
606
+ if (args?.type)
607
+ params.set("type", args.type);
608
+ return { content: [{ type: "text", text: JSON.stringify(await alegraRequest("GET", `/bank-accounts?${params}`), null, 2) }] };
609
+ }
370
610
  case "get_company":
371
611
  return { content: [{ type: "text", text: JSON.stringify(await alegraRequest("GET", "/company"), null, 2) }] };
372
612
  default:
@@ -395,7 +635,7 @@ async function main() {
395
635
  const t = new StreamableHTTPServerTransport({ sessionIdGenerator: () => randomUUID(), onsessioninitialized: (id) => { transports.set(id, t); } });
396
636
  t.onclose = () => { if (t.sessionId)
397
637
  transports.delete(t.sessionId); };
398
- const s = new Server({ name: "mcp-alegra", version: "0.1.0" }, { capabilities: { tools: {} } });
638
+ const s = new Server({ name: "mcp-alegra", version: "0.2.1" }, { capabilities: { tools: {} } });
399
639
  server._requestHandlers.forEach((v, k) => s._requestHandlers.set(k, v));
400
640
  server._notificationHandlers?.forEach((v, k) => s._notificationHandlers.set(k, v));
401
641
  await s.connect(t);
package/package.json CHANGED
@@ -1,13 +1,15 @@
1
1
  {
2
2
  "name": "@codespar/mcp-alegra",
3
- "version": "0.1.0",
4
- "description": "MCP server for Alegra cloud accounting for LATAM (Colombian-founded)",
3
+ "version": "0.2.1",
4
+ "description": "MCP server for Alegra \u2014 cloud accounting for LATAM (Colombian-founded)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "bin": {
8
8
  "mcp-alegra": "dist/index.js"
9
9
  },
10
- "files": ["dist"],
10
+ "files": [
11
+ "dist"
12
+ ],
11
13
  "scripts": {
12
14
  "build": "tsc",
13
15
  "start": "node dist/index.js"
@@ -20,6 +22,13 @@
20
22
  "typescript": "^5.8.0"
21
23
  },
22
24
  "license": "MIT",
23
- "keywords": ["alegra", "accounting", "colombia", "latam", "invoicing", "mcp"],
25
+ "keywords": [
26
+ "alegra",
27
+ "accounting",
28
+ "colombia",
29
+ "latam",
30
+ "invoicing",
31
+ "mcp"
32
+ ],
24
33
  "mcpName": "io.github.codespar/mcp-alegra"
25
34
  }