fix: preserve probed MCP tools across session switches

mergeDiscoveredToolingState now carries over probedTools from existing
servers when the config fingerprint is unchanged. The equality check in
syncProjectDiscoveredTooling also strips probedTools before comparing,
so runtime-only probe data never triggers a spurious state replacement.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
David Kaya
2026-03-28 20:09:45 +01:00
co-authored by Copilot
parent 08876f694d
commit 9ddd831b34
3 changed files with 51 additions and 2 deletions
+4 -2
View File
@@ -2348,8 +2348,10 @@ export class AryxAppService extends EventEmitter<AppServiceEvents> {
left?: DiscoveredToolingState,
right?: DiscoveredToolingState,
): boolean {
return JSON.stringify(normalizeDiscoveredToolingState(left).mcpServers)
=== JSON.stringify(normalizeDiscoveredToolingState(right).mcpServers);
const stripRuntime = (servers: DiscoveredMcpServer[]) =>
servers.map(({ probedTools: _, ...rest }) => rest);
return JSON.stringify(stripRuntime(normalizeDiscoveredToolingState(left).mcpServers))
=== JSON.stringify(stripRuntime(normalizeDiscoveredToolingState(right).mcpServers));
}
private equalProjectCustomizationState(
+1
View File
@@ -122,6 +122,7 @@ export function mergeDiscoveredToolingState(
return {
...server,
status: existing.status,
probedTools: existing.probedTools,
} satisfies DiscoveredMcpServer;
}
+46
View File
@@ -105,4 +105,50 @@ describe('discovered tooling helpers', () => {
expect(listPendingDiscoveredMcpServers(dismissed)).toEqual([]);
expect(dismissed.mcpServers[1]?.status).toBe('dismissed');
});
test('preserves probedTools when fingerprint is unchanged on re-scan', () => {
const probedTools = [
{ name: 'git_status', description: 'Get git status' },
{ name: 'git_diff', description: 'Get git diff' },
];
const current = {
mcpServers: [
createDiscoveredServer({
status: 'accepted',
probedTools,
}),
],
lastScannedAt: TIMESTAMP,
};
const merged = mergeDiscoveredToolingState(
current,
[createDiscoveredServer()],
'2026-03-25T01:00:00.000Z',
);
expect(merged.mcpServers[0]?.probedTools).toEqual(probedTools);
expect(merged.mcpServers[0]?.status).toBe('accepted');
});
test('drops probedTools when fingerprint changes on re-scan', () => {
const current = {
mcpServers: [
createDiscoveredServer({
status: 'accepted',
probedTools: [{ name: 'git_status' }],
}),
],
lastScannedAt: TIMESTAMP,
};
const merged = mergeDiscoveredToolingState(
current,
[createDiscoveredServer({ args: ['server.js', '--debug'] })],
'2026-03-25T01:00:00.000Z',
);
expect(merged.mcpServers[0]?.probedTools).toBeUndefined();
expect(merged.mcpServers[0]?.status).toBe('pending');
});
});