delete_footnote
Remove a footnote and its reference from a Word document by providing the file path and footnote ID.
Instructions
Delete a footnote and its reference from the document.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| file_path | Yes | Path to the DOCX file. | |
| note_id | Yes | Footnote ID to delete. |
Implementation Reference
- MCP tool handler for delete_footnote. Resolves the session, validates the note_id parameter, delegates to session.doc.deleteFootnote(), and returns a structured response with error handling for reserved footnotes, missing files, and not-found cases.
import { SessionManager } from '../session/manager.js'; import { errorCode, errorMessage } from "../error_utils.js"; import { resolveSessionForTool, mergeSessionResolutionMetadata } from './session_resolution.js'; import { ok, err, type ToolResponse } from './types.js'; export async function deleteFootnote( manager: SessionManager, params: { file_path?: string; note_id?: number; }, ): Promise<ToolResponse> { const resolved = await resolveSessionForTool(manager, params, { toolName: 'delete_footnote' }); if (!resolved.ok) return resolved.response; const { session, metadata } = resolved; if (params.note_id == null) { return err('MISSING_PARAMETER', 'note_id is required.', 'Provide the footnote ID to delete.'); } try { await session.doc.deleteFootnote({ noteId: params.note_id }); manager.markEdited(session); return ok(mergeSessionResolutionMetadata({ note_id: params.note_id, file_path: manager.normalizePath(session.originalPath), }, metadata)); } catch (e: unknown) { const msg = errorMessage(e); if (msg.includes('reserved')) { return err('RESERVED_TYPE', msg, 'Reserved footnotes (separator, continuationSeparator) cannot be deleted.'); } if (msg.includes('Missing file in .docx: word/footnotes.xml')) { return err('NOTE_NOT_FOUND', `Footnote ID ${params.note_id} not found`, 'Use get_footnotes to list available footnotes.'); } if (msg.includes('not found')) { return err('NOTE_NOT_FOUND', msg, 'Use get_footnotes to list available footnotes.'); } return err('FOOTNOTE_ERROR', msg); } } - Core implementation of footnote deletion. Removes the footnote element from word/footnotes.xml and removes all corresponding footnoteReference elements from document.xml. Throws if the footnote is reserved (separator/continuationSeparator) or not found.
export async function deleteFootnote( documentXml: Document, zip: DocxZip, params: { noteId: number }, ): Promise<void> { const { noteId } = params; const footnotesXml = await zip.readText('word/footnotes.xml'); const footnotesDoc = parseXml(footnotesXml); const fnEl = findFootnoteById(footnotesDoc, noteId); if (!fnEl) throw new Error(`Footnote ID ${noteId} not found`); if (isReservedFootnote(fnEl)) throw new Error(`Cannot delete reserved footnote ID ${noteId}`); // Remove from footnotes.xml fnEl.parentNode?.removeChild(fnEl); zip.writeText('word/footnotes.xml', serializeXml(footnotesDoc)); // Remove footnoteReference elements from document.xml const refs = documentXml.getElementsByTagNameNS(OOXML.W_NS, W.footnoteReference); const refsToRemove: Element[] = []; for (let i = 0; i < refs.length; i++) { const ref = refs.item(i) as Element; const idStr = getWAttr(ref, 'id'); if (idStr && parseInt(idStr, 10) === noteId) { refsToRemove.push(ref); } } for (const ref of refsToRemove) { const run = ref.parentNode as Element | null; if (!run) continue; // Remove only the footnoteReference element, not the entire run run.removeChild(ref); // If the run is now empty (no visible content), remove it if (!hasVisibleContent(run)) { run.parentNode?.removeChild(run); } } } - Document class method that delegates to the deleteFootnote implementation from footnotes.ts, then refreshes the internal footnotes XML cache and marks the document as dirty.
async deleteFootnote(params: { noteId: number }): Promise<void> { await deleteFootnoteImpl(this.documentXml, this.zip, params); await this.refreshFootnotesXml(); this.dirty = true; - Schema registration for delete_footnote in the tool catalog. Defines the name, description, input schema (file_path and note_id), and sets destructiveHint: true.
{ name: 'delete_footnote', description: 'Delete a footnote and its reference from the document.', input: z.object({ ...FILE_FIELD, note_id: z.number().describe('Footnote ID to delete.'), }), annotations: { readOnlyHint: false, destructiveHint: true }, }, - packages/docx-mcp/src/server.ts:139-140 (registration)Server-side registration: maps the 'delete_footnote' tool name to the deleteFootnote handler function within the main server switch/case dispatch.
case 'delete_footnote': return await deleteFootnote(sessions, args as Parameters<typeof deleteFootnote>[1]);