Skip to main content
Glama
networkCapture.jsβ€’9.04 kB
import { BrowserUtilities } from "../utilities/browser.js"; import { NetworkUtilities } from "../utilities/network.js"; /** * Network capture tool for monitoring HTTP requests and responses * Can capture all network traffic or filter by specific criteria */ /** * Start network capture session on a browser page * @param {string} sessionId - Session ID from initializeSession * @param {Object} options - Capture options * @param {boolean} options.capturePostOnly - Only capture POST requests (default: false) * @param {boolean} options.captureStreaming - Only capture streaming responses (default: false) * @param {Array<string>} options.urlFilters - Array of URL patterns to filter (default: []) * @param {number} options.maxCaptures - Maximum number of captures to store (default: 100) * @returns {Promise<Object>} Capture session info */ export async function startNetworkCapture(sessionId, options = {}) { const session = global.activeSessions?.get(sessionId); if (!session) { throw new Error( `Session ${sessionId} not found. Call initializeSession first.` ); } const { capturePostOnly = false, captureStreaming = false, urlFilters = [], maxCaptures = 100, } = options; // Initialize capture storage const captureData = { sessionId, startTime: Date.now(), requests: [], responses: [], wsFrames: [], streamingResponses: [], options: { capturePostOnly, captureStreaming, urlFilters, maxCaptures }, }; // Store capture data in session session.networkCapture = captureData; // Set up CDP session for network monitoring const client = await session.context.newCDPSession(session.page); await client.send("Network.enable"); await client.send("Fetch.enable", { patterns: [{ requestStage: "Response" }], }); // Store client reference for cleanup captureData.cdpClient = client; // Network request capture client.on("Network.requestWillBeSent", (params) => { try { const { requestId, request, timestamp } = params; // Apply filters if (capturePostOnly && request.method !== "POST") return; if ( urlFilters.length > 0 && !urlFilters.some((pattern) => request.url.includes(pattern)) ) return; const requestData = { requestId, url: request.url, method: request.method, timestamp, headers: request.headers, postData: request.postData || null, }; captureData.requests.push(requestData); // Limit storage if (captureData.requests.length > maxCaptures) { captureData.requests.shift(); } } catch (e) { // Ignore capture errors } }); // Network response capture client.on("Network.responseReceived", async (params) => { try { const { requestId, response } = params; const matchingRequest = captureData.requests.find( (r) => r.requestId === requestId ); if (!matchingRequest) return; // Apply streaming filter if enabled if (captureStreaming) { const isStreaming = NetworkUtilities.isStreamingHeaders(response.headers) || response.mimeType?.includes("stream") || response.headers["transfer-encoding"] === "chunked"; if (!isStreaming) return; } const responseData = { requestId, url: response.url, status: response.status, statusText: response.statusText, headers: response.headers, mimeType: response.mimeType, timestamp: Date.now(), }; // Try to capture response body for small responses if ( response.headers["content-length"] && parseInt(response.headers["content-length"]) < 10000 ) { try { const body = await client.send("Network.getResponseBody", { requestId, }); responseData.body = body.body; responseData.base64Encoded = body.base64Encoded; } catch (e) { // Body capture failed, continue without it } } captureData.responses.push(responseData); // Limit storage if (captureData.responses.length > maxCaptures) { captureData.responses.shift(); } } catch (e) { // Ignore capture errors } }); // WebSocket frame capture client.on("Network.webSocketFrameReceived", (params) => { try { const frameData = { timestamp: Date.now(), type: "received", opcode: params.response.opcode, payload: params.response.payloadData, }; captureData.wsFrames.push(frameData); if (captureData.wsFrames.length > maxCaptures) { captureData.wsFrames.shift(); } } catch (e) { // Ignore capture errors } }); client.on("Network.webSocketFrameSent", (params) => { try { const frameData = { timestamp: Date.now(), type: "sent", opcode: params.response.opcode, payload: params.response.payloadData, }; captureData.wsFrames.push(frameData); if (captureData.wsFrames.length > maxCaptures) { captureData.wsFrames.shift(); } } catch (e) { // Ignore capture errors } }); return { sessionId, captureId: `capture_${Date.now()}`, status: "active", options: captureData.options, message: "Network capture started successfully", }; } /** * Stop network capture and return captured data * @param {string} sessionId - Session ID from initializeSession * @returns {Promise<Object>} Captured network data */ export async function stopNetworkCapture(sessionId) { const session = global.activeSessions?.get(sessionId); if (!session) { throw new Error(`Session ${sessionId} not found.`); } const captureData = session.networkCapture; if (!captureData) { throw new Error( `No active network capture for session ${sessionId}. Call startNetworkCapture first.` ); } // Clean up CDP session if (captureData.cdpClient) { try { await captureData.cdpClient.send("Network.disable"); await captureData.cdpClient.send("Fetch.disable"); await captureData.cdpClient.detach(); } catch (e) { // Ignore cleanup errors } } // Calculate capture duration const endTime = Date.now(); const duration = endTime - captureData.startTime; // Prepare result const result = { sessionId, captureId: `capture_${captureData.startTime}`, duration, startTime: new Date(captureData.startTime).toISOString(), endTime: new Date(endTime).toISOString(), summary: { totalRequests: captureData.requests.length, totalResponses: captureData.responses.length, totalWsFrames: captureData.wsFrames.length, streamingResponses: captureData.streamingResponses.length, }, options: captureData.options, data: { requests: captureData.requests, responses: captureData.responses, wsFrames: captureData.wsFrames, streamingResponses: captureData.streamingResponses, }, }; // Clean up session data delete session.networkCapture; return result; } /** * Get current network capture status * @param {string} sessionId - Session ID from initializeSession * @returns {Promise<Object>} Current capture status */ export async function getNetworkCaptureStatus(sessionId) { const session = global.activeSessions?.get(sessionId); if (!session) { throw new Error(`Session ${sessionId} not found.`); } const captureData = session.networkCapture; if (!captureData) { return { sessionId, status: "inactive", message: "No active network capture session", }; } const duration = Date.now() - captureData.startTime; return { sessionId, status: "active", startTime: new Date(captureData.startTime).toISOString(), duration, currentStats: { requests: captureData.requests.length, responses: captureData.responses.length, wsFrames: captureData.wsFrames.length, streamingResponses: captureData.streamingResponses.length, }, options: captureData.options, }; } /** * Clear captured network data without stopping capture * @param {string} sessionId - Session ID from initializeSession * @returns {Promise<Object>} Status of clear operation */ export async function clearNetworkCapture(sessionId) { const session = global.activeSessions?.get(sessionId); if (!session) { throw new Error(`Session ${sessionId} not found.`); } const captureData = session.networkCapture; if (!captureData) { throw new Error(`No active network capture for session ${sessionId}.`); } // Clear all data arrays but keep capture running captureData.requests = []; captureData.responses = []; captureData.wsFrames = []; captureData.streamingResponses = []; return { sessionId, status: "cleared", message: "Network capture data cleared, capture continues", options: captureData.options, }; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/pyscout/webscout-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server