feat(sdk): metadata statiques contributes.mcpServers[].tools — #296 (type IdeAPluginMcpToolMetadata {name exact non vide, description optionnelle non vide} exporté public; validation manifest: tools optionnel, noms uniques par serveur — metadata d'affichage pour l'UI d'attribution de capacités, ne remplace ni ne cache MCP tools/list et n'enregistre rien; scripts/check-manifest-tools.mjs + npm run test:manifest intégré à check: optionnel/valide/doublon rejeté; doc manifest.md: exemple unity_get_scene/run_tests + règles; QA verte reconfirmée par Git: npm run check)

This commit is contained in:
2026-09-09 19:52:23 +02:00
parent fdb3a907af
commit d93e302320
5 changed files with 81 additions and 2 deletions

View File

@ -5,6 +5,7 @@ export type {
IdeAPluginEngineConstraints,
IdeAPluginLayoutContribution,
IdeAPluginMcpServerContribution,
IdeAPluginMcpToolMetadata,
IdeAPluginMenuItemContribution,
IdeAPluginSkillContribution,
IdeAPluginSkillKind,

View File

@ -95,6 +95,15 @@ export interface IdeAPluginMcpServerContribution {
transport: "stdio";
autoStart?: boolean;
allowAbsoluteCommand?: boolean;
/** Optional static UI metadata; runtime MCP tools/list remains authoritative. */
tools?: IdeAPluginMcpToolMetadata[];
}
export interface IdeAPluginMcpToolMetadata {
/** Exact tool name advertised by the MCP server. */
name: string;
/** Optional human-readable summary for capability-management UI. */
description?: string;
}
export type PluginManifestValidationResult =
@ -269,6 +278,22 @@ function validateContributes(value: unknown, errors: string[]): void {
optionalString(server, "cwd", errors, `contributes.mcpServers[${index}].cwd`);
optionalBoolean(server, "autoStart", errors, `contributes.mcpServers[${index}].autoStart`);
optionalBoolean(server, "allowAbsoluteCommand", errors, `contributes.mcpServers[${index}].allowAbsoluteCommand`);
validateArray(server, "tools", errors, (tool, toolIndex) => {
requireString(tool, "name", errors, `contributes.mcpServers[${index}].tools[${toolIndex}].name`);
if (tool.description !== undefined) {
requireString(tool, "description", errors, `contributes.mcpServers[${index}].tools[${toolIndex}].description`);
}
});
if (Array.isArray(server.tools)) {
const names = new Set<string>();
server.tools.forEach((tool, toolIndex) => {
if (!isRecord(tool) || typeof tool.name !== "string" || tool.name.trim() === "") return;
if (names.has(tool.name)) {
errors.push(`contributes.mcpServers[${index}].tools[${toolIndex}].name must be unique within the server`);
}
names.add(tool.name);
});
}
});
}