@netlinksinc/odoo-mcp 0.1.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 (66) hide show
  1. package/LICENSE +21 -0
  2. package/dist/bin.d.ts +3 -0
  3. package/dist/bin.d.ts.map +1 -0
  4. package/dist/bin.js +37 -0
  5. package/dist/bin.js.map +1 -0
  6. package/dist/config.d.ts +7 -0
  7. package/dist/config.d.ts.map +1 -0
  8. package/dist/config.js +59 -0
  9. package/dist/config.js.map +1 -0
  10. package/dist/context.d.ts +16 -0
  11. package/dist/context.d.ts.map +1 -0
  12. package/dist/context.js +37 -0
  13. package/dist/context.js.map +1 -0
  14. package/dist/errors.d.ts +10 -0
  15. package/dist/errors.d.ts.map +1 -0
  16. package/dist/errors.js +15 -0
  17. package/dist/errors.js.map +1 -0
  18. package/dist/index.d.ts +3 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +2 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/logger.d.ts +26 -0
  23. package/dist/logger.d.ts.map +1 -0
  24. package/dist/logger.js +57 -0
  25. package/dist/logger.js.map +1 -0
  26. package/dist/probe.d.ts +19 -0
  27. package/dist/probe.d.ts.map +1 -0
  28. package/dist/probe.js +181 -0
  29. package/dist/probe.js.map +1 -0
  30. package/dist/resources.d.ts +11 -0
  31. package/dist/resources.d.ts.map +1 -0
  32. package/dist/resources.js +37 -0
  33. package/dist/resources.js.map +1 -0
  34. package/dist/server.d.ts +20 -0
  35. package/dist/server.d.ts.map +1 -0
  36. package/dist/server.js +32 -0
  37. package/dist/server.js.map +1 -0
  38. package/dist/tools/action.d.ts +6 -0
  39. package/dist/tools/action.d.ts.map +1 -0
  40. package/dist/tools/action.js +158 -0
  41. package/dist/tools/action.js.map +1 -0
  42. package/dist/tools/execute.d.ts +6 -0
  43. package/dist/tools/execute.d.ts.map +1 -0
  44. package/dist/tools/execute.js +156 -0
  45. package/dist/tools/execute.js.map +1 -0
  46. package/dist/tools/index.d.ts +5 -0
  47. package/dist/tools/index.d.ts.map +1 -0
  48. package/dist/tools/index.js +13 -0
  49. package/dist/tools/index.js.map +1 -0
  50. package/dist/tools/introspect.d.ts +6 -0
  51. package/dist/tools/introspect.d.ts.map +1 -0
  52. package/dist/tools/introspect.js +155 -0
  53. package/dist/tools/introspect.js.map +1 -0
  54. package/dist/tools/orm.d.ts +16 -0
  55. package/dist/tools/orm.d.ts.map +1 -0
  56. package/dist/tools/orm.js +139 -0
  57. package/dist/tools/orm.js.map +1 -0
  58. package/dist/tools/report.d.ts +6 -0
  59. package/dist/tools/report.d.ts.map +1 -0
  60. package/dist/tools/report.js +99 -0
  61. package/dist/tools/report.js.map +1 -0
  62. package/dist/tools/schemas.d.ts +202 -0
  63. package/dist/tools/schemas.d.ts.map +1 -0
  64. package/dist/tools/schemas.js +77 -0
  65. package/dist/tools/schemas.js.map +1 -0
  66. package/package.json +56 -0
