mcp-grocy 2.2.0 → 2.5.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 (40) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +112 -32
  3. package/build/api/client.js +11 -13
  4. package/build/config/index.js +74 -20
  5. package/build/resources/CHANGELOG.md +31 -0
  6. package/build/resources/DOCS.md +8 -3
  7. package/build/resources/README.md +112 -32
  8. package/build/resources/api-reference.md +88 -88
  9. package/build/resources/config.md +30 -17
  10. package/build/resources/examples.md +120 -221
  11. package/build/resources/installation.md +9 -14
  12. package/build/resources/response-format.md +18 -13
  13. package/build/server/http-server.js +154 -42
  14. package/build/server/mcp-server.js +143 -96
  15. package/build/server/resources.js +37 -24
  16. package/build/server/tool-input-zod.js +86 -0
  17. package/build/tools/base.js +19 -15
  18. package/build/tools/household/definitions.js +47 -43
  19. package/build/tools/household/handlers.js +2 -2
  20. package/build/tools/household/index.js +2 -2
  21. package/build/tools/inventory/definitions.js +150 -113
  22. package/build/tools/inventory/handlers.js +55 -42
  23. package/build/tools/inventory/index.js +2 -2
  24. package/build/tools/module-loader.js +15 -12
  25. package/build/tools/recipes/definitions.js +103 -86
  26. package/build/tools/recipes/handlers.js +44 -38
  27. package/build/tools/recipes/index.js +3 -3
  28. package/build/tools/recipes/validations.js +8 -2
  29. package/build/tools/shopping/definitions.js +22 -20
  30. package/build/tools/shopping/handlers.js +1 -1
  31. package/build/tools/shopping/index.js +2 -2
  32. package/build/tools/system/definitions.js +25 -22
  33. package/build/tools/system/handlers.js +74 -12
  34. package/build/tools/system/index.js +2 -2
  35. package/build/tools/validation-helpers.js +10 -7
  36. package/build/types/index.js +12 -10
  37. package/build/utils/errors.js +10 -5
  38. package/build/utils/logger.js +16 -15
  39. package/build/version.js +2 -2
  40. package/package.json +38 -23
