Skip to main content
Glama
zeph-gh

DOCX MCP Server

by zeph-gh

analyze_structure

Analyze document structure, headings, and formatting elements in .docx files to understand organization and layout.

Instructions

Analyze document structure, headings, and formatting elements

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
file_pathYesPath to the .docx file

Implementation Reference

  • The handler function for the 'analyze_structure' tool. It processes a DOCX file by converting it to HTML using mammoth, extracts headings, paragraphs, formatting elements, and computes document statistics.
    async ({ file_path }) => {
      try {
        const absolutePath = path.resolve(file_path)
    
        if (!fs.existsSync(absolutePath)) {
          throw new Error(`File not found: ${absolutePath}`)
        }
    
        // Convert to HTML to analyze structure
        const htmlResult = await mammoth.convertToHtml({ path: absolutePath })
        const html = htmlResult.value
    
        // Extract text for analysis
        const textResult = await mammoth.extractRawText({ path: absolutePath })
        const text = textResult.value
    
        // Analyze structure
        const headings = (html.match(/<h[1-6][^>]*>.*?<\/h[1-6]>/gi) || []).map(
          (h: string) => ({
            level: parseInt(h.match(/<h([1-6])/)![1]),
            text: h.replace(/<[^>]*>/g, '').trim(),
          })
        )
    
        const paragraphs = (html.match(/<p[^>]*>.*?<\/p>/gi) || []).length
        const strongElements = (html.match(/<strong[^>]*>.*?<\/strong>/gi) || [])
          .length
        const emElements = (html.match(/<em[^>]*>.*?<\/em>/gi) || []).length
        const lists = (html.match(/<[uo]l[^>]*>.*?<\/[uo]l>/gi) || []).length
        const listItems = (html.match(/<li[^>]*>.*?<\/li>/gi) || []).length
    
        const analysis = {
          document_stats: {
            total_characters: text.length,
            total_words: text
              .split(/\s+/)
              .filter((word: string) => word.length > 0).length,
            total_paragraphs: paragraphs,
            total_headings: headings.length,
          },
          structure: {
            headings: headings,
            heading_levels: [
              ...new Set(headings.map((h: any) => h.level)),
            ].sort(),
          },
          formatting: {
            bold_elements: strongElements,
            italic_elements: emElements,
            lists: lists,
            list_items: listItems,
          },
          messages: htmlResult.messages,
        }
    
        return {
          content: [
            {
              type: 'text',
              text: JSON.stringify(analysis, null, 2),
            },
          ],
        }
      } catch (error) {
        return {
          content: [
            {
              type: 'text',
              text: `Error analyzing structure: ${(error as Error).message}`,
            },
          ],
          isError: true,
        }
      }
    }
  • Input schema for the 'analyze_structure' tool, requiring a file_path parameter.
    {
      file_path: z.string().describe('Path to the .docx file'),
    },
  • src/index.ts:137-218 (registration)
    Registration of the 'analyze_structure' tool using server.tool(), including name, description, input schema, and inline handler function.
    server.tool(
      'analyze_structure',
      'Analyze document structure, headings, and formatting elements',
      {
        file_path: z.string().describe('Path to the .docx file'),
      },
      async ({ file_path }) => {
        try {
          const absolutePath = path.resolve(file_path)
    
          if (!fs.existsSync(absolutePath)) {
            throw new Error(`File not found: ${absolutePath}`)
          }
    
          // Convert to HTML to analyze structure
          const htmlResult = await mammoth.convertToHtml({ path: absolutePath })
          const html = htmlResult.value
    
          // Extract text for analysis
          const textResult = await mammoth.extractRawText({ path: absolutePath })
          const text = textResult.value
    
          // Analyze structure
          const headings = (html.match(/<h[1-6][^>]*>.*?<\/h[1-6]>/gi) || []).map(
            (h: string) => ({
              level: parseInt(h.match(/<h([1-6])/)![1]),
              text: h.replace(/<[^>]*>/g, '').trim(),
            })
          )
    
          const paragraphs = (html.match(/<p[^>]*>.*?<\/p>/gi) || []).length
          const strongElements = (html.match(/<strong[^>]*>.*?<\/strong>/gi) || [])
            .length
          const emElements = (html.match(/<em[^>]*>.*?<\/em>/gi) || []).length
          const lists = (html.match(/<[uo]l[^>]*>.*?<\/[uo]l>/gi) || []).length
          const listItems = (html.match(/<li[^>]*>.*?<\/li>/gi) || []).length
    
          const analysis = {
            document_stats: {
              total_characters: text.length,
              total_words: text
                .split(/\s+/)
                .filter((word: string) => word.length > 0).length,
              total_paragraphs: paragraphs,
              total_headings: headings.length,
            },
            structure: {
              headings: headings,
              heading_levels: [
                ...new Set(headings.map((h: any) => h.level)),
              ].sort(),
            },
            formatting: {
              bold_elements: strongElements,
              italic_elements: emElements,
              lists: lists,
              list_items: listItems,
            },
            messages: htmlResult.messages,
          }
    
          return {
            content: [
              {
                type: 'text',
                text: JSON.stringify(analysis, null, 2),
              },
            ],
          }
        } catch (error) {
          return {
            content: [
              {
                type: 'text',
                text: `Error analyzing structure: ${(error as Error).message}`,
              },
            ],
            isError: true,
          }
        }
      }
    )
Behavior2/5

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

No annotations are provided, so the description carries the full burden of behavioral disclosure. It states the tool analyzes structure but doesn't disclose traits like whether it's read-only, what permissions are needed, how it handles errors, or the format of the output. This is a significant gap for a tool with no annotations, as it leaves key behavioral aspects unspecified.

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 extremely concise and front-loaded, consisting of a single, clear sentence that directly states the tool's purpose without any wasted words. Every part of the sentence earns its place by specifying the action and target resources efficiently.

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

Completeness2/5

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

Given the lack of annotations and output schema, the description is incomplete. It doesn't explain what the analysis returns (e.g., a structured report or raw data), potential side effects, or error handling. For a tool with no structured behavioral data, the description should provide more context to be fully helpful to an agent.

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?

The input schema has 100% description coverage, with the single parameter 'file_path' clearly documented as 'Path to the .docx file'. The description doesn't add any meaning beyond this, such as specifying file format constraints or analysis scope, but the schema provides adequate baseline information, justifying a score of 3.

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

Purpose4/5

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

The description clearly states the tool's purpose with specific verbs ('analyze') and resources ('document structure, headings, and formatting elements'), making it easy to understand what it does. However, it doesn't explicitly differentiate from sibling tools like 'extract_text' or 'convert_to_html', which might also involve document analysis, so it doesn't reach a perfect score.

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

Usage Guidelines2/5

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

The description provides no guidance on when to use this tool versus alternatives like 'extract_text' or 'convert_to_html'. It lacks any context about prerequisites, such as requiring a .docx file, or exclusions, leaving the agent to infer usage based on the tool name and parameters alone.

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/zeph-gh/Docx-Mcp-Server'

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