@@ -0,0 +1,20 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { type OdooConfig } from '@netlinksinc/odoo-client';
3
+ import { type Logger } from './logger.js';
4
+ export interface McpServerConfig {
5
+ odooConfig: OdooConfig;
6
+ logFile?: string;
7
+ }
8
+ /**
9
+ * Wires all subsystems together and returns the ready-to-connect MCP server
10
+ * along with the logger instance (so bin.ts can call logger.startup and
11
+ * logger.shutdown without opening a second file descriptor on the log file).
12
+ *
13
+ * Authentication errors (OdooAuthError) are intentionally NOT caught here —
14
+ * they propagate to the caller (bin.ts), which serialises them to stderr.
15
+ */
16
+ export declare function createOdooMcpServer(config: McpServerConfig): Promise<{
17
+ server: McpServer;
18
+ logger: Logger;
19
+ }>;
20
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAc,KAAK,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAEvE,OAAO,EAAE,KAAK,MAAM,EAAgB,MAAM,aAAa,CAAC;AAKxD,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,UAAU,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,eAAe,GACtB,OAAO,CAAC;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAuBhD"}
package/dist/server.js ADDED
@@ -0,0 +1,32 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { OdooClient } from '@netlinksinc/odoo-client';
3
+ import { createLogger } from './logger.js';
4
+ import { runProbe } from './probe.js';
5
+ import { registerResources } from './resources.js';
6
+ import { registerAllTools } from './tools/index.js';
7
+ /**
8
+ * Wires all subsystems together and returns the ready-to-connect MCP server
9
+ * along with the logger instance (so bin.ts can call logger.startup and
10
+ * logger.shutdown without opening a second file descriptor on the log file).
11
+ *
12
+ * Authentication errors (OdooAuthError) are intentionally NOT caught here —
13
+ * they propagate to the caller (bin.ts), which serialises them to stderr.
14
+ */
15
+ export async function createOdooMcpServer(config) {
16
+ // 1. Build the Odoo client.
17
+ const client = new OdooClient(config.odooConfig);
18
+ // 2. Authenticate — may throw OdooAuthError; propagate to caller (US-2 AC-3).
19
+ const session = await client.authenticate();
20
+ // 3. Create logger (opens the log-file fd once).
21
+ const logger = createLogger(config.logFile);
22
+ // 4. Run the startup probe (never throws — always resolves).
23
+ const probe = await runProbe(client);
24
+ // 5. Create the MCP server.
25
+ const server = new McpServer({ name: 'odoo-mcp', version: '0.1.0' });
26
+ // 6. Register resources (static, backed by probe snapshot).
27
+ registerResources(server, probe);
28
+ // 7. Register all tool handlers.
29
+ registerAllTools(server, client, session, logger);
30
+ return { server, logger };
31
+ }
32
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,UAAU,EAAmB,MAAM,0BAA0B,CAAC;AAEvE,OAAO,EAAe,YAAY,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAOpD;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,MAAuB;IAEvB,4BAA4B;IAC5B,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IAEjD,8EAA8E;IAC9E,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,YAAY,EAAE,CAAC;IAE5C,iDAAiD;IACjD,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAE5C,6DAA6D;IAC7D,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC;IAErC,4BAA4B;IAC5B,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;IAErE,4DAA4D;IAC5D,iBAAiB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAEjC,iCAAiC;IACjC,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IAElD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AAC5B,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { type OdooSession } from '@netlinksinc/odoo-client';
3
+ import type { OdooClient } from '@netlinksinc/odoo-client';
4
+ import type { Logger } from '../logger.js';
5
+ export declare function registerActionTool(server: McpServer, client: OdooClient, session: OdooSession, logger: Logger): void;
6
+ //# sourceMappingURL=action.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"action.d.ts","sourceRoot":"","sources":["../../src/tools/action.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,EAAa,KAAK,WAAW,EAAgB,MAAM,0BAA0B,CAAC;AACrF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAI3D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAe3C,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,MAAM,GACb,IAAI,CAuJN"}
@@ -0,0 +1,158 @@
1
+ import { OdooError, sanitizeArgs } from '@netlinksinc/odoo-client';
2
+ import { buildContext, validateCompanySubset } from '../context.js';
3
+ import { formatMcpError } from '../errors.js';
4
+ import { callActionSchema } from './schemas.js';
5
+ function inputValidationError(message) {
6
+ return {
7
+ isError: true,
8
+ content: [
9
+ {
10
+ type: 'text',
11
+ text: JSON.stringify({ error_type: 'InputValidationError', message }),
12
+ },
13
+ ],
14
+ };
15
+ }
16
+ export function registerActionTool(server, client, session, logger) {
17
+ // Use the no-schema overload so we can return InputValidationError manually.
18
+ server.tool('odoo_call_action', async (args) => {
19
+ const start = Date.now();
20
+ // Step 1: parse with Zod schema (model + action_name regex enforced via MODEL_NAME/METHOD_NAME)
21
+ const parsed = callActionSchema.safeParse(args);
22
+ if (!parsed.success) {
23
+ logger.toolCall({
24
+ tool: 'odoo_call_action',
25
+ args_sanitized: sanitizeArgs('odoo_call_action', args),
26
+ latency_ms: Date.now() - start,
27
+ status: 'error',
28
+ error: 'InputValidationError',
29
+ });
30
+ return inputValidationError(parsed.error.message);
31
+ }
32
+ const data = parsed.data;
33
+ // Step 2: validate company subset if provided
34
+ if (data.allowed_company_ids !== undefined) {
35
+ try {
36
+ validateCompanySubset(data.allowed_company_ids, session.allowedCompanyIds);
37
+ }
38
+ catch (e) {
39
+ if (e instanceof OdooError) {
40
+ const latency_ms = Date.now() - start;
41
+ logger.toolCall({
42
+ tool: 'odoo_call_action',
43
+ args_sanitized: sanitizeArgs('odoo_call_action', args),
44
+ latency_ms,
45
+ status: 'error',
46
+ error: e.message,
47
+ });
48
+ return {
49
+ isError: true,
50
+ content: [
51
+ {
52
+ type: 'text',
53
+ text: JSON.stringify(formatMcpError(e)),
54
+ },
55
+ ],
56
+ };
57
+ }
58
+ // Non-OdooError from company validation — log and return as InternalError.
59
+ const message = e instanceof Error ? e.message : String(e);
60
+ const latency_ms = Date.now() - start;
61
+ logger.toolCall({
62
+ tool: 'odoo_call_action',
63
+ args_sanitized: sanitizeArgs('odoo_call_action', args),
64
+ latency_ms,
65
+ status: 'error',
66
+ error: 'InternalError',
67
+ });
68
+ return {
69
+ isError: true,
70
+ content: [
71
+ {
72
+ type: 'text',
73
+ text: JSON.stringify({
74
+ error_type: 'InternalError',
75
+ message: 'unexpected error',
76
+ detail: message,
77
+ }),
78
+ },
79
+ ],
80
+ };
81
+ }
82
+ }
83
+ // Step 3: merge caller context with company context.
84
+ // buildContext re-applies uid/company_id/allowed_company_ids AFTER extraContext
85
+ // so caller-supplied context CANNOT override identity (US-5 AC-4 + US-7 AC-7).
86
+ const context = buildContext(session, {
87
+ allowed_company_ids: data.allowed_company_ids,
88
+ active_company_id: data.active_company_id,
89
+ }, data.context);
90
+ // Step 4: call client.callAction
91
+ try {
92
+ const result = await client.callAction(data.model, data.ids, data.action_name, context);
93
+ const latency_ms = Date.now() - start;
94
+ // Step 5: return result and log
95
+ logger.toolCall({
96
+ tool: 'odoo_call_action',
97
+ args_sanitized: sanitizeArgs('odoo_call_action', args),
98
+ latency_ms,
99
+ status: 'ok',
100
+ });
101
+ return {
102
+ isError: false,
103
+ content: [
104
+ {
105
+ type: 'text',
106
+ text: JSON.stringify(result),
107
+ },
108
+ ],
109
+ };
110
+ }
111
+ catch (e) {
112
+ // Step 6: on OdooError, format and return isError:true
113
+ if (e instanceof OdooError) {
114
+ const latency_ms = Date.now() - start;
115
+ logger.toolCall({
116
+ tool: 'odoo_call_action',
117
+ args_sanitized: sanitizeArgs('odoo_call_action', args),
118
+ latency_ms,
119
+ status: 'error',
120
+ error: e.message,
121
+ });
122
+ return {
123
+ isError: true,
124
+ content: [
125
+ {
126
+ type: 'text',
127
+ text: JSON.stringify(formatMcpError(e)),
128
+ },
129
+ ],
130
+ };
131
+ }
132
+ // Step 7: Non-OdooError — unexpected exception. Log + return as InternalError-shaped.
133
+ const message = e instanceof Error ? e.message : String(e);
134
+ const latency_ms = Date.now() - start;
135
+ logger.toolCall({
136
+ tool: 'odoo_call_action',
137
+ args_sanitized: sanitizeArgs('odoo_call_action', args),
138
+ latency_ms,
139
+ status: 'error',
140
+ error: 'InternalError',
141
+ });
142
+ return {
143
+ isError: true,
144
+ content: [
145
+ {
146
+ type: 'text',
147
+ text: JSON.stringify({
148
+ error_type: 'InternalError',
149
+ message: 'unexpected error',
150
+ detail: message,
151
+ }),
152
+ },
153
+ ],
154
+ };
155
+ }
156
+ });
157
+ }
158
+ //# sourceMappingURL=action.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"action.js","sourceRoot":"","sources":["../../src/tools/action.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { type OdooSession } from '@netlinksinc/odoo-client';
3
+ import type { OdooClient } from '@netlinksinc/odoo-client';
4
+ import type { Logger } from '../logger.js';
5
+ export declare function registerExecuteTool(server: McpServer, client: OdooClient, session: OdooSession, logger: Logger): void;
6
+ //# sourceMappingURL=execute.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"execute.d.ts","sourceRoot":"","sources":["../../src/tools/execute.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,EAA2B,KAAK,WAAW,EAAgB,MAAM,0BAA0B,CAAC;AACnG,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAI3D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAe3C,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,MAAM,GACb,IAAI,CAiJN"}
@@ -0,0 +1,156 @@
1
+ import { OdooError, sanitizeArgs } from '@netlinksinc/odoo-client';
2
+ import { buildContext, validateCompanySubset } from '../context.js';
3
+ import { formatMcpError } from '../errors.js';
4
+ import { executeSchema } from './schemas.js';
5
+ function inputValidationError(message) {
6
+ return {
7
+ isError: true,
8
+ content: [
9
+ {
10
+ type: 'text',
11
+ text: JSON.stringify({ error_type: 'InputValidationError', message }),
12
+ },
13
+ ],
14
+ };
15
+ }
16
+ export function registerExecuteTool(server, client, session, logger) {
17
+ // Use the no-schema overload so we can return InputValidationError manually.
18
+ server.tool('odoo_execute', async (args) => {
19
+ const start = Date.now();
20
+ // Step 1: parse with Zod schema (includes model + method regex via MODEL_NAME/METHOD_NAME)
21
+ const parsed = executeSchema.safeParse(args);
22
+ if (!parsed.success) {
23
+ logger.toolCall({
24
+ tool: 'odoo_execute',
25
+ args_sanitized: sanitizeArgs('odoo_execute', args),
26
+ latency_ms: Date.now() - start,
27
+ status: 'error',
28
+ error: 'InputValidationError',
29
+ });
30
+ return inputValidationError(parsed.error.message);
31
+ }
32
+ const data = parsed.data;
33
+ // Step 2: validate company subset if provided
34
+ if (data.allowed_company_ids !== undefined) {
35
+ try {
36
+ validateCompanySubset(data.allowed_company_ids, session.allowedCompanyIds);
37
+ }
38
+ catch (e) {
39
+ if (e instanceof OdooError) {
40
+ const latency_ms = Date.now() - start;
41
+ logger.toolCall({
42
+ tool: 'odoo_execute',
43
+ args_sanitized: sanitizeArgs('odoo_execute', args),
44
+ latency_ms,
45
+ status: 'error',
46
+ error: e.message,
47
+ });
48
+ return {
49
+ isError: true,
50
+ content: [
51
+ {
52
+ type: 'text',
53
+ text: JSON.stringify(formatMcpError(e)),
54
+ },
55
+ ],
56
+ };
57
+ }
58
+ // Non-OdooError from company validation — log and return as InternalError.
59
+ const message = e instanceof Error ? e.message : String(e);
60
+ const latency_ms = Date.now() - start;
61
+ logger.toolCall({
62
+ tool: 'odoo_execute',
63
+ args_sanitized: sanitizeArgs('odoo_execute', args),
64
+ latency_ms,
65
+ status: 'error',
66
+ error: 'InternalError',
67
+ });
68
+ return {
69
+ isError: true,
70
+ content: [
71
+ {
72
+ type: 'text',
73
+ text: JSON.stringify({
74
+ error_type: 'InternalError',
75
+ message: 'unexpected error',
76
+ detail: message,
77
+ }),
78
+ },
79
+ ],
80
+ };
81
+ }
82
+ }
83
+ // Step 3: build context
84
+ const context = buildContext(session, {
85
+ allowed_company_ids: data.allowed_company_ids,
86
+ active_company_id: data.active_company_id,
87
+ });
88
+ // Step 4: call client.execute
89
+ try {
90
+ const result = await client.execute(data.model, data.method, data.args, data.kwargs, context);
91
+ const latency_ms = Date.now() - start;
92
+ // Step 5 & 6: return result and log
93
+ logger.toolCall({
94
+ tool: 'odoo_execute',
95
+ args_sanitized: sanitizeArgs('odoo_execute', args),
96
+ latency_ms,
97
+ status: 'ok',
98
+ });
99
+ return {
100
+ isError: false,
101
+ content: [
102
+ {
103
+ type: 'text',
104
+ text: JSON.stringify(result),
105
+ },
106
+ ],
107
+ };
108
+ }
109
+ catch (e) {
110
+ // Step 7: on OdooError, format and return isError:true
111
+ if (e instanceof OdooError) {
112
+ const latency_ms = Date.now() - start;
113
+ logger.toolCall({
114
+ tool: 'odoo_execute',
115
+ args_sanitized: sanitizeArgs('odoo_execute', args),
116
+ latency_ms,
117
+ status: 'error',
118
+ error: e.message,
119
+ });
120
+ return {
121
+ isError: true,
122
+ content: [
123
+ {
124
+ type: 'text',
125
+ text: JSON.stringify(formatMcpError(e)),
126
+ },
127
+ ],
128
+ };
129
+ }
130
+ // Step 8: Non-OdooError — unexpected exception. Log + return as InternalError-shaped.
131
+ const message = e instanceof Error ? e.message : String(e);
132
+ const latency_ms = Date.now() - start;
133
+ logger.toolCall({
134
+ tool: 'odoo_execute',
135
+ args_sanitized: sanitizeArgs('odoo_execute', args),
136
+ latency_ms,
137
+ status: 'error',
138
+ error: 'InternalError',
139
+ });
140
+ return {
141
+ isError: true,
142
+ content: [
143
+ {
144
+ type: 'text',
145
+ text: JSON.stringify({
146
+ error_type: 'InternalError',
147
+ message: 'unexpected error',
148
+ detail: message,
149
+ }),
150
+ },
151
+ ],
152
+ };
153
+ }
154
+ });
155
+ }
156
+ //# sourceMappingURL=execute.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"execute.js","sourceRoot":"","sources":["../../src/tools/execute.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { OdooClient, OdooSession } from '@netlinksinc/odoo-client';
3
+ import type { Logger } from '../logger.js';
4
+ export declare function registerAllTools(server: McpServer, client: OdooClient, session: OdooSession, logger: Logger): void;
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAExE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAO3C,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,MAAM,GACb,IAAI,CAMN"}
@@ -0,0 +1,13 @@
1
+ import { registerActionTool } from './action.js';
2
+ import { registerExecuteTool } from './execute.js';
3
+ import { registerIntrospectTool } from './introspect.js';
4
+ import { registerOrmTools } from './orm.js';
5
+ import { registerReportTool } from './report.js';
6
+ export function registerAllTools(server, client, session, logger) {
7
+ registerOrmTools(server, client, session, logger);
8
+ registerExecuteTool(server, client, session, logger);
9
+ registerReportTool(server, client, session, logger);
10
+ registerActionTool(server, client, session, logger);
11
+ registerIntrospectTool(server, client, session, logger);
12
+ }
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEjD,MAAM,UAAU,gBAAgB,CAC9B,MAAiB,EACjB,MAAkB,EAClB,OAAoB,EACpB,MAAc;IAEd,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IAClD,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IACrD,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IACpD,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IACpD,sBAAsB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;AAC1D,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { type OdooSession } from '@netlinksinc/odoo-client';
3
+ import type { OdooClient } from '@netlinksinc/odoo-client';
4
+ import type { Logger } from '../logger.js';
5
+ export declare function registerIntrospectTool(server: McpServer, client: OdooClient, session: OdooSession, logger: Logger): void;
6
+ //# sourceMappingURL=introspect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"introspect.d.ts","sourceRoot":"","sources":["../../src/tools/introspect.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,EAAa,KAAK,WAAW,EAAgB,MAAM,0BAA0B,CAAC;AACrF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAI3D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAe3C,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,MAAM,GACb,IAAI,CAgJN"}
@@ -0,0 +1,155 @@
1
+ import { OdooError, sanitizeArgs } from '@netlinksinc/odoo-client';
2
+ import { buildContext, validateCompanySubset } from '../context.js';
3
+ import { formatMcpError } from '../errors.js';
4
+ import { fieldsGetSchema } from './schemas.js';
5
+ function inputValidationError(message) {
6
+ return {
7
+ isError: true,
8
+ content: [
9
+ {
10
+ type: 'text',
11
+ text: JSON.stringify({ error_type: 'InputValidationError', message }),
12
+ },
13
+ ],
14
+ };
15
+ }
16
+ export function registerIntrospectTool(server, client, session, logger) {
17
+ server.tool('odoo_fields_get', async (args) => {
18
+ const start = Date.now();
19
+ // Step 1: parse with Zod schema (model regex enforced via MODEL_NAME)
20
+ const parsed = fieldsGetSchema.safeParse(args);
21
+ if (!parsed.success) {
22
+ logger.toolCall({
23
+ tool: 'odoo_fields_get',
24
+ args_sanitized: sanitizeArgs('odoo_fields_get', args),
25
+ latency_ms: Date.now() - start,
26
+ status: 'error',
27
+ error: 'InputValidationError',
28
+ });
29
+ return inputValidationError(parsed.error.message);
30
+ }
31
+ const data = parsed.data;
32
+ // Step 2: validate company subset if provided
33
+ if (data.allowed_company_ids !== undefined) {
34
+ try {
35
+ validateCompanySubset(data.allowed_company_ids, session.allowedCompanyIds);
36
+ }
37
+ catch (e) {
38
+ if (e instanceof OdooError) {
39
+ const latency_ms = Date.now() - start;
40
+ logger.toolCall({
41
+ tool: 'odoo_fields_get',
42
+ args_sanitized: sanitizeArgs('odoo_fields_get', args),
43
+ latency_ms,
44
+ status: 'error',
45
+ error: e.message,
46
+ });
47
+ return {
48
+ isError: true,
49
+ content: [
50
+ {
51
+ type: 'text',
52
+ text: JSON.stringify(formatMcpError(e)),
53
+ },
54
+ ],
55
+ };
56
+ }
57
+ // Non-OdooError from company validation — log and return as InternalError.
58
+ const message = e instanceof Error ? e.message : String(e);
59
+ const latency_ms = Date.now() - start;
60
+ logger.toolCall({
61
+ tool: 'odoo_fields_get',
62
+ args_sanitized: sanitizeArgs('odoo_fields_get', args),
63
+ latency_ms,
64
+ status: 'error',
65
+ error: 'InternalError',
66
+ });
67
+ return {
68
+ isError: true,
69
+ content: [
70
+ {
71
+ type: 'text',
72
+ text: JSON.stringify({
73
+ error_type: 'InternalError',
74
+ message: 'unexpected error',
75
+ detail: message,
76
+ }),
77
+ },
78
+ ],
79
+ };
80
+ }
81
+ }
82
+ // Step 3: build context (no extraContext for fields_get)
83
+ const context = buildContext(session, {
84
+ allowed_company_ids: data.allowed_company_ids,
85
+ active_company_id: data.active_company_id,
86
+ });
87
+ // Step 4: call client.fieldsGet — pass attributes as-is (undefined if not provided)
88
+ try {
89
+ const result = await client.fieldsGet(data.model, data.attributes, context);
90
+ const latency_ms = Date.now() - start;
91
+ // Step 5: return result and log
92
+ logger.toolCall({
93
+ tool: 'odoo_fields_get',
94
+ args_sanitized: sanitizeArgs('odoo_fields_get', args),
95
+ latency_ms,
96
+ status: 'ok',
97
+ });
98
+ return {
99
+ isError: false,
100
+ content: [
101
+ {
102
+ type: 'text',
103
+ text: JSON.stringify(result),
104
+ },
105
+ ],
106
+ };
107
+ }
108
+ catch (e) {
109
+ // Step 6: on OdooError, format and return isError:true
110
+ if (e instanceof OdooError) {
111
+ const latency_ms = Date.now() - start;
112
+ logger.toolCall({
113
+ tool: 'odoo_fields_get',
114
+ args_sanitized: sanitizeArgs('odoo_fields_get', args),
115
+ latency_ms,
116
+ status: 'error',
117
+ error: e.message,
118
+ });
119
+ return {
120
+ isError: true,
121
+ content: [
122
+ {
123
+ type: 'text',
124
+ text: JSON.stringify(formatMcpError(e)),
125
+ },
126
+ ],
127
+ };
128
+ }
129
+ // Step 7: Non-OdooError — unexpected exception. Log + return as InternalError-shaped.
130
+ const message = e instanceof Error ? e.message : String(e);
131
+ const latency_ms = Date.now() - start;
132
+ logger.toolCall({
133
+ tool: 'odoo_fields_get',
134
+ args_sanitized: sanitizeArgs('odoo_fields_get', args),
135
+ latency_ms,
136
+ status: 'error',
137
+ error: 'InternalError',
138
+ });
139
+ return {
140
+ isError: true,
141
+ content: [
142
+ {
143
+ type: 'text',
144
+ text: JSON.stringify({
145
+ error_type: 'InternalError',
146
+ message: 'unexpected error',
147
+ detail: message,
148
+ }),
149
+ },
150
+ ],
151
+ };
152
+ }
153
+ });
154
+ }
155
+ //# sourceMappingURL=introspect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"introspect.js","sourceRoot":"","sources":["../../src/tools/introspect.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAoB,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAGrF,OAAO,EAAE,YAAY,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C,SAAS,oBAAoB,CAAC,OAAe;IAC3C,OAAO;QACL,OAAO,EAAE,IAAa;QACtB,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,MAAe;gBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,UAAU,EAAE,sBAAsB,EAAE,OAAO,EAAE,CAAC;aACtE;SACF;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,sBAAsB,CACpC,MAAiB,EACjB,MAAkB,EAClB,OAAoB,EACpB,MAAc;IAEd,MAAM,CAAC,IAAI,CAAC,iBAAiB,EAAE,KAAK,EAAE,IAA6B,EAAE,EAAE;QACrE,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAEzB,sEAAsE;QACtE,MAAM,MAAM,GAAG,eAAe,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAC/C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,MAAM,CAAC,QAAQ,CAAC;gBACd,IAAI,EAAE,iBAAiB;gBACvB,cAAc,EAAE,YAAY,CAAC,iBAAiB,EAAE,IAAI,CAAC;gBACrD,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK;gBAC9B,MAAM,EAAE,OAAO;gBACf,KAAK,EAAE,sBAAsB;aAC9B,CAAC,CAAC;YACH,OAAO,oBAAoB,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACpD,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;QAEzB,8CAA8C;QAC9C,IAAI,IAAI,CAAC,mBAAmB,KAAK,SAAS,EAAE,CAAC;YAC3C,IAAI,CAAC;gBACH,qBAAqB,CAAC,IAAI,CAAC,mBAAmB,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAC;YAC7E,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,IAAI,CAAC,YAAY,SAAS,EAAE,CAAC;oBAC3B,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;oBACtC,MAAM,CAAC,QAAQ,CAAC;wBACd,IAAI,EAAE,iBAAiB;wBACvB,cAAc,EAAE,YAAY,CAAC,iBAAiB,EAAE,IAAI,CAAC;wBACrD,UAAU;wBACV,MAAM,EAAE,OAAO;wBACf,KAAK,EAAE,CAAC,CAAC,OAAO;qBACjB,CAAC,CAAC;oBACH,OAAO;wBACL,OAAO,EAAE,IAAa;wBACtB,OAAO,EAAE;4BACP;gCACE,IAAI,EAAE,MAAe;gCACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;6BACxC;yBACF;qBACF,CAAC;gBACJ,CAAC;gBACD,2EAA2E;gBAC3E,MAAM,OAAO,GAAG,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;gBAC3D,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;gBACtC,MAAM,CAAC,QAAQ,CAAC;oBACd,IAAI,EAAE,iBAAiB;oBACvB,cAAc,EAAE,YAAY,CAAC,iBAAiB,EAAE,IAAI,CAAC;oBACrD,UAAU;oBACV,MAAM,EAAE,OAAO;oBACf,KAAK,EAAE,eAAe;iBACvB,CAAC,CAAC;gBACH,OAAO;oBACL,OAAO,EAAE,IAAa;oBACtB,OAAO,EAAE;wBACP;4BACE,IAAI,EAAE,MAAe;4BACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gCACnB,UAAU,EAAE,eAAe;gCAC3B,OAAO,EAAE,kBAAkB;gCAC3B,MAAM,EAAE,OAAO;6BAChB,CAAC;yBACH;qBACF;iBACF,CAAC;YACJ,CAAC;QACH,CAAC;QAED,yDAAyD;QACzD,MAAM,OAAO,GAAG,YAAY,CAAC,OAAO,EAAE;YACpC,mBAAmB,EAAE,IAAI,CAAC,mBAAmB;YAC7C,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;SAC1C,CAAC,CAAC;QAEH,oFAAoF;QACpF,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YAE5E,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;YAEtC,gCAAgC;YAChC,MAAM,CAAC,QAAQ,CAAC;gBACd,IAAI,EAAE,iBAAiB;gBACvB,cAAc,EAAE,YAAY,CAAC,iBAAiB,EAAE,IAAI,CAAC;gBACrD,UAAU;gBACV,MAAM,EAAE,IAAI;aACb,CAAC,CAAC;YAEH,OAAO;gBACL,OAAO,EAAE,KAAc;gBACvB,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;qBAC7B;iBACF;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,uDAAuD;YACvD,IAAI,CAAC,YAAY,SAAS,EAAE,CAAC;gBAC3B,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;gBACtC,MAAM,CAAC,QAAQ,CAAC;oBACd,IAAI,EAAE,iBAAiB;oBACvB,cAAc,EAAE,YAAY,CAAC,iBAAiB,EAAE,IAAI,CAAC;oBACrD,UAAU;oBACV,MAAM,EAAE,OAAO;oBACf,KAAK,EAAE,CAAC,CAAC,OAAO;iBACjB,CAAC,CAAC;gBACH,OAAO;oBACL,OAAO,EAAE,IAAa;oBACtB,OAAO,EAAE;wBACP;4BACE,IAAI,EAAE,MAAe;4BACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;yBACxC;qBACF;iBACF,CAAC;YACJ,CAAC;YACD,sFAAsF;YACtF,MAAM,OAAO,GAAG,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YAC3D,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;YACtC,MAAM,CAAC,QAAQ,CAAC;gBACd,IAAI,EAAE,iBAAiB;gBACvB,cAAc,EAAE,YAAY,CAAC,iBAAiB,EAAE,IAAI,CAAC;gBACrD,UAAU;gBACV,MAAM,EAAE,OAAO;gBACf,KAAK,EAAE,eAAe;aACvB,CAAC,CAAC;YACH,OAAO;gBACL,OAAO,EAAE,IAAa;gBACtB,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;4BACnB,UAAU,EAAE,eAAe;4BAC3B,OAAO,EAAE,kBAAkB;4BAC3B,MAAM,EAAE,OAAO;yBAChB,CAAC;qBACH;iBACF;aACF,CAAC;QACJ,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { type OdooSession } from '@netlinksinc/odoo-client';
3
+ import type { OdooClient } from '@netlinksinc/odoo-client';
4
+ import type { Logger } from '../logger.js';
5
+ /**
6
+ * Register all 6 ORM tools on the MCP server.
7
+ *
8
+ * Tools registered: odoo_search_read, odoo_read, odoo_create, odoo_write,
9
+ * odoo_unlink, odoo_search_count.
10
+ *
11
+ * The server.tool(name, cb) 2-arg overload is used deliberately so that
12
+ * validation failures return `isError: true` rather than a thrown McpError.
13
+ * Tests drive the handlers via a lightweight mock that stores the callback.
14
+ */
15
+ export declare function registerOrmTools(server: McpServer, client: OdooClient, session: OdooSession, logger: Logger): void;
16
+ //# sourceMappingURL=orm.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orm.d.ts","sourceRoot":"","sources":["../../src/tools/orm.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,EAA2B,KAAK,WAAW,EAAgB,MAAM,0BAA0B,CAAC;AACnG,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAK3D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAmH3C;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,MAAM,GACb,IAAI,CAiHN"}