Switches the system proxy off for a network service, leaving the configured server and port intact so it can be re-enabled from System Settings. Use when check_proxy_settings shows an enabled proxy pointing at an unreachable server — the classic 'I have internet but no websites load'.
/** * mcp/skills/disableProxy.ts — disable_proxy skill * * Switches the system proxy OFF for one network service, leaving the * configured server and port in place. The read-only counterpart is * `check_proxy_settings`, which reports what is currently set. * * Why disable rather than clear * ----------------------------- * Clearing the address (`networksetup -setwebproxy "" 0`) would lose a * setting the user may need again — a corporate proxy that is merely * unreachable right now is still the correct configuration for the office. * Flipping only the state is one toggle away from reversible in the OS UI, * which makes this the least-destructive fix for the common fault: a stale * proxy left behind by a VPN or a captive portal. * * Platform strategy * ----------------- * darwin `networksetup -setwebproxystate / -setsecurewebproxystate / * -setautoproxystate "<service>" off` — admin, routed through the * privileged helper daemon (op `disable_proxy`). * win32 HKCU Internet Settings `ProxyEnable=0` — per-user, but routed * through the same helper op for a uniform audit trail. * * Never touches WinHTTP (`netsh winhttp`): that is the system-service proxy, * is not what `check_proxy_settings` reads, and resetting it can break * Windows Update and other service traffic. * * Smoke test * npx tsx -r dotenv/config mcp/skills/disableProxy.ts */import * as os from "os";import { z } from "zod";import { execAsync } from "./_shared/platform";const EXEC_TIMEOUT_MS = 15_000;// -- Meta ---------------------------------------------------------------------export const meta = { name: "disable_proxy", description: "Switches the system proxy off for a network service, leaving the configured " + "server and port intact so it can be re-enabled from System Settings. " + "Use when check_proxy_settings shows an enabled proxy pointing at an " + "unreachable server — the classic 'I have internet but no websites load'.", // Medium, not high: this flips a reversible state flag and destroys no // configuration. reset_network_settings is high because it discards custom // locations, static IPs and manual DNS. riskLevel: "medium", destructive: false, requiresConsent: true, supportsDryRun: true, affectedScope: ["network", "system"], auditRequired: true, escalationHint: { darwin: "sudo networksetup -setwebproxystate \"<service>\" off # repeat for -setsecurewebproxystate / -setautoproxystate", win32: "Settings → Network & Internet → Proxy → turn off \"Use a proxy server\"", }, outputKeys: ["interface","disabled","dryRun","message","platform"], schema: { // snake_case-free: the helper's Params field is `interface`, and G4 // forwards executor params verbatim, so this name is the wire contract. interface: z .string() .describe( "Network service to disable the proxy on. macOS: the service name as " + "shown in System Settings → Network (e.g. \"Wi-Fi\", \"Ethernet\"). " + "Windows: accepted for parity but unused — the proxy is per-user.", ), protocols: z .array(z.enum(["web", "secureweb", "auto"])) .nullable().optional() .describe( "Which proxy kinds to switch off. Omit to disable all three.", ), dryRun: z .boolean() .nullable().optional() .describe("If true, report what would be disabled without changing anything. Default: true"), },} as const;// -- Types --------------------------------------------------------------------type Protocol = "web" | "secureweb" | "auto";const ALL_PROTOCOLS: Protocol[] = ["web", "secureweb", "auto"];interface DisableProxyResult { interface: string; disabled: Protocol[]; dryRun: boolean; message: string; platform: string;}// -- Exported run function ----------------------------------------------------/** * Local implementation. In production G4 routes the real call through the * privileged helper (`affectedScope` includes "system"); this body serves the * dry-run preview and the helper-unavailable path, where it fails cleanly * rather than half-applying. */export async function run({ interface: iface, protocols, dryRun = true,}: { interface: string; protocols?: Protocol[] | null; dryRun?: boolean | null;}): Promise<DisableProxyResult> { const platform = os.platform(); const targets = protocols && protocols.length > 0 ? protocols : ALL_PROTOCOLS; if (!iface || !iface.trim()) { throw new Error("[disable_proxy] 'interface' is required (network service name)."); } if (dryRun !== false) { return { interface: iface, disabled: targets, dryRun: true, message: platform === "win32" ? `Dry run: would set ProxyEnable=0 for the current user (${targets.join(", ")}). The proxy address is kept so it can be switched back on.` : `Dry run: would switch off ${targets.join(", ")} proxy on "${iface}". The server and port are kept so it can be switched back on.`, platform, }; } // Real execution normally happens in the helper. Reaching here means the // helper was unavailable and G4 fell back — attempt locally and let the // caller surface a permission failure rather than reporting a false success. const flags: Record<Protocol, string> = { web: "-setwebproxystate", secureweb: "-setsecurewebproxystate", auto: "-setautoproxystate", }; try { if (platform === "win32") { await execAsync( `reg add "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings" /v ProxyEnable /t REG_DWORD /d 0 /f`, { timeout: EXEC_TIMEOUT_MS }, ); } else { for (const p of targets) { await execAsync( `networksetup ${flags[p]} '${iface.replace(/'/g, "'\\''")}' off`, { timeout: EXEC_TIMEOUT_MS }, ); } } } catch (e) { return { interface: iface, disabled: [], dryRun: false, message: `Failed to disable the proxy on "${iface}": ${(e as Error).message}. This needs administrator rights — the privileged helper was not available.`, platform, }; } return { interface: iface, disabled: targets, dryRun: false, message: `Proxy switched off (${targets.join(", ")}) on "${iface}". The server and port are unchanged, so it can be re-enabled from System Settings.`, platform, };}// -- CLI smoke test -----------------------------------------------------------if (false) { run({ interface: "Wi-Fi" }) .then(r => console.log(JSON.stringify(r, null, 2))) .catch((err: Error) => { console.error(err.message); process.exit(1); });}