Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions apisix/plugins/mcp-bridge.lua
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,13 @@ local function on_connect(conf, ctx)
local line, _
line, _, stderr_partial = proc:stderr_read_line()
if line then
local ok, err = server.transport:send(
'{"jsonrpc":"2.0","method":"notifications/stderr","params":{"content":"'
.. (stderr_partial and stderr_partial .. line or line) .. '"}}')
local ok, err = server.transport:send(core.json.encode({
jsonrpc = "2.0",
method = "notifications/stderr",
params = {
content = stderr_partial and stderr_partial .. line or line,
},
}))
if not ok then
core.log.info("session ", server.session_id,
" exit, failed to send response message: ", err)
Expand Down
37 changes: 37 additions & 0 deletions t/plugin/mcp-bridge.t
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,40 @@ property "command" is required
property "command" validation failed: wrong type: expected string, got number
done
property "args" validation failed: wrong type: expected array, got string



=== TEST 2: stderr content with JSON special characters keeps the notification well-formed
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local pipe = require("ngx.pipe")

-- a subprocess line that contains double quotes, a backslash and the
-- "}}" sequence, all of which break naive string concatenation
local payload = [[Error: invalid input "x\y" }}]]

local proc = assert(pipe.spawn({"sh", "-c", "printf '%s\\n' '" .. payload .. "' 1>&2"}))
proc:set_timeouts(nil, 1000, 1000)
local line = assert(proc:stderr_read_line())

-- build the notification the same way the plugin does
local msg = core.json.encode({
jsonrpc = "2.0",
method = "notifications/stderr",
params = {
content = line,
},
})

local decoded, err = core.json.decode(msg)
if not decoded then
ngx.say("not valid json: ", err)
return
end
ngx.say("valid json: ", decoded.params.content == payload)
}
}
--- response_body
valid json: true
Loading