Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion samples/EverythingServer/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ await ctx.Server.SampleAsync([
new ChatMessage(ChatRole.System, "You are a helpful test server"),
new ChatMessage(ChatRole.User, $"Resource {uri}, context: A new subscription was started"),
],
options: new ChatOptions
chatOptions: new ChatOptions
{
MaxOutputTokens = 100,
Temperature = 0.7f,
Expand Down
2 changes: 1 addition & 1 deletion samples/EverythingServer/Tools/SampleLlmTool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public static async Task<string> SampleLLM(
CancellationToken cancellationToken)
{
var samplingParams = CreateRequestSamplingParams(prompt ?? string.Empty, "sampleLLM", maxTokens);
var sampleResult = await server.SampleAsync(samplingParams, cancellationToken);
var sampleResult = await server.SampleAsync(samplingParams, cancellationToken: cancellationToken);

return $"LLM sampling result: {sampleResult.Content.OfType<TextContentBlock>().FirstOrDefault()?.Text}";
}
Expand Down
2 changes: 1 addition & 1 deletion samples/TestServerWithHosting/Tools/SampleLlmTool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public static async Task<string> SampleLLM(
CancellationToken cancellationToken)
{
var samplingParams = CreateRequestSamplingParams(prompt ?? string.Empty, "sampleLLM", maxTokens);
var sampleResult = await thisServer.SampleAsync(samplingParams, cancellationToken);
var sampleResult = await thisServer.SampleAsync(samplingParams, cancellationToken: cancellationToken);

return $"LLM sampling result: {sampleResult.Content.OfType<TextContentBlock>().FirstOrDefault()?.Text}";
}
Expand Down
124 changes: 76 additions & 48 deletions src/ModelContextProtocol.Core/Client/McpClient.Methods.cs

Large diffs are not rendered by default.

36 changes: 18 additions & 18 deletions src/ModelContextProtocol.Core/Client/McpClientExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public static class McpClientExtensions
[Obsolete($"Use {nameof(McpClient)}.{nameof(McpClient.PingAsync)} instead. This member will be removed in a subsequent release.")] // See: https://github.com/modelcontextprotocol/csharp-sdk/issues/774
[EditorBrowsable(EditorBrowsableState.Never)]
public static Task PingAsync(this IMcpClient client, CancellationToken cancellationToken = default)
=> AsClientOrThrow(client).PingAsync(cancellationToken);
=> AsClientOrThrow(client).PingAsync(null, cancellationToken).AsTask();

/// <summary>
/// Retrieves a list of available tools from the server.
Expand Down Expand Up @@ -86,7 +86,7 @@ public static ValueTask<IList<McpClientTool>> ListToolsAsync(
this IMcpClient client,
JsonSerializerOptions? serializerOptions = null,
CancellationToken cancellationToken = default)
=> AsClientOrThrow(client).ListToolsAsync(serializerOptions, cancellationToken);
=> AsClientOrThrow(client).ListToolsAsync(new RequestOptions { JsonSerializerOptions = serializerOptions }, cancellationToken);

/// <summary>
/// Creates an enumerable for asynchronously enumerating all available tools from the server.
Expand Down Expand Up @@ -126,7 +126,7 @@ public static IAsyncEnumerable<McpClientTool> EnumerateToolsAsync(
this IMcpClient client,
JsonSerializerOptions? serializerOptions = null,
CancellationToken cancellationToken = default)
=> AsClientOrThrow(client).EnumerateToolsAsync(serializerOptions, cancellationToken);
=> AsClientOrThrow(client).EnumerateToolsAsync(new RequestOptions { JsonSerializerOptions = serializerOptions }, cancellationToken);

/// <summary>
/// Retrieves a list of available prompts from the server.
Expand All @@ -149,7 +149,7 @@ public static IAsyncEnumerable<McpClientTool> EnumerateToolsAsync(
[EditorBrowsable(EditorBrowsableState.Never)]
public static ValueTask<IList<McpClientPrompt>> ListPromptsAsync(
this IMcpClient client, CancellationToken cancellationToken = default)
=> AsClientOrThrow(client).ListPromptsAsync(cancellationToken);
=> AsClientOrThrow(client).ListPromptsAsync(null, cancellationToken);

/// <summary>
/// Creates an enumerable for asynchronously enumerating all available prompts from the server.
Expand Down Expand Up @@ -182,7 +182,7 @@ public static ValueTask<IList<McpClientPrompt>> ListPromptsAsync(
[EditorBrowsable(EditorBrowsableState.Never)]
public static IAsyncEnumerable<McpClientPrompt> EnumeratePromptsAsync(
this IMcpClient client, CancellationToken cancellationToken = default)
=> AsClientOrThrow(client).EnumeratePromptsAsync(cancellationToken);
=> AsClientOrThrow(client).EnumeratePromptsAsync(null, cancellationToken);

/// <summary>
/// Retrieves a specific prompt from the MCP server.
Expand Down Expand Up @@ -217,7 +217,7 @@ public static ValueTask<GetPromptResult> GetPromptAsync(
IReadOnlyDictionary<string, object?>? arguments = null,
JsonSerializerOptions? serializerOptions = null,
CancellationToken cancellationToken = default)
=> AsClientOrThrow(client).GetPromptAsync(name, arguments, serializerOptions, cancellationToken);
=> AsClientOrThrow(client).GetPromptAsync(name, arguments, new RequestOptions { JsonSerializerOptions = serializerOptions }, cancellationToken);

/// <summary>
/// Retrieves a list of available resource templates from the server.
Expand All @@ -240,7 +240,7 @@ public static ValueTask<GetPromptResult> GetPromptAsync(
[EditorBrowsable(EditorBrowsableState.Never)]
public static ValueTask<IList<McpClientResourceTemplate>> ListResourceTemplatesAsync(
this IMcpClient client, CancellationToken cancellationToken = default)
=> AsClientOrThrow(client).ListResourceTemplatesAsync(cancellationToken);
=> AsClientOrThrow(client).ListResourceTemplatesAsync(null, cancellationToken);

/// <summary>
/// Creates an enumerable for asynchronously enumerating all available resource templates from the server.
Expand Down Expand Up @@ -273,7 +273,7 @@ public static ValueTask<IList<McpClientResourceTemplate>> ListResourceTemplatesA
[EditorBrowsable(EditorBrowsableState.Never)]
public static IAsyncEnumerable<McpClientResourceTemplate> EnumerateResourceTemplatesAsync(
this IMcpClient client, CancellationToken cancellationToken = default)
=> AsClientOrThrow(client).EnumerateResourceTemplatesAsync(cancellationToken);
=> AsClientOrThrow(client).EnumerateResourceTemplatesAsync(null, cancellationToken);

/// <summary>
/// Retrieves a list of available resources from the server.
Expand Down Expand Up @@ -308,7 +308,7 @@ public static IAsyncEnumerable<McpClientResourceTemplate> EnumerateResourceTempl
[EditorBrowsable(EditorBrowsableState.Never)]
public static ValueTask<IList<McpClientResource>> ListResourcesAsync(
this IMcpClient client, CancellationToken cancellationToken = default)
=> AsClientOrThrow(client).ListResourcesAsync(cancellationToken);
=> AsClientOrThrow(client).ListResourcesAsync(null, cancellationToken);

/// <summary>
/// Creates an enumerable for asynchronously enumerating all available resources from the server.
Expand Down Expand Up @@ -341,7 +341,7 @@ public static ValueTask<IList<McpClientResource>> ListResourcesAsync(
[EditorBrowsable(EditorBrowsableState.Never)]
public static IAsyncEnumerable<McpClientResource> EnumerateResourcesAsync(
this IMcpClient client, CancellationToken cancellationToken = default)
=> AsClientOrThrow(client).EnumerateResourcesAsync(cancellationToken);
=> AsClientOrThrow(client).EnumerateResourcesAsync(null, cancellationToken);

/// <summary>
/// Reads a resource from the server.
Expand All @@ -356,7 +356,7 @@ public static IAsyncEnumerable<McpClientResource> EnumerateResourcesAsync(
[EditorBrowsable(EditorBrowsableState.Never)]
public static ValueTask<ReadResourceResult> ReadResourceAsync(
this IMcpClient client, string uri, CancellationToken cancellationToken = default)
=> AsClientOrThrow(client).ReadResourceAsync(uri, cancellationToken);
=> AsClientOrThrow(client).ReadResourceAsync(uri, null, cancellationToken);

/// <summary>
/// Reads a resource from the server.
Expand All @@ -370,7 +370,7 @@ public static ValueTask<ReadResourceResult> ReadResourceAsync(
[EditorBrowsable(EditorBrowsableState.Never)]
public static ValueTask<ReadResourceResult> ReadResourceAsync(
this IMcpClient client, Uri uri, CancellationToken cancellationToken = default)
=> AsClientOrThrow(client).ReadResourceAsync(uri, cancellationToken);
=> AsClientOrThrow(client).ReadResourceAsync(uri, null, cancellationToken);

/// <summary>
/// Reads a resource from the server.
Expand All @@ -386,7 +386,7 @@ public static ValueTask<ReadResourceResult> ReadResourceAsync(
[EditorBrowsable(EditorBrowsableState.Never)]
public static ValueTask<ReadResourceResult> ReadResourceAsync(
this IMcpClient client, string uriTemplate, IReadOnlyDictionary<string, object?> arguments, CancellationToken cancellationToken = default)
=> AsClientOrThrow(client).ReadResourceAsync(uriTemplate, arguments, cancellationToken);
=> AsClientOrThrow(client).ReadResourceAsync(uriTemplate, arguments, null, cancellationToken);

/// <summary>
/// Requests completion suggestions for a prompt argument or resource reference.
Expand Down Expand Up @@ -450,7 +450,7 @@ public static ValueTask<CompleteResult> CompleteAsync(this IMcpClient client, Re
[Obsolete($"Use {nameof(McpClient)}.{nameof(McpClient.SubscribeToResourceAsync)} instead. This member will be removed in a subsequent release.")] // See: https://github.com/modelcontextprotocol/csharp-sdk/issues/774
[EditorBrowsable(EditorBrowsableState.Never)]
public static Task SubscribeToResourceAsync(this IMcpClient client, string uri, CancellationToken cancellationToken = default)
=> AsClientOrThrow(client).SubscribeToResourceAsync(uri, cancellationToken);
=> AsClientOrThrow(client).SubscribeToResourceAsync(uri, null, cancellationToken);

/// <summary>
/// Subscribes to a resource on the server to receive notifications when it changes.
Expand Down Expand Up @@ -479,7 +479,7 @@ public static Task SubscribeToResourceAsync(this IMcpClient client, string uri,
[Obsolete($"Use {nameof(McpClient)}.{nameof(McpClient.SubscribeToResourceAsync)} instead. This member will be removed in a subsequent release.")] // See: https://github.com/modelcontextprotocol/csharp-sdk/issues/774
[EditorBrowsable(EditorBrowsableState.Never)]
public static Task SubscribeToResourceAsync(this IMcpClient client, Uri uri, CancellationToken cancellationToken = default)
=> AsClientOrThrow(client).SubscribeToResourceAsync(uri, cancellationToken);
=> AsClientOrThrow(client).SubscribeToResourceAsync(uri, null, cancellationToken);

/// <summary>
/// Unsubscribes from a resource on the server to stop receiving notifications about its changes.
Expand Down Expand Up @@ -508,7 +508,7 @@ public static Task SubscribeToResourceAsync(this IMcpClient client, Uri uri, Can
[Obsolete($"Use {nameof(McpClient)}.{nameof(McpClient.UnsubscribeFromResourceAsync)} instead. This member will be removed in a subsequent release.")] // See: https://github.com/modelcontextprotocol/csharp-sdk/issues/774
[EditorBrowsable(EditorBrowsableState.Never)]
public static Task UnsubscribeFromResourceAsync(this IMcpClient client, string uri, CancellationToken cancellationToken = default)
=> AsClientOrThrow(client).UnsubscribeFromResourceAsync(uri, cancellationToken);
=> AsClientOrThrow(client).UnsubscribeFromResourceAsync(uri, null, cancellationToken);

/// <summary>
/// Unsubscribes from a resource on the server to stop receiving notifications about its changes.
Expand Down Expand Up @@ -536,7 +536,7 @@ public static Task UnsubscribeFromResourceAsync(this IMcpClient client, string u
[Obsolete($"Use {nameof(McpClient)}.{nameof(McpClient.UnsubscribeFromResourceAsync)} instead. This member will be removed in a subsequent release.")] // See: https://github.com/modelcontextprotocol/csharp-sdk/issues/774
[EditorBrowsable(EditorBrowsableState.Never)]
public static Task UnsubscribeFromResourceAsync(this IMcpClient client, Uri uri, CancellationToken cancellationToken = default)
=> AsClientOrThrow(client).UnsubscribeFromResourceAsync(uri, cancellationToken);
=> AsClientOrThrow(client).UnsubscribeFromResourceAsync(uri, null, cancellationToken);

/// <summary>
/// Invokes a tool on the server.
Expand Down Expand Up @@ -582,7 +582,7 @@ public static ValueTask<CallToolResult> CallToolAsync(
IProgress<ProgressNotificationValue>? progress = null,
JsonSerializerOptions? serializerOptions = null,
CancellationToken cancellationToken = default)
=> AsClientOrThrow(client).CallToolAsync(toolName, arguments, progress, serializerOptions, cancellationToken);
=> AsClientOrThrow(client).CallToolAsync(toolName, arguments, progress, new RequestOptions { JsonSerializerOptions = serializerOptions }, cancellationToken);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
#pragma warning disable CS0618 // Type or member is obsolete
Expand Down
2 changes: 1 addition & 1 deletion src/ModelContextProtocol.Core/Client/McpClientPrompt.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,6 @@ public async ValueTask<GetPromptResult> GetAsync(
arguments as IReadOnlyDictionary<string, object?> ??
arguments?.ToDictionary();

return await _client.GetPromptAsync(ProtocolPrompt.Name, argDict, serializerOptions, cancellationToken: cancellationToken).ConfigureAwait(false);
return await _client.GetPromptAsync(ProtocolPrompt.Name, argDict, new RequestOptions(){JsonSerializerOptions = serializerOptions}, cancellationToken).ConfigureAwait(false);
}
}
4 changes: 2 additions & 2 deletions src/ModelContextProtocol.Core/Client/McpClientResource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,10 @@ public McpClientResource(McpClient client, Resource resource)
/// <returns>A <see cref="ValueTask{ReadResourceResult}"/> containing the resource's result with content and messages.</returns>
/// <remarks>
/// <para>
/// This is a convenience method that internally calls <see cref="McpClient.ReadResourceAsync(string, CancellationToken)"/>.
/// This is a convenience method that internally calls <see cref="McpClient.ReadResourceAsync(string, RequestOptions, CancellationToken)"/>.
/// </para>
/// </remarks>
public ValueTask<ReadResourceResult> ReadAsync(
CancellationToken cancellationToken = default) =>
_client.ReadResourceAsync(Uri, cancellationToken);
_client.ReadResourceAsync(Uri, cancellationToken: cancellationToken);
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,5 +84,5 @@ public McpClientResourceTemplate(McpClient client, ResourceTemplate resourceTemp
public ValueTask<ReadResourceResult> ReadAsync(
IReadOnlyDictionary<string, object?> arguments,
CancellationToken cancellationToken = default) =>
_client.ReadResourceAsync(UriTemplate, arguments, cancellationToken);
_client.ReadResourceAsync(UriTemplate, arguments, cancellationToken: cancellationToken);
}
10 changes: 9 additions & 1 deletion src/ModelContextProtocol.Core/Client/McpClientTool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,15 @@ public ValueTask<CallToolResult> CallAsync(
IProgress<ProgressNotificationValue>? progress = null,
JsonSerializerOptions? serializerOptions = null,
CancellationToken cancellationToken = default) =>
_client.CallToolAsync(ProtocolTool.Name, arguments, progress, serializerOptions, cancellationToken);
_client.CallToolAsync(
ProtocolTool.Name,
arguments,
progress,
serializerOptions is null ? null : new RequestOptions
{
JsonSerializerOptions = serializerOptions
},
cancellationToken);

/// <summary>
/// Creates a new instance of the tool but modified to return the specified name from its <see cref="Name"/> property.
Expand Down
2 changes: 1 addition & 1 deletion src/ModelContextProtocol.Core/McpEndpointExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ public static Task NotifyProgressAsync(
ProgressToken progressToken,
ProgressNotificationValue progress,
CancellationToken cancellationToken = default)
=> AsSessionOrThrow(endpoint).NotifyProgressAsync(progressToken, progress, cancellationToken);
=> AsSessionOrThrow(endpoint).NotifyProgressAsync(progressToken, progress, cancellationToken: cancellationToken);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
#pragma warning disable CS0618 // Type or member is obsolete
Expand Down
1 change: 1 addition & 0 deletions src/ModelContextProtocol.Core/McpJsonUtilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ internal static bool IsValidMcpToolSchema(JsonElement element)
[JsonSerializable(typeof(ListRootsResult))]
[JsonSerializable(typeof(ListToolsRequestParams))]
[JsonSerializable(typeof(ListToolsResult))]
[JsonSerializable(typeof(PingRequestParams))]
[JsonSerializable(typeof(PingResult))]
[JsonSerializable(typeof(ReadResourceRequestParams))]
[JsonSerializable(typeof(ReadResourceResult))]
Expand Down
3 changes: 3 additions & 0 deletions src/ModelContextProtocol.Core/McpSession.Methods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ internal Task SendNotificationAsync<TParameters>(
/// </summary>
/// <param name="progressToken">The token that identifies the operation for which progress is being reported.</param>
/// <param name="progress">The progress update to send, containing information such as percentage complete or status message.</param>
/// <param name="options">Optional request options including metadata, serialization settings, and progress tracking.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
/// <returns>A task representing the completion of the notification operation (not the operation being tracked).</returns>
/// <exception cref="ArgumentNullException">The current session instance is <see langword="null"/>.</exception>
Expand All @@ -168,6 +169,7 @@ internal Task SendNotificationAsync<TParameters>(
public Task NotifyProgressAsync(
ProgressToken progressToken,
ProgressNotificationValue progress,
RequestOptions? options = null,
CancellationToken cancellationToken = default)
{
return SendNotificationAsync(
Expand All @@ -176,6 +178,7 @@ public Task NotifyProgressAsync(
{
ProgressToken = progressToken,
Progress = progress,
Meta = options?.Meta,
},
McpJsonUtilities.JsonContext.Default.ProgressNotificationParams,
cancellationToken);
Expand Down
11 changes: 11 additions & 0 deletions src/ModelContextProtocol.Core/Protocol/PingRequestParams.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace ModelContextProtocol.Protocol;

/// <summary>
/// Represents the parameters used with a <see cref="RequestMethods.Ping"/> request to verify
/// server connectivity.
/// </summary>
/// <remarks>
/// The server responds with a <see cref="PingResult"/>.
/// See the <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/">schema</see> for details.
/// </remarks>
public sealed class PingRequestParams : RequestParams;
18 changes: 1 addition & 17 deletions src/ModelContextProtocol.Core/Protocol/RequestParams.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ private protected RequestParams()
public JsonObject? Meta { get; set; }

/// <summary>
/// Gets or sets an opaque token that will be attached to any subsequent progress notifications.
/// Gets the opaque token that will be attached to any subsequent progress notifications.
/// </summary>
[JsonIgnore]
public ProgressToken? ProgressToken
Expand All @@ -48,21 +48,5 @@ public ProgressToken? ProgressToken

return null;
}
set
{
if (value is null)
{
Meta?.Remove("progressToken");
}
else
{
(Meta ??= [])["progressToken"] = value.Value.Token switch
{
string s => JsonValue.Create(s),
long l => JsonValue.Create(l),
_ => throw new InvalidOperationException("ProgressToken must be a string or a long.")
};
}
}
}
}
6 changes: 3 additions & 3 deletions src/ModelContextProtocol.Core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ foreach (var tool in await client.ListToolsAsync())
var result = await client.CallToolAsync(
"echo",
new Dictionary<string, object?>() { ["message"] = "Hello MCP!" },
cancellationToken:CancellationToken.None);
cancellationToken: CancellationToken.None);

// echo always returns one and only one text content object
Console.WriteLine(result.Content.First(c => c.Type == "text").Text);
Expand Down Expand Up @@ -83,13 +83,13 @@ using System.ComponentModel;
var serverOptions = new McpServerOptions();

// Add tools directly
serverOptions.Capabilities.Tools = new()
serverOptions.Capabilities.Tools = new()
{
ListChanged = true,
ToolCollection = [
McpServerTool.Create((string message) => $"hello {message}", new()
{
Name = "echo",
Name = "echo",
Description = "Echoes the message back to the client."
})
]
Expand Down
Loading
Loading