Skip to main content
Glama
libra850
by libra850

link_notes

Create wiki-style links between notes in Obsidian to connect related content and build knowledge networks.

Instructions

ノート間にウィキリンクを作成します

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
sourceNoteYesリンク元ノートパス(vault相対パス)
targetNoteYesリンク先ノートパス(vault相対パス)
linkTextNo表示テキスト(省略時はファイル名)
insertPositionNo挿入位置(end/cursor/行番号)end

Implementation Reference

  • Implements the core logic for linking notes: validates paths, checks file existence, generates wiki link, detects duplicates, inserts link at specified position, updates source note file.
    async linkNotes(sourceNote: string, targetNote: string, linkText?: string, insertPosition: 'end' | 'cursor' | number = 'end'): Promise<string> {
      if (!FileUtils.validatePath(this.config.vaultPath, sourceNote)) {
        throw new Error('無効なソースノートパスです');
      }
      if (!FileUtils.validatePath(this.config.vaultPath, targetNote)) {
        throw new Error('無効なターゲットノートパスです');
      }
    
      const sourceFullPath = path.join(this.config.vaultPath, sourceNote);
      const targetFullPath = path.join(this.config.vaultPath, targetNote);
    
      // ファイル存在チェック
      if (!(await FileUtils.fileExists(sourceFullPath))) {
        throw new Error(`ソースノート '${sourceNote}' が見つかりません`);
      }
      if (!(await FileUtils.fileExists(targetFullPath))) {
        throw new Error(`ターゲットノート '${targetNote}' が見つかりません`);
      }
    
      // ソースノートの内容を読み込み
      const sourceContent = await fs.readFile(sourceFullPath, 'utf-8');
    
      // リンクテキストが指定されていない場合はファイル名を使用
      const displayText = linkText || path.basename(targetNote, '.md');
      
      // ターゲットノートパスから .md 拡張子を除去
      const targetNotePath = targetNote.replace(/\.md$/, '');
      
      // ウィキリンク作成
      const wikiLink = `[[${targetNotePath}|${displayText}]]`;
    
      // 重複リンク検出
      const existingLinkPattern = new RegExp(`\\[\\[${targetNotePath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}(\\|[^\\]]+)?\\]\\]`);
      if (existingLinkPattern.test(sourceContent)) {
        return `警告: ターゲット '${targetNote}' への既存のリンクが見つかりました。重複リンクは作成されませんでした。`;
      }
    
      let updatedContent: string;
    
      // 挿入位置に応じてリンクを挿入
      if (insertPosition === 'end') {
        updatedContent = sourceContent + '\n' + wikiLink;
      } else if (insertPosition === 'cursor') {
        // cursor位置は実装が困難なため、endと同様に処理
        updatedContent = sourceContent + '\n' + wikiLink;
      } else if (typeof insertPosition === 'number') {
        const lines = sourceContent.split('\n');
        if (insertPosition < 0 || insertPosition > lines.length) {
          throw new Error('無効な挿入位置です');
        }
        lines.splice(insertPosition, 0, wikiLink);
        updatedContent = lines.join('\n');
      } else {
        updatedContent = sourceContent + '\n' + wikiLink;
      }
    
      // ファイルを更新
      await fs.writeFile(sourceFullPath, updatedContent, 'utf-8');
    
      return `ノート '${sourceNote}' に '${targetNote}' へのリンクを追加しました`;
    }
  • src/server.ts:165-191 (registration)
    Registers the 'link_notes' tool in the MCP server's listTools handler, defining name, description, and input schema.
    {
      name: 'link_notes',
      description: 'ノート間にウィキリンクを作成します',
      inputSchema: {
        type: 'object',
        properties: {
          sourceNote: {
            type: 'string',
            description: 'リンク元ノートパス(vault相対パス)',
          },
          targetNote: {
            type: 'string',
            description: 'リンク先ノートパス(vault相対パス)',
          },
          linkText: {
            type: 'string',
            description: '表示テキスト(省略時はファイル名)',
          },
          insertPosition: {
            type: ['string', 'number'],
            description: '挿入位置(end/cursor/行番号)',
            default: 'end',
          },
        },
        required: ['sourceNote', 'targetNote'],
      },
    },
  • Defines the input schema for the 'link_notes' tool, specifying parameters, types, descriptions, and required fields.
    inputSchema: {
      type: 'object',
      properties: {
        sourceNote: {
          type: 'string',
          description: 'リンク元ノートパス(vault相対パス)',
        },
        targetNote: {
          type: 'string',
          description: 'リンク先ノートパス(vault相対パス)',
        },
        linkText: {
          type: 'string',
          description: '表示テキスト(省略時はファイル名)',
        },
        insertPosition: {
          type: ['string', 'number'],
          description: '挿入位置(end/cursor/行番号)',
          default: 'end',
        },
      },
      required: ['sourceNote', 'targetNote'],
    },
  • Dispatches the tool call to the ObsidianHandler.linkNotes method in the MCP server's callTool request handler.
    case 'link_notes':
      const linkResult = await this.obsidianHandler.linkNotes(
        args.sourceNote as string,
        args.targetNote as string,
        args.linkText as string,
        (args.insertPosition as 'end' | 'cursor' | number) || 'end'
      );
      return {
        content: [{ type: 'text', text: linkResult }],
      };

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