Skip to content

Make options types fully mutable #107

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 26, 2025
Merged
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
10 changes: 5 additions & 5 deletions src/ModelContextProtocol/Client/McpClientOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,25 @@ namespace ModelContextProtocol.Client;
/// protocol version.
/// <see href="https://spec.modelcontextprotocol.io/specification/2024-11-05/basic/lifecycle/">See the protocol specification for details on capability negotiation</see>
/// </summary>
public record McpClientOptions
public class McpClientOptions
{
/// <summary>
/// Information about this client implementation.
/// </summary>
public required Implementation ClientInfo { get; init; }
public required Implementation ClientInfo { get; set; }

/// <summary>
/// Client capabilities to advertise to the server.
/// </summary>
public ClientCapabilities? Capabilities { get; init; }
public ClientCapabilities? Capabilities { get; set; }

/// <summary>
/// Protocol version to request from the server.
/// </summary>
public string ProtocolVersion { get; init; } = "2024-11-05";
public string ProtocolVersion { get; set; } = "2024-11-05";

/// <summary>
/// Timeout for initialization sequence.
/// </summary>
public TimeSpan InitializationTimeout { get; init; } = TimeSpan.FromSeconds(60);
public TimeSpan InitializationTimeout { get; set; } = TimeSpan.FromSeconds(60);
}
33 changes: 10 additions & 23 deletions src/ModelContextProtocol/Configuration/McpServerOptionsSetup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,14 @@ public void Configure(McpServerOptions options)

// Configure the option's server information based on the current process,
// if it otherwise lacks server information.
var assemblyName = (Assembly.GetEntryAssembly() ?? Assembly.GetCallingAssembly()).GetName();
if (options.ServerInfo is not { } serverInfo ||
serverInfo.Name is null ||
serverInfo.Version is null)
if (options.ServerInfo is not { } serverInfo)
{
options.ServerInfo = options.ServerInfo is null ?
new()
{
Name = assemblyName.Name ?? "McpServer",
Version = assemblyName.Version?.ToString() ?? "1.0.0",
} :
options.ServerInfo with
{
Name = options.ServerInfo.Name ?? assemblyName.Name ?? "McpServer",
Version = options.ServerInfo.Version ?? assemblyName.Version?.ToString() ?? "1.0.0",
};
var assemblyName = (Assembly.GetEntryAssembly() ?? Assembly.GetCallingAssembly()).GetName();
options.ServerInfo = new()
{
Name = assemblyName.Name ?? "McpServer",
Version = assemblyName.Version?.ToString() ?? "1.0.0",
};
}

// Collect all of the provided tools into a tools collection. If the options already has
Expand All @@ -55,14 +47,9 @@ options.ServerInfo with

if (!toolsCollection.IsEmpty)
{
options.Capabilities = options.Capabilities is null ?
new() { Tools = new() { ToolCollection = toolsCollection } } :
options.Capabilities with
{
Tools = options.Capabilities.Tools is null ?
new() { ToolCollection = toolsCollection } :
options.Capabilities.Tools with { ToolCollection = toolsCollection },
};
options.Capabilities ??= new();
options.Capabilities.Tools ??= new();
options.Capabilities.Tools.ToolCollection = toolsCollection;
}

// Apply custom server handlers.
Expand Down
56 changes: 28 additions & 28 deletions src/ModelContextProtocol/Protocol/Types/Capabilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,62 +7,62 @@ namespace ModelContextProtocol.Protocol.Types;
/// Represents the capabilities that a client may support.
/// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.json">See the schema for details</see>
/// </summary>
public record ClientCapabilities
public class ClientCapabilities
{
/// <summary>
/// Experimental, non-standard capabilities that the client supports.
/// </summary>
[JsonPropertyName("experimental")]
public Dictionary<string, object>? Experimental { get; init; }
public Dictionary<string, object>? Experimental { get; set; }

/// <summary>
/// Present if the client supports listing roots.
/// </summary>
[JsonPropertyName("roots")]
public RootsCapability? Roots { get; init; }
public RootsCapability? Roots { get; set; }

/// <summary>
/// Present if the client supports sampling from an LLM.
/// </summary>
[JsonPropertyName("sampling")]
public SamplingCapability? Sampling { get; init; }
public SamplingCapability? Sampling { get; set; }
}

/// <summary>
/// Represents the roots capability configuration.
/// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.json">See the schema for details</see>
/// </summary>
public record RootsCapability
public class RootsCapability
{
/// <summary>
/// Whether the client supports notifications for changes to the roots list.
/// </summary>
[JsonPropertyName("listChanged")]
public bool? ListChanged { get; init; }
public bool? ListChanged { get; set; }

/// <summary>Gets or sets the handler for sampling requests.</summary>
[JsonIgnore]
public Func<ListRootsRequestParams?, CancellationToken, Task<ListRootsResult>>? RootsHandler { get; init; }
public Func<ListRootsRequestParams?, CancellationToken, Task<ListRootsResult>>? RootsHandler { get; set; }
}

