diff --git a/src/renderer/components/ChatPane.tsx b/src/renderer/components/ChatPane.tsx index 91354c9..7d158b8 100644 --- a/src/renderer/components/ChatPane.tsx +++ b/src/renderer/components/ChatPane.tsx @@ -131,15 +131,17 @@ export function ChatPane({ ); const effectiveAutoApprovedCount = useMemo(() => { const groups = groupApprovalToolsByProvider(approvalTools, toolingSettings); - let count = 0; + const counted = new Set(); for (const group of groups) { if (group.serverApprovalKey && effectiveAutoApproved.has(group.serverApprovalKey)) { - count += group.tools.length; + for (const tool of group.tools) counted.add(tool.id); } else { - count += group.tools.filter((t) => effectiveAutoApproved.has(t.id)).length; + for (const tool of group.tools) { + if (effectiveAutoApproved.has(tool.id)) counted.add(tool.id); + } } } - return count; + return counted.size; }, [approvalTools, effectiveAutoApproved, toolingSettings]); useEffect(() => { diff --git a/src/shared/domain/tooling.ts b/src/shared/domain/tooling.ts index bc2f170..e1c23bb 100644 --- a/src/shared/domain/tooling.ts +++ b/src/shared/domain/tooling.ts @@ -306,6 +306,22 @@ export function groupApprovalToolsByProvider( const groups = new Map(); for (const tool of tools) { + // Place MCP tools in every provider group they belong to, so each server + // shows its own tools even when multiple servers share the same tool names. + if (tool.kind === 'mcp' && tool.providerIds.length > 1) { + for (const providerId of tool.providerIds) { + const groupId = `mcp:${providerId}`; + let group = groups.get(groupId); + if (!group) { + const label = serverNames.get(providerId) ?? providerId; + group = { id: groupId, label, kind: 'mcp', tools: [] }; + groups.set(groupId, group); + } + group.tools.push(tool); + } + continue; + } + const groupKey = resolveApprovalToolGroupKey(tool, serverNames, profileNames); let group = groups.get(groupKey.id); if (!group) { diff --git a/tests/shared/tooling.test.ts b/tests/shared/tooling.test.ts index de1a28b..e114a07 100644 --- a/tests/shared/tooling.test.ts +++ b/tests/shared/tooling.test.ts @@ -443,7 +443,7 @@ describe('groupApprovalToolsByProvider', () => { expect(builtinGroups[0].tools.length).toBe(5); }); - test('multi-provider tools go into first provider group, second provider gets empty group', () => { + test('multi-provider tools appear in all provider groups', () => { const tooling = makeTooling([ makeMcpServer('git-a', 'Git A', ['git.status']), makeMcpServer('git-b', 'Git B', ['git.status']), @@ -455,10 +455,12 @@ describe('groupApprovalToolsByProvider', () => { expect(mcpGroups.length).toBe(2); const gitA = mcpGroups.find((g) => g.label === 'Git A'); expect(gitA).toBeDefined(); + expect(gitA!.tools.length).toBe(1); expect(gitA!.tools[0].providerNames).toEqual(['Git A', 'Git B']); const gitB = mcpGroups.find((g) => g.label === 'Git B'); expect(gitB).toBeDefined(); - expect(gitB!.tools.length).toBe(0); + expect(gitB!.tools.length).toBe(1); + expect(gitB!.tools[0].id).toBe('git.status'); }); test('sorts builtin first, then MCP by name, then LSP by name', () => {