index_build
Build a searchable index from a root directory, enabling local LLMs to retrieve documents for context-aware responses.
Instructions
Alias of index.build
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| root | No |
Implementation Reference
- src/tools/doc.ts:58-76 (handler)The core handler function for indexBuild. It collects text files (.txt, .md, .html, .pdf) from the sandbox directory (or a given root), reads each file's content, creates a MiniSearch full-text index, and persists the index to .cache/index.json.
export async function indexBuild(root?: string) { const base = root ? path.resolve(root) : CONFIG.sandboxDir; const files = await collectFiles(base); const docs: DocRecord[] = []; for (const p of files) { const { title, text } = await fileToText(p); docs.push({ id: p, path: p, title, text }); } const mini = new MiniSearch({ fields: ['title','text'], storeFields: ['path','title'], searchOptions: { boost: { title: 2 } } }); mini.addAll(docs); const payload = { docs, index: mini.toJSON() }; await fs.mkdir(path.dirname(INDEX_PATH), { recursive: true }).catch(()=>{}); await fs.writeFile(INDEX_PATH, JSON.stringify(payload)); return { ok: true, indexed: docs.length }; } - src/server.ts:142-142 (schema)Schema definition for index.build / index_build: accepts an optional 'root' string parameter.
const indexBuildShape = { root: z.string().optional() }; - src/server.ts:143-149 (registration)Registration of the 'index.build' tool (dotted name) on the MCP server, mapping to the indexBuild handler.
server.tool('index.build', 'Build MiniSearch index for documents in sandbox directory.', indexBuildShape, OPEN, async ({ root }) => { const res = await indexBuild(root); return { content: [{ type: 'text', text: JSON.stringify(res) }] }; } ); - src/server.ts:150-156 (registration)Registration of the 'index_build' alias (underscore name) on the MCP server, also mapping to the indexBuild handler.
server.tool('index_build', 'Alias of index.build', indexBuildShape, OPEN, async ({ root }) => { const res = await indexBuild(root); return { content: [{ type: 'text', text: JSON.stringify(res) }] }; } ); - src/tools/doc.ts:27-39 (helper)Helper function collectFiles: recursively walks a directory and collects file paths matching .txt, .md, .html, or .pdf extensions.
async function collectFiles(root: string): Promise<string[]> { const out: string[] = []; async function walk(dir: string) { const ents = await fs.readdir(dir, { withFileTypes: true }); for (const e of ents) { const p = path.join(dir, e.name); if (e.isDirectory()) await walk(p); else if (/(\.txt|\.md|\.html?|\.pdf)$/i.test(e.name)) out.push(p); } } await walk(root); return out; } - src/tools/doc.ts:41-56 (helper)Helper function fileToText: reads a file and extracts its title and text content, handling .pdf (via pdf-parse), .html (via JSDOM + Readability), and plain text files.
async function fileToText(p: string): Promise<{ title: string, text: string }> { const buf = await fs.readFile(p); const name = path.basename(p); if (/\.pdf$/i.test(p)) { try { const parsed = await pdfParseLazy(buf as unknown as Buffer); return { title: name, text: parsed.text || '' }; } catch { return { title: name, text: '' }; } } const s = buf.toString('utf-8'); if (/\.html?$/i.test(p)) { const dom = new JSDOM(s, { url: 'file://' + p }); const reader = new Readability(dom.window.document); const art = reader.parse(); return { title: art?.title || name, text: art?.textContent || dom.window.document.body.textContent || s }; } return { title: name, text: s }; }