An MCP server for reading, writing, and manipulating Excel spreadsheets with support for cells, ranges, tables, pictures, and formatting
Strong tool definitions with comprehensive descriptions (avg 250+ chars) and explicit JSON schemas. All 13 tools have clear verb-noun naming and detailed parameter documentation. Schemas include types and descriptions for all parameters. However, output schemas are not formally documented in the source, error handling lacks recovery guidance, and some parameter relationships (e.g., conditional 'newSheetName' in ManageWorksheet) could be clearer. No security concerns detected (no secrets in params). Tool composition is sound with clear single responsibilities.
Apply formatting to cells in an Excel worksheet based on user specifications. Supports individual cells or ranges with comprehensive formatting options including font, fill, alignment, borders, and number formats.
Remove the contents of a range of cells in a worksheet — the inverse of UpdateRange. 'range' is the area to clear (e.g. 'A1:Q60'); if it is larger than the sheet's used range, only the used range is cleared. Set 'clearFormats' to true to wipe the cells completely instead: styling, borders and number formats, but also merged regions, data validation, conditional formats and comments. By default only the cell values are removed and everything else is left in place. Returns a confirmation message.
Search worksheets of a workbook for cells whose text contains any of the given strings. 'searchStrings' is a list of substrings; a cell matches if its text contains any of them (case-insensitive). 'spreadSheetList' restricts the search to the named worksheets; leave it empty to search every worksheet. Returns one entry per worksheet that has at least one match; sheets with no match are omitted. Each entry's 'Contents' is the same two-column Markdown table as LoadRange ('| Address | Contents |'), with 'SheetName' set to the worksheet name and 'TargetRange' left empty.
Get all worksheets from an Excel file, each with its name, used range, and the cell addresses of any pictures it contains.
Get the first picture in a range of cells from a worksheet, returned as an image content block. Returns null when the range contains no pictures.
Output schemas not formally documented. Tools return complex objects (MarkdownSheet, SerializableSheet, etc.) but response structure is not visible in source. LLMs cannot plan downstream calls without knowing returned fields.
ManageWorksheet and ManageTables use action enums with conditional required parameters (newSheetName only for 'rename', table only for 'create'). Parameter descriptions do not explicitly state these dependencies, risking LLM confusion.
Error handling not visible in source. No evidence of recovery guidance (e.g., 'file not found → try GetWorkingDirectory first'). Destructive tools (ClearRange, ManageWorksheet delete) lack confirmation or dry-run patterns.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | C | 61 | 2026-07-28+ | v2 |
Returns the base directory where spreadsheet files are located. IMPORTANT: Call this first before using any other tool to resolve relative file names to absolute paths.
Read cells from a worksheet within the specified range. Prefer this tool over LoadRangeInMarkdownTable when you only need cell values and do not care about spatial layout — it omits empty cells entirely, making it more token-efficient for sparse sheets. The range parameter is required (e.g. 'A1:Q60'). If the sheet's used range is smaller than the requested range, only the used range is read. 'Contents' is a two-column Markdown table ('| Address | Contents |') with one row per non-empty cell: the Address column is a cell address (or, for merged regions, the full range address such as 'AD629:AL638') and the Contents column is the cell text rendered as Markdown (bold → **text**, italic → *text*, strikethrough → ~~text~~). Rows are ordered by spreadsheet position (row first, then column); any literal '|' in a value is escaped as '\|'. Empty cells are excluded from the result (no blank rows). Use 'truncate' to cap the output table size (in characters); when set, the last rows in spreadsheet order are dropped to fit within the limit.
Read cells from a worksheet within the specified range, laid out as a visual grid Markdown table (the spatial counterpart to LoadRange). Use this tool instead of LoadRange when spatial layout matters — for example, when reading a form, understanding column alignment, or diagnosing merged cell structure. The range parameter is required (e.g. 'A1:Q60'). If the sheet's used range is smaller than the requested range, only the used range is read. 'Contents' is a grid Markdown table: the first header column is empty and the remaining headers are the column letters (A, B, C…); each body row is prefixed with its spreadsheet row number (1, 2, 3…), and each grid cell holds the cell value rendered as Markdown (bold → **text**, italic → *text*, strikethrough → ~~text~~). A literal '|' is escaped as '\|' and newlines are collapsed to spaces. Interior empty cells are kept as blank grid cells to preserve the layout; trailing fully-empty rows and columns are dropped. A merged region's value appears only in its top-left anchor cell, with the covered cells left blank. Use 'truncate' to cap the output table size (in characters); when set, the last rows are dropped to fit within the limit. 'TargetRange' reports the tight bounding box actually emitted.
Get, create, or delete an Excel table on a worksheet. 'action' must be 'get', 'create', or 'delete'. For 'get', all tables defined on sheetName are returned; tableName and table are ignored. For 'create', 'table' is required — it converts a cell range into a named Excel Table with auto-filter dropdowns, sortable headers, and optional row banding. Use this whenever you are writing structured tabular data (a header row plus one or more data rows) to a spreadsheet — prefer it over writing plain cells with UpdateRange for any grid-shaped dataset. Workflow: (1) write the data rows (not the header row) into the range first with UpdateRange, then (2) call ManageTables with action 'create' — it writes the column names from 'table.columns' into the first row of 'table.reference' automatically.
Create, delete, or rename a worksheet in an Excel file. 'action' must be 'create', 'delete', or 'rename'. For 'create', a new empty worksheet named spreadSheetName is added. For 'delete', the worksheet named spreadSheetName is removed. For 'rename', the worksheet named spreadSheetName is renamed to newSheetName (newSheetName is required). Returns a confirmation message.
Insert one or more pictures into a worksheet at specified locations. Each picture is anchored to a top-left cell and can be resized. Pictures are inserted in the order given; if multiple pictures target the same cell, later ones are layered on top.
Read the visual styling of a worksheet range and return it as CellFormatSpec entries — the inverse of ApplyCellFormatting. The requested range is intersected with the used range (counting cells that carry only styling, not just contents). Cells whose style matches the workbook default are omitted entirely, and each spec carries only the properties that differ from that default. Adjacent cells sharing identical styling are coalesced into a single rectangular range entry (e.g. 'A1:D1'). Row heights and column widths that differ from the sheet default are emitted first, as dimension-only entries addressed to a cell in the affected row/column.
Write Markdown-formatted text into a worksheet — the inverse of LoadRange. Pass a sheet object with 'SheetName' and 'Contents', where 'Contents' is a two-column Markdown table ('| Address | Contents |', with a '| --- | --- |' separator row) and one row per cell. An Address is either a single cell ('A1') or a merged range address ('AD629:AL638'); range addresses merge the region and write the value into its top-left cell. Escape any literal '|' in a value as '\|'. Inline Markdown is converted to cell formatting: '**text**' → bold, '*text*' → italic, '~~text~~' → strikethrough.
Tool annotations (readOnlyHint, destructiveHint, idempotentHint) not present in source. Risk classification is inferred from tool names/descriptions but not formally declared to the MCP client.
No pagination or result limits documented for FindStringsInSheets. If a workbook has thousands of matching cells, response could exhaust context window. Baseline pattern expects limit + pagination.