/// <summary>
/// Represents the sampling capability configuration.
/// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.json">See the schema for details</see>
/// </summary>
public record SamplingCapability
public class SamplingCapability
{
// Currently empty in the spec, but may be extended in the future

/// <summary>Gets or sets the handler for sampling requests.</summary>
[JsonIgnore]
public Func<CreateMessageRequestParams?, CancellationToken, Task<CreateMessageResult>>? SamplingHandler { get; init; }
public Func<CreateMessageRequestParams?, CancellationToken, Task<CreateMessageResult>>? SamplingHandler { get; set; }
}

/// <summary>
/// Represents the logging capability configuration.
/// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.json">See the schema for details</see>
/// </summary>
public record LoggingCapability
public class LoggingCapability
{
// Currently empty in the spec, but may be extended in the future

Expand All @@ -71,106 +71,106 @@ public record LoggingCapability
/// Gets or sets the handler for set logging level requests.
/// </summary>
[JsonIgnore]
public Func<RequestContext<SetLevelRequestParams>, CancellationToken, Task<EmptyResult>>? SetLoggingLevelHandler { get; init; }
public Func<RequestContext<SetLevelRequestParams>, CancellationToken, Task<EmptyResult>>? SetLoggingLevelHandler { get; set; }
}

/// <summary>
/// Represents the prompts capability configuration.
/// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.json">See the schema for details</see>
/// </summary>
public record PromptsCapability
public class PromptsCapability
{
/// <summary>
/// Whether this server supports notifications for changes to the prompt list.
/// </summary>
[JsonPropertyName("listChanged")]
public bool? ListChanged { get; init; }
public bool? ListChanged { get; set; }

/// <summary>
/// Gets or sets the handler for list prompts requests.
/// </summary>
[JsonIgnore]
public Func<RequestContext<ListPromptsRequestParams>, CancellationToken, Task<ListPromptsResult>>? ListPromptsHandler { get; init; }
public Func<RequestContext<ListPromptsRequestParams>, CancellationToken, Task<ListPromptsResult>>? ListPromptsHandler { get; set; }

/// <summary>
/// Gets or sets the handler for get prompt requests.
/// </summary>
[JsonIgnore]
public Func<RequestContext<GetPromptRequestParams>, CancellationToken, Task<GetPromptResult>>? GetPromptHandler { get; init; }
public Func<RequestContext<GetPromptRequestParams>, CancellationToken, Task<GetPromptResult>>? GetPromptHandler { get; set; }
}

/// <summary>
/// Represents the resources capability configuration.
/// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.json">See the schema for details</see>
/// </summary>
public record ResourcesCapability
public class ResourcesCapability
{
/// <summary>
/// Whether this server supports subscribing to resource updates.
/// </summary>
[JsonPropertyName("subscribe")]
public bool? Subscribe { get; init; }
public bool? Subscribe { get; set; }

/// <summary>
/// Whether this server supports notifications for changes to the resource list.
/// </summary>
[JsonPropertyName("listChanged")]
public bool? ListChanged { get; init; }
public bool? ListChanged { get; set; }

/// <summary>
/// Gets or sets the handler for list resource templates requests.
/// </summary>
[JsonIgnore]
public Func<RequestContext<ListResourceTemplatesRequestParams>, CancellationToken, Task<ListResourceTemplatesResult>>? ListResourceTemplatesHandler { get; init; }
public Func<RequestContext<ListResourceTemplatesRequestParams>, CancellationToken, Task<ListResourceTemplatesResult>>? ListResourceTemplatesHandler { get; set; }

/// <summary>
/// Gets or sets the handler for list resources requests.
/// </summary>
[JsonIgnore]
public Func<RequestContext<ListResourcesRequestParams>, CancellationToken, Task<ListResourcesResult>>? ListResourcesHandler { get; init; }
public Func<RequestContext<ListResourcesRequestParams>, CancellationToken, Task<ListResourcesResult>>? ListResourcesHandler { get; set; }

/// <summary>
/// Gets or sets the handler for read resources requests.
/// </summary>
[JsonIgnore]
public Func<RequestContext<ReadResourceRequestParams>, CancellationToken, Task<ReadResourceResult>>? ReadResourceHandler { get; init; }
public Func<RequestContext<ReadResourceRequestParams>, CancellationToken, Task<ReadResourceResult>>? ReadResourceHandler { get; set; }

/// <summary>
/// Gets or sets the handler for subscribe to resources messages.
/// </summary>
[JsonIgnore]
public Func<RequestContext<SubscribeRequestParams>, CancellationToken, Task<EmptyResult>>? SubscribeToResourcesHandler { get; init; }
public Func<RequestContext<SubscribeRequestParams>, CancellationToken, Task<EmptyResult>>? SubscribeToResourcesHandler { get; set; }

/// <summary>
/// Gets or sets the handler for unsubscribe from resources messages.
/// </summary>
[JsonIgnore]
public Func<RequestContext<UnsubscribeRequestParams>, CancellationToken, Task<EmptyResult>>? UnsubscribeFromResourcesHandler { get; init; }
public Func<RequestContext<UnsubscribeRequestParams>, CancellationToken, Task<EmptyResult>>? UnsubscribeFromResourcesHandler { get; set; }
}

