From 2c17941247938ab331e86ddfa5f34fbc7d374cbc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 19 Apr 2026 18:07:56 +0000 Subject: [PATCH 1/4] Initial plan From 4275388327c292bd77574d8ee0fbc94b8755418c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 19 Apr 2026 18:29:22 +0000 Subject: [PATCH 2/4] fix: parse SSE tools/list responses for MCP CLI tool cache Agent-Logs-Url: https://github.com/github/gh-aw/sessions/0e75c57f-0945-4f73-9eb4-4b3ac62f9a35 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/mount_mcp_as_cli.cjs | 51 +++++++++++++++++++++- actions/setup/js/mount_mcp_as_cli.test.cjs | 39 +++++++++++++++++ 2 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 actions/setup/js/mount_mcp_as_cli.test.cjs diff --git a/actions/setup/js/mount_mcp_as_cli.cjs b/actions/setup/js/mount_mcp_as_cli.cjs index 33d5c626f6c..a481abca25c 100644 --- a/actions/setup/js/mount_mcp_as_cli.cjs +++ b/actions/setup/js/mount_mcp_as_cli.cjs @@ -146,6 +146,53 @@ function httpPostJSON(urlStr, headers, body, timeoutMs = DEFAULT_HTTP_TIMEOUT_MS }); } +/** + * Parse an MCP response body that may be JSON or Server-Sent Events (SSE). + * + * Some MCP gateway responses are streamed as SSE and contain lines like: + * data: {"jsonrpc":"2.0","id":3,"result":{...}} + * + * @param {unknown} body - Parsed response body from httpPostJSON + * @returns {unknown} + */ +function parseMCPResponseBody(body) { + if (body && typeof body === "object") { + return body; + } + if (typeof body !== "string") { + return null; + } + + const trimmed = body.trim(); + if (!trimmed) { + return null; + } + + try { + return JSON.parse(trimmed); + } catch { + // Fall through to SSE parsing. + } + + /** @type {unknown} */ + let lastDataMessage = null; + for (const line of trimmed.split(/\r?\n/)) { + if (!line.startsWith("data:")) { + continue; + } + const payload = line.slice(5).trim(); + if (!payload || payload === "[DONE]") { + continue; + } + try { + lastDataMessage = JSON.parse(payload); + } catch { + // Ignore non-JSON SSE data lines. + } + } + return lastDataMessage; +} + /** * Query the tools list from an MCP server via JSON-RPC. * Follows the standard MCP handshake: initialize → notifications/initialized → tools/list. @@ -196,7 +243,7 @@ async function fetchMCPTools(serverUrl, apiKey, core) { // Step 3: tools/list – get the available tool definitions try { const listResp = await httpPostJSON(serverUrl, { ...authHeaders, ...sessionHeader }, { jsonrpc: "2.0", id: 2, method: "tools/list" }, DEFAULT_HTTP_TIMEOUT_MS); - const respBody = listResp.body; + const respBody = parseMCPResponseBody(listResp.body); if (respBody && typeof respBody === "object" && "result" in respBody && respBody.result && typeof respBody.result === "object") { const result = respBody.result; if ("tools" in result && Array.isArray(result.tools)) { @@ -396,4 +443,4 @@ async function main() { core.setOutput("mounted-servers", mountedServers.join(",")); } -module.exports = { main, fetchMCPTools, generateCLIWrapperScript, isValidServerName, shellEscapeDoubleQuoted }; +module.exports = { main, fetchMCPTools, generateCLIWrapperScript, isValidServerName, shellEscapeDoubleQuoted, parseMCPResponseBody }; diff --git a/actions/setup/js/mount_mcp_as_cli.test.cjs b/actions/setup/js/mount_mcp_as_cli.test.cjs new file mode 100644 index 00000000000..91dc5463917 --- /dev/null +++ b/actions/setup/js/mount_mcp_as_cli.test.cjs @@ -0,0 +1,39 @@ +import { describe, expect, it } from "vitest"; + +import { parseMCPResponseBody } from "./mount_mcp_as_cli.cjs"; + +describe("mount_mcp_as_cli.cjs", () => { + it("parses JSON object responses unchanged", () => { + const body = { jsonrpc: "2.0", result: { tools: [{ name: "logs" }] } }; + expect(parseMCPResponseBody(body)).toEqual(body); + }); + + it("parses raw JSON string responses", () => { + const body = '{"jsonrpc":"2.0","result":{"tools":[{"name":"logs"}]}}'; + expect(parseMCPResponseBody(body)).toEqual({ + jsonrpc: "2.0", + result: { tools: [{ name: "logs" }] }, + }); + }); + + it("parses SSE data lines and returns the JSON payload", () => { + const body = ["event: message", 'data: {"jsonrpc":"2.0","id":2,"result":{"tools":[{"name":"logs","inputSchema":{"properties":{"count":{"type":"integer"}}}}]}}', ""].join("\n"); + + expect(parseMCPResponseBody(body)).toEqual({ + jsonrpc: "2.0", + id: 2, + result: { + tools: [ + { + name: "logs", + inputSchema: { + properties: { + count: { type: "integer" }, + }, + }, + }, + ], + }, + }); + }); +}); From f53cb4fafa7b24395c7b63d4c41626cfa19401bd Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 19 Apr 2026 18:33:42 +0000 Subject: [PATCH 3/4] test: harden MCP CLI tools-list SSE parsing coverage Agent-Logs-Url: https://github.com/github/gh-aw/sessions/0e75c57f-0945-4f73-9eb4-4b3ac62f9a35 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/mount_mcp_as_cli.cjs | 2 +- actions/setup/js/mount_mcp_as_cli.test.cjs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/actions/setup/js/mount_mcp_as_cli.cjs b/actions/setup/js/mount_mcp_as_cli.cjs index a481abca25c..494ca48dcef 100644 --- a/actions/setup/js/mount_mcp_as_cli.cjs +++ b/actions/setup/js/mount_mcp_as_cli.cjs @@ -156,7 +156,7 @@ function httpPostJSON(urlStr, headers, body, timeoutMs = DEFAULT_HTTP_TIMEOUT_MS * @returns {unknown} */ function parseMCPResponseBody(body) { - if (body && typeof body === "object") { + if (body && typeof body === "object" && !Array.isArray(body)) { return body; } if (typeof body !== "string") { diff --git a/actions/setup/js/mount_mcp_as_cli.test.cjs b/actions/setup/js/mount_mcp_as_cli.test.cjs index 91dc5463917..731c4ce06d4 100644 --- a/actions/setup/js/mount_mcp_as_cli.test.cjs +++ b/actions/setup/js/mount_mcp_as_cli.test.cjs @@ -17,7 +17,8 @@ describe("mount_mcp_as_cli.cjs", () => { }); it("parses SSE data lines and returns the JSON payload", () => { - const body = ["event: message", 'data: {"jsonrpc":"2.0","id":2,"result":{"tools":[{"name":"logs","inputSchema":{"properties":{"count":{"type":"integer"}}}}]}}', ""].join("\n"); + const sseToolListPayload = 'data: {"jsonrpc":"2.0","id":2,"result":{"tools":[{"name":"logs","inputSchema":{"properties":{"count":{"type":"integer"}}}}]}}'; + const body = ["event: message", sseToolListPayload, ""].join("\n"); expect(parseMCPResponseBody(body)).toEqual({ jsonrpc: "2.0", From b50fb0b0c287069a3584e4965205f295e832ea2d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 19 Apr 2026 18:59:09 +0000 Subject: [PATCH 4/4] test: add ts-check header to mount_mcp_as_cli tests Agent-Logs-Url: https://github.com/github/gh-aw/sessions/9de0fe6c-f17b-4286-9886-417b476eec70 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/mount_mcp_as_cli.test.cjs | 1 + 1 file changed, 1 insertion(+) diff --git a/actions/setup/js/mount_mcp_as_cli.test.cjs b/actions/setup/js/mount_mcp_as_cli.test.cjs index 731c4ce06d4..cd86c1f53be 100644 --- a/actions/setup/js/mount_mcp_as_cli.test.cjs +++ b/actions/setup/js/mount_mcp_as_cli.test.cjs @@ -1,3 +1,4 @@ +// @ts-check import { describe, expect, it } from "vitest"; import { parseMCPResponseBody } from "./mount_mcp_as_cli.cjs";