* fix: include current changelog in releases * test: normalize workflow line endings --------- Co-authored-by: Stefan Broenner <stbrnner@microsoft.com>
19 KiB
ExcelMcp Release Strategy
This document outlines the unified release process for all ExcelMcp components.
Overview
All ExcelMcp components are released together with a single version tag:
| Component | Primary Distribution | Secondary Distribution | Description |
|---|---|---|---|
| MCP Server | Standalone exe ZIP | NuGet (.NET tool) | mcp-excel.exe — no .NET runtime required |
| CLI | Standalone exe ZIP | NuGet (.NET tool) | excelcli.exe — no .NET runtime required |
| VS Code Extension | VSIX + Marketplace | — | Self-contained — bundles MCP Server + CLI + skills |
| MCPB | Claude Desktop bundle | — | Self-contained one-click installation |
| GitHub Copilot Plugins | Published plugin marketplace | — | excel-mcp and excel-cli plugins with wrapper/bootstrap assets that fetch the latest runtime on first use |
| Agent Skills | GitHub Release ZIP | Direct skill extraction | Reusable skill packages for AI coding assistants (npx skills add) |
Unified Release Workflow
Workflow: .github/workflows/release.yml
Trigger: workflow_dispatch with version bump (major/minor/patch) or custom version
What Gets Released
When you run the release workflow, all components are released together:
- CLI → Standalone self-contained exe (
excelcli.exe) shipped as:- ZIP file (primary distribution)
- NuGet package (secondary distribution)
- MCP Server → Standalone self-contained exe (
mcp-excel.exe) + ZIP [primary] + NuGet pack [secondary] - VS Code Extension → Self-contained VSIX (bundles both exes + skills) → VS Code Marketplace
- MCPB → Claude Desktop bundle (
.mcpbfile) - Agent Skills → ZIP package for AI coding assistants
- GitHub Copilot Plugins → Republished to the GitHub Copilot plugin marketplace repo via
publish-plugins.ymlwith wrapper/bootstrap assets only; the plugins fetch the newest self-contained Windows runtime from the main release on first use (see Phase 3 Plugin Publishing) - NuGet → Both packages published to NuGet.org (secondary channel)
- MCP Registry → Updated after NuGet propagation
- GitHub Release → Created with all artifacts and the prepared changelog notes
Release Artifacts
| Artifact | Format | Distribution |
|---|---|---|
ExcelMcp-MCP-Server-{version}-windows.zip |
ZIP | GitHub Release (primary — contains mcp-excel.exe) |
ExcelMcp-CLI-{version}-windows.zip |
ZIP | GitHub Release (primary — contains excelcli.exe) |
SHA256SUMS |
GNU-style SHA-256 manifest (<hash> <filename>) |
GitHub Release (covers both Windows runtime ZIPs) |
Sbroenne.ExcelMcp.CLI.{version}.nupkg |
NuGet | NuGet.org (secondary — contains excelcli.exe, requires .NET 10 runtime) |
Sbroenne.ExcelMcp.McpServer.{version}.nupkg |
NuGet | NuGet.org (secondary — contains mcp-excel.exe, requires .NET 10 runtime) |
excel-skills-v{version}.zip |
ZIP | GitHub Release (contains excel-cli + excel-mcp skills for direct extraction) |
excelmcp-{version}.vsix |
VSIX | GitHub Release + VS Code Marketplace (~68-70 MB, self-contained with both exes + skills) |
excel-mcp-{version}.mcpb |
MCPB | GitHub Release (Claude Desktop bundle, self-contained) |
Release Process
1. Add a Changeset (every PR, not just before release)
CHANGELOG.md is no longer hand-edited. Every PR that changes user-visible
behavior adds a small changeset fragment describing the change, and a CI
check (.github/workflows/changeset-check.yml) fails the PR if one is missing
(unless the PR is labeled skip-changelog). See .changeset/README.md
for the full guide and examples of good vs. too-technical entries.
npx changeset
# → pick a bump type (metadata only, doesn't drive the real release version)
# → write a short, end-user-facing summary
# → commit the generated .changeset/<name>.md with your PR
Nothing needs to happen "before creating a release tag" — fragments accumulate
in .changeset/ across PRs and are compiled automatically when the release
workflow runs (see Changelog Generation below).
2. Run the Release Workflow
- Go to Actions → Release All Components → Run workflow
- Select the version bump type:
- patch (default):
1.5.6→1.5.7 - minor:
1.5.6→1.6.0 - major:
1.5.6→2.0.0
- patch (default):
- Or enter a custom version (e.g.,
1.5.7) to override the bump
The workflow will:
- Calculate the next version from the latest git tag
- Compile pending changesets into the current release changelog
- Build all components (standalone exes + NuGet packages), packaging that changelog where applicable
- Commit the generated release metadata and create the git tag (
v1.5.7) at that commit - Publish to NuGet.org, VS Code Marketplace, and MCP Registry
- Create the GitHub Release with all artifacts and the prepared release notes
3. Monitor Workflow
The main release workflow runs automatically (11 jobs), then the plugin publish workflow runs automatically if the release succeeds:
- version → Calculates the version from the latest tag and dispatch input
- prepare-release → Compiles changesets and uploads the changelog and release notes used by packaging jobs
- build-cli (3-5 min) → Builds standalone
excelcli.exe(win-x64, self-contained), creates ZIP + NuGet pack - build-mcp-server (4-6 min) → Builds standalone
mcp-excel.exe(win-x64, self-contained), creates ZIP + NuGet pack - build-vscode (5-8 min) → Builds the self-contained VSIX with the prepared changelog
- build-mcpb (3-5 min) → Builds the Claude Desktop bundle with the prepared changelog
- build-agent-skills (1-2 min) → Builds agent skills ZIP package (for direct skill extraction via
npx skills add) - create-tag → Regenerates and verifies release metadata, commits it to
main, then tags that exact commit - publish-mcp-registry (10-30 min) → Waits for NuGet propagation, updates MCP Registry
- publish → Publishes to NuGet.org and VS Code Marketplace
- create-release → Creates the GitHub Release with all artifacts and the prepared release notes
Afterward, publish-plugins.yml runs as a follow-on workflow and sync-gates republication of excel-mcp and excel-cli to sbroenne/mcp-server-excel-plugins when plugin-facing install artifacts changed.
4. Verify Release
After workflow completes:
- GitHub Release created with all artifacts (MCP Server ZIP, CLI ZIP,
SHA256SUMS, VSIX, MCPB, skills ZIP) - NuGet packages available on NuGet.org (may take 10-30 min for full propagation)
- VS Code Marketplace updated (verify self-contained extension works without .NET)
- MCP Registry updated
publish-plugins.ymlcompleted; if the sync gate detected plugin-facing changes,sbroenne/mcp-server-excel-pluginswas updated- Release tag contains the current version in
CHANGELOG.mdand points to the release metadata commit onmain
5. Agent Plugin Publishing (Automatic)
Workflow: .github/workflows/publish-plugins.yml
Trigger: Runs automatically after release.yml completes successfully, with a manual workflow_dispatch re-sync path for existing source release tags
Published Repo: sbroenne/mcp-server-excel-plugins (the actual Copilot CLI marketplace repo)
The publish-plugins.yml workflow automatically publishes updated plugins when the release workflow completes:
- Extracts version from the release tag created by
release.yml - Runs a source-side sync gate and skips the downstream publish when no plugin-published source files changed since the previous release tag
- Builds plugins via
scripts/Build-Plugins.ps1:- Copies validated plugin structure from the published marketplace repo
- Applies source-owned plugin overlays from
.github/plugins/(overlay content only; not standalone plugin roots) - Strips committed runtime payloads from plugin bundles so the published repo stays wrapper/bootstrap-only
- Updates version in plugin.json and version.txt for release-tag metadata, while runtime bootstrap still targets the newest GitHub Release at invocation time
- Refreshes skill content (always uses latest source) and stamps the explicit release-tag version into each packaged skill's generated
VERSION
- Checks published-repo guards before mutation, reading the current published plugin version from the canonical marketplace manifest when present (or the legacy root manifest before migration):
- Rejects explicit tag/version mismatches
- Rejects downgrade publishes
- Skips automatic duplicate publishes when the published repo already has the same version and tag
- Publishes plugin artifacts by committing and tagging the published repo when needed, rewriting the repo to the canonical marketplace layout (
.github/plugin/marketplace.json) and removing the legacy rootmarketplace.json
Maintainers can also replay plugin publication for an existing release tag without cutting a new release:
gh workflow run publish-plugins.yml -f release_tag=v1.2.3
Key Points:
- ✅ Automatic — No manual intervention required
- ✅ Idempotent — Safe to re-run on the same version
- ✅ Version-aligned — Uses the exact version from the release
- ✅ No stale fallback — Distributable builds require an explicit version; canonical skill sources contain no
VERSIONfile - ✅ Sync-gated — skips downstream plugin republish when plugin install-surface inputs did not change since the prior release tag
- ✅ Guarded replay — downgrade syncs are rejected, automatic duplicates are skipped, and manual repair/replay runs must keep the requested tag aligned with the incoming plugin manifest/version
- ✅ Manual repair path — maintainers keep a
workflow_dispatchre-sync entry point for repair/replay scenarios - ⚠️ Requires cross-repo token — First-time setup needs a repository secret
PLUGINS_REPO_TOKENin the source repo. Use either a PAT withpublic_reposcope or an app token withcontents:writeonsbroenne/mcp-server-excel-plugins(see Phase 3 Plugin Publishing docs) - ℹ️ Setup command — After creating the token:
gh secret set PLUGINS_REPO_TOKEN --repo sbroenne/mcp-server-excel --body "<token-value>"
Surface note:
- The release automation publishes plugin bundles (manifest, skills, agents, hooks, MCP config, helper scripts) to the published repo.
- Those bundles intentionally exclude self-contained runtime binaries; plugin-local wrapper/download logic retrieves the newest Windows release asset on first use, verifies it against the exact release's
SHA256SUMSasset, and re-checks freshness at most once per chat session. - The published repo is the marketplace; this source repo only owns inputs, overlays, and automation.
- Those artifacts can be relevant across multiple plugin-capable clients, but marketplace registration, discovery, and installation UX remain client-specific.
- The current workflow and docs only claim a verified GitHub Copilot install flow; they do not claim automatic publication into VS Code or Claude-specific plugin marketplaces.
Hardening note:
- Automatic publication now passes through a source-side sync gate so unchanged plugin install surfaces do not produce redundant downstream publishes.
- The published-side sync path rejects downgrade attempts, rewrites the published repo to the canonical
.github/plugin/marketplace.jsonlayout, and keeps explicit repair/replay runs honest by requiring tag/version alignment. - Maintainers still have a manual
workflow_dispatchre-sync entry point when a repair or replay is needed.
For detailed setup instructions and troubleshooting, see Phase 3 Plugin Publishing Setup.
Version Management
Single Version Number
All components use the same version number extracted from the tag:
Tag: v1.5.7
↓
MCP Server: 1.5.7
CLI: 1.5.7
VS Code Extension: 1.5.7
MCPB: 1.5.7
Version Sources
| Component | Version Source |
|---|---|
| MCP Server | .csproj (updated at build time from tag) |
| CLI | .csproj (updated at build time from tag) |
| VS Code Extension | package.json (updated at build time from tag) |
| MCPB | manifest.json (updated at build time from tag) |
Development Version
During development, use placeholder version 1.0.0 in:
Directory.Build.propspackage.jsonmanifest.json
The release workflow injects the correct version from the tag.
Changelog Generation
CHANGELOG.md is end-user facing and generated from changesets, not hand-edited. This replaced a manual ## [Unreleased] section that repeatedly went stale — the auto-rename step below relied on a PR merge that didn't always happen, so several released versions (v1.8.64–v1.9.0) sat mislabeled as "Unreleased" for weeks. See the changeset fragments' own guide at .changeset/README.md for day-to-day usage.
How it works:
- Every PR that changes user-visible behavior adds a small markdown fragment via
npx changeset(from repo root), describing the change in 1-3 end-user-facing sentences. This is committed to.changeset/<random-name>.mdalongside the PR. - CI enforces this via
.github/workflows/changeset-check.yml, which fails the PR if no fragment was added — unless the PR carries theskip-changeloglabel (docs/tests/CI/dependency-only changes). - At release time, the
prepare-releasejob inrelease.ymlrunsscripts/Build-Changelog.ps1 -Version <version> -Date <date>, which:- Runs
npx changeset versionto consume every pending fragment, deleting them. - Normalizes the tool's generated version header to this repo's
## [X.Y.Z] - YYYY-MM-DD(Keep a Changelog) style. - Extracts the new section verbatim into
release_notes_body.md, used directly as the "What's New" body of the GitHub Release.
- Runs
- Artifact builds consume that prepared changelog, so packaged VS Code and MCPB changelog files include the version being released.
- After all builds pass, the
create-tagjob regenerates the metadata using the same release date and verifies it byte-for-byte against the prepared artifact. It commitsCHANGELOG.md, synchronized version metadata, and consumed.changeset/*.mddeletions tomainthrough the Git Data API, then points the release tag at that exact commit.
Root package.json and .changeset/config.json (using @changesets/changelog-github for PR-linked entries) exist solely to drive this tooling — they have no bearing on the actual MCP Server / CLI / VS Code Extension / MCPB version, which remains fully controlled by the version_bump / custom_version workflow inputs as described above.
# Changelog
## [Unreleased]
_No pending changes. New entries are added automatically from changesets when a release is cut._
## [1.9.1] - 2025-01-21
### Minor Changes
- **Feature description** (#123): what changed and why it matters to users.
### Patch Changes
- **Bug fix description** (#124): what was broken and what's fixed now.
Why the Git Data API? Branch protection prevents the default workflow token from pushing the bookkeeping commit directly.
RELEASE_PATbelongs to the repository administrator and hascontents: write, allowing the workflow to create a fast-forward metadata commit before tagging without opening a release-time pull request.
Required Secrets and Variables
Configure these GitHub repository secrets and variables:
| Type | Name | Purpose |
|---|---|---|
| Secret | NUGET_USER |
NuGet.org username (for OIDC trusted publishing) |
| Secret | VSCE_TOKEN |
VS Code Marketplace PAT |
| Secret | APPINSIGHTS_CONNECTION_STRING |
Application Insights (optional telemetry) |
| Secret | RELEASE_PAT |
Repository-admin token with contents: write for the pre-tag release metadata commit |
| Secret | PLUGINS_REPO_TOKEN |
Cross-repo PAT (public_repo) or app token (contents:write) for publishing plugins to sbroenne/mcp-server-excel-plugins |
Notes:
- NuGet uses OIDC trusted publishing (no API key needed). The
NUGET_USERis just the NuGet.org profile name for OIDC token exchange.- The follow-on plugin publish workflow uses a stored cross-repo token (
PLUGINS_REPO_TOKEN) with write access to the published plugin repo. A PAT needspublic_repo; an app token needscontents:write.- No npm tokens required — agent skills are distributed through GitHub Release ZIP and direct skill extraction (
npx skills add), not npm registry.
Troubleshooting
NuGet Publishing Fails
- Verify
NUGET_USERsecret is set to your NuGet.org profile name (not email) - Check NuGet.org trusted publishers are configured for OIDC
VS Code Marketplace Fails
- Verify
VSCE_TOKENis valid and not expired - Check extension ID matches marketplace listing
MCPB Build Fails
- Ensure
mcpb/manifest.jsonis valid JSON - Verify
mcpb/icon-512.pngexists (512x512 PNG)
MCP Registry Update Fails
- MCP Registry update uses GitHub OIDC
- Failures don't block the release (marked continue-on-error)
- Can be retried manually via MCP publisher tool
Publish Plugins Fails
- Confirm the repository secret
PLUGINS_REPO_TOKENexists insbroenne/mcp-server-excel - Confirm the token is valid for the published repo (PAT with
public_repo, or app token withcontents:write) - Verify the token hasn't expired and has push access to
sbroenne/mcp-server-excel-plugins - If the main release succeeded but plugins did not update, inspect the separate follow-on
publish-plugins.ymlrun - If you need to replay the publish without cutting a new release, dispatch
publish-plugins.ymlmanually withrelease_tag=vX.Y.Z - If the workflow reports a downgrade, duplicate, or tag/version mismatch, fix the published repo state first instead of forcing a lower or inconsistent version through
Benefits of Unified Releases
- Single version across all components ensures compatibility
- One tag triggers all releases — simpler process
- Synchronized updates — users always get matching versions
- Reduced coordination — no need to remember multiple tag patterns
- Complete changelog — all changes documented in one place, auto-updated via PR
- Faster releases — parallel builds for independent components
- Dual distribution — standalone exe (primary, no .NET needed) + NuGet (secondary, for .NET users)
- Self-contained VS Code — extension bundles everything, no external dependencies