@@ -12,6 +12,12 @@ namespace ModelContextProtocol.Client;
12
12
/// <inheritdoc/>
13
13
internal sealed class McpClient : McpEndpoint , IMcpClient
14
14
{
15
+ private static Implementation DefaultImplementation { get ; } = new ( )
16
+ {
17
+ Name = DefaultAssemblyName . Name ?? nameof ( McpClient ) ,
18
+ Version = DefaultAssemblyName . Version ? . ToString ( ) ?? "1.0.0" ,
19
+ } ;
20
+
15
21
private readonly IClientTransport _clientTransport ;
16
22
private readonly McpClientOptions _options ;
17
23
@@ -29,43 +35,53 @@ internal sealed class McpClient : McpEndpoint, IMcpClient
29
35
/// <param name="options">Options for the client, defining protocol version and capabilities.</param>
30
36
/// <param name="serverConfig">The server configuration.</param>
31
37
/// <param name="loggerFactory">The logger factory.</param>
32
- public McpClient ( IClientTransport clientTransport , McpClientOptions options , McpServerConfig serverConfig , ILoggerFactory ? loggerFactory )
38
+ public McpClient ( IClientTransport clientTransport , McpClientOptions ? options , McpServerConfig serverConfig , ILoggerFactory ? loggerFactory )
33
39
: base ( loggerFactory )
34
40
{
41
+ options ??= new ( ) ;
42
+
35
43
_clientTransport = clientTransport ;
36
44
_options = options ;
37
45
38
46
EndpointName = $ "Client ({ serverConfig . Id } : { serverConfig . Name } )";
39
47
40
- if ( options . Capabilities ? . Sampling is { } samplingCapability )
48
+ if ( options . Capabilities is { } capabilities )
41
49
{
42
- if ( samplingCapability . SamplingHandler is not { } samplingHandler )
50
+ if ( capabilities . NotificationHandlers is { } notificationHandlers )
43
51
{
44
- throw new InvalidOperationException ( $ "Sampling capability was set but it did not provide a handler." ) ;
52
+ NotificationHandlers . AddRange ( notificationHandlers ) ;
45
53
}
46
54
47
- SetRequestHandler (
48
- RequestMethods . SamplingCreateMessage ,
49
- ( request , cancellationToken ) => samplingHandler (
50
- request ,
51
- request ? . Meta ? . ProgressToken is { } token ? new TokenProgress ( this , token ) : NullProgress . Instance ,
52
- cancellationToken ) ,
53
- McpJsonUtilities . JsonContext . Default . CreateMessageRequestParams ,
54
- McpJsonUtilities . JsonContext . Default . CreateMessageResult ) ;
55
- }
56
-
57
- if ( options . Capabilities ? . Roots is { } rootsCapability )
58
- {
59
- if ( rootsCapability . RootsHandler is not { } rootsHandler )
55
+ if ( capabilities . Sampling is { } samplingCapability )
60
56
{
61
- throw new InvalidOperationException ( $ "Roots capability was set but it did not provide a handler.") ;
57
+ if ( samplingCapability . SamplingHandler is not { } samplingHandler )
58
+ {
59
+ throw new InvalidOperationException ( $ "Sampling capability was set but it did not provide a handler.") ;
60
+ }
61
+
62
+ RequestHandlers . Set (
63
+ RequestMethods . SamplingCreateMessage ,
64
+ ( request , cancellationToken ) => samplingHandler (
65
+ request ,
66
+ request ? . Meta ? . ProgressToken is { } token ? new TokenProgress ( this , token ) : NullProgress . Instance ,
67
+ cancellationToken ) ,
68
+ McpJsonUtilities . JsonContext . Default . CreateMessageRequestParams ,
69
+ McpJsonUtilities . JsonContext . Default . CreateMessageResult ) ;
62
70
}
63
71
64
- SetRequestHandler (
65
- RequestMethods . RootsList ,
66
- rootsHandler ,
67
- McpJsonUtilities . JsonContext . Default . ListRootsRequestParams ,
68
- McpJsonUtilities . JsonContext . Default . ListRootsResult ) ;
72
+ if ( capabilities . Roots is { } rootsCapability )
73
+ {
74
+ if ( rootsCapability . RootsHandler is not { } rootsHandler )
75
+ {
76
+ throw new InvalidOperationException ( $ "Roots capability was set but it did not provide a handler.") ;
77
+ }
78
+
79
+ RequestHandlers . Set (
80
+ RequestMethods . RootsList ,
81
+ rootsHandler ,
82
+ McpJsonUtilities . JsonContext . Default . ListRootsRequestParams ,
83
+ McpJsonUtilities . JsonContext . Default . ListRootsResult ) ;
84
+ }
69
85
}
70
86
}
71
87
@@ -96,20 +112,20 @@ public async Task ConnectAsync(CancellationToken cancellationToken = default)
96
112
using var initializationCts = CancellationTokenSource . CreateLinkedTokenSource ( cancellationToken ) ;
97
113
initializationCts . CancelAfter ( _options . InitializationTimeout ) ;
98
114
99
- try
100
- {
101
- // Send initialize request
102
- var initializeResponse = await this . SendRequestAsync (
103
- RequestMethods . Initialize ,
104
- new InitializeRequestParams
105
- {
106
- ProtocolVersion = _options . ProtocolVersion ,
107
- Capabilities = _options . Capabilities ?? new ClientCapabilities ( ) ,
108
- ClientInfo = _options . ClientInfo
109
- } ,
110
- McpJsonUtilities . JsonContext . Default . InitializeRequestParams ,
111
- McpJsonUtilities . JsonContext . Default . InitializeResult ,
112
- cancellationToken : initializationCts . Token ) . ConfigureAwait ( false ) ;
115
+ try
116
+ {
117
+ // Send initialize request
118
+ var initializeResponse = await this . SendRequestAsync (
119
+ RequestMethods . Initialize ,
120
+ new InitializeRequestParams
121
+ {
122
+ ProtocolVersion = _options . ProtocolVersion ,
123
+ Capabilities = _options . Capabilities ?? new ClientCapabilities ( ) ,
124
+ ClientInfo = _options . ClientInfo ?? DefaultImplementation ,
125
+ } ,
126
+ McpJsonUtilities . JsonContext . Default . InitializeRequestParams ,
127
+ McpJsonUtilities . JsonContext . Default . InitializeResult ,
128
+ cancellationToken : initializationCts . Token ) . ConfigureAwait ( false ) ;
113
129
114
130
// Store server information
115
131
_logger . ServerCapabilitiesReceived ( EndpointName ,
0 commit comments