Skip to content

Commit c6a019d

Browse files
committed
Move extension methods to instance methods
1 parent dba2129 commit c6a019d

17 files changed

+1756
-2117
lines changed

src/ModelContextProtocol.Core/Client/McpClient.cs

Lines changed: 666 additions & 1 deletion
Large diffs are not rendered by default.

src/ModelContextProtocol.Core/Client/McpClientExtensions.cs

Lines changed: 0 additions & 955 deletions
Large diffs are not rendered by default.

src/ModelContextProtocol.Core/Client/McpClientPrompt.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ namespace ModelContextProtocol.Client;
1010
/// <para>
1111
/// This class provides a client-side wrapper around a prompt defined on an MCP server. It allows
1212
/// retrieving the prompt's content by sending a request to the server with optional arguments.
13-
/// Instances of this class are typically obtained by calling <see cref="McpClientExtensions.ListPromptsAsync"/>
14-
/// or <see cref="McpClientExtensions.EnumeratePromptsAsync"/>.
13+
/// Instances of this class are typically obtained by calling <see cref="McpClient.ListPromptsAsync"/>
14+
/// or <see cref="McpClient.EnumeratePromptsAsync"/>.
1515
/// </para>
1616
/// <para>
1717
/// Each prompt has a name and optionally a description, and it can be invoked with arguments
@@ -63,7 +63,7 @@ internal McpClientPrompt(McpClient client, Prompt prompt)
6363
/// The server will process the request and return a result containing messages or other content.
6464
/// </para>
6565
/// <para>
66-
/// This is a convenience method that internally calls <see cref="McpClientExtensions.GetPromptAsync"/>
66+
/// This is a convenience method that internally calls <see cref="McpClient.GetPromptAsync"/>
6767
/// with this prompt's name and arguments.
6868
/// </para>
6969
/// </remarks>

