mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-15 14:23:02 -07:00
fix(core): drain stderr stream unconditionally for StdioClientTransport
This commit is contained in:
@@ -1993,6 +1993,27 @@ describe('mcp-client', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should unconditionally attach a data listener to stderr to prevent process hang', async () => {
|
||||
const mockStderr = {
|
||||
on: vi.fn(),
|
||||
};
|
||||
|
||||
vi.spyOn(SdkClientStdioLib, 'StdioClientTransport').mockReturnValue({
|
||||
stderr: mockStderr,
|
||||
} as unknown as SdkClientStdioLib.StdioClientTransport);
|
||||
|
||||
await createTransport(
|
||||
'test-server',
|
||||
{
|
||||
command: 'test-command',
|
||||
},
|
||||
false, // debugMode = false
|
||||
MOCK_CONTEXT,
|
||||
);
|
||||
|
||||
expect(mockStderr.on).toHaveBeenCalledWith('data', expect.any(Function));
|
||||
});
|
||||
|
||||
it('sets an env variable GEMINI_CLI=1 for stdio MCP servers', async () => {
|
||||
const mockedTransport = vi
|
||||
.spyOn(SdkClientStdioLib, 'StdioClientTransport')
|
||||
|
||||
@@ -2291,31 +2291,40 @@ export async function createTransport(
|
||||
transport = new XcodeMcpBridgeFixTransport(transport);
|
||||
}
|
||||
|
||||
if (debugMode) {
|
||||
// The `XcodeMcpBridgeFixTransport` wrapper hides the underlying `StdioClientTransport`,
|
||||
// which exposes `stderr` for debug logging. We need to unwrap it to attach the listener.
|
||||
// The `XcodeMcpBridgeFixTransport` wrapper hides the underlying `StdioClientTransport`,
|
||||
// which exposes `stderr` for debug logging. We need to unwrap it to attach the listener.
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
const underlyingTransport =
|
||||
transport instanceof XcodeMcpBridgeFixTransport
|
||||
? // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-type-assertion
|
||||
(transport as any).transport
|
||||
: transport;
|
||||
const underlyingTransport =
|
||||
transport instanceof XcodeMcpBridgeFixTransport
|
||||
? // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
(transport as unknown as { transport: unknown }).transport
|
||||
: transport;
|
||||
|
||||
if (
|
||||
underlyingTransport instanceof StdioClientTransport &&
|
||||
underlyingTransport.stderr
|
||||
) {
|
||||
underlyingTransport.stderr.on('data', (data) => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
const stderrStr = data.toString().trim();
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const streamTransport = underlyingTransport as {
|
||||
stderr?: {
|
||||
on: (event: string, listener: (data: unknown) => void) => void;
|
||||
};
|
||||
};
|
||||
|
||||
if (
|
||||
streamTransport &&
|
||||
typeof streamTransport === 'object' &&
|
||||
'stderr' in streamTransport &&
|
||||
streamTransport.stderr &&
|
||||
typeof streamTransport.stderr.on === 'function'
|
||||
) {
|
||||
streamTransport.stderr.on('data', (data: unknown) => {
|
||||
if (debugMode) {
|
||||
const stderrStr = String(data).trim();
|
||||
debugLogger.debug(
|
||||
`[DEBUG] [MCP STDERR (${mcpServerName})]: `,
|
||||
stderrStr,
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return transport;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user