link_notes
Create wiki-style links between notes in Obsidian to connect related content and build knowledge networks.
Instructions
ノート間にウィキリンクを作成します
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| sourceNote | Yes | リンク元ノートパス(vault相対パス) | |
| targetNote | Yes | リンク先ノートパス(vault相対パス) | |
| linkText | No | 表示テキスト(省略時はファイル名) | |
| insertPosition | No | 挿入位置(end/cursor/行番号) | end |
Implementation Reference
- src/obsidian-handler.ts:258-318 (handler)Core implementation of the link_notes tool. Validates paths, checks file existence, reads source note, generates wiki link, detects duplicates, inserts link at specified position, and updates the 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)Tool registration in the MCP server's list of tools, including name, description, and input schema definition.{ 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'], }, },
- src/server.ts:168-190 (schema)Input schema defining parameters for the link_notes tool: sourceNote, targetNote (required), linkText (optional), insertPosition (default 'end').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'], },
- src/server.ts:330-339 (handler)Server-side handler that receives tool call, extracts arguments, delegates to ObsidianHandler.linkNotes, and returns result as MCP content.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 }], };