@macroforge/mcp-server
Version:
MCP server for Macroforge documentation and code analysis
162 lines (161 loc) • 6.5 kB
TypeScript
/**
* @module docs-loader
*
* Documentation Loading and Search Utilities
*
* This module provides functionality for loading, searching, and retrieving
* Macroforge documentation sections. Documentation is stored as markdown files
* with metadata in `docs/sections.json`.
*
* Key features:
* - Eagerly loads documentation sections (metadata and content) from disk at startup
* - Supports multiple search strategies (exact, partial, fuzzy, category)
* - Handles chunked documentation for large sections
* - Provides type-safe interfaces for documentation structure
*
* @example
* ```typescript
* import { loadSections, getSection, searchSections } from './docs-loader.ts';
*
* const sections = loadSections();
* const debug = getSection(sections, 'debug');
* const matches = searchSections(sections, 'serialization');
* ```
*/
/**
* Represents a documentation section with metadata and optional content.
*
* Sections can be standalone or part of a chunked hierarchy for large documents.
* Chunked sections have a parent entry with `is_chunked: true` and child entries
* with `parent_id` pointing to the parent.
*
* @property id - Unique identifier for the section (e.g., "debug", "serde-validators")
* @property title - Human-readable title displayed to users
* @property category - Category slug for grouping (e.g., "macros", "guides")
* @property category_title - Human-readable category name
* @property path - Relative path to the markdown content file from docs directory
* @property use_cases - Comma-separated keywords describing when this doc is useful
* @property content - The actual markdown content (loaded eagerly by loadSections, undefined for chunked parents)
* @property is_chunked - True if this section is split into multiple sub-chunks
* @property parent_id - For sub-chunks, the ID of the parent section
* @property chunk_ids - For chunked parents, ordered list of child chunk IDs
*/
export interface Section {
id: string;
title: string;
category: string;
category_title: string;
path: string;
use_cases: string;
content?: string;
is_chunked?: boolean;
parent_id?: string;
chunk_ids?: string[];
}
/**
* Loads all documentation sections from the docs directory.
*
* This function reads `docs/sections.json` for metadata and loads the markdown
* content for each section from disk. Chunked parent sections do not have their
* content loaded directly - their content is accessed through child chunks.
*
* @returns Array of Section objects with content loaded. Returns empty array if
* sections.json is not found (with a warning logged to stderr).
* @throws When sections.json lists a markdown file that does not exist.
*
* @example
* ```typescript
* const sections = loadSections();
* console.log(`Loaded ${sections.length} sections`);
* ```
*/
export declare function loadSections(): Section[];
/**
* Finds a section by ID or title using progressive matching strategies.
*
* The function attempts to match in the following order (stopping at first match):
* 1. Exact ID match (case-insensitive)
* 2. Exact title match (case-insensitive)
* 3. Partial ID match (query is substring of ID)
* 4. Partial title match (query is substring of title)
*
* @param sections - Array of sections to search through
* @param query - Search query (ID or title to find)
* @returns The first matching Section, or undefined if no match found
*
* @example
* ```typescript
* const debug = getSection(sections, 'debug'); // Exact ID match
* const serde = getSection(sections, 'Serialize'); // Exact title match
* const partial = getSection(sections, 'valid'); // Partial match on "validators"
* ```
*/
export declare function getSection(sections: Section[], query: string): Section | undefined;
/**
* Retrieves multiple sections by their IDs or titles.
*
* Uses {@link getSection} for each query, deduplicating results if the same
* section matches multiple queries.
*
* @param sections - Array of sections to search through
* @param queries - Array of search queries (IDs or titles)
* @returns Array of unique matching Sections in the order they were found
*
* @example
* ```typescript
* const docs = getSections(sections, ['debug', 'serialize', 'clone']);
* // Returns all three sections if found
* ```
*/
export declare function getSections(sections: Section[], queries: string[]): Section[];
/**
* Performs a fuzzy search across sections using a weighted scoring algorithm.
*
* The search splits the query into keywords and scores each section based on
* where matches are found. Results are sorted by relevance score (highest first).
*
* ## Scoring Algorithm
*
* Each section is scored based on matches in different fields:
* - **ID match** (+10): Full query found in section ID
* - **Title match** (+10): Full query found in section title
* - **Use cases match** (+5 per keyword): Each query keyword found in use_cases
* - **Content match** (+1 per keyword): Each query keyword found in content
*
* The higher weights for ID/title ensure exact matches rank above content matches.
* Use cases are weighted moderately as they indicate intended use.
*
* @param sections - Array of sections to search through
* @param query - Search query (can contain multiple space-separated keywords)
* @returns Array of matching Sections sorted by relevance score (highest first)
*
* @example
* ```typescript
* // Single keyword search
* const results = searchSections(sections, 'validation');
*
* // Multi-keyword search (scores sections matching more keywords higher)
* const results = searchSections(sections, 'email url length');
* ```
*/
export declare function searchSections(sections: Section[], query: string): Section[];
/**
* Filters sections by category slug or category title.
*
* Matches against both `category` (slug) and `category_title` (display name)
* to support flexible lookups.
*
* @param sections - Array of sections to filter
* @param category - Category slug or title to filter by (case-insensitive)
* @returns Array of Sections belonging to the specified category
*
* @example
* ```typescript
* // Filter by category slug
* const macros = getSectionsByCategory(sections, 'macros');
*
* // Filter by category title
* const guides = getSectionsByCategory(sections, 'Getting Started');
* ```
*/
export declare function getSectionsByCategory(sections: Section[], category: string): Section[];