Skip to content

Commit 676289a

Browse files
committed
fix: multiple fixes for remote mcp error and timeout
1 parent 7007714 commit 676289a

File tree

4 files changed

+48
-14
lines changed

4 files changed

+48
-14
lines changed

server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1238,7 +1238,7 @@ export class McpEventHandler {
12381238
const serverConfig = McpManager.instance.getAllServerConfigs().get(serverName)
12391239
if (serverConfig) {
12401240
// Emit server initialize event after permission change
1241-
const transportType = serverConfig.command ? 'stdio' : 'http'
1241+
const transportType = serverConfig.command?.trim() ? 'stdio' : 'http'
12421242
this.#telemetryController?.emitMCPServerInitializeEvent({
12431243
source: 'updatePermission',
12441244
command: transportType === 'stdio' ? serverConfig.command : undefined,
@@ -1319,7 +1319,7 @@ export class McpEventHandler {
13191319
enabled: enabled,
13201320
numTools: mcpManager.getAllToolsWithPermissions(serverName).length,
13211321
scope: config.__configPath__ === globalAgentPath ? 'global' : 'workspace',
1322-
transportType: 'stdio',
1322+
transportType: transportType,
13231323
languageServerVersion: this.#features.runtime.serverInfo.version,
13241324
})
13251325
}

server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ export class McpManager {
292292
this.features.logging.debug(`MCP: initializing server [${serverName}]`)
293293

294294
const client = new Client({
295-
name: `mcp-client-${serverName}`,
295+
name: `q-chat-plugin`, // Do not use variables in the client name to avoid polluting builder-mcp metrics
296296
version: '1.0.0',
297297
})
298298

@@ -662,7 +662,7 @@ export class McpManager {
662662
disabled: cfg.disabled ?? false,
663663
}
664664
// Only add timeout to agent config if it's not 0
665-
if (cfg.timeout !== 0) {
665+
if (cfg.timeout !== undefined) {
666666
serverConfig.timeout = cfg.timeout
667667
}
668668
if (cfg.args && cfg.args.length > 0) {
@@ -1281,11 +1281,21 @@ export class McpManager {
12811281
private handleError(server: string | undefined, err: unknown) {
12821282
const msg = err instanceof Error ? err.message : String(err)
12831283

1284-
this.features.logging.error(`MCP ERROR${server ? ` [${server}]` : ''}: ${msg}`)
1284+
const isBenignSseDisconnect =
1285+
/SSE error:\s*TypeError:\s*terminated:\s*Body Timeout Error/i.test(msg) ||
1286+
/TypeError:\s*terminated:\s*Body Timeout Error/i.test(msg) ||
1287+
/TypeError:\s*terminated:\s*other side closed/i.test(msg) ||
1288+
/ECONNRESET|ENETRESET|EPIPE/i.test(msg)
12851289

1286-
if (server) {
1287-
this.setState(server, McpServerStatus.FAILED, 0, msg)
1288-
this.emitToolsChanged(server)
1290+
if (isBenignSseDisconnect) {
1291+
this.features.logging.debug(`MCP SSE idle timeout${server ? ` [${server}]` : ''}: ${msg}`)
1292+
} else {
1293+
// default path for real errors
1294+
this.features.logging.error(`MCP ERROR${server ? ` [${server}]` : ''}: ${msg}`)
1295+
if (server) {
1296+
this.setState(server, McpServerStatus.FAILED, 0, msg)
1297+
this.emitToolsChanged(server)
1298+
}
12891299
}
12901300
}
12911301

server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpOauthClient.ts

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,16 @@ export class OAuthClient {
5656
const port = Number(new URL(savedReg.redirect_uri).port)
5757
server = http.createServer()
5858
try {
59-
await new Promise<void>(res => server.listen(port, '127.0.0.1', res))
59+
await this.listen(server, port)
6060
redirectUri = savedReg.redirect_uri
6161
this.logger.info(`OAuth: reusing redirect URI ${redirectUri}`)
6262
} catch (e: any) {
6363
if (e.code === 'EADDRINUSE') {
64+
try {
65+
server.close()
66+
} catch {
67+
/* ignore */
68+
}
6469
this.logger.warn(`Port ${port} in use; falling back to new random port`)
6570
;({ server, redirectUri } = await this.buildCallbackServer())
6671
this.logger.info(`OAuth: new redirect URI ${redirectUri}`)
@@ -131,9 +136,8 @@ export class OAuthClient {
131136
// Spin up a one‑time HTTP listener on localhost:randomPort */
132137
private static async buildCallbackServer(): Promise<{ server: http.Server; redirectUri: string }> {
133138
const server = http.createServer()
134-
const port = await new Promise<number>(res =>
135-
server.listen(0, '127.0.0.1', () => res((server.address() as any).port))
136-
)
139+
await this.listen(server, 0)
140+
const port = (server.address() as any).port as number
137141
return { server, redirectUri: `http://localhost:${port}` }
138142
}
139143

@@ -393,4 +397,24 @@ export class OAuthClient {
393397
'sso',
394398
'cache'
395399
)
400+
401+
/**
402+
* Await server.listen() but reject if it emits 'error' (eg EADDRINUSE),
403+
* so callers can handle it immediately instead of hanging.
404+
*/
405+
private static listen(server: http.Server, port: number, host: string = '127.0.0.1'): Promise<void> {
406+
return new Promise((resolve, reject) => {
407+
const onListening = () => {
408+
server.off('error', onError)
409+
resolve()
410+
}
411+
const onError = (err: NodeJS.ErrnoException) => {
412+
server.off('listening', onListening)
413+
reject(err)
414+
}
415+
server.once('listening', onListening)
416+
server.once('error', onError)
417+
server.listen(port, host)
418+
})
419+
}
396420
}

server/aws-lsp-codewhisperer/src/shared/localProjectContextController.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ export class LocalProjectContextController {
8585
try {
8686
await waitUntil(async () => this.instance, {
8787
interval: 1000,
88-
timeout: 60,
88+
timeout: 60_000,
8989
truthy: true,
9090
})
9191

@@ -359,7 +359,7 @@ export class LocalProjectContextController {
359359
}
360360
return false
361361
},
362-
{ interval: 1000, timeout: 60, truthy: true }
362+
{ interval: 1000, timeout: 60_000, truthy: true }
363363
)
364364
return true
365365
} catch (error) {

0 commit comments

Comments
 (0)