@netlinksinc/odoo-mcp 0.1.0 → 0.1.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.
@@ -1 +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"}
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;AAG3C,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,MAAM,GACb,IAAI,CA4EN"}
@@ -2,145 +2,60 @@ import { OdooError, sanitizeArgs } from '@netlinksinc/odoo-client';
2
2
  import { buildContext, validateCompanySubset } from '../context.js';
3
3
  import { formatMcpError } from '../errors.js';
4
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
5
  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
6
+ server.registerTool('odoo_call_action', {
7
+ description: 'Call a named server action (a method) on a model. Caller-supplied `context` merges with session context but cannot override `uid` or `company_id`.',
8
+ inputSchema: callActionSchema.shape,
9
+ }, async (args) => {
10
+ const t0 = Date.now();
11
+ const rawArgs = args;
91
12
  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
13
+ if (args.allowed_company_ids) {
14
+ validateCompanySubset(args.allowed_company_ids, session.allowedCompanyIds);
15
+ }
16
+ // buildContext re-applies session-authoritative fields AFTER extraContext
17
+ // so caller-supplied context cannot override identity (US-5 AC-4 + US-7 AC-7).
18
+ const context = buildContext(session, {
19
+ allowed_company_ids: args.allowed_company_ids,
20
+ active_company_id: args.active_company_id,
21
+ }, args.context);
22
+ const result = await client.callAction(args.model, args.ids, args.action_name, context);
95
23
  logger.toolCall({
96
24
  tool: 'odoo_call_action',
97
- args_sanitized: sanitizeArgs('odoo_call_action', args),
98
- latency_ms,
25
+ args_sanitized: sanitizeArgs('odoo_call_action', rawArgs),
26
+ latency_ms: Date.now() - t0,
99
27
  status: 'ok',
100
28
  });
101
29
  return {
30
+ content: [{ type: 'text', text: JSON.stringify(result) }],
102
31
  isError: false,
103
- content: [
104
- {
105
- type: 'text',
106
- text: JSON.stringify(result),
107
- },
108
- ],
109
32
  };
110
33
  }
111
34
  catch (e) {
112
- // Step 6: on OdooError, format and return isError:true
35
+ const latency_ms = Date.now() - t0;
113
36
  if (e instanceof OdooError) {
114
- const latency_ms = Date.now() - start;
37
+ const formatted = formatMcpError(e);
115
38
  logger.toolCall({
116
39
  tool: 'odoo_call_action',
117
- args_sanitized: sanitizeArgs('odoo_call_action', args),
40
+ args_sanitized: sanitizeArgs('odoo_call_action', rawArgs),
118
41
  latency_ms,
119
42
  status: 'error',
120
- error: e.message,
43
+ error: formatted.error_type,
121
44
  });
122
45
  return {
46
+ content: [{ type: 'text', text: JSON.stringify(formatted) }],
123
47
  isError: true,
124
- content: [
125
- {
126
- type: 'text',
127
- text: JSON.stringify(formatMcpError(e)),
128
- },
129
- ],
130
48
  };
131
49
  }
132
- // Step 7: Non-OdooError — unexpected exception. Log + return as InternalError-shaped.
133
50
  const message = e instanceof Error ? e.message : String(e);
134
- const latency_ms = Date.now() - start;
135
51
  logger.toolCall({
136
52
  tool: 'odoo_call_action',
137
- args_sanitized: sanitizeArgs('odoo_call_action', args),
53
+ args_sanitized: sanitizeArgs('odoo_call_action', rawArgs),
138
54
  latency_ms,
139
55
  status: 'error',
140
56
  error: 'InternalError',
141
57
  });
142
58
  return {
143
- isError: true,
144
59
  content: [
145
60
  {
146
61
  type: 'text',
@@ -151,6 +66,7 @@ export function registerActionTool(server, client, session, logger) {
151
66
  }),
152
67
  },
153
68
  ],
69
+ isError: true,
154
70
  };
155
71
  }
156
72
  });
