* Refactor README files: Simplify language in ExcelMcp.ComInterop and remove ExcelMcp.Core documentation * chore: Remove references to COMMANDS.md in documentation and workflows, update to README.md or component documentation * chore: Update documentation references to CLI and remove obsolete CLI.md file * feat(cli): implement 38 missing command wrappers and sync online help Implementation (38 commands): - Range: Add 33 commands (copy-values/formulas, insert/delete cells/rows/columns, find/replace/sort, discovery, hyperlinks, styles/validation, merge/autofit, advanced) - Table: Add 2 commands (get/set-column-format) - QueryTable: Add 3 commands (create-from-connection/query, update-properties) - PivotTable: Document 7 blocked methods with technical context Routing & Help: - Add 38 routing entries in Program.cs switch statement - Update ShowHelp() function with all 38 commands: * Range: Reorganize into 8 subsections for clarity * Table: Add 2 column format commands * QueryTable: Add 3 create/update commands - Grow Program.cs from 554 to 608 lines (+9.7%) Documentation: - Update CLI README: 109 → 147 commands - Update category counts: Range (11→44), Table (21→23), QueryTable (5→8) - Update MCP Server README: CLI reference now shows 147 commands - Document PivotTable limitations in code comments Status: 38/45 commands complete (84.4%) - Implemented: 38 (Range: 33, Table: 2, QueryTable: 3) - Blocked: 7 (PivotTable methods awaiting file manipulation support) Fixes: - Correct property names in RangeCommands (Address vs Url, ScreenTip vs Tooltip) - Fix hyperlink removal logic (target address calculation) - Replace ToLowerInvariant() with StringComparison.OrdinalIgnoreCase for CA1862 - Ensure consistent formatting throughout Zero compilation errors, all tests passing. * refactor(release): unify MCP Server and CLI releases, optimize copilot instructions Release Workflow Changes: - Rename release-mcp-server.yml to handle both MCP Server and CLI - Change tag pattern: mcp-v* → v* (unified versioning) - MCP Server and CLI always release together with same version - Single workflow builds and publishes both NuGet packages - GitHub release includes both ZIP packages - Delete obsolete workflows: * release-cli.yml (merged into unified workflow) * release-core.yml (no longer publishing Core to NuGet) * release-cominterop.yml (no longer publishing ComInterop to NuGet) Copilot Instructions Optimization: - copilot-instructions.md: 184→132 lines (-28%) * Replace verbose navigation with priority-based structure * Consolidate code patterns (remove redundant comments) * Compress 28 lesson paragraphs → 7 one-line takeaways * Simplify path-specific explanation - critical-rules.instructions.md: Add usage-based priority table * Group rules by context: Every Edit, Writing Code, Writing Tests, Before Commit, PR Process, Rare * Replace flat list with contextual grouping for 10x faster scanning * Add 'Why Critical' column for each rule Benefits: - Simplified release process: One tag (v1.2.3) releases both packages - Version consistency: MCP Server and CLI stay in sync - Reduced CI/CD complexity: 3 fewer workflows to maintain - Better LLM efficiency: 28% less token usage in main instructions - Faster rule lookup: O(1) with priority table vs linear scan * docs: update release documentation for unified v* versioning - Updated RELEASE-STRATEGY.md: Removed separate Core/ComInterop/MCP/CLI sections, added unified MCP+CLI release section - Updated NUGET-GUIDE.md: Changed to unified v* tag pattern, combined package documentation - Updated MCP_REGISTRY_PUBLISHING.md: Changed mcp-v* to v* tag pattern - All docs now reflect simplified release strategy (MCP Server + CLI always released together) * docs: update development-workflow instructions for unified versioning - Changed tag pattern from separate mcp-v*/cli-v* to unified v* - Reflects simplified release strategy (MCP Server + CLI together) * Remove redundant CheckIfOpen action FileAction.CheckIfOpen was redundant because ExcelBatch already checks if files are locked before opening Excel COM (via FileAccessValidator. ValidateFileNotLocked). Operations fail gracefully with clear error messages when files are open, eliminating need for pre-flight checks. Changes: - Remove CheckIfOpen from FileAction enum - Remove CheckIfOpen implementation (75 lines) - Remove CheckIfOpen from ActionExtensions mapping - Update audit scripts to remove CheckIfOpen exceptions - Update excel_file.md prompt to document automatic lock detection - Update ExcelFileTool [Description] to remove CheckIfOpen guidance Benefits: - Simpler architecture with less mental load for LLMs - One less action to learn and maintain - Automatic error handling with actionable user guidance - Consistent with batch mechanism that already handles this Fixes: MCP Server test failures (missing enum mapping) * Optimize instruction files for expert LLM audience - Eliminate duplication across all 13 instruction files - Remove beginner content and explanatory 'why' sections - Establish expert tone throughout (assumes C#, Excel, COM knowledge) - Consolidate test commands to testing-strategy (single source of truth) - Cross-reference instead of duplicating content (WithExcel, SaveAsync, workflows) - Major rewrites: bug-fixing (416→82), documentation-structure (355→86), mcp-llm-guidance (414→152), mcp-server-guide (282→192) - Result: Most files now under 200 lines, focused on project-specific patterns only * Update MCP Server README: emphasize RPA/CLI capabilities and simplify installation - Add RPA (Robotic Process Automation) terminology for CLI automation use cases - Remove specific command counts that change frequently - Simplify installation section to prioritize VS Code Extension - Add CLI example use case for version control workflows - Update resources section with RPA/CI/CD focus * feat: improve SEO with GitHub Pages docs and enhanced server.json description * feat: Improve SEO and add comprehensive installation guide - Add GitHub repository topics (20 relevant tags for discoverability) - Update GitHub repository description for better search results - Enable GitHub Pages with docs/index.md landing page - Enhance MCP Registry server.json description - Improve NuGet package metadata with comprehensive tags - Add REPL developer callout and interactive development messaging - Create comprehensive INSTALLATION.md guide - Fix VS Code marketplace extension ID (sbroenne.excel-mcp) - Add Critical Rule 20: Never commit automatically - Update README and docs to mention both MCP Server and CLI prominently --------- Co-authored-by: Stefan Broenner <stefan.broenner@microsoft.comm>
67 KiB
Excel Formatting & Data Validation Specification
Comprehensive formatting and validation capabilities for ranges, formulas, and tables
🤖 Primary Audience: LLMs using MCP Server tools for professional Excel automation
What This Spec Provides (For LLMs)
This specification consolidates and extends formatting and data validation across all Excel operations:
Number Formatting - Professional Data Display
- Currency, percentages, dates, custom formats - Make data readable
- Get/Set operations - Read existing formats or apply new ones
- Bulk operations - Format entire ranges or table columns efficiently
- Common use: Format sales reports, financial dashboards, date columns, percentages
Visual Formatting - Professional Appearance
- Fonts - Family, size, bold, italic, color, underline, strikethrough
- Cell appearance - Background colors, borders, patterns
- Alignment - Horizontal, vertical, text wrapping, indentation, rotation
- Common use: Headers, highlighting, color-coding, readability improvements
Data Validation - Data Integrity
- Dropdown lists - Restrict input to predefined values
- Number ranges - Min/max validation (whole numbers, decimals, dates, times)
- Text length - Character limits
- Custom formulas - Complex validation rules
- Error alerts - Custom messages for invalid data
- Common use: Data entry forms, quality control, preventing errors
Why You Need These Tools
When users ask you to "format the sales report" or "add dropdowns for status," you'll use these commands to:
- Create professional-looking spreadsheets with proper number formats
- Apply visual styling (colors, fonts, borders) for readability
- Ensure data quality with validation rules
- Build user-friendly data entry interfaces
Current State Analysis
✅ What EXISTS Today
Range Operations (Phase 1 - Implemented):
- ✅ Get/Set values and formulas
- ✅ Clear operations (all, contents, formats)
- ✅ Copy operations (all, values, formulas)
- ✅ Insert/delete cells/rows/columns
- ✅ Find/replace
- ✅ Sort
- ✅ Hyperlinks
- ✅ UsedRange, CurrentRegion, RangeInfo
Table Operations (Implemented):
- ✅ Lifecycle (create, rename, delete, info, resize)
- ✅ Style management (SetStyleAsync)
- ✅ Totals row management
- ✅ Filtering (apply, clear, get state)
- ✅ Column operations (add, remove, rename)
- ✅ Sorting (single and multi-column)
- ✅ Structured references
- ✅ Append rows
PivotTable Operations (Phase 1 - Implemented):
- ✅ Lifecycle (create, delete, list, info)
- ✅ Field management (add/remove/move fields in all areas)
- ✅ Field formatting (SetFieldFormatAsync for number formats)
- ✅ Layout management (SetLayoutAsync - Compact, Outline, Tabular)
- ✅ Style management (SetStyleAsync - 28 built-in styles)
- ✅ Data analysis (refresh, filter, sort)
❌ What's MISSING Today
Number Formatting:
- ❌ Get number formats from ranges
- ❌ Set number formats (uniform or cell-by-cell)
- ❌ Common format presets (currency, percentage, date patterns)
- ❌ Table column number formatting
Visual Formatting:
- ❌ Font properties (name, size, bold, italic, color, underline, strikethrough)
- ❌ Cell background colors
- ❌ Borders (styles, weights, colors)
- ❌ Alignment (horizontal, vertical, wrap, indent, rotation)
- ❌ Row height / column width
- ❌ Auto-fit columns/rows
Data Validation:
- ❌ Add validation rules to ranges
- ❌ Get validation settings from cells
- ❌ Remove validation
- ❌ All validation types (list, whole, decimal, date, time, text-length, custom)
- ❌ Error alerts and input messages
- ❌ Table column validation
Advanced:
- ❌ Conditional formatting
- ❌ Cell merge/unmerge
- ❌ Cell locking for protection
Note: PivotTable formatting (field formats, layouts, styles) is fully implemented and functional.
Target Architecture
Design Principles
- LLM-First Design - Optimized for AI automation workflows
- Breaking Changes Acceptable - Clean API > backwards compatibility
- Unified Approach - Consistent patterns across ranges and tables
- Excel COM Native - Use native Excel capabilities, no custom processing
- Performance Optimized - Batch operations where possible
Proposed Command Structure
Formatting & Validation Commands:
├── RangeCommands (extends existing)
│ ├── Number Formatting (3 methods)
│ ├── Visual Formatting (8 methods)
│ └── Data Validation (4 methods)
│
└── TableCommands (extends existing)
├── Number Formatting (2 methods)
├── Visual Formatting (4 methods - via ranges)
└── Data Validation (2 methods)
Philosophy:
- RangeCommands = Low-level, works anywhere
- TableCommands = High-level, table-specific convenience methods that delegate to RangeCommands
Proposed API Design
1. Range Number Formatting
public interface IRangeCommands
{
// === NUMBER FORMAT OPERATIONS ===
/// <summary>
/// Gets number format codes from range (2D array matching range dimensions)
/// Excel COM: Range.NumberFormat
/// </summary>
/// <returns>2D array of format codes (e.g., [["$#,##0.00", "0.00%"], ["m/d/yyyy", "General"]])</returns>
Task<RangeNumberFormatResult> GetNumberFormatsAsync(IExcelBatch batch, string sheetName, string rangeAddress);
/// <summary>
/// Sets uniform number format for entire range
/// Excel COM: Range.NumberFormat = formatCode
/// </summary>
/// <param name="formatCode">
/// Excel format code (e.g., "$#,##0.00", "0.00%", "m/d/yyyy", "General", "@")
/// See NumberFormatPresets class for common patterns
/// </param>
Task<OperationResult> SetNumberFormatAsync(IExcelBatch batch, string sheetName, string rangeAddress, string formatCode);
/// <summary>
/// Sets number formats cell-by-cell from 2D array
/// Excel COM: Range.NumberFormat (per cell)
/// </summary>
/// <param name="formats">2D array of format codes matching range dimensions</param>
Task<OperationResult> SetNumberFormatsAsync(IExcelBatch batch, string sheetName, string rangeAddress, List<List<string>> formats);
}
/// <summary>
/// Common Excel number format codes for LLM convenience
/// </summary>
public static class NumberFormatPresets
{
// Currency
public const string Currency = "$#,##0.00";
public const string CurrencyNoDecimals = "$#,##0";
public const string CurrencyNegativeRed = "$#,##0.00_);[Red]($#,##0.00)";
// Percentages
public const string Percentage = "0.00%";
public const string PercentageNoDecimals = "0%";
public const string PercentageOneDecimal = "0.0%";
// Dates
public const string DateShort = "m/d/yyyy";
public const string DateLong = "mmmm d, yyyy";
public const string DateMonthYear = "mmm yyyy";
public const string DateDayMonth = "dd/mm/yyyy";
// Times
public const string Time12Hour = "h:mm AM/PM";
public const string Time24Hour = "h:mm";
public const string DateTime = "m/d/yyyy h:mm";
// Numbers
public const string Number = "#,##0.00";
public const string NumberNoDecimals = "#,##0";
public const string NumberOneDecimal = "#,##0.0";
public const string Scientific = "0.00E+00";
// Special
public const string Text = "@";
public const string Fraction = "# ?/?";
public const string Accounting = "_($* #,##0.00_);_($* (#,##0.00);_($* \"-\"??_);_(@_)";
public const string General = "General";
}
// Result type
public class RangeNumberFormatResult : ResultBase
{
public string SheetName { get; set; } = string.Empty;
public string RangeAddress { get; set; } = string.Empty;
/// <summary>
/// 2D array of number format codes (matches range dimensions)
/// </summary>
public List<List<string>> Formats { get; set; } = [];
public int RowCount { get; set; }
public int ColumnCount { get; set; }
}
2. Range Visual Formatting
public interface IRangeCommands
{
// === FONT OPERATIONS ===
/// <summary>
/// Gets font properties from first cell in range
/// Excel COM: Range.Font
/// </summary>
Task<RangeFontResult> GetFontAsync(IExcelBatch batch, string sheetName, string rangeAddress);
/// <summary>
/// Sets font properties for entire range
/// Excel COM: Range.Font
/// </summary>
/// <param name="font">Font properties (null values = no change)</param>
Task<OperationResult> SetFontAsync(IExcelBatch batch, string sheetName, string rangeAddress, FontOptions font);
// === CELL APPEARANCE ===
/// <summary>
/// Gets background color from first cell in range
/// Excel COM: Range.Interior.Color
/// </summary>
Task<RangeColorResult> GetBackgroundColorAsync(IExcelBatch batch, string sheetName, string rangeAddress);
/// <summary>
/// Sets background color for entire range
/// Excel COM: Range.Interior.Color
/// </summary>
/// <param name="color">RGB color as integer: (red) | (green << 8) | (blue << 16)</param>
Task<OperationResult> SetBackgroundColorAsync(IExcelBatch batch, string sheetName, string rangeAddress, int color);
/// <summary>
/// Clears background color (resets to no fill)
/// Excel COM: Range.Interior.ColorIndex = xlColorIndexNone
/// </summary>
Task<OperationResult> ClearBackgroundColorAsync(IExcelBatch batch, string sheetName, string rangeAddress);
/// <summary>
/// Gets border settings from range
/// Excel COM: Range.Borders
/// </summary>
Task<RangeBorderResult> GetBordersAsync(IExcelBatch batch, string sheetName, string rangeAddress);
/// <summary>
/// Sets borders for range
/// Excel COM: Range.Borders
/// </summary>
Task<OperationResult> SetBordersAsync(IExcelBatch batch, string sheetName, string rangeAddress, BorderOptions borders);
/// <summary>
/// Clears all borders from range
/// Excel COM: Range.Borders.LineStyle = xlLineStyleNone
/// </summary>
Task<OperationResult> ClearBordersAsync(IExcelBatch batch, string sheetName, string rangeAddress);
// === ALIGNMENT ===
/// <summary>
/// Gets alignment properties from first cell in range
/// Excel COM: Range.HorizontalAlignment, Range.VerticalAlignment, etc.
/// </summary>
Task<RangeAlignmentResult> GetAlignmentAsync(IExcelBatch batch, string sheetName, string rangeAddress);
/// <summary>
/// Sets alignment properties for range
/// Excel COM: Range alignment properties
/// </summary>
Task<OperationResult> SetAlignmentAsync(IExcelBatch batch, string sheetName, string rangeAddress, AlignmentOptions alignment);
// === ROW HEIGHT / COLUMN WIDTH ===
/// <summary>
/// Auto-fits column widths to content
/// Excel COM: Range.Columns.AutoFit()
/// </summary>
Task<OperationResult> AutoFitColumnsAsync(IExcelBatch batch, string sheetName, string rangeAddress);
/// <summary>
/// Auto-fits row heights to content
/// Excel COM: Range.Rows.AutoFit()
/// </summary>
Task<OperationResult> AutoFitRowsAsync(IExcelBatch batch, string sheetName, string rangeAddress);
/// <summary>
/// Sets column width in points
/// Excel COM: Range.ColumnWidth
/// </summary>
Task<OperationResult> SetColumnWidthAsync(IExcelBatch batch, string sheetName, string rangeAddress, double width);
/// <summary>
/// Sets row height in points
/// Excel COM: Range.RowHeight
/// </summary>
Task<OperationResult> SetRowHeightAsync(IExcelBatch batch, string sheetName, string rangeAddress, double height);
}
// Supporting types
public class FontOptions
{
public string? Name { get; set; } // Font family (e.g., "Arial", "Calibri")
public int? Size { get; set; } // Font size in points
public bool? Bold { get; set; } // Bold text
public bool? Italic { get; set; } // Italic text
public int? Color { get; set; } // RGB color
public bool? Underline { get; set; } // Underline
public bool? Strikethrough { get; set; } // Strikethrough
}
public class BorderOptions
{
public BorderStyle Style { get; set; } = BorderStyle.Continuous;
public BorderWeight Weight { get; set; } = BorderWeight.Thin;
public int? Color { get; set; } // RGB color (null = default black)
public bool ApplyToAll { get; set; } = true; // Apply to all edges (top, bottom, left, right)
// Individual edge control (if ApplyToAll = false)
public bool? Top { get; set; }
public bool? Bottom { get; set; }
public bool? Left { get; set; }
public bool? Right { get; set; }
}
public enum BorderStyle
{
None, // xlLineStyleNone
Continuous, // xlContinuous
Dashed, // xlDash
Dotted, // xlDot
DashDot, // xlDashDot
DashDotDot, // xlDashDotDot
Double // xlDouble
}
public enum BorderWeight
{
Hairline, // xlHairline
Thin, // xlThin
Medium, // xlMedium
Thick // xlThick
}
public class AlignmentOptions
{
public HorizontalAlignment? Horizontal { get; set; }
public VerticalAlignment? Vertical { get; set; }
public bool? WrapText { get; set; } // Text wrapping
public int? Indent { get; set; } // Indentation level (0-15)
public int? Orientation { get; set; } // Text rotation in degrees (-90 to 90)
}
public enum HorizontalAlignment
{
General, // xlGeneral (Excel default)
Left, // xlLeft
Center, // xlCenter
Right, // xlRight
Fill, // xlFill
Justify, // xlJustify
CenterAcrossSelection, // xlCenterAcrossSelection
Distributed // xlDistributed
}
public enum VerticalAlignment
{
Top, // xlTop
Center, // xlCenter
Bottom, // xlBottom
Justify, // xlJustify
Distributed // xlDistributed
}
// Result types
public class RangeFontResult : ResultBase
{
public string SheetName { get; set; } = string.Empty;
public string RangeAddress { get; set; } = string.Empty;
public string FontName { get; set; } = string.Empty;
public int FontSize { get; set; }
public bool Bold { get; set; }
public bool Italic { get; set; }
public int Color { get; set; }
public bool Underline { get; set; }
public bool Strikethrough { get; set; }
}
public class RangeColorResult : ResultBase
{
public string SheetName { get; set; } = string.Empty;
public string RangeAddress { get; set; } = string.Empty;
public bool HasColor { get; set; }
public int? Color { get; set; } // RGB integer (null if no color)
public int? Red { get; set; } // Red component 0-255
public int? Green { get; set; } // Green component 0-255
public int? Blue { get; set; } // Blue component 0-255
public string? HexColor { get; set; } // #RRGGBB format
}
public class RangeBorderResult : ResultBase
{
public string SheetName { get; set; } = string.Empty;
public string RangeAddress { get; set; } = string.Empty;
public bool HasBorders { get; set; }
public string? Style { get; set; }
public string? Weight { get; set; }
public int? Color { get; set; }
}
public class RangeAlignmentResult : ResultBase
{
public string SheetName { get; set; } = string.Empty;
public string RangeAddress { get; set; } = string.Empty;
public string Horizontal { get; set; } = string.Empty;
public string Vertical { get; set; } = string.Empty;
public bool WrapText { get; set; }
public int Indent { get; set; }
public int Orientation { get; set; }
}
3. Range Data Validation
public interface IRangeCommands
{
// === DATA VALIDATION OPERATIONS ===
/// <summary>
/// Gets data validation settings from first cell in range
/// Excel COM: Range.Validation
/// </summary>
Task<RangeValidationResult> GetValidationAsync(IExcelBatch batch, string sheetName, string rangeAddress);
/// <summary>
/// Adds data validation to range
/// Excel COM: Range.Validation.Add()
/// </summary>
/// <param name="validation">Validation rule configuration</param>
Task<OperationResult> AddValidationAsync(IExcelBatch batch, string sheetName, string rangeAddress, ValidationRule validation);
/// <summary>
/// Modifies existing validation rule
/// Excel COM: Range.Validation.Modify()
/// </summary>
Task<OperationResult> ModifyValidationAsync(IExcelBatch batch, string sheetName, string rangeAddress, ValidationRule validation);
/// <summary>
/// Removes data validation from range
/// Excel COM: Range.Validation.Delete()
/// </summary>
Task<OperationResult> RemoveValidationAsync(IExcelBatch batch, string sheetName, string rangeAddress);
}
// Supporting types
public class ValidationRule
{
/// <summary>
/// Type of validation (List, WholeNumber, Decimal, Date, Time, TextLength, Custom)
/// </summary>
public ValidationType Type { get; set; }
/// <summary>
/// Comparison operator (Between, NotBetween, Equal, NotEqual, Greater, Less, GreaterOrEqual, LessOrEqual)
/// Only used for numeric/date validations (not for List or Custom)
/// </summary>
public ValidationOperator Operator { get; set; } = ValidationOperator.Between;
/// <summary>
/// First formula/value
/// - List: Comma-separated values "Item1,Item2,Item3" or range reference "=$A$1:$A$10"
/// - Number/Date/Time: Minimum value or single comparison value
/// - TextLength: Minimum length
/// - Custom: Formula expression (must return TRUE/FALSE)
/// </summary>
public string Formula1 { get; set; } = string.Empty;
/// <summary>
/// Second formula/value (only for Between/NotBetween operators)
/// - Number/Date/Time: Maximum value
/// - TextLength: Maximum length
/// </summary>
public string? Formula2 { get; set; }
/// <summary>
/// Whether to ignore blank cells (default: true)
/// </summary>
public bool IgnoreBlank { get; set; } = true;
/// <summary>
/// Whether to show input message when cell is selected
/// </summary>
public bool ShowInputMessage { get; set; } = false;
/// <summary>
/// Input message title
/// </summary>
public string? InputTitle { get; set; }
/// <summary>
/// Input message content
/// </summary>
public string? InputMessage { get; set; }
/// <summary>
/// Whether to show error alert on invalid data
/// </summary>
public bool ShowErrorAlert { get; set; } = true;
/// <summary>
/// Error alert style (Stop, Warning, Information)
/// </summary>
public ValidationAlertStyle ErrorStyle { get; set; } = ValidationAlertStyle.Stop;
/// <summary>
/// Error alert title
/// </summary>
public string? ErrorTitle { get; set; }
/// <summary>
/// Error alert message
/// </summary>
public string? ErrorMessage { get; set; }
}
public enum ValidationType
{
List, // xlValidateList - dropdown list
WholeNumber, // xlValidateWholeNumber
Decimal, // xlValidateDecimal
Date, // xlValidateDate
Time, // xlValidateTime
TextLength, // xlValidateTextLength
Custom // xlValidateCustom - formula-based
}
public enum ValidationOperator
{
Between, // xlBetween
NotBetween, // xlNotBetween
Equal, // xlEqual
NotEqual, // xlNotEqual
Greater, // xlGreater
Less, // xlLess
GreaterOrEqual, // xlGreaterEqual
LessOrEqual // xlLessEqual
}
public enum ValidationAlertStyle
{
Stop, // xlValidAlertStop - prevents invalid data
Warning, // xlValidAlertWarning - warns but allows
Information // xlValidAlertInformation - info only
}
public class RangeValidationResult : ResultBase
{
public string SheetName { get; set; } = string.Empty;
public string RangeAddress { get; set; } = string.Empty;
public bool HasValidation { get; set; }
public string? Type { get; set; }
public string? Operator { get; set; }
public string? Formula1 { get; set; }
public string? Formula2 { get; set; }
public bool IgnoreBlank { get; set; }
public bool ShowInputMessage { get; set; }
public string? InputTitle { get; set; }
public string? InputMessage { get; set; }
public bool ShowErrorAlert { get; set; }
public string? ErrorStyle { get; set; }
public string? ErrorTitle { get; set; }
public string? ErrorMessage { get; set; }
}
4. Table Formatting & Validation
public interface ITableCommands
{
// === NUMBER FORMATTING (delegates to RangeCommands) ===
/// <summary>
/// Gets number formats for a table column
/// Delegates to RangeCommands.GetNumberFormatsAsync() on column range
/// </summary>
Task<RangeNumberFormatResult> GetColumnNumberFormatAsync(IExcelBatch batch, string tableName, string columnName);
/// <summary>
/// Sets uniform number format for entire table column
/// Delegates to RangeCommands.SetNumberFormatAsync() on column data range (excludes header)
/// </summary>
/// <param name="formatCode">Excel format code (e.g., "$#,##0.00", "0.00%")</param>
Task<OperationResult> SetColumnNumberFormatAsync(IExcelBatch batch, string tableName, string columnName, string formatCode);
// === VISUAL FORMATTING (delegates to RangeCommands) ===
/// <summary>
/// Sets font for table column data cells
/// Delegates to RangeCommands.SetFontAsync() on column data range
/// </summary>
Task<OperationResult> SetColumnFontAsync(IExcelBatch batch, string tableName, string columnName, FontOptions font);
/// <summary>
/// Sets background color for table column data cells
/// Delegates to RangeCommands.SetBackgroundColorAsync()
/// </summary>
Task<OperationResult> SetColumnBackgroundColorAsync(IExcelBatch batch, string tableName, string columnName, int color);
/// <summary>
/// Sets alignment for table column data cells
/// Delegates to RangeCommands.SetAlignmentAsync()
/// </summary>
Task<OperationResult> SetColumnAlignmentAsync(IExcelBatch batch, string tableName, string columnName, AlignmentOptions alignment);
/// <summary>
/// Auto-fits table column width to content
/// Delegates to RangeCommands.AutoFitColumnsAsync()
/// </summary>
Task<OperationResult> AutoFitColumnAsync(IExcelBatch batch, string tableName, string columnName);
// === DATA VALIDATION (delegates to RangeCommands) ===
/// <summary>
/// Adds data validation to table column data cells
/// Delegates to RangeCommands.AddValidationAsync() on column data range
/// </summary>
Task<OperationResult> AddColumnValidationAsync(IExcelBatch batch, string tableName, string columnName, ValidationRule validation);
/// <summary>
/// Removes data validation from table column
/// Delegates to RangeCommands.RemoveValidationAsync()
/// </summary>
Task<OperationResult> RemoveColumnValidationAsync(IExcelBatch batch, string tableName, string columnName);
}
5. PivotTable Formatting
Note: PivotTable formatting is ALREADY IMPLEMENTED in Phase 1 (as of October 30, 2025). See PIVOTTABLE-API-SPECIFICATION.md for complete details.
public interface IPivotTableCommands
{
// === NUMBER FORMATTING (IMPLEMENTED) ===
/// <summary>
/// Sets number format for value field in PivotTable
/// Excel COM: PivotField.NumberFormat
/// </summary>
/// <param name="fieldName">Name of value field (e.g., "Sum of Sales")</param>
/// <param name="numberFormat">Excel format code (e.g., "$#,##0.00", "0.00%")</param>
Task<PivotFieldResult> SetFieldFormatAsync(IExcelBatch batch, string pivotTableName,
string fieldName, string numberFormat);
// === LAYOUT & STYLE (IMPLEMENTED) ===
/// <summary>
/// Sets PivotTable layout form
/// Excel COM: PivotTable.RowAxisLayout() or PivotTable.LayoutForm
/// </summary>
/// <param name="layout">Compact, Outline, or Tabular</param>
Task<OperationResult> SetLayoutAsync(IExcelBatch batch, string pivotTableName,
PivotTableLayout layout);
/// <summary>
/// Sets PivotTable visual style
/// Excel COM: PivotTable.TableStyle2
/// </summary>
/// <param name="styleName">
/// Built-in style name (e.g., "PivotStyleMedium2", "PivotStyleLight16")
/// See PivotTableStylePresets for common options
/// </param>
Task<OperationResult> SetStyleAsync(IExcelBatch batch, string pivotTableName,
string styleName);
}
// Layout options
public enum PivotTableLayout
{
Compact, // xlCompactForm - hierarchical, space-saving
Outline, // xlOutlineForm - hierarchical with subtotals
Tabular // xlTabularForm - flat, traditional layout
}
/// <summary>
/// Common PivotTable style names for LLM convenience
/// </summary>
public static class PivotTableStylePresets
{
// Light Styles (subtle colors)
public const string Light1 = "PivotStyleLight1";
public const string Light2 = "PivotStyleLight2";
public const string Light9 = "PivotStyleLight9";
public const string Light16 = "PivotStyleLight16";
public const string Light21 = "PivotStyleLight21";
// Medium Styles (balanced colors)
public const string Medium1 = "PivotStyleMedium1";
public const string Medium2 = "PivotStyleMedium2"; // Popular choice
public const string Medium3 = "PivotStyleMedium3";
public const string Medium9 = "PivotStyleMedium9";
public const string Medium10 = "PivotStyleMedium10";
// Dark Styles (high contrast)
public const string Dark1 = "PivotStyleDark1";
public const string Dark2 = "PivotStyleDark2";
public const string Dark11 = "PivotStyleDark11";
// None (remove styling)
public const string None = "";
}
PivotTable Formatting Capabilities (Implemented):
✅ Number Formatting - Format value fields (Sum of Sales, Average Price, etc.) - PERSISTENT (survives refresh)
✅ Layout Forms - Compact, Outline, or Tabular layout - PERSISTENT
✅ Visual Styles - 28 built-in PivotTable styles (Light, Medium, Dark) - PERSISTENT
How It Works:
// SetFieldFormatAsync() sets format on the PivotField object itself
// Excel COM: dataField.NumberFormat = "$#,##0.00"
// This is a FIELD-LEVEL setting, not a cell-level format
// Result: Format persists across RefreshTable(), save/reopen, data updates
Advanced Formatting (NOT in current scope):
- ❌ Row/column header cell formatting (use RangeCommands, but lost on refresh)
- ❌ Grand total cell formatting (use RangeCommands, but lost on refresh)
- ❌ Conditional formatting within PivotTable (use RangeCommands, but lost on refresh)
- ❌ Individual data cell formatting (recalculated on refresh, formats lost)
Recommended Approach for PivotTable Formatting:
-
✅ Use PivotTableCommands for structure and value field formats (PERSISTENT)
SetFieldFormatAsync()for number formats on value fieldsSetLayoutAsync()for layout formSetStyleAsync()for visual appearance
-
⚠️ Use RangeCommands carefully for additional formatting (NOT PERSISTENT)
- Can format header cells, grand totals, or specific data cells
- Warning: These formats will be lost on refresh
- Only use for one-time formatting or static PivotTables that won't refresh
-
💡 Best Practice: Always use field-level formats when possible
- Field formats are part of the PivotTable definition
- They persist across all PivotTable operations
- They're saved with the workbook
MCP Server Integration
Updated excel_range Tool
{
"name": "excel_range",
"actions": [
// EXISTING (Phase 1)
"get-values", "set-values",
"get-formulas", "set-formulas",
"clear-all", "clear-contents", "clear-formats",
"copy", "copy-values", "copy-formulas",
"insert-cells", "delete-cells", "insert-rows", "delete-rows", "insert-columns", "delete-columns",
"find", "replace", "sort",
"get-used-range", "get-current-region", "get-range-info",
"add-hyperlink", "remove-hyperlink", "list-hyperlinks", "get-hyperlink",
// NEW: NUMBER FORMATTING
"get-number-formats",
"set-number-format",
"set-number-formats",
// NEW: VISUAL FORMATTING
"get-font", "set-font",
"get-background-color", "set-background-color", "clear-background-color",
"get-borders", "set-borders", "clear-borders",
"get-alignment", "set-alignment",
"auto-fit-columns", "auto-fit-rows",
"set-column-width", "set-row-height",
// NEW: DATA VALIDATION
"get-validation",
"add-validation",
"modify-validation",
"remove-validation"
]
}
Updated excel_table Tool
{
"name": "excel_table",
"actions": [
// EXISTING
"list", "create", "rename", "delete", "info", "resize",
"toggle-totals", "set-column-total", "append-rows", "set-style",
"add-to-datamodel",
"apply-filter", "apply-filter-values", "clear-filters", "get-filters",
"add-column", "remove-column", "rename-column",
"get-structured-reference",
"sort", "sort-multi",
// NEW: FORMATTING & VALIDATION
"get-column-number-format", "set-column-number-format",
"set-column-font", "set-column-background-color", "set-column-alignment", "auto-fit-column",
"add-column-validation", "remove-column-validation"
]
}
excel_pivottable Tool (Existing - Already Implemented)
{
"name": "excel_pivottable",
"description": "PivotTable operations - create, configure, format, and analyze data",
"actions": [
// EXISTING (18 actions implemented in Phase 1)
"create", "delete", "list", "info",
"list-fields", "add-row-field", "add-column-field", "add-value-field",
"add-filter-field", "remove-field", "move-field",
"set-field-function", "set-field-name", "set-field-format",
"get-data", "set-field-filter", "sort-field", "refresh",
// FORMATTING (IMPLEMENTED)
"set-layout", // Compact, Outline, or Tabular
"set-style" // PivotTable visual styles
]
}
Note: PivotTable formatting commands (set-layout, set-style, set-field-format) are already implemented and functional. See PIVOTTABLE-API-SPECIFICATION.md for complete documentation.
MCP Server Parameter Reference (Critical for LLMs)
Common Parameters Across All Actions
Required on ALL actions:
excelPath(string) - Absolute path to Excel file (e.g., "C:\Users\user\sales.xlsx")action(string) - Action to perform (e.g., "set-number-format", "add-validation")
Optional batch parameter:
batchId(string) - If using batch mode, reference batch session ID
excel_range Actions - Parameter Details
Number Formatting
get-number-formats
- Required:
excelPath,sheetName,rangeAddress - Returns:
{ success, sheetName, rangeAddress, formats: [[string]], rowCount, columnCount }
set-number-format
- Required:
excelPath,sheetName,rangeAddress,formatCode formatCode: Excel format string (e.g., "$#,##0.00", "0.00%", "m/d/yyyy", "@")- Returns:
{ success, message }
set-number-formats
- Required:
excelPath,sheetName,rangeAddress,formats formats: 2D array of format codes[["$#,##0", "0.00%"], ["m/d/yyyy", "General"]]- Returns:
{ success, message }
Visual Formatting
set-font
- Required:
excelPath,sheetName,rangeAddress,font font(object with ALL properties optional):name(string): Font family (e.g., "Arial", "Calibri", "Times New Roman")size(number): Font size in points (e.g., 10, 12, 14)bold(boolean): Bold text (true/false)italic(boolean): Italic text (true/false)color(number): RGB integer (see RGB calculation below)underline(boolean): Underline text (true/false)strikethrough(boolean): Strikethrough text (true/false)
- Returns:
{ success, message }
set-background-color
- Required:
excelPath,sheetName,rangeAddress,color color(number): RGB integer (see RGB calculation below)- Returns:
{ success, message }
set-borders
- Required:
excelPath,sheetName,rangeAddress,borders borders(object):style(string): "Continuous", "Dashed", "Dotted", "DashDot", "DashDotDot", "Double", "None"weight(string): "Hairline", "Thin", "Medium", "Thick"color(number): RGB integer (optional, default black)applyToAll(boolean): Apply to all edges (true) or specify individual edges (false)- If
applyToAll= false:top(boolean): Apply to top edgebottom(boolean): Apply to bottom edgeleft(boolean): Apply to left edgeright(boolean): Apply to right edge
- Returns:
{ success, message }
set-alignment
- Required:
excelPath,sheetName,rangeAddress,alignment alignment(object with ALL properties optional):horizontal(string): "General", "Left", "Center", "Right", "Fill", "Justify", "CenterAcrossSelection", "Distributed"vertical(string): "Top", "Center", "Bottom", "Justify", "Distributed"wrapText(boolean): Enable text wrapping (true/false)indent(number): Indentation level 0-15orientation(number): Text rotation in degrees (-90 to 90)
- Returns:
{ success, message }
Data Validation
add-validation
- Required:
excelPath,sheetName,rangeAddress,validation validation(object):type(string): "List", "WholeNumber", "Decimal", "Date", "Time", "TextLength", "Custom"operator(string): "Between", "NotBetween", "Equal", "NotEqual", "Greater", "Less", "GreaterOrEqual", "LessOrEqual"formula1(string): First value/formula/listformula2(string, optional): Second value (for Between/NotBetween)ignoreBlank(boolean, optional): Ignore blank cells (default: true)showInputMessage(boolean, optional): Show input message (default: false)inputTitle(string, optional): Input message titleinputMessage(string, optional): Input message textshowErrorAlert(boolean, optional): Show error alert (default: true)errorStyle(string, optional): "Stop", "Warning", "Information" (default: "Stop")errorTitle(string, optional): Error alert titleerrorMessage(string, optional): Error alert message
- Returns:
{ success, message }
excel_table Actions - Parameter Details
set-column-number-format
- Required:
excelPath,tableName,columnName,formatCode - Returns:
{ success, message }
set-column-font
- Required:
excelPath,tableName,columnName,font font: Same structure as excel_range set-font- Returns:
{ success, message }
set-column-background-color
- Required:
excelPath,tableName,columnName,color - Returns:
{ success, message }
add-column-validation
- Required:
excelPath,tableName,columnName,validation validation: Same structure as excel_range add-validation- Returns:
{ success, message }
excel_pivottable Actions - Parameter Details
set-field-format
- Required:
excelPath,pivotTableName,fieldName,numberFormat fieldName: Use value field name from list-fields (e.g., "Sum of Sales", "Average of Price")- Returns:
{ success, fieldName, customName, area, numberFormat }
set-layout
- Required:
excelPath,pivotTableName,layout layout(string): "Compact", "Outline", "Tabular"- Returns:
{ success, message }
set-style
- Required:
excelPath,pivotTableName,styleName styleName(string): Built-in style name (e.g., "PivotStyleMedium2", "PivotStyleLight16")- Returns:
{ success, message }
RGB Color Calculation (Critical Reference)
How to Calculate RGB Integer for Color Parameters:
Formula: RGB(red, green, blue) = red + (green × 256) + (blue × 256²)
Alternative: red + (green << 8) + (blue << 16)
Where: red, green, blue are each 0-255
Common Colors (Ready to Use):
| Color Name | RGB Values | Integer Value | Use For |
|---|---|---|---|
| Red | (255, 0, 0) | 255 | Errors, alerts, negative values |
| Green | (0, 255, 0) | 65280 | Success, positive values |
| Blue | (0, 0, 255) | 16711680 | Headers, links |
| Yellow | (255, 255, 0) | 65535 | Highlights, warnings |
| Orange | (255, 165, 0) | 42495 | Warnings, important items |
| Purple | (128, 0, 128) | 8388736 | Categories, special items |
| Light Gray | (211, 211, 211) | 13882323 | Disabled, secondary |
| Light Blue | (173, 216, 230) | 15128749 | Header backgrounds |
| Light Green | (144, 238, 144) | 9498256 | Positive highlights |
| Light Yellow | (255, 255, 224) | 14745599 | Subtle highlights |
| White | (255, 255, 255) | 16777215 | Clear/reset background |
| Black | (0, 0, 0) | 0 | Text, borders |
When User Says Color Name:
"red background" → color: 255
"yellow highlight" → color: 65535
"green text" → font.color: 65280
"light blue cells" → color: 15128749
Batch Mode Usage (Performance Optimization)
When to Use Batch Mode:
- Formatting 3+ ranges/columns
- Multiple operations on same file
- Complete workbook setup workflows
How to Use Batch Mode with MCP Server:
// Step 1: Begin batch session
{
"tool": "begin_excel_batch",
"excelPath": "C:\\reports\\sales.xlsx"
}
// Returns: { "success": true, "batchId": "batch_abc123" }
// Step 2: Execute multiple operations (use batchId)
{
"tool": "excel_range",
"action": "set-number-format",
"batchId": "batch_abc123",
"sheetName": "Sales",
"rangeAddress": "D2:D100",
"formatCode": "$#,##0.00"
}
{
"tool": "excel_range",
"action": "set-font",
"batchId": "batch_abc123",
"sheetName": "Sales",
"rangeAddress": "A1:E1",
"font": { "bold": true, "size": 12 }
}
{
"tool": "excel_range",
"action": "add-validation",
"batchId": "batch_abc123",
"sheetName": "Sales",
"rangeAddress": "F2:F100",
"validation": {
"type": "List",
"formula1": "Active,Inactive"
}
}
// Step 3: Commit batch (saves all changes)
{
"tool": "commit_excel_batch",
"batchId": "batch_abc123",
"save": true
}
// Returns: { "success": true, "message": "Batch committed, changes saved" }
Benefits:
- ✅ Excel opened once for all operations
- ✅ Changes saved once at end
- ✅ 5-10x faster for multiple operations
- ✅ Atomic - all succeed or all fail
Common Mistakes & How to Avoid Them
Range Formatting Mistakes
❌ Mistake 1: Wrong range address separator
// WRONG
"rangeAddress": "A1-D10"
// CORRECT
"rangeAddress": "A1:D10"
❌ Mistake 2: Wrong alignment case
// WRONG
"alignment": { "horizontal": "center" }
// CORRECT
"alignment": { "horizontal": "Center" } // Capitalize enum values
❌ Mistake 3: Formatting entire columns inefficiently
// SLOW: Formats millions of cells
"rangeAddress": "A:Z"
// FAST: Format only used range
"rangeAddress": "A1:Z1000"
// Or use get-used-range first to find actual data
❌ Mistake 4: Wrong RGB color calculation
// WRONG: Using separate R, G, B values
"color": { "red": 255, "green": 0, "blue": 0 }
// CORRECT: Use integer
"color": 255 // For red
❌ Mistake 5: Providing partial 2D array for set-number-formats
// WRONG: 2x3 range but only 1x2 formats array
"rangeAddress": "A1:C2",
"formats": [["$#,##0", "0.00%"]]
// CORRECT: Match dimensions
"formats": [
["$#,##0", "0.00%", "m/d/yyyy"],
["$#,##0", "0.00%", "m/d/yyyy"]
]
Validation Mistakes
❌ Mistake 6: Wrong validation type for dropdown
// WRONG
"type": "Dropdown"
// CORRECT
"type": "List"
❌ Mistake 7: Forgetting formula2 for Between operator
// WRONG: Between requires two values
"type": "WholeNumber",
"operator": "Between",
"formula1": "1"
// Missing formula2!
// CORRECT
"type": "WholeNumber",
"operator": "Between",
"formula1": "1",
"formula2": "100"
❌ Mistake 8: Using formula reference without = prefix
// WRONG: List from range needs = prefix
"formula1": "A1:A10"
// CORRECT
"formula1": "=$A$1:$A$10"
Table Formatting Mistakes
❌ Mistake 9: Using range address instead of table name
// WRONG: excel_table needs table name
"tableName": "A1:D100"
// CORRECT
"tableName": "SalesData"
❌ Mistake 10: Formatting table headers (not supported)
// WRONG: Headers have fixed formatting from table style
{
"tool": "excel_table",
"action": "set-column-font",
"columnName": "Amount",
"font": { "bold": true } // Affects data cells only, not header
}
// CORRECT: Use table styles instead
{
"tool": "excel_table",
"action": "set-style",
"tableName": "SalesData",
"styleName": "TableStyleMedium2"
}
LLM Usage Examples
Example 1: Format Sales Report
// Scenario: LLM formatting a professional sales report
// Step 1: Format currency column
{
"tool": "excel_range",
"action": "set-number-format",
"sheetName": "Sales",
"rangeAddress": "D2:D100",
"formatCode": "$#,##0.00"
}
// Step 2: Format percentage column
{
"tool": "excel_range",
"action": "set-number-format",
"sheetName": "Sales",
"rangeAddress": "E2:E100",
"formatCode": "0.00%"
}
// Step 3: Format date column
{
"tool": "excel_range",
"action": "set-number-format",
"sheetName": "Sales",
"rangeAddress": "A2:A100",
"formatCode": "m/d/yyyy"
}
// Step 4: Bold headers
{
"tool": "excel_range",
"action": "set-font",
"sheetName": "Sales",
"rangeAddress": "A1:E1",
"font": { "bold": true, "size": 12 }
}
// Step 5: Center align headers
{
"tool": "excel_range",
"action": "set-alignment",
"sheetName": "Sales",
"rangeAddress": "A1:E1",
"alignment": { "horizontal": "Center" }
}
// Step 6: Add borders
{
"tool": "excel_range",
"action": "set-borders",
"sheetName": "Sales",
"rangeAddress": "A1:E100",
"borders": { "style": "Continuous", "weight": "Thin" }
}
// Step 7: Auto-fit columns
{
"tool": "excel_range",
"action": "auto-fit-columns",
"sheetName": "Sales",
"rangeAddress": "A:E"
}
Example 2: Data Entry Form with Validation
// Scenario: LLM creating data entry form with dropdowns
// Step 1: Add status dropdown validation
{
"tool": "excel_range",
"action": "add-validation",
"sheetName": "Orders",
"rangeAddress": "D2:D1000",
"validation": {
"type": "List",
"formula1": "Pending,Processing,Shipped,Delivered,Cancelled",
"showErrorAlert": true,
"errorStyle": "Stop",
"errorTitle": "Invalid Status",
"errorMessage": "Please select a status from the dropdown list."
}
}
// Step 2: Add quantity number validation (1-999)
{
"tool": "excel_range",
"action": "add-validation",
"sheetName": "Orders",
"rangeAddress": "E2:E1000",
"validation": {
"type": "WholeNumber",
"operator": "Between",
"formula1": "1",
"formula2": "999",
"showErrorAlert": true,
"errorTitle": "Invalid Quantity",
"errorMessage": "Quantity must be between 1 and 999."
}
}
// Step 3: Add email text length validation
{
"tool": "excel_range",
"action": "add-validation",
"sheetName": "Orders",
"rangeAddress": "C2:C1000",
"validation": {
"type": "TextLength",
"operator": "LessOrEqual",
"formula1": "100",
"showInputMessage": true,
"inputTitle": "Email Address",
"inputMessage": "Enter customer email (max 100 characters)"
}
}
Example 3: Table Column Formatting
// Scenario: LLM formatting table columns professionally
// Step 1: Format amount column as currency
{
"tool": "excel_table",
"action": "set-column-number-format",
"tableName": "SalesData",
"columnName": "Amount",
"formatCode": "$#,##0.00"
}
// Step 2: Format growth column as percentage
{
"tool": "excel_table",
"action": "set-column-number-format",
"tableName": "SalesData",
"columnName": "Growth",
"formatCode": "0.0%"
}
// Step 3: Add status dropdown validation
{
"tool": "excel_table",
"action": "add-column-validation",
"tableName": "SalesData",
"columnName": "Status",
"validation": {
"type": "List",
"formula1": "Active,Inactive,Pending"
}
}
// Step 4: Center align status column
{
"tool": "excel_table",
"action": "set-column-alignment",
"tableName": "SalesData",
"columnName": "Status",
"alignment": { "horizontal": "Center" }
}
// Step 5: Auto-fit all columns
{
"tool": "excel_table",
"action": "auto-fit-column",
"tableName": "SalesData",
"columnName": "Amount"
}
// Repeat for other columns or use range auto-fit for all at once
Example 4: PivotTable Professional Formatting
// Scenario: LLM creating and formatting a professional PivotTable
// Step 1: Create PivotTable from table
{
"tool": "excel_pivottable",
"action": "create",
"sourceType": "table",
"sourceTable": "SalesData",
"destinationSheet": "Analysis",
"destinationCell": "A1",
"pivotTableName": "SalesPivot"
}
// Step 2: Configure fields
{
"tool": "excel_pivottable",
"action": "add-row-field",
"pivotTableName": "SalesPivot",
"fieldName": "Region"
}
{
"tool": "excel_pivottable",
"action": "add-column-field",
"pivotTableName": "SalesPivot",
"fieldName": "Quarter"
}
{
"tool": "excel_pivottable",
"action": "add-value-field",
"pivotTableName": "SalesPivot",
"fieldName": "Amount",
"function": "Sum",
"customName": "Total Sales"
}
// Step 3: Format value field as currency
{
"tool": "excel_pivottable",
"action": "set-field-format",
"pivotTableName": "SalesPivot",
"fieldName": "Total Sales",
"numberFormat": "$#,##0"
}
// Step 4: Set layout to Tabular (easier to read)
{
"tool": "excel_pivottable",
"action": "set-layout",
"pivotTableName": "SalesPivot",
"layout": "Tabular"
}
// Step 5: Apply professional style
{
"tool": "excel_pivottable",
"action": "set-style",
"pivotTableName": "SalesPivot",
"styleName": "PivotStyleMedium2"
}
// Step 6: Refresh to show data
{
"tool": "excel_pivottable",
"action": "refresh",
"pivotTableName": "SalesPivot"
}
LLM Decision Logic
1. Number Format Selection
When user says a format type, use these codes:
| User Request | Format Code | Use For |
|---|---|---|
| "currency" | $#,##0.00 |
Money amounts |
| "percentage" | 0.00% |
Percentages with 2 decimals |
| "percent" | 0% |
Percentages without decimals |
| "date" | m/d/yyyy |
US date format |
| "date long" | mmmm d, yyyy |
Full date (January 1, 2025) |
| "time" | h:mm AM/PM |
12-hour time |
| "number" | #,##0.00 |
General numbers with commas |
| "text" | @ |
Force text format |
| "accounting" | See NumberFormatPresets.Accounting |
Accounting format with alignment |
2. Visual Formatting Decisions
Font Formatting:
User says "make headers bold" → SetFontAsync({ bold: true })
User says "increase font size" → SetFontAsync({ size: 14 })
User says "red text" → SetFontAsync({ color: RGB(255, 0, 0) })
User says "italicize" → SetFontAsync({ italic: true })
Color Application:
User says "highlight in yellow" → SetBackgroundColorAsync(RGB(255, 255, 0))
User says "green background" → SetBackgroundColorAsync(RGB(0, 255, 0))
User says "remove color" → ClearBackgroundColorAsync()
Borders:
User says "add borders" → SetBordersAsync({ style: Continuous, weight: Thin })
User says "thick border" → SetBordersAsync({ weight: Thick })
User says "remove borders" → ClearBordersAsync()
Alignment:
User says "center align" → SetAlignmentAsync({ horizontal: Center })
User says "wrap text" → SetAlignmentAsync({ wrapText: true })
User says "indent" → SetAlignmentAsync({ indent: 2 })
3. Validation Type Selection
User says "dropdown list" or "select from list"
→ Type: List, Formula1: "Item1,Item2,Item3"
User says "number between X and Y"
→ Type: WholeNumber/Decimal, Operator: Between, Formula1: "X", Formula2: "Y"
User says "date range" or "date after X"
→ Type: Date, Operator: Greater, Formula1: "1/1/2025"
User says "maximum length" or "max X characters"
→ Type: TextLength, Operator: LessOrEqual, Formula1: "X"
User says "custom rule" or "formula validation"
→ Type: Custom, Formula1: "=AND(A1>0, A1<100)"
4. Range vs Table vs PivotTable Decision
If user mentions PivotTable or pivot table
→ Use excel_pivottable actions
→ For value field formatting: use set-field-format
→ For layout: use set-layout (Compact, Outline, Tabular)
→ For visual style: use set-style (PivotStyleMedium2, etc.)
→ Note: Cell-level formatting lost on refresh - use field formats
If user mentions table name explicitly
→ Use excel_table actions (e.g., set-column-number-format)
If user mentions specific range or worksheet
→ use excel_range actions
For new tables being created
→ Create table first, then use table formatting actions
→ More efficient than formatting range then converting to table
For PivotTable creation + formatting workflow
→ Create PivotTable → Add fields → Format value fields → Set layout → Set style → Refresh
5. PivotTable Formatting Guide (Critical for LLMs)
When User Says "Format the PivotTable":
Step 1: Identify what needs formatting
→ Value fields (numbers) → Use set-field-format (PERSISTENT)
→ Layout/structure → Use set-layout (PERSISTENT)
→ Visual appearance → Use set-style (PERSISTENT)
→ Specific cells → DANGER: Use excel_range (NOT PERSISTENT - see pitfalls)
Step 2: Format value fields FIRST (before layout/style)
→ Locate value field name (e.g., "Sum of Sales", "Average Price")
→ Apply number format using set-field-format
→ Examples:
- Currency: "$#,##0.00" or "$#,##0"
- Percentage: "0.00%" or "0%"
- Numbers: "#,##0.00" or "#,##0"
- Dates: "m/d/yyyy" (rarely needed in values)
Step 3: Set layout for readability
→ Compact: Best for space-saving, hierarchical data
→ Outline: Best for subtotals and grouping
→ Tabular: Best for flat data, easier to read (RECOMMENDED for most cases)
Step 4: Apply visual style
→ Medium styles most popular (PivotStyleMedium2)
→ Light styles for subtle appearance
→ Dark styles for high contrast
Step 5: ALWAYS refresh after formatting
→ Refresh materializes the formatting changes
→ Without refresh, formats may not appear correctly
Critical Pitfalls to Avoid:
❌ PITFALL 1: Using excel_range to format PivotTable data cells
Problem: Formats lost on next refresh
Example: set-number-format on "C5:C20" (data area)
Why: PivotTable regenerates cells on refresh
Solution: Use set-field-format on value field instead
❌ PITFALL 2: Formatting before adding all fields
Problem: Layout changes as fields added, formats misaligned
Example: Format cells, then add column field
Solution: Add ALL fields first, THEN format
❌ PITFALL 3: Forgetting to refresh after formatting
Problem: Formatting doesn't appear or incomplete
Example: set-field-format, then immediately read data
Solution: ALWAYS call refresh action after formatting
❌ PITFALL 4: Trying to format row/column headers persistently
Problem: Header cells regenerate on refresh
Example: Bold the "Region" header cells
Solution: Not supported persistently - use styles instead
OR format with excel_range knowing it's temporary
❌ PITFALL 5: Using wrong field name
Problem: Field name is display name, not source name
Example: Field is "Sum of Sales" not "Sales"
Solution: Use list-fields to see actual value field names
Value fields are usually "Sum of X", "Count of Y", etc.
❌ PITFALL 6: Applying validation to PivotTable cells
Problem: Validation lost on refresh, cells are calculated
Example: Add dropdown to data cells
Solution: Don't add validation to PivotTables - they're read-only summaries
Correct PivotTable Formatting Workflow:
// ✅ CORRECT: Field-level formatting (persistent)
{
"tool": "excel_pivottable",
"action": "set-field-format",
"pivotTableName": "SalesPivot",
"fieldName": "Sum of Amount", // Use actual field name from list-fields
"numberFormat": "$#,##0"
}
// ✅ CORRECT: Layout for readability
{
"tool": "excel_pivottable",
"action": "set-layout",
"pivotTableName": "SalesPivot",
"layout": "Tabular" // Most readable for most users
}
// ✅ CORRECT: Professional style
{
"tool": "excel_pivottable",
"action": "set-style",
"pivotTableName": "SalesPivot",
"styleName": "PivotStyleMedium2" // Popular, professional
}
// ✅ CORRECT: Refresh to materialize
{
"tool": "excel_pivottable",
"action": "refresh",
"pivotTableName": "SalesPivot"
}
// ❌ WRONG: Cell-level formatting (lost on refresh)
{
"tool": "excel_range",
"action": "set-number-format",
"sheetName": "Analysis",
"rangeAddress": "C5:C20", // Don't format PivotTable data cells this way!
"formatCode": "$#,##0.00"
}
When to Use Each Formatting Approach:
Use set-field-format when:
✅ User wants to format numbers in PivotTable
✅ Format needs to persist across refreshes
✅ Formatting sum, average, count, etc. values
✅ User says "format the sales column" (value field)
Use set-layout when:
✅ User wants to change PivotTable structure
✅ User says "make it easier to read"
✅ User wants subtotals shown differently
✅ Default: Choose Tabular (most readable)
Use set-style when:
✅ User wants professional appearance
✅ User mentions colors, banding, headers
✅ User says "make it look nice"
✅ Default: PivotStyleMedium2 or PivotStyleMedium9
Use excel_range when (RARE):
✅ User explicitly wants one-time formatting
✅ PivotTable will never refresh
✅ Formatting grand total row/column specifically
⚠️ WARN USER: Format will be lost on refresh
Field Name Discovery Pattern:
// ALWAYS discover field names first if unsure
{
"tool": "excel_pivottable",
"action": "list-fields",
"pivotTableName": "SalesPivot"
}
// Response shows:
// - Fields in Values area: "Sum of Amount", "Average of Price", "Count of Orders"
// - These are the names to use in set-field-format
// Then format using discovered names:
{
"tool": "excel_pivottable",
"action": "set-field-format",
"pivotTableName": "SalesPivot",
"fieldName": "Sum of Amount", // Use exact name from list-fields
"numberFormat": "$#,##0.00"
}
Common User Requests Translation:
User says: "Format the sales numbers as currency"
→ set-field-format with fieldName="Sum of Sales" or "Total Sales"
→ numberFormat="$#,##0.00"
User says: "Make the PivotTable easier to read"
→ set-layout with layout="Tabular"
→ set-style with styleName="PivotStyleMedium2"
User says: "Make it look professional"
→ set-style with styleName="PivotStyleMedium2" or "PivotStyleMedium9"
→ Consider set-layout to "Tabular" if currently Compact
User says: "Format the totals row"
→ WARNING: Not supported persistently
→ Can use excel_range but warn it's temporary
→ Better: Use styles that format totals automatically
User says: "Add percentage formatting"
→ set-field-format with numberFormat="0.00%" or "0%"
→ Common for growth, margin, conversion rate fields
5. Batch Operations
Formatting 3+ columns/ranges
→ Use batch mode (begin_excel_batch → operations → commit_excel_batch)
→ Example: Format entire sales report (currency, percentages, dates, fonts, borders)
Single column/range formatting
→ Direct action call is fine
Complete workbook setup (create + format + validate)
→ Always use batch mode for consistency
Error Response Structure (Critical for LLM Error Handling)
Success Response Format
All operations return consistent success response:
{
"success": true,
"sheetName": "Sales", // Echo back for confirmation
"rangeAddress": "D2:D100", // Echo back for confirmation
"message": "Number format applied successfully"
}
Error Response Format
All operations return consistent error response:
{
"success": false,
"errorMessage": "Sheet 'Sales' not found in workbook",
"errorCode": "SHEET_NOT_FOUND"
}
Common Error Codes
| Error Code | Meaning | User Action |
|---|---|---|
SHEET_NOT_FOUND |
Sheet name doesn't exist | List sheets first with excel_worksheet.list |
INVALID_RANGE |
Range address malformed | Use "A1:D10" format, check column/row exists |
TABLE_NOT_FOUND |
Table name doesn't exist | List tables with excel_table.list |
COLUMN_NOT_FOUND |
Column name not in table | List columns with excel_table.get-structured-reference |
PIVOTTABLE_NOT_FOUND |
PivotTable name doesn't exist | List pivot tables with excel_pivottable.list |
FIELD_NOT_FOUND |
Field name not in PivotTable | List fields with excel_pivottable.list-fields |
FIELD_NOT_IN_VALUES |
Field not in Values area | Check area with list-fields, only Values area supports number formats |
INVALID_FORMAT_CODE |
Number format code invalid | Use valid Excel format code (e.g., "$#,##0.00", not "currency") |
INVALID_VALIDATION_TYPE |
Validation type not recognized | Use: "List", "WholeNumber", "Decimal", "Date", "Time", "TextLength", "Custom" |
FILE_NOT_FOUND |
Excel file doesn't exist | Check excelPath is absolute path, file exists |
FILE_LOCKED |
Excel file open by another process | Close Excel file first |
BATCH_NOT_FOUND |
Batch ID doesn't exist | Check batchId from begin_excel_batch response |
Get Operations - Return Value Structure
get-number-formats returns:
{
"success": true,
"sheetName": "Sales",
"rangeAddress": "A1:C3",
"formats": [
["General", "$#,##0.00", "0.00%"],
["m/d/yyyy", "General", "General"],
["General", "#,##0", "@"]
],
"rowCount": 3,
"columnCount": 3
}
get-font returns:
{
"success": true,
"sheetName": "Sales",
"rangeAddress": "A1",
"font": {
"name": "Calibri",
"size": 11,
"bold": false,
"italic": false,
"color": 0,
"underline": false,
"strikethrough": false
}
}
get-background-color returns:
{
"success": true,
"sheetName": "Sales",
"rangeAddress": "A1:E1",
"colors": [
[15128749, 15128749, 15128749, 15128749, 15128749]
],
"rowCount": 1,
"columnCount": 5
}
get-borders returns:
{
"success": true,
"sheetName": "Sales",
"rangeAddress": "A1",
"borders": {
"top": { "style": "Continuous", "weight": "Thin", "color": 0 },
"bottom": { "style": "Continuous", "weight": "Thin", "color": 0 },
"left": { "style": "None", "weight": "Hairline", "color": 0 },
"right": { "style": "None", "weight": "Hairline", "color": 0 }
}
}
get-alignment returns:
{
"success": true,
"sheetName": "Sales",
"rangeAddress": "A1:E1",
"alignment": {
"horizontal": "Center",
"vertical": "Bottom",
"wrapText": false,
"indent": 0,
"orientation": 0
}
}
get-validation returns:
{
"success": true,
"sheetName": "Sales",
"rangeAddress": "F2:F100",
"validation": {
"type": "List",
"operator": "Between",
"formula1": "Active,Inactive",
"formula2": null,
"ignoreBlank": true,
"showInputMessage": false,
"inputTitle": null,
"inputMessage": null,
"showErrorAlert": true,
"errorStyle": "Stop",
"errorTitle": "Invalid Entry",
"errorMessage": "Please select from dropdown"
}
}
// If no validation exists:
{
"success": true,
"sheetName": "Sales",
"rangeAddress": "A1",
"validation": null
}
Breaking Changes from Current API
✅ Acceptable Breaking Changes
- RangeNumberFormatResult - New result type (previously planned but not implemented)
- Font/Border/Alignment enums - New types for better type safety
- ValidationRule class - Comprehensive validation configuration (cleaner than multiple parameters)
- Table formatting methods - New methods, no existing API to break
❌ No Breaking Changes To
- Existing RangeCommands Phase 1 - All value/formula/clear/copy operations unchanged
- Existing TableCommands - All lifecycle/filter/sort operations unchanged
- Result types - Existing ResultBase, OperationResult, RangeValueResult unchanged
Implementation Strategy
Phase 2A: Number Formatting (Priority 1)
Timeline: 2-3 days
Core Implementation:
- ✅ Add
GetNumberFormatsAsync,SetNumberFormatAsync,SetNumberFormatsAsyncto IRangeCommands - ✅ Implement in RangeCommands.cs using Excel COM Range.NumberFormat
- ✅ Add
NumberFormatPresetsstatic class - ✅ Add
RangeNumberFormatResulttype - ✅ Add table methods:
GetColumnNumberFormatAsync,SetColumnNumberFormatAsync
MCP Server:
- ✅ Add actions to excel_range tool:
get-number-formats,set-number-format,set-number-formats - ✅ Add actions to excel_table tool:
get-column-number-format,set-column-number-format
Tests:
- ✅ Currency format tests ($#,##0.00)
- ✅ Percentage format tests (0.00%)
- ✅ Date format tests (m/d/yyyy)
- ✅ Custom format tests
- ✅ Bulk format tests (2D array)
- ✅ Table column format tests
Why First: Most commonly requested by users, simplest to implement, highest ROI.
Phase 2B: Visual Formatting (Priority 2)
Timeline: 3-4 days
Core Implementation:
- ✅ Add 14 font/color/border/alignment methods to IRangeCommands
- ✅ Implement using Excel COM Range.Font, Range.Interior, Range.Borders, alignment properties
- ✅ Add supporting types: FontOptions, BorderOptions, AlignmentOptions, enums
- ✅ Add result types: RangeFontResult, RangeColorResult, RangeBorderResult, RangeAlignmentResult
- ✅ Add table methods for column formatting
MCP Server:
- ✅ Add 14+ actions to excel_range tool
- ✅ Add 4 formatting actions to excel_table tool
Tests:
- ✅ Font tests (bold, italic, size, color)
- ✅ Background color tests (set, get, clear)
- ✅ Border tests (styles, weights)
- ✅ Alignment tests (horizontal, vertical, wrap, indent, rotation)
- ✅ Auto-fit tests
- ✅ Table column visual format tests
Why Second: High user demand, professional appearance, builds on number formatting foundation.
Phase 2C: Data Validation (Priority 3)
Timeline: 2-3 days
Core Implementation:
- ✅ Add 4 validation methods to IRangeCommands
- ✅ Implement using Excel COM Range.Validation
- ✅ Add ValidationRule class with all types/operators
- ✅ Add ValidationOperator, ValidationType, ValidationAlertStyle enums
- ✅ Add RangeValidationResult type
- ✅ Add table methods for column validation
MCP Server:
- ✅ Add 4 actions to excel_range tool
- ✅ Add 2 actions to excel_table tool
Tests:
- ✅ List validation tests (dropdown)
- ✅ Number validation tests (whole, decimal, between)
- ✅ Date/time validation tests
- ✅ Text length validation tests
- ✅ Custom formula validation tests
- ✅ Error alert tests
- ✅ Table column validation tests
Why Third: Data quality critical, complex API, requires careful Excel COM handling.
Phase 2D: CLI Implementation (Priority 4)
Timeline: 2 days
CLI Commands:
- ✅
range-get-number-formats,range-set-number-format,range-set-number-formats - ✅
range-set-font,range-set-background-color,range-set-borders,range-set-alignment - ✅
range-auto-fit-columns,range-auto-fit-rows - ✅
range-add-validation,range-get-validation,range-remove-validation - ✅
table-set-column-number-format,table-add-column-validation, etc.
Documentation:
- ✅ Update README.md
- ✅ Update copilot instructions
Testing Strategy
Unit Tests
- Number format code validation
- RGB color conversion
- Enum mapping (BorderStyle, ValidationOperator, etc.)
- ValidationRule validation
Integration Tests (Requires Excel)
Number Formatting:
- Set currency format, read back, verify
- Set custom format, verify rendering
- Bulk format 2D array, verify each cell
- Table column format, verify data cells only (not headers)
Visual Formatting:
- Set font properties, verify each property
- Set background color, verify RGB components
- Set borders, verify style/weight/color
- Set alignment, verify horizontal/vertical/wrap
- Auto-fit, verify column widths adjusted
Data Validation:
- Add list validation, verify dropdown appears
- Add number range validation, test invalid input blocked
- Add date validation, verify date picker
- Add custom formula validation, verify evaluation
- Remove validation, verify dropdown removed
Table Operations:
- Format table column, verify only data cells affected
- Add validation to table column, verify auto-expands with new rows
- Auto-fit table columns, verify all columns sized
Success Criteria
Phase 2A - Number Formatting:
- All 3 range number format methods implemented and tested
- NumberFormatPresets class with 20+ common patterns
- 2 table methods working
- MCP actions functional
- 10+ integration tests passing
Phase 2B - Visual Formatting:
- All 14 visual formatting methods implemented and tested
- Font, border, alignment options working
- RGB color handling correct
- Auto-fit functioning
- 20+ integration tests passing
Phase 2C - Data Validation:
- All 4 validation methods implemented and tested
- All validation types working (List, Number, Date, TextLength, Custom)
- Error alerts and input messages functional
- Table column validation auto-expanding
- 15+ integration tests passing
Phase 2D - CLI:
- All CLI commands implemented
- Documentation complete
- CLI tests passing
Overall:
- All 21 new range methods working
- All 8 new table methods working
- 95%+ test coverage
- MCP Server integration complete
- Documentation comprehensive
- Zero regression in existing features
Future Enhancements (Phase 3+)
Conditional Formatting (Complex)
- Rule-based formatting (data bars, color scales, icon sets)
- Formula-based rules
- Manage existing conditional formats
Cell Merge/Unmerge
- Merge cells in range
- Unmerge cells
- Check merge status
Cell Protection
- Lock/unlock cells
- Protect worksheet with password
- Check protection status
Advanced Formatting
- Patterns (diagonal lines, dots, etc.)
- Gradient fills
- Custom number formats with conditions
These can be considered in future iterations based on user demand and complexity vs value analysis.
Summary
This specification provides a comprehensive, LLM-first approach to Excel formatting and data validation:
Key Benefits:
- Professional Output - LLMs can create polished, formatted reports
- Data Quality - Validation ensures data integrity
- User Experience - Dropdowns and input messages guide users
- Consistency - Unified API across ranges and tables
- Performance - Batch operations for efficiency
Total API Surface:
- 21 new range methods (number formatting: 3, visual: 14, validation: 4)
- 8 new table methods (number formatting: 2, visual: 4, validation: 2)
- 0 new PivotTable methods (already implemented in Phase 1)
- 29+ new MCP actions (range + table only)
Implementation Timeline:
- Phase 2A (Number): 2-3 days
- Phase 2B (Visual): 3-4 days
- Phase 2C (Validation): 2-3 days
- Phase 2D (CLI): 2 days
- Total: 9-12 days for complete Phase 2
This represents a significant enhancement to ExcelMcp's capabilities, enabling LLMs to create production-quality Excel workbooks programmatically.