Skip to main content
Glama

check_documentation_links

Validate external, internal, and anchor links in documentation to identify broken references before deployment.

Instructions

Comprehensive link checking for documentation deployment with external, internal, and anchor link validation

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
documentation_pathNoPath to the documentation directory to check./docs
check_external_linksNoValidate external URLs (slower but comprehensive)
check_internal_linksNoValidate internal file references
check_anchor_linksNoValidate anchor links within documents
timeout_msNoTimeout for external link requests in milliseconds
max_concurrent_checksNoMaximum concurrent link checks
allowed_domainsNoWhitelist of allowed external domains (empty = all allowed)
ignore_patternsNoURL patterns to ignore during checking
fail_on_broken_linksNoFail the check if broken links are found
output_formatNoOutput format for resultsdetailed

Implementation Reference

  • The primary handler function for the 'check_documentation_links' tool. It orchestrates scanning documentation files, extracting links, checking their validity (internal, external, anchor), and generating a comprehensive report with summaries and recommendations.
    export async function checkDocumentationLinks( input: Partial<LinkCheckInput>, ): Promise<MCPToolResponse<LinkCheckReport>> { const startTime = Date.now(); try { // Validate input with defaults const validatedInput = LinkCheckInputSchema.parse(input); const { documentation_path, check_external_links, check_internal_links, check_anchor_links, timeout_ms, max_concurrent_checks, allowed_domains, ignore_patterns, fail_on_broken_links, } = validatedInput; // Scan documentation files const documentationFiles = await scanDocumentationFiles(documentation_path); if (documentationFiles.length === 0) { return { success: false, error: { code: "NO_DOCUMENTATION_FILES", message: "No documentation files found in the specified path", details: `Searched in: ${documentation_path}`, resolution: "Verify the documentation_path parameter points to a directory containing markdown files", }, metadata: { toolVersion: "1.0.0", executionTime: Date.now() - startTime, timestamp: new Date().toISOString(), }, }; } // Extract all links from documentation files const allLinks = await extractLinksFromFiles( documentationFiles, documentation_path, ); // Filter links based on configuration const filteredLinks = filterLinks(allLinks, { checkExternalLinks: check_external_links, checkInternalLinks: check_internal_links, checkAnchorLinks: check_anchor_links, ignorePatterns: ignore_patterns, }); // Check links with concurrency control const linkResults = await checkLinksWithConcurrency(filteredLinks, { timeoutMs: timeout_ms, maxConcurrent: max_concurrent_checks, allowedDomains: allowed_domains, documentationPath: documentation_path, }); // Generate report const report = generateLinkCheckReport(linkResults, { checkExternalLinks: check_external_links, checkInternalLinks: check_internal_links, checkAnchorLinks: check_anchor_links, timeoutMs: timeout_ms, maxConcurrentChecks: max_concurrent_checks, filesScanned: documentationFiles.length, executionTime: Date.now() - startTime, }); // Check if we should fail on broken links if (fail_on_broken_links && report.summary.brokenLinks > 0) { return { success: false, error: { code: "BROKEN_LINKS_FOUND", message: `Found ${report.summary.brokenLinks} broken links`, details: `${report.summary.brokenLinks} out of ${report.summary.totalLinks} links are broken`, resolution: "Fix the broken links or set fail_on_broken_links to false", }, data: report, metadata: { toolVersion: "1.0.0", executionTime: Date.now() - startTime, timestamp: new Date().toISOString(), }, }; } return { success: true, data: report, metadata: { toolVersion: "1.0.0", executionTime: Date.now() - startTime, timestamp: new Date().toISOString(), }, }; } catch (error) { return { success: false, error: { code: "LINK_CHECK_ERROR", message: "Failed to check documentation links", details: error instanceof Error ? error.message : "Unknown error occurred", resolution: "Check the documentation path and ensure files are accessible", }, metadata: { toolVersion: "1.0.0", executionTime: Date.now() - startTime, timestamp: new Date().toISOString(), }, }; } }
  • Zod input schema defining parameters for the tool, including defaults for documentation path, link check options, timeouts, and output format.
    const LinkCheckInputSchema = z.object({ documentation_path: z.string().default("./docs"), check_external_links: z.boolean().default(true), check_internal_links: z.boolean().default(true), check_anchor_links: z.boolean().default(true), timeout_ms: z.number().min(1000).max(30000).default(5000), max_concurrent_checks: z.number().min(1).max(20).default(5), allowed_domains: z.array(z.string()).default([]), ignore_patterns: z.array(z.string()).default([]), fail_on_broken_links: z.boolean().default(false), output_format: z.enum(["summary", "detailed", "json"]).default("detailed"), });
  • TypeScript interface defining the structure of the tool's output report, including summary statistics, detailed results, recommendations, and configuration.
    interface LinkCheckReport { summary: { totalLinks: number; validLinks: number; brokenLinks: number; warningLinks: number; skippedLinks: number; executionTime: number; filesScanned: number; }; results: LinkCheckResult[]; recommendations: string[]; configuration: { checkExternalLinks: boolean; checkInternalLinks: boolean; checkAnchorLinks: boolean; timeoutMs: number; maxConcurrentChecks: number; }; }
  • Helper function to recursively scan the documentation directory for markdown files.
    async function scanDocumentationFiles(basePath: string): Promise<string[]> { const files: string[] = []; async function scanDirectory(dirPath: string): Promise<void> { try { const entries = await readdir(dirPath); for (const entry of entries) { const fullPath = join(dirPath, entry); const stats = await stat(fullPath); if (stats.isDirectory()) { // Skip node_modules and hidden directories if (!entry.startsWith(".") && entry !== "node_modules") { await scanDirectory(fullPath); } } else if (stats.isFile()) { const ext = extname(entry).toLowerCase(); if ([".md", ".mdx", ".markdown"].includes(ext)) { files.push(fullPath); } } } } catch (error) { // Skip directories we can't read } } await scanDirectory(basePath); return files; }
  • Supporting helper functions that handle link extraction, filtering, concurrent checking for internal/external/anchor links, and report generation.
    } async function scanDocumentationFiles(basePath: string): Promise<string[]> {

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/tosin2013/documcp'

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