Prepare a new release for the C# MCP SDK. Assesses Semantic Versioning level (PATCH/MINOR/MAJOR), bumps the version, runs ApiCompat and ApiDiff, reviews documentation, updates changelogs, drafts release notes, and creates a pull request with all release artifacts. Use when asked to prepare a release, start a release, create a release PR, or assess what the next release should be.
72
90%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Low
Low-risk findings worth noting
Prepare a new release for the modelcontextprotocol/csharp-sdk repository. This skill assesses the appropriate Semantic Versioning 2.0.0 level based on queued changes, bumps the version, runs API compatibility and diff tools, reviews documentation, drafts release notes, and creates a pull request containing all release artifacts.
Safety: This skill creates a local branch and PR. It must never create a GitHub release. Release creation is handled by the publish-release skill after this PR is merged.
User confirmation required: This skill NEVER pushes a branch or creates a pull request without explicit user confirmation. The user must review and approve all details before any remote operations occur.
Use the shared release branch reference for branch roles, previous-release lookup rules, and release work-branch naming.
Work through each step sequentially. Present findings at each step and get user confirmation before proceeding. Skip any step that has no applicable items.
Every later step reads branches, tags, and file contents from the local repository. Stale local refs produce assessments that are wrong in ways that look plausible: a missing tag makes a released version invisible, and a stale branch hides merged PRs. Establish a complete, current view before reading anything.
modelcontextprotocol/csharp-sdk).
Do not assume it is named origin — in a fork-based checkout origin is often the fork:
git remote -vgit fetch {upstream} --prune --prune-tags --tagsgit rev-parse --verify v{previous}^{commit}Report what changed as a result of the fetch — new tags, updated branch heads — so the user can see whether the starting state was stale.
Read every subsequent step's branch state from the remote-tracking refs ({upstream}/main,
{upstream}/release/{MAJOR}.x), not from local branches, which may lag or have diverged.
List candidate source/base branches via:
gh api repos/{owner}/{repo}/branches --paginate --jq '[.[] | select(.name == "main" or (.name | startswith("release/"))) | .name]'
Present the list to the user and ask them to choose the source/base branch. Default selection: main.
The selected branch drives every subsequent step:
src/Directory.Build.props.v{MAJOR}.* on release/{MAJOR}.x).--base) for gh pr create at the end of the skill.See release-branches.md for the structured branch rules.
The user may provide:
Once the target is established:
Determine the previous release tag from gh release list — the highest semver among published releases that are ancestors of the target commit (exclude drafts with --exclude-drafts). Do not order by publication date; see release-branches.md for why the two differ and what breaks. On release/{MAJOR}.x, restrict candidates to tags matching v{MAJOR}.*; on main, there is no MAJOR filter.
Get the full list of PRs merged between the previous release tag and the target commit on the selected branch.
Read src/Directory.Build.props at the target commit. Extract <VersionPrefix> and <VersionSuffix>; the candidate version is {VersionPrefix} plus -{VersionSuffix} when the suffix is present (for example, 2.0.0-preview.1).
Verify the previous release tag is an ancestor of the target commit:
git merge-base --is-ancestor v{previous} {target}
If it is not an ancestor, stop and report. The two histories have diverged, which means the selected source branch is not a continuation of the previous release. Every downstream conclusion would be wrong: the PR range would be computed across unrelated history, and the ApiCompat baseline in Step 7 would report the previous release's entire API surface as removed. This is a source-selection problem, not a compatibility problem — do not attempt to suppress it.
The usual cause is that the previous release shipped from a different branch than the one selected. Re-run Step 1 and choose the branch that actually contains the previous release, or confirm with the user that a divergent source is intended and why.
Sort every PR into one of four categories. See references/categorization.md for detailed guidance.
| Category | Content |
|---|---|
| What's Changed | Features, bug fixes, improvements, breaking changes |
| Documentation Updates | PRs whose sole purpose is documentation |
| Test Improvements | Adding, fixing, or unskipping tests; flaky test repairs |
| Repository Infrastructure Updates | CI/CD, dependency bumps, version bumps, build system |
Entry format — * Description #PR by @author with co-authors when present:
* Description #PR by @author
* Description #PR by @author (co-authored by @user1 @Copilot)Attribution rules:
Co-authored-by trailers from all commits in each PR (not just the merge commit) to identify co-authors. Do this for every PR regardless of primary author.copilot_work_started timeline event to identify the triggering user. That person becomes the primary author; @Copilot becomes a co-author.Invoke the breaking-changes skill with the commit range from the previous release tag to the target commit. Examine every PR, assess impact, reconcile labels (offering to add/remove labels and comment on PRs), and get user confirmation.
Use the results (confirmed breaking changes with impact ordering and detail bullets) in the remaining steps.
Using the categorized PRs from Step 3 and confirmed breaking changes from Step 4, assess the appropriate Semantic Versioning 2.0.0 release level. Follow the SemVer assessment guide (owned by the bump-version skill) for the full assessment criteria.
[Experimental] APIspreview.N or rc.N, the recommendation may simply increment the trailing integer per the assessment guidesrc/Directory.Build.props. Flag any discrepancy:
After the version is confirmed:
release-{version} from the target commit (e.g., release-2.0.0-preview.1, release-1.3.1).src/Directory.Build.props:
<VersionPrefix> to the confirmed stable component<VersionSuffix> for prerelease versions, or clear it for stable versions; add the element if it is missing<PackageValidationBaselineVersion> when appropriate, per the rule in references/apicompat-apidiff.md. Read the current value from src/Directory.Build.props and derive the correct one from the versions actually published; never copy a version from an example. Show the derivation — current value, published versions considered, resulting value, and whether it changes — and get confirmation before editing. If the value changes, the baseline-transition suppression audit is mandatory.dotnet buildThis step creates local changes only — nothing is committed or pushed yet.
Run API compatibility validation against the baseline version. Follow references/apicompat-apidiff.md for the full procedure.
dotnet pack to trigger package validation against PackageValidationBaselineVersionPackageValidationBaselineVersion changed in this release, run the baseline-transition suppression audit before interpreting anything else. Moving the baseline makes suppressions written for the old baseline stale, and the resulting failure looks exactly like a mass breaking change.Unnecessary suppressions found. That is a hard failure in its own right, and the CP0001/CP0002/CP0005 lines beneath it are the listing of unused suppression entries, not live API breaks. Regenerate the suppression file and cross-check the API diff before believing them.CompatibilitySuppressions.xml in the affected project directory — only after the suppression audit is completePackageValidationBaselineVersion to silence errors, do not set ApiCompatPermitUnnecessarySuppressions, do not NoWarn CP diagnostics, and do not disable package validation. The baseline is determined by what shipped; suppressions record user-confirmed intentional breaks. If validation fails unexpectedly, stop and report.dotnet clean -c Release; dotnet pack -c ReleaseGenerate a human-readable diff of the public API surface between the previous release and the new version. Follow references/apicompat-apidiff.md for the full procedure, including how to install the Microsoft.DotNet.ApiDiff.Tool from the .NET transport feed.
Microsoft.DotNet.ApiDiff.Tool from the transport feed if not already installed (requires --prerelease and --add-source pointing to https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet{MAJOR}-transport/nuget/v3/index.json)dotnet apidiff comparing baseline vs. current assemblies for each SDK packageIf the ApiDiff tool cannot be installed or fails to produce output, STOP and inform the user. Present the error and ask how to proceed. Do not fall back to a manual summary — the user must decide whether to troubleshoot, skip the API diff, or abort.
Review repository documentation for changes needed to compensate for or adapt to this release:
src/PACKAGE.md and verify each item in the checklist:
nuget/vpre for a prerelease series or nuget/v for a stable release. Switch all badges together if the release type has changed.https://github.com/modelcontextprotocol/csharp-sdk/releases/tag/v{version} for the confirmed release version. The tag does not yet exist at prepare time; the link is forward-referencing and resolves when the GitHub release is published.README.md.csharp-fenced code blocks in src/PACKAGE.md and README.md compile against the current SDK. Follow references/readme-snippets.md for the full procedure. Propose fixes for any API mismatches.docs/ for content affected by the changes in this release. Update references to changed APIs, new features, or removed functionality.docs/versioning.md reflects them.CHANGELOG.md), update them with the release information. If no changelogs exist, skip this sub-step and note it in the summary.Stage all documentation changes for inclusion in the release commit.
Edge Cases for README updates:
src/PACKAGE.md and README.md. Use the package's <Description> from its .csproj as the short description.nuget/vpre and nuget/v together.Compose the release notes that will appear in the PR description and serve as the foundation for the publish-release skill. This is a draft — the final release notes will be refreshed when the GitHub release is created.
v{MAJOR} slug for the version being released — see release-branches.md.gh api repos/{owner}/{repo}/collaborators/{user}/permission --jq .permission and omit
anyone with admin or write. Maintainers still appear in the reviewers bullet.v1.3.1 or v2.0.0-preview.1)Omit empty sections. Present each section for user review before proceeding. Tag references in templates use v{version} exactly, including prerelease suffixes; the Full Changelog link compares the previous tag to the suffixed tag when applicable.
Do this before committing, and never defer it to the Step 12 summary. Showing the finished notes is not a substitute for this step. A complete, well-formatted set of release notes reads as correct and does not invite scrutiny; users routinely approve it and then find miscategorized entries afterward, once the PR is already open. Ask targeted questions while the answers are still cheap to apply.
Present two compact review artifacts and stop for a response after each.
1. Categorization table. Every PR, its assigned section, and the reason — not just the borderline ones, since the user cannot correct a call they were not shown:
| PR | Title | Section | Why |
|---|---|---|---|
| #{number} | {title} | {section} | {what the placement turned on} |
Then explicitly surface the judgment calls, naming the PRs and the reasoning that made each one close:
These were the close calls: {PRs} touch code but not shipped packages, so I placed them under {section}. Any of these belong in a different section?
Flag as a close call any PR that touches samples/ or tests/ but not src/, any PR placed in
"What's Changed" whose changes are confined to non-shipping paths, and any PR whose title suggests
a different section than the one you assigned.
2. Acknowledgements roster. Each person, why they are listed, and their maintainer status:
| Person | Reason | Maintainer? |
|---|---|---|
| @{handle} | {contribution or issue, and the PR that resolved it} | {yes/no — if yes, omit per Step 10 item 7} |
Show entries you excluded and why, so the user can overrule the omission. Ask directly whether the remaining list is right, since acknowledgement errors are about people and are the least comfortable thing to correct after publication.
Apply any corrections before Step 11. Record what changed so the same misclassification is not reintroduced when publish-release refreshes the notes for late-arriving PRs.
Commit all changes to the release-{version} branch:
Prepare release v{version}Present all of the following details to the user for review. The user must confirm every aspect before proceeding to Step 13.
release-2.0.0-preview.1, release-1.3.1)origin)src/Directory.Build.props — Version bumped from 2.0.0-preview.1 to 2.0.0-preview.2
src/ModelContextProtocol.Core/CompatibilitySuppressions.xml — Added 2 new suppressions
README.md — Updated code sample for new API
docs/experimental.md — Added new experimental API referencePackageValidationBaselineVersion or to any suppression file explicitly.Release v2.0.0-preview.1, Release v1.3.1)After presenting all details, explicitly ask the user:
Would you like to push the branch and create the pull request?
Confirm the Step 10b review actually happened before asking. If categorization and acknowledgements were never reviewed as their own decisions, go back and do that first — this gate is about publishing mechanics, and burying content questions in it is how miscategorized entries reach an open PR.
Do not proceed without explicit "yes" confirmation.
Only after explicit user confirmation in Step 12:
release-{version} branch to the remotegh pr create --base {step-1-branch}:
Release v{version}release-{version}release)gh pr checks {pr-number} --watchgh run view {run-id} --log-failed), distinguish product/API validation failures from infrastructure or tooling flakiness, and diagnose before proposing a rerun. For ApiCompat failures, apply the interpretation rules in references/apicompat-apidiff.md before concluding the release is breaking. Present the diagnosis and a proposed fix, then stop — pushing a fix needs the same explicit approval as the original push.Important: No draft GitHub release is created at this point. The publish-release skill handles release creation after this PR is merged.
src/ changes: Documentation Updates or Test Improvements, not "What's Changed" — the shipped packages did not changeCo-authored-by trailers to determine whether @Copilot should be a co-author; if still unclear, use @Copilot as primary authorDirectory.Build.props doesn't match the SemVer assessment, present the discrepancy and let the user decide the final version2.0.0-preview.2 on release/1.x), flag this as a warning and ask the user to confirm. Do not hard-fail. This is informational, not a policy enforcement.preview.N, the SemVer assessment may simply increment N rather than computing MAJOR/MINOR/PATCH. Refer to the SemVer assessment guide's Prereleases section.--tags before concluding the release does not exist; a tag absent locally is far more often a stale checkout than an unpublished releasedotnet pack output; note in the PR description that full ApiCompat was run via package validation onlyUnnecessary suppressions found in ApiCompat output: the CP lines that follow are unused suppression entries, not live breaks. Run the baseline-transition suppression audit and cross-check the API diff before treating the release as breakingdotnet clean -c Release; dotnet pack -c Release reproduces CIrelease-{version} already exists locally or remotely, ask the user whether to reuse it, delete and recreate, or choose a different name/v{MAJOR}/versioning.html path does not exist until the release is published and the Publish Docs workflow runs. The link is forward-referencing at prepare time, like the release-notes tag link. Use the slugged form anyway; do not fall back to the unslugged URL.The PR description combines release notes, ApiCompat, and ApiDiff into a single document. Omit empty sections. The {version} placeholder is the full version and may include a prerelease suffix (for example, Release v2.0.0-preview.1).
# Release v{version}
[Preamble — summarize the release theme]
## Release Notes
### Breaking Changes
Refer to the [C# SDK Versioning](https://csharp.sdk.modelcontextprotocol.io/v{MAJOR}/versioning.html) documentation for details on versioning and breaking change policies.
1. **Description #PR**
* Detail of the break
* Migration guidance
### What's Changed
* Description #PR by @author (co-authored by @user1 @Copilot)
### Documentation Updates
* Description #PR by @author
### Test Improvements
* Description #PR by @author
### Repository Infrastructure Updates
* Description #PR by @author
### Acknowledgements
* @user made their first contribution in #PR
* @user1 @user2 @user3 reviewed pull requests
**Full Changelog**: https://github.com/modelcontextprotocol/csharp-sdk/compare/{previous-tag}...v{version}
<!-- Example: https://github.com/modelcontextprotocol/csharp-sdk/compare/v1.3.0...v2.0.0-preview.1 -->
---
## API Compatibility Report
[ApiCompat output — pass/fail status per package and any issues or suppressions]
## API Diff Report
### ModelContextProtocol.Core
[API diff — additions, removals, changes]
### ModelContextProtocol
[API diff — additions, removals, changes]
### ModelContextProtocol.AspNetCore
[API diff — additions, removals, changes]The release notes section within the PR description uses the same format as the final GitHub release notes (used by the publish-release skill). This ensures consistency between the PR and the published release. Tag examples such as v2.0.0-preview.1 are valid and should be used verbatim when the version has a prerelease suffix.
Omit empty sections. The preamble is always required — it is not inside a section heading. The versioning link uses the v{MAJOR} slug for the version being released — see release-branches.md.
[Preamble — REQUIRED. Summarize the release theme.]
## Breaking Changes
Refer to the [C# SDK Versioning](https://csharp.sdk.modelcontextprotocol.io/v{MAJOR}/versioning.html) documentation for details on versioning and breaking change policies.
1. **Description #PR**
* Detail of the break
* Migration guidance
## What's Changed
* Description #PR by @author (co-authored by @user1 @Copilot)
## Documentation Updates
* Description #PR by @author (co-authored by @user1 @Copilot)
## Test Improvements
* Description #PR by @author (co-authored by @user1 @Copilot)
## Repository Infrastructure Updates
* Description #PR by @author (co-authored by @user1 @Copilot)
## Acknowledgements
* @user made their first contribution in #PR
* @user submitted issue #1234 (resolved by #5678)
* @user1 @user2 @user3 reviewed pull requests
**Full Changelog**: https://github.com/modelcontextprotocol/csharp-sdk/compare/{previous-tag}...v{version}
<!-- Example: https://github.com/modelcontextprotocol/csharp-sdk/compare/v1.3.0...v2.0.0-preview.1 -->609499b
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.