obsidian_prune_empty_dirs
Find and remove empty directories in an Obsidian vault, working bottom-up while skipping .obsidian, .git, and .trash folders. Supports dry-run and configurable limits.
Instructions
Find and optionally remove empty directories bottom-up, skipping .obsidian, .git, and .trash.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| vault | No | Optional configured vault name. Defaults to the server default vault. | |
| folder | No | . | |
| dryRun | No | ||
| limit | No |
Implementation Reference
- src/tools.ts:637-647 (registration)Registration of the obsidian_prune_empty_dirs tool using the MCP tool() helper. The schema specifies vault, folder, dryRun, and limit parameters. The handler delegates to pruneEmptyDirs() from ops.ts.
tool( "obsidian_prune_empty_dirs", "Find and optionally remove empty directories bottom-up, skipping .obsidian, .git, and .trash.", { vault: vaultArg, folder: z.string().optional().default("."), dryRun: z.boolean().optional().default(true), limit: z.number().int().min(1).max(5000).optional().default(1000), }, async (args) => pruneEmptyDirs(vaults, args.vault, args), ); - src/ops.ts:152-186 (handler)The pruneEmptyDirs function implements the core logic: recursively walks directories bottom-up, skips .obsidian/.git/.trash, and removes empty directories. Supports dry-run mode and a configurable limit.
export async function pruneEmptyDirs( vaults: VaultManager, vault: string | undefined, options: { folder?: string; dryRun?: boolean; limit?: number } = {}, ): Promise<{ dryRun: boolean; removed: string[] }> { vaults.assertWritable(); const base = vaults.resolvePath(options.folder ?? ".", vault); const removed: string[] = []; async function walk(dir: string): Promise<boolean> { const entries = await fs.readdir(dir, { withFileTypes: true }); let empty = true; for (const entry of entries) { if ([".obsidian", ".git", ".trash"].includes(entry.name)) { empty = false; continue; } const full = path.join(dir, entry.name); if (entry.isDirectory()) { const childEmpty = await walk(full); if (!childEmpty) empty = false; } else { empty = false; } } if (empty && dir !== base.absolute && removed.length < (options.limit ?? 1000)) { const rel = path.relative(base.vault.root, dir).replace(/\\/g, "/"); removed.push(rel); if (!options.dryRun) await fs.rmdir(dir); return true; } return false; } await walk(base.absolute); return { dryRun: options.dryRun ?? true, removed }; } - src/tools.ts:28-28 (helper)Import of the pruneEmptyDirs function from ops.ts into the tools registration file.
import { batchRename, deleteFolder, pruneEmptyDirs, regexReplaceAcrossVault, updateLinksAcrossVault } from "./ops.js";