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/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 as TextContentBlock)?.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 as TextContentBlock)?.Text}";
}
Expand Down
120 changes: 73 additions & 47 deletions src/ModelContextProtocol.Core/Client/McpClient.Methods.cs

Large diffs are not rendered by default.

56 changes: 28 additions & 28 deletions src/ModelContextProtocol.Core/Client/McpClientExtensions.cs

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions src/ModelContextProtocol.Core/Client/McpClientPrompt.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public McpClientPrompt(McpClient client, Prompt prompt)
/// which can be useful for advanced scenarios or when implementing custom MCP client extensions.
/// </para>
/// <para>
/// For most common use cases, you can use the more convenient <see cref="Name"/> and
/// For most common use cases, you can use the more convenient <see cref="Name"/> and
/// <see cref="Description"/> properties instead of accessing the <see cref="ProtocolPrompt"/> directly.
/// </para>
/// </remarks>
Expand Down Expand Up @@ -85,7 +85,7 @@ public McpClientPrompt(McpClient client, Prompt prompt)
/// The server will process the request and return a result containing messages or other content.
/// </para>
/// <para>
/// This is a convenience method that internally calls <see cref="McpClient.GetPromptAsync"/>
/// This is a convenience method that internally calls <see cref="McpClient.GetPromptAsync"/>
/// with this prompt's name and arguments.
/// </para>
/// </remarks>
Expand All @@ -98,6 +98,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(null, serializerOptions), cancellationToken).ConfigureAwait(false);
}
}
6 changes: 3 additions & 3 deletions src/ModelContextProtocol.Core/Client/McpClientResource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public McpClientResource(McpClient client, Resource resource)
/// which can be useful for advanced scenarios or when implementing custom MCP client extensions.
/// </para>
/// <para>
/// For most common use cases, you can use the more convenient <see cref="Name"/> and
/// For most common use cases, you can use the more convenient <see cref="Name"/> and
/// <see cref="Description"/> properties instead of accessing the <see cref="ProtocolResource"/> directly.
/// </para>
/// </remarks>
Expand Down Expand Up @@ -80,10 +80,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, null, cancellationToken);
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public McpClientResourceTemplate(McpClient client, ResourceTemplate resourceTemp
/// which can be useful for advanced scenarios or when implementing custom MCP client extensions.
/// </para>
/// <para>
/// For most common use cases, you can use the more convenient <see cref="UriTemplate"/> and
/// For most common use cases, you can use the more convenient <see cref="UriTemplate"/> and
/// <see cref="Description"/> properties instead of accessing the <see cref="ProtocolResourceTemplate"/> directly.
/// </para>
/// </remarks>
Expand Down Expand Up @@ -85,5 +85,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, null, cancellationToken);
}
18 changes: 13 additions & 5 deletions src/ModelContextProtocol.Core/Client/McpClientTool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace ModelContextProtocol.Client;
/// </summary>
/// <remarks>
/// <para>
/// The <see cref="McpClientTool"/> class encapsulates an <see cref="McpClient"/> along with a description of
/// The <see cref="McpClientTool"/> class encapsulates an <see cref="McpClient"/> along with a description of
/// a tool available via that client, allowing it to be invoked as an <see cref="AIFunction"/>. This enables integration
/// with AI models that support function calling capabilities.
/// </para>
Expand Down Expand Up @@ -194,7 +194,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,
new RequestOptions
Copy link
Contributor

Choose a reason for hiding this comment

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

It'd be nice to avoid allocating the RequestOptions when serializerOptions is null (which is expected to be the common case)