@@ -3,6 +3,7 @@ export const inventoryToolDefinitions = [
3
3
  {
4
4
  name: 'inventory_products_get',
5
5
  description: '[INVENTORY/PRODUCTS] Get specific fields for all products from your Grocy instance. You must specify which fields to retrieve.',
6
+ annotations: { readOnlyHint: true },
6
7
  inputSchema: {
7
8
  type: 'object',
8
9
  properties: {
@@ -10,184 +11,219 @@ export const inventoryToolDefinitions = [
10
11
  type: 'array',
11
12
  items: {
12
13
  type: 'string',
13
- enum: ['id', 'name', 'description', 'product_group_id', 'active', 'location_id', 'shopping_location_id', 'qu_id_purchase', 'qu_id_stock', 'qu_factor_purchase_to_stock', 'min_stock_amount', 'default_best_before_days', 'default_best_before_days_after_open', 'default_best_before_days_after_freezing', 'default_best_before_days_after_thawing', 'picture_file_name', 'allow_label_per_unit', 'energy_per_stock_unit', 'calories_per_stock_unit', 'default_stock_label_type', 'should_not_be_frozen', 'treat_opened_as_out_of_stock', 'no_own_stock', 'cumulate_min_stock_amount_of_sub_products', 'parent_product_id', 'calories_per_unit_factor', 'quick_consume_amount', 'hide_on_stock_overview']
14
+ enum: [
15
+ 'id',
16
+ 'name',
17
+ 'description',
18
+ 'product_group_id',
19
+ 'active',
20
+ 'location_id',
21
+ 'shopping_location_id',
22
+ 'qu_id_purchase',
23
+ 'qu_id_stock',
24
+ 'qu_factor_purchase_to_stock',
25
+ 'min_stock_amount',
26
+ 'default_best_before_days',
27
+ 'default_best_before_days_after_open',
28
+ 'default_best_before_days_after_freezing',
29
+ 'default_best_before_days_after_thawing',
30
+ 'picture_file_name',
31
+ 'allow_label_per_unit',
32
+ 'energy_per_stock_unit',
33
+ 'calories_per_stock_unit',
34
+ 'default_stock_label_type',
35
+ 'should_not_be_frozen',
36
+ 'treat_opened_as_out_of_stock',
37
+ 'no_own_stock',
38
+ 'cumulate_min_stock_amount_of_sub_products',
39
+ 'parent_product_id',
40
+ 'calories_per_unit_factor',
41
+ 'quick_consume_amount',
42
+ 'hide_on_stock_overview',
43
+ ],
14
44
  },
15
- description: 'Array of field names to retrieve. For basic lookup use ["id", "name"]. For detailed info include ["id", "name", "description", "active"]. Available fields: id, name, description, product_group_id, active, location_id, shopping_location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock, min_stock_amount, default_best_before_days, default_best_before_days_after_open, default_best_before_days_after_freezing, default_best_before_days_after_thawing, picture_file_name, allow_label_per_unit, energy_per_stock_unit, calories_per_stock_unit, default_stock_label_type, should_not_be_frozen, treat_opened_as_out_of_stock, no_own_stock, cumulate_min_stock_amount_of_sub_products, parent_product_id, calories_per_unit_factor, quick_consume_amount, hide_on_stock_overview'
16
- }
45
+ description: 'Array of field names to retrieve. For basic lookup use ["id", "name"]. For detailed info include ["id", "name", "description", "active"]. Available fields: id, name, description, product_group_id, active, location_id, shopping_location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock, min_stock_amount, default_best_before_days, default_best_before_days_after_open, default_best_before_days_after_freezing, default_best_before_days_after_thawing, picture_file_name, allow_label_per_unit, energy_per_stock_unit, calories_per_stock_unit, default_stock_label_type, should_not_be_frozen, treat_opened_as_out_of_stock, no_own_stock, cumulate_min_stock_amount_of_sub_products, parent_product_id, calories_per_unit_factor, quick_consume_amount, hide_on_stock_overview',
46
+ },
17
47
  },
18
- required: ['fields']
19
- }
48
+ required: ['fields'],
49
+ },
20
50
  },
21
51
  {
22
52
  name: 'inventory_products_get_groups',
23
- description: '[INVENTORY/PRODUCTS] Get all product groups from your Grocy instance.',
53
+ description: '[INVENTORY/PRODUCTS] **Categories only:** list product groups (taxonomy), not individual products. For product rows with fields use inventory_products_get.',
54
+ annotations: { readOnlyHint: true },
24
55
  inputSchema: {
25
56
  type: 'object',
26
57
  properties: {},
27
- required: []
28
- }
58
+ required: [],
59
+ },
29
60
  },
30
61
  {
31
62
  name: 'inventory_products_get_price_history',
32
63
  description: '[INVENTORY/PRODUCTS] Get the price history of a product from your Grocy instance.',
64
+ annotations: { readOnlyHint: true },
33
65
  inputSchema: {
34
66
  type: 'object',
35
67
  properties: {
36
68
  productId: {
37
69
  type: 'number',
38
- description: 'ID of the product to get price history for. Use get_products tool to find the correct product ID by name.'
39
- }
70
+ description: 'ID of the product to get price history for. Use inventory_products_lookup to find the product ID by name (or inventory_products_get with fields if listing products).',
71
+ },
40
72
  },
41
- required: ['productId']
42
- }
73
+ required: ['productId'],
74
+ },
43
75
  },
44
76
  // Stock Management Tools
45
77
  {
46
78
  name: 'inventory_stock_get_all',
47
- description: '[INVENTORY/STOCK] Get all stock entries from every location in your Grocy instance. This returns the complete stock database with detailed information including stock entry IDs.',
79
+ description: '[INVENTORY/STOCK] **Full stock dump**—every stock entry in the home with stockIds. Prefer inventory_stock_get_by_product when the user names one product; prefer inventory_stock_get_by_location when they name one storage place.',
80
+ annotations: { readOnlyHint: true },
48
81
  inputSchema: {
49
82
  type: 'object',
50
83
  properties: {},
51
- required: []
52
- }
84
+ required: [],
85
+ },
53
86
  },