src/ModelContextProtocol.Core/Client/McpClientResource.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ namespace ModelContextProtocol.Client;
99
/// <para>
1010
/// This class provides a client-side wrapper around a resource defined on an MCP server. It allows
1111
/// retrieving the resource's content by sending a request to the server with the resource's URI.
12-
/// Instances of this class are typically obtained by calling <see cref="McpClientExtensions.ListResourcesAsync"/>
13-
/// or <see cref="McpClientExtensions.EnumerateResourcesAsync"/>.
12+
/// Instances of this class are typically obtained by calling <see cref="McpClient.ListResourcesAsync"/>
13+
/// or <see cref="McpClient.EnumerateResourcesAsync"/>.
1414
/// </para>
1515
/// </remarks>
1616
public sealed class McpClientResource
@@ -58,7 +58,7 @@ internal McpClientResource(McpClient client, Resource resource)
5858
/// <returns>A <see cref="ValueTask{ReadResourceResult}"/> containing the resource's result with content and messages.</returns>
5959
/// <remarks>
6060
/// <para>
61-
/// This is a convenience method that internally calls <see cref="McpClientExtensions.ReadResourceAsync(McpClient, string, CancellationToken)"/>.
61+
/// This is a convenience method that internally calls <see cref="McpClient.ReadResourceAsync(string, CancellationToken)"/>.
6262
/// </para>
6363
/// </remarks>
6464
public ValueTask<ReadResourceResult> ReadAsync(

src/ModelContextProtocol.Core/Client/McpClientResourceTemplate.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ namespace ModelContextProtocol.Client;
99
/// <para>
1010
/// This class provides a client-side wrapper around a resource template defined on an MCP server. It allows
1111
/// retrieving the resource template's content by sending a request to the server with the resource's URI.
12-
/// Instances of this class are typically obtained by calling <see cref="McpClientExtensions.ListResourceTemplatesAsync"/>
13-
/// or <see cref="McpClientExtensions.EnumerateResourceTemplatesAsync"/>.
12+
/// Instances of this class are typically obtained by calling <see cref="McpClient.ListResourceTemplatesAsync"/>
13+
/// or <see cref="McpClient.EnumerateResourceTemplatesAsync"/>.
1414
/// </para>
1515
/// </remarks>
1616
public sealed class McpClientResourceTemplate

src/ModelContextProtocol.Core/Client/McpClientTool.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ namespace ModelContextProtocol.Client;
1919
/// <see cref="WithName"/> and <see cref="WithDescription"/> without changing the underlying tool functionality.
2020
/// </para>
2121
/// <para>
22-
/// Typically, you would get instances of this class by calling the <see cref="McpClientExtensions.ListToolsAsync"/>
23-
/// or <see cref="McpClientExtensions.EnumerateToolsAsync"/> extension methods on an <see cref="McpClient"/> instance.
22+
/// Typically, you would get instances of this class by calling the <see cref="McpClient.ListToolsAsync"/>
23+
/// or <see cref="McpClient.EnumerateToolsAsync"/> extension methods on an <see cref="McpClient"/> instance.
2424
/// </para>
2525
/// </remarks>
2626
public sealed class McpClientTool : AIFunction

src/ModelContextProtocol.Core/McpSession.cs

Lines changed: 178 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
using ModelContextProtocol.Client;
22
using ModelContextProtocol.Protocol;
33
using ModelContextProtocol.Server;
4+
using System.Text.Json;
5+
using System.Text.Json.Nodes;
6+
using System.Text.Json.Serialization.Metadata;
47

58
namespace ModelContextProtocol;
69

@@ -46,7 +49,7 @@ public abstract class McpSession : IAsyncDisposable
4649
/// <exception cref="McpException">An error occured during request processing.</exception>
4750
/// <remarks>
4851
/// This method provides low-level access to send raw JSON-RPC requests. For most use cases,
49-
/// consider using the strongly-typed extension methods that provide a more convenient API.
52+
/// consider using the strongly-typed methods that provide a more convenient API.
5053
/// </remarks>
5154
public abstract Task<JsonRpcResponse> SendRequestAsync(JsonRpcRequest request, CancellationToken cancellationToken = default);
5255

@@ -64,9 +67,8 @@ public abstract class McpSession : IAsyncDisposable
6467
/// <remarks>
6568
/// <para>
6669
/// This method provides low-level access to send any JSON-RPC message. For specific message types,
67-
/// consider using the higher-level methods such as <see cref="SendRequestAsync"/> or extension methods
68-
/// like <see cref="McpSessionExtensions.SendNotificationAsync(McpSession, string, CancellationToken)"/>,
69-
/// which provide a simpler API.
70+
/// consider using the higher-level methods such as <see cref="SendRequestAsync"/> or methods
71+
/// on this class that provide a simpler API.
7072
/// </para>
7173
/// <para>
7274
/// The method will serialize the message and transmit it using the underlying transport mechanism.
@@ -82,4 +84,176 @@ public abstract class McpSession : IAsyncDisposable
8284

8385
/// <inheritdoc/>
8486
public abstract ValueTask DisposeAsync();
87+
88+
/// <summary>
89+
/// Sends a JSON-RPC request and attempts to deserialize the result to <typeparamref name="TResult"/>.
90+
/// </summary>
91+
/// <typeparam name="TParameters">The type of the request parameters to serialize from.</typeparam>
92+
/// <typeparam name="TResult">The type of the result to deserialize to.</typeparam>
93+
/// <param name="method">The JSON-RPC method name to invoke.</param>
94+
/// <param name="parameters">Object representing the request parameters.</param>
95+
/// <param name="requestId">The request id for the request.</param>
96+
/// <param name="serializerOptions">The options governing request serialization.</param>
97+
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
98+
/// <returns>A task that represents the asynchronous operation. The task result contains the deserialized result.</returns>
99+
public ValueTask<TResult> SendRequestAsync<TParameters, TResult>(
100+
string method,
101+
TParameters parameters,
102+
JsonSerializerOptions? serializerOptions = null,
103+
RequestId requestId = default,
104+
CancellationToken cancellationToken = default)
105+
where TResult : notnull
106+
{
107+
serializerOptions ??= McpJsonUtilities.DefaultOptions;
108+
serializerOptions.MakeReadOnly();
109+
110+
JsonTypeInfo<TParameters> paramsTypeInfo = serializerOptions.GetTypeInfo<TParameters>();
111+
JsonTypeInfo<TResult> resultTypeInfo = serializerOptions.GetTypeInfo<TResult>();
112+
return SendRequestAsync(method, parameters, paramsTypeInfo, resultTypeInfo, requestId, cancellationToken);
113+
}
114+
115+
/// <summary>
116+
/// Sends a JSON-RPC request and attempts to deserialize the result to <typeparamref name="TResult"/>.
117+
/// </summary>
118+
/// <typeparam name="TParameters">The type of the request parameters to serialize from.</typeparam>
119+
/// <typeparam name="TResult">The type of the result to deserialize to.</typeparam>
120+
/// <param name="method">The JSON-RPC method name to invoke.</param>
121+
/// <param name="parameters">Object representing the request parameters.</param>
122+
/// <param name="parametersTypeInfo">The type information for request parameter serialization.</param>
123+
/// <param name="resultTypeInfo">The type information for request parameter deserialization.</param>
124+
/// <param name="requestId">The request id for the request.</param>
125+
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
126+
/// <returns>A task that represents the asynchronous operation. The task result contains the deserialized result.</returns>
127+
internal async ValueTask<TResult> SendRequestAsync<TParameters, TResult>(
128+
string method,
129+
TParameters parameters,
130+
JsonTypeInfo<TParameters> parametersTypeInfo,
131+
JsonTypeInfo<TResult> resultTypeInfo,
132+
RequestId requestId = default,
133+
CancellationToken cancellationToken = default)
134+
where TResult : notnull
135+
{
136+
Throw.IfNullOrWhiteSpace(method);
137+
Throw.IfNull(parametersTypeInfo);
138+
Throw.IfNull(resultTypeInfo);
139+
140+
JsonRpcRequest jsonRpcRequest = new()
141+
{
142+
Id = requestId,
143+
Method = method,
144+
Params = JsonSerializer.SerializeToNode(parameters, parametersTypeInfo),
145+
};
146+
147+
JsonRpcResponse response = await SendRequestAsync(jsonRpcRequest, cancellationToken).ConfigureAwait(false);
148+
return JsonSerializer.Deserialize(response.Result, resultTypeInfo) ?? throw new JsonException("Unexpected JSON result in response.");
149+
}
150+
151+
/// <summary>
152+
/// Sends a parameterless notification to the connected session.
153+
/// </summary>
154+
/// <param name="method">The notification method name.</param>
155+
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
156+
/// <returns>A task that represents the asynchronous send operation.</returns>
157+
/// <remarks>
158+
/// <para>
159+
/// This method sends a notification without any parameters. Notifications are one-way messages
160+
/// that don't expect a response. They are commonly used for events, status updates, or to signal
161+
/// changes in state.
162+
/// </para>
163+
/// </remarks>
164+
public Task SendNotificationAsync(string method, CancellationToken cancellationToken = default)
165+
{
166+
Throw.IfNullOrWhiteSpace(method);
167+
return SendMessageAsync(new JsonRpcNotification { Method = method }, cancellationToken);
168+
}
169+
170+
/// <summary>
171+
/// Sends a notification with parameters to the connected session.
172+
/// </summary>
173+
/// <typeparam name="TParameters">The type of the notification parameters to serialize.</typeparam>
174+
/// <param name="method">The JSON-RPC method name for the notification.</param>
175+
/// <param name="parameters">Object representing the notification parameters.</param>
176+
/// <param name="serializerOptions">The options governing parameter serialization. If null, default options are used.</param>
177+
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
178+
/// <returns>A task that represents the asynchronous send operation.</returns>
179+
/// <remarks>
180+
/// <para>
181+
/// This method sends a notification with parameters to the connected session. Notifications are one-way
182+
/// messages that don't expect a response, commonly used for events, status updates, or signaling changes.
183+
/// </para>
184+
/// <para>
185+
/// The parameters object is serialized to JSON according to the provided serializer options or the default
186+
/// options if none are specified.
187+
/// </para>
188+
/// <para>
189+
/// The Model Context Protocol defines several standard notification methods in <see cref="NotificationMethods"/>,
190+
/// but custom methods can also be used for application-specific notifications.
191+
/// </para>
192+
/// </remarks>
193+
public Task SendNotificationAsync<TParameters>(
194+
string method,
195+
TParameters parameters,
196+
JsonSerializerOptions? serializerOptions = null,
197+
CancellationToken cancellationToken = default)
198+
{
199+
serializerOptions ??= McpJsonUtilities.DefaultOptions;
200+
serializerOptions.MakeReadOnly();
201+
202+
JsonTypeInfo<TParameters> parametersTypeInfo = serializerOptions.GetTypeInfo<TParameters>();
203+
return SendNotificationAsync(method, parameters, parametersTypeInfo, cancellationToken);
204+
}
205+
206+
/// <summary>
207+
/// Sends a notification to the server with parameters.
208+
/// </summary>
209+
/// <param name="method">The JSON-RPC method name to invoke.</param>
210+
/// <param name="parameters">Object representing the request parameters.</param>
211+
/// <param name="parametersTypeInfo">The type information for request parameter serialization.</param>
212+
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
213+
internal Task SendNotificationAsync<TParameters>(
214+
string method,
215+
TParameters parameters,
216+
JsonTypeInfo<TParameters> parametersTypeInfo,
217+
CancellationToken cancellationToken = default)
218+
{
219+
Throw.IfNullOrWhiteSpace(method);
220+
Throw.IfNull(parametersTypeInfo);
221+
222+
JsonNode? parametersJson = JsonSerializer.SerializeToNode(parameters, parametersTypeInfo);
223+
return SendMessageAsync(new JsonRpcNotification { Method = method, Params = parametersJson }, cancellationToken);
224+
}
225+
226+
/// <summary>
227+
/// Notifies the connected session of progress for a long-running operation.
228+
/// </summary>
229+
/// <param name="progressToken">The <see cref="ProgressToken"/> identifying the operation for which progress is being reported.</param>
230+
/// <param name="progress">The progress update to send, containing information such as percentage complete or status message.</param>
231+
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
232+
/// <returns>A task representing the completion of the notification operation (not the operation being tracked).</returns>
233+
/// <exception cref="ArgumentNullException">The current session instance is <see langword="null"/>.</exception>
234+
/// <remarks>
235+
/// <para>
236+
/// This method sends a progress notification to the connected session using the Model Context Protocol's
237+
/// standardized progress notification format. Progress updates are identified by a <see cref="ProgressToken"/>
238+
/// that allows the recipient to correlate multiple updates with a specific long-running operation.
239+
/// </para>
240+
/// <para>
241+
/// Progress notifications are sent asynchronously and don't block the operation from continuing.
242+
/// </para>
243+
/// </remarks>
244+
public Task NotifyProgressAsync(
245+
ProgressToken progressToken,
246+
ProgressNotificationValue progress,
247+
CancellationToken cancellationToken = default)
248+
{
249+
return SendNotificationAsync(
250+
NotificationMethods.ProgressNotification,
251+
new ProgressNotificationParams
252+
{
253+
ProgressToken = progressToken,
254+
Progress = progress,
255+
},
256+
McpJsonUtilities.JsonContext.Default.ProgressNotificationParams,
257+
cancellationToken);
258+
}
85259
}

0 commit comments

Comments
 (0)