Skip to main content
Glama

Git MCP Server

markdown-builder.ts8.71 kB
/** * @fileoverview Markdown builder utility for creating well-structured, semantic markdown content * @module mcp-server/tools/utils/markdown-builder */ /** * Utility class for building well-formatted markdown content with consistent structure. * * This builder provides a fluent API for creating markdown documents with proper * spacing, hierarchy, and semantic structure. It helps eliminate string concatenation * and ensures consistent formatting across all tool response formatters. * * @example * ```typescript * const md = new MarkdownBuilder() * .h1('Commit Created Successfully') * .keyValue('Commit Hash', 'abc123def') * .keyValue('Author', 'John Doe') * .section('Files Changed', () => { * md.list(['file1.ts', 'file2.ts']); * }); * * const markdown = md.build(); * ``` */ export class MarkdownBuilder { private sections: string[] = []; /** * Add a level 1 heading. * @param text - The heading text * @param emoji - Optional emoji to prepend * @returns this builder for chaining */ h1(text: string, emoji?: string): this { const prefix = emoji ? `${emoji} ` : ''; this.sections.push(`# ${prefix}${text}\n\n`); return this; } /** * Add a level 2 heading. * @param text - The heading text * @param emoji - Optional emoji to prepend * @returns this builder for chaining */ h2(text: string, emoji?: string): this { const prefix = emoji ? `${emoji} ` : ''; this.sections.push(`## ${prefix}${text}\n\n`); return this; } /** * Add a level 3 heading. * @param text - The heading text * @param emoji - Optional emoji to prepend * @returns this builder for chaining */ h3(text: string, emoji?: string): this { const prefix = emoji ? `${emoji} ` : ''; this.sections.push(`### ${prefix}${text}\n\n`); return this; } /** * Add a level 4 heading. * @param text - The heading text * @returns this builder for chaining */ h4(text: string): this { this.sections.push(`#### ${text}\n\n`); return this; } /** * Add a bold key-value pair on a single line. * @param key - The key (will be bolded) * @param value - The value * @returns this builder for chaining */ keyValue(key: string, value: string | number | boolean | null): this { const displayValue = value === null ? 'null' : String(value); this.sections.push(`**${key}:** ${displayValue}\n`); return this; } /** * Add a key-value pair without bolding (for less emphasis). * @param key - The key * @param value - The value * @returns this builder for chaining */ keyValuePlain(key: string, value: string | number | boolean | null): this { const displayValue = value === null ? 'null' : String(value); this.sections.push(`${key}: ${displayValue}\n`); return this; } /** * Add a bulleted or numbered list. * @param items - Array of items to list * @param ordered - If true, creates a numbered list * @returns this builder for chaining */ list(items: string[], ordered = false): this { if (items.length === 0) return this; const marker = ordered ? (i: number) => `${i + 1}.` : () => '-'; this.sections.push( items.map((item, i) => `${marker(i)} ${item}`).join('\n') + '\n\n', ); return this; } /** * Add a code block with optional language syntax highlighting. * @param content - The code content * @param language - Optional language identifier (e.g., 'typescript', 'diff', 'json') * @returns this builder for chaining */ codeBlock(content: string, language = ''): this { this.sections.push(`\`\`\`${language}\n${content}\n\`\`\`\n\n`); return this; } /** * Add inline code (backticks). * @param code - The code text * @returns this builder for chaining */ inlineCode(code: string): this { this.sections.push(`\`${code}\``); return this; } /** * Add a paragraph of text. * @param text - The paragraph content * @returns this builder for chaining */ paragraph(text: string): this { this.sections.push(`${text}\n\n`); return this; } /** * Add a blockquote. * @param text - The quoted text * @returns this builder for chaining */ blockquote(text: string): this { const lines = text.split('\n'); const quoted = lines.map((line) => `> ${line}`).join('\n'); this.sections.push(`${quoted}\n\n`); return this; } /** * Add a horizontal rule. * @returns this builder for chaining */ hr(): this { this.sections.push('---\n\n'); return this; } /** * Add a link. * @param text - The link text * @param url - The URL * @returns this builder for chaining */ link(text: string, url: string): this { this.sections.push(`[${text}](${url})`); return this; } /** * Add a table from structured data. * @param headers - Array of column headers * @param rows - Array of rows, each row is an array of cell values * @returns this builder for chaining */ table(headers: string[], rows: string[][]): this { if (headers.length === 0 || rows.length === 0) return this; // Header row this.sections.push(`| ${headers.join(' | ')} |\n`); // Separator row this.sections.push(`| ${headers.map(() => '---').join(' | ')} |\n`); // Data rows rows.forEach((row) => { this.sections.push(`| ${row.join(' | ')} |\n`); }); this.sections.push('\n'); return this; } /** * Add a section with a heading and callback for content. * This is useful for grouping related content. * * @example * ```typescript * md.section('Files Changed', () => { * md.list(['file1.ts', 'file2.ts']); * }); * ``` * * @param title - The section heading * @param level - Heading level (2-4), defaults to 2 * @param content - Callback function to build section content * @returns this builder for chaining */ section(title: string, level: 2 | 3 | 4 = 2, content: () => void): this { switch (level) { case 2: this.h2(title); break; case 3: this.h3(title); break; case 4: this.h4(title); break; } content(); return this; } /** * Add a collapsible details section (HTML details/summary). * Note: Not all markdown renderers support this. * * @param summary - The summary text (always visible) * @param details - The detailed content (collapsed by default) * @returns this builder for chaining */ details(summary: string, details: string): this { this.sections.push(`<details>\n<summary>${summary}</summary>\n\n`); this.sections.push(`${details}\n\n`); this.sections.push(`</details>\n\n`); return this; } /** * Add raw markdown content directly. * Use this for custom formatting not covered by other methods. * * @param markdown - Raw markdown string * @returns this builder for chaining */ raw(markdown: string): this { this.sections.push(markdown); return this; } /** * Add a blank line for spacing. * @returns this builder for chaining */ blankLine(): this { this.sections.push('\n'); return this; } /** * Add text without any formatting or line breaks. * Useful for inline text that will be followed by other inline elements. * * @param text - The text to add * @returns this builder for chaining */ text(text: string): this { this.sections.push(text); return this; } /** * Conditionally add content based on a predicate. * * @example * ```typescript * md.when(files.length > 0, () => { * md.h2('Files Changed').list(files); * }); * ``` * * @param condition - If true, execute the callback * @param content - Callback function to build conditional content * @returns this builder for chaining */ when(condition: boolean, content: () => void): this { if (condition) { content(); } return this; } /** * Build the final markdown string. * Trims trailing whitespace and ensures the document ends cleanly. * * @returns The complete markdown document as a string */ build(): string { return this.sections.join('').trim(); } /** * Reset the builder to start building a new document. * @returns this builder for chaining */ reset(): this { this.sections = []; return this; } } /** * Helper function to create a MarkdownBuilder instance. * Provides a shorter alternative to `new MarkdownBuilder()`. * * @returns A new MarkdownBuilder instance */ export function markdown(): MarkdownBuilder { return new MarkdownBuilder(); }

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/cyanheads/git-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server