Skip to main content
Glama

add_footnote

Destructive

Add explanatory footnotes to DOCX documents by anchoring them to specific paragraphs. Insert references after designated text or at paragraph ends to provide citations and additional context while preserving document formatting.

Instructions

Add a footnote anchored to a paragraph. Optionally position the reference after specific text using after_text. Note: [^N] markers in read_file output are display-only and not part of the editable text used by replace_text.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
file_pathYesPath to the DOCX file.
target_paragraph_idYesParagraph ID to anchor the footnote to.
after_textNoText after which to insert the footnote reference. If omitted, appends at end of paragraph.
textYesFootnote body text.

Implementation Reference

  • The MCP tool handler for 'add_footnote', which validates input, resolves the document session, and calls the low-level docx-core addFootnote implementation.
    export async function addFootnote(
      manager: SessionManager,
      params: {
        file_path?: string;
        target_paragraph_id?: string;
        after_text?: string;
        text?: string;
      },
    ): Promise<ToolResponse> {
      const resolved = await resolveSessionForTool(manager, params, { toolName: 'add_footnote' });
      if (!resolved.ok) return resolved.response;
      const { session, metadata } = resolved;
    
      if (!params.target_paragraph_id) {
        return err('MISSING_PARAMETER', 'target_paragraph_id is required.', 'Provide the _bk_* ID of the paragraph to anchor the footnote to.');
      }
      if (!params.text) {
        return err('MISSING_PARAMETER', 'text is required.', 'Provide the footnote body text.');
      }
    
      const pid = params.target_paragraph_id;
      const pEl = session.doc.getParagraphElementById(pid);
      if (!pEl) {
        return err('ANCHOR_NOT_FOUND', `Paragraph ID ${pid} not found in document`, 'Use grep or read_file to find valid paragraph IDs.');
      }
    
      try {
        const result = await session.doc.addFootnote({
          paragraphId: pid,
          afterText: params.after_text,
          text: params.text,
        });
    
        manager.markEdited(session);
        return ok(mergeSessionResolutionMetadata({
          note_id: result.noteId,
          target_paragraph_id: pid,
          after_text: params.after_text ?? null,
          file_path: manager.normalizePath(session.originalPath),
        }, metadata));
      } catch (e: unknown) {
        const msg = errorMessage(e);
        if (msg.includes('not found in paragraph')) {
          return err('TEXT_NOT_FOUND', msg, 'Verify after_text is present in the target paragraph.');
        }
        if (msg.includes('found') && msg.includes('times')) {
          return err('MULTIPLE_MATCHES', msg, 'Provide more specific after_text for a unique match.');
        }
        return err('FOOTNOTE_ERROR', msg);
      }
    }
  • The core implementation of adding a footnote to a DOCX document, handling XML structure for footnotes.xml and updating document references.
    export async function addFootnote(
      documentXml: Document,
      zip: DocxZip,
      params: AddFootnoteParams,
    ): Promise<AddFootnoteResult> {
      const { paragraphEl, afterText, text } = params;
    
      // Load or bootstrap footnotes.xml
      const footnotesXml = await zip.readText('word/footnotes.xml');
      const footnotesDoc = parseXml(footnotesXml);
    
      // Allocate next ID
      const noteId = allocateNextFootnoteId(footnotesDoc);
    
      // Insert footnoteReference run in document body
      insertFootnoteReference(documentXml, paragraphEl, noteId, afterText);
    
      // Add footnote body to footnotes.xml
      addFootnoteElement(footnotesDoc, noteId, text);
      zip.writeText('word/footnotes.xml', serializeXml(footnotesDoc));
    
      return { noteId };
    }
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations indicate the operation is destructive and not read-only. The description adds valuable behavioral context beyond annotations: the 'anchored' relationship to paragraphs and crucially, that [^N] markers in read_file output are display-only and not editable text, which prevents incorrect usage patterns with replace_text.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is efficiently structured with three distinct sentences: core purpose, optional parameter usage, and a critical behavioral note. Every sentence provides unique value without redundancy or filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the 4-parameter schema with full coverage and destructive annotations, the description adequately covers the primary operation and the important caveat about [^N] markers. It is missing explicit error behavior (e.g., if after_text is not found) and whether the operation requires an explicit save call.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 100% schema description coverage, the baseline is 3. The description references after_text ('Optionally position the reference after specific text') and implies target_paragraph_id ('anchored to a paragraph'), reinforcing the schema, but does not significantly expand on parameter semantics beyond what the schema already documents.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb ('Add') and resource ('footnote'), clarifies the anchoring mechanism ('anchored to a paragraph'), and distinguishes the operation from siblings like delete_footnote and update_footnote through the explicit 'Add' action.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides an important workflow note about [^N] markers being display-only in read_file output, implicitly guiding users away from using replace_text for footnote operations. However, it lacks explicit guidance on when to use add_footnote versus update_footnote or prerequisites like paragraph ID retrieval.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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/UseJunior/safe-docx'

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