fcp-sheets
Click on "Install 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-sheetsCreate 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
| Name | Required | Description | Default |
|---|---|---|---|
| ops | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description fully discloses behavior: operation syntax, all subcommands, response prefixes, and conventions. It covers destructive actions (clear, delete) and provides a comprehensive reference.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is very long and detailed, but structured into sections. It is not concise; many details could be moved to a help file. However, the front-loading of the operation format and conventions helps usability.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity, lack of schema descriptions, output schema, or annotations, the description is remarkably complete. It covers all operation categories, response indicators, and usage conventions, leaving minimal ambiguity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description compensates fully. It explains the 'ops' array format (VERB TARGET [key:value ...]) and provides exhaustive examples, adding immense semantic value beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it 'Execute sheets operations' and provides a comprehensive list of subcommands, distinguishing it from siblings like sheets_query (querying) and sheets_help (reference).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
While the description implies this tool is for executing modifications and mentions sheets_help for reference, it does not explicitly contrast when to use this versus siblings for reading or session management. The example workflow demonstrates typical usage.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
sheets_helpA
Returns the sheets reference card with all syntax.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It correctly describes a straightforward read-only operation with no side effects, which is sufficient for this simple help tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, concise sentence with no wasted words. Every part adds value, and it is front-loaded with the key verb and noun.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given no parameters, no output schema, and the simple nature of a help tool, the description is complete. It fully explains what the tool does without needing additional context.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, and the description does not need to add parameter details. According to the rubric, 0 parameters starts at a baseline of 4, and the description is adequate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the verb 'Returns' and the resource 'sheets reference card', specifying that it returns all syntax. This is specific and distinguishes it from sibling tools like sheets, sheets_query, and sheets_session, as it is a help/reference tool.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage for obtaining syntax reference but provides no explicit guidance on when to use this tool vs alternatives like sheets_query or sheets_session. No when-not-to-use or prerequisite context is given.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
sheets_queryD
Query sheets state.
| Name | Required | Description | Default |
|---|---|---|---|
| q | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description must fully convey behavioral traits. It only states 'Query sheets state', omitting crucial details such as read-only nature, side effects, access requirements, or output behavior. The description is insufficient for safe invocation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is extremely short (three words), but this is under-specification rather than conciseness. While it is front-loaded, it lacks necessary details to be useful.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool has one required parameter and no output schema, the description is severely incomplete. It does not explain what 'sheets state' means, the expected query format, or what the tool returns, leaving major gaps for the agent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has one parameter 'q' with zero description coverage. The tool description does not mention or explain 'q' at all, failing to add meaning beyond the schema's bare type definition.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description 'Query sheets state' is largely tautological with the tool name 'sheets_query'. It adds the word 'state' but fails to specify what 'state' refers to or how it differs from sibling tools like 'sheets', 'sheets_session', and 'sheets_help'. Purpose is vague and not distinct.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No guidance is provided on when to use this tool versus alternatives. The description does not mention contexts, prerequisites, or exclusions, leaving the agent without criteria for tool selection.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
sheets_sessionD
Session: 'new "Title"', 'open ./file', 'save', 'checkpoint v1', 'undo', 'redo'
| Name | Required | Description | Default |
|---|---|---|---|
| action | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations provided. The description only gives example action strings without explaining behavior, side effects, permissions, or what happens on execution. Completely opaque.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single line, which is concise, but it sacrifices clarity. It lists commands without explanation, making it under-informative.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with one parameter and no output schema, the description fails to explain the tool's purpose, valid input format, and relationship to siblings. Incomplete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The only parameter 'action' has no schema description (0% coverage). The description hints at possible values via examples, but the format is unclear (e.g., quotes, slashes). It partially compensates but remains ambiguous.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description lists example actions like 'new "Title"' and 'open ./file' but does not clearly state what the tool does. It is ambiguous whether this tool executes session operations or lists commands. No verb+resource clarity.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No guidance on when to use this tool versus siblings (sheets, sheets_query, sheets_help). No indication of appropriate context or alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
4 tool updates
v0.2.0- First observed
sheets - First observed
sheets_help - First observed
sheets_query - First observed
sheets_session
TDQS
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
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
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.
MCP server for AI dialogue using various LLM models via AceDataCloud
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-
- AlicenseCqualityAmaintenanceLocal-first Excel MCP server for AI agents enabling structured reads, workbook introspection, and safer .xlsx mutation without Microsoft Excel or LibreOffice.782MIT
- 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 gradedqualityCmaintenanceMCP 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
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/os-tack/fcp-sheets'
If you have feedback or need assistance with the MCP directory API, please join our Discord server