54
87
  {
55
88
  name: 'inventory_stock_get_by_product',
56
- description: '[INVENTORY/STOCK] Get stock entries for a specific product in your Grocy instance with filtered essential information.',
89
+ description: '[INVENTORY/STOCK] Stock rows for **one product** across locations (needs productId). Use when the user asks how much of a product is on hand or needs stockId for that product—not for everything in a cupboard (use inventory_stock_get_by_location).',
90
+ annotations: { readOnlyHint: true },
57
91
  inputSchema: {
58
92
  type: 'object',
59
93
  properties: {
60
94
  productId: {
61
95
  type: 'number',
62
- description: 'ID of the product to get stock entries for. Use get_products tool to find the correct product ID by name.'
63
- }
96
+ description: 'ID of the product to get stock entries for. Use inventory_products_lookup to find the product ID by name (or inventory_products_get with fields if listing products).',
97
+ },
64
98
  },
65
- required: ['productId']
66
- }
99
+ required: ['productId'],
100
+ },
67
101
  },
68
102
  {
69
103
  name: 'inventory_stock_get_volatile',
70
104
  description: '[INVENTORY/STOCK] Get volatile stock information (due products, overdue products, expired products, missing products).',
105
+ annotations: { readOnlyHint: true },
71
106
  inputSchema: {
72
107
  type: 'object',
73
108
  properties: {
74
109
  includeDetails: {
75
110
  type: 'boolean',
76
- description: 'Whether to include additional details about each stock item'
77
- }
111
+ description: 'Whether to include additional details about each stock item',
112
+ },
78
113
  },
79
- required: []
80
- }
114
+ required: [],
115
+ },
81
116
  },
82
117
  {
83
118
  name: 'inventory_stock_get_by_location',
84
- description: '[INVENTORY/STOCK] Get stock entries from a specific location in your Grocy instance.',
119
+ description: '[INVENTORY/STOCK] Everything stocked in **one storage location** (needs locationId from system_locations_get). Use when the user asks what is in the freezer/pantry—not for one named product across sites (use inventory_stock_get_by_product).',
120
+ annotations: { readOnlyHint: true },
85
121
  inputSchema: {
86
122
  type: 'object',
87
123
  properties: {
88
124
  locationId: {
89
125
  type: 'number',
90
- description: 'ID of the location to get stock for.'
91
- }
126
+ description: 'ID of the location to get stock for.',
127
+ },
92
128
  },
93
- required: ['locationId']
94
- }
129
+ required: ['locationId'],
130
+ },
95
131
  },
96
132
  // Stock Transaction Tools
97
133
  {
98
134
  name: 'inventory_transactions_purchase',
99
- description: '[INVENTORY/TRANSACTIONS] Add a product to stock (purchase/add inventory). Use inventory_products_get to find the product ID and system_locations_get to find location IDs.',
135
+ description: '[INVENTORY/TRANSACTIONS] **Product-level purchase:** add quantity by productId (creates/merges stock). No stockId. Use inventory_products_get and system_locations_get for IDs.',
100
136
  inputSchema: {
101
137
  type: 'object',
102
138
  properties: {
103
139
  productId: {
104
140
  type: 'number',
105
- description: 'ID of the product to purchase. Use get_products tool to find the correct product ID by name.'
141
+ description: 'ID of the product to purchase. Use inventory_products_lookup to find the product ID by name (or inventory_products_get with fields if listing products).',
106
142
  },
107
143
  amount: {
108
144
  type: 'number',
109
- description: 'Amount to purchase in the product\'s stock unit (e.g., 2 pieces, 1.5 kg, 750 ml). Ensure you know the product\'s unit before specifying amount.'
145
+ description: "Amount to purchase in the product's stock unit (e.g., 2 pieces, 1.5 kg, 750 ml). Ensure you know the product's unit before specifying amount.",
110
146
  },
111
147
  bestBeforeDate: {
112
148
  type: 'string',
113
- description: 'Best before date in YYYY-MM-DD format. If not provided, will use product\'s default best before days.'
149
+ description: "Best before date in YYYY-MM-DD format. If not provided, will use product's default best before days.",
114
150
  },
115
151
  price: {
116
152
  type: 'number',
117
- description: 'Price per stock unit (optional)'
153
+ description: 'Price per stock unit (optional)',
118
154
  },
119
155
  locationId: {
120
156
  type: 'number',
121
- description: 'Location ID where the product should be stored. Use get_locations tool to find the correct location ID. If not provided, uses product\'s default location.'
157
+ description: "Location ID where the product should be stored. Use system_locations_get to find the location ID. If not provided, uses product's default location.",
122
158
  },
123
159
  note: {
124
160
  type: 'string',
125
- description: 'Optional note for the stock entry'
126
- }
161
+ description: 'Optional note for the stock entry',
162
+ },
127
163
  },
128
- required: ['productId', 'amount']
129
- }
164
+ required: ['productId', 'amount'],
165
+ },
130
166
  },