@@ -1 +1 @@
1
- {"version":3,"file":"action.js","sourceRoot":"","sources":["../../src/tools/action.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"action.js","sourceRoot":"","sources":["../../src/tools/action.ts"],"names":[],"mappings":"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"}
@@ -1 +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"}
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;AAG3C,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,MAAM,GACb,IAAI,CA4EN"}
@@ -2,143 +2,58 @@ import { OdooError, sanitizeArgs } from '@netlinksinc/odoo-client';
2
2
  import { buildContext, validateCompanySubset } from '../context.js';
3
3
  import { formatMcpError } from '../errors.js';
4
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
5
  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
6
+ server.registerTool('odoo_execute', {
7
+ description: 'Call any model method (execute_kw). Use this for operations not covered by the typed CRUD tools. Model and method are regex-validated.',
8
+ inputSchema: executeSchema.shape,
9
+ }, async (args) => {
10
+ const t0 = Date.now();
11
+ const rawArgs = args;
89
12
  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
13
+ if (args.allowed_company_ids) {
14
+ validateCompanySubset(args.allowed_company_ids, session.allowedCompanyIds);
15
+ }
16
+ const context = buildContext(session, {
17
+ allowed_company_ids: args.allowed_company_ids,
18
+ active_company_id: args.active_company_id,
19
+ });
20
+ const result = await client.execute(args.model, args.method, args.args, args.kwargs, context);
93
21
  logger.toolCall({
94
22
  tool: 'odoo_execute',
95
- args_sanitized: sanitizeArgs('odoo_execute', args),
96
- latency_ms,
23
+ args_sanitized: sanitizeArgs('odoo_execute', rawArgs),
24
+ latency_ms: Date.now() - t0,
97
25
  status: 'ok',
98
26
  });
99
27
  return {
28
+ content: [{ type: 'text', text: JSON.stringify(result) }],
100
29
  isError: false,
101
- content: [
102
- {
103
- type: 'text',
104
- text: JSON.stringify(result),
105
- },
106
- ],
107
30
  };
108
31
  }
109
32
  catch (e) {
110
- // Step 7: on OdooError, format and return isError:true
33
+ const latency_ms = Date.now() - t0;
111
34
  if (e instanceof OdooError) {
112
- const latency_ms = Date.now() - start;
35
+ const formatted = formatMcpError(e);
113
36
  logger.toolCall({
114
37
  tool: 'odoo_execute',
115
- args_sanitized: sanitizeArgs('odoo_execute', args),
38
+ args_sanitized: sanitizeArgs('odoo_execute', rawArgs),
116
39
  latency_ms,
117
40
  status: 'error',
118
- error: e.message,
41
+ error: formatted.error_type,
119
42
  });
120
43
  return {
44
+ content: [{ type: 'text', text: JSON.stringify(formatted) }],
121
45
  isError: true,
122
- content: [
123
- {
124
- type: 'text',
125
- text: JSON.stringify(formatMcpError(e)),
126
- },
127
- ],
128
46
  };
129
47
  }
130
- // Step 8: Non-OdooError — unexpected exception. Log + return as InternalError-shaped.
131
48
  const message = e instanceof Error ? e.message : String(e);
132
- const latency_ms = Date.now() - start;
133
49
  logger.toolCall({
134
50
  tool: 'odoo_execute',
135
- args_sanitized: sanitizeArgs('odoo_execute', args),
51
+ args_sanitized: sanitizeArgs('odoo_execute', rawArgs),
136
52
  latency_ms,
137
53
  status: 'error',
138
54
  error: 'InternalError',
139
55
  });
140
56
  return {
141
- isError: true,
142
57
  content: [
143
58
  {
144
59
  type: 'text',
@@ -149,6 +64,7 @@ export function registerExecuteTool(server, client, session, logger) {
149
64
  }),
150
65
  },
151
66
  ],
67
+ isError: true,
152
68
  };
153
69
  }
154
70
  });
