From 6177fe797601c3d6bb64467d59a2ba28e72791bc Mon Sep 17 00:00:00 2001 From: bhuvan-somisetty Date: Fri, 25 Sep 2026 17:26:06 +0530 Subject: [PATCH] fix(mcp-bridge): retain partial stdout and stderr across read timeouts When reading lines from the spawned MCP process via proc:stdout_read_line() and proc:stderr_read_line(), a read timeout sets the 3rd return value (partial data). On subsequent reads, the multiple assignment was overwriting the partial buffer with nil upon reading the remaining line, discarding the buffered data and sending truncated/corrupted payloads. Retain and accumulate partial stdout/stderr buffers across read timeouts, clearing them only after successfully joining with the completed line. Fixes #13987 Signed-off-by: bhuvan-somisetty --- apisix/plugins/mcp-bridge.lua | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/apisix/plugins/mcp-bridge.lua b/apisix/plugins/mcp-bridge.lua index a73d94393d6c..2a7c73cb71bb 100644 --- a/apisix/plugins/mcp-bridge.lua +++ b/apisix/plugins/mcp-bridge.lua @@ -86,19 +86,19 @@ local function on_connect(conf, ctx) -- if there is an incomplete message it is buffered and -- spliced before the next message repeat - local line, _ - line, _, stdout_partial = proc:stdout_read_line() + local line, _, partial = proc:stdout_read_line() if line then - local ok, err = server.transport:send( - stdout_partial and stdout_partial .. line or line - ) + local msg = stdout_partial and (stdout_partial .. line) or line + stdout_partial = nil + local ok, err = server.transport:send(msg) if not ok then core.log.info("session ", server.session_id, " exit, failed to send response message: ", err) need_exit = true break end - stdout_partial = nil -- luacheck: ignore + elseif partial and #partial > 0 then + stdout_partial = (stdout_partial or "") .. partial end until not line if need_exit then @@ -106,19 +106,21 @@ local function on_connect(conf, ctx) end repeat - local line, _ - line, _, stderr_partial = proc:stderr_read_line() + local line, _, partial = proc:stderr_read_line() if line then + local content = stderr_partial and (stderr_partial .. line) or line + stderr_partial = nil local ok, err = server.transport:send( '{"jsonrpc":"2.0","method":"notifications/stderr","params":{"content":"' - .. (stderr_partial and stderr_partial .. line or line) .. '"}}') + .. content .. '"}}') if not ok then core.log.info("session ", server.session_id, " exit, failed to send response message: ", err) need_exit = true break end - stderr_partial = "" -- luacheck: ignore + elseif partial and #partial > 0 then + stderr_partial = (stderr_partial or "") .. partial end until not line if need_exit then