131
167
  {
132
168
  name: 'inventory_transactions_consume',
133
- description: '[INVENTORY/TRANSACTIONS] Remove a product from stock (consume/use inventory). For more granular control over specific stock entries, prefer inventory_stock_entry_consume. Use inventory_products_get to find the product ID.',
169
+ description: '[INVENTORY/TRANSACTIONS] **Product-level consume:** reduce stock by productId+amount (Grocy picks lots). If the user refers to a specific package/stock row, use inventory_stock_entry_consume (stockId). Use inventory_products_get for productId.',
134
170
  inputSchema: {
135
171
  type: 'object',
136
172
  properties: {
137
173
  productId: {
138
174
  type: 'number',
139
- description: 'ID of the product to consume. Use get_products tool to find the correct product ID by name.'
175
+ description: 'ID of the product to consume. Use inventory_products_lookup to find the product ID by name (or inventory_products_get with fields if listing products).',
140
176
  },
141
177
  amount: {
142
178
  type: 'number',
143
- description: 'Amount to consume in the product\'s stock unit (e.g., 2 pieces, 1.5 kg, 750 ml). Ensure you know the product\'s unit before specifying amount.'
179
+ description: "Amount to consume in the product's stock unit (e.g., 2 pieces, 1.5 kg, 750 ml). Ensure you know the product's unit before specifying amount.",
144
180
  },
145
181
  spoiled: {
146
182
  type: 'boolean',
147
183
  description: 'Whether the product was spoiled/wasted (default: false)',
148
- default: false
184
+ default: false,
149
185
  },
150
186
  locationId: {
151
187
  type: 'number',
152
- description: 'Location ID to consume from (optional). Use get_locations tool to find the correct location ID.'
188
+ description: 'Location ID to consume from (optional). Use system_locations_get to find the location ID.',
153
189
  },
154
190
  note: {
155
191
  type: 'string',
156
- description: 'Optional note for the consumption'
157
- }
192
+ description: 'Optional note for the consumption',
193
+ },
158
194
  },
159
- required: ['productId', 'amount']
160
- }
195
+ required: ['productId', 'amount'],
196
+ },
161
197
  },
