create_moc
Automatically generates a Map of Contents (MOC) note in Obsidian to organize and link related notes based on tags, folders, or patterns.
Instructions
Map of Contents(目次ノート)を自動生成します
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| title | Yes | MOCのタイトル | |
| targetPath | Yes | MOCの保存先パス(vault相対パス) | |
| sourcePattern | No | 対象ノートのパターン(省略時は全て) | |
| groupBy | No | グループ化方法 | none |
| includeDescription | No | 説明を含めるかどうか |
Implementation Reference
- src/obsidian-handler.ts:622-681 (handler)The core handler function implementing the create_moc tool. It generates a Map of Contents (MOC) note by collecting source files, grouping them if specified, generating wiki links, and writing the MOC file to the target path.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:215-246 (schema)The input schema definition for the create_moc tool, specifying parameters like title, targetPath, sourcePattern, groupBy, and includeDescription.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'], }, },
- src/server.ts:365-376 (registration)The registration and dispatching logic in the CallToolRequest handler that invokes the createMoc method on ObsidianHandler for the 'create_moc' tool.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 }], };
- src/obsidian-handler.ts:683-697 (helper)Helper method to collect source Markdown files matching the optional sourcePattern, used by createMoc.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); }); }
- src/obsidian-handler.ts:699-735 (helper)Helper method to group collected files by tag or folder for the MOC generation, used by createMoc.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; }