@@ -153,12 +153,8 @@ export class McpSseClient {
153153 if ( headerTimedOut ) {
154154 throw new BailianError ( "MCP SSE timed out waiting for response headers." , ExitCode . TIMEOUT ) ;
155155 }
156- throw new BailianError (
157- `MCP SSE request failed: ${ error instanceof Error ? error . message : String ( error ) } ` ,
158- ExitCode . NETWORK ,
159- undefined ,
160- { cause : error } ,
161- ) ;
156+ // Rethrow fetch failures so runtime can surface errno (e.g. ENOTFOUND) in JSON/text.
157+ throw error ;
162158 }
163159
164160 if ( this . deps . settings . verbose ) {
@@ -352,34 +348,46 @@ export class McpSseClient {
352348 const requestSignal = createLinkedAbortSignal ( timeoutMs , this . abortController ?. signal ) ;
353349 let res : Response ;
354350 try {
355- res = await fetch ( this . messageUrl , {
356- method : "POST" ,
357- headers,
358- body : JSON . stringify ( body ) ,
359- signal : requestSignal . signal ,
360- } ) ;
361- } catch ( error ) {
362- if ( this . closed ) {
363- throw new BailianError ( "MCP SSE session closed." , ExitCode . GENERAL ) ;
351+ try {
352+ res = await fetch ( this . messageUrl , {
353+ method : "POST" ,
354+ headers,
355+ body : JSON . stringify ( body ) ,
356+ signal : requestSignal . signal ,
357+ } ) ;
358+ } catch ( error ) {
359+ if ( this . closed ) {
360+ throw new BailianError ( "MCP SSE session closed." , ExitCode . GENERAL ) ;
361+ }
362+ throw error ;
364363 }
365- throw error ;
366- } finally {
367- requestSignal . cleanup ( ) ;
368- }
369364
370- if ( this . deps . settings . verbose ) {
371- console . error ( `< ${ res . status } ${ res . statusText } ` ) ;
372- }
365+ if ( this . deps . settings . verbose ) {
366+ console . error ( `< ${ res . status } ${ res . statusText } ` ) ;
367+ }
373368
374- if ( ! res . ok ) {
375- let errMsg = `MCP request failed: ${ res . status } ${ res . statusText } ` ;
376- try {
377- const errBody = await res . text ( ) ;
378- if ( errBody ) errMsg += ` - ${ errBody . slice ( 0 , 500 ) } ` ;
379- } catch {
380- /* ignore */
369+ if ( ! res . ok ) {
370+ // Keep signal until error body is read (same class of bug as GET openSse).
371+ let errMsg = `MCP request failed: ${ res . status } ${ res . statusText } ` ;
372+ try {
373+ const errBody = await res . text ( ) ;
374+ if ( errBody ) errMsg += ` - ${ errBody . slice ( 0 , 500 ) } ` ;
375+ } catch ( error ) {
376+ if ( this . closed ) {
377+ throw new BailianError ( "MCP SSE session closed." , ExitCode . GENERAL ) ;
378+ }
379+ if ( requestSignal . timedOut ) {
380+ throw new BailianError (
381+ "MCP SSE timed out reading error response body." ,
382+ ExitCode . TIMEOUT ,
383+ ) ;
384+ }
385+ throw new BailianError ( errMsg , ExitCode . GENERAL , undefined , { cause : error } ) ;
386+ }
387+ throw new BailianError ( errMsg , ExitCode . GENERAL ) ;
381388 }
382- throw new BailianError ( errMsg , ExitCode . GENERAL ) ;
389+ } finally {
390+ requestSignal . cleanup ( ) ;
383391 }
384392 }
385393}
@@ -439,9 +447,13 @@ function cancellableTimeoutReject(
439447function createLinkedAbortSignal (
440448 timeoutMs : number ,
441449 parentSignal ?: AbortSignal ,
442- ) : { signal : AbortSignal ; cleanup : ( ) => void } {
450+ ) : { signal : AbortSignal ; cleanup : ( ) => void ; timedOut : boolean } {
443451 const controller = new AbortController ( ) ;
444- const timeout = setTimeout ( ( ) => controller . abort ( ) , timeoutMs ) ;
452+ const state = { timedOut : false } ;
453+ const timeout = setTimeout ( ( ) => {
454+ state . timedOut = true ;
455+ controller . abort ( ) ;
456+ } , timeoutMs ) ;
445457 const abortFromParent = ( ) => controller . abort ( parentSignal ?. reason ) ;
446458 const cleanup = ( ) => {
447459 clearTimeout ( timeout ) ;
@@ -452,5 +464,11 @@ function createLinkedAbortSignal(
452464 else parentSignal ?. addEventListener ( "abort" , abortFromParent , { once : true } ) ;
453465 controller . signal . addEventListener ( "abort" , cleanup , { once : true } ) ;
454466
455- return { signal : controller . signal , cleanup } ;
467+ return {
468+ signal : controller . signal ,
469+ cleanup,
470+ get timedOut ( ) {
471+ return state . timedOut ;
472+ } ,
473+ } ;
456474}
0 commit comments