fix(team): proactively add all agent-teams MCP tools on first approval

When user approves any mcp__agent-teams__* tool, also add all other
agent-teams tools to settings.local.json preemptively. This prevents
teammates from getting stuck on subsequent tool calls (task_get,
task_start, task_complete, etc.) since each generates a separate
permission_request and the teammate blocks until resolved.

FACT: Settings file approach only prevents FUTURE blocks, not current
ones. Pre-adding all tools on first approval covers the common case.
This commit is contained in:
iliya 2026-03-30 15:59:53 +03:00
parent d2487e41c9
commit 34f1f0d612
2 changed files with 39 additions and 14 deletions

View file

@ -6370,11 +6370,31 @@ export class TeamProvisioningService {
for (const suggestion of suggestions) {
if (suggestion.type !== 'addRules' || !Array.isArray(suggestion.rules)) continue;
const toolNames = suggestion.rules
let toolNames = suggestion.rules
.map((r) => r.toolName)
.filter((name): name is string => typeof name === 'string' && name.length > 0);
if (toolNames.length === 0) continue;
// When approving ANY mcp__agent-teams__ tool, proactively add ALL agent-teams tools.
// FACT: Teammates need multiple MCP tools (member_briefing, task_get, task_start, etc.)
// FACT: Each tool generates a separate permission_request, but by the time we process it
// the teammate is already stuck waiting. Pre-adding all tools prevents future blocks.
if (toolNames.some((name) => name.startsWith('mcp__agent-teams__'))) {
const agentTeamsTools = [
'mcp__agent-teams__member_briefing',
'mcp__agent-teams__task_briefing',
'mcp__agent-teams__task_create',
'mcp__agent-teams__task_get',
'mcp__agent-teams__task_list',
'mcp__agent-teams__task_start',
'mcp__agent-teams__task_complete',
'mcp__agent-teams__task_set_status',
'mcp__agent-teams__task_add_comment',
];
const merged = new Set([...toolNames, ...agentTeamsTools]);
toolNames = Array.from(merged);
}
const behavior = suggestion.behavior ?? 'allow';
// FACT: observed destinations are "localSettings" (project-level .claude/settings.local.json)
const settingsPath =

View file

@ -223,22 +223,27 @@ function MemberPopoverContent({
Recent tools
</div>
<div className="space-y-1">
{node.recentTools.slice(0, 3).map((tool) => (
<div
key={`${tool.name}:${tool.finishedAt}:${tool.startedAt}`}
className="rounded border border-[var(--color-border)] bg-[var(--color-surface-secondary)] px-2 py-1 text-[10px]"
>
{node.recentTools.slice(0, 3).map((tool) => {
const shortName = formatToolName(tool.name);
const shortPreview = formatToolPreview(tool.preview);
return (
<div
className="font-mono"
style={{ color: tool.state === 'error' ? '#ef4444' : '#22c55e' }}
key={`${tool.name}:${tool.finishedAt}:${tool.startedAt}`}
className="flex items-center gap-1.5 rounded border border-[var(--color-border)] bg-[var(--color-surface-secondary)] px-2 py-1 text-[10px]"
>
{tool.preview ? `${tool.name}: ${tool.preview}` : tool.name}
<span
className="size-1.5 shrink-0 rounded-full"
style={{ background: tool.state === 'error' ? '#ef4444' : '#22c55e' }}
/>
<span className="font-mono font-medium text-[var(--color-text)]">
{shortName}
</span>
{shortPreview && (
<span className="truncate text-[var(--color-text-muted)]">{shortPreview}</span>
)}
</div>
{tool.resultPreview && (
<div className="mt-0.5 text-[var(--color-text-muted)]">{tool.resultPreview}</div>
)}
</div>
))}
);
})}
</div>
</div>
)}