Skip to main content
Glama
ishayoyo

Excel MCP Server

by ishayoyo

write_file

Write data to CSV or Excel files with support for multiple sheets, enabling structured data export from the Excel MCP Server.

Instructions

Write data to a new CSV or Excel file (supports multiple sheets for Excel)

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
filePathYesPath for the new file (must end with .csv, .xlsx, or .xls)
dataNoArray of arrays representing rows of data (single sheet mode)
headersNoOptional headers for the first row (single sheet mode)
sheetNoSheet name for Excel files (single sheet mode, defaults to "Sheet1")
sheetsNoArray of sheet objects for multi-sheet Excel files

Implementation Reference

  • Core handler function that executes write_file tool: supports writing to CSV/Excel (.xlsx/.xls), single-sheet with data/headers/sheet, multi-sheet with sheets array using ExcelJS.
    async writeFile(args: ToolArgs): Promise<ToolResponse> {
      const { filePath, data, headers, sheet = 'Sheet1', sheets } = args;
      const ext = path.extname(filePath).toLowerCase();
      const absolutePath = path.resolve(filePath);
    
      // Multi-sheet mode for Excel files
      if (sheets && Array.isArray(sheets)) {
        if (ext === '.csv') {
          throw new Error('CSV format does not support multiple sheets. Use .xlsx or .xls for multi-sheet files.');
        }
    
        if (ext !== '.xlsx' && ext !== '.xls') {
          throw new Error('Multi-sheet mode only works with Excel files (.xlsx or .xls)');
        }
    
        const workbook = new ExcelJS.Workbook();
        let totalRows = 0;
        let totalColumns = 0;
    
        for (const sheetData of sheets) {
          if (!sheetData.data || !Array.isArray(sheetData.data)) {
            throw new Error(`Sheet "${sheetData.name}" must have valid data array`);
          }
    
          const fullData = sheetData.headers
            ? [sheetData.headers, ...sheetData.data]
            : sheetData.data;
    
          if (fullData.length === 0) {
            // Add empty row if no data
            fullData.push([]);
          }
    
          const worksheet = workbook.addWorksheet(sheetData.name);
          fullData.forEach((row: any[]) => {
            worksheet.addRow(row);
          });
    
          totalRows += fullData.length;
          if (fullData.length > 0 && Array.isArray(fullData[0])) {
            totalColumns = Math.max(totalColumns, fullData[0].length || 0);
          }
        }
    
        await workbook.xlsx.writeFile(absolutePath);
    
        return {
          content: [
            {
              type: 'text',
              text: JSON.stringify({
                success: true,
                filePath: absolutePath,
                mode: 'multi-sheet',
                sheetsWritten: sheets.length,
                sheetNames: sheets.map(s => s.name),
                totalRowsWritten: totalRows,
                maxColumnsWritten: totalColumns,
              }, null, 2),
            },
          ],
        };
      }
    
      // Single sheet mode (backward compatible)
      if (!data || !Array.isArray(data)) {
        throw new Error('Either "data" (for single sheet) or "sheets" (for multiple sheets) must be provided.');
      }
    
      const fullData = headers ? [headers, ...data] : data;
    
      if (ext === '.csv') {
        // Write CSV file
        const csvContent = csvStringify.stringify(fullData);
        await fs.writeFile(absolutePath, csvContent, 'utf-8');
      } else if (ext === '.xlsx' || ext === '.xls') {
        // Write Excel file
        const workbook = new ExcelJS.Workbook();
        const worksheet = workbook.addWorksheet(sheet);
        fullData.forEach((row: any[]) => {
          worksheet.addRow(row);
        });
        await workbook.xlsx.writeFile(absolutePath);
      } else {
        throw new Error('Unsupported file format. Please use .csv, .xlsx, or .xls extension.');
      }
    
      return {
        content: [
          {
            type: 'text',
            text: JSON.stringify({
              success: true,
              filePath: absolutePath,
              mode: 'single-sheet',
              sheetName: ext === '.csv' ? null : sheet,
              rowsWritten: fullData.length,
              columnsWritten: fullData[0]?.length || 0,
            }, null, 2),
          },
        ],
      };
    }
  • Input schema definition for write_file tool in the MCP tools list, specifying parameters like filePath (required), data, headers, sheet, and optional sheets for multi-sheet Excel files.
    name: 'write_file',
    description: 'Write data to a new CSV or Excel file (supports multiple sheets for Excel)',
    inputSchema: {
      type: 'object',
      properties: {
        filePath: {
          type: 'string',
          description: 'Path for the new file (must end with .csv, .xlsx, or .xls)',
        },
        data: {
          type: 'array',
          description: 'Array of arrays representing rows of data (single sheet mode)',
          items: {
            type: 'array',
          },
        },
        headers: {
          type: 'array',
          description: 'Optional headers for the first row (single sheet mode)',
          items: {
            type: 'string',
          },
        },
        sheet: {
          type: 'string',
          description: 'Sheet name for Excel files (single sheet mode, defaults to "Sheet1")',
        },
        sheets: {
          type: 'array',
          description: 'Array of sheet objects for multi-sheet Excel files',
          items: {
            type: 'object',
            properties: {
              name: {
                type: 'string',
                description: 'Sheet name',
              },
              data: {
                type: 'array',
                description: 'Array of arrays representing rows of data',
                items: {
                  type: 'array',
                },
              },
              headers: {
                type: 'array',
                description: 'Optional headers for the first row',
                items: {
                  type: 'string',
                },
              },
            },
            required: ['name', 'data'],
          },
        },
      },
      required: ['filePath'],
    },
  • src/index.ts:1242-1255 (registration)
    Tool registration in MCP server: imports FileOperationsHandler, instantiates it (line 55), lists schema in ListToolsRequestHandler (536-593), and dispatches calls to fileOpsHandler.writeFile in CallToolRequestSchema switch.
    // File Operations
    case 'write_file':
      return await this.fileOpsHandler.writeFile(toolArgs);
    case 'add_sheet':
      return await this.fileOpsHandler.addSheet(toolArgs);
    case 'write_multi_sheet':
      return await this.fileOpsHandler.writeMultiSheet(toolArgs);
    case 'export_analysis':
      return await this.fileOpsHandler.exportAnalysis(toolArgs);
    case 'format_cells':
      return await this.fileOpsHandler.formatCells(toolArgs);
    case 'auto_fit_columns':
      return await this.fileOpsHandler.autoFitColumns(toolArgs);
