Code

/**
 * mcp/skills/checkProxySettings.ts — check_proxy_settings skill
 *
 * Reports current system proxy configuration for all active network interfaces.
 * Misconfigured proxies are a common cause of internet failures while internal
 * resources remain accessible.
 *
 * Platform strategy
 * -----------------
 * darwin  `networksetup` commands per active network service for HTTP, HTTPS,
 *         PAC URL, and bypass domains
 * win32   PowerShell reads proxy settings from HKCU Internet Settings registry
 *
 * Smoke test
 *   npx tsx -r dotenv/config mcp/skills/checkProxySettings.ts
 */
 
import * as os       from "os";
import { exec }      from "child_process";
import { promisify } from "util";
import { z }         from "zod";
 
const execAsync = promisify(exec);
 
// -- Meta ---------------------------------------------------------------------
 
export const meta = {
  name: "check_proxy_settings",
  description:
    "Reports current system proxy configuration for all active network interfaces. " +
    "Misconfigured proxies are a common cause of internet failures while internal " +
    "resources remain accessible.",
  riskLevel:       "low",
  destructive:     false,
  requiresConsent: false,
  supportsDryRun:  false,
  affectedScope:   ["user"],
  auditRequired:   false,
  schema: {},
} as const;
 
// -- Types --------------------------------------------------------------------
 
interface ProxyEntry {
  enabled: boolean;
  server:  string;
  port:    number;
}
 
interface ProxyRow {
  type:    string;
  enabled: boolean;
  server:  string;
  port:    number;
}
 
interface CheckProxySettingsResult {
  proxies:    ProxyRow[];
  pacUrl:     string | null;
  bypassList: string[];
  anyEnabled: boolean;
  platform:   string;
}
 
// -- PowerShell helper --------------------------------------------------------
 
async function runPS(script: string): Promise<string> {
  const encoded = Buffer.from(script, "utf16le").toString("base64");
  const { stdout } = await execAsync(
    `powershell.exe -NoProfile -NonInteractive -EncodedCommand ${encoded}`,
    { maxBuffer: 10 * 1024 * 1024 },
  );
  return stdout.trim();
}
 
// -- Helpers ------------------------------------------------------------------
 
function parseNetworksetupProxy(output: string): ProxyEntry | null {
  const enabledMatch = output.match(/Enabled:\s*(\w+)/i);
  const serverMatch  = output.match(/Server:\s*(.+)/i);
  const portMatch    = output.match(/Port:\s*(\d+)/i);
 
  if (!enabledMatch) return null;
 
  const enabled = enabledMatch[1].toLowerCase() === "yes";
  const server  = serverMatch?.[1]?.trim() ?? "";
  const port    = parseInt(portMatch?.[1] ?? "0", 10);
 
  // Only return non-null if we have a server configured (enabled or not)
  if (!server) return null;
  return { enabled, server, port };
}
 
// -- darwin implementation ----------------------------------------------------
 
