Repository navigation
Align Skills with server primitives and typed request handlers - #1993
Conversation
Pass custom method handlers a RequestContext with raw parameters, request-bound services, and the existing asynchronous scope lifecycle. Migrate Tasks and the existing Skills consumer so the Core signature change stands alone. Document the intentional MCPEXP002 source/binary break and retain the final focused context, scope-ownership, and null-handler regressions. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Separate authored packages from registered primitives, compose typed Skills handlers and filters, and use standard client request options and aggregation. Keep the cohesive replacement together with its validation, integrity, ownership, HTTP, AOT, and conformance coverage, plus samples and docs. Mark public Skills APIs MCPEXP005 and preserve the settled MIME and URI behavior. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
🔵 Needs a closer look
The Core handler ABI break and cross-transport request-scope changes need maintainer confirmation of extension-package compatibility and the reported multi-target and Native AOT validation.
No open issues 🎉
What changed in this PR
This PR aligns Skills with the SDK’s existing server primitives and request lifecycle, replacing the separate catalog abstraction with registered skills, typed handlers, and filters. It supersedes the catalog-based proposal while leaving automatic authorization integration to #1990.
Changes:
- Give custom extension handlers request-bound context and service scopes, and migrate Tasks to the new delegate.
- Replace Skills catalog APIs with package authoring, primitive collections, and application-owned handlers; standardize URI matching and validation errors.
- Update samples, documentation, and regression coverage for authorization, pagination, integrity, protocol versions, and Native AOT.
| File | Description |
|---|---|
tests/ModelContextProtocol.Tests/Server/SkillsUriIdentityTests.cs |
Tests URI aliases, rejected identities, and ambiguous manifests. |
tests/ModelContextProtocol.Tests/Server/SkillsCustomProtocolTests.cs |
Tests direct sampling and elicitation callbacks across protocol versions. |
tests/ModelContextProtocol.Tests/Server/SkillFrontmatterTests.cs |
Migrates frontmatter round-trip tests to package authoring. |
tests/ModelContextProtocol.Tests/Server/SkillFrontmatterRegressionTests.cs |
Migrates parser regressions to package factories. |
tests/ModelContextProtocol.Tests/Server/SkillFrontmatterNodeClassificationTests.cs |
Updates frontmatter classification tests for package authoring. |
tests/ModelContextProtocol.Tests/Server/McpSkillsOptionsTests.cs |
Tests deferred options configuration and collection preservation. |
tests/ModelContextProtocol.Tests/Server/McpSkillDirectorySelectionTests.cs |
Updates directory-selection tests for package options. |
tests/ModelContextProtocol.Tests/Server/McpServerSkillsTests.cs |
Migrates end-to-end tests and strengthens rejection-before-I/O coverage. |
tests/ModelContextProtocol.Tests/Server/McpServerSkillsProviderTests.cs |
Tests shared-result preservation and servers without service providers. |
tests/ModelContextProtocol.Tests/Server/McpServerSkillsOwnershipTests.cs |
Tests handler-owned metadata and copied file bytes. |
tests/ModelContextProtocol.Tests/Server/McpServerSkillsIntegrityTests.cs |
Migrates byte-integrity and requested-file verification tests. |
tests/ModelContextProtocol.Tests/Server/McpServerSkillsFilterTests.cs |
Tests filter ordering, matching, validation, and cache hints. |
tests/ModelContextProtocol.Tests/Server/McpServerSkillsDefaultsTests.cs |
Updates default caching and capability tests. |
tests/ModelContextProtocol.Tests/Server/McpServerSkillAuthoringBoundaryTests.cs |
Removes the separate authoring-boundary test suite. |
tests/ModelContextProtocol.Tests/Server/McpServerNestedUnicodeSkillTests.cs |
Migrates nested Unicode skills and shared-resource tests. |
tests/ModelContextProtocol.Tests/Server/McpServerNativeUriSkillTests.cs |
Migrates native resource URI tests to packages. |
tests/ModelContextProtocol.Tests/Server/CustomRequestHandlerTests.cs |
Tests scope ownership and concurrent request-context isolation. |
tests/ModelContextProtocol.Tests/Server/CustomRequestHandlerCollisionTests.cs |
Adds startup validation coverage for null handlers. |
tests/ModelContextProtocol.Tests/Samples/SkillsClientFrontmatterReaderTests.cs |
Updates sample-reader comparisons to package authoring. |
tests/ModelContextProtocol.Tests/Samples/DatabaseStyleSkillsHandlersTests.cs |
Tests tenant filtering, pagination, aliases, and direct access. |
tests/ModelContextProtocol.Tests/Protocol/SkillSerializationTests.cs |
Tests experimental annotations and manifest/result serialization boundaries. |
tests/ModelContextProtocol.Tests/ModelContextProtocol.Tests.csproj |
Links repository sample code and suppresses Skills diagnostics. |
tests/ModelContextProtocol.Tests/Client/SkillVerifierTests.cs |
Updates exception assertions and adds invalid Base64 coverage. |
tests/ModelContextProtocol.Tests/Client/SkillsRequestOptionsTests.cs |
Tests metadata, progress-token, and cancellation forwarding. |
tests/ModelContextProtocol.Tests/Client/McpSkillsPaginationTests.cs |
Tests opaque cursors, aggregation, and invalid later pages. |
tests/ModelContextProtocol.Tests/Client/McpSkillsEnumerationTests.cs |
Removes tests for retired enumeration limits and cursor tracking. |
tests/ModelContextProtocol.Tests/Client/McpSkillsClientUnreadableTextTests.cs |
Removes the former raw-response unreadable-text suite. |
tests/ModelContextProtocol.ConformanceServer/Skills/ConformanceSkills.cs |
Replaces catalog construction with packages and registered primitives. |
tests/ModelContextProtocol.ConformanceServer/Program.cs |
Registers Skills primitives without catalog-wide cache settings. |
tests/ModelContextProtocol.ConformanceServer/ModelContextProtocol.ConformanceServer.csproj |
Suppresses the experimental Skills diagnostic. |
tests/ModelContextProtocol.AspNetCore.Tests/SkillsProtocolBoundaryTests.cs |
Tests callback behavior on stateful and stateless HTTP. |
tests/ModelContextProtocol.AspNetCore.Tests/SkillsDependencyInjectionTests.cs |
Tests request-service identity and asynchronous disposal. |
tests/ModelContextProtocol.AspNetCore.Tests/SkillsAuthorizationTests.cs |
Tests explicit Skills and resource authorization separately. |
tests/ModelContextProtocol.AspNetCore.Tests/ModelContextProtocol.AspNetCore.Tests.csproj |
Suppresses the experimental Skills diagnostic. |
tests/ModelContextProtocol.AotCompatibility.TestApp/Program.cs |
Exercises packages, filters, fallback handlers, and scoped services under AOT. |
tests/ModelContextProtocol.AotCompatibility.TestApp/ModelContextProtocol.AotCompatibility.TestApp.csproj |
Suppresses the experimental Skills diagnostic. |
src/ModelContextProtocol.Extensions.Tasks/Server/McpTasksBuilderExtensions.cs |
Migrates Tasks handlers to contextual parameters. |
src/ModelContextProtocol.Extensions.Skills/SkillValidation.cs |
Updates URI validation, removes size ceilings, and standardizes errors. |
src/ModelContextProtocol.Extensions.Skills/SkillUriComparer.cs |
Adds URI-equivalent identity comparison. |
src/ModelContextProtocol.Extensions.Skills/SkillsProtocol.cs |
Marks constants experimental and removes file-count/size limits. |
src/ModelContextProtocol.Extensions.Skills/Server/McpSkillsOptions.cs |
Introduces primitive collections, typed handlers, and filters. |
src/ModelContextProtocol.Extensions.Skills/Server/McpSkillRequestContext.cs |
Removes the Skills-specific request context. |
src/ModelContextProtocol.Extensions.Skills/Server/McpSkillPage.cs |
Removes the catalog-specific page type. |
src/ModelContextProtocol.Extensions.Skills/Server/McpServerSkillPackageDiscoveryOptions.cs |
Adds directory-discovery and shared metadata options. |
src/ModelContextProtocol.Extensions.Skills/Server/McpServerSkillPackageCreateOptions.cs |
Adds package authoring options and settings capture. |
src/ModelContextProtocol.Extensions.Skills/Server/McpServerSkillFile.cs |
Updates authoring documentation and marks the type experimental. |
src/ModelContextProtocol.Extensions.Skills/Server/McpServerSkillCollection.cs |
Adds a thread-safe, URI-indexed primitive collection. |
src/ModelContextProtocol.Extensions.Skills/Server/InMemoryMcpSkillCatalog.cs |
Removes the fixed catalog and its pagination policy. |
src/ModelContextProtocol.Extensions.Skills/Server/IMcpSkillCatalog.cs |
Removes the parallel catalog abstraction. |
src/ModelContextProtocol.Extensions.Skills/Protocol/SkillResourcesConverter.cs |
Rejects null manifests and null entries during serialization. |
src/ModelContextProtocol.Extensions.Skills/Protocol/SkillResources.cs |
Renames manifest entries and annotates dynamic-state nullability. |
src/ModelContextProtocol.Extensions.Skills/Protocol/SkillResource.cs |
Marks the type experimental and updates its specification link. |
src/ModelContextProtocol.Extensions.Skills/Protocol/Skill.cs |
Clarifies validation responsibilities and preserves manifest serialization. |
src/ModelContextProtocol.Extensions.Skills/Protocol/ListSkillsResult.cs |
Marks listing results experimental and updates documentation. |
src/ModelContextProtocol.Extensions.Skills/Protocol/ListSkillsRequestParams.cs |
Marks listing parameters experimental and updates documentation. |
src/ModelContextProtocol.Extensions.Skills/Protocol/GetSkillResult.cs |
Marks get results experimental and updates documentation. |
src/ModelContextProtocol.Extensions.Skills/Protocol/GetSkillRequestParams.cs |
Marks get parameters experimental and updates documentation. |
src/ModelContextProtocol.Extensions.Skills/ModelContextProtocol.Extensions.Skills.csproj |
Adds nullable-attribute polyfills and diagnostic suppression. |
src/ModelContextProtocol.Extensions.Skills/McpSkillsJsonContext.cs |
Marks the serialization context experimental. |
src/ModelContextProtocol.Extensions.Skills/Client/SkillVerifier.cs |
Uses standard errors, URI equivalence, and ambiguous-entry rejection. |
src/ModelContextProtocol.Extensions.Skills/Client/SkillVerificationException.cs |
Removes the Skills-specific verification exception. |
src/ModelContextProtocol.Extensions.Skills/Client/SkillListingResult.cs |
Removes the partial-result listing wrapper. |
src/ModelContextProtocol.Extensions.Skills/Client/SkillEntryRejection.cs |
Removes per-entry rejection reporting. |
src/ModelContextProtocol.Core/Server/McpServerRequestHandler.cs |
Changes custom handlers to receive standard request context. |
src/ModelContextProtocol.Core/Server/McpServerOptions.cs |
Documents contextual handlers and method uniqueness. |
src/ModelContextProtocol.Core/Server/McpServerImpl.cs |
Routes custom handlers through normal invocation and validates null handlers. |
src/ModelContextProtocol.Core/CompatibilitySuppressions.xml |
Records the intentional experimental handler compatibility break. |
src/Common/Experimentals.cs |
Defines the dedicated Skills diagnostic and documentation URL. |
samples/SkillsServer/SkillsServer.csproj |
Suppresses the experimental Skills diagnostic. |
samples/SkillsServer/README.md |
Documents package registration and repository-backed handler patterns. |
samples/SkillsServer/Program.cs |
Uses subdirectory registration with conservative cache defaults. |
samples/SkillsServer/DatabaseStyleHandlers.cs |
Demonstrates scoped handlers with in-memory tenant-aware queries. |
samples/SkillsClient/SkillsClient.csproj |
Suppresses the experimental Skills diagnostic. |
samples/SkillsClient/README.md |
Documents strict validation and application-owned pagination budgets. |
docs/list-of-diagnostics.md |
Documents Skills opt-in and custom-handler migration requirements. |
docs/concepts/filters.md |
Explains Skills filters and their separate authorization boundary. |
Review effort: Balanced
|
Non-blocking API design suggestion: request-owned Skills responses Could we make the protocol objects exposed to Skills filters request-owned, rather than sharing the registered The current ownership rules are documented, so this is not a correctness issue against that contract. However, a filter that modifies a returned skill's A clearer ownership model would be: Registered definition → request-owned response → filters → serialization This would require copying mutable protocol data, including nested JSON and manifest entries, but not file bytes or arbitrary server-local metadata. Snapshotting caller-supplied protocol data during package creation could separately protect the definition from later input mutations. There is an allocation tradeoff worth measuring. Before this API stabilizes, I would prefer making response mutation safe by construction rather than requiring every filter author to understand the sharing rules. A focused regression test could mutate an entry in one request's filter and verify that the registered definition and another request's response remain unchanged. |
|
Non-blocking follow-up: common bounded aggregation Could we track a separate issue for caller-controlled aggregation budgets across the SDK's list APIs, including tools, prompts, resources and Skills? The convenience methods collect pages until the server ends pagination. A faulty or untrusted server can therefore cause unbounded requests or accumulated results. Cancellation helps bound elapsed time, but does not directly bound page or entry counts. A common design could support optional maximum-page and maximum-entry budgets alongside cancellation, with consistent behavior when a limit is reached. It should preserve existing defaults and avoid silently presenting partial results as complete. This does not need to expand the current PR. Applications can already enforce budgets through the single-page overloads; the follow-up would evaluate whether the SDK should provide a consistent convenience API rather than introducing Skills-only limits. |
Apply MCPEXP005 directly to public builder and client extension methods, with lightweight checks in the existing metadata test. Remove the distracting MRTR discussion and restrict the direct-callback success test to the legacy protocol. Retain the documented shared-definition ownership model without a fixed-get-only copy guarantee. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
I added On ownership, I’m retaining the documented shared-definition model, consistent with Core resource listings. Each fixed get already creates a fresh I opened issues to track cross-SDK aggregation budgets with #1996 and consistent strict/diagnostic entry validation in #1997. They’re cross-linked. The single-page overloads remain available for application-owned budgets and pagination policy. |
|
CC @girishkvs |
Authorize fixed resource reads by matched primitive ID and cover equivalent URI aliases. Reuse one manifest index for requested-file and returned-content verification while preserving ambiguity, integrity, and error checks. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
I changed both resource-read filters to authorize Verification now builds one index with I'm not adding startup warnings here. They would add startup/logging plumbing while only covering registration-time collisions, and wouldn't establish whether an override actually serves different bytes. Verified reads already report digest and size mismatches. |
| or counting them toward the published manifest's limits. The `includeHiddenAndSystemFiles: true` overloads of | ||
| `WithSkillsFromDirectory` and `McpServerSkill.CreateFromDirectory` provide an explicit opt-in. For a narrower | ||
| selection, use `McpServerSkill.Create` with explicit files; that API keeps the files the caller selected. | ||
| Names used as URI path segments are percent-encoded. |
There was a problem hiding this comment.
| Names used as URI path segments are percent-encoded. | |
| Names used as URI path segments are escaped with [`Uri.EscapeDataString`](https://learn.microsoft.com/dotnet/api/system.uri.escapedatastring). |
| /// Percent-encodes each segment of a normalized relative path so that characters with URI syntax (such as | ||
| /// <c>{</c>, <c>?</c>, <c>#</c>, or a space) in a file name stay literal. Without this, a file named | ||
| /// <c>{name}.md</c> would register as a resource template rather than a concrete resource. |
There was a problem hiding this comment.
| /// Percent-encodes each segment of a normalized relative path so that characters with URI syntax (such as | |
| /// <c>{</c>, <c>?</c>, <c>#</c>, or a space) in a file name stay literal. Without this, a file named | |
| /// <c>{name}.md</c> would register as a resource template rather than a concrete resource. | |
| /// Each segment of a normalized relative path is escaped with <see cref="Uri.EscapeDataString(string)"/> so that | |
| /// characters with URI syntax (such as <c>{</c>, <c>?</c>, <c>#</c>, or a space) in a file name stay literal. | |
| /// Without this, a file named <c>{name}.md</c> would register as a resource template rather than a concrete resource. |
| /// Defaults to <c>skill://</c>. A missing trailing slash is added to a local copy. Names used as path | ||
| /// segments are percent-encoded. Each discovered skill reads its own frontmatter. |
There was a problem hiding this comment.
| /// Defaults to <c>skill://</c>. A missing trailing slash is added to a local copy. Names used as path | |
| /// segments are percent-encoded. Each discovered skill reads its own frontmatter. | |
| /// Defaults to <c>skill://</c>. A missing trailing slash is added to a local copy. | |
| /// Names used as URI path segments are escaped with <see cref="Uri.EscapeDataString(string)"/>. | |
| /// Each discovered skill reads its own frontmatter. |
| where they are required and default to `0` and `private` when unset, the same conservative defaults the built-in | ||
| list methods use. On earlier revisions, which reject them as unrecognized keys, they are omitted. Both methods use | ||
| the same configured hints, so use `public` only when the listing and every entry are identical for every caller. | ||
| The factories do not require DI. `CreateFromSubdirectories` also returns standalone packages. |
There was a problem hiding this comment.
| The factories do not require DI. `CreateFromSubdirectories` also returns standalone packages. | |
| The factories do not require dependency injection. `CreateFromSubdirectories` also returns standalone packages. |
|
|
||
| This example filters unpaginated static Skills and resource listings. For paginated sources, authorize before forming | ||
| pages and cursors; filtering afterwards cannot repair a cursor that reveals hidden entries. Listing omission never | ||
| denies get or file read. Skills and resource filters are independent, with no automatic policy inheritance. | ||
| Automatic participation in ASP.NET Core | ||
| `AddAuthorizationFilters` is deferred and tracked by [#1990](https://github.com/modelcontextprotocol/csharp-sdk/issues/1990). |
There was a problem hiding this comment.
| This example filters unpaginated static Skills and resource listings. For paginated sources, authorize before forming | |
| pages and cursors; filtering afterwards cannot repair a cursor that reveals hidden entries. Listing omission never | |
| denies get or file read. Skills and resource filters are independent, with no automatic policy inheritance. | |
| Automatic participation in ASP.NET Core | |
| `AddAuthorizationFilters` is deferred and tracked by [#1990](https://github.com/modelcontextprotocol/csharp-sdk/issues/1990). | |
| > [!IMPORTANT] | |
| > This example filters unpaginated static Skills and resource listings. For paginated sources, authorize before forming | |
| > pages and cursors; filtering afterwards cannot repair a cursor that reveals hidden entries. Listing omission never | |
| > denies get or file read. Skills and resource filters are independent, with no automatic policy inheritance. | |
| > Automatic participation in ASP.NET Core `AddAuthorizationFilters` is not yet integrated and | |
| > tracked by [#1990](https://github.com/modelcontextprotocol/csharp-sdk/issues/1990). |
| | `skill://refunds/SKILL.md` | `SKILL.md`, `policy/REFUND_POLICY.md`, `examples/approved.md`, `examples/declined.md` | | ||
|
|
||
| `WithSkillsFromDirectory` reads every skill directory, parses the YAML frontmatter of each `SKILL.md`, computes the | ||
| `WithSkillsFromSubdirectories` reads every skill directory, parses the YAML frontmatter of each `SKILL.md`, computes the |
There was a problem hiding this comment.
Not for this initial version, but I'd like to consider the alternate name of WithSkillsFromDirectories as an attempt to connote that it looks at immediate directories only, vs. nested subdirectories.
There was a problem hiding this comment.
I still like WithSkillsFromSubdirectories over WithSkillsFromDirectories. The current name communicates that the argument is a parent directory whose children contain skills. The proposed name could sound like it accepts several directory paths, and neither name inherently guarantees nonrecursive discovery. Explicitly documenting "immediate child directories" does more to resolve that ambiguity.
|
I opened #2000 to make you suggested doc changes. |
Summary
Replace the Skills-specific catalog model with the same building blocks used for other server primitives: registered skills, typed request handlers and filters, ordinary file resources, and application-owned storage.
The goal is not to remove database-backed skills. It is to support them without a parallel catalog abstraction, bespoke request context, or separate service-scope rules. A database-backed Skills source can work like a database-backed resource source: resolve the repository from the actual request's services, enforce the application's policy, and return a typed result.
Related work
Review order
This PR contains two dependency-ordered commits:
McpRequestHandler<JsonNode?, JsonNode?>, pass the existingRequestContextthrough the normal invocation path, migrate Tasks, and include the minimal old-Skills adapter needed for this commit to stand alone. The tests and migration documentation are in the same commit.What changes
Request-time and database-backed sources
McpSkillsOptions.ListSkillsHandlerandGetSkillHandlerreplaceIMcpSkillCatalog. They use the standard typed handler delegate and receive the request's parameters, services, caller, server, items, and cancellation token. Applications can resolve a scoped repository orDbContextfromcontext.Services; they no longer need a catalog-specific wrapper or a separately created scope.The Core change is useful beyond Skills: independently packaged extensions can use the same request-bound services and asynchronous scope ownership as built-in methods. Stateless HTTP retains
HttpContext.RequestServices; other transports honor the existingScopeRequestsbehavior. Skills does not create an additional nested scope, and this PR does not change filter-factory lifetimes.Applications own query predicates, ordering, page boundaries, and cursors. Tenant/permission checks belong in the query before pagination. The database-style sample demonstrates the wiring with a fixed in-memory store; it is not presented as a database or authentication implementation. It also shows ordinary
resources/listandresources/readhandlers for the same content.Registered skills and authored packages
McpServerSkillis a primitive with an immutable identity, an optional listing entry, local metadata, and asynchronousGetAsync. A get-only registration can remain unlisted while still being retrievable directly. Listing and initialization do not invoke its get implementation.McpServerSkillPackageauthors a skill and the ordinary resources serving its files, independently of DI. File/directory factories compute the manifest from owned file bytes.WithSkillPackagesregisters both components; applications can also register the skill and resources separately.Filters, authorization, and protocol handling
Typed Skills list/get filters wrap both registered and application-provided entries. Get filters can inspect
MatchedPrimitive; final results are structurally checked after filters, and get results must match the requested URI.Skills authorization is explicit and separate from file-resource authorization. The fixed-collection example now protects all four discovery/access paths: denied callers receive empty
skills/listandresources/listresults, and get/read operations enforce their own checks. The HTTP regression checks registered and application-provided resources under both modern and legacy protocol versions. The pagination caveat remains: post-filtering a page cannot make a revealing cursor safe.No automatic
AddAuthorizationFiltersintegration, resource-ownership policy infrastructure, or new authorization framework is introduced.For
2026-07-28+, wire results useresultType: "complete"and conservative default cache hints (ttlMs: 0,cacheScope: "private"). Earlier protocols omit these fields. Cache hints are set on results or in filters rather than as one catalog-wide option, and wire shaping does not mutate shared application results.Client behavior and integrity
Client convenience methods use standard
RequestOptions, including forwarding options to verified resource reads. Capability checks useServerCapabilities.SupportsSkills().ListSkillsAsync()aggregates pages intoIList<Skill>like the tools/resources/prompts helpers; the explicit-parameters overload returns one page with its cursor and cache hints.Invalid entries fail the operation rather than being silently dropped. Validation/integrity errors use
InvalidDataException, malformed result shapes retain JSON errors, and RPC failures retain normal MCP exceptions.Verified reads check manifest membership before I/O, then verify the returned URI, bytes, size, and digest. The no-I/O regression now serves a real resource outside the held manifest and counts handler invocations, so a client that reads first and rejects afterward fails the test. Digest agreement still does not establish frontmatter agreement: hosts must independently parse the fetched
SKILL.mdand compare it with the advertised JSON. The client sample demonstrates that with its real YamlDotNet-backed reader.Removed or deferred surfaces
IMcpSkillCatalog,InMemoryMcpSkillCatalog,McpSkillPage, andMcpSkillRequestContext. Their storage scenario moves to standard handlers/registered primitives; it is not dropped.ListSkillsWithDiagnosticsAsync,SkillListingResult, andSkillEntryRejection. Partial-result/rejection reporting is deferred until there is a consistent design for analogous resources/tools/prompts behavior. Ordinary listing remains strict.SkillVerificationExceptionin favor of standard exception types, and move catalog-wide cache settings to per-result hints.The optional directory-read protocol method and automatic authorization integration remain outside this change.
Compatibility and focused cleanup
The
MCPEXP002custom-handler signature change is intentionally source- and binary-breaking: extensions compiled against the old property must be rebuilt, and explicitly typed handlers must switch fromJsonRpcRequesttoRequestContext<JsonNode?>. The raw envelope remains available ascontext.JsonRpcRequest; operation parameters come fromcontext.Params.All public Skills APIs are marked
MCPEXP005, reflecting the extension's experimental/Beta status.The final cleanup keeps semantic/scalar validation at its shared boundary and retains representative file/directory, implicit/explicit URI, and public-argument forwarding tests. It removes the pretend host verifier, callback-only cancellation matrix, and sample-constructor duplicate-identity test. Owned bytes, metadata preservation, manifest/frontmatter disagreement, real sample-reader behavior, and transport-level behavior remain covered.
Validation
dotnet build --no-restore: 0 warnings, 0 errors.net10.0,net9.0, andnet8.0; 900 passed onnet472.net10.0,net9.0, andnet8.0.expected 0,actual 1), even though its exception assertion still passed. That mutation was reverted before the final build and passing runs.Note
This pull request and its description were prepared with GitHub Copilot.