@@ -1 +1 @@
1
- {"version":3,"file":"execute.js","sourceRoot":"","sources":["../../src/tools/execute.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"execute.js","sourceRoot":"","sources":["../../src/tools/execute.ts"],"names":[],"mappings":"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"}
@@ -1 +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"}
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;AAG3C,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,MAAM,GACb,IAAI,CAsEN"}
@@ -2,142 +2,58 @@ import { OdooError, sanitizeArgs } from '@netlinksinc/odoo-client';
2
2
  import { buildContext, validateCompanySubset } from '../context.js';
3
3
  import { formatMcpError } from '../errors.js';
4
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
5
  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)
6
+ server.registerTool('odoo_fields_get', {
7
+ description: 'Introspect a model to discover its fields, types, labels, and constraints. Returns one entry per field.',
8
+ inputSchema: fieldsGetSchema.shape,
9
+ }, async (args) => {
10
+ const t0 = Date.now();
11
+ const rawArgs = args;
88
12
  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
13
+ if (args.allowed_company_ids) {
14
+ validateCompanySubset(args.allowed_company_ids, session.allowedCompanyIds);
15
+ }
16
+ const context = buildContext(session, {
17
+ allowed_company_ids: args.allowed_company_ids,
18
+ active_company_id: args.active_company_id,
19
+ });
20
+ const result = await client.fieldsGet(args.model, args.attributes, context);
92
21
  logger.toolCall({
93
22
  tool: 'odoo_fields_get',
94
- args_sanitized: sanitizeArgs('odoo_fields_get', args),
95
- latency_ms,
23
+ args_sanitized: sanitizeArgs('odoo_fields_get', rawArgs),
24
+ latency_ms: Date.now() - t0,
96
25
  status: 'ok',
97
26
  });
98
27
  return {
28
+ content: [{ type: 'text', text: JSON.stringify(result) }],
99
29
  isError: false,
100
- content: [
101
- {
102
- type: 'text',
103
- text: JSON.stringify(result),
104
- },
105
- ],
106
30
  };
107
31
  }
108
32
  catch (e) {
109
- // Step 6: on OdooError, format and return isError:true
33
+ const latency_ms = Date.now() - t0;
110
34
  if (e instanceof OdooError) {
111
- const latency_ms = Date.now() - start;
35
+ const formatted = formatMcpError(e);
112
36
  logger.toolCall({
113
37
  tool: 'odoo_fields_get',
114
- args_sanitized: sanitizeArgs('odoo_fields_get', args),
38
+ args_sanitized: sanitizeArgs('odoo_fields_get', rawArgs),
115
39
  latency_ms,
116
40
  status: 'error',
117
- error: e.message,
41
+ error: formatted.error_type,
118
42
  });
119
43
  return {
44
+ content: [{ type: 'text', text: JSON.stringify(formatted) }],
120
45
  isError: true,
121
- content: [
122
- {
123
- type: 'text',
124
- text: JSON.stringify(formatMcpError(e)),
125
- },
126
- ],
127
46
  };
128
47
  }
129
- // Step 7: Non-OdooError — unexpected exception. Log + return as InternalError-shaped.
130
48
  const message = e instanceof Error ? e.message : String(e);
131
- const latency_ms = Date.now() - start;
132
49
  logger.toolCall({
133
50
  tool: 'odoo_fields_get',
134
- args_sanitized: sanitizeArgs('odoo_fields_get', args),
51
+ args_sanitized: sanitizeArgs('odoo_fields_get', rawArgs),
135
52
  latency_ms,
136
53
  status: 'error',
137
54
  error: 'InternalError',
138
55
  });
139
56
  return {
140
- isError: true,
141
57
  content: [
142
58
  {
143
59
  type: 'text',
@@ -148,6 +64,7 @@ export function registerIntrospectTool(server, client, session, logger) {
148
64
  }),
149
65
  },
150
66
  ],
67
+ isError: true,
151
68
  };
152
69
  }
153
70
  });
