interceptor_spawn
Spawn a command with pre-configured proxy environment variables to route traffic through the MITM proxy for interception and modification.
Instructions
Spawn a command with proxy env vars pre-configured (HTTP_PROXY, HTTPS_PROXY, SSL_CERT_FILE, NODE_EXTRA_CA_CERTS, CURL_CA_BUNDLE, and 15+ more). Traffic automatically routes through the MITM proxy.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| command | Yes | Command to run (e.g., 'curl', 'node', 'python') | |
| args | No | Command arguments | |
| cwd | No | Working directory (default: current) | |
| env | No | Additional env vars to set |
Implementation Reference
- src/tools/interceptors.ts:296-325 (registration)MCP tool registration for 'interceptor_spawn' using server.tool() with Zod schema for command, args, cwd, env.
server.tool( "interceptor_spawn", "Spawn a command with proxy env vars pre-configured (HTTP_PROXY, HTTPS_PROXY, SSL_CERT_FILE, NODE_EXTRA_CA_CERTS, CURL_CA_BUNDLE, and 15+ more). Traffic automatically routes through the MITM proxy.", { command: z.string().describe("Command to run (e.g., 'curl', 'node', 'python')"), args: z.array(z.string()).optional().default([]).describe("Command arguments"), cwd: z.string().optional().describe("Working directory (default: current)"), env: z.record(z.string()).optional().describe("Additional env vars to set"), }, async ({ command, args, cwd, env }) => { try { const proxyInfo = requireProxy(); const result = await interceptorManager.activate("terminal", { ...proxyInfo, command, args, cwd, env, }); return { content: [{ type: "text", text: JSON.stringify({ status: "success", ...result }), }], }; } catch (e) { return { content: [{ type: "text", text: JSON.stringify({ status: "error", error: errorToString(e) }) }] }; } }, ); - src/tools/interceptors.ts:305-324 (handler)Handler function that calls requireProxy() to get proxy info and interceptorManager.activate('terminal') to spawn the command with proxy env vars.
async ({ command, args, cwd, env }) => { try { const proxyInfo = requireProxy(); const result = await interceptorManager.activate("terminal", { ...proxyInfo, command, args, cwd, env, }); return { content: [{ type: "text", text: JSON.stringify({ status: "success", ...result }), }], }; } catch (e) { return { content: [{ type: "text", text: JSON.stringify({ status: "error", error: errorToString(e) }) }] }; } }, - src/tools/interceptors.ts:299-303 (schema)Zod input schema: command (string, required), args (array of strings, optional), cwd (string, optional), env (record of strings, optional).
{ command: z.string().describe("Command to run (e.g., 'curl', 'node', 'python')"), args: z.array(z.string()).optional().default([]).describe("Command arguments"), cwd: z.string().optional().describe("Working directory (default: current)"), env: z.record(z.string()).optional().describe("Additional env vars to set"), - src/tools/interceptors.ts:37-50 (helper)requireProxy() helper: validates proxy is running and returns proxyPort, certPem, and certFingerprint used by interceptor_spawn handler.
function requireProxy(): { proxyPort: number; certPem: string; certFingerprint: string } { if (!proxyManager.isRunning()) { throw new Error("Proxy is not running. Start it first with proxy_start."); } const cert = proxyManager.getCert(); if (!cert) { throw new Error("No certificate available. Start the proxy first."); } return { proxyPort: proxyManager.getPort()!, certPem: cert.cert, certFingerprint: cert.fingerprint, }; } - src/interceptors/terminal.ts:34-152 (helper)TerminalInterceptor.activate(): core logic that spawns the child process with proxy env vars (HTTP_PROXY, HTTPS_PROXY, SSL_CERT_FILE, etc.) and returns targetId.
async activate(options: ActivateOptions): Promise<ActivateResult> { const { proxyPort, certPem, certFingerprint } = options; const command = options.command as string | undefined; const args = options.args as string[] | undefined; const cwd = options.cwd as string | undefined; const env = options.env as Record<string, string> | undefined; if (!command) { throw new Error("'command' option is required for terminal interceptor"); } // Write cert to temp file for SSL_CERT_FILE and friends const certPath = await writeCertTempFile(certPem); const proxyUrl = `http://127.0.0.1:${proxyPort}`; // Build env with proxy vars const proxyEnv: Record<string, string> = { ...process.env as Record<string, string>, ...env, // Standard proxy vars (both cases for compatibility) HTTP_PROXY: proxyUrl, HTTPS_PROXY: proxyUrl, http_proxy: proxyUrl, https_proxy: proxyUrl, // SSL certificate file (many tools check this) SSL_CERT_FILE: certPath, // Node.js NODE_EXTRA_CA_CERTS: certPath, NODE_TLS_REJECT_UNAUTHORIZED: "0", // Python requests REQUESTS_CA_BUNDLE: certPath, // curl CURL_CA_BUNDLE: certPath, // AWS SDK AWS_CA_BUNDLE: certPath, // Deno DENO_CERT: certPath, DENO_TLS_CA_STORE: "system", // Git GIT_SSL_CAINFO: certPath, GIT_SSL_NO_VERIFY: "true", // npm/yarn npm_config_proxy: proxyUrl, npm_config_https_proxy: proxyUrl, npm_config_cafile: certPath, npm_config_strict_ssl: "false", // Certificate fingerprint (for reference) PROXY_MCP_CERT_FINGERPRINT: certFingerprint, }; const child = spawn(command, args ?? [], { cwd, env: proxyEnv, stdio: ["ignore", "pipe", "pipe"], detached: false, }); const targetId = `proc_${child.pid ?? Date.now()}`; const entry: SpawnedProcess = { target: { id: targetId, description: `${command} ${(args ?? []).join(" ")}`.trim(), activatedAt: Date.now(), details: { pid: child.pid, command, args: args ?? [], cwd: cwd ?? process.cwd(), proxyUrl, certPath, }, }, process: child, stdout: "", stderr: "", exitCode: null, exited: false, }; // Capture stdout/stderr in ring buffers child.stdout?.on("data", (chunk: Buffer) => { entry.stdout += chunk.toString("utf-8"); if (entry.stdout.length > MAX_OUTPUT_BUFFER) { entry.stdout = entry.stdout.slice(-MAX_OUTPUT_BUFFER); } }); child.stderr?.on("data", (chunk: Buffer) => { entry.stderr += chunk.toString("utf-8"); if (entry.stderr.length > MAX_OUTPUT_BUFFER) { entry.stderr = entry.stderr.slice(-MAX_OUTPUT_BUFFER); } }); child.on("exit", (code) => { entry.exitCode = code; entry.exited = true; }); child.on("error", (err) => { entry.stderr += `\n[spawn error] ${err.message}`; entry.exited = true; }); this.spawned.set(targetId, entry); return { targetId, details: { pid: child.pid, command, args: args ?? [], proxyUrl, certPath, }, }; }