obsidian_delete_folder
Delete a folder from an Obsidian vault with dry-run preview and confirmation required for permanent removal, or move it to trash.
Instructions
Delete a folder recursively or move it to .trash/mcp. Dry-run by default and confirmation is required for real deletes.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| vault | No | Optional configured vault name. Defaults to the server default vault. | |
| folder | Yes | ||
| dryRun | No | ||
| permanent | No | ||
| confirmation | No |
Implementation Reference
- src/tools.ts:623-635 (registration)Tool registration for 'obsidian_delete_folder'. Defines the schema (folder, dryRun, permanent, confirmation) and delegates to the deleteFolder() handler from ops.ts.
tool( "obsidian_delete_folder", "Delete a folder recursively or move it to .trash/mcp. Dry-run by default and confirmation is required for real deletes.", { vault: vaultArg, folder: z.string(), dryRun: z.boolean().optional().default(true), permanent: z.boolean().optional().default(false), confirmation: z.string().optional(), }, async (args) => deleteFolder(vaults, args.vault, args.folder, args), { destructiveHint: true }, ); - src/tools.ts:626-632 (schema)Zod schema for the obsidian_delete_folder tool: vault (optional), folder (required), dryRun (optional, default true), permanent (optional, default false), confirmation (optional).
{ vault: vaultArg, folder: z.string(), dryRun: z.boolean().optional().default(true), permanent: z.boolean().optional().default(false), confirmation: z.string().optional(), }, - src/ops.ts:124-150 (handler)The core deleteFolder() handler. Validates folder exists, checks directory, enforces confirmation for real deletes, counts entries, then either dry-runs, permanently deletes (fs.rm recursive), or moves to .trash/mcp with timestamp.
export async function deleteFolder( vaults: VaultManager, vault: string | undefined, folder: string, options: { dryRun?: boolean; permanent?: boolean; confirmation?: string } = {}, ): Promise<{ folder: string; entries: number; dryRun: boolean; deleted: boolean; trashPath?: string }> { vaults.assertWritable(); const resolved = vaults.resolvePath(folder, vault); if (!fssync.existsSync(resolved.absolute)) throw new Error(`Folder does not exist: ${resolved.relative}`); const stat = await fs.stat(resolved.absolute); if (!stat.isDirectory()) throw new Error(`Path is not a directory: ${resolved.relative}`); if (!options.dryRun && options.confirmation !== resolved.relative && options.confirmation !== "DELETE") { throw new Error(`Confirmation must equal "${resolved.relative}" or "DELETE"`); } const entries = await countEntries(resolved.absolute); if (options.dryRun) return { folder: resolved.relative, entries, dryRun: true, deleted: false }; if (options.permanent) { await fs.rm(resolved.absolute, { recursive: true, force: false }); return { folder: resolved.relative, entries, dryRun: false, deleted: true }; } const stamp = new Date().toISOString().replace(/[:.]/g, "-"); const trashRel = `.trash/mcp/${stamp}-${path.basename(resolved.relative)}`; const trash = vaults.resolvePath(trashRel, resolved.vault.name); await fs.mkdir(path.dirname(trash.absolute), { recursive: true }); await fs.rename(resolved.absolute, trash.absolute); return { folder: resolved.relative, entries, dryRun: false, deleted: true, trashPath: trash.relative }; } - src/ops.ts:209-216 (helper)Helper function countEntries() used by deleteFolder to recursively count files/folders in the target directory for the dry-run summary.
async function countEntries(dir: string): Promise<number> { let count = 0; for (const entry of await fs.readdir(dir, { withFileTypes: true })) { count += 1; if (entry.isDirectory()) count += await countEntries(path.join(dir, entry.name)); } return count; } - src/tools.ts:28-28 (registration)Import of deleteFolder from './ops.js' in the tools.ts registration file.
import { batchRename, deleteFolder, pruneEmptyDirs, regexReplaceAcrossVault, updateLinksAcrossVault } from "./ops.js";