/**
* mcp/skills/removePrinter.ts — remove_printer skill
*
* Removes a printer from the system. Use when a printer is stuck in
* permanent error state or needs to be re-added with fresh configuration.
*
* Platform strategy
* -----------------
* darwin `lpstat -p` to verify name exists; `lpadmin -x {name}` to remove
* win32 PowerShell Get-Printer to verify; Remove-Printer to remove
*
* Smoke test
* npx tsx -r dotenv/config mcp/skills/removePrinter.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: "remove_printer",
description:
"Removes a printer from the system. " +
"Use when a printer is stuck in permanent error state or needs to be " +
"re-added with fresh configuration.",
riskLevel: "high",
destructive: false,
requiresConsent: true,
supportsDryRun: true,
affectedScope: ["system"],
auditRequired: true,
escalationHint: {
darwin: "sudo lpadmin -x \"<printerName>\" # substitute the exact printer name from list_printers",
win32: "Remove-Printer -Name \"<printerName>\" # run from elevated PowerShell",
},
schema: {
printerName: z
.string()
.describe("Exact printer name to remove (get names from list_printers)"),
dryRun: z
.boolean()
.optional()
.describe("If true, verify printer exists without removing. Default: true"),
},
} as const;
// -- Types --------------------------------------------------------------------
interface RemovePrinterResult {
printerName: string;
found: boolean;
removed: boolean;
dryRun: boolean;
message: 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();
}
// -- darwin implementation ----------------------------------------------------
async function removePrinterDarwin(
printerName: string,
dryRun: boolean,
): Promise<RemovePrinterResult> {
// List printers to verify the name exists
let found = false;
try {
const { stdout } = await execAsync("lpstat -p");
const lines = stdout.split("\n").filter(Boolean);
found = lines.some((line) => {
// lpstat -p output: "printer NAME ..."
const parts = line.trim().split(/\s+/);
return parts[1] === printerName;
});
} catch {
found = false;
}
let removed = false;
if (!dryRun && found) {
try {
await execAsync(`lpadmin -x '${printerName.replace(/'/g, "'\\''")}'`);
removed = true;
} catch {
removed = false;
}
}
const message = dryRun
? found
? `Printer "${printerName}" found. Run with dryRun=false to remove it.`
: `Printer "${printerName}" not found. Use list_printers to see available printer names.`
: removed
? `Printer "${printerName}" has been removed from the system.`
: found
? `Failed to remove printer "${printerName}". You may need administrator privileges.`
: `Printer "${printerName}" not found — nothing to remove.`;
return { printerName, found, removed, dryRun, message };
}
// -- win32 implementation -----------------------------------------------------
async function removePrinterWin32(
printerName: string,
dryRun: boolean,
): Promise<RemovePrinterResult> {
// Verify printer exists
let found = false;
try {
const raw = await runPS(
`$ErrorActionPreference='SilentlyContinue'
$p = Get-Printer -Name '${printerName.replace(/'/g, "''")}' -ErrorAction SilentlyContinue
if ($p) { 'true' } else { 'false' }`,
);
found = raw.trim().toLowerCase() === "true";
} catch {
found = false;
}
let removed = false;
if (!dryRun && found) {
try {
await runPS(
`Remove-Printer -Name '${printerName.replace(/'/g, "''")}'`,
);
removed = true;
} catch {
removed = false;
}
}
const message = dryRun
? found
? `Printer "${printerName}" found. Run with dryRun=false to remove it.`
: `Printer "${printerName}" not found. Use list_printers to see available printer names.`
: removed
? `Printer "${printerName}" has been removed from the system.`
: found
? `Failed to remove printer "${printerName}". Ensure you have administrator privileges.`
: `Printer "${printerName}" not found — nothing to remove.`;
return { printerName, found, removed, dryRun, message };
}
// -- Exported run function ----------------------------------------------------
export async function run({
printerName,
dryRun = true,
}: {
printerName: string;
dryRun?: boolean;
}) {
const platform = os.platform();
return platform === "win32"
? removePrinterWin32(printerName, dryRun)
: removePrinterDarwin(printerName, dryRun);
}
// -- Smoke test ---------------------------------------------------------------
if (false) {
run({ printerName: "TestPrinter" })
.then(r => console.log(JSON.stringify(r, null, 2)))
.catch((err: Error) => { console.error(err.message); process.exit(1); });
}