dedup_load
Load a deduped_requests.txt file from Burp's Deduped HTTP History + JS Exporter extension, providing a named source of deduplicated requests for structured HTTP request creation.
Instructions
Load a deduped_requests.txt file produced by the user's Burp
Deduped HTTP History + JS Exporter extension.
path: filesystem path (absolute or ~-expandable).
name: identifier to address this source by in later calls. Default:
parent directory name.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | ||
| name | No |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| result | Yes |
Implementation Reference
- src/burp_mcp_plus/server.py:637-647 (handler)MCP tool handler for 'dedup_load' — registers a dedup file via dedup.register and returns JSON with name, path, and entry count.
@mcp.tool() def dedup_load(path: str, name: str | None = None) -> str: """Load a `deduped_requests.txt` file produced by the user's Burp `Deduped HTTP History + JS Exporter` extension. `path`: filesystem path (absolute or ~-expandable). `name`: identifier to address this source by in later calls. Default: parent directory name. """ src = dedup.register(path, name) return json.dumps({"name": src.name, "path": src.path, "entries": len(src.entries)}, indent=2) - src/burp_mcp_plus/server.py:637-637 (registration)The @mcp.tool() decorator registers dedup_load as an MCP tool on the FastMCP server instance.
@mcp.tool() - src/burp_mcp_plus/dedup.py:137-150 (helper)dedup.register: resolves the path, parses the file, stores the source in _REGISTRY, and returns the DedupSource.
def register(path: str, name: str | None = None) -> DedupSource: p = os.path.abspath(os.path.expanduser(path)) if not os.path.isfile(p): raise FileNotFoundError(p) if name is None: # Default name: parent dir basename, fall back to file stem. parent = os.path.basename(os.path.dirname(p)) or os.path.splitext( os.path.basename(p) )[0] name = parent entries = parse_dedup_file(p) src = DedupSource(name=name, path=p, entries=entries) _REGISTRY[name] = src return src - src/burp_mcp_plus/dedup.py:72-130 (helper)parse_dedup_file: parses the custom deduped_requests.txt format, extracting entries with metadata, request, and response.
def parse_dedup_file(path: str | Path) -> list[DedupEntry]: text = Path(path).read_text(errors="replace") # Split on the long === line that delimits each entry header. # The format puts === lines around the metadata header. Easiest robust # parse: split by "-- REQUEST --" and walk back/forward. parts = text.split("-- REQUEST --") entries: list[DedupEntry] = [] # parts[0] is the file preamble; parts[1..] each begin with the request # body, then "-- RESPONSE --", then response, then the next entry's # metadata header. # The metadata for entry i lives at the END of parts[i] (preceded by ===). for i in range(1, len(parts)): # Metadata for THIS entry sits at the end of the PREVIOUS chunk. prev = parts[i - 1] meta_match = _HEADER_RE.findall(prev) if not meta_match: continue idx_s, method, url = meta_match[-1] try: idx = int(idx_s) except ValueError: continue # Status/Length/Parameters from the trailing portion of prev. # Find the last header block in prev. last_eq = prev.rfind("======") meta_block = prev[max(0, prev.rfind("====", 0, last_eq) - 200):] status_m = _STATUS_RE.search(meta_block) length_m = _LENGTH_RE.search(meta_block) params_m = _PARAMS_RE.search(meta_block) status = int(status_m.group(1)) if status_m else None length = int(length_m.group(1)) if length_m else None parameters = params_m.group(1).strip() if params_m else "" # Body is parts[i] up to "-- RESPONSE --"; response is after. body = parts[i] if "-- RESPONSE --" in body: req_block, resp_block = body.split("-- RESPONSE --", 1) else: req_block, resp_block = body, "" # Trim the dashed separator line "-----..." from end of req_block. req_clean = re.sub(r"\n-{40,}\s*$", "", req_block.strip("\r\n"), count=1) # Trim the next entry's "===..." from start of resp_block. resp_clean = resp_block next_eq = resp_clean.find("\n========================================") if next_eq != -1: resp_clean = resp_clean[:next_eq] resp_clean = resp_clean.strip("\r\n") entries.append( DedupEntry( index=idx, method=method, url=url, status=status, length=length, parameters=parameters, request=req_clean, response=resp_clean, ) ) return entries - src/burp_mcp_plus/dedup.py:44-69 (schema)Data model classes DedupEntry and DedupSource defining the schema for parsed dedup file entries.
@dataclass class DedupEntry: index: int # 1-based as in the file method: str url: str status: int | None length: int | None parameters: str request: str response: str def host_path(self) -> tuple[str, str]: # url is full https://host[:port]/path m = re.match(r"https?://([^/]+)(/.*)?$", self.url) if not m: return "", self.url host = m.group(1) path = m.group(2) or "/" return host, path @dataclass class DedupSource: name: str path: str entries: list[DedupEntry]