@@ -223,7 +223,7 @@ export async function startHttpServer(
223223 await new Promise < void > ( ( resolve ) => nodeServer . listen ( opts . port , opts . host , ( ) => resolve ( ) ) ) ;
224224
225225 // Advertise discovery so providers can auto-detect this server locally
226- await advertiseDiscovery ( opts . host , opts . port , opts . logsRoute , { projectRoot : process . cwd ( ) , scope : 'http' } ) ;
226+ await advertiseDiscovery ( opts . host , opts . port , opts . logsRoute , { projectRoot : process . env . BROWSER_ECHO_PROJECT_ROOT || process . cwd ( ) , scope : 'http' } ) ;
227227
228228 // eslint-disable-next-line no-console
229229 console . log ( `MCP (Streamable HTTP) listening → http://${ opts . host } :${ opts . port } ${ opts . endpoint } ` ) ;
@@ -315,39 +315,60 @@ export async function startIngestOnlyServer(
315315 }
316316 }
317317
318- // Only the primary (5179) should advertise to OS tmp to avoid discovery flapping
318+ // Advertise discovery for stdio transport. By default, only write project-local discovery.
319319 const requestedPort = opts . port ;
320320 const isAggregator = requestedPort !== 0 && actualPort === requestedPort ;
321- await advertiseDiscovery ( opts . host , actualPort , opts . logsRoute , { projectRoot : process . cwd ( ) , scope : 'stdio' , aggregator : isAggregator } ) ;
321+ await advertiseDiscovery ( opts . host , actualPort , opts . logsRoute , { projectRoot : process . env . BROWSER_ECHO_PROJECT_ROOT || process . cwd ( ) , scope : 'stdio' , aggregator : isAggregator } ) ;
322322
323323 // eslint-disable-next-line no-console
324324 console . error ( `Log ingest endpoint → http://${ opts . host } :${ actualPort } ${ opts . logsRoute } ` ) ;
325325}
326326
327327async function advertiseDiscovery ( host : string , port : number , logsRoute : `/${string } `, meta ?: { projectRoot ?: string ; token ?: string ; scope ?: 'http' | 'stdio' ; aggregator ?: boolean } ) {
328328 try {
329- const { writeFileSync } = await import ( 'node:fs' ) ;
329+ const { writeFileSync, chmodSync } = await import ( 'node:fs' ) ;
330330 const { join } = await import ( 'node:path' ) ;
331331 const { tmpdir } = await import ( 'node:os' ) ;
332332
333333 const baseUrl = `http://${ host } :${ port } ` ;
334- const payload = JSON . stringify ( {
334+ const allowTmp = process . env . BROWSER_ECHO_ALLOW_TMP_DISCOVERY === '1' ;
335+ const token = allowTmp ? ( process . env . BROWSER_ECHO_DISCOVERY_TOKEN || randomUUID ( ) ) : undefined ;
336+ if ( allowTmp ) {
337+ try { process . env . BROWSER_ECHO_DISCOVERY_TOKEN = token as string ; } catch { }
338+ try { process . env . BROWSER_ECHO_REQUIRE_TOKEN = process . env . BROWSER_ECHO_REQUIRE_TOKEN || '1' ; } catch { }
339+ }
340+ const payloadLocal = JSON . stringify ( {
341+ url : baseUrl ,
342+ routeLogs : logsRoute ,
343+ timestamp : Date . now ( ) ,
344+ pid : typeof process !== 'undefined' ? process . pid : undefined ,
345+ projectRoot : meta ?. projectRoot || process . cwd ( )
346+ } ) ;
347+ const payloadTmp = JSON . stringify ( {
335348 url : baseUrl ,
336349 routeLogs : logsRoute ,
337350 timestamp : Date . now ( ) ,
338351 pid : typeof process !== 'undefined' ? process . pid : undefined ,
339352 projectRoot : meta ?. projectRoot || process . cwd ( ) ,
340- token : meta ?. token || undefined
353+ token
341354 } ) ;
342355
343- const files = meta ?. scope === 'http'
344- ? [ join ( tmpdir ( ) , 'browser-echo-mcp.json' ) ]
345- : meta ?. aggregator
346- ? [ join ( process . cwd ( ) , '.browser-echo-mcp.json' ) , join ( tmpdir ( ) , 'browser-echo-mcp.json' ) ]
347- : [ join ( process . cwd ( ) , '.browser-echo-mcp.json' ) ] ;
356+ let files : string [ ] = [ ] ;
357+ if ( meta ?. scope === 'http' ) {
358+ // HTTP transport: write project-local; mirror to tmp only when explicitly enabled
359+ files = [ join ( process . cwd ( ) , '.browser-echo-mcp.json' ) ] ;
360+ if ( allowTmp ) files . push ( join ( tmpdir ( ) , 'browser-echo-mcp.json' ) ) ;
361+ } else {
362+ // STDIO transport writes only to project-local by default; optionally mirror to tmp when explicitly enabled
363+ files = [ join ( process . cwd ( ) , '.browser-echo-mcp.json' ) ] ;
364+ if ( allowTmp ) files . push ( join ( tmpdir ( ) , 'browser-echo-mcp.json' ) ) ;
365+ }
348366
349367 for ( const f of files ) {
350- try { writeFileSync ( f , payload ) ; } catch { }
368+ const isTmp = f === join ( tmpdir ( ) , 'browser-echo-mcp.json' ) ;
369+ try { writeFileSync ( f , isTmp ? payloadTmp : payloadLocal ) ; } catch { }
370+ // Restrict permissions when writing token-bearing tmp file
371+ if ( isTmp ) { try { chmodSync ( f , 0o600 ) ; } catch { } }
351372 }
352373 } catch {
353374 // best-effort only
0 commit comments