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 }],
      };
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden of behavioral disclosure. It states the tool creates wiki links, implying a write operation, but doesn't cover aspects like whether it modifies existing notes, requires specific permissions, handles errors for non-existent notes, or what happens on success/failure. This leaves significant gaps for a mutation tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, efficient sentence in Japanese that directly states the tool's purpose without any wasted words. It's appropriately sized and front-loaded, making it easy to understand at a glance.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity as a mutation operation with 4 parameters, no annotations, and no output schema, the description is insufficient. It doesn't explain the return values, error conditions, or behavioral nuances, leaving the agent with incomplete information for proper invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has 100% description coverage, providing clear details for all 4 parameters (sourceNote, targetNote, linkText, insertPosition). The description doesn't add any additional meaning beyond what's in the schema, such as explaining parameter interactions or usage examples, so it meets the baseline score when schema coverage is high.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose as 'creates wiki links between notes' (ノート間にウィキリンクを作成します), which specifies the action (creates wiki links) and resource (between notes). However, it doesn't differentiate from sibling tools like 'find_broken_links' or 'analyze_backlinks' which also deal with note links, so it doesn't reach the highest score.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives. It doesn't mention prerequisites, context, or exclusions, such as when to choose this over 'update_note' for modifying links or how it relates to sibling tools like 'find_broken_links'.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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