1- // Mcp Client Temp State script supports OpenClaw repository automation .
1+ // MCP client temp-state helpers used by QA-owned MCP E2E fixtures .
22import { mkdirSync , mkdtempSync , rmSync , writeFileSync } from "node:fs" ;
33import { tmpdir } from "node:os" ;
44import path from "node:path" ;
@@ -16,6 +16,12 @@ export type ReconnectableMcpClientHandle = {
1616 transport : { close : ( ) => Promise < unknown > } ;
1717} ;
1818
19+ type McpConnectTransport = {
20+ close ?( ) : Promise < void > | void ;
21+ } ;
22+
23+ const MCP_TIMEOUT_CLOSE_GRACE_MS = 5_000 ;
24+
1925export function createMcpClientTempState ( params : {
2026 gatewayToken : string ;
2127 tempRoot ?: string ;
@@ -35,6 +41,55 @@ export function createMcpClientTempState(params: {
3541 } ;
3642}
3743
44+ export async function connectMcpWithTimeout < TTransport extends McpConnectTransport > (
45+ client : { connect ( transport : TTransport ) : Promise < void > } ,
46+ transport : TTransport ,
47+ timeoutMs : number ,
48+ ) : Promise < void > {
49+ let timedOut = false ;
50+ let timeout : NodeJS . Timeout | undefined ;
51+ const timeoutPromise = new Promise < never > ( ( _ , reject ) => {
52+ timeout = setTimeout ( ( ) => {
53+ timedOut = true ;
54+ reject ( new Error ( `MCP stdio connect timed out after ${ timeoutMs } ms` ) ) ;
55+ } , timeoutMs ) ;
56+ timeout . unref ?.( ) ;
57+ } ) ;
58+
59+ try {
60+ await Promise . race ( [ client . connect ( transport ) , timeoutPromise ] ) ;
61+ } catch ( error ) {
62+ if ( timedOut ) {
63+ await closeTimedOutTransport ( transport ) ;
64+ }
65+ throw error ;
66+ } finally {
67+ if ( timeout ) {
68+ clearTimeout ( timeout ) ;
69+ }
70+ }
71+ }
72+
73+ async function closeTimedOutTransport ( transport : McpConnectTransport ) : Promise < void > {
74+ if ( ! transport . close ) {
75+ return ;
76+ }
77+ let timer : NodeJS . Timeout | undefined ;
78+ try {
79+ await Promise . race ( [
80+ Promise . resolve ( transport . close ( ) ) . catch ( ( ) => undefined ) ,
81+ new Promise < void > ( ( resolve ) => {
82+ timer = setTimeout ( resolve , MCP_TIMEOUT_CLOSE_GRACE_MS ) ;
83+ timer . unref ?.( ) ;
84+ } ) ,
85+ ] ) ;
86+ } finally {
87+ if ( timer ) {
88+ clearTimeout ( timer ) ;
89+ }
90+ }
91+ }
92+
3893export async function connectMcpClientWithPairingReconnect <
3994 T extends ReconnectableMcpClientHandle ,
4095> ( params : {
0 commit comments