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> {
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It describes what the tool returns (expanded code, diagnostics, help text) and its purpose for debugging, but lacks details on error handling, performance implications, or any side effects. It does not contradict annotations, but could benefit from more behavioral context like rate limits or memory usage.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured and front-loaded with the core purpose in the first sentence. Each subsequent section ('Shows:', 'Useful for:') adds value without redundancy, and the bullet points are concise. There is no wasted text, making it efficient for an AI agent to parse.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (transforming code with diagnostics) and no output schema, the description does a good job explaining the return values (expanded code, diagnostics, help text). However, it could be more complete by mentioning potential limitations or edge cases, such as handling invalid input or the scope of macro expansion. With no annotations, it adequately covers the tool's purpose and output but leaves some behavioral gaps.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has 100% description coverage, clearly documenting both parameters ('code' and 'filename'). The description does not add any additional semantic details beyond what the schema provides, such as explaining the format of 'code' or when 'filename' is necessary. Baseline score of 3 is appropriate as the schema does the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the specific action ('Expands Macroforge macros in TypeScript code') and resource ('TypeScript code'), distinguishing it from siblings like 'get-documentation' or 'get-macro-info' by focusing on transformation rather than information retrieval. It explicitly mentions the output ('returns the transformed result') and the context of @derive decorators.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear context for when to use this tool ('Useful for: Seeing what code the macros generate, Understanding how @derive decorators transform your classes, Debugging macro expansion issues'), which helps differentiate it from siblings. However, it does not explicitly state when not to use it or name specific alternatives, such as when to prefer 'macroforge-autofixer' for fixing issues instead of just expanding.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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