fcp-sheets
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@fcp-sheets Create a PE portfolio review workbook with audit checks."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
fcp-sheets
MCP server for semantic spreadsheet operations.
What It Does
fcp-sheets lets LLMs create and edit Excel workbooks by describing spreadsheet intent -- data entry, formulas, styling, charts, conditional formatting -- and renders it into standard .xlsx files. Instead of writing openpyxl code cell-by-cell, the LLM works with operations like data A5 block entry, style A1:F1 bold fill:#1a1a2e, and chart add stacked-column data:B3:C7. Built on the FCP framework, powered by openpyxl for serialization.
Related MCP server: SheetForge MCP
Quick Example
sheets_session('new "Q4 Report" sheets:"Summary,Details"')
sheets([
'data A1',
'| Region | Q4 Revenue | Q4 Costs | Margin |',
'| North | 1250000 | 875000 | =C2/B2 |',
'| South | 980000 | 710000 | =C3/B3 |',
'| East | 1100000 | 790000 | =C4/B4 |',
'| West | 870000 | 620000 | =C5/B5 |',
'data end',
'style A1:D1 bold fill:#2F5496 color:#FFFFFF',
'style B2:C5 fmt:$#,##0',
'style D2:D5 fmt:0.0%',
'chart add clustered-column title:"Q4 Revenue by Region" data:B1:C5 categories:A2:A5',
])
sheets_session('save as:./q4_report.xlsx')Available MCP Tools
Tool | Purpose |
| Batch mutations -- data entry, formulas, styling, charts, merges, borders |
| Inspect the workbook -- list sheets, describe ranges, read values, find |
| Lifecycle -- new, open, save, checkpoint, undo, redo |
| Full reference card |
Benchmark
In a head-to-head against raw openpyxl on a 6-sheet PE portfolio workbook (84 audit checks):
Metric | FCP | Raw openpyxl | Delta |
Audit Score | 84/84 (100%) | 84/84 (100%) | Tie |
Total Time | 559s (9.3 min) | 1,360s (22.7 min) | FCP 2.4x faster |
Total Cost | $3.37 | $4.11 | FCP 18% cheaper |
Output Tokens | 29,065 | 101,909 | FCP 3.5x fewer |
See docs/benchmark/ for the full writeup, audit script, and output files.
Installation
Requires Python >= 3.11.
pip install fcp-sheetsThe image verb (inserting images into a workbook) requires Pillow, which is
an optional extra:
pip install 'fcp-sheets[images]'MCP Client Configuration
{
"mcpServers": {
"sheets": {
"command": "uv",
"args": ["run", "python", "-m", "fcp_sheets"]
}
}
}Architecture
3-layer architecture:
MCP Server (Intent Layer)
Parses op strings, dispatches to verb handlers
|
Semantic Model
Thin wrapper around openpyxl Workbook
Cell ref parser, sheet index, block mode, undo/redo via byte snapshots
|
Serialization (openpyxl)
Semantic model -> .xlsx binary outputKey features:
Block data entry --
data/data endblocks enter tabular data with markdown table syntaxFormulas -- Including cross-sheet references (
='Sheet 2'!B5)Styling -- Font, fill, borders, number formats, merges, alignment
Charts -- Bar, line, pie, scatter, bubble, area, doughnut, stacked variants
Conditional formatting -- Cell-is rules, color scales, data bars
Named ranges & validation -- Drop-down lists, range names
Page setup -- Orientation, print titles, frozen panes, filters
Undo/redo -- Full workbook snapshots with event sourcing
Development
uv sync
uv run pytest # 616 tests
uv run ruff check # linting
uv run pyright # type checkingLicense
MIT
Available Tools
4 toolssheetsA
Execute sheets operations. Each op string follows: VERB TARGET [key:value ...] Call sheets_help for the full reference card.
CELLS: set CELL VALUE [fmt:FORMAT] data ANCHOR ... data end fill SRC dir:down|right [to:CELL|count:N] [until:COL] clear RANGE [all]
SHEETS: sheet add|remove|rename|copy|hide|unhide|activate NAME [at:N]
STYLE: style RANGE|@SEL [bold] [italic] [underline] [strike] [font:NAME] [size:N] [color:#HEX] [fill:#HEX] [align:ALIGN] [valign:VALIGN] [wrap] [indent:N] [rotate:N] [fmt:FORMAT] border RANGE|@SEL SIDES [line:STYLE] [color:#HEX] define-style NAME [font:F] [size:N] [bold] [fill:#HEX] [color:#HEX] [fmt:FORMAT] [align:A] [border:SIDES-STYLE] apply-style NAME RANGE|@SEL
STRUCTURE: merge RANGE [align:center] unmerge RANGE freeze CELL unfreeze filter RANGE | filter off width COL|RANGE SIZE|auto height ROW|RANGE SIZE hide-col COL|RANGE hide-row ROW|RANGE unhide-col COL|RANGE unhide-row ROW|RANGE group-rows RANGE [collapse] group-cols RANGE [collapse] ungroup-rows RANGE ungroup-cols RANGE
CHARTS: chart add TYPE [title:"TEXT"] data:RANGE [categories:RANGE] [at:CELL] [size:WxH] [legend:POS] [style:N]
TABLES: table add NAME range:RANGE [style:STYLE] [banded-rows] [banded-cols] [first-col] [last-col]
CONDITIONAL FORMATTING: cond-fmt RANGE TYPE [params...] Types: cell-is OP VALUE | formula =EXPR | color-scale | data-bar | icon-set | duplicate | unique | top N | bottom N
DATA VALIDATION: validate RANGE TYPE [params...] | validate off RANGE
EDITING: remove @SELECTOR copy RANGE to:CELL [sheet:NAME] move RANGE to:CELL [sheet:NAME] sort RANGE by:COL [dir:asc|desc] [by2:COL dir2:asc|desc] insert-row ROW [count:N] insert-col COL [count:N] delete-row ROW [count:N] delete-col COL [count:N]
MISC: name define|remove NAME [range:RANGE] [scope:SHEET] image CELL path:PATH [size:WxH] link CELL url:URL [text:"TEXT"] | link CELL sheet:NAME!CELL | link off CELL comment CELL "TEXT" | comment off CELL protect [password:PWD] unprotect [password:PWD] lock RANGE unlock RANGE page-setup [orient:landscape|portrait] [paper:letter|a4|legal] [margins:T,R,B,L] [header:TEXT] [footer:TEXT] [print-area:RANGE] [print-title-rows:ROW_RANGE] [print-title-cols:COL_RANGE] [fit-width:N] [fit-height:N] [gridlines] [center-h] [center-v]
CELL REFERENCES: A1 single | A1:D10 range | B:B column | 3:3 row | Sheet2!A1 cross-sheet @bottom_left @bottom_right @right_top (spatial anchors, +N offset)
DATA BLOCKS (PREFERRED FOR MULTI-CELL INPUT): CSV: data A1 Name,Age,City Alice,30,NYC Bob,25,LA data end Markdown: data A1 | Name | Age | City | |------|-----|----- | | Alice | 30 | NYC | data end Formulas: =SUM(A1:A10), =B2*0.22, =C3/C$8 all work inside data blocks Types: bare numbers → numeric, =expr → formula, "quoted" → text, 007 → text
NUMBER FORMATS: General | 0 | 0.00 | #,##0 | $#,##0 | $#,##0.00 0% | 0.00% | yyyy-mm-dd | mm/dd/yyyy | hh:mm:ss | @
COLORS: #4472C4 blue #ED7D31 orange #A5A5A5 gray #FFC000 gold #5B9BD5 lt-blue #70AD47 green #FF0000 red #00B050 dk-green #C6EFCE good-fill #FFC7CE bad-fill #FFEB9C neutral-fill
CHART TYPES: bar, column, line, pie, scatter, area, doughnut, radar, bubble stacked-bar, stacked-column, stacked-area 100-bar, 100-column, 100-area bar-3d, column-3d, line-3d, pie-3d, area-3d
SELECTORS: @sheet:NAME @range:A1:Z99 @row:N @col:A @type:formula|number|text|date|empty @table:NAME @name:NAME @all @recent @recent:N @not:TYPE:VALUE Combine to intersect: @sheet:Revenue @col:E @type:formula
BORDER STYLES: thin | medium | thick | dashed | dotted | double | hair Sides: all | outline | top | bottom | left | right | inner | h | v
CONDITIONAL FORMATTING: cond-fmt RANGE cell-is OP VALUE [VALUE2] [fill:#HEX] [color:#HEX] [bold] cond-fmt RANGE formula =EXPR [fill:#HEX] [color:#HEX] [bold] cond-fmt RANGE color-scale [min-color:#HEX] [max-color:#HEX] [mid-color:#HEX] cond-fmt RANGE data-bar [color:#HEX] cond-fmt RANGE icon-set [icons:arrows|flags|traffic|rating|symbols] cond-fmt RANGE duplicate|unique [fill:#HEX] [color:#HEX] cond-fmt RANGE top|bottom N [fill:#HEX] [color:#HEX] Operators (cell-is only): gt | lt | gte | lte | eq | neq | between | not-between
TABLE STYLES: TableStyleLight1-21 | TableStyleMedium1-28 | TableStyleDark1-11
RESPONSE PREFIXES:
cell/data created ~ chart/table created
style/format modified - cell/range removed ! error or meta @ bulk/selector operation
EXAMPLE WORKFLOW:
sheets_session('new "Q4 Report"')
sheets(['sheet add Revenue'])
sheets(['merge A1:F1', 'set A1 "Revenue Summary"', 'style A1:F1 bold size:16 fill:#1a1a2e color:#FFFFFF'])
sheets(['data A2', '| Month | Revenue | COGS | Gross Profit |', '|-------|---------|------|--------------|', '| Jan | 500000 | =B30.22 | =B3-C3 |', '| Feb | 600000 | =B40.22 | =B4-C4 |', '| Total | =SUM(B3:B4) | =SUM(C3:C4) | =SUM(D3:D4) |', 'data end'])
sheets(['style A2:D2 bold fill:#4472C4 color:#FFFFFF', 'style B3:D6 fmt:$#,##0', 'freeze A3', 'width A 14', 'width B:D 16'])
sheets(['chart add column title:"Revenue" data:B3:B4 categories:A3:A4'])
sheets_session('save as:./report.xlsx')
CONVENTIONS:
Use data blocks for tables/grids — never set cells one-by-one
Batch multiple ops in one sheets() call for efficiency
Values beginning with = are formulas
Quoted strings are text; bare numbers are numeric
Active sheet is implicit target; use sheet:NAME for cross-sheet
Call sheets_help after context truncation for full reference
Inputs: ops (required).
sheets_helpA
Returns the sheets reference card with all syntax.
Inputs: no named parameters.
sheets_queryD
Query sheets state.
Inputs: q (required).
sheets_sessionD
Session: 'new "Title"', 'open ./file', 'save', 'checkpoint v1', 'undo', 'redo'
Inputs: action (required).
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 4 tools
The four tools have clearly distinct purposes: 'sheets' executes operations, 'sheets_query' queries state, 'sheets_session' manages sessions, and 'sheets_help' returns documentation. There is no ambiguity or overlap.
All auxiliary tools follow the 'sheets_<verb>' pattern, while the primary tool is simply 'sheets'. This is a consistent and predictable naming convention.
With only 4 tools, the server is highly focused. The main 'sheets' tool encapsulates a vast DSL for all spreadsheet operations, making the count appropriate for its comprehensive purpose.
The server covers an extensive range of spreadsheet operations: cells, sheets, styles, charts, tables, conditional formatting, data validation, editing, and more. Combined with session management and querying, it is very complete.
Maintenance
Related MCP Connectors
The Excel engine for AI agents: read, check and edit Excel models over MCP.
MCP server for generating rough-draft project plans from natural-language prompts.
MCP server that lets AI assistants use all OneSchema features exposed via the public API.
MCP server unifying ERPs, CRMs, APIs and knowledge base for Claude, ChatGPT and Gemini.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceAn MCP server that allows LLMs to read, analyze, and interact with Excel files through file operations, data discovery, and comprehensive analysis tools.2-
- AlicenseCqualityBmaintenanceLocal-first Excel MCP server for AI agents enabling structured reads, workbook introspection, and safer .xlsx mutation without Microsoft Excel or LibreOffice.83314 PyPI3MIT
- AlicenseNot gradedqualityDmaintenanceA Model Context Protocol (MCP) server that lets you manipulate Excel files without needing Microsoft Excel installed. Create, read, and modify Excel workbooks with your AI agent.MIT
- AlicenseNot gradedqualityDmaintenanceMCP server that turns Excel files into queryable databases, enabling AI agents to filter, aggregate, group, sort data and export results as new Excel files.2MIT