Skip to main content
Glama
libra850
by libra850

create_moc

Generate a Map of Contents note in Obsidian to organize and link related notes based on tags, folders, or patterns.

Instructions

Map of Contents(目次ノート)を自動生成します

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
titleYesMOCのタイトル
targetPathYesMOCの保存先パス(vault相対パス)
sourcePatternNo対象ノートのパターン(省略時は全て)
groupByNoグループ化方法none
includeDescriptionNo説明を含めるかどうか

Implementation Reference

  • Core handler function for the 'create_moc' tool. Collects Markdown files matching a source pattern (or all), groups them by tag, folder, or none, generates a Markdown MOC file with wiki links to the files (with optional descriptions), and saves it to the target path in the Obsidian vault.
    async createMoc(title: string, targetPath: string, sourcePattern?: string, groupBy: 'tag' | 'folder' | 'none' = 'none', includeDescription: boolean = false): Promise<string> {
      if (!FileUtils.validatePath(this.config.vaultPath, targetPath)) {
        throw new Error('無効な保存パスです');
      }
    
      const vaultPath = this.config.vaultPath;
      const fullTargetPath = path.join(vaultPath, targetPath);
      
      // ディレクトリを作成
      await FileUtils.ensureDir(path.dirname(fullTargetPath));
    
      // ソースファイルを収集
      const sourceFiles = await this.collectSourceFiles(sourcePattern);
      
      // グループ化
      const groupedFiles = await this.groupFiles(sourceFiles, groupBy);
      
      // MOC内容を生成
      let mocContent = `# ${title}\n\n`;
      mocContent += `*このMap of Contentsは自動生成されました - ${new Date().toISOString().split('T')[0]}*\n\n`;
    
      if (groupBy === 'none') {
        mocContent += '## 目次\n\n';
        for (const file of sourceFiles) {
          const relativeFilePath = path.relative(vaultPath, file);
          const fileName = path.basename(file, '.md');
          const linkText = `[[${relativeFilePath.replace(/\.md$/, '')}|${fileName}]]`;
          
          if (includeDescription) {
            const description = await this.extractDescription(file);
            mocContent += `- ${linkText}${description ? ` - ${description}` : ''}\n`;
          } else {
            mocContent += `- ${linkText}\n`;
          }
        }
      } else {
        for (const [groupName, files] of Object.entries(groupedFiles)) {
          mocContent += `## ${groupName}\n\n`;
          
          for (const file of files) {
            const relativeFilePath = path.relative(vaultPath, file);
            const fileName = path.basename(file, '.md');
            const linkText = `[[${relativeFilePath.replace(/\.md$/, '')}|${fileName}]]`;
            
            if (includeDescription) {
              const description = await this.extractDescription(file);
              mocContent += `- ${linkText}${description ? ` - ${description}` : ''}\n`;
            } else {
              mocContent += `- ${linkText}\n`;
            }
          }
          mocContent += '\n';
        }
      }
    
      // ファイルを書き込み
      await fs.writeFile(fullTargetPath, mocContent, 'utf-8');
    
      return `Map of Contents '${title}' を '${targetPath}' に作成しました。${sourceFiles.length}個のファイルを含みます。`;
    }
  • src/server.ts:214-246 (registration)
    Registration of the 'create_moc' tool in the MCP server's listTools handler, including name, description, and full input schema definition.
    {
      name: 'create_moc',
      description: 'Map of Contents(目次ノート)を自動生成します',
      inputSchema: {
        type: 'object',
        properties: {
          title: {
            type: 'string',
            description: 'MOCのタイトル',
          },
          targetPath: {
            type: 'string',
            description: 'MOCの保存先パス(vault相対パス)',
          },
          sourcePattern: {
            type: 'string',
            description: '対象ノートのパターン(省略時は全て)',
          },
          groupBy: {
            type: 'string',
            enum: ['tag', 'folder', 'none'],
            description: 'グループ化方法',
            default: 'none',
          },
          includeDescription: {
            type: 'boolean',
            description: '説明を含めるかどうか',
            default: false,
          },
        },
        required: ['title', 'targetPath'],
      },
    },
  • Dispatch handler in the MCP server's CallToolRequestSchema that maps the tool call to the ObsidianHandler.createMoc method with argument casting.
    case 'create_moc':
      const mocResult = await this.obsidianHandler.createMoc(
        args.title as string,
        args.targetPath as string,
        args.sourcePattern as string,
        (args.groupBy as 'tag' | 'folder' | 'none') || 'none',
        (args.includeDescription as boolean) || false
      );
      return {
        content: [{ type: 'text', text: mocResult }],
      };
  • Helper method to collect all Markdown files in the vault or filter by sourcePattern for inclusion in the MOC.
    private async collectSourceFiles(sourcePattern?: string): Promise<string[]> {
      const vaultPath = this.config.vaultPath;
      const allMdFiles = await this.getAllMdFiles(vaultPath);
      
      if (!sourcePattern) {
        return allMdFiles;
      }
      
      // パターンマッチング(簡単な実装)
      return allMdFiles.filter(file => {
        const relativePath = path.relative(vaultPath, file);
        return relativePath.includes(sourcePattern) || 
               path.basename(file).includes(sourcePattern);
      });
    }
  • Helper method to group collected files by folder path or tags extracted from each file for structured MOC generation.
    private async groupFiles(files: string[], groupBy: 'tag' | 'folder' | 'none'): Promise<Record<string, string[]>> {
      if (groupBy === 'none') {
        return { 'All Files': files };
      }
    
      const groups: Record<string, string[]> = {};
    
      for (const file of files) {
        if (groupBy === 'folder') {
          const dir = path.dirname(path.relative(this.config.vaultPath, file));
          const folderName = dir === '.' ? 'ルート' : dir;
          
          if (!groups[folderName]) {
            groups[folderName] = [];
          }
          groups[folderName].push(file);
        } else if (groupBy === 'tag') {
          const tags = await this.extractFileTags(file);
          
          if (tags.length === 0) {
            if (!groups['タグなし']) {
              groups['タグなし'] = [];
            }
            groups['タグなし'].push(file);
          } else {
            for (const tag of tags) {
              if (!groups[tag]) {
                groups[tag] = [];
              }
              groups[tag].push(file);
            }
          }
        }
      }
    
      return groups;
    }
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 'automatically generates' a Map of Contents note, implying a write operation, but doesn't specify permissions needed, whether it overwrites existing files, error handling, or output format. For a tool that likely creates or modifies files, this lack of detail is a significant gap in transparency.

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, clear sentence in Japanese: 'Map of Contents(目次ノート)を自動生成します'. It's front-loaded with the core purpose, has zero wasted words, and is appropriately sized for the tool's complexity. Every part of the sentence earns its place by stating what the tool does.

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 has no annotations and no output schema, the description is incomplete. It doesn't cover behavioral aspects like file creation effects, error cases, or return values. For a tool with 5 parameters that likely modifies the file system, more context is needed to fully understand its operation and implications.

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 description adds no parameter semantics beyond what the input schema provides. Schema description coverage is 100%, with all parameters well-documented in Japanese (e.g., 'MOCのタイトル' for title, 'グループ化方法' for groupBy). The description doesn't explain how parameters interact or provide additional context, so it meets the baseline for high schema coverage.

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: 'Map of Contents(目次ノート)を自動生成します' (automatically generates a Map of Contents/table of contents note). It specifies the verb '自動生成します' (automatically generates) and the resource 'Map of Contents(目次ノート)'. However, it doesn't explicitly differentiate from sibling tools like 'create_note_from_template' or 'update_note', which could also create notes, 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 any prerequisites, context, or exclusions, nor does it compare to sibling tools such as 'create_note_from_template' or 'link_notes'. This leaves the agent with minimal direction on appropriate usage scenarios.

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