Compare commits

...

3 Commits

Author SHA1 Message Date
Spencer bf3daed9ed Merge branch 'main' into dupe-listing 2026-04-24 14:53:47 -04:00
Spencer 868e3f7180 fix(cli): filter blocked MCP servers case-insensitively to prevent duplication
Fixes a bug where disconnected MCP servers were listed twice in '/mcp list' (once as 'Disconnected' and once as 'Blocked') due to a strict string equality check that failed when extension server names had different casing or trailing whitespace compared to user configuration. Updated the filter in 'McpStatus.tsx' to use '.trim().toLowerCase()'.
2026-04-24 18:46:18 +00:00
Spencer cfd7541ad4 fix(cli): allow output redirection for cli commands (#25894) 2026-04-24 18:31:43 +00:00
4 changed files with 41 additions and 10 deletions
+5 -9
View File
@@ -358,8 +358,8 @@ export async function main() {
const isDebugMode = cliConfig.isDebugMode(argv);
const consolePatcher = new ConsolePatcher({
stderr: true,
interactive: isHeadlessMode() ? false : true,
stderr: argv.isCommand ? false : true,
interactive: isHeadlessMode() && !argv.isCommand ? false : true,
debugMode: isDebugMode,
onNewMessage: (msg) => {
coreEvents.emitConsoleLog(msg.type, msg.content);
@@ -786,20 +786,16 @@ export function initializeOutputListenersAndFlush() {
if (coreEvents.listenerCount(CoreEvent.ConsoleLog) === 0) {
coreEvents.on(CoreEvent.ConsoleLog, (payload: ConsoleLogPayload) => {
if (payload.type === 'error' || payload.type === 'warn') {
writeToStderr(payload.content);
writeToStderr(payload.content + '\n');
} else {
writeToStdout(payload.content);
writeToStderr(payload.content + '\n');
}
});
}
if (coreEvents.listenerCount(CoreEvent.UserFeedback) === 0) {
coreEvents.on(CoreEvent.UserFeedback, (payload: UserFeedbackPayload) => {
if (payload.severity === 'error' || payload.severity === 'warning') {
writeToStderr(payload.message);
} else {
writeToStdout(payload.message);
}
writeToStderr(payload.message + '\n');
});
}
}
@@ -202,6 +202,30 @@ describe('McpStatus', () => {
unmount();
});
it('filters blocked servers case-insensitively and ignores whitespace', async () => {
const { lastFrame, unmount } = await render(
<McpStatus
{...baseProps}
servers={{
'SERVER-1 ': {
url: 'http://localhost:8080',
description: 'A test server',
},
' server-2': {
url: 'http://localhost:8081',
description: 'A blocked server',
},
}}
blockedServers={[
{ name: ' server-1', extensionName: 'test-extension' },
{ name: 'SERVER-2 ', extensionName: 'test-extension' },
]}
/>,
);
expect(lastFrame()).toMatchSnapshot();
unmount();
});
it('renders only blocked servers when no configured servers exist', async () => {
const { lastFrame, unmount } = await render(
<McpStatus
@@ -50,7 +50,9 @@ export const McpStatus: React.FC<McpStatusProps> = ({
const serverNames = Object.keys(servers).filter(
(serverName) =>
!blockedServers.some(
(blockedServer) => blockedServer.name === serverName,
(blockedServer) =>
blockedServer.name.trim().toLowerCase() ===
serverName.trim().toLowerCase(),
),
);
@@ -1,5 +1,14 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`McpStatus > filters blocked servers case-insensitively and ignores whitespace 1`] = `
"Configured MCP servers:
🔴 server-1 (from test-extension) - Blocked
🔴 SERVER-2 (from test-extension) - Blocked
"
`;
exports[`McpStatus > renders correctly when discovery is in progress 1`] = `
"⏳ MCP servers are starting up (0 initializing)...
Note: First startup may take longer. Tool availability will update automatically.