162
198
  {
163
199
  name: 'inventory_transactions_transfer',
164
- description: '[INVENTORY/TRANSACTIONS] Transfer a product between locations. For more granular control over specific stock entries, prefer inventory_stock_entry_transfer. Use inventory_products_get to find the product ID and system_locations_get to find location IDs.',
200
+ description: '[INVENTORY/TRANSACTIONS] **Product-level transfer:** move amount of a product between locations without choosing a stock row. For one specific lot, use inventory_stock_entry_transfer (stockId). Use inventory_products_get and system_locations_get.',
165
201
  inputSchema: {
166
202
  type: 'object',
167
203
  properties: {
168
204
  productId: {
169
205
  type: 'number',
170
- description: 'ID of the product to transfer. Use get_products tool to find the correct product ID by name.'
206
+ description: 'ID of the product to transfer. Use inventory_products_lookup to find the product ID by name (or inventory_products_get with fields if listing products).',
171
207
  },
172
208
  amount: {
173
209
  type: 'number',
174
- description: 'Amount to transfer in the product\'s stock unit (e.g., 2 pieces, 1.5 kg, 750 ml). Ensure you know the product\'s unit before specifying amount.'
210
+ description: "Amount to transfer in the product's stock unit (e.g., 2 pieces, 1.5 kg, 750 ml). Ensure you know the product's unit before specifying amount.",
175
211
  },
176
212
  fromLocationId: {
177
213
  type: 'number',
178
- description: 'Source location ID. Use get_locations tool to find the correct location ID.'
214
+ description: 'Source location ID. Use system_locations_get to find the location ID.',
179
215
  },
180
216
  toLocationId: {
181
217
  type: 'number',
182
- description: 'Destination location ID. Use get_locations tool to find the correct location ID.'
218
+ description: 'Destination location ID. Use system_locations_get to find the location ID.',
183
219
  },
184
220
  note: {
185
221
  type: 'string',
186
- description: 'Optional note for the transfer'
187
- }
222
+ description: 'Optional note for the transfer',
223
+ },
188
224
  },
189
- required: ['productId', 'amount', 'fromLocationId', 'toLocationId']
190
- }
225
+ required: ['productId', 'amount', 'fromLocationId', 'toLocationId'],
226
+ },
191
227
  },
192
228
  {
193
229
  name: 'inventory_transactions_adjust',
@@ -197,64 +233,65 @@ export const inventoryToolDefinitions = [
197
233
  properties: {
198
234
  productId: {
199
235
  type: 'number',
200
- description: 'ID of the product to inventory. Use get_products tool to find the correct product ID by name.'
236
+ description: 'ID of the product to inventory. Use inventory_products_lookup to find the product ID by name (or inventory_products_get with fields if listing products).',
201
237
  },
202
238
  newAmount: {
203
239
  type: 'number',
204
- description: 'The new/correct total amount of stock for this product in the product\'s stock unit.'
240
+ description: "The new/correct total amount of stock for this product in the product's stock unit.",
205
241
  },
206
242
  bestBeforeDate: {
207
243
  type: 'string',
208
- description: 'Best before date in YYYY-MM-DD format for the inventory correction.'
244
+ description: 'Best before date in YYYY-MM-DD format for the inventory correction.',
209
245
  },
210
246
  locationId: {
211
247
  type: 'number',
212
- description: 'Location ID for the inventory (optional). Use get_locations tool to find the correct location ID.'
248
+ description: 'Location ID for the inventory (optional). Use system_locations_get to find the location ID.',
213
249
  },
214
250
  note: {
215
251
  type: 'string',
216
- description: 'Optional note for the inventory correction'
217
- }
252
+ description: 'Optional note for the inventory correction',
253
+ },
218
254
  },
219
- required: ['productId', 'newAmount']
220
- }
255
+ required: ['productId', 'newAmount'],
256
+ },
221
257
  },
222
258
  {
223
259
  name: 'inventory_transactions_open',
224
- description: '[INVENTORY/TRANSACTIONS] Mark a product as opened/started. For more granular control over specific stock entries, prefer inventory_stock_entry_open. Use inventory_products_get to find the product ID.',
260
+ description: '[INVENTORY/TRANSACTIONS] **Product-level open:** mark opened/started without a stock row. For one specific package use inventory_stock_entry_open (stockId). Use inventory_products_get for productId.',
225
261
  inputSchema: {
226
262
  type: 'object',
227
263
  properties: {
228
264
  productId: {
229
265
  type: 'number',
230
- description: 'ID of the product to open. Use get_products tool to find the correct product ID by name.'
266
+ description: 'ID of the product to open. Use inventory_products_lookup to find the product ID by name (or inventory_products_get with fields if listing products).',
231
267
  },
232
268
  amount: {
233
269
  type: 'number',
234
- description: 'Amount to mark as opened in the product\'s stock unit (e.g., 1 piece, 0.5 kg). Default: 1',
235
- default: 1
270
+ description: "Amount to mark as opened in the product's stock unit (e.g., 1 piece, 0.5 kg). Default: 1",
271
+ default: 1,
236
272
  },
237
273
  note: {
238
274
  type: 'string',
239
- description: 'Optional note for opening the product'
240
- }
275
+ description: 'Optional note for opening the product',
276
+ },
241
277
  },
242
- required: ['productId']
243
- }
278
+ required: ['productId'],
279
+ },
244
280
  },
