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
| 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)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'], }, },
- src/server.ts:365-375 (handler)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 }], };
- src/obsidian-handler.ts:683-697 (helper)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); }); }
- src/obsidian-handler.ts:699-735 (helper)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; }