@@ -1 +1 @@
1
- {"version":3,"file":"introspect.js","sourceRoot":"","sources":["../../src/tools/introspect.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"introspect.js","sourceRoot":"","sources":["../../src/tools/introspect.ts"],"names":[],"mappings":"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"}
@@ -3,14 +3,12 @@ import { type OdooSession } from '@netlinksinc/odoo-client';
3
3
  import type { OdooClient } from '@netlinksinc/odoo-client';
4
4
  import type { Logger } from '../logger.js';
5
5
  /**
6
- * Register all 6 ORM tools on the MCP server.
6
+ * Register all 6 ORM tools on the MCP server using the 3-arg registerTool
7
+ * overload that advertises the Zod input schema as JSON Schema in tools/list.
7
8
  *
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.
9
+ * Without inputSchema in the registration, MCP clients (Claude Code,
10
+ * Claude Desktop, etc.) see an empty properties bag and strip every arg
11
+ * before calling — making tools effectively unusable.
14
12
  */
15
13
  export declare function registerOrmTools(server: McpServer, client: OdooClient, session: OdooSession, logger: Logger): void;
16
14
  //# sourceMappingURL=orm.d.ts.map
@@ -1 +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"}
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;AAI3D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AA+E3C;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,MAAM,GACb,IAAI,CA6GN"}
package/dist/tools/orm.js CHANGED
@@ -2,75 +2,46 @@ import { OdooError, sanitizeArgs } from '@netlinksinc/odoo-client';
2
2
  import { buildContext, validateCompanySubset } from '../context.js';
3
3
  import { formatMcpError } from '../errors.js';
4
4
  import { createSchema, readSchema, searchCountSchema, searchReadSchema, unlinkSchema, writeSchema, } from './schemas.js';
5
- /**
6
- * Central handler for all ORM tool invocations.
7
- *
8
- * Sequence:
9
- * 1. Parse/validate args with the schema (returns isError on failure).
10
- * 2. Validate allowed_company_ids against session (returns isError on failure).
11
- * 3. Build Odoo RPC context.
12
- * 4. Execute the client method.
13
- * 5. Return serialised result or formatted OdooError.
14
- *
15
- * The callback is registered with the 2-arg overload `server.tool(name, cb)` so
16
- * that tests can drive it via a simple mock that stores and directly calls `cb`.
17
- * Inside the callback we perform our own safeParse so validation failures produce
18
- * `isError: true` (not a thrown McpError as the SDK's schema-overload would do).
19
- */
20
- async function executeHandler(tool, args, schema, exec, logger, session) {
5
+ /** Shape every tool handler funnels through after SDK-level Zod parsing. */
6
+ async function callOrm(tool, args, exec, logger, session) {
21
7
  const t0 = Date.now();
8
+ const rawArgs = args;
22
9
  try {
23
- const parsed = schema.safeParse(args);
24
- if (!parsed.success) {
25
- const text = JSON.stringify({
26
- error_type: 'InputValidationError',
27
- message: parsed.error.message,
28
- });
29
- logger.toolCall({
30
- tool,
31
- args_sanitized: sanitizeArgs(tool, args),
32
- latency_ms: Date.now() - t0,
33
- status: 'error',
34
- error: 'InputValidationError',
35
- });
36
- return { content: [{ type: 'text', text }], isError: true };
37
- }
38
- // Company-subset enforcement (US-7 AC-7).
39
- const data = parsed.data;
40
- if (data.allowed_company_ids) {
41
- validateCompanySubset(data.allowed_company_ids, session.allowedCompanyIds);
10
+ if (args.allowed_company_ids) {
11
+ validateCompanySubset(args.allowed_company_ids, session.allowedCompanyIds);
42
12
  }
43
13
  const context = buildContext(session, {
44
- allowed_company_ids: data.allowed_company_ids,
45
- active_company_id: data.active_company_id,
14
+ allowed_company_ids: args.allowed_company_ids,
15
+ active_company_id: args.active_company_id,
46
16
  });
47
- const result = await exec(parsed.data, context);
17
+ const result = await exec(args, context);
48
18
  logger.toolCall({
49
19
  tool,
50
- args_sanitized: sanitizeArgs(tool, args),
20
+ args_sanitized: sanitizeArgs(tool, rawArgs),
51
21
  latency_ms: Date.now() - t0,
52
22
  status: 'ok',
53
23
  });
54
24
  return { content: [{ type: 'text', text: JSON.stringify(result) }], isError: false };
55
25
  }
56
26
  catch (e) {
27
+ const latency_ms = Date.now() - t0;
57
28
  if (e instanceof OdooError) {
58
29
  const formatted = formatMcpError(e);
59
30
  logger.toolCall({
60
31
  tool,
61
- args_sanitized: sanitizeArgs(tool, args),
62
- latency_ms: Date.now() - t0,
32
+ args_sanitized: sanitizeArgs(tool, rawArgs),
33
+ latency_ms,
63
34
  status: 'error',
64
35
  error: formatted.error_type,
65
36
  });
66
37
  return { content: [{ type: 'text', text: JSON.stringify(formatted) }], isError: true };
67
38
  }
68
- // Non-OdooError — unexpected exception. Log + return as InternalError-shaped.
39
+ // Non-OdooError — log + return InternalError shape (don't re-throw to MCP SDK)
69
40
  const message = e instanceof Error ? e.message : String(e);
70
41
  logger.toolCall({
71
42
  tool,
72
- args_sanitized: sanitizeArgs(tool, args),
73
- latency_ms: Date.now() - t0,
43
+ args_sanitized: sanitizeArgs(tool, rawArgs),
44
+ latency_ms,
74
45
  status: 'error',
75
46
  error: 'InternalError',
76
47
  });
@@ -90,50 +61,42 @@ async function executeHandler(tool, args, schema, exec, logger, session) {
90
61
  }
91
62
  }
92
63
  /**
93
- * Register all 6 ORM tools on the MCP server.
94
- *
95
- * Tools registered: odoo_search_read, odoo_read, odoo_create, odoo_write,
96
- * odoo_unlink, odoo_search_count.
64
+ * Register all 6 ORM tools on the MCP server using the 3-arg registerTool
65
+ * overload that advertises the Zod input schema as JSON Schema in tools/list.
97
66
  *
98
- * The server.tool(name, cb) 2-arg overload is used deliberately so that
99
- * validation failures return `isError: true` rather than a thrown McpError.
100
- * Tests drive the handlers via a lightweight mock that stores the callback.
67
+ * Without inputSchema in the registration, MCP clients (Claude Code,
68
+ * Claude Desktop, etc.) see an empty properties bag and strip every arg
69
+ * before calling making tools effectively unusable.
101
70
  */
102
71
  export function registerOrmTools(server, client, session, logger) {
103
- // -------------------------------------------------------------------------
104
- // odoo_search_read
105
- // -------------------------------------------------------------------------
106
- // biome-ignore lint/suspicious/noExplicitAny: MCP SDK no-schema tool() overload signature mismatch
107
- server.tool('odoo_search_read', async (args) => executeHandler('odoo_search_read', args, searchReadSchema, (parsed, context) => client.searchRead(parsed.model, parsed.domain, parsed.fields, {
72
+ server.registerTool('odoo_search_read', {
73
+ description: 'Search and read records in one call. Returns matching rows up to `limit` (default 80).',
74
+ inputSchema: searchReadSchema.shape,
75
+ }, async (args) => callOrm('odoo_search_read', args, (parsed, context) => client.searchRead(parsed.model, parsed.domain, parsed.fields, {
108
76
  limit: parsed.limit,
109
77
  offset: parsed.offset,
110
78
  order: parsed.order,
111
79
  context,
112
80
  }), logger, session));
113
- // -------------------------------------------------------------------------
114
- // odoo_read
115
- // -------------------------------------------------------------------------
116
- // biome-ignore lint/suspicious/noExplicitAny: MCP SDK no-schema tool() overload signature mismatch
117
- server.tool('odoo_read', async (args) => executeHandler('odoo_read', args, readSchema, (parsed, context) => client.read(parsed.model, parsed.ids, parsed.fields, context), logger, session));
118
- // -------------------------------------------------------------------------
119
- // odoo_create
120
- // -------------------------------------------------------------------------
121
- // biome-ignore lint/suspicious/noExplicitAny: MCP SDK no-schema tool() overload signature mismatch
122
- server.tool('odoo_create', async (args) => executeHandler('odoo_create', args, createSchema, (parsed, context) => client.create(parsed.model, parsed.values, context), logger, session));
123
- // -------------------------------------------------------------------------
124
- // odoo_write
125
- // -------------------------------------------------------------------------
126
- // biome-ignore lint/suspicious/noExplicitAny: MCP SDK no-schema tool() overload signature mismatch
127
- server.tool('odoo_write', async (args) => executeHandler('odoo_write', args, writeSchema, (parsed, context) => client.write(parsed.model, parsed.ids, parsed.values, context), logger, session));
128
- // -------------------------------------------------------------------------
129
- // odoo_unlink
130
- // -------------------------------------------------------------------------
131
- // biome-ignore lint/suspicious/noExplicitAny: MCP SDK no-schema tool() overload signature mismatch
132
- server.tool('odoo_unlink', async (args) => executeHandler('odoo_unlink', args, unlinkSchema, (parsed, context) => client.unlink(parsed.model, parsed.ids, context), logger, session));
133
- // -------------------------------------------------------------------------
134
- // odoo_search_count
135
- // -------------------------------------------------------------------------
136
- // biome-ignore lint/suspicious/noExplicitAny: MCP SDK no-schema tool() overload signature mismatch
137
- server.tool('odoo_search_count', async (args) => executeHandler('odoo_search_count', args, searchCountSchema, (parsed, context) => client.searchCount(parsed.model, parsed.domain, context), logger, session));
81
+ server.registerTool('odoo_read', {
82
+ description: 'Read specific record IDs from a model. Returns one row per ID.',
83
+ inputSchema: readSchema.shape,
84
+ }, async (args) => callOrm('odoo_read', args, (parsed, context) => client.read(parsed.model, parsed.ids, parsed.fields, context), logger, session));
85
+ server.registerTool('odoo_create', {
86
+ description: 'Create one or many records. `values` may be a single dict or an array of dicts.',
87
+ inputSchema: createSchema.shape,
88
+ }, async (args) => callOrm('odoo_create', args, (parsed, context) => client.create(parsed.model, parsed.values, context), logger, session));
89
+ server.registerTool('odoo_write', {
90
+ description: 'Update existing records. Applies `values` to every record in `ids`.',
91
+ inputSchema: writeSchema.shape,
92
+ }, async (args) => callOrm('odoo_write', args, (parsed, context) => client.write(parsed.model, parsed.ids, parsed.values, context), logger, session));
93
+ server.registerTool('odoo_unlink', {
94
+ description: 'Delete records. Returns true on success.',
95
+ inputSchema: unlinkSchema.shape,
96
+ }, async (args) => callOrm('odoo_unlink', args, (parsed, context) => client.unlink(parsed.model, parsed.ids, context), logger, session));
97
+ server.registerTool('odoo_search_count', {
98
+ description: 'Count records matching the domain. Returns an integer.',
99
+ inputSchema: searchCountSchema.shape,
100
+ }, async (args) => callOrm('odoo_search_count', args, (parsed, context) => client.searchCount(parsed.model, parsed.domain, context), logger, session));
138
101
  }
139
102
  //# sourceMappingURL=orm.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"orm.js","sourceRoot":"","sources":["../../src/tools/orm.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"orm.js","sourceRoot":"","sources":["../../src/tools/orm.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../src/tools/report.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;AAG3C,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,MAAM,GACb,IAAI,CA0GN"}
1
+ {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../src/tools/report.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;AAG3C,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,MAAM,GACb,IAAI,CA2EN"}
@@ -3,85 +3,58 @@ import { buildContext, validateCompanySubset } from '../context.js';
3
3
  import { formatMcpError } from '../errors.js';
4
4
  import { runReportSchema } from './schemas.js';
5
5
  export function registerReportTool(server, client, session, logger) {
6
- server.tool('odoo_run_report', async (args) => {
6
+ server.registerTool('odoo_run_report', {
7
+ description: 'Render a QWeb PDF report for the given document IDs. Returns base64-encoded PDF content with its MIME type.',
8
+ inputSchema: runReportSchema.shape,
9
+ }, async (args) => {
7
10
  const t0 = Date.now();
8
11
  const toolName = 'odoo_run_report';
9
- const parsed = runReportSchema.safeParse(args);
10
- if (!parsed.success) {
11
- const errorPayload = {
12
- error_type: 'InputValidationError',
13
- message: parsed.error.message,
14
- };
15
- logger.toolCall({
16
- tool: toolName,
17
- args_sanitized: sanitizeArgs(toolName, args),
18
- latency_ms: Date.now() - t0,
19
- status: 'error',
20
- error: 'InputValidationError',
21
- });
22
- return {
23
- isError: true,
24
- content: [{ type: 'text', text: JSON.stringify(errorPayload) }],
25
- };
26
- }
27
- const data = parsed.data;
12
+ const rawArgs = args;
28
13
  try {
29
- if (data.allowed_company_ids !== undefined) {
30
- validateCompanySubset(data.allowed_company_ids, session.allowedCompanyIds);
14
+ if (args.allowed_company_ids) {
15
+ validateCompanySubset(args.allowed_company_ids, session.allowedCompanyIds);
31
16
  }
32
17
  const context = buildContext(session, {
33
- allowed_company_ids: data.allowed_company_ids,
34
- active_company_id: data.active_company_id,
18
+ allowed_company_ids: args.allowed_company_ids,
19
+ active_company_id: args.active_company_id,
35
20
  });
36
- const { content, contentType } = await client.runReport(data.report_id, data.doc_ids, context);
37
- const latency_ms = Date.now() - t0;
21
+ const { content, contentType } = await client.runReport(args.report_id, args.doc_ids, context);
38
22
  logger.toolCall({
39
23
  tool: toolName,
40
- args_sanitized: sanitizeArgs(toolName, args),
41
- latency_ms,
24
+ args_sanitized: sanitizeArgs(toolName, rawArgs),
25
+ latency_ms: Date.now() - t0,
42
26
  status: 'ok',
43
27
  });
44
28
  return {
29
+ content: [{ type: 'text', text: JSON.stringify({ content, contentType }) }],
45
30
  isError: false,
46
- content: [
47
- {
48
- type: 'text',
49
- text: JSON.stringify({ content, contentType }),
50
- },
51
- ],
52
31
  };
53
32
  }
54
33
  catch (e) {
55
34
  const latency_ms = Date.now() - t0;
56
35
  if (e instanceof OdooError) {
36
+ const formatted = formatMcpError(e);
57
37
  logger.toolCall({
58
38
  tool: toolName,
59
- args_sanitized: sanitizeArgs(toolName, args),
39
+ args_sanitized: sanitizeArgs(toolName, rawArgs),
60
40
  latency_ms,
61
41
  status: 'error',
62
- error: e.message,
42
+ error: formatted.error_type,
63
43
  });
64
44
  return {
45
+ content: [{ type: 'text', text: JSON.stringify(formatted) }],
65
46
  isError: true,
66
- content: [
67
- {
68
- type: 'text',
69
- text: JSON.stringify(formatMcpError(e)),
70
- },
71
- ],
72
47
  };
73
48
  }
74
- // Non-OdooError — unexpected exception. Log + return as InternalError-shaped.
75
49
  const message = e instanceof Error ? e.message : String(e);
76
50
  logger.toolCall({
77
51
  tool: toolName,
78
- args_sanitized: sanitizeArgs(toolName, args),
52
+ args_sanitized: sanitizeArgs(toolName, rawArgs),
79
53
  latency_ms,
80
54
  status: 'error',
81
55
  error: 'InternalError',
82
56
  });
83
57
  return {
84
- isError: true,
85
58
  content: [
86
59
  {
87
60
  type: 'text',
@@ -92,6 +65,7 @@ export function registerReportTool(server, client, session, logger) {
92
65
  }),
93
66
  },
94
67
  ],
68
+ isError: true,
95
69
  };
96
70
  }
97
71
  });
@@ -1 +1 @@
1
- {"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/tools/report.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/tools/report.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netlinksinc/odoo-mcp",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "MCP server exposing any Odoo 19 instance to Claude (Desktop, Code, Cowork) — generic-only tool surface, works on stock and customized Odoo",
5
5
  "keywords": [
6
6
  "mcp",
@@ -43,7 +43,7 @@
43
43
  "dependencies": {
44
44
  "@modelcontextprotocol/sdk": "^1",
45
45
  "zod": "^3",
46
- "@netlinksinc/odoo-client": "0.1.0"
46
+ "@netlinksinc/odoo-client": "0.1.1"
47
47
  },
48
48
  "devDependencies": {
49
49
  "typescript": "^5.7",