245
281
  {
246
282
  name: 'inventory_products_lookup',
247
283
  description: '[INVENTORY/PRODUCTS] Search for products by name using fuzzy matching. Returns up to 5 best matches with stock information and location details.',
284
+ annotations: { readOnlyHint: true },
248
285
  inputSchema: {
249
286
  type: 'object',
250
287
  properties: {
251
288
  productName: {
252
289
  type: 'string',
253
- description: 'Product name to search for. Uses fuzzy matching to find similar products.'
254
- }
290
+ description: 'Product name to search for. Uses fuzzy matching to find similar products.',
291
+ },
255
292
  },
256
- required: ['productName']
257
- }
293
+ required: ['productName'],
294
+ },
258
295
  },
259
296
  {
260
297
  name: 'inventory_products_print_label',
@@ -264,11 +301,11 @@ export const inventoryToolDefinitions = [
264
301
  properties: {
265
302
  productId: {
266
303
  type: 'number',
267
- description: 'ID of the product to print label for. Use inventory_products_get tool to find the correct product ID.'
268
- }
304
+ description: 'ID of the product to print label for. Use inventory_products_get tool to find the correct product ID.',
305
+ },
269
306
  },
270
- required: ['productId']
271
- }
307
+ required: ['productId'],
308
+ },
272
309
  },
273
310
  {
274
311
  name: 'inventory_stock_entry_print_label',
@@ -278,102 +315,102 @@ export const inventoryToolDefinitions = [
278
315
  properties: {
279
316
  stockId: {
280
317
  type: 'number',
281
- description: 'ID of the stock entry to print label for. Use get_stock_by_product tool to find specific stockId values.'
318
+ description: 'ID of the stock entry to print label for. Use inventory_stock_get_by_product to find stockId values.',
282
319
  },
283
320
  productId: {
284
321
  type: 'number',
285
- description: 'ID of the product that the stock entry belongs to. This is required for validation.'
286
- }
322
+ description: 'ID of the product that the stock entry belongs to. This is required for validation.',
323
+ },
287
324
  },
288
- required: ['stockId', 'productId']
289
- }
325
+ required: ['stockId', 'productId'],
326
+ },
290
327
  },
291
328
  // ==================== GRANULAR STOCK ENTRY OPERATIONS ====================
292
329
  {
293
330
  name: 'inventory_stock_entry_consume',
294
- description: '[INVENTORY/STOCK] Consume from a specific stock entry. Use inventory_stock_get_by_product to find specific stockId values.',
331
+ description: '[INVENTORY/STOCK] **Specific stock row (stockId):** consume from one lot. If the user only names a product/amount without a particular package, use inventory_transactions_consume instead. Find stockId via inventory_stock_get_by_product.',
295
332
  inputSchema: {
296
333
  type: 'object',
297
334
  properties: {
298
335
  stockId: {
299
336
  type: 'number',
300
- description: 'ID of the specific stock entry to consume from.'
337
+ description: 'ID of the specific stock entry to consume from.',
301
338
  },
302
339
  productId: {
303
340
  type: 'number',
304
- description: 'ID of the product being consumed. This is required for verification - if you know the stockId, you must know the productId.'
341
+ description: 'ID of the product being consumed. This is required for verification - if you know the stockId, you must know the productId.',
305
342
  },
306
343
  amount: {
307
344
  type: 'number',
308
- description: 'Amount to consume in the product\'s stock unit (e.g., 1 piece, 0.5 kg, 250 ml). Ensure you know the product\'s stock unit before specifying amount.'
345
+ description: "Amount to consume in the product's stock unit (e.g., 1 piece, 0.5 kg, 250 ml). Ensure you know the product's stock unit before specifying amount.",
309
346
  },
310
347
  spoiled: {
311
348
  type: 'boolean',
312
349
  description: 'Whether the product is spoiled (default: false)',
313
- default: false
350
+ default: false,
314
351
  },
315
352
  note: {
316
353
  type: 'string',
317
- description: 'Optional note'
318
- }
354
+ description: 'Optional note',
355
+ },
319
356
  },
320
- required: ['stockId', 'productId', 'amount']
321
- }
357
+ required: ['stockId', 'productId', 'amount'],
358
+ },
322
359
  },
