Contributing to ExcelMcp
September 11, 2026 ยท View on GitHub
Thank you for your interest in contributing to Sbroenne.ExcelMcp! This project is designed to be extended by the community, especially to support coding agents like GitHub Copilot.
๐ฏ Project Vision
ExcelMcp aims to be the go-to command-line tool for coding agents to interact with Microsoft Excel files. We prioritize:
- Simplicity - Clear, predictable commands
- Reliability - Robust COM automation
- Extensibility - Easy to add new features
- Agent-Friendly - Designed for AI coding assistants
๐ Getting Started
Development Environment
-
Prerequisites:
- Windows OS (required for Excel COM)
- Visual Studio 2022 or VS Code
- .NET 10 SDK
- Microsoft Excel installed
-
Setup:
git clone https://github.com/sbroenne/mcp-server-excel.git cd mcp-server-excel dotnet restore dotnet build -
Test your setup (surgical โ don't run the full integration suite, it takes 45+ minutes):
dotnet test --filter "Feature=Sheet&RunType!=OnDemand"
๐จ CRITICAL: Pull Request Workflow Required
All changes must be made through Pull Requests (PRs). Direct commits to main are prohibited.
Merge Strategy: Squash Merge โ All PRs are merged via squash merge (single commit to main). This keeps the history clean.
Quick PR Process
- Create feature branch:
git checkout -b feature/your-feature - Make changes: Code, tests, documentation
- Run the pre-commit hook: follow the
pre-commit setup guide, then let it run on every
commit. It checks COM cleanup, MCP/CLI parity, the Release build, packaging,
smoke tests, and other required gates. Never bypass it with
--no-verify. - Push branch:
git push origin feature/your-feature - Create PR: Use GitHub's PR template
- Address review: Investigate human and automated comments, fix verified defects, and explain why an incorrect or inapplicable suggestion was not applied. Do not make unrelated style changes simply because a bot suggested them.
- Merge: After approval and CI checks pass โ GitHub will squash commits automatically
- Verify the final commit message accurately describes the changes
- After merge, your feature branch can be safely deleted
๐ Detailed workflow: See DEVELOPMENT.md for complete instructions.
๐ Development Guidelines
Portable npm lockfiles
Every npm project with a tracked lockfile needs its own .npmrc containing:
omit-lockfile-registry-resolved=true
This applies to the repository root, vscode-extension, and
videos/excel-mcp-intro, as well as any new nested npm project. npm does not
inherit the root project's configuration in nested projects. Preserve any
other existing project settings; do not change registry, proxy, credentials,
or user/global npm configuration to clean up a lockfile.
Run this command inside each affected project:
npm install --package-lock-only --ignore-scripts
Use npm to regenerate lockfiles, not search-and-replace. For portability-only
changes, keep dependency versions and integrity hashes unchanged; do not run
npm update or npm audit fix. Downloads then use the developer's or CI
environment's configured registry rather than a URL saved by another machine.
Direct URL dependencies are not portable under this policy and must use
registry versions or local dependencies instead.
Run the focused checks from the repository root (no Excel required):
pwsh -NoProfile -File scripts\Test-NpmLockfiles.ps1
pwsh -NoProfile -File scripts\check-npm-lockfiles.ps1
The required CI Gate runs both checks with two-minute limits. The pre-commit
hook checks the staged contents with -Staged. The guard discovers tracked
package-lock.json and npm-shrinkwrap.json files at any depth, excludes
node_modules, and reports offending filenames without exposing URLs or
credentials. New lockfiles must be staged before the guard can discover them.
Respect local package sources
npm installs and .NET restores use the package manager's normal configuration hierarchy. The repository does not clear NuGet package sources or force a registry/source/configuration file for restores. Keep local feeds, credentials, proxy settings, caches, and environment settings under the developer's or CI environment's control; do not overwrite them to work around a restore failure. Report an unavailable configured feed instead.
NuGet publishing commands intentionally name the public publishing destination.
That dotnet nuget push --source setting is not a restore-source override.
Code Style
- C# version follows
Directory.Build.propsand the SDK selected byglobal.json - Nullable reference types enabled - handle nulls properly
- No warnings - project must build with zero warnings
- XML documentation for public APIs (these docs are extracted into MCP tool descriptions and shown to LLMs โ keep them accurate)
- Consistent naming - follow established patterns
- Type organization - one public type per file, with a matching file name; split large command classes into domain-specific partial files
- Typed boundaries - use result models for cross-layer data rather than anonymous or loosely typed payloads
Architecture
ExcelMcp has two equal entry points โ an MCP Server and a CLI โ sharing one Core layer:
MCP Server โโโบ In-process ExcelMcpService โโโบ Core Commands โโโบ Excel COM
CLI โโโโโโโโโโบ CLI Daemon (named pipe) โโโโโโบ Core Commands โโโบ Excel COM
ExcelMcp.ComInterop- Reusable COM automation primitives (STA threading, session/batch management)ExcelMcp.Core- Excel business logic (Power Query, VBA, worksheets, PivotTables, etc.)ExcelMcp.Service- Excel session management and command routingExcelMcp.CLI- Command-line interface (session-based:excelcli session open, then operate on the session, thenexcelcli session close --save)ExcelMcp.McpServer- Model Context Protocol tools for AI assistantsExcelMcp.Generators*- Source generators that produce CLI commands and MCP tools directly from Core interfaces โ you do not hand-write CLI verb registration or MCP tool schemas
Command Pattern
Core Commands use the batch API and let exceptions propagate โ never wrap batch.Execute() in a try-catch that returns an error result:
public OperationResult Rename(IExcelBatch batch, string oldName, string newName)
{
ArgumentException.ThrowIfNullOrWhiteSpace(oldName);
ArgumentException.ThrowIfNullOrWhiteSpace(newName);
return batch.Execute((ctx, ct) =>
{
Excel.Worksheet? sheet = null;
try
{
ct.ThrowIfCancellationRequested();
sheet = ComUtilities.FindSheet(ctx.Book, oldName)
?? throw new InvalidOperationException(
$"Worksheet '{oldName}' was not found.");
sheet.Name = newName;
return new OperationResult { Success = true };
}
finally
{
ComUtilities.Release(ref sheet);
}
});
}
Here Excel aliases Microsoft.Office.Interop.Excel. Validate ordinary .NET
arguments before entering the batch. The batch propagates callback failures to
the caller; Service and MCP boundaries serialize failures with their diagnostic
context. Do not replace that context with a second generic error result.
Critical Rules
- Always use the batch API - Never manage Excel lifecycle manually
- Excel uses 1-based indexing -
collection.Item(1)is the first element - Never suppress exceptions with a catch block that returns
Success = falseโ letbatch.Execute()handle it Success = truemust never coexist with a non-emptyErrorMessage- COM objects are released only in
finallyblocks, never swallowed in emptycatchblocks
Excel COM Best Practices
- Typed Excel PIAs first - use late binding only for documented PIA/runtime dependency gaps
- Proper error handling - Catch
COMExceptionwhere specific handling is needed; otherwise let exceptions propagate - Resource cleanup - the batch owns its application and workbook; release every COM reference acquired by a command in reverse order in
finally, including intermediate collections - Input validation - Check file existence and argument validity early
- Performance - reuse sessions and bulk range operations instead of per-cell COM calls
See the COM pitfalls for application-state, refresh, numeric conversion, and shutdown constraints.
Testing
COM behavior requires real Excel integration tests. Pure parsing, mapping, serialization, and generation can use focused tests without Excel. For behavior changes, write a failing regression test before implementation. See the test guide for fixtures, assertions, and persistence.
# Select the affected project and feature; use a hard execution timeout
dotnet test tests\ExcelMcp.Core.Tests\ExcelMcp.Core.Tests.csproj --filter "Feature=PowerQuery&RunType!=OnDemand"
# Session/batch changes also require relevant ComInterop OnDemand tests
dotnet test tests\ExcelMcp.ComInterop.Tests\ExcelMcp.ComInterop.Tests.csproj --filter "RunType=OnDemand"
Before submitting a PR:
- Tests pass for the feature(s) you changed
- Test-owned Excel processes clean up; do not terminate unrelated user sessions
- Error conditions tested (missing files, invalid arguments, etc.)
- Build has zero warnings
- Pre-commit hook passes every gate applicable to the staged paths. Excel E2E is required only when Core, CLI, or MCP runtime paths change, including
ComInterop,Service, and their source generators.
๐ง Adding a New Operation
New operations are added to the Core interface/implementation; CLI commands and MCP tool schemas are then generated automatically โ you don't hand-write CLI arg parsing or MCP tool registration.
- Add the method to the relevant Core interface (e.g.
Commands/Sheet/ISheetCommands.cs), with XML doc comments (these become the MCP tool/parameter descriptions). - Implement it in the corresponding partial class (e.g.
SheetCommands.Lifecycle.cs), following the batch-API pattern above. - Build the solution - the source generators (
ExcelMcp.Generators,ExcelMcp.Generators.CLI) produce the CLI verb and MCP tool automatically from the interface. - Add integration tests for the new operation (TDD: write them first).
- Update
FEATURES.mdand the appropriatedocs/features/*.mdfile with the new operation and updated operation count โscripts/check-doc-counts.ps1enforces that documented counts match the code.
Tracing a bug or contract change
Start at the failing entry point and trace generated routing, Service, Core, and Excel to identify the owning layer. Check sibling operations, fallback and retry branches, and cached or parallel paths for the same defect before choosing a fix.
For changed actions or parameters, compare the Core contract, generated Service arguments, CLI options and batch JSON, MCP schema and manual exceptions, tests, and shared guidance. Names, defaults, validation, results, and timeout behavior must agree. A successful build does not establish that every operation is exposed; run the applicable repository audits.
Reproduce the bug in a focused test, observe the failure, fix the owning layer, then rerun that test and the smallest related group. Coverage should follow the risk, not a fixed number of tests or documentation edits.
Documentation changes
Keep entry READMEs focused on their audience: repository acquisition and quick
start, component installation/use, or Marketplace benefits. Put detailed feature
behavior in docs/features/ and shared agent workflows in skills/shared/.
There is no fixed README length or requirement to edit every README.
Before shortening or moving a page, identify where each substantive caveat,
example, installation option, and workflow will remain. Update that destination
first, then replace duplicate material with a link. Permanent guides belong in
docs/, decisions in docs/ADR-*.md, and feature requirements in specs/.
Temporary investigations belong in issue/PR discussions, not SUMMARY/FIX files.
Use current declared action names and verify operation tables, not just headline counts. The count audit derives the advertised surface from generated metadata. See the website authoring guide for source maps, wrappers, navigation, and machine-readable outputs.
๐ Pull Request Process
Before Submitting
- Code builds with zero warnings
- Feature-scoped tests pass (
dotnet test --filter "Feature=<name>&RunType!=OnDemand") - Excel processes clean up properly
- Added appropriate error handling (no suppressed exceptions)
- Updated
FEATURES.mdanddocs/features/*.mdif operation counts or behaviors changed - Pre-commit hook passes locally
PR Description Template
## Summary
Brief description of changes
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Testing
- [ ] Tested manually with Excel files
- [ ] Verified Excel process cleanup
- [ ] Tested error conditions
- [ ] VBA script execution tested (if applicable)
- [ ] No build warnings
## Checklist
- [ ] Code follows project conventions
- [ ] Self-review completed
- [ ] Updated documentation as needed
๐จ UI Guidelines
Spectre.Console Usage
// Success (green checkmark)
AnsiConsole.MarkupLine($"[green]โ[/] Operation succeeded");
// Error (red)
AnsiConsole.MarkupLine($"[red]Error:[/] {message.EscapeMarkup()}");
// Warning (yellow)
AnsiConsole.MarkupLine($"[yellow]Note:[/] {message}");
// Info/debug (dim)
AnsiConsole.MarkupLine($"[dim]{message}[/]");
// Headers (cyan)
AnsiConsole.MarkupLine($"[cyan]{title}[/]");
Output Consistency
- Tables for structured data (query lists, sheet lists)
- Panels for code blocks (M code display)
- Progress indicators for long operations
- Clear error messages with actionable guidance
๐ Bug Reports
When reporting bugs, please include:
- Excel version and Windows version
- Command used and arguments
- Expected behavior vs actual behavior
- Sample Excel file (if possible)
- Error messages (full text)
๐ก Feature Requests
Great feature requests include:
- Use case description - Why is this needed?
- Proposed command syntax - How should it work?
- Excel operations involved - What APIs would be used?
- Target users - Coding agents? Direct users?
๐ Learning Resources
- Excel VBA Object Model Reference
- Power Query M Language Reference
- Spectre.Console Documentation
- .NET COM Interop Guide
๐ฆ For Maintainers
- NuGet Publishing Guide - Complete guide for publishing all packages with OIDC trusted publishing
๐ท๏ธ Issue Labels
bug- Something isn't workingenhancement- New feature or improvementdocumentation- Documentation improvementsgood first issue- Good for newcomershelp wanted- Extra attention neededexcel-com- Excel COM automation issuespower-query- Power Query specificcoding-agent- Coding agent related
Thank you for contributing to Sbroenne.ExcelMcp! Together we're making Excel automation more accessible to coding agents and developers worldwide. ๐