fix: keep mcporter JSON stdout parseable
Move keep-alive daemon retry diagnostics to stderr so mcporter call --output json keeps stdout parseable after daemon recovery. Current main already covers the structuredContent and raw-envelope JSON fallbacks from the same issue; this PR adds explicit regression coverage for MCP isError envelopes and daemon retry logging.\n\nVerified locally with:\n- pnpm exec vitest run tests/cli-output-utils.test.ts tests/keep-alive-runtime.test.ts tests/result-utils.test.ts\n- pnpm check\n- PNPM_CONFIG_LOGLEVEL=error npm_config_loglevel=error pnpm test\n- pnpm build\n- git diff --check\n\nFixes #160.\n\nCo-authored-by: clawSean <260045960+clawSean@users.noreply.github.com>
This commit is contained in:
parent
39b49ef3bd
commit
e2c0641c1e
@ -4,6 +4,7 @@
|
||||
|
||||
### CLI
|
||||
|
||||
- Keep keep-alive daemon retry diagnostics on stderr so `mcporter call --output json` stdout stays parseable after a daemon recovery. (PR #163 / issue #160, thanks @clawSean)
|
||||
- Increase the default OAuth browser wait from 60 seconds to 5 minutes so hosted MCP sign-ins have enough time for account and permission review.
|
||||
- Skip the redundant daemon `status` preflight for warm keep-alive access, cutting one socket round-trip from each routed list/call/resource request while preserving stale-config and dead-daemon recovery.
|
||||
- Route explicit default keep-alive calls like `chrome-devtools.list_pages` through a daemon-only fast path, avoiding full runtime startup on warm calls.
|
||||
|
||||
@ -160,5 +160,5 @@ function shouldRestartDaemonServer(error: unknown): boolean {
|
||||
|
||||
function logDaemonRetry(server: string, operation: string, error: unknown): void {
|
||||
const reason = error instanceof Error ? error.message : String(error);
|
||||
console.log(`[mcporter] Restarting '${server}' before retrying ${operation}: ${reason}`);
|
||||
console.error(`[mcporter] Restarting '${server}' before retrying ${operation}: ${reason}`);
|
||||
}
|
||||
|
||||
@ -87,6 +87,17 @@ describe('printCallOutput format selection', () => {
|
||||
expect(JSON.parse(String(logged))).toEqual({ content: [{ type: 'text', text: 'no json here' }] });
|
||||
},
|
||||
],
|
||||
[
|
||||
'json emits valid JSON for MCP error envelopes instead of inspect output',
|
||||
'json',
|
||||
{ content: [{ type: 'text', text: 'MCP error -32602: Tool search not found' }], isError: true },
|
||||
(logged: unknown) => {
|
||||
expect(JSON.parse(String(logged))).toEqual({
|
||||
content: [{ type: 'text', text: 'MCP error -32602: Tool search not found' }],
|
||||
isError: true,
|
||||
});
|
||||
},
|
||||
],
|
||||
[
|
||||
'json emits null for undefined raw fallback',
|
||||
'json',
|
||||
|
||||
@ -139,12 +139,15 @@ describe('createKeepAliveRuntime', () => {
|
||||
keepAliveServers: new Set(['alpha']),
|
||||
});
|
||||
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
|
||||
const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
||||
|
||||
await expect(keepAliveRuntime.callTool('alpha', 'ping', {})).resolves.toBe('daemon-call');
|
||||
expect(daemon.callTool).toHaveBeenCalledTimes(2);
|
||||
expect(daemon.closeServer).toHaveBeenCalledWith({ server: 'alpha' });
|
||||
expect(logSpy).toHaveBeenCalledWith(expect.stringContaining("Restarting 'alpha'"));
|
||||
expect(logSpy).not.toHaveBeenCalled();
|
||||
expect(errorSpy).toHaveBeenCalledWith(expect.stringContaining("Restarting 'alpha'"));
|
||||
logSpy.mockRestore();
|
||||
errorSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('deduplicates concurrent restarts for the same server', async () => {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user