323
360
  {
324
361
  name: 'inventory_stock_entry_transfer',
325
- description: '[INVENTORY/STOCK] Transfer a specific stock entry to another location. Use inventory_stock_get_by_product to find specific stockId values.',
362
+ description: '[INVENTORY/STOCK] **Specific stock row (stockId):** move one lot to another location. For moving an amount of a product without picking a row, use inventory_transactions_transfer. Find stockId via inventory_stock_get_by_product.',
326
363
  inputSchema: {
327
364
  type: 'object',
328
365
  properties: {
329
366
  stockId: {
330
367
  type: 'number',
331
- description: 'ID of the specific stock entry to transfer.'
368
+ description: 'ID of the specific stock entry to transfer.',
332
369
  },
333
370
  productId: {
334
371
  type: 'number',
335
- description: 'ID of the product being transferred. This is required for verification - if you know the stockId, you must know the productId.'
372
+ description: 'ID of the product being transferred. This is required for verification - if you know the stockId, you must know the productId.',
336
373
  },
337
374
  amount: {
338
375
  type: 'number',
339
- description: 'Amount to transfer in the product\'s stock unit (e.g., 1 piece, 0.5 kg, 250 ml). Ensure you know the product\'s stock unit before specifying amount.'
376
+ description: "Amount to transfer in the product's stock unit (e.g., 1 piece, 0.5 kg, 250 ml). Ensure you know the product's stock unit before specifying amount.",
340
377
  },
341
378
  locationIdTo: {
342
379
  type: 'number',
343
- description: 'ID of the destination location.'
380
+ description: 'ID of the destination location.',
344
381
  },
345
382
  note: {
346
383
  type: 'string',
347
- description: 'Optional note for this transfer'
348
- }
384
+ description: 'Optional note for this transfer',
385
+ },
349
386
  },
350
- required: ['stockId', 'productId', 'amount', 'locationIdTo']
351
- }
387
+ required: ['stockId', 'productId', 'amount', 'locationIdTo'],
388
+ },
352
389
  },
353
390
  {
354
391
  name: 'inventory_stock_entry_open',
355
- description: '[INVENTORY/STOCK] Mark a specific stock entry as opened. Use inventory_stock_get_by_product to find specific stockId values.',
392
+ description: '[INVENTORY/STOCK] **Specific stock row (stockId):** mark one opened package. For product-level open without a row, use inventory_transactions_open. Find stockId via inventory_stock_get_by_product.',
356
393
  inputSchema: {
357
394
  type: 'object',
358
395
  properties: {
359
396
  stockId: {
360
397
  type: 'number',
361
- description: 'ID of the specific stock entry to mark as opened.'
398
+ description: 'ID of the specific stock entry to mark as opened.',
362
399
  },
363
400
  productId: {
364
401
  type: 'number',
365
- description: 'ID of the product being opened. This is required for verification - if you know the stockId, you must know the productId.'
402
+ description: 'ID of the product being opened. This is required for verification - if you know the stockId, you must know the productId.',
366
403
  },
367
404
  amount: {
368
405
  type: 'number',
369
- description: 'Amount to mark as opened in the product\'s stock unit (e.g., 1 piece, 0.5 kg, 200 ml). Ensure you know the product\'s stock unit before specifying amount.'
406
+ description: "Amount to mark as opened in the product's stock unit (e.g., 1 piece, 0.5 kg, 200 ml). Ensure you know the product's stock unit before specifying amount.",
370
407
  },
371
408
  note: {
372
409
  type: 'string',
373
- description: 'Optional note'
374
- }
410
+ description: 'Optional note',
411
+ },
375
412
  },
376
- required: ['stockId', 'productId', 'amount']
377
- }
378
- }
413
+ required: ['stockId', 'productId', 'amount'],
414
+ },
415
+ },
379
416
  ];