@joinluminous/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.
Files changed (47) hide show
  1. package/README.md +126 -0
  2. package/dist/client.d.ts +26 -0
  3. package/dist/client.js +82 -0
  4. package/dist/client.js.map +1 -0
  5. package/dist/config.d.ts +6 -0
  6. package/dist/config.js +19 -0
  7. package/dist/config.js.map +1 -0
  8. package/dist/index.d.ts +2 -0
  9. package/dist/index.js +46 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/tools/companies.d.ts +2 -0
  12. package/dist/tools/companies.js +25 -0
  13. package/dist/tools/companies.js.map +1 -0
  14. package/dist/tools/create.d.ts +2 -0
  15. package/dist/tools/create.js +28 -0
  16. package/dist/tools/create.js.map +1 -0
  17. package/dist/tools/custom-fields.d.ts +2 -0
  18. package/dist/tools/custom-fields.js +35 -0
  19. package/dist/tools/custom-fields.js.map +1 -0
  20. package/dist/tools/delete.d.ts +2 -0
  21. package/dist/tools/delete.js +27 -0
  22. package/dist/tools/delete.js.map +1 -0
  23. package/dist/tools/get.d.ts +2 -0
  24. package/dist/tools/get.js +23 -0
  25. package/dist/tools/get.js.map +1 -0
  26. package/dist/tools/inventory.d.ts +2 -0
  27. package/dist/tools/inventory.js +40 -0
  28. package/dist/tools/inventory.js.map +1 -0
  29. package/dist/tools/list.d.ts +2 -0
  30. package/dist/tools/list.js +29 -0
  31. package/dist/tools/list.js.map +1 -0
  32. package/dist/tools/products.d.ts +2 -0
  33. package/dist/tools/products.js +41 -0
  34. package/dist/tools/products.js.map +1 -0
  35. package/dist/tools/purchase-orders.d.ts +2 -0
  36. package/dist/tools/purchase-orders.js +40 -0
  37. package/dist/tools/purchase-orders.js.map +1 -0
  38. package/dist/tools/sales-orders.d.ts +2 -0
  39. package/dist/tools/sales-orders.js +45 -0
  40. package/dist/tools/sales-orders.js.map +1 -0
  41. package/dist/tools/tags.d.ts +2 -0
  42. package/dist/tools/tags.js +40 -0
  43. package/dist/tools/tags.js.map +1 -0
  44. package/dist/tools/update.d.ts +2 -0
  45. package/dist/tools/update.js +28 -0
  46. package/dist/tools/update.js.map +1 -0
  47. package/package.json +39 -0
