MCP server for reading Excel workbooks (.xlsx) — list sheets, tables, pivot tables, and read cell data.
14 tools with complete schemas and descriptions, but quality is uneven. All tools have input schemas with types and descriptions (baseline met). Tool names follow verb_noun pattern well (list_*, get_*, export_*, create_*, add_*, set_*). Descriptions range 50-250 chars, mostly adequate but some lack actionable context. Parameters are well-typed with enums where appropriate (delimiter, cell_range optional). Major gaps: no output schemas documented, no error handling guidance, no pagination for list tools, no idempotency hints for write operations, no permission/scope declarations. Export tools return inline content OR file path (good flexibility), but response structure not formally documented. Write tools lack confirmation/dry-run patterns for destructive ops.
Add data to a sheet starting at the given cell.
Add a new sheet to the Excel file.
Add a table to a sheet over the given cell range (ref).
Create a new blank Excel file at the given path.
Export a single Excel sheet to a CSV file. - file_path: path to the source .xlsx workbook - sheet_name: name of the sheet to export - output_path: destination file path (e.g. "/tmp/data.csv"), or "return inline" to return the content directly without saving - delimiter: column separator — "comma" (default), "pipe", or "tab" - cell_range: optional Excel range string (e.g. "A1:D10"). When omitted the entire used range is exported. Returns a dict with: - output_path: path of the file written (omitted when returning inline) - content: CSV text (only present when returning inline) - sheet: sheet name - range: the range that was exported - rows_written: number of rows written
No output schemas documented. LLMs cannot plan downstream calls or extract fields. Export tools return dict with conditional keys (output_path vs content), structure not formally specified.
Write tools (create_blank_file, add_sheet, add_data_to_sheet, add_table_to_sheet, set_cell_value, set_cell_formula) lack confirmation/dry-run patterns. Destructive operations should support preview before commit to prevent accidental data loss.
No error handling guidance. Tools raise ValueError for missing sheets/invalid ranges but do not guide LLM recovery. E.g., 'Sheet not found' should suggest 'Call list_sheets() to see available sheets.'
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | D | 54 | 2026-07-28+ | v2 |
Export a single Excel sheet to a Markdown table. The first row is treated as the header row and a separator line is inserted beneath it. All column widths are padded to align the table. - file_path: path to the source .xlsx workbook - sheet_name: name of the sheet to export - output_path: destination file path (e.g. "/tmp/data.md"), or "return inline" to return the content directly without saving - cell_range: optional Excel range string (e.g. "A1:D10"). When omitted the entire used range is exported. Returns a dict with: - output_path: path of the file written (omitted when returning inline) - content: markdown text (only present when returning inline) - sheet: sheet name - range: the range that was exported - rows_written: number of rows written (including header)
Export a single Excel sheet to a plain-text delimited file. Values are joined with the chosen delimiter with no CSV quoting applied, making output easy to read as a flat text file. - file_path: path to the source .xlsx workbook - sheet_name: name of the sheet to export - output_path: destination file path (e.g. "/tmp/data.txt"), or "return inline" to return the content directly without saving - delimiter: column separator — "pipe" (default), "comma", or "tab" - cell_range: optional Excel range string (e.g. "A1:D10"). When omitted the entire used range is exported. Returns a dict with: - output_path: path of the file written (omitted when returning inline) - content: text content (only present when returning inline) - sheet: sheet name - range: the range that was exported - rows_written: number of rows written
Return cell data from a sheet. - sheet_name: name of the sheet to read - cell_range: optional Excel range string (e.g. "A1:D10"). When omitted the entire used range is returned. Returns a dict with: - sheet: sheet name - range: the range that was read - rows: list of rows; each row is a list of cell values
Return data from a named Excel table. - table_name: the display name of the table (from list_tables) Returns a dict with: - table: table name - sheet: sheet the table lives on - ref: cell range - headers: first row (column headers) - rows: remaining rows as list of lists
Return every pivot table in the workbook. Each entry contains: - name: pivot table name - sheet: sheet the pivot table is rendered on - ref: cell range of the pivot table output - source_sheet: data source sheet (if determinable, else null) - source_ref: data source range (if determinable, else null)
Return the names of all sheets in the workbook.
Return every named table in the workbook. Each entry contains: - name: display name of the table - sheet: sheet the table lives on - ref: cell range (e.g. "A1:D20")
Set a formula in a single cell in a sheet (formula should start with '=').
Set the value of a single cell in a sheet.
List tools (list_sheets, list_tables, list_pivot_tables) lack pagination. No limit, offset, or cursor parameters. Large workbooks could return thousands of items, exhausting context.
Write tool descriptions are minimal (50 chars). 'Add a new sheet to the Excel file' lacks context on when to use, what happens, or what it returns. Should explain idempotency, file persistence, and return value.