Skip to main content
Glama

find_broken_links

Detect and fix broken links in Obsidian vaults to maintain organized note connections and improve content reliability.

Instructions

壊れたリンクの検出と修復支援を行います

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Implementation Reference

  • Core implementation of findBrokenLinks tool: scans all .md files in vault for broken wiki [[ ]] and markdown [ ]() links, verifies target existence, collects broken links with line numbers and similarity-based suggestions.
    async findBrokenLinks(): Promise<{ brokenLinks: Array<{ sourceFile: string; linkText: string; targetPath: string; lineNumber: number; suggestions: string[]; }>; totalCount: number; }> { const vaultPath = this.config.vaultPath; const brokenLinks: Array<{ sourceFile: string; linkText: string; targetPath: string; lineNumber: number; suggestions: string[]; }> = []; // すべてのMarkdownファイルを取得 const allMdFiles = await this.getAllMdFiles(vaultPath); const allFileBasenames = allMdFiles.map(file => path.basename(file, '.md')); const processFile = async (filePath: string) => { try { const content = await fs.readFile(filePath, 'utf-8'); const lines = content.split('\n'); const relativeFilePath = path.relative(vaultPath, filePath); for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) { const line = lines[lineIndex]; // ウィキリンク [[]] の検出 const wikiLinkMatches = line.matchAll(/\[\[([^\]|]+)(\|[^\]]+)?\]\]/g); for (const match of wikiLinkMatches) { const targetPath = match[1]; const linkText = match[2] ? match[2].substring(1) : targetPath; // ターゲットファイルの存在確認 const possiblePaths = [ path.join(vaultPath, `${targetPath}.md`), path.join(vaultPath, targetPath), ]; let exists = false; for (const possiblePath of possiblePaths) { if (await FileUtils.fileExists(possiblePath)) { exists = true; break; } } if (!exists) { // 修復候補を検索 const suggestions = this.findSimilarFiles(targetPath, allFileBasenames); brokenLinks.push({ sourceFile: relativeFilePath, linkText, targetPath, lineNumber: lineIndex + 1, suggestions, }); } } // Markdownリンク []() の検出 const mdLinkMatches = line.matchAll(/\[([^\]]+)\]\(([^)]+)\)/g); for (const match of mdLinkMatches) { const linkText = match[1]; const targetPath = match[2]; // 内部リンク(.mdファイル)のみチェック if (targetPath.endsWith('.md') || !targetPath.includes('://')) { const fullTargetPath = path.resolve(path.dirname(filePath), targetPath); if (!(await FileUtils.fileExists(fullTargetPath))) { const suggestions = this.findSimilarFiles(path.basename(targetPath, '.md'), allFileBasenames); brokenLinks.push({ sourceFile: relativeFilePath, linkText, targetPath, lineNumber: lineIndex + 1, suggestions, }); } } } } } catch (error) { // ファイル読み込みエラーは無視 } }; // すべてのMarkdownファイルを処理 for (const filePath of allMdFiles) { await processFile(filePath); } return { brokenLinks, totalCount: brokenLinks.length, }; }
  • src/server.ts:192-199 (registration)
    Tool registration in MCP server's listTools handler, defining name, Japanese description, and empty input schema (no parameters required).
    { name: 'find_broken_links', description: '壊れたリンクの検出と修復支援を行います', inputSchema: { type: 'object', properties: {}, }, },
  • src/server.ts:341-350 (registration)
    Dispatch handler in MCP server's callToolRequest that invokes ObsidianHandler.findBrokenLinks() and returns JSON-formatted result as text content.
    case 'find_broken_links': const brokenLinksResult = await this.obsidianHandler.findBrokenLinks(); return { content: [ { type: 'text', text: JSON.stringify(brokenLinksResult, null, 2), }, ], };
  • Helper method to recursively collect all .md file paths in the vault, used by findBrokenLinks to get files to scan.
    private async getAllMdFiles(dirPath: string): Promise<string[]> { const files: string[] = []; const processDirectory = async (currentPath: string) => { try { const entries = await fs.readdir(currentPath, { withFileTypes: true }); for (const entry of entries) { const fullPath = path.join(currentPath, entry.name); if (entry.isDirectory()) { await processDirectory(fullPath); } else if (entry.isFile() && entry.name.endsWith('.md')) { files.push(fullPath); } } } catch (error) { // ディレクトリ読み込みエラーは無視 } }; await processDirectory(dirPath); return files; }
  • Levenshtein distance-based similarity calculator used for generating repair suggestions in findSimilarFiles.
    private calculateSimilarity(str1: string, str2: string): number { const matrix = []; const len1 = str1.length; const len2 = str2.length; for (let i = 0; i <= len1; i++) { matrix[i] = [i]; } for (let j = 0; j <= len2; j++) { matrix[0][j] = j; } for (let i = 1; i <= len1; i++) { for (let j = 1; j <= len2; j++) { const cost = str1[i - 1] === str2[j - 1] ? 0 : 1; matrix[i][j] = Math.min( matrix[i - 1][j] + 1, matrix[i][j - 1] + 1, matrix[i - 1][j - 1] + cost ); } } const distance = matrix[len1][len2]; return 1 - distance / Math.max(len1, len2); }

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/libra850/obsidian-mcp-server'

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