From 7888e9383b1bed4b78195fdac3c2ef2914355649 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 11 Jan 2026 07:29:00 +0000 Subject: [PATCH 1/4] Initial plan From e6fd6013a658f0d1b55512ac383eb3be549c84f5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 11 Jan 2026 07:36:03 +0000 Subject: [PATCH 2/4] Add MCP server connection failure detection to Copilot parser Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/parse_copilot_log.cjs | 32 +++++++-- actions/setup/js/parse_copilot_log.test.cjs | 74 +++++++++++++++++++++ 2 files changed, 100 insertions(+), 6 deletions(-) diff --git a/actions/setup/js/parse_copilot_log.cjs b/actions/setup/js/parse_copilot_log.cjs index 5daa74ea10..3983c06609 100644 --- a/actions/setup/js/parse_copilot_log.cjs +++ b/actions/setup/js/parse_copilot_log.cjs @@ -40,6 +40,7 @@ function extractPremiumRequestCount(logContent) { */ function parseCopilotLog(logContent) { let logEntries; + let mcpFailures = []; // First, try to parse as JSON array (structured format) try { @@ -49,9 +50,10 @@ function parseCopilotLog(logContent) { } } catch (jsonArrayError) { // If that fails, try to parse as debug logs format - const debugLogEntries = parseDebugLogFormat(logContent); - if (debugLogEntries && debugLogEntries.length > 0) { - logEntries = debugLogEntries; + const debugLogResult = parseDebugLogFormat(logContent); + if (debugLogResult && debugLogResult.entries && debugLogResult.entries.length > 0) { + logEntries = debugLogResult.entries; + mcpFailures = debugLogResult.mcpFailures || []; } else { // Try JSONL format using shared function logEntries = parseLogEntries(logContent); @@ -126,7 +128,12 @@ function parseCopilotLog(logContent) { }, }); - return { markdown, logEntries }; + // Return result with mcpFailures if any were detected + const result = { markdown, logEntries }; + if (mcpFailures.length > 0) { + result.mcpFailures = mcpFailures; + } + return result; } /** @@ -208,15 +215,28 @@ function scanForToolErrors(logContent) { /** * Parses Copilot CLI debug log format and reconstructs the conversation flow * @param {string} logContent - Raw debug log content - * @returns {Array} Array of log entries in structured format + * @returns {{entries: Array, mcpFailures: string[]}} Object with array of log entries and array of failed MCP server names */ function parseDebugLogFormat(logContent) { const entries = []; const lines = logContent.split("\n"); + const mcpFailures = []; // First pass: scan for tool errors const toolErrors = scanForToolErrors(logContent); + // Scan for MCP server connection failures + // Pattern: [ERROR] Failed to start MCP client for remote server : TypeError: fetch failed + for (const line of lines) { + const mcpFailureMatch = line.match(/\[ERROR\]\s+Failed to start MCP client for remote server\s+([^:]+):\s+TypeError:\s+fetch failed/i); + if (mcpFailureMatch) { + const serverName = mcpFailureMatch[1].trim(); + if (serverName && !mcpFailures.includes(serverName)) { + mcpFailures.push(serverName); + } + } + } + // Extract model information from the start let model = "unknown"; let sessionId = null; @@ -683,7 +703,7 @@ function parseDebugLogFormat(logContent) { } } - return entries; + return { entries, mcpFailures }; } // Export for testing diff --git a/actions/setup/js/parse_copilot_log.test.cjs b/actions/setup/js/parse_copilot_log.test.cjs index f3fcaa7dc6..e9d0cba2a7 100644 --- a/actions/setup/js/parse_copilot_log.test.cjs +++ b/actions/setup/js/parse_copilot_log.test.cjs @@ -278,4 +278,78 @@ describe("parse_copilot_log.cjs", () => { expect(result.markdown).toContain("safe_outputs::create_issue"); }); }); + + describe("MCP server failure detection", () => { + it("should detect MCP server connection failures from debug logs", () => { + const logWithMcpFailure = `2026-01-11T07:21:35.050Z [DEBUG] Starting Copilot CLI +2026-01-11T07:21:35.050Z [ERROR] Failed to start MCP client for remote server github: TypeError: fetch failed +2026-01-11T07:21:35.100Z [DEBUG] data: +2026-01-11T07:21:35.100Z [DEBUG] { +2026-01-11T07:21:35.100Z [DEBUG] "choices": [{"message": {"content": "test"}}] +2026-01-11T07:21:35.100Z [DEBUG] }`; + + const result = parseCopilotLog(logWithMcpFailure); + + expect(result.mcpFailures).toBeDefined(); + expect(result.mcpFailures).toHaveLength(1); + expect(result.mcpFailures[0]).toBe("github"); + }); + + it("should detect multiple MCP server failures", () => { + const logWithMultipleMcpFailures = `2026-01-11T07:21:35.050Z [DEBUG] Starting Copilot CLI +2026-01-11T07:21:35.050Z [ERROR] Failed to start MCP client for remote server github: TypeError: fetch failed +2026-01-11T07:21:35.100Z [ERROR] Failed to start MCP client for remote server playwright: TypeError: fetch failed +2026-01-11T07:21:35.150Z [DEBUG] data: +2026-01-11T07:21:35.150Z [DEBUG] { +2026-01-11T07:21:35.150Z [DEBUG] "choices": [{"message": {"content": "test"}}] +2026-01-11T07:21:35.150Z [DEBUG] }`; + + const result = parseCopilotLog(logWithMultipleMcpFailures); + + expect(result.mcpFailures).toBeDefined(); + expect(result.mcpFailures).toHaveLength(2); + expect(result.mcpFailures).toContain("github"); + expect(result.mcpFailures).toContain("playwright"); + }); + + it("should not report MCP failures for successful logs", () => { + const successfulLog = `2026-01-11T07:21:35.050Z [DEBUG] Starting Copilot CLI +2026-01-11T07:21:35.050Z [DEBUG] Connected to MCP server github +2026-01-11T07:21:35.100Z [DEBUG] data: +2026-01-11T07:21:35.100Z [DEBUG] { +2026-01-11T07:21:35.100Z [DEBUG] "choices": [{"message": {"content": "test"}}] +2026-01-11T07:21:35.100Z [DEBUG] }`; + + const result = parseCopilotLog(successfulLog); + + expect(result.mcpFailures).toBeUndefined(); + }); + + it("should handle JSON format without MCP failures", () => { + const jsonLog = JSON.stringify([ + { type: "system", subtype: "init", session_id: "test", tools: ["Bash"], model: "gpt-4" }, + { type: "result", num_turns: 1, usage: { input_tokens: 100, output_tokens: 50 } } + ]); + + const result = parseCopilotLog(jsonLog); + + expect(result.mcpFailures).toBeUndefined(); + }); + + it("should avoid duplicate MCP server names in failures list", () => { + const logWithDuplicateErrors = `2026-01-11T07:21:35.050Z [DEBUG] Starting Copilot CLI +2026-01-11T07:21:35.050Z [ERROR] Failed to start MCP client for remote server github: TypeError: fetch failed +2026-01-11T07:21:35.100Z [ERROR] Failed to start MCP client for remote server github: TypeError: fetch failed +2026-01-11T07:21:35.150Z [DEBUG] data: +2026-01-11T07:21:35.150Z [DEBUG] { +2026-01-11T07:21:35.150Z [DEBUG] "choices": [{"message": {"content": "test"}}] +2026-01-11T07:21:35.150Z [DEBUG] }`; + + const result = parseCopilotLog(logWithDuplicateErrors); + + expect(result.mcpFailures).toBeDefined(); + expect(result.mcpFailures).toHaveLength(1); + expect(result.mcpFailures[0]).toBe("github"); + }); + }); }); From d9ef7cecb47377ce71ba336a0b44631d793dee63 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 11 Jan 2026 07:39:49 +0000 Subject: [PATCH 3/4] Verification complete: MCP server connection failure detection working Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/parse_copilot_log.test.cjs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/actions/setup/js/parse_copilot_log.test.cjs b/actions/setup/js/parse_copilot_log.test.cjs index e9d0cba2a7..085a746c6a 100644 --- a/actions/setup/js/parse_copilot_log.test.cjs +++ b/actions/setup/js/parse_copilot_log.test.cjs @@ -289,7 +289,7 @@ describe("parse_copilot_log.cjs", () => { 2026-01-11T07:21:35.100Z [DEBUG] }`; const result = parseCopilotLog(logWithMcpFailure); - + expect(result.mcpFailures).toBeDefined(); expect(result.mcpFailures).toHaveLength(1); expect(result.mcpFailures[0]).toBe("github"); @@ -305,7 +305,7 @@ describe("parse_copilot_log.cjs", () => { 2026-01-11T07:21:35.150Z [DEBUG] }`; const result = parseCopilotLog(logWithMultipleMcpFailures); - + expect(result.mcpFailures).toBeDefined(); expect(result.mcpFailures).toHaveLength(2); expect(result.mcpFailures).toContain("github"); @@ -321,18 +321,18 @@ describe("parse_copilot_log.cjs", () => { 2026-01-11T07:21:35.100Z [DEBUG] }`; const result = parseCopilotLog(successfulLog); - + expect(result.mcpFailures).toBeUndefined(); }); it("should handle JSON format without MCP failures", () => { const jsonLog = JSON.stringify([ { type: "system", subtype: "init", session_id: "test", tools: ["Bash"], model: "gpt-4" }, - { type: "result", num_turns: 1, usage: { input_tokens: 100, output_tokens: 50 } } + { type: "result", num_turns: 1, usage: { input_tokens: 100, output_tokens: 50 } }, ]); const result = parseCopilotLog(jsonLog); - + expect(result.mcpFailures).toBeUndefined(); }); @@ -346,7 +346,7 @@ describe("parse_copilot_log.cjs", () => { 2026-01-11T07:21:35.150Z [DEBUG] }`; const result = parseCopilotLog(logWithDuplicateErrors); - + expect(result.mcpFailures).toBeDefined(); expect(result.mcpFailures).toHaveLength(1); expect(result.mcpFailures[0]).toBe("github"); From 151e8bfc14f3c910155bc3af3415647371207f5c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 11 Jan 2026 07:56:03 +0000 Subject: [PATCH 4/4] Call core.setFailed immediately when MCP failures detected in parseDebugLogFormat Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/parse_copilot_log.cjs | 6 ++++++ actions/setup/js/parse_copilot_log.test.cjs | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/actions/setup/js/parse_copilot_log.cjs b/actions/setup/js/parse_copilot_log.cjs index 3983c06609..053b947924 100644 --- a/actions/setup/js/parse_copilot_log.cjs +++ b/actions/setup/js/parse_copilot_log.cjs @@ -237,6 +237,12 @@ function parseDebugLogFormat(logContent) { } } + // Fail the step immediately if MCP server failures are detected + if (mcpFailures.length > 0) { + const failedServers = mcpFailures.join(", "); + core.setFailed(`MCP server(s) failed to launch: ${failedServers}`); + } + // Extract model information from the start let model = "unknown"; let sessionId = null; diff --git a/actions/setup/js/parse_copilot_log.test.cjs b/actions/setup/js/parse_copilot_log.test.cjs index 085a746c6a..66662eb685 100644 --- a/actions/setup/js/parse_copilot_log.test.cjs +++ b/actions/setup/js/parse_copilot_log.test.cjs @@ -293,6 +293,7 @@ describe("parse_copilot_log.cjs", () => { expect(result.mcpFailures).toBeDefined(); expect(result.mcpFailures).toHaveLength(1); expect(result.mcpFailures[0]).toBe("github"); + expect(mockCore.setFailed).toHaveBeenCalledWith("MCP server(s) failed to launch: github"); }); it("should detect multiple MCP server failures", () => { @@ -310,6 +311,7 @@ describe("parse_copilot_log.cjs", () => { expect(result.mcpFailures).toHaveLength(2); expect(result.mcpFailures).toContain("github"); expect(result.mcpFailures).toContain("playwright"); + expect(mockCore.setFailed).toHaveBeenCalledWith("MCP server(s) failed to launch: github, playwright"); }); it("should not report MCP failures for successful logs", () => { @@ -323,6 +325,7 @@ describe("parse_copilot_log.cjs", () => { const result = parseCopilotLog(successfulLog); expect(result.mcpFailures).toBeUndefined(); + expect(mockCore.setFailed).not.toHaveBeenCalled(); }); it("should handle JSON format without MCP failures", () => { @@ -334,6 +337,7 @@ describe("parse_copilot_log.cjs", () => { const result = parseCopilotLog(jsonLog); expect(result.mcpFailures).toBeUndefined(); + expect(mockCore.setFailed).not.toHaveBeenCalled(); }); it("should avoid duplicate MCP server names in failures list", () => { @@ -350,6 +354,7 @@ describe("parse_copilot_log.cjs", () => { expect(result.mcpFailures).toBeDefined(); expect(result.mcpFailures).toHaveLength(1); expect(result.mcpFailures[0]).toBe("github"); + expect(mockCore.setFailed).toHaveBeenCalledWith("MCP server(s) failed to launch: github"); }); }); });