/// <summary>
/// Represents the tools capability configuration.
/// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.json">See the schema for details</see>
/// </summary>
public record ToolsCapability
public class ToolsCapability
{
/// <summary>
/// Gets or sets whether this server supports notifications for changes to the tool list.
/// </summary>
[JsonPropertyName("listChanged")]
public bool? ListChanged { get; init; }
public bool? ListChanged { get; set; }

/// <summary>
/// Gets or sets the handler for list tools requests.
/// </summary>
[JsonIgnore]
public Func<RequestContext<ListToolsRequestParams>, CancellationToken, Task<ListToolsResult>>? ListToolsHandler { get; init; }
public Func<RequestContext<ListToolsRequestParams>, CancellationToken, Task<ListToolsResult>>? ListToolsHandler { get; set; }

/// <summary>
/// Gets or sets the handler for call tool requests.
/// </summary>
[JsonIgnore]
public Func<RequestContext<CallToolRequestParams>, CancellationToken, Task<CallToolResponse>>? CallToolHandler { get; init; }
public Func<RequestContext<CallToolRequestParams>, CancellationToken, Task<CallToolResponse>>? CallToolHandler { get; set; }

/// <summary>Gets or sets a collection of tools served by the server.</summary>
/// <remarks>
Expand All @@ -182,5 +182,5 @@ public record ToolsCapability
/// will be invoked as a fallback.
/// </remarks>
[JsonIgnore]
public McpServerToolCollection? ToolCollection { get; init; }
public McpServerToolCollection? ToolCollection { get; set; }
}
6 changes: 3 additions & 3 deletions src/ModelContextProtocol/Protocol/Types/Implementation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@ namespace ModelContextProtocol.Protocol.Types;
/// Describes the name and version of an MCP implementation.
/// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.json">See the schema for details</see>
/// </summary>
public record Implementation
public class Implementation
{
/// <summary>
/// Name of the implementation.
/// </summary>
[JsonPropertyName("name")]
public required string Name { get; init; }
public required string Name { get; set; }

/// <summary>
/// Version of the implementation.
/// </summary>
[JsonPropertyName("version")]
public required string Version { get; init; }
public required string Version { get; set; }
}
12 changes: 6 additions & 6 deletions src/ModelContextProtocol/Protocol/Types/ServerCapabilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,35 @@ namespace ModelContextProtocol.Protocol.Types;
/// Represents the capabilities that a server may support.
/// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.json">See the schema for details</see>
/// </summary>
public record ServerCapabilities
public class ServerCapabilities
{
/// <summary>
/// Experimental, non-standard capabilities that the server supports.
/// </summary>
[JsonPropertyName("experimental")]
public Dictionary<string, object>? Experimental { get; init; }
public Dictionary<string, object>? Experimental { get; set; }

/// <summary>
/// Present if the server supports sending log messages to the client.
/// </summary>
[JsonPropertyName("logging")]
public LoggingCapability? Logging { get; init; }
public LoggingCapability? Logging { get; set; }

/// <summary>
/// Present if the server offers any prompt templates.
/// </summary>
[JsonPropertyName("prompts")]
public PromptsCapability? Prompts { get; init; }
public PromptsCapability? Prompts { get; set; }

/// <summary>
/// Present if the server offers any resources to read.
/// </summary>
[JsonPropertyName("resources")]
public ResourcesCapability? Resources { get; init; }
public ResourcesCapability? Resources { get; set; }

/// <summary>
/// Present if the server offers any tools to call.
/// </summary>
[JsonPropertyName("tools")]
public ToolsCapability? Tools { get; init; }
public ToolsCapability? Tools { get; set; }
}
27 changes: 8 additions & 19 deletions src/ModelContextProtocol/Server/McpServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -263,25 +263,14 @@ private void SetToolsHandler(ref McpServerOptions options)
return tool.InvokeAsync(request, cancellationToken);
};

toolsCapability = toolsCapability is null ?
new()
{
CallToolHandler = callToolHandler,
ListToolsHandler = listToolsHandler,
ToolCollection = tools,
ListChanged = true,
} :
toolsCapability with
{
CallToolHandler = callToolHandler,
ListToolsHandler = listToolsHandler,
ToolCollection = tools,
ListChanged = true,
};

options.Capabilities = options.Capabilities is null ?
new() { Tools = toolsCapability } :
options.Capabilities with { Tools = toolsCapability };
toolsCapability ??= new();
toolsCapability.CallToolHandler = callToolHandler;
toolsCapability.ListToolsHandler = listToolsHandler;
toolsCapability.ToolCollection = tools;
toolsCapability.ListChanged = true;

options.Capabilities ??= new();
options.Capabilities.Tools = toolsCapability;

tools.Changed += delegate
{
Expand Down
Loading