diff --git a/src/tools/config-tools.js b/src/tools/config-tools.js index 6187ea5..5a2955b 100644 --- a/src/tools/config-tools.js +++ b/src/tools/config-tools.js @@ -49,6 +49,16 @@ Examples: description: 'If true, return only parameters that have at least one warehouse override (default: false).', default: false, }, + limit: { + type: 'number', + description: 'Maximum number of parameters returned per call (default: 50). The full unfiltered list is ~70,000 characters — raise this only if you really need everything at once.', + default: 50, + }, + offset: { + type: 'number', + description: 'Number of matching parameters to skip, for pagination (default: 0). Combine with limit to walk the full list.', + default: 0, + }, }, }, }, @@ -64,9 +74,18 @@ async function executeTool(name, args) { } } +const DEFAULT_PARAMS_LIMIT = 50; + async function getSystemParameters(args) { const { warehouse, param_class, search, only_overridden = false } = args || {}; + // Bornes de pagination — valeurs invalides ramenées aux défauts, la + // validation du wrapper (D23) ne contrôle que les noms de paramètres. + const rawLimit = Number(args && args.limit); + const limit = Number.isFinite(rawLimit) && rawLimit >= 1 ? Math.floor(rawLimit) : DEFAULT_PARAMS_LIMIT; + const rawOffset = Number(args && args.offset); + const offset = Number.isFinite(rawOffset) && rawOffset >= 0 ? Math.floor(rawOffset) : 0; + try { // Both entities are small (a few hundred rows max) — fetch fully and merge // client-side to avoid LINQ string-injection and null-field pitfalls. @@ -124,18 +143,33 @@ async function getSystemParameters(args) { rows.sort((a, b) => String(a.code).localeCompare(String(b.code))); + // Pagination (L3.1) : sans elle la sortie sans filtre atteint ~70 000 + // caractères et se fait rejeter par les clients MCP. totalParameters est + // le total correspondant aux filtres, AVANT pagination — le signal + // truncated se vérifie donc depuis la réponse : offset + returned < total. + const matched = rows.length; + const page = rows.slice(offset, offset + limit); + const truncated = offset + page.length < matched; + + const payload = { + success: true, + warehouse: warehouse || '(none — effective value = default)', + filters: { param_class: param_class || null, search: search || null, only_overridden }, + totalParameters: matched, + totalOverrides: Array.isArray(paramValues) ? paramValues.length : 0, + returned: page.length, + offset, + }; + if (truncated) { + payload.truncated = true; + payload.hint = `Showing parameters ${offset + 1}-${offset + page.length} of ${matched}. Call again with offset=${offset + page.length} for the next page, or narrow the result with param_class / search.`; + } + payload.parameters = page; + return { content: [{ type: 'text', - text: JSON.stringify({ - success: true, - warehouse: warehouse || '(none — effective value = default)', - filters: { param_class: param_class || null, search: search || null, only_overridden }, - totalParameters: Array.isArray(parameters) ? parameters.length : 0, - totalOverrides: Array.isArray(paramValues) ? paramValues.length : 0, - returned: rows.length, - parameters: rows, - }, null, 2), + text: JSON.stringify(payload, null, 2), }], }; } catch (err) {