using System.ComponentModel; using System.Text.Json; using ModelContextProtocol; using ModelContextProtocol.Protocol; using ModelContextProtocol.Server; using static ModelContextProtocol.Protocol.ElicitRequestParams; namespace Elicitation.Tools; [McpServerToolType] public sealed class InteractiveTools { // [McpServerTool, Description("A simple game where the user has to guess a number between 1 and 10.")] public async Task GuessTheNumber( McpServer server, // Get the McpServer from DI container CancellationToken cancellationToken ) { // Check if the client supports elicitation if (server.ClientCapabilities?.Elicitation == null) { // fail the tool call throw new McpException("Client does not support elicitation"); } // First ask the user if they want to play var playSchema = new RequestSchema { Properties = { ["Answer"] = new BooleanSchema() } }; var playResponse = await server.ElicitAsync(new ElicitRequestParams { Message = "Do you want to play a game?", RequestedSchema = playSchema }, cancellationToken); // Check if user wants to play if (playResponse.Action != "accept" || playResponse.Content?["Answer"].ValueKind != JsonValueKind.True) { return "Maybe next time!"; } // // Now ask the user to enter their name var nameSchema = new RequestSchema { Properties = { ["Name"] = new StringSchema() { Description = "Name of the player", MinLength = 2, MaxLength = 50, } } }; var nameResponse = await server.ElicitAsync(new ElicitRequestParams { Message = "What is your name?", RequestedSchema = nameSchema }, cancellationToken); if (nameResponse.Action != "accept") { return "Maybe next time!"; } string? playerName = nameResponse.Content?["Name"].GetString(); // Generate a random number between 1 and 10 Random random = new(); int targetNumber = random.Next(1, 11); // 1 to 10 inclusive int attempts = 0; var message = "Guess a number between 1 and 10"; while (true) { attempts++; var guessSchema = new RequestSchema { Properties = { ["Guess"] = new NumberSchema() { Type = "integer", Minimum = 1, Maximum = 10, } } }; var guessResponse = await server.ElicitAsync(new ElicitRequestParams { Message = message, RequestedSchema = guessSchema }, cancellationToken); if (guessResponse.Action != "accept") { return "Maybe next time!"; } int guess = (int)(guessResponse.Content?["Guess"].GetInt32())!; // Check if the guess is correct if (guess == targetNumber) { return $"Congratulations {playerName}! You guessed the number {targetNumber} in {attempts} attempts!"; } else if (guess < targetNumber) { message = $"Your guess is too low! Try again (Attempt #{attempts}):"; } else { message = $"Your guess is too high! Try again (Attempt #{attempts}):"; } } } // [McpServerTool, Description("Example tool demonstrating various enum schema types")] public async Task EnumExamples( McpServer server, CancellationToken cancellationToken ) { // Example 1: UntitledSingleSelectEnumSchema - Simple enum without display titles var prioritySchema = new RequestSchema { Properties = { ["Priority"] = new UntitledSingleSelectEnumSchema { Title = "Priority Level", Description = "Select the priority level", Enum = ["low", "medium", "high", "critical"], Default = "medium" } } }; var priorityResponse = await server.ElicitAsync(new ElicitRequestParams { Message = "Select a priority level:", RequestedSchema = prioritySchema }, cancellationToken); if (priorityResponse.Action != "accept") { return "Operation cancelled"; } string? priority = priorityResponse.Content?["Priority"].GetString(); // Example 2: TitledSingleSelectEnumSchema - Enum with custom display titles var severitySchema = new RequestSchema { Properties = { ["Severity"] = new TitledSingleSelectEnumSchema { Title = "Issue Severity", Description = "Select the issue severity level", OneOf = [ new EnumSchemaOption { Const = "p0", Title = "P0 - Critical (Immediate attention required)" }, new EnumSchemaOption { Const = "p1", Title = "P1 - High (Urgent, within 24 hours)" }, new EnumSchemaOption { Const = "p2", Title = "P2 - Medium (Within a week)" }, new EnumSchemaOption { Const = "p3", Title = "P3 - Low (As time permits)" } ], Default = "p2" } } }; var severityResponse = await server.ElicitAsync(new ElicitRequestParams { Message = "Select the issue severity:", RequestedSchema = severitySchema }, cancellationToken); if (severityResponse.Action != "accept") { return "Operation cancelled"; } string? severity = severityResponse.Content?["Severity"].GetString(); // Example 3: UntitledMultiSelectEnumSchema - Select multiple values var tagsSchema = new RequestSchema { Properties = { ["Tags"] = new UntitledMultiSelectEnumSchema { Title = "Tags", Description = "Select one or more tags", MinItems = 1, MaxItems = 3, Items = new UntitledEnumItemsSchema { Type = "string", Enum = ["bug", "feature", "documentation", "enhancement", "question"] }, Default = ["bug"] } } }; var tagsResponse = await server.ElicitAsync(new ElicitRequestParams { Message = "Select up to 3 tags:", RequestedSchema = tagsSchema }, cancellationToken); if (tagsResponse.Action != "accept") { return "Operation cancelled"; } // For multi-select, the value is an array var tags = tagsResponse.Content?["Tags"].EnumerateArray() .Select(e => e.GetString()) .ToArray(); // Example 4: TitledMultiSelectEnumSchema - Multi-select with custom titles var featuresSchema = new RequestSchema { Properties = { ["Features"] = new TitledMultiSelectEnumSchema { Title = "Features", Description = "Select desired features", Items = new TitledEnumItemsSchema { AnyOf = [ new EnumSchemaOption { Const = "auth", Title = "Authentication & Authorization" }, new EnumSchemaOption { Const = "api", Title = "RESTful API" }, new EnumSchemaOption { Const = "ui", Title = "Modern UI Components" }, new EnumSchemaOption { Const = "db", Title = "Database Integration" } ] } } } }; var featuresResponse = await server.ElicitAsync(new ElicitRequestParams { Message = "Select desired features:", RequestedSchema = featuresSchema }, cancellationToken); if (featuresResponse.Action != "accept") { return "Operation cancelled"; } var features = featuresResponse.Content?["Features"].EnumerateArray() .Select(e => e.GetString()) .ToArray(); return $"Selected: Priority={priority}, Severity={severity}, Tags=[{string.Join(", ", tags ?? [])}], Features=[{string.Join(", ", features ?? [])}]"; } // }