From f7f505aec98cb067c25dc2aecfd278ec7604bb75 Mon Sep 17 00:00:00 2001 From: Jeff Handley Date: Thu, 19 Feb 2026 22:35:30 -0800 Subject: [PATCH 01/10] Add release-notes agent skill Add a new agent skill for preparing release notes for draft GitHub releases. The skill follows the Agent Skills specification from agentskills.io with progressive disclosure across SKILL.md and reference files. The skill automates an 8-step process: - Version detection from Directory.Build.props - PR categorization with co-author attribution from commit trailers - Breaking change audit with impact assessment - Label reconciliation with user confirmation - Acknowledgements for issue reporters and PR reviewers - Draft release creation or update (never publishes) Reference files provide detailed guidance for categorization, breaking change classification, and formatting best practices. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/skills/release-notes/SKILL.md | 153 ++++++++++++++++++ .../references/breaking-changes.md | 114 +++++++++++++ .../references/categorization.md | 95 +++++++++++ .../release-notes/references/formatting.md | 43 +++++ 4 files changed, 405 insertions(+) create mode 100644 .github/skills/release-notes/SKILL.md create mode 100644 .github/skills/release-notes/references/breaking-changes.md create mode 100644 .github/skills/release-notes/references/categorization.md create mode 100644 .github/skills/release-notes/references/formatting.md diff --git a/.github/skills/release-notes/SKILL.md b/.github/skills/release-notes/SKILL.md new file mode 100644 index 000000000..503000d44 --- /dev/null +++ b/.github/skills/release-notes/SKILL.md @@ -0,0 +1,153 @@ +--- +name: release-notes +description: Prepare release notes for the C# MCP SDK. Categorizes PRs, audits breaking changes, reconciles labels, attributes co-authors, identifies acknowledgements, and creates or updates a draft GitHub release. Use when asked to prepare a release, write release notes, update release notes, create a changelog, or summarize a version. +compatibility: Requires gh CLI with repo access and GitHub API access for PR details, timeline events, and commit trailers. +--- + +# Release Notes Preparation + +Prepare polished, categorized release notes for the `modelcontextprotocol/csharp-sdk` repository. This skill determines the version from the repository's build properties, gathers all data from GitHub, and creates or updates a **draft** release. + +> **Safety: This skill only creates and updates draft releases. It must never publish a release.** If the user asks to publish, decline and instruct them to publish manually through the GitHub UI. + +## Process + +Work through each step sequentially. Present findings at each step and get user confirmation before proceeding. Skip any step that has no applicable items. + +### Step 1: Determine Version and Target + +The user may provide: +- **A git ref** (commit SHA, branch, or tag) — use as the target commit +- **An existing draft release** (URL or tag) — use its target commit +- **No context** — show the last 5 commits on `main` (noting HEAD) and offer the option to enter a branch or tag name instead + +Once the target is established: +1. Read `src/Directory.Build.props` **at the target commit**. Extract `` and ``. The tag and title are `v{VersionPrefix}-{VersionSuffix}`, or `v{VersionPrefix}` if no suffix. Pre-release if `VersionSuffix` is present. +2. Check for an existing draft release matching this tag. +3. Determine the previous release tag from `gh release list` (most recent published release). +4. Get the full list of PRs merged between the previous release tag and the target commit. + +### Step 2: Categorize and Attribute + +Sort every PR into one of three categories. See [references/categorization.md](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 | +| **Repository Infrastructure Updates** | CI/CD, tests, dependency bumps, version bumps | + +**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:** +- Harvest `Co-authored-by` trailers from all commits in each PR's merge commit +- For Copilot-authored PRs, check the `copilot_work_started` timeline event to identify the triggering user. That person becomes the primary author; `@Copilot` becomes a co-author +- Omit the co-author parenthetical when there are none +- Sort entries within each section by merge date (chronological) + +### Step 3: Breaking Change Audit + +Examine **every** PR for breaking changes — both API (compile-time) and behavioral (runtime). For each PR, study the description, linked issues, review comments, and full diff. + +For each identified breaking change, assess **impact** (breadth of consumers affected, compile-time vs. behavioral, migration difficulty) to inform the ordering in Step 5. + +Compare findings against existing `breaking-change` labels. See [references/breaking-changes.md](references/breaking-changes.md) for classification guidance. + +### Step 4: Reconcile Labels + +Present mismatches to the user interactively: + +- **Unlabeled but appears breaking** → explain why, ask user to confirm. If confirmed: apply label, ask user whether to comment on the PR explaining the addition, and include in Breaking Changes. +- **Labeled but does not appear breaking** → explain why, ask user to confirm removal. If confirmed: remove label, ask user whether to comment on the PR explaining the removal, and exclude from Breaking Changes. + +### Step 5: Review Sections + +Present each section for user review: +1. **Breaking Changes** — sorted most → least impactful (from Step 3 assessment) +2. **What's Changed** — chronological; includes breaking change PRs +3. **Documentation Updates** — chronological +4. **Repository Infrastructure Updates** — chronological + +### Step 6: Acknowledgements + +Identify contributors beyond PR authors: +1. **New contributors** — first contribution to the repository in this release +2. **Issue reporters** — users who submitted issues resolved by PRs in this release (cite the resolving PR) +3. **PR reviewers** — users who reviewed PRs, excluding PR authors and bots + +Exclude anyone already listed as a PR author. Format: +``` +* @user made their first contribution in #PR +* @user submitted issue #1234 (resolved by #5678) +* PR reviewers: @user1 @user2 @user3 +``` +Reviewers go on a single bullet, sorted by number of PRs reviewed (most first), without citing the count. + +### Step 7: Final Assembly + +1. **Preamble** — summarize the release theme. If there are breaking changes, mention them and link to the [C# SDK Versioning](https://modelcontextprotocol.github.io/csharp-sdk/versioning.html) docs. Do not repeat preamble text under the Breaking Changes heading. Let the user revise or omit. +2. **Notable callouts** — only if something is extraordinarily noteworthy. +3. Present the **complete release notes** for user approval. + +Follow [references/formatting.md](references/formatting.md) when composing and updating the release body. + +### Step 8: Create or Update Draft Release + +Display release metadata for user review: +- **Title / Tag**: e.g. `v0.9.0-preview.1` +- **Target**: commit SHA, its message, and associated PR link +- **Newer commits**: whether `main` has commits beyond the target +- **Pre-release**: yes/no (based on `VersionSuffix`) + +After confirmation: +- **No existing draft** → create with `gh release create --draft` (always `--draft`) +- **Existing draft** → update the release notes body only +- **Never publish.** Never change pre-release state, title, tag, or other metadata on an existing draft. + +When the user requests revisions after the initial update, always rewrite the complete body as a file — never perform in-place string replacements. See [references/formatting.md](references/formatting.md). + +## Edge Cases + +- **PR spans categories**: categorize by primary intent +- **Copilot timeline missing**: fall back to `Co-authored-by` trailers; if still unclear, use `@Copilot` as primary author +- **Draft tag changes**: re-fetch the tag before each `gh release edit` +- **No breaking changes**: omit the Breaking Changes section and breaking change preamble language +- **Single breaking change**: use the same numbered format as multiple + +## Release Notes Template + +Omit empty sections: + +```markdown +[Preamble — release theme, breaking changes note, versioning docs link] + +## Breaking Changes + +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) + +## 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) +* PR reviewers: @user1 @user2 @user3 + +**Full Changelog**: previous-tag...new-tag +``` diff --git a/.github/skills/release-notes/references/breaking-changes.md b/.github/skills/release-notes/references/breaking-changes.md new file mode 100644 index 000000000..9c526dbef --- /dev/null +++ b/.github/skills/release-notes/references/breaking-changes.md @@ -0,0 +1,114 @@ +# Breaking Change Classification Guide + +This guide defines how to identify and classify breaking changes during the release notes process for the C# MCP SDK. It is derived from the [dotnet/runtime breaking change guidelines](https://github.com/dotnet/runtime/blob/main/docs/coding-guidelines/breaking-changes.md). + +## Two Categories of Breaking Changes + +### API Breaking Changes (Compile-Time) +Changes that alter the public API surface in ways that break existing code at compile time: + +- **Renaming or removing** a public type, member, or parameter +- **Changing the return type** of a method or property +- **Changing parameter types, order, or count** on a public method +- **Sealing** a type that was previously unsealed (when it has accessible constructors) +- **Making a virtual member abstract** +- **Adding `abstract` to a member** when the type has accessible constructors and is not sealed +- **Removing an interface** from a type's implementation +- **Changing the value** of a public constant or enum member +- **Changing the underlying type** of an enum +- **Adding `readonly` to a field** +- **Removing `params` from a parameter** +- **Adding/removing `in`, `out`, or `ref`** parameter modifiers +- **Renaming a parameter** (breaks named arguments and late-binding) +- **Adding the `[Obsolete]` attribute** or changing its diagnostic ID +- **Adding the `[Experimental]` attribute** or changing its diagnostic ID +- **Removing accessibility** (making a public/protected member less visible) + +### Behavioral Breaking Changes (Runtime) +Changes that don't break compilation but alter observable behavior: + +- **Throwing a new/different exception type** in an existing scenario (unless it's a more derived type) +- **No longer throwing an exception** that was previously thrown +- **Changing return values** for existing inputs +- **Decreasing the range of accepted values** for a parameter +- **Changing default values** for properties, fields, or parameters +- **Changing the order of events** being fired +- **Removing the raising of an event** +- **Changing timing/order** of operations +- **Changing parsing behavior** and throwing new errors +- **Changing serialization format** or adding new fields to serialized types + +## Classification Buckets + +### Bucket 1: Clear Public Contract Violation +Obvious breaking changes to the public API shape. **Always flag these.** + +### Bucket 2: Reasonable Grey Area +Behavioral changes that customers would have reasonably depended on. **Flag and discuss with user.** + +### Bucket 3: Unlikely Grey Area +Behavioral changes that customers could have depended on but probably wouldn't (e.g., corner case corrections). **Flag with lower confidence.** + +### Bucket 4: Clearly Non-Public +Changes to internal surface or behavior (e.g., internal APIs, private reflection). **Generally not flagged** unless they could affect ecosystem tools. + +## What to Study for Each PR + +For every PR in the release, examine: + +1. **PR description** — Authors often describe breaking changes here +2. **Linked issues** — May contain discussion about breaking impact +3. **Review comments** — Reviewers may have flagged breaking concerns +4. **Code diff** — Look at changes to: + - Public type/member signatures + - Exception throwing patterns + - Default values and constants + - Return value changes + - Parameter validation changes + - Attribute changes (`[Obsolete]`, `[Experimental]`, etc.) +5. **Labels** — Check if `breaking-change` is already applied + +## Breaking Changes Section Format + +When breaking changes exist, format them under the `## Breaking Changes` heading with no introductory blurb (the preamble at the top of the release notes already introduces the breaking changes). Use the numbered list format — GitHub will auto-link `#PR`: + +```markdown +## Breaking Changes + +1. **Description #PR_NUMBER** + * Specific API or behavior that changed + * What existing code needs to do differently + +2. **Another breaking change #PR_NUMBER** + * Detail of the break +``` + +Each breaking change entry should have: +- A bold title with the PR number (GitHub auto-links `#PR`) +- 1-2 bullet points succinctly describing what breaks and how + +### Example from v0.5.0-preview.1 + +```markdown +## Breaking Changes + +1. **Add request options bag to high level requests and include Meta #970** + * High-level request methods refactored to use options bag. Methods `CallToolAsync`, `GetPromptAsync`, `ListResourcesAsync`, etc. now accept a new `RequestOptions` parameter instead of individual `JsonSerializerOptions` and `ProgressToken` parameters. + * Code that passes `JsonSerializerOptions` or `ProgressToken` as named or positional parameters to high-level request methods will break and must be updated to use the `RequestOptions` bag instead. + +2. **Remove obsolete APIs from codebase #985** + * `McpServerFactory` class: Removed obsolete factory class for creating MCP servers. + * `McpClientFactory` class: Removed obsolete factory class for creating MCP clients. + * Obsolete interfaces removed: `IMcpEndpoint`, `IMcpClient`, `IMcpServer` +``` + +### Example: Single breaking change (v0.8.0-preview.1) + +When there is only one breaking change, the numbered format with detail bullets still applies: + +```markdown +## Breaking Changes + +1. **Seal public Protocol reference types to prevent external inheritance #1232** + * Public protocol reference types (e.g. `Tool`, `Prompt`, `Resource`) are now sealed. Code that subclasses these types will no longer compile. +``` diff --git a/.github/skills/release-notes/references/categorization.md b/.github/skills/release-notes/references/categorization.md new file mode 100644 index 000000000..768ed474b --- /dev/null +++ b/.github/skills/release-notes/references/categorization.md @@ -0,0 +1,95 @@ +# Categorization Guide + +## Category Definitions + +### What's Changed +Feature work, bug fixes, API improvements, performance enhancements, and any other user-facing changes. This includes: +- New API surface area (new types, methods, properties) +- Bug fixes that affect runtime behavior +- Performance improvements +- Breaking changes (these appear in both "Breaking Changes" and "What's Changed") +- Changes that span code + docs (categorize based on the primary intent) + +### Documentation Updates +PRs whose **sole purpose** is documentation. Examples: +- Fixing typos in docs +- Adding or improving XML doc comments (when not part of a functional change) +- Updating conceptual documentation (e.g., files in `docs/`) +- README updates +- Adding CONTRIBUTING.md or similar guides + +**Important**: A PR that changes code AND updates docs should go in "What's Changed" — only pure documentation PRs belong here. However, documentation PRs should still be studied during the breaking change audit, as they may document changes that were not properly flagged as breaking. + +### Repository Infrastructure Updates +PRs that maintain the development environment but don't affect the shipped product. Examples: +- Version bumps (`Bump version to X.Y.Z`) +- CI/CD workflow changes (GitHub Actions updates) +- Dependency updates from Dependabot +- Test infrastructure improvements (new test helpers, test fixes, flaky test repairs) +- Build system changes +- Dev container or codespace configuration +- Copilot instructions updates +- NuGet/package configuration changes + +## Entry Format + +Use this simplified format (GitHub auto-links `#PR` and `@user`): +``` +* Description #PR by @author +``` + +For PRs with co-authors (harvested from `Co-authored-by` commit trailers): +``` +* Description #PR by @author (co-authored by @user1 @user2) +``` + +For Dependabot PRs, do not acknowledge @dependabot[bot]: +``` +* Bump actions/checkout from 5.0.0 to 6.0.0 #1234 +``` + +For Copilot-authored PRs, identify who triggered Copilot using the `copilot_work_started` timeline event on the PR. That person becomes the primary author, and @Copilot becomes a co-author: +``` +* Add trace-level logging for JSON-RPC payloads #1234 by @halter73 (co-authored by @Copilot) +``` + +## Sorting + +Sort entries within each section by **merge date** (chronological order, oldest first). + +## Examples from Past Releases + +### What's Changed (format example) +``` +* Add Trace-level logging for JSON-RPC payloads in transports #1191 by @halter73 (co-authored by @Copilot) +* Use Process.Kill(entireProcessTree: true) on .NET for faster process termination #1187 by @stephentoub +* Include response body in HttpRequestException for transport client errors #1193 by @halter73 (co-authored by @Copilot) +* Fix race condition in SSE GET request initialization #1212 by @stephentoub +* Fix keyset pagination with monotonic UUIDv7-like task IDs #1215 by @halter73 (co-authored by @Copilot) +* Add ILoggerFactory to StreamableHttpServerTransport #1213 by @halter73 (co-authored by @Copilot) +* Add support for message-level filters to McpServer #1207 by @halter73 +* Add `DistributedCacheEventStreamStore` #1136 by @MackinnonBuck +``` + +### Documentation Updates (format example) +``` +* Fix typo in elicitation.md #1186 by @ruyut +* Fix typo in progress.md #1189 by @ruyut +* Clarify McpMetaAttribute documentation scope #1242 by @stephentoub (co-authored by @Copilot) +``` + +### Repository Infrastructure Updates (format example) +``` +* Bump version to 0.8.0-preview.1 #1181 by @stephentoub (co-authored by @Copilot) +* Bump actions/checkout from 6.0.1 to 6.0.2 #1173 by @dependabot[bot] +* Bump the opentelemetry-testing group with 6 updates #1174 by @dependabot[bot] +* Remove 10 second wait from docker tests #1188 by @stephentoub +* Fix Session_TracksActivities test #1200 by @stephentoub +``` + +### Acknowledgements (format example) +``` +* @ruyut made their first contribution in #1186 +* @user submitted issue #1234 (resolved by #5678) +* PR reviewers: @user1 @user2 @user3 +``` diff --git a/.github/skills/release-notes/references/formatting.md b/.github/skills/release-notes/references/formatting.md new file mode 100644 index 000000000..96c45b83b --- /dev/null +++ b/.github/skills/release-notes/references/formatting.md @@ -0,0 +1,43 @@ +# Release Notes Formatting Guide + +When creating or editing release notes content, follow these rules to ensure the markdown is well-formed and renders correctly on GitHub. + +## GitHub Auto-Linking + +GitHub automatically links `@username`, `#123`, and `@org/repo#123` references in release notes. Never use full URLs for these — use the shorthand forms: + +- `@stephentoub` not `[@stephentoub](https://github.com/stephentoub)` +- `#1234` not `[#1234](https://github.com/modelcontextprotocol/csharp-sdk/pull/1234)` + +This keeps the markdown source readable and avoids brittle links. + +## Writing the Release Body + +Always compose the full release body as a complete markdown file before uploading. Never perform incremental string replacements on the body through shell commands or API calls — this risks collapsing newlines, introducing encoding artifacts, or corrupting the markdown structure. + +### Workflow for Updates + +When the user requests changes to existing release notes: + +1. Fetch the current release body +2. Write the **entire** corrected body to a local file (ensuring proper line breaks between all sections, entries, and paragraphs) +3. Upload the complete file using `gh release edit --notes-file ` +4. Verify the result by fetching the body again and checking that line count and structure are intact + +### Common Pitfalls + +| Problem | Cause | Prevention | +|---------|-------|------------| +| Body collapses to a single line | PowerShell string manipulation strips newlines during round-trip (variable assignment → `.Replace()` → `WriteAllText`) | Always recreate the full body as a file rather than manipulating in-memory strings | +| UTF-8 BOM / garbage characters | `[System.IO.File]::WriteAllText()` with default encoding adds BOM | Use `UTF8Encoding($false)` or write via a tool that produces BOM-less UTF-8 | +| Stray unicode characters | Encoding mismatch between shell output and file write | Avoid piping `gh` output through PowerShell variable assignment for content that will be written back | + +### Verification Checklist + +After every release body update: + +- [ ] Line count matches expected structure (~80+ lines for a typical release) +- [ ] Section headings (`## Breaking Changes`, `## What's Changed`, etc.) each appear on their own line +- [ ] Bullet entries are each on their own line +- [ ] No stray characters at the start of the body +- [ ] Preview the release on GitHub to confirm rendering From cc3e0744ee9559bfda027216f77147341c02707e Mon Sep 17 00:00:00 2001 From: Jeff Handley Date: Thu, 19 Feb 2026 22:41:16 -0800 Subject: [PATCH 02/10] Refactor breaking-changes into standalone skill Extract the breaking change audit from the release-notes skill into a new breaking-changes skill that can be invoked independently for any commit range. The release-notes skill now delegates to it. - Add .github/skills/breaking-changes/ with SKILL.md and references/classification.md (moved from release-notes) - Simplify release-notes Steps 3-4 into a single delegation step - Renumber release-notes steps from 8 to 7 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/skills/breaking-changes/SKILL.md | 71 +++++++++++++++++++ .../references/classification.md} | 49 +------------ .github/skills/release-notes/SKILL.md | 23 ++---- 3 files changed, 80 insertions(+), 63 deletions(-) create mode 100644 .github/skills/breaking-changes/SKILL.md rename .github/skills/{release-notes/references/breaking-changes.md => breaking-changes/references/classification.md} (58%) diff --git a/.github/skills/breaking-changes/SKILL.md b/.github/skills/breaking-changes/SKILL.md new file mode 100644 index 000000000..ed92263fe --- /dev/null +++ b/.github/skills/breaking-changes/SKILL.md @@ -0,0 +1,71 @@ +--- +name: breaking-changes +description: Audit pull requests for breaking changes in the C# MCP SDK. Examines PR descriptions, review comments, and diffs to identify API and behavioral breaking changes, then reconciles labels with user confirmation. Use when asked to audit breaking changes, check for breaking changes, or review a set of PRs for breaking impact. +compatibility: Requires gh CLI with repo access and GitHub API access for PR details, review history, and labels. +--- + +# Breaking Change Audit + +Audit pull requests in the `modelcontextprotocol/csharp-sdk` repository for breaking changes. This skill examines a range of commits, identifies API and behavioral breaking changes, assesses their impact, reconciles `breaking-change` labels, and returns structured results. + +## Input + +The user provides a commit range in any of these forms: +- `tag..HEAD` (e.g. `v0.8.0-preview.1..HEAD`) +- `tag..tag` (e.g. `v0.8.0-preview.1..v0.9.0-preview.1`) +- `sha..sha` +- `tag..sha` or `sha..HEAD` + +If no range is provided, ask the user to specify one. + +Use the GitHub API to get the full list of PRs merged within the specified range. + +## Process + +### Step 1: Examine Every PR + +For each PR in the range, study: +- PR description and linked issues +- Full review and comment history +- Complete code diff + +Look for both categories of breaking changes: +- **API (compile-time)** — changes to public type signatures, parameter types, return types, removed members, sealed types, new obsoletion attributes, etc. +- **Behavioral (runtime)** — new/changed exceptions, altered return values, changed defaults, modified event ordering, serialization changes, etc. + +See [references/classification.md](references/classification.md) for the full classification guide. + +### Step 2: Assess Impact + +For each identified breaking change, assess: +- **Breadth** — how many consumers are likely affected (widely-used type vs. obscure API) +- **Severity** — compile-time break (immediate build failure) vs. behavioral (subtle runtime difference) +- **Migration** — straightforward fix vs. significant code changes required + +This assessment informs how breaking changes are ordered when presented (most impactful first). + +### Step 3: Reconcile Labels + +Compare findings against existing `breaking-change` labels on PRs. + +Present mismatches to the user interactively: + +- **Unlabeled but appears breaking** → explain why the PR appears breaking, ask user to confirm. If confirmed: apply the `breaking-change` label and ask the user whether to comment on the PR explaining the addition. +- **Labeled but does not appear breaking** → explain why, ask user to confirm removal. If confirmed: remove the label and ask the user whether to comment on the PR explaining the removal. + +### Step 4: Present Results + +Present the final list of confirmed breaking changes, sorted from most impactful to least, with: +- PR number and title +- Classification (API or behavioral) +- Impact assessment summary +- 1-2 bullet description of what breaks and migration guidance + +## Output + +The audit produces a structured list of breaking changes that can be consumed by other skills (e.g. the release-notes skill) or presented directly to the user. + +Each entry contains: +- PR number and description +- Impact ranking (most → least impactful) +- Detail bullets describing the break and migration path diff --git a/.github/skills/release-notes/references/breaking-changes.md b/.github/skills/breaking-changes/references/classification.md similarity index 58% rename from .github/skills/release-notes/references/breaking-changes.md rename to .github/skills/breaking-changes/references/classification.md index 9c526dbef..94344f057 100644 --- a/.github/skills/release-notes/references/breaking-changes.md +++ b/.github/skills/breaking-changes/references/classification.md @@ -1,6 +1,6 @@ # Breaking Change Classification Guide -This guide defines how to identify and classify breaking changes during the release notes process for the C# MCP SDK. It is derived from the [dotnet/runtime breaking change guidelines](https://github.com/dotnet/runtime/blob/main/docs/coding-guidelines/breaking-changes.md). +This guide defines how to identify and classify breaking changes in the C# MCP SDK. It is derived from the [dotnet/runtime breaking change guidelines](https://github.com/dotnet/runtime/blob/main/docs/coding-guidelines/breaking-changes.md). ## Two Categories of Breaking Changes @@ -54,7 +54,7 @@ Changes to internal surface or behavior (e.g., internal APIs, private reflection ## What to Study for Each PR -For every PR in the release, examine: +For every PR in the range, examine: 1. **PR description** — Authors often describe breaking changes here 2. **Linked issues** — May contain discussion about breaking impact @@ -67,48 +67,3 @@ For every PR in the release, examine: - Parameter validation changes - Attribute changes (`[Obsolete]`, `[Experimental]`, etc.) 5. **Labels** — Check if `breaking-change` is already applied - -## Breaking Changes Section Format - -When breaking changes exist, format them under the `## Breaking Changes` heading with no introductory blurb (the preamble at the top of the release notes already introduces the breaking changes). Use the numbered list format — GitHub will auto-link `#PR`: - -```markdown -## Breaking Changes - -1. **Description #PR_NUMBER** - * Specific API or behavior that changed - * What existing code needs to do differently - -2. **Another breaking change #PR_NUMBER** - * Detail of the break -``` - -Each breaking change entry should have: -- A bold title with the PR number (GitHub auto-links `#PR`) -- 1-2 bullet points succinctly describing what breaks and how - -### Example from v0.5.0-preview.1 - -```markdown -## Breaking Changes - -1. **Add request options bag to high level requests and include Meta #970** - * High-level request methods refactored to use options bag. Methods `CallToolAsync`, `GetPromptAsync`, `ListResourcesAsync`, etc. now accept a new `RequestOptions` parameter instead of individual `JsonSerializerOptions` and `ProgressToken` parameters. - * Code that passes `JsonSerializerOptions` or `ProgressToken` as named or positional parameters to high-level request methods will break and must be updated to use the `RequestOptions` bag instead. - -2. **Remove obsolete APIs from codebase #985** - * `McpServerFactory` class: Removed obsolete factory class for creating MCP servers. - * `McpClientFactory` class: Removed obsolete factory class for creating MCP clients. - * Obsolete interfaces removed: `IMcpEndpoint`, `IMcpClient`, `IMcpServer` -``` - -### Example: Single breaking change (v0.8.0-preview.1) - -When there is only one breaking change, the numbered format with detail bullets still applies: - -```markdown -## Breaking Changes - -1. **Seal public Protocol reference types to prevent external inheritance #1232** - * Public protocol reference types (e.g. `Tool`, `Prompt`, `Resource`) are now sealed. Code that subclasses these types will no longer compile. -``` diff --git a/.github/skills/release-notes/SKILL.md b/.github/skills/release-notes/SKILL.md index 503000d44..d068c1457 100644 --- a/.github/skills/release-notes/SKILL.md +++ b/.github/skills/release-notes/SKILL.md @@ -51,28 +51,19 @@ Sort every PR into one of three categories. See [references/categorization.md](r ### Step 3: Breaking Change Audit -Examine **every** PR for breaking changes — both API (compile-time) and behavioral (runtime). For each PR, study the description, linked issues, review comments, and full diff. +Invoke the **breaking-changes** skill with the commit range from the previous release tag to the target commit. That skill handles the full audit — examining every PR, assessing impact, reconciling labels, and getting user confirmation. -For each identified breaking change, assess **impact** (breadth of consumers affected, compile-time vs. behavioral, migration difficulty) to inform the ordering in Step 5. +Use the results (confirmed breaking changes with impact ordering and detail bullets) in the remaining steps. -Compare findings against existing `breaking-change` labels. See [references/breaking-changes.md](references/breaking-changes.md) for classification guidance. - -### Step 4: Reconcile Labels - -Present mismatches to the user interactively: - -- **Unlabeled but appears breaking** → explain why, ask user to confirm. If confirmed: apply label, ask user whether to comment on the PR explaining the addition, and include in Breaking Changes. -- **Labeled but does not appear breaking** → explain why, ask user to confirm removal. If confirmed: remove label, ask user whether to comment on the PR explaining the removal, and exclude from Breaking Changes. - -### Step 5: Review Sections +### Step 4: Review Sections Present each section for user review: -1. **Breaking Changes** — sorted most → least impactful (from Step 3 assessment) +1. **Breaking Changes** — sorted most → least impactful (from Step 3 results) 2. **What's Changed** — chronological; includes breaking change PRs 3. **Documentation Updates** — chronological 4. **Repository Infrastructure Updates** — chronological -### Step 6: Acknowledgements +### Step 5: Acknowledgements Identify contributors beyond PR authors: 1. **New contributors** — first contribution to the repository in this release @@ -87,7 +78,7 @@ Exclude anyone already listed as a PR author. Format: ``` Reviewers go on a single bullet, sorted by number of PRs reviewed (most first), without citing the count. -### Step 7: Final Assembly +### Step 6: Final Assembly 1. **Preamble** — summarize the release theme. If there are breaking changes, mention them and link to the [C# SDK Versioning](https://modelcontextprotocol.github.io/csharp-sdk/versioning.html) docs. Do not repeat preamble text under the Breaking Changes heading. Let the user revise or omit. 2. **Notable callouts** — only if something is extraordinarily noteworthy. @@ -95,7 +86,7 @@ Reviewers go on a single bullet, sorted by number of PRs reviewed (most first), Follow [references/formatting.md](references/formatting.md) when composing and updating the release body. -### Step 8: Create or Update Draft Release +### Step 7: Create or Update Draft Release Display release metadata for user review: - **Title / Tag**: e.g. `v0.9.0-preview.1` From 3dc6b08a60ceb25b9e780f3aa2226d6c8b05ffd6 Mon Sep 17 00:00:00 2001 From: Jeff Handley Date: Thu, 19 Feb 2026 23:41:20 -0800 Subject: [PATCH 03/10] Refine release-notes and breaking-changes skills - Add compat switch guidance to breaking change classification - Break Test Improvements out of Repository Infrastructure category - PRs touching tests/ must not be categorized as Infrastructure - Conformance test PRs require examination of product code changes - Change reviewer acknowledgement format to '@user reviewed pull requests' Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../references/classification.md | 9 ++++++++ .github/skills/release-notes/SKILL.md | 12 +++++++--- .../references/categorization.md | 22 ++++++++++++++++--- 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/.github/skills/breaking-changes/references/classification.md b/.github/skills/breaking-changes/references/classification.md index 94344f057..5b27a1ac0 100644 --- a/.github/skills/breaking-changes/references/classification.md +++ b/.github/skills/breaking-changes/references/classification.md @@ -52,6 +52,14 @@ Behavioral changes that customers could have depended on but probably wouldn't ( ### Bucket 4: Clearly Non-Public Changes to internal surface or behavior (e.g., internal APIs, private reflection). **Generally not flagged** unless they could affect ecosystem tools. +## Compatibility Switches + +When a breaking change includes an `AppContext` switch or other opt-in/opt-out mechanism, always note it in the migration guidance. Search for `AppContext.TryGetSwitch`, `DOTNET_` environment variables, and similar compat patterns in the diff. Include the switch name and the value that alters the behavior: + +``` +* Compat switch: `ModelContextProtocol.AspNetCore.AllowNewSessionForNonInitializeRequests` = `true` restores previous behavior +``` + ## What to Study for Each PR For every PR in the range, examine: @@ -66,4 +74,5 @@ For every PR in the range, examine: - Return value changes - Parameter validation changes - Attribute changes (`[Obsolete]`, `[Experimental]`, etc.) + - `AppContext.TryGetSwitch` or environment variable compat switches 5. **Labels** — Check if `breaking-change` is already applied diff --git a/.github/skills/release-notes/SKILL.md b/.github/skills/release-notes/SKILL.md index d068c1457..75d31fb64 100644 --- a/.github/skills/release-notes/SKILL.md +++ b/.github/skills/release-notes/SKILL.md @@ -35,7 +35,8 @@ Sort every PR into one of three categories. See [references/categorization.md](r |----------|---------| | **What's Changed** | Features, bug fixes, improvements, breaking changes | | **Documentation Updates** | PRs whose sole purpose is documentation | -| **Repository Infrastructure Updates** | CI/CD, tests, dependency bumps, version bumps | +| **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: ``` @@ -61,7 +62,8 @@ Present each section for user review: 1. **Breaking Changes** — sorted most → least impactful (from Step 3 results) 2. **What's Changed** — chronological; includes breaking change PRs 3. **Documentation Updates** — chronological -4. **Repository Infrastructure Updates** — chronological +4. **Test Improvements** — chronological +5. **Repository Infrastructure Updates** — chronological ### Step 5: Acknowledgements @@ -130,6 +132,10 @@ Omit empty sections: * 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) @@ -138,7 +144,7 @@ Omit empty sections: * @user made their first contribution in #PR * @user submitted issue #1234 (resolved by #5678) -* PR reviewers: @user1 @user2 @user3 +* @user1 @user2 @user3 reviewed pull requests **Full Changelog**: previous-tag...new-tag ``` diff --git a/.github/skills/release-notes/references/categorization.md b/.github/skills/release-notes/references/categorization.md index 768ed474b..a3dfc9464 100644 --- a/.github/skills/release-notes/references/categorization.md +++ b/.github/skills/release-notes/references/categorization.md @@ -21,16 +21,27 @@ PRs whose **sole purpose** is documentation. Examples: **Important**: A PR that changes code AND updates docs should go in "What's Changed" — only pure documentation PRs belong here. However, documentation PRs should still be studied during the breaking change audit, as they may document changes that were not properly flagged as breaking. ### Repository Infrastructure Updates -PRs that maintain the development environment but don't affect the shipped product. Examples: +PRs that maintain the development environment but don't affect the shipped product or test coverage. Examples: - Version bumps (`Bump version to X.Y.Z`) - CI/CD workflow changes (GitHub Actions updates) - Dependency updates from Dependabot -- Test infrastructure improvements (new test helpers, test fixes, flaky test repairs) - Build system changes - Dev container or codespace configuration - Copilot instructions updates - NuGet/package configuration changes +**Important**: PRs that touch the `tests/` folder should never be categorized as Infrastructure — they belong in either "Test Improvements" or "What's Changed" depending on whether product code was also modified. + +### Test Improvements +PRs focused on test quality, coverage, or reliability. Examples: +- Adding new tests (unit, integration, regression, conformance) +- Fixing broken or incorrect tests +- Addressing flaky tests (timing, race conditions) +- Unskipping or skipping tests +- Test infrastructure improvements (new test helpers, test base classes) + +**Important**: PRs that reference "MCP conformance tests" are not automatically test-only. Examine the PR body and file changes to determine whether product code was modified to achieve conformance — if so, the PR belongs in "What's Changed." Conformance PRs should never be placed in "Repository Infrastructure Updates." + ## Entry Format Use this simplified format (GitHub auto-links `#PR` and `@user`): @@ -83,13 +94,18 @@ Sort entries within each section by **merge date** (chronological order, oldest * Bump version to 0.8.0-preview.1 #1181 by @stephentoub (co-authored by @Copilot) * Bump actions/checkout from 6.0.1 to 6.0.2 #1173 by @dependabot[bot] * Bump the opentelemetry-testing group with 6 updates #1174 by @dependabot[bot] +``` + +### Test Improvements (format example) +``` * Remove 10 second wait from docker tests #1188 by @stephentoub * Fix Session_TracksActivities test #1200 by @stephentoub +* Add serialization roundtrip tests for all Protocol namespace types #1289 by @stephentoub (co-authored by @Copilot) ``` ### Acknowledgements (format example) ``` * @ruyut made their first contribution in #1186 * @user submitted issue #1234 (resolved by #5678) -* PR reviewers: @user1 @user2 @user3 +* @user1 @user2 @user3 reviewed pull requests ``` From da197ec46ff76c757c89c76b8cd8e2da66c169b3 Mon Sep 17 00:00:00 2001 From: Jeff Handley Date: Thu, 19 Feb 2026 23:50:38 -0800 Subject: [PATCH 04/10] Add bump-version skill Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/skills/bump-version/SKILL.md | 45 ++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 .github/skills/bump-version/SKILL.md diff --git a/.github/skills/bump-version/SKILL.md b/.github/skills/bump-version/SKILL.md new file mode 100644 index 000000000..4d5eb9fde --- /dev/null +++ b/.github/skills/bump-version/SKILL.md @@ -0,0 +1,45 @@ +--- +name: bump-version +description: Bump the SDK version after publishing a release. Reads the current version from src/Directory.Build.props, suggests the next minor version, and creates a pull request with the change. Use when asked to bump the version, prepare for the next release, or increment the version number. +compatibility: Requires gh CLI with repo access for creating branches and pull requests. +--- + +# Bump Version + +Bump the SDK version in `src/Directory.Build.props` after publishing a release and create a pull request with the change. + +## Process + +### Step 1: Read Current Version + +Read `src/Directory.Build.props` on the default branch and extract: +- `` — the `MAJOR.MINOR.PATCH` version +- `` — the prerelease suffix (e.g. `preview.1`), if present + +Display the current version to the user: `{VersionPrefix}-{VersionSuffix}` or `{VersionPrefix}` if no suffix. + +### Step 2: Determine Next Version + +If the user provided a target version in their prompt, use it. Otherwise, suggest the next **minor** version with the same suffix pattern: + +- Current `0.9.0` with suffix `preview.1` → suggest `0.10.0-preview.1` +- Current `1.0.0` with no suffix → suggest `1.1.0` +- Current `1.2.3` with suffix `rc.1` → suggest `1.3.0-rc.1` + +Present the suggestion and let the user confirm or provide an alternative. Parse the confirmed version into its `VersionPrefix` and `VersionSuffix` components. + +### Step 3: Create Pull Request + +1. Create a new branch named `bump-version-to-{version}` (e.g. `bump-version-to-0.10.0-preview.1`) from the default branch +2. Update `src/Directory.Build.props`: + - Set `` to the new prefix + - Set `` to the new suffix, or remove the element if there is no suffix +3. Commit with message: `Bump version to {version}` +4. Push the branch and create a pull request: + - **Title**: `Bump version to {version}` + - **Label**: `infrastructure` + - **Base**: default branch + +### Step 4: Confirm + +Display the pull request URL to the user. From 3bd2da49dd14f3e07b7476869214c3b26589b413 Mon Sep 17 00:00:00 2001 From: Jeff Handley Date: Thu, 19 Feb 2026 23:56:45 -0800 Subject: [PATCH 05/10] Add version bump step to release-notes skill Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/skills/release-notes/SKILL.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/skills/release-notes/SKILL.md b/.github/skills/release-notes/SKILL.md index 75d31fb64..0cdb06fb6 100644 --- a/.github/skills/release-notes/SKILL.md +++ b/.github/skills/release-notes/SKILL.md @@ -103,6 +103,10 @@ After confirmation: When the user requests revisions after the initial update, always rewrite the complete body as a file — never perform in-place string replacements. See [references/formatting.md](references/formatting.md). +### Step 8: Bump Version + +After the draft release is created or updated, inform the user that the draft release is now associated with a known target commit (state the short SHA and commit message) and recommend proceeding with a version bump. Ask if they want to create a pull request to bump the version for the next release. If yes, invoke the **bump-version** skill and let it handle determining or requesting the target version number. + ## Edge Cases - **PR spans categories**: categorize by primary intent From ff4ebbf232d0549c7114f494d95dcf961ff8ab48 Mon Sep 17 00:00:00 2001 From: Jeff Handley Date: Fri, 20 Feb 2026 00:18:28 -0800 Subject: [PATCH 06/10] Require diff confirmation before overwriting published release notes Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/skills/release-notes/references/formatting.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/skills/release-notes/references/formatting.md b/.github/skills/release-notes/references/formatting.md index 96c45b83b..e93411f5a 100644 --- a/.github/skills/release-notes/references/formatting.md +++ b/.github/skills/release-notes/references/formatting.md @@ -21,8 +21,9 @@ When the user requests changes to existing release notes: 1. Fetch the current release body 2. Write the **entire** corrected body to a local file (ensuring proper line breaks between all sections, entries, and paragraphs) -3. Upload the complete file using `gh release edit --notes-file ` -4. Verify the result by fetching the body again and checking that line count and structure are intact +3. **If the release is already published** (not a draft): save the original body to a local file, show the user a diff between the original and updated body, and require explicit confirmation before uploading +4. Upload the complete file using `gh release edit --notes-file ` +5. Verify the result by fetching the body again and checking that line count and structure are intact ### Common Pitfalls From 139f523dc204e58f35be871d7d63ca55e6676020 Mon Sep 17 00:00:00 2001 From: Jeff Handley Date: Fri, 20 Feb 2026 00:18:28 -0800 Subject: [PATCH 07/10] Require diff confirmation before overwriting published release notes Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/skills/release-notes/references/formatting.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/skills/release-notes/references/formatting.md b/.github/skills/release-notes/references/formatting.md index 96c45b83b..9614b24f8 100644 --- a/.github/skills/release-notes/references/formatting.md +++ b/.github/skills/release-notes/references/formatting.md @@ -19,10 +19,11 @@ Always compose the full release body as a complete markdown file before uploadin When the user requests changes to existing release notes: -1. Fetch the current release body -2. Write the **entire** corrected body to a local file (ensuring proper line breaks between all sections, entries, and paragraphs) -3. Upload the complete file using `gh release edit --notes-file ` -4. Verify the result by fetching the body again and checking that line count and structure are intact +1. Fetch the current release body and save it to a local file +2. Write the **entire** corrected body to a separate local file (ensuring proper line breaks between all sections, entries, and paragraphs) +3. **If the release is already published** (not a draft): run `git diff --no-index` between the original and updated files and present the raw diff output to the user. Do not summarize — show the diff and nothing else. Require explicit confirmation before uploading. Before uploading, offer to save the original body to a permanent local file, noting that GitHub does not retain prior versions of release notes. +4. Upload the complete file using `gh release edit --notes-file ` +5. Verify the result by fetching the body again and checking that line count and structure are intact ### Common Pitfalls From aecb4ebb206538ca92a636ced58e17bd3b5df1e0 Mon Sep 17 00:00:00 2001 From: Jeff Handley Date: Fri, 20 Feb 2026 00:48:50 -0800 Subject: [PATCH 08/10] Extract preamble into separate step in release-notes skill Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/skills/release-notes/SKILL.md | 17 +++++++++++++---- .../release-notes/references/formatting.md | 2 +- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/.github/skills/release-notes/SKILL.md b/.github/skills/release-notes/SKILL.md index 0cdb06fb6..4e1331246 100644 --- a/.github/skills/release-notes/SKILL.md +++ b/.github/skills/release-notes/SKILL.md @@ -80,15 +80,24 @@ Exclude anyone already listed as a PR author. Format: ``` Reviewers go on a single bullet, sorted by number of PRs reviewed (most first), without citing the count. -### Step 6: Final Assembly +### Step 6: Preamble -1. **Preamble** — summarize the release theme. If there are breaking changes, mention them and link to the [C# SDK Versioning](https://modelcontextprotocol.github.io/csharp-sdk/versioning.html) docs. Do not repeat preamble text under the Breaking Changes heading. Let the user revise or omit. +Compose a short preamble summarizing the release theme. + +- **New release**: Draft a preamble based on the categorized changes. If there are breaking changes, mention them and link to the [C# SDK Versioning](https://modelcontextprotocol.github.io/csharp-sdk/versioning.html) docs. +- **Editing an existing release**: Extract the current preamble from the release body (text before the first `##` heading) and present it alongside a newly drafted alternative. + +Present the options and let the user choose one, edit one, or enter their own text or markdown. Do not repeat preamble text under the Breaking Changes heading. + +### Step 7: Final Assembly + +1. Combine the confirmed preamble with all sections from previous steps. 2. **Notable callouts** — only if something is extraordinarily noteworthy. 3. Present the **complete release notes** for user approval. Follow [references/formatting.md](references/formatting.md) when composing and updating the release body. -### Step 7: Create or Update Draft Release +### Step 8: Create or Update Draft Release Display release metadata for user review: - **Title / Tag**: e.g. `v0.9.0-preview.1` @@ -103,7 +112,7 @@ After confirmation: When the user requests revisions after the initial update, always rewrite the complete body as a file — never perform in-place string replacements. See [references/formatting.md](references/formatting.md). -### Step 8: Bump Version +### Step 9: Bump Version After the draft release is created or updated, inform the user that the draft release is now associated with a known target commit (state the short SHA and commit message) and recommend proceeding with a version bump. Ask if they want to create a pull request to bump the version for the next release. If yes, invoke the **bump-version** skill and let it handle determining or requesting the target version number. diff --git a/.github/skills/release-notes/references/formatting.md b/.github/skills/release-notes/references/formatting.md index 9614b24f8..9deb434e4 100644 --- a/.github/skills/release-notes/references/formatting.md +++ b/.github/skills/release-notes/references/formatting.md @@ -21,7 +21,7 @@ When the user requests changes to existing release notes: 1. Fetch the current release body and save it to a local file 2. Write the **entire** corrected body to a separate local file (ensuring proper line breaks between all sections, entries, and paragraphs) -3. **If the release is already published** (not a draft): run `git diff --no-index` between the original and updated files and present the raw diff output to the user. Do not summarize — show the diff and nothing else. Require explicit confirmation before uploading. Before uploading, offer to save the original body to a permanent local file, noting that GitHub does not retain prior versions of release notes. +3. **If the release is already published** (not a draft): run `git diff --no-index` between the original and updated files and present the raw diff output directly in the response as a fenced code block with `diff` syntax highlighting. Do not summarize or paraphrase the diff. Require explicit confirmation before uploading. Before uploading, offer to save the original body to a permanent local file, noting that GitHub does not retain prior versions of release notes. 4. Upload the complete file using `gh release edit --notes-file ` 5. Verify the result by fetching the body again and checking that line count and structure are intact From 94f85f6e77ecb422f387dfad520a2de549d10718 Mon Sep 17 00:00:00 2001 From: Jeff Handley Date: Fri, 20 Feb 2026 05:18:58 -0800 Subject: [PATCH 09/10] Revise release process to use Copilot CLI release-notes skill Update the release process documentation to direct maintainers to use the Copilot CLI release-notes skill for preparing releases instead of manually drafting release notes through GitHub.com. This change was made as part of using the new skill to rewrite all past release notes to follow the standardized template with proper categorization, acknowledgements, and formatting. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../references/classification.md | 11 ++++++++ .github/skills/release-notes/SKILL.md | 23 +++++++++------ .../references/categorization.md | 5 ++++ .../release-notes/references/formatting.md | 18 +++++++++--- .github/workflows/release.md | 28 ++++++------------- 5 files changed, 54 insertions(+), 31 deletions(-) diff --git a/.github/skills/breaking-changes/references/classification.md b/.github/skills/breaking-changes/references/classification.md index 5b27a1ac0..036a25e8f 100644 --- a/.github/skills/breaking-changes/references/classification.md +++ b/.github/skills/breaking-changes/references/classification.md @@ -49,6 +49,17 @@ Behavioral changes that customers would have reasonably depended on. **Flag and ### Bucket 3: Unlikely Grey Area Behavioral changes that customers could have depended on but probably wouldn't (e.g., corner case corrections). **Flag with lower confidence.** +### Bug Fixes (Exclude) +Changes that correct incorrect behavior, fix spec compliance, or address security issues are **not breaking changes** even if they alter observable behavior. Examples: +- Fixing encoding to match a specification requirement +- Correcting a logger category or metric name that was wrong +- Fixing exception message leaks that were a security concern +- Moving data to the correct location per protocol spec evolution +- Setting a flag that should have been set automatically (e.g., `IsError` for error content) +- Returning a more specific/informative exception for better diagnostics + +If a change is primarily a bug fix or spec compliance correction, exclude it from the breaking changes list even though the observable behavior changes. + ### Bucket 4: Clearly Non-Public Changes to internal surface or behavior (e.g., internal APIs, private reflection). **Generally not flagged** unless they could affect ecosystem tools. diff --git a/.github/skills/release-notes/SKILL.md b/.github/skills/release-notes/SKILL.md index 4e1331246..1c9a1d253 100644 --- a/.github/skills/release-notes/SKILL.md +++ b/.github/skills/release-notes/SKILL.md @@ -52,7 +52,12 @@ Sort every PR into one of three categories. See [references/categorization.md](r ### Step 3: Breaking Change Audit -Invoke the **breaking-changes** skill with the commit range from the previous release tag to the target commit. That skill handles the full audit — examining every PR, assessing impact, reconciling labels, and getting user confirmation. +Invoke the **breaking-changes** skill with the commit range from the previous release tag to the target commit. The full audit process applies whether creating new release notes or editing existing ones — examine every PR, assess impact, reconcile labels (offering to add/remove labels and comment on PRs), and get user confirmation. + +When **editing an existing release**, also extract any breaking changes already documented in the current release notes (`## Breaking Changes` section). These must be preserved — never remove breaking changes from existing notes. Reconcile the existing documented breaks with the audit results: +- **Previously documented breaks**: keep them, updating formatting if needed +- **Newly discovered breaks**: add them alongside the existing ones +- **Audit finds no issue with a documented break**: still keep it (do not remove without explicit user request) Use the results (confirmed breaking changes with impact ordering and detail bullets) in the remaining steps. @@ -82,12 +87,12 @@ Reviewers go on a single bullet, sorted by number of PRs reviewed (most first), ### Step 6: Preamble -Compose a short preamble summarizing the release theme. +Every release **must** have a preamble — a short paragraph summarizing the release theme that appears before the first `##` heading. The preamble is not optional. The preamble may mention the presence of breaking changes as part of the theme summary, but the versioning documentation link belongs under the Breaking Changes heading (see template), not in the preamble. -- **New release**: Draft a preamble based on the categorized changes. If there are breaking changes, mention them and link to the [C# SDK Versioning](https://modelcontextprotocol.github.io/csharp-sdk/versioning.html) docs. +- **New release**: Draft a preamble based on the categorized changes. - **Editing an existing release**: Extract the current preamble from the release body (text before the first `##` heading) and present it alongside a newly drafted alternative. -Present the options and let the user choose one, edit one, or enter their own text or markdown. Do not repeat preamble text under the Breaking Changes heading. +Present the options and let the user choose one, edit one, or enter their own text or markdown. ### Step 7: Final Assembly @@ -121,18 +126,20 @@ After the draft release is created or updated, inform the user that the draft re - **PR spans categories**: categorize by primary intent - **Copilot timeline missing**: fall back to `Co-authored-by` trailers; if still unclear, use `@Copilot` as primary author - **Draft tag changes**: re-fetch the tag before each `gh release edit` -- **No breaking changes**: omit the Breaking Changes section and breaking change preamble language +- **No breaking changes**: omit the Breaking Changes section entirely - **Single breaking change**: use the same numbered format as multiple ## Release Notes Template -Omit empty sections: +Omit empty sections. The preamble is **always required** — it is not inside a section heading. ```markdown -[Preamble — release theme, breaking changes note, versioning docs link] +[Preamble — REQUIRED. Summarize the release theme.] ## Breaking Changes +Refer to the [C# SDK Versioning](https://modelcontextprotocol.github.io/csharp-sdk/versioning.html) documentation for details on versioning and breaking change policies. + 1. **Description #PR** * Detail of the break * Migration guidance @@ -159,5 +166,5 @@ Omit empty sections: * @user submitted issue #1234 (resolved by #5678) * @user1 @user2 @user3 reviewed pull requests -**Full Changelog**: previous-tag...new-tag +**Full Changelog**: https://github.com/modelcontextprotocol/csharp-sdk/compare/previous-tag...new-tag ``` diff --git a/.github/skills/release-notes/references/categorization.md b/.github/skills/release-notes/references/categorization.md index a3dfc9464..18ae11a84 100644 --- a/.github/skills/release-notes/references/categorization.md +++ b/.github/skills/release-notes/references/categorization.md @@ -59,6 +59,11 @@ For Dependabot PRs, do not acknowledge @dependabot[bot]: * Bump actions/checkout from 5.0.0 to 6.0.0 #1234 ``` +For direct commits without an associated PR (e.g., version bumps merged directly to the branch), use the commit description and `by @author` but omit the `#PR` reference: +``` +* Bump version to v0.1.0-preview.12 by @halter73 +``` + For Copilot-authored PRs, identify who triggered Copilot using the `copilot_work_started` timeline event on the PR. That person becomes the primary author, and @Copilot becomes a co-author: ``` * Add trace-level logging for JSON-RPC payloads #1234 by @halter73 (co-authored by @Copilot) diff --git a/.github/skills/release-notes/references/formatting.md b/.github/skills/release-notes/references/formatting.md index 9deb434e4..467dbb3f2 100644 --- a/.github/skills/release-notes/references/formatting.md +++ b/.github/skills/release-notes/references/formatting.md @@ -11,6 +11,12 @@ GitHub automatically links `@username`, `#123`, and `@org/repo#123` references i This keeps the markdown source readable and avoids brittle links. +**Exception — Full Changelog link**: The `**Full Changelog**` compare link at the bottom of the release notes does **not** auto-link. It must use the full URL format: +``` +**Full Changelog**: https://github.com/modelcontextprotocol/csharp-sdk/compare/previous-tag...new-tag +``` +A bare `previous-tag...new-tag` will render as plain text, not a clickable link. + ## Writing the Release Body Always compose the full release body as a complete markdown file before uploading. Never perform incremental string replacements on the body through shell commands or API calls — this risks collapsing newlines, introducing encoding artifacts, or corrupting the markdown structure. @@ -20,10 +26,12 @@ Always compose the full release body as a complete markdown file before uploadin When the user requests changes to existing release notes: 1. Fetch the current release body and save it to a local file -2. Write the **entire** corrected body to a separate local file (ensuring proper line breaks between all sections, entries, and paragraphs) -3. **If the release is already published** (not a draft): run `git diff --no-index` between the original and updated files and present the raw diff output directly in the response as a fenced code block with `diff` syntax highlighting. Do not summarize or paraphrase the diff. Require explicit confirmation before uploading. Before uploading, offer to save the original body to a permanent local file, noting that GitHub does not retain prior versions of release notes. -4. Upload the complete file using `gh release edit --notes-file ` -5. Verify the result by fetching the body again and checking that line count and structure are intact +2. **Breaking change audit**: Run the full breaking-changes skill audit on the commit range, just as for new release notes — this includes examining PRs, reconciling labels, offering to comment on PRs, and getting user confirmation. Also extract any breaking changes already documented in the existing release body; these must be preserved and reconciled with the audit results. +3. **Preamble check**: Verify the release has a preamble (text before the first `##` heading). If missing, compose one. The versioning documentation link belongs under the `## Breaking Changes` heading, not in the preamble. +4. Write the **entire** corrected body to a separate local file (ensuring proper line breaks between all sections, entries, and paragraphs) +5. Run `git diff --no-index` between the original and updated files and **always** present the raw diff output directly in the response as a fenced code block with `diff` syntax highlighting. Do not summarize or paraphrase the diff — always show the complete diff to the user. Require explicit confirmation before uploading. For published releases (not drafts), also offer to save the original body to a permanent local file, noting that GitHub does not retain prior versions of release notes. +6. Upload the complete file using `gh release edit --notes-file ` +7. Verify the result by fetching the body again and checking that line count and structure are intact ### Common Pitfalls @@ -37,6 +45,8 @@ When the user requests changes to existing release notes: After every release body update: +- [ ] Preamble exists before the first `##` heading +- [ ] If `## Breaking Changes` section exists, it begins with the versioning docs link paragraph before the numbered list - [ ] Line count matches expected structure (~80+ lines for a typical release) - [ ] Section headings (`## Breaking Changes`, `## What's Changed`, etc.) each appear on their own line - [ ] Bullet entries are each on their own line diff --git a/.github/workflows/release.md b/.github/workflows/release.md index 280c35383..4c4ff6855 100644 --- a/.github/workflows/release.md +++ b/.github/workflows/release.md @@ -7,24 +7,13 @@ The following process is used when publishing new releases to NuGet.org: - Once the state of the branch is known to be good, a release can proceed - **The release workflow _does not_ run tests** -2. **Create a new Release in GitHub** - - Use the link on the repo home page to [Create a new release](https://github.com/modelcontextprotocol/csharp-sdk/releases/new) - - Click the 'Choose a tag' dropdown button - - Type the name using the `v{major}.{minor}.{patch}-{suffix}` pattern - - Click 'Create new tag: ... on publish' - - Click the 'Target' dropdown button - - Choose the 'Recent Commits' tab - - Select the commit to use for the release, ensuring it's one from above where CI is known to be green - - The 'Previous tag' dropdown can remain on 'Auto' unless the previous release deviated from this process - - Click the 'Generate release notes button' - - This will add release notes into the Release description - - The generated release notes include what has changed and the list of new contributors - - Verify the Release title - - It will be populated to match the tag name to be created - - This should be retained, using the release title format matching the `v{major}.{minor}.{patch}-{suffix}` format - - Augment the Release description as desired - - This content is presented used on GitHub and is not persisted into any artifacts - - Check the 'Set as a pre-release' button under the release description if appropriate +2. **Prepare release notes using Copilot CLI** + - From a local clone of the repository, use Copilot CLI to invoke the `release-notes` skill + - Provide the target commit (SHA, branch, or tag) when prompted, ensuring it's one from above where CI is known to be green + - The skill will determine the version from `src/Directory.Build.props`, gather PRs, categorize changes, audit breaking changes, identify acknowledgements, and create a **draft** GitHub release + - Review each section as the skill presents it and confirm or adjust as needed + - After the draft release is created, review it on GitHub + - Check the 'Set as a pre-release' checkbox if appropriate - Click 'Publish release' 3. **Monitor the Release workflow** @@ -33,4 +22,5 @@ The following process is used when publishing new releases to NuGet.org: - Verify the package version becomes listed on at [https://nuget.org/packages/ModelContextProtocol](https://www.nuget.org/packages/ModelContextProtocol) 4. **Update the source to increment the version number** - - Immediately after publishing a new release, the [`/src/Directory.Build.Props`](../../src/Directory.Build.props) file needs to be updated to bump the version to the next expected release version + - The `release-notes` skill will offer to invoke the `bump-version` skill to create a pull request bumping the version + - Alternatively, manually update [`/src/Directory.Build.Props`](../../src/Directory.Build.props) to bump the version to the next expected release version From 096a6220232e3b62b0ab6cb2b77085cd07d28a81 Mon Sep 17 00:00:00 2001 From: Jeff Handley Date: Fri, 20 Feb 2026 05:31:33 -0800 Subject: [PATCH 10/10] Incorporate SDK versioning policy into breaking change classification Replace the brief API Deprecation section with a comprehensive SDK Versioning Policy section covering pre-1.0 preview flexibility, Experimental API handling, the three-step obsoletion lifecycle, and spec-driven changes. Reference versioning policies in the skill's Step 1 guidance. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/skills/breaking-changes/SKILL.md | 2 +- .../references/classification.md | 33 +++++++++++++++---- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/.github/skills/breaking-changes/SKILL.md b/.github/skills/breaking-changes/SKILL.md index ed92263fe..425a997a5 100644 --- a/.github/skills/breaking-changes/SKILL.md +++ b/.github/skills/breaking-changes/SKILL.md @@ -33,7 +33,7 @@ Look for both categories of breaking changes: - **API (compile-time)** — changes to public type signatures, parameter types, return types, removed members, sealed types, new obsoletion attributes, etc. - **Behavioral (runtime)** — new/changed exceptions, altered return values, changed defaults, modified event ordering, serialization changes, etc. -See [references/classification.md](references/classification.md) for the full classification guide. +See [references/classification.md](references/classification.md) for the full classification guide, including SDK-specific versioning policies (pre-1.0 preview flexibility, experimental APIs, obsoletion lifecycle, and spec-driven changes) that influence how breaks are assessed. ### Step 2: Assess Impact diff --git a/.github/skills/breaking-changes/references/classification.md b/.github/skills/breaking-changes/references/classification.md index 01382b617..c638f81c2 100644 --- a/.github/skills/breaking-changes/references/classification.md +++ b/.github/skills/breaking-changes/references/classification.md @@ -63,15 +63,36 @@ If a change is primarily a bug fix or spec compliance correction, exclude it fro ### Bucket 4: Clearly Non-Public Changes to internal surface or behavior (e.g., internal APIs, private reflection). **Generally not flagged** unless they could affect ecosystem tools. -## API Deprecation and Removal +## SDK Versioning Policy -The MCP SDK follows a more flexible deprecation policy than fully stable frameworks. In exceptional circumstances, removal of public APIs is permissible provided: +The classification rules above are derived from the dotnet/runtime breaking change guidelines, but the MCP SDK has its own versioning policy (see `docs/versioning.md`) that provides additional context for classification decisions. -- The removal is called out explicitly in planning and release notes -- A relevant `[Obsolete]` attribute is added in an earlier release, giving consumers a migration window -- The removal is documented in the Breaking Changes section with migration guidance +### Pre-1.0 Preview Status -When auditing for breaking changes, API removal that follows this process should still be flagged as a breaking change, but the migration guidance should note the prior deprecation. +Prior to a stable 1.0.0 release, the SDK is in preview and breaking changes can be introduced without prior notice. This does **not** change how breaks are classified — they should still be flagged, labeled, and documented — but it affects the **severity assessment**. Preview consumers expect breaks, so migration guidance matters more than avoidance. + +### Experimental APIs + +APIs annotated with `[Experimental]` (using `MCP`-prefixed diagnostic codes) can change at any time, including within PATCH or MINOR updates. Changes to experimental APIs should still be **noted** in the audit, but classified as **Bucket 3 (Unlikely Grey Area)** or lower unless the API has been widely adopted despite its experimental status. + +### Obsoletion Lifecycle + +The SDK follows a three-step obsoletion process: + +1. **MINOR update**: API marked `[Obsolete]` producing _build warnings_ with migration guidance +2. **MAJOR update**: API marked `[Obsolete]` producing _build errors_ (API throws at runtime) +3. **MAJOR update**: API removed entirely (expected to be rare) + +When auditing, classify each step appropriately: +- Step 1 (adding `[Obsolete]` warning) → API breaking change (new build warning) +- Step 2 (escalating to error) → API breaking change (previously working code now fails) +- Step 3 (removal) → API breaking change; migration guidance should note prior deprecation + +In exceptional circumstances — especially during the pre-1.0 preview period — the obsoletion lifecycle may be compressed (e.g., marking obsolete and removing in the same MINOR release). This should still be flagged as a breaking change but the migration guidance should explain the rationale. + +### Spec-Driven Changes + +Breaking changes necessitated by MCP specification evolution should be flagged and documented normally, but the migration guidance should reference the spec change. If a spec change forces an incompatible API change, preference is given to supporting the most recent spec version. ## Compatibility Switches