Behavior2/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 mentions file creation and format support but fails to address critical behaviors: whether it overwrites existing files, requires specific permissions, handles errors, or has rate limits. For a write operation, this leaves significant gaps in understanding its impact and constraints.

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 a single, efficient sentence that front-loads the core purpose and key capability (multi-sheet support). There is no wasted verbiage, making it easy to parse and understand at a glance.

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

Completeness2/5

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

For a write tool with no annotations and no output schema, the description is incomplete. It lacks details on file overwriting behavior, error handling, format-specific constraints, and response structure. Given the complexity of 5 parameters and the absence of structured safety hints, more context is needed for reliable use.

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?

Schema description coverage is 100%, so the schema fully documents all 5 parameters. The description adds minimal value beyond the schema by implying parameter usage modes (e.g., single vs. multi-sheet), but doesn't clarify mutual exclusivity or provide examples. Baseline 3 is appropriate given the schema's comprehensive coverage.

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

Purpose4/5

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

The description clearly states the action ('Write data') and target resource ('to a new CSV or Excel file'), with the specific capability of supporting multiple sheets for Excel. It distinguishes itself from sibling tools like 'read_file' by specifying a write operation, though it doesn't explicitly differentiate from 'write_multi_sheet' beyond mentioning multi-sheet support.

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

Usage Guidelines2/5

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

The description provides no guidance on when to use this tool versus alternatives like 'write_multi_sheet' or 'add_sheet', nor does it mention prerequisites or exclusions. It lacks context for choosing between single-sheet and multi-sheet modes, leaving usage decisions ambiguous.

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/ishayoyo/excel-mcp'

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