feat(agents,plugins): surface unifiée Capacités de l'agent — skills et tools MCP natifs + plugins #296 (domain: PluginMcpToolMetadata dans PluginMcpServerContribution, validation hôte alignée SDK — name requis non vide, description optionnelle non vide, doublons rejetés; application: McpToolPermissionCatalogue.vue structurée additive tools {name, description, access read|writeAction} enrichie des descriptions canoniques infrastructure orchestrator mcp tools, use case SetAgentMcpToolAllowed — toggle atomique idempotente d'un tool natif dans l'allowlist explicite d'un agent, refus unknown tool sans mutation, overrides vides retirés; backend DTO: catalogue.tools additive + SetAgentMcpToolAllowedRequestDto, wire camelCase; app-tauri + web-server: commande set_agent_mcp_tool_allowed; frontend: AgentPluginCapabilities devient la surface unifiée — skills natifs assign/unassign, tools natifs via setAgentMcpToolAllowed (catalogue structuré avec fallback legacy), skills/tools plugins avec metadata statiques mcpServers[].tools et saisie manuelle fallback pour serveurs sans catalogue, tombstones indisponibles, bannière redémarrage requis si agent actif; AgentsPanel retire l'ancienne section Skills séparée au profit de la surface unifiée; ProjectPluginsPanel recentré enable/disable avec renvoi Capacités des agents; adapters Tauri/HTTP/mock + permission.test.ts; QA verte reconfirmée par Git: application mcp_tool_permissions 5/5 + plugin::tests 37/37, backend ciblés 3/3 + checks domain/application/backend, app-tauri dto 33/33 + dto_agents 30/30 + dto_plugins 2/2, check web-server, npm test 35/35 + 65/65, npm run build; suites complètes rouges classées non bloquantes par QA: web-server parallèle too many open files + 7 PTY série passant individuellement, frontend 32 échecs sur 6 fichiers web non modifiés reproduits isolément)

This commit is contained in:
2026-09-09 19:52:38 +02:00
parent 6e4d9eb47e
commit e283f4a9e4
22 changed files with 1152 additions and 301 deletions

View File

@ -2952,6 +2952,20 @@ pub struct McpToolCatalogueDto {
pub read_only_tools: Vec<String>,
/// Tools treated as writing/action/execution tools.
pub write_action_tools: Vec<String>,
/// Structured additive catalogue for unified capability surfaces.
pub tools: Vec<McpToolCatalogueEntryDto>,
}
/// Structured metadata for one native IdeA MCP tool.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct McpToolCatalogueEntryDto {
/// Stable tool name.
pub name: String,
/// Human-readable description from the canonical MCP definition.
pub description: String,
/// Coarse access class: `read` or `writeAction`.
pub access: String,
}
/// Full MCP tool permission state crossing the wire.
@ -2975,6 +2989,20 @@ impl From<ReadMcpToolPermissionsOutput> for ProjectMcpToolPermissionsDto {
catalogue: McpToolCatalogueDto {
read_only_tools: out.catalogue.read_only_tools,
write_action_tools: out.catalogue.write_action_tools,
tools: out
.catalogue
.tools
.into_iter()
.map(|tool| McpToolCatalogueEntryDto {
name: tool.name,
description: tool.description,
access: match tool.access {
application::McpToolCatalogueAccess::Read => "read",
application::McpToolCatalogueAccess::WriteAction => "writeAction",
}
.to_owned(),
})
.collect(),
},
project_default: out.permissions.project_default,
agents: out.permissions.agents,
@ -3068,6 +3096,20 @@ pub struct UpdateAgentMcpToolPermissionsRequestDto {
pub policy: Option<McpToolPolicy>,
}
/// Request for atomically toggling one native MCP tool for an agent.
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SetAgentMcpToolAllowedRequestDto {
/// Id of the owning project.
pub project_id: String,
/// Target agent id.
pub agent_id: String,
/// Exact native MCP tool name.
pub tool_name: String,
/// Desired explicit allowlist membership.
pub allowed: bool,
}
/// Request DTO for `update_project_context`.
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
@ -5782,7 +5824,11 @@ mod tests {
vec!["idea_ticket_read".to_owned()],
vec!["idea_ticket_update".to_owned()],
)
.unwrap(),
.unwrap()
.with_descriptions([
("idea_ticket_read", "Read one ticket."),
("idea_ticket_update", "Update one ticket."),
]),
permissions: ProjectMcpToolPermissions {
version: 1,
project_default: Some(
@ -5804,7 +5850,19 @@ mod tests {
"version": 1,
"catalogue": {
"readOnlyTools": ["idea_ticket_read"],
"writeActionTools": ["idea_ticket_update"]
"writeActionTools": ["idea_ticket_update"],
"tools": [
{
"name": "idea_ticket_read",
"description": "Read one ticket.",
"access": "read"
},
{
"name": "idea_ticket_update",
"description": "Update one ticket.",
"access": "writeAction"
}
]
},
"projectDefault": {
"allowedTools": ["idea_ticket_read"]