list_network_requests
Retrieve captured network requests with filters by URL, domain, method, status, or resource type for debugging and reverse engineering.
Instructions
List captured network requests with optional filters.
Args: url_filter: Substring filter for request URLs. url_contains_domain: Convenience domain filter (e.g. 'nmpa.gov.cn'). method: HTTP method filter (e.g. "GET", "POST"). resource_type: Resource type filter (e.g. "xhr", "fetch", "script", "document"). status_code: HTTP status code filter.
Returns: List of request summaries with id, url, method, status, type, ms, size.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| url_filter | No | ||
| url_contains_domain | No | ||
| method | No | ||
| resource_type | No | ||
| status_code | No |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| result | Yes |
Implementation Reference
- The main handler function for the 'list_network_requests' MCP tool. Decorated with @mcp.tool(), retrieves captured network requests from browser_manager._network_requests, applies optional filters (url_filter, url_contains_domain, method, resource_type, status_code), and returns summarized results with id, url, method, status, type, ms, size, and has_body.
@mcp.tool() async def list_network_requests( url_filter: str | None = None, url_contains_domain: str | None = None, method: str | None = None, resource_type: str | None = None, status_code: int | None = None, ) -> list[dict]: """List captured network requests with optional filters. Args: url_filter: Substring filter for request URLs. url_contains_domain: Convenience domain filter (e.g. 'nmpa.gov.cn'). method: HTTP method filter (e.g. "GET", "POST"). resource_type: Resource type filter (e.g. "xhr", "fetch", "script", "document"). status_code: HTTP status code filter. Returns: List of request summaries with id, url, method, status, type, ms, size. """ try: reqs = list(browser_manager._network_requests) if url_filter: reqs = [r for r in reqs if url_filter in r["url"]] if url_contains_domain: reqs = [r for r in reqs if url_contains_domain in r.get("url", "")] if method: reqs = [r for r in reqs if r["method"].upper() == method.upper()] if resource_type: reqs = [r for r in reqs if r.get("resource_type") == resource_type] if status_code is not None: reqs = [r for r in reqs if r.get("status") == status_code] summaries = [] for r in reqs: body_size = len(r["response_body"]) if r.get("response_body") else 0 summaries.append({ "id": r["id"], "url": r["url"][:200], "method": r["method"], "status": r.get("status"), "type": r.get("resource_type"), "ms": r.get("duration"), "size": body_size, "has_body": body_size > 0, }) return summaries except Exception as e: return [{"error": str(e)}] - src/camoufox_reverse_mcp/server.py:19-19 (registration)Registration of the network tools module (including list_network_requests) is done by importing the tools.network module in server.py, which triggers the @mcp.tool() decorator at module load time.
from .tools import network # noqa: E402, F401 — network_capture + list/get requests - The BrowserManager class stores captured network requests in _network_requests deque and tracks capture state via _capturing, _capture_pattern, _capture_body and _request_id_counter. These are the data structures that list_network_requests reads from.
def __init__(self) -> None: self.browser = None self.contexts: dict[str, BrowserContext] = {} self.pages: dict[str, Page] = {} self.active_page_name: str | None = None self._cm = None # AsyncCamoufox context manager self._console_logs: deque[dict] = deque(maxlen=MAX_LOG_SIZE) self._network_requests: deque[dict] = deque(maxlen=MAX_LOG_SIZE) self._request_id_counter = 0 self._capturing = False self._capture_pattern: str = "**/*" - The _on_request listener captures request data into _network_requests when capturing is active, populating the entries that list_network_requests later reads.
def _on_request(self, req) -> None: if not self._capturing: return import fnmatch if not fnmatch.fnmatch(req.url, self._capture_pattern): return self._request_id_counter += 1 entry = { "id": self._request_id_counter, "url": req.url, "method": req.method, "resource_type": req.resource_type, "request_headers": dict(req.headers), "request_post_data": req.post_data, "timestamp": int(time.time() * 1000), "status": None, "response_headers": None, "response_body": None, "duration": None, } self._network_requests.append(entry) - The _on_response_async listener updates entries in _network_requests with status, response_headers, duration, and optionally response_body, enriching the data returned by list_network_requests.
def _on_response_async(self, resp) -> None: """Handle response events, optionally capturing body asynchronously.""" if not self._capturing: return for entry in reversed(self._network_requests): if entry["url"] == resp.url and entry["status"] is None: entry["status"] = resp.status entry["response_headers"] = dict(resp.headers) entry["duration"] = int(time.time() * 1000) - entry["timestamp"] if self._capture_body: asyncio.ensure_future(self._fetch_response_body(resp, entry)) break