{
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 All @@ -203,7 +211,7 @@ public ValueTask<CallToolResult> CallAsync(
/// <returns>A new instance of <see cref="McpClientTool"/> with the provided name.</returns>
/// <remarks>
/// <para>
/// This is useful for optimizing the tool name for specific models or for prefixing the tool name
/// This is useful for optimizing the tool name for specific models or for prefixing the tool name
/// with a namespace to avoid conflicts.
/// </para>
/// <para>
Expand All @@ -215,7 +223,7 @@ public ValueTask<CallToolResult> CallAsync(
/// <item>Creating specialized versions of a general tool for specific contexts</item>
/// </list>
/// <para>
/// When invoking <see cref="AIFunction.InvokeAsync"/>, the MCP server will still be called with
/// When invoking <see cref="AIFunction.InvokeAsync"/>, the MCP server will still be called with
/// the original tool name, so no mapping is required on the server side. This new name only affects
/// the value returned from this instance's <see cref="AITool.Name"/>.
/// </para>
Expand All @@ -238,7 +246,7 @@ public McpClientTool WithName(string name) =>
/// <item>You need to tailor the tool's description for specific model requirements</item>
/// </list>
/// <para>
/// When invoking <see cref="AIFunction.InvokeAsync"/>, the MCP server will still be called with
/// When invoking <see cref="AIFunction.InvokeAsync"/>, the MCP server will still be called with
/// the original tool description, so no mapping is required on the server side. This new description only affects
/// the value returned from this instance's <see cref="AITool.Description"/>.
/// </para>
Expand Down
10 changes: 5 additions & 5 deletions src/ModelContextProtocol.Core/McpEndpointExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ public static ValueTask<TResult> SendRequestAsync<TParameters, TResult>(
/// <returns>A task that represents the asynchronous send operation.</returns>
/// <remarks>
/// <para>
/// This method sends a notification without any parameters. Notifications are one-way messages
/// that don't expect a response. They are commonly used for events, status updates, or to signal
/// This method sends a notification without any parameters. Notifications are one-way messages
/// that don't expect a response. They are commonly used for events, status updates, or to signal
/// changes in state.
/// </para>
/// </remarks>
Expand All @@ -78,11 +78,11 @@ public static Task SendNotificationAsync(this IMcpEndpoint client, string method
/// <returns>A task that represents the asynchronous send operation.</returns>
/// <remarks>
/// <para>
/// This method sends a notification with parameters to the connected endpoint. Notifications are one-way
/// This method sends a notification with parameters to the connected endpoint. Notifications are one-way
/// messages that don't expect a response, commonly used for events, status updates, or signaling changes.
/// </para>
/// <para>
/// The parameters object is serialized to JSON according to the provided serializer options or the default
/// The parameters object is serialized to JSON according to the provided serializer options or the default
/// options if none are specified.
/// </para>
/// <para>
Expand Down 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, null, cancellationToken);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
#pragma warning disable CS0618 // Type or member is obsolete
Expand Down
5 changes: 3 additions & 2 deletions src/ModelContextProtocol.Core/McpJsonUtilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public static partial class McpJsonUtilities
/// </summary>
/// <remarks>
/// <para>
/// For Native AOT or applications disabling <see cref="JsonSerializer.IsReflectionEnabledByDefault"/>, this instance
/// For Native AOT or applications disabling <see cref="JsonSerializer.IsReflectionEnabledByDefault"/>, this instance
/// includes source generated contracts for all common exchange types contained in the ModelContextProtocol library.
/// </para>
/// <para>
Expand Down Expand Up @@ -88,7 +88,7 @@ internal static bool IsValidMcpToolSchema(JsonElement element)
[JsonSourceGenerationOptions(JsonSerializerDefaults.Web,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
NumberHandling = JsonNumberHandling.AllowReadingFromString)]

// JSON-RPC
[JsonSerializable(typeof(JsonRpcMessage))]
[JsonSerializable(typeof(JsonRpcMessage[]))]
Expand Down 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
11 changes: 7 additions & 4 deletions src/ModelContextProtocol.Core/McpSession.Methods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ internal async ValueTask<TResult> SendRequestAsync<TParameters, TResult>(
/// <returns>A task that represents the asynchronous send operation.</returns>
/// <remarks>
/// <para>
/// This method sends a notification without any parameters. Notifications are one-way messages
/// that don't expect a response. They are commonly used for events, status updates, or to signal
/// This method sends a notification without any parameters. Notifications are one-way messages
/// that don't expect a response. They are commonly used for events, status updates, or to signal
/// changes in state.
/// </para>
/// </remarks>
Expand All @@ -102,11 +102,11 @@ public Task SendNotificationAsync(string method, CancellationToken cancellationT
/// <returns>A task that represents the asynchronous send operation.</returns>
/// <remarks>
/// <para>
/// This method sends a notification with parameters to the connected session. Notifications are one-way
/// This method sends a notification with parameters to the connected session. Notifications are one-way
/// messages that don't expect a response, commonly used for events, status updates, or signaling changes.
/// </para>
/// <para>
/// The parameters object is serialized to JSON according to the provided serializer options or the default
/// The parameters object is serialized to JSON according to the provided serializer options or the default
/// options if none are specified.
/// </para>
/// <para>
Expand Down Expand Up @@ -152,6 +152,7 @@ internal Task SendNotificationAsync<TParameters>(
/// </summary>
/// <param name="progressToken">The <see cref="ProgressToken"/> identifying 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;
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
60 changes: 60 additions & 0 deletions src/ModelContextProtocol.Core/RequestOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using ModelContextProtocol.Protocol;

namespace ModelContextProtocol;

/// <summary>
/// Contains optional parameters for MCP requests.
/// </summary>
public sealed class RequestOptions
{
/// <summary>
/// Gets or sets optional metadata to include in the request.
/// </summary>
public JsonObject? Meta { get; set; }

/// <summary>
/// Gets or sets the JSON serializer options to use for serialization and deserialization.
/// </summary>
public JsonSerializerOptions? JsonSerializerOptions { get; set; }

/// <summary>
/// Gets or sets the progress token for tracking long-running operations.
/// </summary>
public ProgressToken? ProgressToken { get; set; }

/// <summary>
/// Gets a default instance with all properties set to null.
/// </summary>
public static RequestOptions Default { get; } = new();
Copy link
Contributor

Choose a reason for hiding this comment

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

Any code in the process could do:

RequestOptions.Default.Meta = new();

or the like with any of the properties, such that the properties would no longer be null.

This property should be removed.

(Alternatively, you could modify the other properties to all throw if ReferenceEquals(this, Default), but I don't think it's worthwhile. Default should never be needed by consumers, as they should always be able to just pass in null for the options.)


/// <summary>
/// Initializes a new instance of the <see cref="RequestOptions"/> class.
/// </summary>
public RequestOptions()
{
}

/// <summary>
/// Initializes a new instance of the <see cref="RequestOptions"/> class with the specified metadata.
/// </summary>
/// <param name="meta">Optional metadata to include in the request.</param>
public RequestOptions(JsonObject? meta)
{
Meta = meta;
}

/// <summary>
/// Initializes a new instance of the <see cref="RequestOptions"/> class with the specified options.
/// </summary>
/// <param name="meta">Optional metadata to include in the request.</param>
/// <param name="jsonSerializerOptions">The JSON serializer options to use.</param>
/// <param name="progressToken">The progress token for tracking operations.</param>
public RequestOptions(JsonObject? meta = null, JsonSerializerOptions? jsonSerializerOptions = null, ProgressToken? progressToken = null)
{
Meta = meta;
JsonSerializerOptions = jsonSerializerOptions;
ProgressToken = progressToken;
}
Comment on lines +39 to +59
Copy link
Contributor

Choose a reason for hiding this comment

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

Why are these constructors necessary?

}
Loading
Loading