L2.2 : rejette les paramètres inconnus et les requis manquants (D23)
Mesure V1 (24/08/2026) : le SDK MCP ignore additionalProperties: false —
read_recent_logs({lines: 5}) avec la clause sur le schéma répondait
success: true, returnedLines: 100 (retombée silencieuse sur le défaut).
La validation vit donc dans le wrapper tools/call de src/index.js,
pilotée par les schémas de la table de routage (D22) : paramètre inconnu
ou requis manquant -> erreur structurée nommant le fautif et les
paramètres valides, avant tout dispatch.
Les 23 schémas portent additionalProperties: false — inerte côté SDK,
mais c'est le contrat que lisent les clients. Pas de renommage de
paramètres (écarté, cf. ROADMAP).
Mesures (via le protocole) :
- read_recent_logs({"lines": 5}) -> "Paramètre(s) inconnu(s) pour
read_recent_logs : lines. Paramètres valides : count, log_file."
- read_recent_logs({"count": 5}) -> succès, returnedLines: 5
- boucle sur 22 outils avec {} (execute_command vérifié statiquement) :
22/22 répondent, aucun Unknown tool, les 11 outils à paramètres requis
échouent avec le message actionnable
- handshake : 23 outils, 6 resources
Docs : D23 dans DECISIONS.md, L2.2 retirée de la ROADMAP.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -94,6 +94,36 @@ for (const { moduleName, module } of TOOL_MODULES) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Valide les arguments d'un appel d'outil contre son inputSchema (D23).
|
||||
* Le SDK MCP ne valide pas les schémas d'entrée — mesuré le 24/08/2026 :
|
||||
* `additionalProperties: false` est ignoré et un paramètre inconnu retombe
|
||||
* silencieusement sur les défauts. La validation vit donc ici, pilotée par la
|
||||
* même table que tools/list : schéma déclaré = contrat appliqué.
|
||||
*/
|
||||
function validateToolArgs(definition, args) {
|
||||
const schema = definition.inputSchema || {};
|
||||
const properties = schema.properties || {};
|
||||
const validNames = Object.keys(properties);
|
||||
const validList = validNames.length > 0 ? validNames.join(', ') : '(aucun)';
|
||||
|
||||
const unknown = Object.keys(args || {}).filter(key => !(key in properties));
|
||||
if (unknown.length > 0) {
|
||||
throw new Error(
|
||||
`Paramètre(s) inconnu(s) pour ${definition.name} : ${unknown.join(', ')}. ` +
|
||||
`Paramètres valides : ${validList}.`
|
||||
);
|
||||
}
|
||||
|
||||
const missing = (schema.required || []).filter(key => args?.[key] === undefined);
|
||||
if (missing.length > 0) {
|
||||
throw new Error(
|
||||
`Paramètre(s) requis manquant(s) pour ${definition.name} : ${missing.join(', ')}. ` +
|
||||
`Paramètres valides : ${validList}.`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Create MCP Server
|
||||
const server = new Server(
|
||||
{
|
||||
@@ -193,6 +223,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
||||
`Unknown tool: ${name}. Available tools: ${Array.from(toolRegistry.keys()).join(', ')}`
|
||||
);
|
||||
}
|
||||
validateToolArgs(entry.definition, args);
|
||||
return await entry.module.executeTool(name, args);
|
||||
} catch (error) {
|
||||
console.error(`[Server] Error executing tool ${name}:`, error.message);
|
||||
|
||||
Reference in New Issue
Block a user