Skip to main content
Glama
libra850
by libra850

analyze_backlinks

Analyze backlinks and understand graph structure for a specific note in Obsidian vaults to visualize connections and relationships.

Instructions

バックリンク分析とグラフ構造の把握を行います

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
targetNoteYes分析対象のノートパス(vault相対パス)

Implementation Reference

  • Core handler function that implements the analyze_backlinks tool logic: scans all vault .md files for incoming wiki links [[target]] and markdown links to the target note, extracts context snippets, identifies related notes, and computes basic graph metrics.
    async analyzeBacklinks(targetNote: string): Promise<{
      targetNote: string;
      backlinks: Array<{
        sourceFile: string;
        context: string;
        linkType: 'wiki' | 'markdown';
      }>;
      relatedNotes: string[];
      metrics: {
        popularity: number;
        centrality: number;
      };
    }> {
      if (!FileUtils.validatePath(this.config.vaultPath, targetNote)) {
        throw new Error('無効なターゲットノートパスです');
      }
    
      const targetFullPath = path.join(this.config.vaultPath, targetNote);
      if (!(await FileUtils.fileExists(targetFullPath))) {
        throw new Error(`ターゲットノート '${targetNote}' が見つかりません`);
      }
    
      const vaultPath = this.config.vaultPath;
      const backlinks: Array<{
        sourceFile: string;
        context: string;
        linkType: 'wiki' | 'markdown';
      }> = [];
    
      // ターゲットノートのベース名(拡張子なし)
      const targetBaseName = path.basename(targetNote, '.md');
      
      // すべてのMarkdownファイルを取得
      const allMdFiles = await this.getAllMdFiles(vaultPath);
    
      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);
    
          // ターゲットノート自体はスキップ
          if (path.resolve(filePath) === path.resolve(targetFullPath)) {
            return;
          }
    
          for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
            const line = lines[lineIndex];
            
            // ウィキリンク [[]] の検出
            const wikiLinkMatches = line.matchAll(/\[\[([^\]|]+)(\|[^\]]+)?\]\]/g);
            for (const match of wikiLinkMatches) {
              const linkTarget = match[1];
              
              if (linkTarget === targetBaseName || linkTarget === targetNote || linkTarget === targetNote.replace(/\.md$/, '')) {
                const context = this.extractContext(lines, lineIndex);
                backlinks.push({
                  sourceFile: relativeFilePath,
                  context,
                  linkType: 'wiki',
                });
              }
            }
    
            // Markdownリンク []() の検出
            const mdLinkMatches = line.matchAll(/\[([^\]]+)\]\(([^)]+)\)/g);
            for (const match of mdLinkMatches) {
              const linkTarget = match[2];
              
              if (linkTarget.includes(targetBaseName) || linkTarget.includes(targetNote)) {
                const context = this.extractContext(lines, lineIndex);
                backlinks.push({
                  sourceFile: relativeFilePath,
                  context,
                  linkType: 'markdown',
                });
              }
            }
          }
        } catch (error) {
          // ファイル読み込みエラーは無視
        }
      };
    
      // すべてのMarkdownファイルを処理
      for (const filePath of allMdFiles) {
        await processFile(filePath);
      }
    
      // 関連ノートを計算(バックリンクを持つファイル)
      const relatedNotes = [...new Set(backlinks.map(bl => bl.sourceFile))];
    
      // メトリクスを計算
      const popularity = backlinks.length;
      const centrality = this.calculateCentrality(backlinks, allMdFiles.length);
    
      return {
        targetNote,
        backlinks,
        relatedNotes,
        metrics: {
          popularity,
          centrality,
        },
      };
    }
  • src/server.ts:200-213 (registration)
    Registration of the 'analyze_backlinks' tool in the MCP server's tool list, including name, description, and input schema.
    {
      name: 'analyze_backlinks',
      description: 'バックリンク分析とグラフ構造の把握を行います',
      inputSchema: {
        type: 'object',
        properties: {
          targetNote: {
            type: 'string',
            description: '分析対象のノートパス(vault相対パス)',
          },
        },
        required: ['targetNote'],
      },
    },
  • MCP server request handler (switch case) that receives tool calls for 'analyze_backlinks', extracts arguments, delegates to ObsidianHandler.analyzeBacklinks, and formats response as JSON text content.
    case 'analyze_backlinks':
      const backlinksResult = await this.obsidianHandler.analyzeBacklinks(
        args.targetNote as string
      );
      return {
        content: [
          {
            type: 'text',
            text: JSON.stringify(backlinksResult, null, 2),
          },
        ],
      };
  • Input schema definition for the analyze_backlinks tool, specifying required 'targetNote' parameter.
    inputSchema: {
      type: 'object',
      properties: {
        targetNote: {
          type: 'string',
          description: '分析対象のノートパス(vault相対パス)',
        },
      },
      required: ['targetNote'],
    },
  • Helper method used by analyzeBacklinks to recursively find all Markdown files in the Obsidian vault.
    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;
    }

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