package/README.md ADDED
@@ -0,0 +1,126 @@
1
+ # @joinluminous/mcp-server
2
+
3
+ MCP server for the [Luminous](https://joinluminous.com) API. Gives Claude access to your products, orders, inventory, companies, contacts, and more.
4
+
5
+ ## Setup
6
+
7
+ ### Claude Desktop
8
+
9
+ Add this to your Claude Desktop config file:
10
+
11
+ **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
12
+ **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
13
+
14
+ ```json
15
+ {
16
+ "mcpServers": {
17
+ "luminous": {
18
+ "command": "npx",
19
+ "args": ["-y", "@joinluminous/mcp-server"],
20
+ "env": {
21
+ "LUMINOUS_SUBDOMAIN": "your-company",
22
+ "LUMINOUS_API_TOKEN": "your-api-token"
23
+ }
24
+ }
25
+ }
26
+ }
27
+ ```
28
+
29
+ Replace `your-company` with your Luminous subdomain (the part before `.api.joinluminous.com`) and `your-api-token` with your API key.
30
+
31
+ ### Claude Code
32
+
33
+ Add to your `.mcp.json`:
34
+
35
+ ```json
36
+ {
37
+ "mcpServers": {
38
+ "luminous": {
39
+ "command": "npx",
40
+ "args": ["-y", "@joinluminous/mcp-server"],
41
+ "env": {
42
+ "LUMINOUS_SUBDOMAIN": "your-company",
43
+ "LUMINOUS_API_TOKEN": "your-api-token"
44
+ }
45
+ }
46
+ }
47
+ }
48
+ ```
49
+
50
+ ## Getting Your API Token
51
+
52
+ Contact [developers@joinluminous.com](mailto:developers@joinluminous.com) to request an API token, or generate one from your Luminous admin settings.
53
+
54
+ ## Available Tools
55
+
56
+ ### Core CRUD
57
+
58
+ | Tool | Description |
59
+ |------|-------------|
60
+ | `luminous_list` | List any resource with filters, pagination, and sorting |
61
+ | `luminous_get` | Get a single resource by ID |
62
+ | `luminous_create` | Create a new resource |
63
+ | `luminous_update` | Update a resource by ID |
64
+ | `luminous_delete` | Delete a resource by ID |
65
+
66
+ ### Inventory
67
+
68
+ | Tool | Description |
69
+ |------|-------------|
70
+ | `luminous_inventory_stocks` | Get current stock levels |
71
+ | `luminous_inventory_adjust` | Adjust stock quantities |
72
+
73
+ ### Sales Orders
74
+
75
+ | Tool | Description |
76
+ |------|-------------|
77
+ | `luminous_sales_order_shipments` | List or create shipments |
78
+ | `luminous_sales_order_export` | Incremental export of changed orders |
79
+
80
+ ### Purchase Orders
81
+
82
+ | Tool | Description |
83
+ |------|-------------|
84
+ | `luminous_purchase_order_payments` | Create, update, or delete payments |
85
+
86
+ ### Products
87
+
88
+ | Tool | Description |
89
+ |------|-------------|
90
+ | `luminous_product_upsert` | Create or update a product by SKU |
91
+ | `luminous_product_pricing` | Get pricing, optionally per-company |
92
+
93
+ ### Companies
94
+
95
+ | Tool | Description |
96
+ |------|-------------|
97
+ | `luminous_company_sub_resources` | List contacts, products, or price overrides for a company |
98
+
99
+ ### Tags & Custom Fields
100
+
101
+ | Tool | Description |
102
+ |------|-------------|
103
+ | `luminous_tags` | Get, attach, detach, or replace tags |
104
+ | `luminous_custom_fields` | Get or update custom field values |
105
+
106
+ ## Supported Resources
107
+
108
+ products, sales-orders, purchase-orders, inventory, companies, contacts, invoices, boms, warehouses, locations, transfer-orders, receiving-reports, price-schedules, price-levels
109
+
110
+ ## Filtering
111
+
112
+ Filters use Luminous query syntax:
113
+
114
+ ```
115
+ {"sku[contains]": "BOLT", "type": "PRODUCT", "created_at[gte]": "2025-01-01"}
116
+ ```
117
+
118
+ **Operators:** `eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `contains`, `notcontains`, `in`, `notin`, `set`, `notset`
119
+
120
+ ## API Documentation
121
+
122
+ Full API docs: [docs.joinluminous.com](https://docs.joinluminous.com)
123
+
124
+ ## License
125
+
126
+ MIT
@@ -0,0 +1,26 @@
1
+ export interface LuminousResponse {
2
+ data?: any;
3
+ meta?: {
4
+ current_page: number;
5
+ last_page: number;
6
+ per_page: number;
7
+ total: number;
8
+ from: number | null;
9
+ to: number | null;
10
+ };
11
+ message?: string;
12
+ }
13
+ export interface RequestOptions {
14
+ method?: string;
15
+ path: string;
16
+ query?: Record<string, string>;
17
+ body?: any;
18
+ }
19
+ export declare function luminousRequest(opts: RequestOptions): Promise<LuminousResponse>;
20
+ /**
21
+ * Build query params from filters object.
22
+ * Filters use Luminous syntax: { "sku[eq]": "ABC", "name[contains]": "bolt" }
23
+ */
24
+ export declare function buildFilterParams(filters?: Record<string, string>, page?: number, perPage?: number, sort?: string): Record<string, string>;
25
+ export declare function getResourcePath(resource: string): string;
26
+ export declare const AVAILABLE_RESOURCES: string[];
package/dist/client.js ADDED
@@ -0,0 +1,82 @@
1
+ import { getConfig } from './config.js';
2
+ export async function luminousRequest(opts) {
3
+ const config = getConfig();
4
+ const url = new URL(`${config.baseUrl}${opts.path}`);
5
+ if (opts.query) {
6
+ for (const [key, value] of Object.entries(opts.query)) {
7
+ url.searchParams.set(key, value);
8
+ }
9
+ }
10
+ const headers = {
11
+ 'Authorization': `Bearer ${config.apiToken}`,
12
+ 'Accept': 'application/json',
13
+ };
14
+ if (opts.body) {
15
+ headers['Content-Type'] = 'application/json';
16
+ }
17
+ const res = await fetch(url.toString(), {
18
+ method: opts.method || 'GET',
19
+ headers,
20
+ body: opts.body ? JSON.stringify(opts.body) : undefined,
21
+ });
22
+ const text = await res.text();
23
+ if (!res.ok) {
24
+ let detail;
25
+ try {
26
+ const json = JSON.parse(text);
27
+ detail = json.message || json.error || text;
28
+ }
29
+ catch {
30
+ detail = text;
31
+ }
32
+ throw new Error(`Luminous API ${res.status}: ${detail}`);
33
+ }
34
+ if (!text)
35
+ return {};
36
+ return JSON.parse(text);
37
+ }
38
+ /**
39
+ * Build query params from filters object.
40
+ * Filters use Luminous syntax: { "sku[eq]": "ABC", "name[contains]": "bolt" }
41
+ */
42
+ export function buildFilterParams(filters, page, perPage, sort) {
43
+ const params = {};
44
+ if (filters) {
45
+ for (const [key, value] of Object.entries(filters)) {
46
+ params[key] = value;
47
+ }
48
+ }
49
+ if (page)
50
+ params.page = String(page);
51
+ if (perPage)
52
+ params.per_page = String(perPage);
53
+ if (sort)
54
+ params.sort = sort;
55
+ return params;
56
+ }
57
+ /** Resource path mapping for sub-resources and irregular plurals */
58
+ const RESOURCE_PATHS = {
59
+ products: '/products',
60
+ 'sales-orders': '/sales-orders',
61
+ 'purchase-orders': '/purchase-orders',
62
+ inventory: '/inventory',
63
+ companies: '/companies',
64
+ contacts: '/contacts',
65
+ invoices: '/invoices',
66
+ boms: '/boms',
67
+ warehouses: '/warehouses',
68
+ locations: '/locations',
69
+ 'transfer-orders': '/transfer-orders',
70
+ 'receiving-reports': '/receiving-reports',
71
+ 'price-schedules': '/price-schedules',
72
+ 'price-levels': '/price-levels',
73
+ };
74
+ export function getResourcePath(resource) {
75
+ const path = RESOURCE_PATHS[resource];
76
+ if (!path) {
77
+ throw new Error(`Unknown resource "${resource}". Available: ${Object.keys(RESOURCE_PATHS).join(', ')}`);
78
+ }
79
+ return path;
80
+ }
81
+ export const AVAILABLE_RESOURCES = Object.keys(RESOURCE_PATHS);
82
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export interface Config {
2
+ subdomain: string;
3
+ apiToken: string;
4
+ baseUrl: string;
5
+ }
6
+ export declare function getConfig(): Config;
package/dist/config.js ADDED
@@ -0,0 +1,19 @@
1
+ let _config = null;
2
+ export function getConfig() {
3
+ if (_config)
4
+ return _config;
5
+ const subdomain = process.env.LUMINOUS_SUBDOMAIN;
6
+ const apiToken = process.env.LUMINOUS_API_TOKEN;
7
+ if (!subdomain || !apiToken) {
8
+ console.error('Missing required environment variables: LUMINOUS_SUBDOMAIN and LUMINOUS_API_TOKEN\n' +
9
+ 'Set them in your Claude Desktop config or as environment variables.');
10
+ process.exit(1);
11
+ }
12
+ _config = {
13
+ subdomain,
14
+ apiToken,
15
+ baseUrl: `https://${subdomain}.api.joinluminous.com/external/api/v1`,
16
+ };
17
+ return _config;
18
+ }
19
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAMA,IAAI,OAAO,GAAkB,IAAI,CAAC;AAElC,MAAM,UAAU,SAAS;IACvB,IAAI,OAAO;QAAE,OAAO,OAAO,CAAC;IAE5B,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;IACjD,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;IAEhD,IAAI,CAAC,SAAS,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC5B,OAAO,CAAC,KAAK,CACX,qFAAqF;YACrF,qEAAqE,CACtE,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,OAAO,GAAG;QACR,SAAS;QACT,QAAQ;QACR,OAAO,EAAE,WAAW,SAAS,uCAAuC;KACrE,CAAC;IAEF,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,46 @@
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 { registerListTool } from './tools/list.js';
5
+ import { registerGetTool } from './tools/get.js';
6
+ import { registerCreateTool } from './tools/create.js';
7
+ import { registerUpdateTool } from './tools/update.js';
8
+ import { registerDeleteTool } from './tools/delete.js';
9
+ import { registerInventoryTools } from './tools/inventory.js';
10
+ import { registerSalesOrderTools } from './tools/sales-orders.js';
11
+ import { registerPurchaseOrderTools } from './tools/purchase-orders.js';
12
+ import { registerCompanyTools } from './tools/companies.js';
13
+ import { registerProductTools } from './tools/products.js';
14
+ import { registerTagTools } from './tools/tags.js';
15
+ import { registerCustomFieldTools } from './tools/custom-fields.js';
16
+ function createServer() {
17
+ const server = new McpServer({
18
+ name: 'luminous',
19
+ version: '1.0.0',
20
+ });
21
+ // Core CRUD tools
22
+ registerListTool(server);
23
+ registerGetTool(server);
24
+ registerCreateTool(server);
25
+ registerUpdateTool(server);
26
+ registerDeleteTool(server);
27
+ // Specialized tools
28
+ registerInventoryTools(server);
29
+ registerSalesOrderTools(server);
30
+ registerPurchaseOrderTools(server);
31
+ registerCompanyTools(server);
32
+ registerProductTools(server);
33
+ registerTagTools(server);
34
+ registerCustomFieldTools(server);
35
+ return server;
36
+ }
37
+ async function main() {
38
+ const server = createServer();
39
+ const transport = new StdioServerTransport();
40
+ await server.connect(transport);
41
+ }
42
+ main().catch((err) => {
43
+ console.error('Fatal error:', err);
44
+ process.exit(1);
45
+ });
46
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAEjF,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,EAAE,0BAA0B,EAAE,MAAM,4BAA4B,CAAC;AACxE,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAEpE,SAAS,YAAY;IACnB,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,UAAU;QAChB,OAAO,EAAE,OAAO;KACjB,CAAC,CAAC;IAEH,kBAAkB;IAClB,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACzB,eAAe,CAAC,MAAM,CAAC,CAAC;IACxB,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAC3B,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAC3B,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAE3B,oBAAoB;IACpB,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAC/B,uBAAuB,CAAC,MAAM,CAAC,CAAC;IAChC,0BAA0B,CAAC,MAAM,CAAC,CAAC;IACnC,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC7B,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC7B,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACzB,wBAAwB,CAAC,MAAM,CAAC,CAAC;IAEjC,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;IAC9B,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC;IACnC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerCompanyTools(server: McpServer): void;
@@ -0,0 +1,25 @@
1
+ import { z } from 'zod';
2
+ import { luminousRequest, buildFilterParams } from '../client.js';
3
+ export function registerCompanyTools(server) {
4
+ server.tool('luminous_company_sub_resources', 'List contacts, products, or price overrides for a specific company.', {
5
+ company_id: z.union([z.string(), z.number()]).describe('Company ID'),
6
+ sub_resource: z.enum(['contacts', 'products', 'price-overrides']).describe('Which sub-resource to list'),
7
+ filters: z.record(z.string()).optional().describe('Optional filters'),
8
+ page: z.number().optional().describe('Page number'),
9
+ per_page: z.number().optional().describe('Items per page (max 100)'),
10
+ }, async ({ company_id, sub_resource, filters, page, per_page }) => {
11
+ try {
12
+ const path = `/companies/${company_id}/${sub_resource}`;
13
+ const query = buildFilterParams(filters, page, per_page);
14
+ const result = await luminousRequest({ path, query });
15
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
16
+ }
17
+ catch (err) {
18
+ return {
19
+ content: [{ type: 'text', text: JSON.stringify({ error: err.message }) }],
20
+ isError: true,
21
+ };
22
+ }
23
+ });
24
+ }
25
+ //# sourceMappingURL=companies.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"companies.js","sourceRoot":"","sources":["../../src/tools/companies.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAElE,MAAM,UAAU,oBAAoB,CAAC,MAAiB;IACpD,MAAM,CAAC,IAAI,CACT,gCAAgC,EAChC,qEAAqE,EACrE;QACE,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC;QACpE,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,UAAU,EAAE,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,4BAA4B,CAAC;QACxG,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,kBAAkB,CAAC;QACrE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,aAAa,CAAC;QACnD,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,0BAA0B,CAAC;KACrE,EACD,KAAK,EAAE,EAAE,UAAU,EAAE,YAAY,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE;QAC9D,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,cAAc,UAAU,IAAI,YAAY,EAAE,CAAC;YACxD,MAAM,KAAK,GAAG,iBAAiB,CAAC,OAAO,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;YACzD,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;YACtD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QACzF,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;gBAClF,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerCreateTool(server: McpServer): void;
@@ -0,0 +1,28 @@
1
+ import { z } from 'zod';
2
+ import { luminousRequest, getResourcePath } from '../client.js';
3
+ const CREATABLE_RESOURCES = [
4
+ 'products', 'sales-orders', 'purchase-orders', 'companies', 'contacts',
5
+ 'boms', 'transfer-orders', 'receiving-reports',
6
+ ];
7
+ export function registerCreateTool(server) {
8
+ server.tool('luminous_create', 'Create a new resource in Luminous. Pass the full resource data as a JSON object. ' +
9
+ `Creatable resources: ${CREATABLE_RESOURCES.join(', ')}.`, {
10
+ resource: z.enum(CREATABLE_RESOURCES).describe('The resource type to create'),
11
+ data: z.record(z.any()).describe('The resource data as a JSON object. Check Luminous docs for required fields.'),
12
+ }, async ({ resource, data }) => {
13
+ try {
14
+ const path = getResourcePath(resource);
15
+ const result = await luminousRequest({ method: 'POST', path, body: data });
16
+ return {
17
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
18
+ };
19
+ }
20
+ catch (err) {
21
+ return {
22
+ content: [{ type: 'text', text: JSON.stringify({ error: err.message }) }],
23
+ isError: true,
24
+ };
25
+ }
26
+ });
27
+ }
28
+ //# sourceMappingURL=create.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create.js","sourceRoot":"","sources":["../../src/tools/create.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,eAAe,EAAuB,MAAM,cAAc,CAAC;AAErF,MAAM,mBAAmB,GAAG;IAC1B,UAAU,EAAE,cAAc,EAAE,iBAAiB,EAAE,WAAW,EAAE,UAAU;IACtE,MAAM,EAAE,iBAAiB,EAAE,mBAAmB;CACtC,CAAC;AAEX,MAAM,UAAU,kBAAkB,CAAC,MAAiB;IAClD,MAAM,CAAC,IAAI,CACT,iBAAiB,EACjB,mFAAmF;QACnF,wBAAwB,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EACzD;QACE,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,QAAQ,CAAC,6BAA6B,CAAC;QAC7E,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,QAAQ,CAAC,8EAA8E,CAAC;KACjH,EACD,KAAK,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,EAAE;QAC3B,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;YACvC,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YAC3E,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;aAC5E,CAAC;QACJ,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;gBAClF,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerCustomFieldTools(server: McpServer): void;
@@ -0,0 +1,35 @@
1
+ import { z } from 'zod';
2
+ import { luminousRequest } from '../client.js';
3
+ const CF_RESOURCES = ['products', 'sales-orders', 'invoices', 'companies'];
4
+ export function registerCustomFieldTools(server) {
5
+ server.tool('luminous_custom_fields', 'Get or update custom field values on a resource. ' +
6
+ `Supported resources: ${CF_RESOURCES.join(', ')}.`, {
7
+ resource: z.enum(CF_RESOURCES).describe('The resource type'),
8
+ id: z.union([z.string(), z.number()]).describe('Resource ID'),
9
+ action: z.enum(['get', 'update']).describe('"get" to read values, "update" to set them'),
10
+ fields: z.record(z.any()).optional().describe('Custom field values to set (required for update), e.g. {"color": "Red", "size": "XL"}'),
11
+ }, async ({ resource, id, action, fields }) => {
12
+ try {
13
+ const path = `/${resource}/${id}/custom-fields`;
14
+ if (action === 'get') {
15
+ const result = await luminousRequest({ path });
16
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
17
+ }
18
+ if (!fields) {
19
+ return {
20
+ content: [{ type: 'text', text: JSON.stringify({ error: 'fields object is required for update' }) }],
21
+ isError: true,
22
+ };
23
+ }
24
+ const result = await luminousRequest({ method: 'PUT', path, body: { custom_fields: fields } });
25
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
26
+ }
27
+ catch (err) {
28
+ return {
29
+ content: [{ type: 'text', text: JSON.stringify({ error: err.message }) }],
30
+ isError: true,
31
+ };
32
+ }
33
+ });
34
+ }
35
+ //# sourceMappingURL=custom-fields.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"custom-fields.js","sourceRoot":"","sources":["../../src/tools/custom-fields.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C,MAAM,YAAY,GAAG,CAAC,UAAU,EAAE,cAAc,EAAE,UAAU,EAAE,WAAW,CAAU,CAAC;AAEpF,MAAM,UAAU,wBAAwB,CAAC,MAAiB;IACxD,MAAM,CAAC,IAAI,CACT,wBAAwB,EACxB,mDAAmD;QACnD,wBAAwB,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAClD;QACE,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,QAAQ,CAAC,mBAAmB,CAAC;QAC5D,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC;QAC7D,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,4CAA4C,CAAC;QACxF,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,uFAAuF,CAAC;KACvI,EACD,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE;QACzC,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,IAAI,QAAQ,IAAI,EAAE,gBAAgB,CAAC;YAEhD,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;gBACrB,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC/C,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;YACzF,CAAC;YAED,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,OAAO;oBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,sCAAsC,EAAE,CAAC,EAAE,CAAC;oBAC7G,OAAO,EAAE,IAAI;iBACd,CAAC;YACJ,CAAC;YAED,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,aAAa,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;YAC/F,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QACzF,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;gBAClF,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerDeleteTool(server: McpServer): void;
@@ -0,0 +1,27 @@
1
+ import { z } from 'zod';
2
+ import { luminousRequest, getResourcePath } from '../client.js';
3
+ const DELETABLE_RESOURCES = [
4
+ 'products', 'purchase-orders', 'companies', 'contacts', 'boms',
5
+ ];
6
+ export function registerDeleteTool(server) {
7
+ server.tool('luminous_delete', 'Delete a resource from Luminous by ID. This action cannot be undone. ' +
8
+ `Deletable resources: ${DELETABLE_RESOURCES.join(', ')}.`, {
9
+ resource: z.enum(DELETABLE_RESOURCES).describe('The resource type to delete'),
10
+ id: z.union([z.string(), z.number()]).describe('The resource ID'),
11
+ }, async ({ resource, id }) => {
12
+ try {
13
+ const path = `${getResourcePath(resource)}/${id}`;
14
+ const result = await luminousRequest({ method: 'DELETE', path });
15
+ return {
16
+ content: [{ type: 'text', text: JSON.stringify({ deleted: true, ...result }, null, 2) }],
17
+ };
18
+ }
19
+ catch (err) {
20
+ return {
21
+ content: [{ type: 'text', text: JSON.stringify({ error: err.message }) }],
22
+ isError: true,
23
+ };
24
+ }
25
+ });
26
+ }
27
+ //# sourceMappingURL=delete.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delete.js","sourceRoot":"","sources":["../../src/tools/delete.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEhE,MAAM,mBAAmB,GAAG;IAC1B,UAAU,EAAE,iBAAiB,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM;CACtD,CAAC;AAEX,MAAM,UAAU,kBAAkB,CAAC,MAAiB;IAClD,MAAM,CAAC,IAAI,CACT,iBAAiB,EACjB,uEAAuE;QACvE,wBAAwB,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EACzD;QACE,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,QAAQ,CAAC,6BAA6B,CAAC;QAC7E,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,iBAAiB,CAAC;KAClE,EACD,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,EAAE,EAAE;QACzB,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,GAAG,eAAe,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC;YAClD,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;YACjE,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;aAClG,CAAC;QACJ,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;gBAClF,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerGetTool(server: McpServer): void;
@@ -0,0 +1,23 @@
1
+ import { z } from 'zod';
2
+ import { luminousRequest, getResourcePath, AVAILABLE_RESOURCES } from '../client.js';
3
+ export function registerGetTool(server) {
4
+ server.tool('luminous_get', 'Get a single resource by ID from Luminous. Returns full details including related data.', {
5
+ resource: z.enum(AVAILABLE_RESOURCES).describe('The resource type'),
6
+ id: z.union([z.string(), z.number()]).describe('The resource ID'),
7
+ }, async ({ resource, id }) => {
8
+ try {
9
+ const path = `${getResourcePath(resource)}/${id}`;
10
+ const result = await luminousRequest({ path });
11
+ return {
12
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
13
+ };
14
+ }
15
+ catch (err) {
16
+ return {
17
+ content: [{ type: 'text', text: JSON.stringify({ error: err.message }) }],
18
+ isError: true,
19
+ };
20
+ }
21
+ });
22
+ }
23
+ //# sourceMappingURL=get.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get.js","sourceRoot":"","sources":["../../src/tools/get.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAErF,MAAM,UAAU,eAAe,CAAC,MAAiB;IAC/C,MAAM,CAAC,IAAI,CACT,cAAc,EACd,yFAAyF,EACzF;QACE,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,mBAA4C,CAAC,CAAC,QAAQ,CAAC,mBAAmB,CAAC;QAC5F,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,iBAAiB,CAAC;KAClE,EACD,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,EAAE,EAAE;QACzB,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,GAAG,eAAe,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC;YAClD,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;YAC/C,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;aAC5E,CAAC;QACJ,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;gBAClF,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerInventoryTools(server: McpServer): void;
@@ -0,0 +1,40 @@
1
+ import { z } from 'zod';
2
+ import { luminousRequest, buildFilterParams } from '../client.js';
3
+ export function registerInventoryTools(server) {
4
+ server.tool('luminous_inventory_stocks', 'Get current inventory stock levels. Filter by warehouse, location, product, SKU, etc.', {
5
+ filters: z.record(z.string()).optional().describe('Filter parameters, e.g. {"warehouse_id": "1", "sku[contains]": "BOLT"}'),
6
+ page: z.number().optional().describe('Page number'),
7
+ per_page: z.number().optional().describe('Items per page (max 100)'),
8
+ }, async ({ filters, page, per_page }) => {
9
+ try {
10
+ const query = buildFilterParams(filters, page, per_page);
11
+ const result = await luminousRequest({ path: '/inventory/stocks', query });
12
+ return {
13
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
14
+ };
15
+ }
16
+ catch (err) {
17
+ return {
18
+ content: [{ type: 'text', text: JSON.stringify({ error: err.message }) }],
19
+ isError: true,
20
+ };
21
+ }
22
+ });
23
+ server.tool('luminous_inventory_adjust', 'Adjust inventory stock levels for a product. Use positive quantities to add stock, negative to remove.', {
24
+ data: z.record(z.any()).describe('Adjustment data: {product_id, warehouse_id, location_id, quantity, reason, ...}'),
25
+ }, async ({ data }) => {
26
+ try {
27
+ const result = await luminousRequest({ method: 'POST', path: '/inventory/adjust', body: data });
28
+ return {
29
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
30
+ };
31
+ }
32
+ catch (err) {
33
+ return {
34
+ content: [{ type: 'text', text: JSON.stringify({ error: err.message }) }],
35
+ isError: true,
36
+ };
37
+ }
38
+ });
39
+ }
40
+ //# sourceMappingURL=inventory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inventory.js","sourceRoot":"","sources":["../../src/tools/inventory.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAElE,MAAM,UAAU,sBAAsB,CAAC,MAAiB;IACtD,MAAM,CAAC,IAAI,CACT,2BAA2B,EAC3B,uFAAuF,EACvF;QACE,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,wEAAwE,CAAC;QAC3H,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,aAAa,CAAC;QACnD,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,0BAA0B,CAAC;KACrE,EACD,KAAK,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE;QACpC,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,iBAAiB,CAAC,OAAO,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;YACzD,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,EAAE,IAAI,EAAE,mBAAmB,EAAE,KAAK,EAAE,CAAC,CAAC;YAC3E,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;aAC5E,CAAC;QACJ,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;gBAClF,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,2BAA2B,EAC3B,wGAAwG,EACxG;QACE,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,QAAQ,CAAC,iFAAiF,CAAC;KACpH,EACD,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;QACjB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YAChG,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;aAC5E,CAAC;QACJ,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;gBAClF,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerListTool(server: McpServer): void;
@@ -0,0 +1,29 @@
1
+ import { z } from 'zod';
2
+ import { luminousRequest, buildFilterParams, getResourcePath, AVAILABLE_RESOURCES } from '../client.js';
3
+ export function registerListTool(server) {
4
+ server.tool('luminous_list', `List resources from Luminous with optional filtering and pagination. Available resources: ${AVAILABLE_RESOURCES.join(', ')}. ` +
5
+ 'Filters use Luminous syntax like {"sku[eq]": "ABC", "name[contains]": "bolt", "order_date[gte]": "2025-01-01"}. ' +
6
+ 'Operators: eq, neq, gt, gte, lt, lte, contains, notcontains, in, notin, set, notset.', {
7
+ resource: z.enum(AVAILABLE_RESOURCES).describe('The resource type to list'),
8
+ filters: z.record(z.string()).optional().describe('Filter parameters, e.g. {"sku[contains]": "BOLT", "type": "PRODUCT"}'),
9
+ page: z.number().optional().describe('Page number (default: 1)'),
10
+ per_page: z.number().optional().describe('Items per page (default: 10, max: 100)'),
11
+ sort: z.string().optional().describe('Sort field and direction, e.g. "name:asc" or "created_at:desc"'),
12
+ }, async ({ resource, filters, page, per_page, sort }) => {
13
+ try {
14
+ const path = getResourcePath(resource);
15
+ const query = buildFilterParams(filters, page, per_page, sort);
16
+ const result = await luminousRequest({ path, query });
17
+ return {
18
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
19
+ };
20
+ }
21
+ catch (err) {
22
+ return {
23
+ content: [{ type: 'text', text: JSON.stringify({ error: err.message }) }],
24
+ isError: true,
25
+ };
26
+ }
27
+ });
28
+ }
29
+ //# sourceMappingURL=list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.js","sourceRoot":"","sources":["../../src/tools/list.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAExG,MAAM,UAAU,gBAAgB,CAAC,MAAiB;IAChD,MAAM,CAAC,IAAI,CACT,eAAe,EACf,6FAA6F,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;QAC/H,kHAAkH;QAClH,sFAAsF,EACtF;QACE,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,mBAA4C,CAAC,CAAC,QAAQ,CAAC,2BAA2B,CAAC;QACpG,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,sEAAsE,CAAC;QACzH,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,0BAA0B,CAAC;QAChE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,wCAAwC,CAAC;QAClF,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,gEAAgE,CAAC;KACvG,EACD,KAAK,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,EAAE;QACpD,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;YACvC,MAAM,KAAK,GAAG,iBAAiB,CAAC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;YAC/D,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;YACtD,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;aAC5E,CAAC;QACJ,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;gBAClF,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerProductTools(server: McpServer): void;
@@ -0,0 +1,41 @@
1
+ import { z } from 'zod';
2
+ import { luminousRequest } from '../client.js';
3
+ export function registerProductTools(server) {
4
+ server.tool('luminous_product_upsert', 'Create or update a product by SKU. If a product with the given SKU exists, it will be updated; otherwise a new product is created.', {
5
+ data: z.record(z.any()).describe('Product data including sku field. Same schema as create/update.'),
6
+ }, async ({ data }) => {
7
+ try {
8
+ const result = await luminousRequest({
9
+ method: 'POST',
10
+ path: '/products/create-or-update',
11
+ body: data,
12
+ });
13
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
14
+ }
15
+ catch (err) {
16
+ return {
17
+ content: [{ type: 'text', text: JSON.stringify({ error: err.message }) }],
18
+ isError: true,
19
+ };
20
+ }
21
+ });
22
+ server.tool('luminous_product_pricing', 'Get pricing information for a product, optionally for a specific company.', {
23
+ product_id: z.union([z.string(), z.number()]).describe('Product ID'),
24
+ company_id: z.union([z.string(), z.number()]).optional().describe('Company ID for company-specific pricing'),
25
+ }, async ({ product_id, company_id }) => {
26
+ try {
27
+ const path = company_id
28
+ ? `/products/${product_id}/pricing/companies/${company_id}`
29
+ : `/products/${product_id}/pricing`;
30
+ const result = await luminousRequest({ path });
31
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
32
+ }
33
+ catch (err) {
34
+ return {
35
+ content: [{ type: 'text', text: JSON.stringify({ error: err.message }) }],
36
+ isError: true,
37
+ };
38
+ }
39
+ });
40
+ }
41
+ //# sourceMappingURL=products.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"products.js","sourceRoot":"","sources":["../../src/tools/products.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C,MAAM,UAAU,oBAAoB,CAAC,MAAiB;IACpD,MAAM,CAAC,IAAI,CACT,yBAAyB,EACzB,oIAAoI,EACpI;QACE,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,QAAQ,CAAC,iEAAiE,CAAC;KACpG,EACD,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;QACjB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC;gBACnC,MAAM,EAAE,MAAM;gBACd,IAAI,EAAE,4BAA4B;gBAClC,IAAI,EAAE,IAAI;aACX,CAAC,CAAC;YACH,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QACzF,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;gBAClF,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,0BAA0B,EAC1B,2EAA2E,EAC3E;QACE,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC;QACpE,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,yCAAyC,CAAC;KAC7G,EACD,KAAK,EAAE,EAAE,UAAU,EAAE,UAAU,EAAE,EAAE,EAAE;QACnC,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,UAAU;gBACrB,CAAC,CAAC,aAAa,UAAU,sBAAsB,UAAU,EAAE;gBAC3D,CAAC,CAAC,aAAa,UAAU,UAAU,CAAC;YACtC,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;YAC/C,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QACzF,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;gBAClF,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerPurchaseOrderTools(server: McpServer): void;
@@ -0,0 +1,40 @@
1
+ import { z } from 'zod';
2
+ import { luminousRequest } from '../client.js';
3
+ export function registerPurchaseOrderTools(server) {
4
+ server.tool('luminous_purchase_order_payments', 'Manage payments on a purchase order: create, update, or delete.', {
5
+ order_id: z.union([z.string(), z.number()]).describe('Purchase order ID'),
6
+ action: z.enum(['create', 'update', 'delete']).describe('Payment action'),
7
+ payment_id: z.union([z.string(), z.number()]).optional().describe('Payment ID (required for update/delete)'),
8
+ data: z.record(z.any()).optional().describe('Payment data (required for create/update)'),
9
+ }, async ({ order_id, action, payment_id, data }) => {
10
+ try {
11
+ const basePath = `/purchase-orders/${order_id}/payments`;
12
+ if (action === 'create') {
13
+ const result = await luminousRequest({ method: 'POST', path: basePath, body: data });
14
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
15
+ }
16
+ if (!payment_id) {
17
+ return {
18
+ content: [{ type: 'text', text: JSON.stringify({ error: 'payment_id is required for update/delete' }) }],
19
+ isError: true,
20
+ };
21
+ }
22
+ const path = `${basePath}/${payment_id}`;
23
+ if (action === 'update') {
24
+ const result = await luminousRequest({ method: 'PUT', path, body: data });
25
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
26
+ }
27
+ else {
28
+ const result = await luminousRequest({ method: 'DELETE', path });
29
+ return { content: [{ type: 'text', text: JSON.stringify({ deleted: true, ...result }, null, 2) }] };
30
+ }
31
+ }
32
+ catch (err) {
33
+ return {
34
+ content: [{ type: 'text', text: JSON.stringify({ error: err.message }) }],
35
+ isError: true,
36
+ };
37
+ }
38
+ });
39
+ }
40
+ //# sourceMappingURL=purchase-orders.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"purchase-orders.js","sourceRoot":"","sources":["../../src/tools/purchase-orders.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerSalesOrderTools(server: McpServer): void;
@@ -0,0 +1,45 @@
1
+ import { z } from 'zod';
2
+ import { luminousRequest, buildFilterParams } from '../client.js';
3
+ export function registerSalesOrderTools(server) {
4
+ server.tool('luminous_sales_order_shipments', 'List or create shipments for a sales order.', {
5
+ order_id: z.union([z.string(), z.number()]).describe('Sales order ID'),
6
+ action: z.enum(['list', 'create']).describe('"list" to view shipments, "create" to create one'),
7
+ data: z.record(z.any()).optional().describe('Shipment data (required for create)'),
8
+ }, async ({ order_id, action, data }) => {
9
+ try {
10
+ const path = `/sales-orders/${order_id}/shipments`;
11
+ if (action === 'list') {
12
+ const result = await luminousRequest({ path });
13
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
14
+ }
15
+ else {
16
+ const result = await luminousRequest({ method: 'POST', path, body: data });
17
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
18
+ }
19
+ }
20
+ catch (err) {
21
+ return {
22
+ content: [{ type: 'text', text: JSON.stringify({ error: err.message }) }],
23
+ isError: true,
24
+ };
25
+ }
26
+ });
27
+ server.tool('luminous_sales_order_export', 'Incrementally export sales orders that have changed since a given date.', {
28
+ since: z.string().optional().describe('ISO date string to export changes since, e.g. "2025-01-01"'),
29
+ page: z.number().optional().describe('Page number'),
30
+ per_page: z.number().optional().describe('Items per page (max 100)'),
31
+ }, async ({ since, page, per_page }) => {
32
+ try {
33
+ const query = buildFilterParams(since ? { since } : undefined, page, per_page);
34
+ const result = await luminousRequest({ path: '/sales-orders/incremental-export', query });
35
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
36
+ }
37
+ catch (err) {
38
+ return {
39
+ content: [{ type: 'text', text: JSON.stringify({ error: err.message }) }],
40
+ isError: true,
41
+ };
42
+ }
43
+ });
44
+ }
45
+ //# sourceMappingURL=sales-orders.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sales-orders.js","sourceRoot":"","sources":["../../src/tools/sales-orders.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerTagTools(server: McpServer): void;
@@ -0,0 +1,40 @@
1
+ import { z } from 'zod';
2
+ import { luminousRequest } from '../client.js';
3
+ const TAGGABLE_RESOURCES = ['products', 'sales-orders', 'invoices', 'companies'];
4
+ export function registerTagTools(server) {
5
+ server.tool('luminous_tags', 'Get, attach, detach, or replace tags on a resource. ' +
6
+ `Taggable resources: ${TAGGABLE_RESOURCES.join(', ')}.`, {
7
+ resource: z.enum(TAGGABLE_RESOURCES).describe('The resource type'),
8
+ id: z.union([z.string(), z.number()]).describe('Resource ID'),
9
+ action: z.enum(['get', 'attach', 'detach', 'replace']).describe('Tag action'),
10
+ tags: z.array(z.string()).optional().describe('Tag names (required for attach/detach/replace)'),
11
+ }, async ({ resource, id, action, tags }) => {
12
+ try {
13
+ const path = `/${resource}/${id}/tags`;
14
+ if (action === 'get') {
15
+ const result = await luminousRequest({ path });
16
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
17
+ }
18
+ if (!tags || tags.length === 0) {
19
+ return {
20
+ content: [{ type: 'text', text: JSON.stringify({ error: 'tags array is required for attach/detach/replace' }) }],
21
+ isError: true,
22
+ };
23
+ }
24
+ const methodMap = { attach: 'POST', detach: 'DELETE', replace: 'PUT' };
25
+ const result = await luminousRequest({
26
+ method: methodMap[action],
27
+ path,
28
+ body: { tags },
29
+ });
30
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
31
+ }
32
+ catch (err) {
33
+ return {
34
+ content: [{ type: 'text', text: JSON.stringify({ error: err.message }) }],
35
+ isError: true,
36
+ };
37
+ }
38
+ });
39
+ }
40
+ //# sourceMappingURL=tags.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tags.js","sourceRoot":"","sources":["../../src/tools/tags.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C,MAAM,kBAAkB,GAAG,CAAC,UAAU,EAAE,cAAc,EAAE,UAAU,EAAE,WAAW,CAAU,CAAC;AAE1F,MAAM,UAAU,gBAAgB,CAAC,MAAiB;IAChD,MAAM,CAAC,IAAI,CACT,eAAe,EACf,sDAAsD;QACtD,uBAAuB,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EACvD;QACE,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,QAAQ,CAAC,mBAAmB,CAAC;QAClE,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC;QAC7D,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC;QAC7E,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,gDAAgD,CAAC;KAChG,EACD,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE;QACvC,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,IAAI,QAAQ,IAAI,EAAE,OAAO,CAAC;YAEvC,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;gBACrB,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC/C,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;YACzF,CAAC;YAED,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC/B,OAAO;oBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,kDAAkD,EAAE,CAAC,EAAE,CAAC;oBACzH,OAAO,EAAE,IAAI;iBACd,CAAC;YACJ,CAAC;YAED,MAAM,SAAS,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAW,CAAC;YAChF,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC;gBACnC,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC;gBACzB,IAAI;gBACJ,IAAI,EAAE,EAAE,IAAI,EAAE;aACf,CAAC,CAAC;YACH,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QACzF,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;gBAClF,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerUpdateTool(server: McpServer): void;
@@ -0,0 +1,28 @@
1
+ import { z } from 'zod';
2
+ import { luminousRequest, getResourcePath } from '../client.js';
3
+ const UPDATABLE_RESOURCES = [
4
+ 'products', 'purchase-orders', 'companies', 'contacts', 'boms',
5
+ ];
6
+ export function registerUpdateTool(server) {
7
+ server.tool('luminous_update', 'Update an existing resource in Luminous by ID. Pass only the fields you want to change. ' +
8
+ `Updatable resources: ${UPDATABLE_RESOURCES.join(', ')}.`, {
9
+ resource: z.enum(UPDATABLE_RESOURCES).describe('The resource type to update'),
10
+ id: z.union([z.string(), z.number()]).describe('The resource ID'),
11
+ data: z.record(z.any()).describe('Fields to update as a JSON object'),
12
+ }, async ({ resource, id, data }) => {
13
+ try {
14
+ const path = `${getResourcePath(resource)}/${id}`;
15
+ const result = await luminousRequest({ method: 'PUT', path, body: data });
16
+ return {
17
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
18
+ };
19
+ }
20
+ catch (err) {
21
+ return {
22
+ content: [{ type: 'text', text: JSON.stringify({ error: err.message }) }],
23
+ isError: true,
24
+ };
25
+ }
26
+ });
27
+ }
28
+ //# sourceMappingURL=update.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update.js","sourceRoot":"","sources":["../../src/tools/update.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEhE,MAAM,mBAAmB,GAAG;IAC1B,UAAU,EAAE,iBAAiB,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM;CACtD,CAAC;AAEX,MAAM,UAAU,kBAAkB,CAAC,MAAiB;IAClD,MAAM,CAAC,IAAI,CACT,iBAAiB,EACjB,0FAA0F;QAC1F,wBAAwB,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EACzD;QACE,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,QAAQ,CAAC,6BAA6B,CAAC;QAC7E,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,iBAAiB,CAAC;QACjE,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,QAAQ,CAAC,mCAAmC,CAAC;KACtE,EACD,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;QAC/B,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,GAAG,eAAe,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC;YAClD,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YAC1E,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;aAC5E,CAAC;QACJ,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;gBAClF,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@joinluminous/mcp-server",
3
+ "version": "1.0.0",
4
+ "description": "MCP server for the Luminous API — products, orders, inventory, companies, and more",
5
+ "type": "module",
6
+ "bin": {
7
+ "luminous-mcp-server": "./dist/index.js"
8
+ },
9
+ "exports": {
10
+ ".": "./dist/index.js"
11
+ },
12
+ "files": [
13
+ "dist"
14
+ ],
15
+ "scripts": {
16
+ "build": "tsc",
17
+ "dev": "tsx watch src/index.ts",
18
+ "start": "node dist/index.js",
19
+ "prepublishOnly": "npm run build"
20
+ },
21
+ "keywords": [
22
+ "mcp",
23
+ "luminous",
24
+ "claude",
25
+ "ai",
26
+ "inventory",
27
+ "erp"
28
+ ],
29
+ "license": "MIT",
30
+ "dependencies": {
31
+ "@modelcontextprotocol/sdk": "^1.12.1",
32
+ "zod": "^3.24.2"
33
+ },
34
+ "devDependencies": {
35
+ "@types/node": "^22.12.0",
36
+ "tsx": "^4.19.2",
37
+ "typescript": "^5.7.3"
38
+ }
39
+ }