Log why a tool call failed in the stdio server's log

A failed call's reason went only to the client, so client logs showed a
failure without its cause.
This commit is contained in:
Sameh Khamis committed 2026-10-02 18:29:42 -07:00
1 parent e82ab7440d
commit ae00f009e6
2 files changed
+32 -1

No files matched your search

+5 -1
View File
@@ -54,7 +54,11 @@ async function respond(server, line, log) {
}
const described = describeRequest(message);
if (described) log(described);
return server.handle(message);
const response = await server.handle(message);
// A failed tool call answers the client, not the log; say why here too.
if (response?.result?.isError)
log(` ${described} failed: ${response.result.content?.[0]?.text}`);
return response;
}
/** Read `--api-base <url>` from command-line arguments. */
+27
View File
@@ -104,3 +104,30 @@ test('the stdio log names methods, tools and resources but never arguments', asy
);
assert.equal(describeRequest({ result: {} }), null);
});
test('a failed tool call is logged with its reason', async () => {
const server = {
handle: async (message) => ({
jsonrpc: '2.0',
id: message.id,
result: { isError: true, content: [{ type: 'text', text: 'bad area' }] },
}),
};
const input = new PassThrough();
const output = new PassThrough();
output.resume();
const logged = [];
const served = serveStdio(server, {
input,
output,
log: (line) => logged.push(line),
});
input.end(
'{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"show_in_gods_eye_view"}}\n',
);
await served;
assert.deepEqual(logged, [
'tools/call show_in_gods_eye_view',
' tools/call show_in_gods_eye_view failed: bad area',
]);
});