Skip to content

C# SDK: align mode value and priorityHint with the SEP#17

Open
PederHP wants to merge 3 commits into
mainfrom
fix/issue-15-mode-priorityhint
Open

C# SDK: align mode value and priorityHint with the SEP#17
PederHP wants to merge 3 commits into
mainfrom
fix/issue-15-mode-priorityhint

Conversation

@PederHP

@PederHP PederHP commented Jun 11, 2026

Copy link
Copy Markdown
Member

Addresses the first two items of #15 (the chain-orchestrator multi-server item follows in a separate PR).

mode: "active""enforce"

The SEP defines mode?: "enforce" | "audit"; the C# SDK serialized "active", making it incompatible with the TypeScript SDK. InterceptorMode.Active is renamed to Enforce with wire value "enforce". Clean break — "active" is no longer accepted on read (experimental extension; the old value was never spec-compliant).

priorityHint: support number | { request?, response? }

The SDK only supported a plain int. This adds a PriorityHint protocol type whose converter accepts both wire forms and preserves them on round-trip (a number stays a number, an object stays an object). Chain ordering now resolves the effective priority per phase exactly as the SEP's resolvePriority algorithm (unset → 0, alphabetical tie-break unchanged).

  • Interceptor.PriorityHint is now PriorityHint?; an implicit conversion from int keeps existing code compiling.
  • [McpServerInterceptor] gains RequestPriorityHint / ResponsePriorityHint (mutually exclusive with the scalar PriorityHint), following the official SDK's backing-field pattern for optional attribute values.
  • Behavior note: attribute-discovered interceptors with no priority set now omit priorityHint from the wire instead of emitting 0 — semantically identical per the SEP default, and consistent with the existing default-skipping for Mode/FailOpen.

Testing

dotnet test from csharp/sdk/: 87 passing (was 66), including new coverage for both wire forms, partial objects, unknown-key tolerance, phase-dependent mutation ordering (the SEP's pii-redactor/compressor example), and the attribute conflict error.

Part of #15.

🤖 Generated with Claude Code

PederHP and others added 2 commits June 11, 2026 17:22
The SEP defines mode as "enforce" | "audit"; the C# SDK used "active" on
the wire, making it incompatible with the TypeScript SDK. Renames the
enum member and wire value, updates the attribute default and the
default-skipping logic, and adds a deserialization test.

Part of #15.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The SEP allows priorityHint to be either a single number or
{ request?, response? } with different priorities per phase; the C# SDK
only supported a plain int. Adds a PriorityHint type with a converter
that round-trips both wire forms, resolves effective priority per phase
in chain ordering, and exposes RequestPriorityHint/ResponsePriorityHint
on the interceptor attribute.

Attribute-discovered interceptors with no priority set now omit
priorityHint from the wire instead of emitting 0 (semantically identical
per the SEP default, and consistent with Mode/FailOpen default-skipping).

Part of #15.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Aligns the C# interceptors SDK with SEP-1763 by updating the mode wire value to match the spec and extending priorityHint to support both scalar and per-phase object forms, including phase-specific mutation ordering in the chain orchestrator.

Changes:

  • Renames InterceptorMode.ActiveInterceptorMode.Enforce and updates default/serialization behavior accordingly.
  • Introduces PriorityHint protocol type + JSON converter to round-trip number | { request?, response? } faithfully.
  • Updates chain orchestration to sort mutations by phase-effective priority and adds/updates tests for new semantics and attribute behavior.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
csharp/sdk/src/ModelContextProtocol.Interceptors/Protocol/InterceptorMode.cs Changes enum member/wire value from active to enforce.
csharp/sdk/src/ModelContextProtocol.Interceptors/Protocol/PriorityHint.cs Adds new protocol type + converter supporting scalar/object priority hints.
csharp/sdk/src/ModelContextProtocol.Interceptors/Protocol/Interceptor.cs Changes PriorityHint property type to PriorityHint? and updates docs.
csharp/sdk/src/ModelContextProtocol.Interceptors/InterceptorJsonContext.cs Registers PriorityHint for source-generated JSON support.
csharp/sdk/src/ModelContextProtocol.Interceptors/Server/McpServerInterceptorAttribute.cs Adds optional per-phase priority hint attribute properties with backing fields.
csharp/sdk/src/ModelContextProtocol.Interceptors/Server/ReflectionMcpServerInterceptor.cs Omits default Enforce mode on the wire and resolves scalar vs per-phase priority hints (with conflict error).
csharp/sdk/src/ModelContextProtocol.Interceptors/Client/InterceptorChainOrchestrator.cs Sorts mutations by phase-effective priority hint.
csharp/sdk/tests/ModelContextProtocol.Interceptors.Tests/ProtocolTypesSerializationTests.cs Adds serialization/round-trip coverage for PriorityHint and updated InterceptorMode.
csharp/sdk/tests/ModelContextProtocol.Interceptors.Tests/ReflectionMcpServerInterceptorTests.cs Adds tests for per-phase attribute hints, omission when unset, and conflict detection.
csharp/sdk/tests/ModelContextProtocol.Interceptors.Tests/InterceptorChainOrchestratorTests.cs Adds tests for phase-dependent ordering, default-zero behavior, and tie-breaking.
csharp/sdk/README.md Documents per-phase priority hint usage for mutation ordering.
csharp/sdk/CLAUDE.md Updates test count and documents expanded PriorityHint semantics.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

ExecuteChainRequestParams.Phase could be set to InterceptorPhase.Both,
which is documented as attribute-only and invalid on the wire. The
orchestrator would silently match no hooks while ordering and branching
as if it were the response phase. Throw ArgumentException up front
instead.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@PederHP

PederHP commented Jun 11, 2026

Copy link
Copy Markdown
Member Author

Good catch from Copilot — ExecuteChainRequestParams.Phase could indeed be set to the attribute-only InterceptorPhase.Both, which would silently match no hooks while branching as if it were the response phase. Added an explicit guard in 82b552f: the orchestrator now throws ArgumentException for any non-Request/Response phase, with a test covering it.

(Authored by Claude Fable 5)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants