Skip to main content
Glama

delete_comment

Destructive

Remove a comment and all its threaded replies from a DOCX document. Specify the file path and comment ID to delete comments while preserving document formatting.

Instructions

Delete a comment and all its threaded replies from the document. Cascade-deletes all descendants.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
file_pathYesPath to the DOCX file.
comment_idYesComment ID to delete.

Implementation Reference

  • MCP tool handler that validates input, resolves the document session, calls the core deleteComment primitive, and returns the appropriate tool response.
    export async function deleteComment(
      manager: SessionManager,
      params: {
        file_path?: string;
        comment_id?: number;
      },
    ): Promise<ToolResponse> {
      const resolved = await resolveSessionForTool(manager, params, { toolName: 'delete_comment' });
      if (!resolved.ok) return resolved.response;
      const { session, metadata } = resolved;
    
      if (params.comment_id == null) {
        return err('MISSING_PARAMETER', 'comment_id is required.', 'Provide the comment ID to delete.');
      }
    
      try {
        await session.doc.deleteComment({ commentId: params.comment_id });
    
        manager.markEdited(session);
        return ok(mergeSessionResolutionMetadata({
          comment_id: params.comment_id,
          file_path: manager.normalizePath(session.originalPath),
        }, metadata));
      } catch (e: unknown) {
        const msg = errorMessage(e);
        if (msg.includes('not found')) {
          return err('COMMENT_NOT_FOUND', msg, 'Use get_comments to list available comments.');
        }
        return err('COMMENT_ERROR', msg);
      }
    }
  • Core implementation of comment deletion. It manipulates the document XML structure, including removing comment elements, extended metadata, and associated markers/references in document.xml.
    export async function deleteComment(
      documentXml: Document,
      zip: DocxZip,
      params: { commentId: number },
    ): Promise<void> {
      const { commentId } = params;
    
      const commentsText = await zip.readTextOrNull('word/comments.xml');
      if (!commentsText) throw new Error(`Comment ID ${commentId} not found`);
    
      const commentsDoc = parseXml(commentsText);
    
      // Find the target comment element and its paraId
      const targetEl = findCommentElementById(commentsDoc, commentId);
      if (!targetEl) throw new Error(`Comment ID ${commentId} not found`);
    
      const targetParaId = getCommentElParaId(targetEl);
    
      // Collect all IDs to delete: the target + all transitive descendants
      const idsToDelete = new Set<number>([commentId]);
      const paraIdsToDelete = new Set<string>();
      if (targetParaId) paraIdsToDelete.add(targetParaId);
    
      // Build paraId→commentId and paraId→commentEl maps for all comments
      const paraIdToId = new Map<string, number>();
      const allCommentEls = commentsDoc.getElementsByTagNameNS(OOXML.W_NS, W.comment);
      for (let i = 0; i < allCommentEls.length; i++) {
        const el = allCommentEls.item(i) as Element;
        const idStr = el.getAttributeNS(OOXML.W_NS, 'id') ?? el.getAttribute('w:id');
        const id = idStr ? parseInt(idStr, 10) : -1;
        if (id < 0) continue;
        const pid = getCommentElParaId(el);
        if (pid) paraIdToId.set(pid, id);
      }
    
      // Read commentsExtended.xml to find descendants via paraIdParent graph
      const extText = await zip.readTextOrNull('word/commentsExtended.xml');
      if (extText) {
        const extDoc = parseXml(extText);
        const exEls = extDoc.getElementsByTagNameNS(OOXML.W15_NS, 'commentEx');
    
        // Build parent→children map
        const childrenOf = new Map<string, string[]>();
        for (let i = 0; i < exEls.length; i++) {
          const ex = exEls.item(i) as Element;
          const childPid = ex.getAttributeNS(OOXML.W15_NS, 'paraId') ?? ex.getAttribute('w15:paraId');
          const parentPid = ex.getAttributeNS(OOXML.W15_NS, 'paraIdParent') ?? ex.getAttribute('w15:paraIdParent');
          if (childPid && parentPid) {
            const arr = childrenOf.get(parentPid);
            if (arr) arr.push(childPid);
            else childrenOf.set(parentPid, [childPid]);
          }
        }
    
        // BFS from target paraId to collect all descendant paraIds
        const queue = targetParaId ? [targetParaId] : [];
        while (queue.length > 0) {
          const pid = queue.shift()!;
          const children = childrenOf.get(pid);
          if (!children) continue;
          for (const childPid of children) {
            if (!paraIdsToDelete.has(childPid)) {
              paraIdsToDelete.add(childPid);
              const childId = paraIdToId.get(childPid);
              if (childId != null) idsToDelete.add(childId);
              queue.push(childPid);
            }
          }
        }
      }
    
      // 1. Remove comment elements from comments.xml
      const elsToRemove: Element[] = [];
      for (let i = 0; i < allCommentEls.length; i++) {
        const el = allCommentEls.item(i) as Element;
        const idStr = el.getAttributeNS(OOXML.W_NS, 'id') ?? el.getAttribute('w:id');
        const id = idStr ? parseInt(idStr, 10) : -1;
        if (idsToDelete.has(id)) elsToRemove.push(el);
      }
      for (const el of elsToRemove) {
        el.parentNode?.removeChild(el);
      }
      zip.writeText('word/comments.xml', serializeXml(commentsDoc));
    
      // 2. Remove commentEx entries from commentsExtended.xml (if present)
      if (extText) {
        const extDoc = parseXml(extText);
        const exEls = extDoc.getElementsByTagNameNS(OOXML.W15_NS, 'commentEx');
        const exToRemove: Element[] = [];
        for (let i = 0; i < exEls.length; i++) {
          const ex = exEls.item(i) as Element;
          const pid = ex.getAttributeNS(OOXML.W15_NS, 'paraId') ?? ex.getAttribute('w15:paraId');
          if (pid && paraIdsToDelete.has(pid)) exToRemove.push(ex);
        }
        for (const ex of exToRemove) {
          ex.parentNode?.removeChild(ex);
        }
        zip.writeText('word/commentsExtended.xml', serializeXml(extDoc));
      }
    
      // 3. Remove range markers and commentReference from document.xml (for root comments)
      for (const cid of idsToDelete) {
        removeCommentMarkersFromDocument(documentXml, cid);
      }
    }
Behavior4/5

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

Annotations indicate the operation is destructive, but the description adds crucial behavioral context that annotations lack: specifically that deletion cascades to 'all descendants' and 'threaded replies,' clarifying the scope of data loss.

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?

Two sentences with zero waste: the first states the primary action and scope, while the second reinforces the critical cascade behavior. Information is front-loaded and every sentence earns its place.

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?

For a destructive operation on document comments, the description adequately covers the critical cascade warning. Given the absence of an output schema and the presence of complete input schema coverage, no additional description of return values or parameters is necessary.

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 (file_path and comment_id fully documented), the description appropriately relies on the schema. It mentions 'the document' and 'comment' which loosely map to parameters, but adds no additional semantic detail beyond the schema definitions.

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 provides a specific verb ('Delete') and resource ('comment and all its threaded replies'), clearly distinguishing this from simple comment removal by explicitly stating it handles threaded replies and cascade-deletes descendants.

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?

While the cascade behavior implies when to use this (removing entire threads), there is no explicit guidance on when to prefer this over alternatives like add_comment or get_comments, nor any prerequisites mentioned.

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