Skip to main content
Glama

delete_footnote_robust

Remove footnotes from Word documents while cleaning up references and orphaned elements to maintain document integrity.

Instructions

Delete footnote with comprehensive cleanup and orphan removal. Ensures complete removal from document.xml, footnotes.xml, and relationships.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
filenameYes
footnote_idNo
search_textNo
clean_orphansNo

Implementation Reference

  • MCP tool registration for 'delete_footnote_robust'. This decorated function registers the tool and serves as the entry point, delegating to the async handler in footnote_tools.
    @mcp.tool() def delete_footnote_robust(filename: str, footnote_id: int = None, search_text: str = None, clean_orphans: bool = True): """Delete footnote with comprehensive cleanup and orphan removal. Ensures complete removal from document.xml, footnotes.xml, and relationships.""" return footnote_tools.delete_footnote_robust_tool( filename, footnote_id, search_text, clean_orphans )
  • Primary async handler function for the delete_footnote_robust tool. Handles input validation, file checks, and delegates to core implementation.
    async def delete_footnote_robust_tool( filename: str, footnote_id: Optional[int] = None, search_text: Optional[str] = None, clean_orphans: bool = True ) -> Dict[str, Any]: """ Delete a footnote with comprehensive cleanup. Args: filename: Path to the Word document footnote_id: ID of footnote to delete search_text: Text near footnote reference clean_orphans: Whether to remove orphaned content Returns: Dict with success status, message, and optional details """ filename = ensure_docx_extension(filename) # Check if file is writeable is_writeable, error_message = check_file_writeable(filename) if not is_writeable: return { "success": False, "message": f"Cannot modify document: {error_message}", "details": None } # Convert footnote_id if provided as string if footnote_id is not None: try: footnote_id = int(footnote_id) except (ValueError, TypeError): return { "success": False, "message": "Invalid parameter: footnote_id must be an integer", "details": None } # Call robust implementation success, message, details = delete_footnote_robust( filename=filename, footnote_id=footnote_id, search_text=search_text, clean_orphans=clean_orphans ) return { "success": success, "message": message, "details": details }
  • Core helper function implementing the actual DOCX XML manipulation: removes footnote references, content, cleans orphans, and rewrites the ZIP archive.
    def delete_footnote_robust( filename: str, footnote_id: Optional[int] = None, search_text: Optional[str] = None, output_filename: Optional[str] = None, clean_orphans: bool = True ) -> Tuple[bool, str, Optional[Dict[str, Any]]]: """Delete a footnote with comprehensive cleanup.""" if not footnote_id and not search_text: return False, "Must provide either footnote_id or search_text", None if not os.path.exists(filename): return False, f"File not found: {filename}", None # Set working file working_file = output_filename if output_filename else filename if output_filename and filename != output_filename: import shutil shutil.copy2(filename, output_filename) try: # Read document parts with zipfile.ZipFile(filename, 'r') as zin: doc_xml = zin.read('word/document.xml') if 'word/footnotes.xml' not in zin.namelist(): return False, "No footnotes in document", None footnotes_xml = zin.read('word/footnotes.xml') # Parse documents doc_root = etree.fromstring(doc_xml) footnotes_root = etree.fromstring(footnotes_xml) nsmap = {'w': W_NS} # Find footnote to delete if search_text: # Find footnote reference near text for para in doc_root.xpath('//w:p', namespaces=nsmap): para_text = ''.join(para.xpath('.//w:t/text()', namespaces=nsmap)) if search_text in para_text: # Look for footnote reference in this paragraph fn_refs = para.xpath('.//w:footnoteReference', namespaces=nsmap) if fn_refs: footnote_id = int(fn_refs[0].get(f'{{{W_NS}}}id')) break if not footnote_id: return False, f"No footnote found near text '{search_text}'", None # Remove footnote reference from document refs_removed = 0 for fn_ref in doc_root.xpath(f'//w:footnoteReference[@w:id="{footnote_id}"]', namespaces=nsmap): # Remove the entire run containing the reference run = fn_ref.getparent() if run is not None and run.tag == f'{{{W_NS}}}r': para = run.getparent() if para is not None: para.remove(run) refs_removed += 1 if refs_removed == 0: return False, f"Footnote {footnote_id} not found", None # Remove footnote content content_removed = 0 for fn in footnotes_root.xpath(f'//w:footnote[@w:id="{footnote_id}"]', namespaces=nsmap): footnotes_root.remove(fn) content_removed += 1 # Clean orphans if requested orphans_removed = [] if clean_orphans: # Find all referenced IDs referenced_ids = set() for ref in doc_root.xpath('//w:footnoteReference', namespaces=nsmap): ref_id = ref.get(f'{{{W_NS}}}id') if ref_id: referenced_ids.add(ref_id) # Remove unreferenced footnotes (except separators) for fn in footnotes_root.xpath('//w:footnote', namespaces=nsmap): fn_id = fn.get(f'{{{W_NS}}}id') if fn_id and fn_id not in referenced_ids and fn_id not in ['-1', '0']: footnotes_root.remove(fn) orphans_removed.append(fn_id) # Write modified document temp_file = working_file + '.tmp' with zipfile.ZipFile(temp_file, 'w', zipfile.ZIP_DEFLATED) as zout: with zipfile.ZipFile(filename, 'r') as zin: for item in zin.infolist(): if item.filename == 'word/document.xml': zout.writestr(item, etree.tostring(doc_root, encoding='UTF-8', xml_declaration=True, standalone="yes")) elif item.filename == 'word/footnotes.xml': zout.writestr(item, etree.tostring(footnotes_root, encoding='UTF-8', xml_declaration=True, standalone="yes")) else: zout.writestr(item, zin.read(item.filename)) os.replace(temp_file, working_file) details = { 'footnote_id': footnote_id, 'references_removed': refs_removed, 'content_removed': content_removed, 'orphans_removed': orphans_removed } message = f"Successfully deleted footnote {footnote_id}" if orphans_removed: message += f" and {len(orphans_removed)} orphaned footnotes" return True, message, details except Exception as e: return False, f"Error deleting footnote: {str(e)}", None

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/GongRzhe/Office-Word-MCP-Server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server