diff --git a/src/ModelContextProtocol.Core/Client/McpClientHandlers.cs b/src/ModelContextProtocol.Core/Client/McpClientHandlers.cs
index 452070c13..9fb26d5c3 100644
--- a/src/ModelContextProtocol.Core/Client/McpClientHandlers.cs
+++ b/src/ModelContextProtocol.Core/Client/McpClientHandlers.cs
@@ -22,7 +22,7 @@ namespace ModelContextProtocol.Client;
/// is done based on an ordinal, case-sensitive string comparison.
///
///
-public class McpClientHandlers
+public sealed class McpClientHandlers
{
/// Gets or sets notification handlers to register with the client.
///
diff --git a/src/ModelContextProtocol.Core/Server/McpMessageFilters.cs b/src/ModelContextProtocol.Core/Server/McpMessageFilters.cs
index 11923d411..82b972b6e 100644
--- a/src/ModelContextProtocol.Core/Server/McpMessageFilters.cs
+++ b/src/ModelContextProtocol.Core/Server/McpMessageFilters.cs
@@ -8,7 +8,7 @@ namespace ModelContextProtocol.Server;
public sealed class McpMessageFilters
{
///
- /// Gets the filters for all incoming JSON-RPC messages.
+ /// Gets or sets the filters for all incoming JSON-RPC messages.
///
///
///
@@ -21,10 +21,18 @@ public sealed class McpMessageFilters
/// the next handler in the pipeline, the default handlers will not be executed.
///
///
- public IList IncomingFilters { get; } = [];
+ public IList IncomingFilters
+ {
+ get => field ??= [];
+ set
+ {
+ Throw.IfNull(value);
+ field = value;
+ }
+ }
///
- /// Gets the filters for all outgoing JSON-RPC messages.
+ /// Gets or sets the filters for all outgoing JSON-RPC messages.
///
///
///
@@ -38,5 +46,13 @@ public sealed class McpMessageFilters
/// server-to-client messages.
///
///
- public IList OutgoingFilters { get; } = [];
+ public IList OutgoingFilters
+ {
+ get => field ??= [];
+ set
+ {
+ Throw.IfNull(value);
+ field = value;
+ }
+ }
}
diff --git a/src/ModelContextProtocol.Core/Server/McpRequestFilters.cs b/src/ModelContextProtocol.Core/Server/McpRequestFilters.cs
index 530a30aa4..5044f8928 100644
--- a/src/ModelContextProtocol.Core/Server/McpRequestFilters.cs
+++ b/src/ModelContextProtocol.Core/Server/McpRequestFilters.cs
@@ -8,7 +8,7 @@ namespace ModelContextProtocol.Server;
public sealed class McpRequestFilters
{
///
- /// Gets the filters for the list-tools handler pipeline.
+ /// Gets or sets the filters for the list-tools handler pipeline.
///
///
///
@@ -22,20 +22,36 @@ public sealed class McpRequestFilters
/// Tools from both sources will be combined when returning results to clients.
///
///
- public IList> ListToolsFilters { get; } = [];
+ public IList> ListToolsFilters
+ {
+ get => field ??= [];
+ set
+ {
+ Throw.IfNull(value);
+ field = value;
+ }
+ }
///
- /// Gets the filters for the call-tool handler pipeline.
+ /// Gets or sets the filters for the call-tool handler pipeline.
///
///
/// These filters wrap handlers that are invoked when a client makes a call to a tool that isn't found in the collection.
/// The filters can modify, log, or perform additional operations on requests and responses for
/// requests. The handler should implement logic to execute the requested tool and return appropriate results.
///
- public IList> CallToolFilters { get; } = [];
+ public IList> CallToolFilters
+ {
+ get => field ??= [];
+ set
+ {
+ Throw.IfNull(value);
+ field = value;
+ }
+ }
///
- /// Gets the filters for the list-prompts handler pipeline.
+ /// Gets or sets the filters for the list-prompts handler pipeline.
///
///
///
@@ -49,20 +65,36 @@ public sealed class McpRequestFilters
/// Prompts from both sources will be combined when returning results to clients.
///
///
- public IList> ListPromptsFilters { get; } = [];
+ public IList> ListPromptsFilters
+ {
+ get => field ??= [];
+ set
+ {
+ Throw.IfNull(value);
+ field = value;
+ }
+ }
///
- /// Gets the filters for the get-prompt handler pipeline.
+ /// Gets or sets the filters for the get-prompt handler pipeline.
///
///
/// These filters wrap handlers that are invoked when a client requests details for a specific prompt that isn't found in the collection.
/// The filters can modify, log, or perform additional operations on requests and responses for
/// requests. The handler should implement logic to fetch or generate the requested prompt and return appropriate results.
///
- public IList> GetPromptFilters { get; } = [];
+ public IList> GetPromptFilters
+ {
+ get => field ??= [];
+ set
+ {
+ Throw.IfNull(value);
+ field = value;
+ }
+ }
///
- /// Gets the filters for the list-resource-templates handler pipeline.
+ /// Gets or sets the filters for the list-resource-templates handler pipeline.
///
///
/// These filters wrap handlers that return a list of available resource templates when requested by a client.
@@ -70,10 +102,18 @@ public sealed class McpRequestFilters
/// requests. It supports pagination through the cursor mechanism,
/// where the client can make repeated calls with the cursor returned by the previous call to retrieve more resource templates.
///
- public IList> ListResourceTemplatesFilters { get; } = [];
+ public IList> ListResourceTemplatesFilters
+ {
+ get => field ??= [];
+ set
+ {
+ Throw.IfNull(value);
+ field = value;
+ }
+ }
///
- /// Gets the filters for the list-resources handler pipeline.
+ /// Gets or sets the filters for the list-resources handler pipeline.
///
///
/// These filters wrap handlers that return a list of available resources when requested by a client.
@@ -81,20 +121,36 @@ public sealed class McpRequestFilters
/// requests. It supports pagination through the cursor mechanism,
/// where the client can make repeated calls with the cursor returned by the previous call to retrieve more resources.
///
- public IList> ListResourcesFilters { get; } = [];
+ public IList> ListResourcesFilters
+ {
+ get => field ??= [];
+ set
+ {
+ Throw.IfNull(value);
+ field = value;
+ }
+ }
///
- /// Gets the filters for the read-resource handler pipeline.
+ /// Gets or sets the filters for the read-resource handler pipeline.
///
///
/// These filters wrap handlers that are invoked when a client requests the content of a specific resource identified by its URI.
/// The filters can modify, log, or perform additional operations on requests and responses for
/// requests. The handler should implement logic to locate and retrieve the requested resource.
///
- public IList> ReadResourceFilters { get; } = [];
+ public IList> ReadResourceFilters
+ {
+ get => field ??= [];
+ set
+ {
+ Throw.IfNull(value);
+ field = value;
+ }
+ }
///
- /// Gets the filters for the complete-handler pipeline.
+ /// Gets or sets the filters for the complete-handler pipeline.
///
///
/// These filters wrap handlers that provide auto-completion suggestions for prompt arguments or resource references in the Model Context Protocol.
@@ -102,10 +158,18 @@ public sealed class McpRequestFilters
/// requests. The handler processes auto-completion requests, returning a list of suggestions based on the
/// reference type and current argument value.
///
- public IList> CompleteFilters { get; } = [];
+ public IList> CompleteFilters
+ {
+ get => field ??= [];
+ set
+ {
+ Throw.IfNull(value);
+ field = value;
+ }
+ }
///
- /// Gets the filters for the subscribe-to-resources handler pipeline.
+ /// Gets or sets the filters for the subscribe-to-resources handler pipeline.
///
///
///
@@ -119,10 +183,18 @@ public sealed class McpRequestFilters
/// whenever a relevant resource is created, updated, or deleted.
///
///
- public IList> SubscribeToResourcesFilters { get; } = [];
+ public IList> SubscribeToResourcesFilters
+ {
+ get => field ??= [];
+ set
+ {
+ Throw.IfNull(value);
+ field = value;
+ }
+ }
///
- /// Gets the filters for the unsubscribe-from-resources handler pipeline.
+ /// Gets or sets the filters for the unsubscribe-from-resources handler pipeline.
///
///
///
@@ -136,10 +208,18 @@ public sealed class McpRequestFilters
/// to the client for the specified resources.
///
///
- public IList> UnsubscribeFromResourcesFilters { get; } = [];
+ public IList> UnsubscribeFromResourcesFilters
+ {
+ get => field ??= [];
+ set
+ {
+ Throw.IfNull(value);
+ field = value;
+ }
+ }
///
- /// Gets the filters for the set-logging-level handler pipeline.
+ /// Gets or sets the filters for the set-logging-level handler pipeline.
///
///
///
@@ -153,5 +233,13 @@ public sealed class McpRequestFilters
/// at or above the specified level to the client as notifications/message notifications.
///
///
- public IList> SetLoggingLevelFilters { get; } = [];
+ public IList> SetLoggingLevelFilters
+ {
+ get => field ??= [];
+ set
+ {
+ Throw.IfNull(value);
+ field = value;
+ }
+ }
}
diff --git a/src/ModelContextProtocol.Core/Server/McpServerFilters.cs b/src/ModelContextProtocol.Core/Server/McpServerFilters.cs
index 39fa1d6a7..d165d55e4 100644
--- a/src/ModelContextProtocol.Core/Server/McpServerFilters.cs
+++ b/src/ModelContextProtocol.Core/Server/McpServerFilters.cs
@@ -12,12 +12,28 @@ namespace ModelContextProtocol.Server;
public sealed class McpServerFilters
{
///
- /// Gets the filters for incoming and outgoing JSON-RPC messages.
+ /// Gets or sets the filters for incoming and outgoing JSON-RPC messages.
///
- public McpMessageFilters Message { get; } = new();
+ public McpMessageFilters Message
+ {
+ get => field ??= new();
+ set
+ {
+ Throw.IfNull(value);
+ field = value;
+ }
+ }
///
- /// Gets the filters for request-specific MCP handler pipelines.
+ /// Gets or sets the filters for request-specific MCP handler pipelines.
///
- public McpRequestFilters Request { get; } = new();
+ public McpRequestFilters Request
+ {
+ get => field ??= new();
+ set
+ {
+ Throw.IfNull(value);
+ field = value;
+ }
+ }
}
diff --git a/src/ModelContextProtocol.Core/Server/McpServerOptions.cs b/src/ModelContextProtocol.Core/Server/McpServerOptions.cs
index b1a63ab0b..a8d232980 100644
--- a/src/ModelContextProtocol.Core/Server/McpServerOptions.cs
+++ b/src/ModelContextProtocol.Core/Server/McpServerOptions.cs
@@ -97,17 +97,33 @@ public sealed class McpServerOptions
///
/// Gets or sets the container of handlers used by the server for processing protocol messages.
///
- public McpServerHandlers Handlers { get; } = new();
+ public McpServerHandlers Handlers
+ {
+ get => field ??= new();
+ set
+ {
+ Throw.IfNull(value);
+ field = value;
+ }
+ }
///
- /// Gets the filter collections for MCP server handlers.
+ /// Gets or sets the filter collections for MCP server handlers.
///
///
/// This property provides access to filter collections that can be used to modify the behavior
/// of various MCP server handlers. The first filter added is the outermost (first to execute),
/// and each subsequent filter wraps closer to the handler.
///
- public McpServerFilters Filters { get; } = new();
+ public McpServerFilters Filters
+ {
+ get => field ??= new();
+ set
+ {
+ Throw.IfNull(value);
+ field = value;
+ }
+ }
///
/// Gets or sets a collection of tools served by the server.
diff --git a/tests/ModelContextProtocol.TestSseServer/Program.cs b/tests/ModelContextProtocol.TestSseServer/Program.cs
index 2222f5b5d..1a27c0c15 100644
--- a/tests/ModelContextProtocol.TestSseServer/Program.cs
+++ b/tests/ModelContextProtocol.TestSseServer/Program.cs
@@ -90,313 +90,316 @@ static CreateMessageRequestParams CreateRequestSamplingParams(string context, st
}
const int pageSize = 10;
- options.Handlers.ListToolsHandler = async (request, cancellationToken) =>
+ options.Handlers = new()
{
- return new ListToolsResult
+ ListToolsHandler = async (request, cancellationToken) =>
{
- Tools =
- [
- new Tool
- {
- Name = "echo",
- Description = "Echoes the input back to the client.",
- InputSchema = JsonElement.Parse("""
- {
- "type": "object",
- "properties": {
- "message": {
- "type": "string",
- "description": "The input to echo back."
- }
- },
- "required": ["message"]
- }
- """),
- },
- new Tool
- {
- Name = "echoSessionId",
- Description = "Echoes the session id back to the client.",
- InputSchema = JsonElement.Parse("""
- {
- "type": "object"
- }
- """),
- },
- new Tool
- {
- Name = "sampleLLM",
- Description = "Samples from an LLM using MCP's sampling feature.",
- InputSchema = JsonElement.Parse("""
- {
- "type": "object",
- "properties": {
- "prompt": {
- "type": "string",
- "description": "The prompt to send to the LLM"
+ return new ListToolsResult
+ {
+ Tools =
+ [
+ new Tool
+ {
+ Name = "echo",
+ Description = "Echoes the input back to the client.",
+ InputSchema = JsonElement.Parse("""
+ {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "description": "The input to echo back."
+ }
},
- "maxTokens": {
- "type": "number",
- "description": "Maximum number of tokens to generate"
- }
- },
- "required": ["prompt", "maxTokens"]
- }
- """),
- },
- new Tool
- {
- Name = "longRunning",
- Description = "Simulates a long-running operation that supports task-based execution.",
- InputSchema = JsonElement.Parse("""
+ "required": ["message"]
+ }
+ """),
+ },
+ new Tool
+ {
+ Name = "echoSessionId",
+ Description = "Echoes the session id back to the client.",
+ InputSchema = JsonElement.Parse("""
+ {
+ "type": "object"
+ }
+ """),
+ },
+ new Tool
+ {
+ Name = "sampleLLM",
+ Description = "Samples from an LLM using MCP's sampling feature.",
+ InputSchema = JsonElement.Parse("""
+ {
+ "type": "object",
+ "properties": {
+ "prompt": {
+ "type": "string",
+ "description": "The prompt to send to the LLM"
+ },
+ "maxTokens": {
+ "type": "number",
+ "description": "Maximum number of tokens to generate"
+ }
+ },
+ "required": ["prompt", "maxTokens"]
+ }
+ """),
+ },
+ new Tool
+ {
+ Name = "longRunning",
+ Description = "Simulates a long-running operation that supports task-based execution.",
+ InputSchema = JsonElement.Parse("""
+ {
+ "type": "object",
+ "properties": {
+ "durationMs": {
+ "type": "number",
+ "description": "Duration of the operation in milliseconds"
+ }
+ },
+ "required": ["durationMs"]
+ }
+ """),
+ Execution = new ToolExecution
{
- "type": "object",
- "properties": {
- "durationMs": {
- "type": "number",
- "description": "Duration of the operation in milliseconds"
- }
- },
- "required": ["durationMs"]
+ TaskSupport = ToolTaskSupport.Optional
}
- """),
- Execution = new ToolExecution
- {
- TaskSupport = ToolTaskSupport.Optional
}
- }
- ]
- };
- };
-
- options.Handlers.CallToolHandler = async (request, cancellationToken) =>
- {
- if (request.Params is null)
- {
- throw new McpProtocolException("Missing required parameter 'name'", McpErrorCode.InvalidParams);
- }
-
- if (request.Params.Name == "echo")
- {
- if (request.Params.Arguments is null || !request.Params.Arguments.TryGetValue("message", out var message))
- {
- throw new McpProtocolException("Missing required argument 'message'", McpErrorCode.InvalidParams);
- }
- return new CallToolResult
- {
- Content = [new TextContentBlock { Text = $"Echo: {message}" }]
- };
- }
- else if (request.Params.Name == "echoSessionId")
- {
- return new CallToolResult
- {
- Content = [new TextContentBlock { Text = request.Server.SessionId ?? string.Empty }]
+ ]
};
- }
- else if (request.Params.Name == "sampleLLM")
+ },
+
+ CallToolHandler = async (request, cancellationToken) =>
{
- if (request.Params.Arguments is null ||
- !request.Params.Arguments.TryGetValue("prompt", out var prompt) ||
- !request.Params.Arguments.TryGetValue("maxTokens", out var maxTokens))
+ if (request.Params is null)
{
- throw new McpProtocolException("Missing required arguments 'prompt' and 'maxTokens'", McpErrorCode.InvalidParams);
+ throw new McpProtocolException("Missing required parameter 'name'", McpErrorCode.InvalidParams);
}
- var sampleResult = await request.Server.SampleAsync(CreateRequestSamplingParams(prompt.ToString(), "sampleLLM", Convert.ToInt32(maxTokens.ToString())),
- cancellationToken: cancellationToken);
- return new CallToolResult
+ if (request.Params.Name == "echo")
{
- Content = [new TextContentBlock { Text = $"LLM sampling result: {sampleResult.Content.OfType().FirstOrDefault()?.Text}" }]
- };
- }
- else if (request.Params.Name == "longRunning")
- {
- if (request.Params.Arguments is null || !request.Params.Arguments.TryGetValue("durationMs", out var durationMsValue))
+ if (request.Params.Arguments is null || !request.Params.Arguments.TryGetValue("message", out var message))
+ {
+ throw new McpProtocolException("Missing required argument 'message'", McpErrorCode.InvalidParams);
+ }
+ return new CallToolResult
+ {
+ Content = [new TextContentBlock { Text = $"Echo: {message}" }]
+ };
+ }
+ else if (request.Params.Name == "echoSessionId")
{
- throw new McpProtocolException("Missing required argument 'durationMs'", McpErrorCode.InvalidParams);
+ return new CallToolResult
+ {
+ Content = [new TextContentBlock { Text = request.Server.SessionId ?? string.Empty }]
+ };
}
- int durationMs = Convert.ToInt32(durationMsValue.ToString());
- await Task.Delay(durationMs, cancellationToken);
- return new CallToolResult
+ else if (request.Params.Name == "sampleLLM")
{
- Content = [new TextContentBlock { Text = $"Long-running operation completed after {durationMs}ms" }]
- };
- }
- else
- {
- throw new McpProtocolException($"Unknown tool: '{request.Params.Name}'", McpErrorCode.InvalidParams);
- }
- };
+ if (request.Params.Arguments is null ||
+ !request.Params.Arguments.TryGetValue("prompt", out var prompt) ||
+ !request.Params.Arguments.TryGetValue("maxTokens", out var maxTokens))
+ {
+ throw new McpProtocolException("Missing required arguments 'prompt' and 'maxTokens'", McpErrorCode.InvalidParams);
+ }
+ var sampleResult = await request.Server.SampleAsync(CreateRequestSamplingParams(prompt.ToString(), "sampleLLM", Convert.ToInt32(maxTokens.ToString())),
+ cancellationToken: cancellationToken);
- options.Handlers.ListResourceTemplatesHandler = async (request, cancellationToken) =>
- {
- return new ListResourceTemplatesResult
- {
- ResourceTemplates = [
- new ResourceTemplate
- {
- UriTemplate = "test://dynamic/resource/{id}",
- Name = "Dynamic Resource",
+ return new CallToolResult
+ {
+ Content = [new TextContentBlock { Text = $"LLM sampling result: {sampleResult.Content.OfType().FirstOrDefault()?.Text}" }]
+ };
}
- ]
- };
- };
-
- options.Handlers.ListResourcesHandler = async (request, cancellationToken) =>
- {
- int startIndex = 0;
- var requestParams = request.Params ?? new();
-
- if (requestParams.Cursor is not null)
- {
- try
+ else if (request.Params.Name == "longRunning")
{
- var startIndexAsString = Encoding.UTF8.GetString(Convert.FromBase64String(requestParams.Cursor));
- startIndex = Convert.ToInt32(startIndexAsString);
+ if (request.Params.Arguments is null || !request.Params.Arguments.TryGetValue("durationMs", out var durationMsValue))
+ {
+ throw new McpProtocolException("Missing required argument 'durationMs'", McpErrorCode.InvalidParams);
+ }
+ int durationMs = Convert.ToInt32(durationMsValue.ToString());
+ await Task.Delay(durationMs, cancellationToken);
+ return new CallToolResult
+ {
+ Content = [new TextContentBlock { Text = $"Long-running operation completed after {durationMs}ms" }]
+ };
}
- catch (Exception e)
+ else
{
- throw new McpProtocolException($"Invalid cursor: '{requestParams.Cursor}'", e, McpErrorCode.InvalidParams);
+ throw new McpProtocolException($"Unknown tool: '{request.Params.Name}'", McpErrorCode.InvalidParams);
}
- }
-
- int endIndex = Math.Min(startIndex + pageSize, resources.Count);
- string? nextCursor = null;
+ },
- if (endIndex < resources.Count)
+ ListResourceTemplatesHandler = async (request, cancellationToken) =>
{
- nextCursor = Convert.ToBase64String(Encoding.UTF8.GetBytes(endIndex.ToString()));
- }
+ return new ListResourceTemplatesResult
+ {
+ ResourceTemplates = [
+ new ResourceTemplate
+ {
+ UriTemplate = "test://dynamic/resource/{id}",
+ Name = "Dynamic Resource",
+ }
+ ]
+ };
+ },
- return new ListResourcesResult
+ ListResourcesHandler = async (request, cancellationToken) =>
{
- NextCursor = nextCursor,
- Resources = resources.GetRange(startIndex, endIndex - startIndex)
- };
- };
+ int startIndex = 0;
+ var requestParams = request.Params ?? new();
- options.Handlers.ReadResourceHandler = async (request, cancellationToken) =>
- {
- if (request.Params?.Uri is null)
- {
- throw new McpProtocolException("Missing required argument 'uri'", McpErrorCode.InvalidParams);
- }
+ if (requestParams.Cursor is not null)
+ {
+ try
+ {
+ var startIndexAsString = Encoding.UTF8.GetString(Convert.FromBase64String(requestParams.Cursor));
+ startIndex = Convert.ToInt32(startIndexAsString);
+ }
+ catch (Exception e)
+ {
+ throw new McpProtocolException($"Invalid cursor: '{requestParams.Cursor}'", e, McpErrorCode.InvalidParams);
+ }
+ }
- if (request.Params.Uri.StartsWith("test://dynamic/resource/"))
- {
- var id = request.Params.Uri.Split('/').LastOrDefault();
- if (string.IsNullOrEmpty(id))
+ int endIndex = Math.Min(startIndex + pageSize, resources.Count);
+ string? nextCursor = null;
+
+ if (endIndex < resources.Count)
{
- throw new McpProtocolException($"Invalid resource URI: '{request.Params.Uri}'", McpErrorCode.InvalidParams);
+ nextCursor = Convert.ToBase64String(Encoding.UTF8.GetBytes(endIndex.ToString()));
}
- return new ReadResourceResult
+ return new ListResourcesResult
{
- Contents = [
- new TextResourceContents
- {
- Uri = request.Params.Uri,
- MimeType = "text/plain",
- Text = $"Dynamic resource {id}: This is a plaintext resource"
- }
- ]
+ NextCursor = nextCursor,
+ Resources = resources.GetRange(startIndex, endIndex - startIndex)
};
- }
-
- ResourceContents? contents = resourceContents.FirstOrDefault(r => r.Uri == request.Params.Uri) ??
- throw new McpProtocolException($"Resource not found: '{request.Params.Uri}'", McpErrorCode.ResourceNotFound);
+ },
- return new ReadResourceResult
+ ReadResourceHandler = async (request, cancellationToken) =>
{
- Contents = [contents]
- };
- };
+ if (request.Params?.Uri is null)
+ {
+ throw new McpProtocolException("Missing required argument 'uri'", McpErrorCode.InvalidParams);
+ }
- options.Handlers.ListPromptsHandler = async (request, cancellationToken) =>
- {
- return new ListPromptsResult
- {
- Prompts = [
- new Prompt
- {
- Name = "simple_prompt",
- Description = "A prompt without arguments"
- },
- new Prompt
+ if (request.Params.Uri.StartsWith("test://dynamic/resource/"))
+ {
+ var id = request.Params.Uri.Split('/').LastOrDefault();
+ if (string.IsNullOrEmpty(id))
{
- Name = "complex_prompt",
- Description = "A prompt with arguments",
- Arguments =
- [
- new PromptArgument
- {
- Name = "temperature",
- Description = "Temperature setting",
- Required = true
- },
- new PromptArgument
- {
- Name = "style",
- Description = "Output style",
- Required = false
- }
- ],
+ throw new McpProtocolException($"Invalid resource URI: '{request.Params.Uri}'", McpErrorCode.InvalidParams);
}
- ]
- };
- };
- options.Handlers.GetPromptHandler = async (request, cancellationToken) =>
- {
- if (request.Params is null)
- {
- throw new McpProtocolException("Missing required parameter 'name'", McpErrorCode.InvalidParams);
- }
+ return new ReadResourceResult
+ {
+ Contents = [
+ new TextResourceContents
+ {
+ Uri = request.Params.Uri,
+ MimeType = "text/plain",
+ Text = $"Dynamic resource {id}: This is a plaintext resource"
+ }
+ ]
+ };
+ }
- List messages = [];
+ ResourceContents? contents = resourceContents.FirstOrDefault(r => r.Uri == request.Params.Uri) ??
+ throw new McpProtocolException($"Resource not found: '{request.Params.Uri}'", McpErrorCode.ResourceNotFound);
- if (request.Params.Name == "simple_prompt")
+ return new ReadResourceResult
+ {
+ Contents = [contents]
+ };
+ },
+
+ ListPromptsHandler = async (request, cancellationToken) =>
{
- messages.Add(new PromptMessage
+ return new ListPromptsResult
{
- Role = Role.User,
- Content = new TextContentBlock { Text = "This is a simple prompt without arguments." },
- });
- }
- else if (request.Params.Name == "complex_prompt")
+ Prompts = [
+ new Prompt
+ {
+ Name = "simple_prompt",
+ Description = "A prompt without arguments"
+ },
+ new Prompt
+ {
+ Name = "complex_prompt",
+ Description = "A prompt with arguments",
+ Arguments =
+ [
+ new PromptArgument
+ {
+ Name = "temperature",
+ Description = "Temperature setting",
+ Required = true
+ },
+ new PromptArgument
+ {
+ Name = "style",
+ Description = "Output style",
+ Required = false
+ }
+ ],
+ }
+ ]
+ };
+ },
+
+ GetPromptHandler = async (request, cancellationToken) =>
{
- string temperature = request.Params.Arguments?["temperature"].ToString() ?? "unknown";
- string style = request.Params.Arguments?["style"].ToString() ?? "unknown";
- messages.Add(new PromptMessage
+ if (request.Params is null)
{
- Role = Role.User,
- Content = new TextContentBlock { Text = $"This is a complex prompt with arguments: temperature={temperature}, style={style}" },
- });
- messages.Add(new PromptMessage
+ throw new McpProtocolException("Missing required parameter 'name'", McpErrorCode.InvalidParams);
+ }
+
+ List messages = [];
+
+ if (request.Params.Name == "simple_prompt")
{
- Role = Role.User,
- Content = new TextContentBlock { Text = "I understand. You've provided a complex prompt with temperature and style arguments. How would you like me to proceed?" },
- });
- messages.Add(new PromptMessage
+ messages.Add(new PromptMessage
+ {
+ Role = Role.User,
+ Content = new TextContentBlock { Text = "This is a simple prompt without arguments." },
+ });
+ }
+ else if (request.Params.Name == "complex_prompt")
{
- Role = Role.User,
- Content = new ImageContentBlock
+ string temperature = request.Params.Arguments?["temperature"].ToString() ?? "unknown";
+ string style = request.Params.Arguments?["style"].ToString() ?? "unknown";
+ messages.Add(new PromptMessage
{
- Data = System.Text.Encoding.UTF8.GetBytes(MCP_TINY_IMAGE),
- MimeType = "image/png"
- }
- });
- }
- else
- {
- throw new McpProtocolException($"Unknown prompt: {request.Params.Name}", McpErrorCode.InvalidParams);
- }
+ Role = Role.User,
+ Content = new TextContentBlock { Text = $"This is a complex prompt with arguments: temperature={temperature}, style={style}" },
+ });
+ messages.Add(new PromptMessage
+ {
+ Role = Role.User,
+ Content = new TextContentBlock { Text = "I understand. You've provided a complex prompt with temperature and style arguments. How would you like me to proceed?" },
+ });
+ messages.Add(new PromptMessage
+ {
+ Role = Role.User,
+ Content = new ImageContentBlock
+ {
+ Data = System.Text.Encoding.UTF8.GetBytes(MCP_TINY_IMAGE),
+ MimeType = "image/png"
+ }
+ });
+ }
+ else
+ {
+ throw new McpProtocolException($"Unknown prompt: {request.Params.Name}", McpErrorCode.InvalidParams);
+ }
- return new GetPromptResult
- {
- Messages = messages
- };
+ return new GetPromptResult
+ {
+ Messages = messages
+ };
+ },
};
}