async function checkProxySettingsDarwin(): Promise<CheckProxySettingsResult> {
  // Find first active network service
  let activeService = "Wi-Fi";
  try {
    const { stdout } = await execAsync("networksetup -listallnetworkservices");
    const services = stdout.split("\n").filter((l) => l.trim() && !l.includes("*"));
    // Skip the header line "An asterisk (*) denotes..."
    const real = services.filter((s) => !s.includes("asterisk") && !s.includes("denotes"));
    if (real.length > 0) activeService = real[0].trim();
  } catch { /* fallback to Wi-Fi */ }
 
  const safeService = activeService.replace(/'/g, "'\\''");
 
  // HTTP proxy
  let httpProxy: ProxyEntry | null = null;
  try {
    const { stdout } = await execAsync(`networksetup -getwebproxy '${safeService}'`);
    httpProxy = parseNetworksetupProxy(stdout);
  } catch { /* ignore */ }
 
  // HTTPS proxy
  let httpsProxy: ProxyEntry | null = null;
  try {
    const { stdout } = await execAsync(`networksetup -getsecurewebproxy '${safeService}'`);
    httpsProxy = parseNetworksetupProxy(stdout);
  } catch { /* ignore */ }
 
  // PAC URL
  let pacUrl: string | null = null;
  try {
    const { stdout } = await execAsync(`networksetup -getautoproxyurl '${safeService}'`);
    const urlMatch = stdout.match(/URL:\s*(.+)/i);
    const urlVal   = urlMatch?.[1]?.trim() ?? "";
    const enabledMatch = stdout.match(/Enabled:\s*(\w+)/i);
    if (urlVal && urlVal !== "(null)" && enabledMatch?.[1]?.toLowerCase() === "yes") {
      pacUrl = urlVal;
    }
  } catch { /* ignore */ }
 
  // Bypass domains
  let bypassList: string[] = [];
  try {
    const { stdout } = await execAsync(`networksetup -getproxybypassdomains '${safeService}'`);
    bypassList = stdout.trim().split("\n").filter((l) => l.trim() && !l.includes("There aren't"));
  } catch { /* ignore */ }
 
  const proxies: ProxyRow[] = [
    ...(httpProxy  ? [{ type: "HTTP",  ...httpProxy  }] : []),
    ...(httpsProxy ? [{ type: "HTTPS", ...httpsProxy }] : []),
  ];
 
  const anyEnabled = proxies.some((p) => p.enabled) || pacUrl !== null;
 
  return {
    proxies,
    pacUrl,
    bypassList,
    anyEnabled,
    platform: "darwin",
  };
}
 
// -- win32 implementation -----------------------------------------------------
 
async function checkProxySettingsWin32(): Promise<CheckProxySettingsResult> {
  const ps = `
$ErrorActionPreference = 'SilentlyContinue'
Get-ItemProperty 'HKCU:\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings' |
  Select-Object ProxyEnable,ProxyServer,ProxyOverride,AutoConfigURL |
  ConvertTo-Json -Compress`.trim();
 
  let rawData: any = {};
  try {
    const raw = await runPS(ps);
    if (raw) rawData = JSON.parse(raw);
  } catch { /* fallback to empty */ }
 
  const proxyEnable = Number(rawData.ProxyEnable ?? 0) === 1;
  const proxyServer = String(rawData.ProxyServer ?? "");
  const pacUrl      = rawData.AutoConfigURL ? String(rawData.AutoConfigURL) : null;
  const override    = rawData.ProxyOverride  ? String(rawData.ProxyOverride) : "";
 
  // ProxyServer may be "host:port" or "http=host:port;https=host:port"
  let httpProxy:  ProxyEntry | null = null;
  let httpsProxy: ProxyEntry | null = null;
 
  if (proxyServer) {
    if (proxyServer.includes("=")) {
      // Per-protocol format
      const parts = proxyServer.split(";");
      for (const part of parts) {
        const [proto, addr] = part.split("=");
        const [srv, portStr] = (addr ?? "").split(":");
        const entry: ProxyEntry = { enabled: proxyEnable, server: srv ?? "", port: parseInt(portStr ?? "80", 10) };
        if (proto?.toLowerCase().includes("http") && !proto.toLowerCase().includes("https")) httpProxy = entry;
        if (proto?.toLowerCase().includes("https")) httpsProxy = entry;
      }
    } else {
      // Single proxy for all protocols
      const [srv, portStr] = proxyServer.split(":");
      const entry: ProxyEntry = { enabled: proxyEnable, server: srv ?? proxyServer, port: parseInt(portStr ?? "80", 10) };
      httpProxy  = entry;
      httpsProxy = { ...entry };
    }
  }
 
  const bypassList = override
    ? override.split(";").map((s: string) => s.trim()).filter(Boolean)
    : [];
 
  const proxies: ProxyRow[] = [
    ...(httpProxy  ? [{ type: "HTTP",  ...httpProxy  }] : []),
    ...(httpsProxy ? [{ type: "HTTPS", ...httpsProxy }] : []),
  ];
 
  const anyEnabled = proxyEnable || pacUrl !== null;
 
  return {
    proxies,
    pacUrl,
    bypassList,
    anyEnabled,
    platform: "win32",
  };
}
 
// -- Exported run function ----------------------------------------------------
 
export async function run(_args: Record<string, never> = {}) {
  const platform = os.platform();
  return platform === "win32"
    ? checkProxySettingsWin32()
    : checkProxySettingsDarwin();
}
 
// -- Smoke test ---------------------------------------------------------------
 
if (false) {
  run({})
    .then(r => console.log(JSON.stringify(r, null, 2)))
    .catch((err: Error) => { console.error(err.message); process.exit(1); });
}