C# implementation of SEP-1763 --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
3.6 KiB
3.6 KiB
TODO - Code Style Alignment with MCP C# SDK
This document tracks remaining refactoring items to align the SEP-1763 C# extension code with the official MCP C# SDK coding style and patterns.
Completed
- Add
Throwhelper class - UseThrow.IfNull()for consistent null validation- Added
Common/Throw.cswithIfNull,IfNullOrWhiteSpace, andIfNegativemethods - Added
CallerArgumentExpressionAttributepolyfill for netstandard2.0 - Added
NullableAttributespolyfill for netstandard2.0 - Updated all files to use the new
Throw.IfNull()pattern
- Added
High Priority
- Mark
InterceptorChainExecutorassealed- File:
Client/InterceptorChainExecutor.cs - Change
public class InterceptorChainExecutortopublic sealed class InterceptorChainExecutor - Same for
Server/ServerInterceptorChainExecutor.cs
- File:
Medium Priority
-
Review access modifiers for internal helper types
PayloadConverter- Consider makinginternal static classif only used internallyReflectionMcpClientInterceptor- Alreadyinternal sealed, verify this is appropriateReflectionMcpServerInterceptor- Alreadyinternal sealed, verify this is appropriate
-
Add
DebuggerDisplayto more result types- Files to update:
Protocol/InterceptorChainResult.csProtocol/ValidationInterceptorResult.csProtocol/MutationInterceptorResult.csProtocol/ObservabilityInterceptorResult.cs
- Example pattern:
[DebuggerDisplay("{DebuggerDisplay,nq}")] public sealed class InterceptorChainResult { [DebuggerBrowsable(DebuggerBrowsableState.Never)] private string DebuggerDisplay => $"Status = {Status}, Results = {Results.Count}"; }
- Files to update:
-
Add
DebuggerDisplaytoMcpClientInterceptor/McpServerInterceptor- Show interceptor name and type in debugger
Low Priority
-
Consider source-generated logging
- If logging is added, use
[LoggerMessage]attributes for high-performance logging - Example:
[LoggerMessage(Level = LogLevel.Debug, Message = "Executing interceptor '{InterceptorName}' for event '{Event}'")] private partial void LogInterceptorExecution(string interceptorName, string @event);
- If logging is added, use
-
Evaluate
ValueTaskvsTaskfor hot pathsInterceptorChainExecutor.ExecuteForSendingAsynccurrently returnsTask<InterceptorChainResult>- Consider changing to
ValueTask<InterceptorChainResult>for reduced allocations - Same for
ExecuteForReceivingAsync
-
Consider static field naming convention (
s_prefix)- SDK uses
s_prefix for static private fields - Review codebase for any static fields that should follow this convention
- SDK uses
-
Add
[EditorBrowsable(EditorBrowsableState.Never)]for internal APIs- Hide implementation details from IntelliSense
- Example methods to consider:
- Factory methods that are technically public but not intended for typical use
Notes
SDK Patterns Already Followed
The extension code already follows many SDK patterns:
- File-scoped namespaces
- Nullable reference types
ConfigureAwait(false)on all awaitssealedon appropriate classes (e.g.,InterceptingMcpClient)- Factory methods via static
Create()methods - Comprehensive XML documentation
DebuggerDisplayonInterceptorclassJsonPropertyNameattributesValueTaskforInvokeAsyncmethods- Using declarations (
using var)
Reference
For comparison with the SDK, see:
/mnt/d/code/ai/mcp/csharp-sdk/src/ModelContextProtocol.Core//mnt/d/code/ai/mcp/csharp-sdk/src/Common/Throw.cs