Skip to main content
Glama

expand-code

Expands TypeScript macros and @derive decorators to show generated code with diagnostics for debugging and understanding transformations.

Instructions

Expands Macroforge macros in TypeScript code and returns the transformed result.

Shows:

  • The fully expanded TypeScript code with all generated methods

  • Any diagnostics (errors, warnings, info) with line/column locations

  • Help text for fixing issues (when available)

Useful for:

  • Seeing what code the macros generate

  • Understanding how @derive decorators transform your classes

  • Debugging macro expansion issues

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
codeYesTypeScript code with @derive decorators to expand
filenameNoFilename for the code (default: input.ts)

Implementation Reference

  • The main handler function that implements the 'expand-code' tool. It dynamically imports @macroforge/core, calls expandSync to expand macros in the provided TypeScript code, processes any diagnostics, and returns formatted markdown output containing the expanded code and diagnostic information.
    async function handleExpandCode(args: { code: string; filename?: string }) {
      const filename = args.filename || 'input.ts';
    
      try {
        const macroforge = await importMacroforge();
    
        if (!macroforge) {
          return {
            content: [
              {
                type: 'text' as const,
                text: 'Native Macroforge bindings not available. Install @macroforge/core to enable code expansion.',
              },
            ],
          };
        }
    
        const result = macroforge.expandSync(args.code, filename, {});
        const diagnostics = result.diagnostics || [];
    
        // Build structured output
        const output: ExpandResult = {
          expandedCode: result.code,
          diagnostics: diagnostics.map((d) => ({
            level: normalizeLevel(d.level),
            message: d.message,
            location: d.span?.start,
            help: d.help || undefined,
          })),
          hasErrors: diagnostics.some((d) => d.level === 'Error'),
        };
    
        // Format human-readable text
        let text = `## Expanded Code\n\n\`\`\`typescript\n${result.code}\n\`\`\``;
    
        if (diagnostics.length > 0) {
          text += '\n\n## Diagnostics\n\n';
          for (const d of diagnostics) {
            const loc = d.span ? ` (line ${d.span.start.line}, col ${d.span.start.column})` : '';
            text += `- **[${normalizeLevel(d.level)}]**${loc} ${d.message}\n`;
            if (d.help) {
              text += `  - Help: ${d.help}\n`;
            }
            if (d.notes && d.notes.length > 0) {
              for (const note of d.notes) {
                text += `  - Note: ${note}\n`;
              }
            }
          }
        }
    
        return {
          content: [{ type: 'text' as const, text }],
        };
      } catch (error) {
        const message = error instanceof Error ? error.message : String(error);
        return {
          content: [
            {
              type: 'text' as const,
              text: `Error expanding code: ${message}`,
            },
          ],
        };
      }
  • The tool registration definition in the ListToolsRequestSchema handler, including the tool name, description, and input schema.
            {
              name: 'expand-code',
              description: `Expands Macroforge macros in TypeScript code and returns the transformed result.
    
    Shows:
    - The fully expanded TypeScript code with all generated methods
    - Any diagnostics (errors, warnings, info) with line/column locations
    - Help text for fixing issues (when available)
    
    Useful for:
    - Seeing what code the macros generate
    - Understanding how @derive decorators transform your classes
    - Debugging macro expansion issues`,
              inputSchema: {
                type: 'object',
                properties: {
                  code: {
                    type: 'string',
                    description: 'TypeScript code with @derive decorators to expand',
                  },
                  filename: {
                    type: 'string',
                    description: 'Filename for the code (default: input.ts)',
                  },
                },
                required: ['code'],
              },
            },
  • TypeScript interface defining the structured output format used internally by the expand-code handler.
    interface ExpandResult {
      expandedCode: string;
      diagnostics: Array<{
        /** Severity level: "error", "warning", or "info" */
        level: string;
        /** Human-readable description of the issue */
        message: string;
        /** Source location (line and column) if available */
        location?: { line: number; column: number };
        /** Suggested fix for the issue */
        help?: string;
      }>;
      hasErrors: boolean;
    }
  • Dispatch case in the CallToolRequestSchema handler that routes 'expand-code' calls to the handleExpandCode function.
    case 'expand-code':
      return handleExpandCode(args as { code: string; filename?: string });
  • Helper functions used by the handler: importMacroforge dynamically loads the optional @macroforge/core dependency, and normalizeLevel converts diagnostic levels to lowercase.
      }
    }
    
    /**
     * Handles the `get-macro-info` tool call.
     *
     * Retrieves documentation for Macroforge macros and field decorators from the
     * native manifest. Can return info for a specific macro/decorator or the full
     * manifest of all available macros and decorators.
     *
     * ## Usage Modes
     *
     * - **Without name**: Returns full manifest with all macros and decorators
     * - **With name**: Returns detailed info for the specific macro or decorator
     *
     * ## Manifest Contents
     *
     * - **Macros**: @derive decorators like Debug, Serialize, Clone
     * - **Decorators**: Field decorators like @serde.skip, @serde.rename
     *
     * @param args - Tool arguments
     * @param args.name - Optional macro or decorator name to look up
     * @returns MCP response with formatted macro/decorator documentation
     */
    async function handleGetMacroInfo(args: { name?: string }) {
      try {
        const macroforge = await importMacroforge();
    
        if (!macroforge || !macroforge.__macroforgeGetManifest) {
          return {
            content: [
              {
                type: 'text' as const,
                text: 'Native Macroforge bindings not available. Install @macroforge/core to access macro documentation.',
              },
            ],
          };
        }
    
        const manifest = macroforge.__macroforgeGetManifest();
    
        if (args.name) {
          // Look up specific macro or decorator
          const nameLower = args.name.toLowerCase();
          const macro = manifest.macros.find(m => m.name.toLowerCase() === nameLower);
          const decorator = manifest.decorators.find(d => d.export.toLowerCase() === nameLower);
    
          if (!macro && !decorator) {
            return {
              content: [
                {
                  type: 'text' as const,
                  text: `No macro or decorator found with name "${args.name}".
    
    Available macros: ${manifest.macros.map(m => m.name).join(', ')}
    Available decorators: ${manifest.decorators.map(d => d.export).join(', ')}`,
                },
              ],
            };
          }
    
          let result = '';
    
          if (macro) {
            result += `## Macro: @derive(${macro.name})\n\n`;
            result += `**Description:** ${macro.description || 'No description available'}\n`;
            result += `**Kind:** ${macro.kind}\n`;
            result += `**Package:** ${macro.package}\n`;
          }
    
          if (decorator) {
            if (result) result += '\n---\n\n';
            result += `## Decorator: @${decorator.export}\n\n`;
            result += `**Documentation:** ${decorator.docs || 'No documentation available'}\n`;
            result += `**Kind:** ${decorator.kind}\n`;
            result += `**Module:** ${decorator.module}\n`;
          }
    
          return {
            content: [{ type: 'text' as const, text: result }],
          };
        }
    
        // Return full manifest
        let result = '# Macroforge Macro Manifest\n\n';
    
        result += '## Available Macros\n\n';
        for (const macro of manifest.macros) {
          result += `### @derive(${macro.name})\n`;
          result += `${macro.description || 'No description'}\n\n`;
        }
    
        if (manifest.decorators.length > 0) {
          result += '## Available Field Decorators\n\n';
          for (const decorator of manifest.decorators) {
            result += `### @${decorator.export}\n`;
            result += `${decorator.docs || 'No documentation'}\n\n`;
          }
        }
    
        return {
          content: [{ type: 'text' as const, text: result }],
        };
      } catch (error) {
        const message = error instanceof Error ? error.message : String(error);
        return {
          content: [
            {
              type: 'text' as const,
              text: `Error getting macro info: ${message}`,
            },
          ],
        };
      }
    }
    
    // ============================================================================
    // Types - Match Rust's Diagnostic structure from macroforge_ts_syn/src/abi/patch.rs
    // ============================================================================
    
    /**
     * Represents a location span in source code.
     *
     * Used by diagnostics to indicate where an error or warning occurred.
     * Matches the Rust `Span` type from the macroforge_ts_syn crate.
     *
     * @property start - Starting position (line and column, 1-indexed)
     * @property end - Ending position (line and column, 1-indexed)
     */
    interface DiagnosticSpan {
      start: { line: number; column: number };
      end: { line: number; column: number };
    }
    
    /**
     * Represents a diagnostic message from the Macroforge analyzer.
     *
     * Diagnostics are produced during code validation and expansion to report
     * errors, warnings, and informational messages. Matches the Rust `Diagnostic`
     * type from macroforge_ts_syn/src/abi/patch.rs.
     *
     * @property level - Severity level: 'Error', 'Warning', or 'Info'
     * @property message - Human-readable description of the issue
     * @property span - Optional source location where the issue occurred
     * @property notes - Additional context or explanatory notes
     * @property help - Optional suggestion for how to fix the issue
     */
    interface Diagnostic {
      level: 'Error' | 'Warning' | 'Info';
      message: string;
      span?: DiagnosticSpan;
      notes: string[];
      help?: string;
    }
    
    /**
     * Metadata for a Macroforge macro in the manifest.
     *
     * Describes a @derive macro that can be applied to classes.
     *
     * @property name - Macro name as used in @derive (e.g., "Debug", "Serialize")
     * @property kind - Type of macro (e.g., "derive")
     * @property description - Human-readable description of what the macro does
     * @property package - Package that provides this macro
     */
    interface MacroManifestEntry {
      name: string;
      kind: string;
      description: string;
      package: string;
    }
    
    /**
     * Metadata for a field decorator in the manifest.
     *
     * Describes a decorator that can be applied to class fields to customize
     * macro behavior (e.g., @serde.skip, @debug.format).
     *
     * @property module - Module path where the decorator is defined
     * @property export - Export name of the decorator
     * @property kind - Type of decorator (e.g., "field")
     * @property docs - Documentation string for the decorator
     */
    interface DecoratorManifestEntry {
      module: string;
      export: string;
      kind: string;
      docs: string;
    }
    
    /**
     * Complete manifest of available Macroforge macros and decorators.
     *
     * Returned by the native bindings to provide documentation and metadata
     * for all available macros and field decorators.
     *
     * @property version - Manifest format version
     * @property macros - Array of available @derive macros
     * @property decorators - Array of available field decorators
     */
    interface MacroManifest {
      version: number;
      macros: MacroManifestEntry[];
      decorators: DecoratorManifestEntry[];
    }
    
    /**
     * Interface for the native Macroforge module (@macroforge/core).
     *
     * Defines the expected API surface of the optional native bindings that
     * provide code validation, expansion, and manifest access.
     *
     * @property expandSync - Synchronously expands macros in TypeScript code
     * @property __macroforgeGetManifest - Optional function to retrieve the macro manifest
     */
    interface MacroforgeModule {
      /**
       * Synchronously expands Macroforge macros in TypeScript code.
       *
       * @param code - TypeScript source code with @derive decorators
       * @param filename - Filename for error reporting
       * @param options - Expansion options (currently unused)
       * @returns Object with expanded code and any diagnostics
       */
      expandSync: (code: string, filename: string, options: object) => {
        code: string;
        diagnostics?: Diagnostic[];
      };
    
      /**
       * Retrieves the macro manifest with all available macros and decorators.
       * Optional - may not be available in all versions.
       */
      __macroforgeGetManifest?: () => MacroManifest;
    }
    
    // ============================================================================
    // Output types for structured responses
    // ============================================================================
    
    /**
     * Structured output format for the `macroforge-autofixer` tool.
     *
     * Provides a JSON response that clients can parse to display errors,
     * navigate to problem locations, and determine if re-validation is needed.
     *
     * @property diagnostics - Array of diagnostic messages with locations
     * @property summary - Counts of errors, warnings, and info messages
     * @property require_another_tool_call_after_fixing - True if errors exist and client should revalidate after fixing
     */
    interface AutofixerResult {
      diagnostics: Array<{
        /** Severity level: "error", "warning", or "info" */
        level: string;
        /** Human-readable description of the issue */
        message: string;
        /** Source location (line and column) if available */
        location?: { line: number; column: number };
        /** Suggested fix for the issue */
        help?: string;
        /** Additional context or explanatory notes */
        notes?: string[];
      }>;
      /** Summary counts for quick overview */
      summary: {
        errors: number;
        warnings: number;
        info: number;
      };
      /** If true, client should fix issues and call autofixer again */
      require_another_tool_call_after_fixing: boolean;
    }
    
    /**
     * Structured output format for the `expand-code` tool.
     *
     * Contains the fully expanded code along with any diagnostics produced
     * during expansion.
     *
     * @property expandedCode - The TypeScript code after macro expansion
     * @property diagnostics - Array of diagnostic messages from expansion
     * @property hasErrors - True if any error-level diagnostics were produced
     */
    interface ExpandResult {
      expandedCode: string;
      diagnostics: Array<{
        /** Severity level: "error", "warning", or "info" */
        level: string;
        /** Human-readable description of the issue */
        message: string;
        /** Source location (line and column) if available */
        location?: { line: number; column: number };
        /** Suggested fix for the issue */
        help?: string;
      }>;
      hasErrors: boolean;
    }
    
    // ============================================================================
    // Helper functions
    // ============================================================================
    
    /**
     * Dynamically imports the native Macroforge bindings.
     *
     * The @macroforge/core package is an optional peer dependency that provides
     * native Rust-based code analysis and expansion. This function attempts to
     * load it at runtime and gracefully returns null if unavailable.
     *
     * Using dynamic import allows the MCP server to run and serve documentation
     * even when the native bindings are not installed.
     *
     * @returns The Macroforge module if available, or null if not installed
     *
     * @example
     * ```typescript
     * const macroforge = await importMacroforge();
     * if (macroforge) {
     *   const result = macroforge.expandSync(code, 'input.ts', {});
     * }
     * ```
     */
    async function importMacroforge(): Promise<MacroforgeModule | null> {

Latest Blog Posts

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/macroforge-ts/mcp-server'

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