A side-by-side look at the Excel Webview2 MCP and LogiSheets MCP servers: transport, auth, tools, quality signals, and the config to install either one in Claude, Cursor, Windsurf or VS Code.
Verdict: choose Excel Webview2 MCP for workplace & productivity work as a local process; choose LogiSheets for workplace & productivity as a local process. You can also run both side by side in one mcpServers block.
WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS.open_workbook, save_workbook, export_xlsx.Rows where the two servers differ are marked.
| Spec | ||
|---|---|---|
| Category | Workplace & Productivity | Workplace & Productivity |
| Quality signal | 35/100 · Fair | 67/100 · Great |
| Install command | Confirmed | Confirmed |
| Transport | Local subprocess (stdio) | Local subprocess (stdio) |
| Auth | Not declared | Not declared |
| Pricing | Not declared | Not declared |
| Required env vars | WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS | None listed |
| Verified owner | Community listing | Community listing |
| GitHub stars | 2 | 41 |
| Directory activity | 1 views 0 installs 0 upvotes | 1 views 0 installs 0 upvotes |
| Tools | Not listed | 32 |
| Full listing | View Excel Webview2 MCP | View LogiSheets |
No tool names declared yet. Check the project README from the listing page.
open_workbookStart the workbook you will work in. Call with no arguments for a fresh, empty one; pass `path` to load an existing .xlsx from disk and work on the human's real file.
This replaces whatever workbook the session currently holds, discarding unsaved changes — so call it once at the start, not between steps. You do NOT have to call it at all: an empty workbook appears automatically the moment any other tool touches the session.
Prefer `path` over `xlsx_base64`. `xlsx_base64` exists for hosts with no shared filesystem and costs enormous context for a file of any size.save_workbookWrite the workbook to a real .xlsx file the human can open in Excel. This is how you hand your work back — do it when the task is done.
Defaults to the path it was opened from, or last saved to; pass `path` to write somewhere else. Values, formulas and the block structure are all saved.
IMPORTANT — if the human is going to work on this in Excel, pass `resolve_block_refs: true`. Formulas that read blocks are written as BLOCKREF/BLOCKREFS, which only LogiSheets understands: Excel shows the saved numbers but turns those cells into #NAME? the moment it recalculates. Resolving rewrites them as ordinary A1 references so Excel can recompute the model. Leave it off when the file is coming back here — the named form is readable and survives rows moving.
The result carries a link to the workbook rather than its bytes, so the host can offer the human the file without any of it passing through your context.export_xlsxReturn the workbook as base64-encoded .xlsx bytes.
Last resort. The bytes land in your context and cost roughly 1.4 KB of text per KB of file. Prefer `save_workbook`, which writes a real file and hands the host a link to it — the host can give the human the workbook without any of it passing through you.list_blocksOrient yourself in a workbook: every sheet, every block, and for each block the fields you can reference. One call is enough to start writing formulas.
Per block you get its ref name (BLOCKREF's first argument), its `fields` in column order (the third argument), `key_field` — the column whose values BLOCKREF matches as its second argument — and `derived_fields`, which are computed by a rule and reject writes.
Use `describe_block` when you need a field's actual rule, or the row keys and values. `next_block_start` clears everything already on the sheet, blocks and loose cell content alike, so passing it as `create_block`'s `position` will not land on top of data.
Omit `sheet` to scan the whole workbook; passing it restricts to one sheet.describe_blockReturn a block's full structure for the LLM: identity (name, sheet, position), per-field schema, and row keys in order. Every field reports both what it IS — `type`, `description`, `required`, `unique`, `default_value`, and `references` for a field pointing at another block — and what currently guards it: the `value_formula`, `validation` and `editability` templates. All of it comes from the Rust schema, the engine's authoritative source, so the answer is the same in every host and survives a save/load.
Read a field's `type` and `description` BEFORE writing a value to it: the description is where the unit, the convention, or the thing-not-to-do is written down, and it is the only record of it. A `type` of null means nobody has claimed one yet.
`analyzes` and `analyzed_by` say whether this block is a table or a conclusion drawn from one. A block with `analyzes` set is an ANALYSIS block — a total row, a set of statistics, a pivot — and its rows are its own, not the source's. Never sum an analysis block alongside the block it analyses: that counts the same numbers twice. A field with `aggregates` set is engine-computed from the source; writes to it are dropped, and you change it by changing the declaration.
Pass `include_rows: true` to additionally include current cell values as `rows[].values[fieldName]`. Off by default to save tokens — use it when the agent actually needs to inspect data, not when it only needs the shape.eval_formulaEvaluate an Excel-style formula in a private scratch cell and return the computed value. Nothing is written to user-visible cells. Returns `{type, value}` where type is one of:
- "number" — value is a JS number
- "str" — value is a string
- "bool" — value is a JS boolean
- "error" — value is the Excel error code (e.g. "#REF!", "#NAME?")
- "empty" — value is null (formula returned an empty cell)
Use for:
- Quick checks: "=SUMIFS(OrderStatus, \"amount\", \"*\")" → total
- Sanity-test a candidate template before set_field_rule
- BLOCKREF / BLOCKREFS lookups against any block in the workbook
Leading "=" is optional — it is added automatically if missing.create_blockCreate a structured block (table) on a sheet. fields[0] is the row-key column — the value BLOCKREF matches on, so it has to be unique per record; it is ordinary data you can write. Block ref name (`name`) is used as the first arg to BLOCKREF/BLOCKREFS in formulas.
Field types supported:
- 'string' / 'number' — plain text/numeric cells.
- 'boolean' — cell stores 0/1 or TRUE/FALSE; UI renders ✅/❌ if host has the widget set.
- 'enum' (+ enum_id) — cell stores variant id; UI renders dropdown if host has the widget set. Watson auto-injects a variant-whitelist validation formula on the field so out-of-set writes light up as warnings even without widget rendering. Requires a prior define_enum_set call with matching id.
Rules (value_formula / validation / editability) are set separately via set_field_rule — this call only declares structure + initial rows. Auto-creates the target sheet if missing.convert_to_blockTurn a table that already exists in ordinary cells into a block, in place, without touching its values.
This is how you adopt a workbook someone hands you. `create_block` is for new tables and refuses to write over existing data; this one takes the data as it stands and gives it a name, fields and row keys, so you can address it as (block, row_key, field) and reference it from formulas by name instead of by coordinate.
Give `position` and the counts for the DATA only, leaving out any header row. Field names come from the header row — pass `header_row`, or leave it out and the row directly above the data is used when it looks like titles. `fields` states them outright instead.
The row key is inferred: the first column whose values are all present and all different. Pass `key_field` to choose. Whatever is inferred is reported back, so check it — the key is how formulas and later edits name a row.
Converting is a one-time cost: the block and its schema survive saving and reloading, and afterwards the region behaves exactly like one created as a block.set_block_descriptionWrite what a block is for, in prose, onto the block itself. Saved in the file and returned by describe_block, so it is how the next agent — or the next you, in a later session — learns what the table means.
Say what one row represents, what any non-obvious field holds, and anything that must not be done to it. Do not restate the field names; they are already visible.
Refused when the block reserves `modifyDescription` to its owner. Pass an empty string to clear it.add_block_rowsAdd rows to an existing block. Appends at the end by default; pass after_key or before_key to insert at a position instead. Each row needs a key; values is an object keyed by field name. Fields with a value_formula are auto-materialized by the engine — don't pass them in values. Validation/editability shadows for the new rows are auto-installed by the engine at InsertRowsInBlock time, so no follow-up is needed. Also inserts the matching sheet rows (one block per sheet-row assumption — extends the sheet so downstream rows shift down).delete_block_rowsDelete rows from a block by their key. Missing keys are silently ignored. Also deletes the matching sheet rows (one block per sheet-row assumption). If you try to delete every row, the last one is kept and its cells are cleared instead — the engine doesn't allow rowCnt=0 blocks.move_block_rowReorder a block by moving one row to a new position, addressing both the row and its destination by key. Moves to the end when neither after_key nor before_key is given (same default as add_block_rows). Row order inside a block is presentation only — formulas address rows by key, so reordering never changes a single computed value. Use it to match a reading order someone expects, not to change the model.Paste either block (or both) into your client config, e.g. claude_desktop_config.json or ~/.cursor/mcp.json. We only show a config when the install command is confirmed.
{
"mcpServers": {
"excel-webview2-mcp": {
"command": "npx",
"args": [
"-y",
"@dsbissett/excel-webview2-mcp@latest"
],
"env": {
"WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS": "YOUR_WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS_HERE"
}
}
}
}
{
"mcpServers": {
"logisheets": {
"command": "npx",
"args": [
"-y",
"logisheets-mcp"
]
}
}
}