reset_bluetooth_module
reset_bluetooth_module
Restarts the system Bluetooth daemon (macOS bluetoothd / Windows bthserv) so the OS re-enumerates paired devices and re-establishes connections. Last-resort fix for paired-but-disconnected devices when toggling the device itself has failed. Requires admin privilege; will briefly drop all Bluetooth connections including any audio call in progress.
Metadata
Name
reset_bluetooth_module
Updated
2 months ago
Source
Risk
Medium
Requires consent
true
Affected scope
system
Code
/**
* mcp/skills/resetBluetoothModule.ts — reset_bluetooth_module skill
*
* Restarts the Bluetooth daemon / service so the OS re-enumerates paired
* devices and re-establishes connections. Used as a last-resort fix
* when devices are paired-but-disconnected, after toggling the device
* itself failed.
*
* Platform strategy
* -----------------
* darwin `sudo launchctl kickstart -k system/com.apple.bluetoothd`
* restarts the system bluetoothd. Requires admin — the G4
* scope-boundary check (`affectedScope: ["system"]`) blocks
* non-admin runs by aborting the step.
* win32 `Restart-Service -Name bthserv -Force` via elevated
* PowerShell. Same admin requirement.
*
* Dry-run: returns the exact command(s) that would run + reports
* whether the agent has admin already (best-effort detection via a
* harmless probe). Does NOT touch the system in dry-run mode.
*
* Notes on side effects
* ---------------------
* - Active connections drop briefly (1–3 s). A user on a Bluetooth
* audio call will hear the audio interrupt.
* - Bluetooth-input devices (keyboard, trackpad) reconnect within
* 2–5 s; the user may temporarily lose input. This is why the
* skill always surfaces the dry-run preview + consent gate.
*/
import * as os from "os";
import { z } from "zod";
import {
execAsync,
runPS,
isDarwin,
isWin32,
} from "./_shared/platform";
// -- Meta ---------------------------------------------------------------------
export const meta = {
name: "reset_bluetooth_module",
description:
"Restarts the system Bluetooth daemon (macOS bluetoothd / Windows bthserv) " +
"so the OS re-enumerates paired devices and re-establishes connections. " +
"Last-resort fix for paired-but-disconnected devices when toggling the " +
"device itself has failed. Requires admin privilege; will briefly drop " +
"all Bluetooth connections including any audio call in progress.",
riskLevel: "medium",
destructive: false,
requiresConsent: true,
supportsDryRun: true,
affectedScope: ["system"],
auditRequired: true,
escalationHint: {
darwin: "sudo /bin/launchctl kickstart -k system/com.apple.bluetoothd",
win32: "Restart-Service -Name bthserv -Force # run from elevated PowerShell",
},
schema: {
dryRun: z
.boolean()
.optional()
.describe("If true, report what would be restarted without touching the system."),
},
} as const;
// -- Types --------------------------------------------------------------------
export interface ResetBluetoothModuleResult {
platform: NodeJS.Platform;
dryRun: boolean;
command: string;
/** Best-effort probe — true when the call succeeded. False when stderr indicated permission denial. */
succeeded: boolean;
/** Diagnostic message — usually a stderr line on failure, or a confirmation on success. */
message: string;
durationMs?: number;
}
// -- Platform helpers ---------------------------------------------------------
const DARWIN_CMD = "sudo /bin/launchctl kickstart -k system/com.apple.bluetoothd";
const WIN_CMD = "Restart-Service -Name bthserv -Force";
function isPermissionFailure(stderr: string): boolean {
const s = stderr.toLowerCase();
return (
s.includes("permission denied") ||
s.includes("not permitted") ||
s.includes("access is denied") ||
s.includes("requires administrative") ||
s.includes("must be run as administrator") ||
s.includes("needed root privileges") ||
s.includes("a password is required")
);
}
async function executeDarwin(): Promise<{ succeeded: boolean; message: string; durationMs: number }> {
const start = Date.now();
try {
const { stdout, stderr } = await execAsync(DARWIN_CMD, { timeout: 15_000 });
const elapsed = Date.now() - start;
if (stderr && isPermissionFailure(stderr)) {
return { succeeded: false, message: stderr.trim(), durationMs: elapsed };
}
return {
succeeded: true,
message: stdout.trim() || "bluetoothd restarted via launchctl kickstart",
durationMs: elapsed,
};
} catch (err) {
const elapsed = Date.now() - start;
const msg = (err as Error).message;
return { succeeded: false, message: msg, durationMs: elapsed };
}
}
async function executeWin32(): Promise<{ succeeded: boolean; message: string; durationMs: number }> {
const start = Date.now();
try {
const stdout = await runPS(`$ErrorActionPreference='Stop'; ${WIN_CMD}; 'OK'`, { timeoutMs: 15_000 });
const elapsed = Date.now() - start;
if (stdout.trim().toLowerCase().endsWith("ok")) {
return { succeeded: true, message: "bthserv restarted via Restart-Service", durationMs: elapsed };
}
return { succeeded: false, message: stdout.trim() || "Restart-Service returned no output", durationMs: elapsed };
} catch (err) {
const elapsed = Date.now() - start;
const msg = (err as Error).message;
return { succeeded: false, message: msg, durationMs: elapsed };
}
}
// -- Exported run function ----------------------------------------------------
export async function run({
dryRun = false,
}: { dryRun?: boolean } = {}): Promise<ResetBluetoothModuleResult> {
const platform = os.platform();
if (!isDarwin() && !isWin32()) {
throw new Error(`reset_bluetooth_module: unsupported platform "${platform}"`);
}
const command = isDarwin() ? DARWIN_CMD : WIN_CMD;
if (dryRun) {
return {
platform,
dryRun: true,
command,
succeeded: true,
message:
`Would restart the Bluetooth daemon. ` +
`Active Bluetooth connections (audio, keyboards, mice) will drop ` +
`for 1–3 seconds while the daemon restarts. Requires admin privilege.`,
};
}
const result = isDarwin() ? await executeDarwin() : await executeWin32();
return {
platform,
dryRun: false,
command,
succeeded: result.succeeded,
message: result.message,
durationMs: result.durationMs,
};
}
// -- Test helpers -------------------------------------------------------------
/** Exported for unit tests only — do not use from production code. */
export const __testing = {
isPermissionFailure,
DARWIN_CMD,
WIN_CMD,
};