Skip to content

Commit 35ece85

Browse files
committed
refactor: streamline MCP log ingestion logic and enhance health probing
- Removed project-local discovery file handling to simplify MCP log ingestion logic. - Introduced a new asynchronous function to probe MCP availability, improving detection of valid endpoints. - Updated health probe mechanism to allow safe auto-detection of MCP during development. - Enhanced terminal output suppression logic based on explicit configuration and MCP availability.
1 parent 1841f49 commit 35ece85

1 file changed

Lines changed: 49 additions & 22 deletions

File tree

packages/vite/src/index.ts

Lines changed: 49 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Avoid exporting Vite types to prevent cross-version type mismatches in consumers
22
import ansis from 'ansis';
33
import type { BrowserLogLevel, NetworkCaptureOptions } from '@browser-echo/core';
4-
import { mkdirSync, appendFileSync, existsSync, readFileSync } from 'node:fs';
4+
import { mkdirSync, appendFileSync } from 'node:fs';
55
import { join as joinPath, dirname } from 'node:path';
66

77
export interface BrowserLogsToTerminalOptions {
@@ -123,25 +123,7 @@ function attachMiddleware(server: any, options: ResolvedOptions) {
123123
return;
124124
}
125125

126-
// 2) Project-local discovery file in CWD (do not default to port 5179)
127-
try {
128-
const discPath = joinPath(process.cwd(), '.browser-echo-mcp.json');
129-
if (existsSync(discPath)) {
130-
try {
131-
const txt = readFileSync(discPath, 'utf-8');
132-
const obj = JSON.parse(txt || '{}') as { url?: string; route?: string };
133-
if (obj && obj.url) {
134-
const base = String(obj.url).trim().replace(/\/$/, '').replace(/\/mcp$/i, '');
135-
const route = (obj as any).route || options.mcp.routeLogs || '/__client-logs';
136-
resolvedBase = base;
137-
resolvedIngest = `${base}${route as `/${string}`}`;
138-
return;
139-
}
140-
} catch {}
141-
}
142-
} catch {}
143-
144-
// 3) No configured or discovered MCP → keep base empty; do not probe, always print locally
126+
// No configured MCP → keep base empty; do not suppress; optional safe auto-detect happens in probe loop
145127
resolvedBase = '';
146128
resolvedIngest = '';
147129
}
@@ -167,12 +149,55 @@ function attachMiddleware(server: any, options: ResolvedOptions) {
167149
}
168150
}
169151

152+
async function probeIsMcp(base: string): Promise<boolean> {
153+
try {
154+
// Expect GET to return 405 Method Not Allowed for MCP endpoint
155+
const ctrl = new AbortController();
156+
const t = setTimeout(() => ctrl.abort(), 400);
157+
const res = await fetch(`${base}/mcp`, { method: 'GET', signal: ctrl.signal as any, cache: 'no-store' as any });
158+
clearTimeout(t);
159+
if (res && res.status === 405) return true;
160+
// Fallback OPTIONS 200/204
161+
const ctrl2 = new AbortController();
162+
const t2 = setTimeout(() => ctrl2.abort(), 400);
163+
const res2 = await fetch(`${base}/mcp`, { method: 'OPTIONS', signal: ctrl2.signal as any, cache: 'no-store' as any });
164+
clearTimeout(t2);
165+
return !!res2 && (res2.status === 200 || res2.status === 204);
166+
} catch {
167+
return false;
168+
}
169+
}
170+
170171
function startHealthProbe() {
171172
// Only starts once per dev server process
172173
let started = false;
173174
if (started) return;
174175
started = true;
175176
const interval = setInterval(async () => {
177+
// If no explicit config and nothing resolved yet, try safe auto-detect in dev (skip during tests)
178+
const hasExplicitConfig = !!(options.mcp.url || process.env.BROWSER_ECHO_MCP_URL);
179+
if (!hasExplicitConfig && !resolvedBase && process.env.NODE_ENV !== 'test') {
180+
const candidate = 'http://127.0.0.1:5179';
181+
// First check health
182+
let healthy = false;
183+
try {
184+
const ctrl = new AbortController();
185+
const t = setTimeout(() => ctrl.abort(), 400);
186+
const res = await fetch(`${candidate}/health`, { signal: ctrl.signal as any, cache: 'no-store' as any });
187+
clearTimeout(t);
188+
healthy = !!res && res.ok;
189+
} catch {}
190+
if (healthy) {
191+
const isMcp = await probeIsMcp(candidate);
192+
if (isMcp) {
193+
resolvedBase = candidate;
194+
resolvedIngest = `${candidate}${options.mcp.routeLogs}`;
195+
isRemoteAvailable = true; // but we will not suppress unless explicit config is present
196+
announce(`${options.tag} forwarding logs to MCP ingest at ${resolvedIngest}`);
197+
}
198+
}
199+
}
200+
176201
if (!resolvedBase) return; // nothing to probe without a known/current MCP
177202
const ok = await probeHealth();
178203
if (ok && !isRemoteAvailable) {
@@ -233,8 +258,10 @@ function attachMiddleware(server: any, options: ResolvedOptions) {
233258
} catch {}
234259

235260
const logger = server.config.logger;
236-
// Suppress when user requests it AND a current MCP endpoint is configured AND is considered available
237-
const shouldPrint = !options.mcp.suppressTerminal || !resolvedBase || !isRemoteAvailable;
261+
const hasExplicitConfig = !!(options.mcp.url || process.env.BROWSER_ECHO_MCP_URL);
262+
// Suppress only when explicitly configured AND MCP considered available
263+
const shouldSuppress = hasExplicitConfig && options.mcp.suppressTerminal && isRemoteAvailable;
264+
const shouldPrint = !shouldSuppress;
238265
const sid = (payload.sessionId ?? 'anon').slice(0, 8);
239266
for (const entry of payload.entries) {
240267
const level = normalizeLevel(entry.level);

0 commit comments

Comments
 (0)