// Copyright (c) Microsoft. All rights reserved. using Microsoft.SemanticKernel; using Microsoft.SemanticKernel.PromptTemplates.Handlebars; using ModelContextProtocol.Protocol; using ModelContextProtocol.Server; namespace MCPServer.Prompts; /// /// Represents a prompt definition. /// public sealed class PromptDefinition { /// /// Gets or sets the prompt. /// public required Prompt Prompt { get; init; } /// /// Gets or sets the handler for the prompt. /// public required Func, CancellationToken, Task> Handler { get; init; } /// /// Gets this prompt definition. /// /// The JSON prompt template. /// An instance of the kernel to render the prompt. /// If not provided, an instance registered in DI container will be used. /// /// The prompt definition. public static PromptDefinition Create(string jsonPrompt, Kernel? kernel = null) { PromptTemplateConfig promptTemplateConfig = PromptTemplateConfig.FromJson(jsonPrompt); IPromptTemplate promptTemplate = new HandlebarsPromptTemplateFactory().Create(promptTemplateConfig); return new PromptDefinition() { Prompt = GetPrompt(promptTemplateConfig), Handler = (context, cancellationToken) => { return GetPromptHandlerAsync(context, promptTemplateConfig, promptTemplate, kernel, cancellationToken); } }; } /// /// Creates an MCP prompt from SK prompt template. /// /// The prompt template configuration. /// The MCP prompt. private static Prompt GetPrompt(PromptTemplateConfig promptTemplateConfig) { // Create the MCP prompt arguments List? arguments = null; foreach (var inputVariable in promptTemplateConfig.InputVariables) { (arguments ??= []).Add(new() { Name = inputVariable.Name, Description = inputVariable.Description, Required = inputVariable.IsRequired }); } // Create the MCP prompt return new Prompt { Name = promptTemplateConfig.Name!, Description = promptTemplateConfig.Description, Arguments = arguments }; } /// /// Handles the prompt request by rendering the prompt. /// /// The MCP request context. /// The prompt template configuration. /// The prompt template. /// The kernel to render the prompt. /// The cancellation token. /// The prompt. private static async Task GetPromptHandlerAsync(RequestContext context, PromptTemplateConfig promptTemplateConfig, IPromptTemplate promptTemplate, Kernel? kernel, CancellationToken cancellationToken) { // Use either explicitly provided kernel or the one registered in DI container kernel ??= context.Server.Services?.GetRequiredService() ?? throw new InvalidOperationException("Kernel is not available."); // Render the prompt string renderedPrompt = await promptTemplate.RenderAsync( kernel: kernel, arguments: context.Params?.Arguments is { } args ? new KernelArguments(args.ToDictionary(kvp => kvp.Key, kvp => (object?)kvp.Value)) : null, cancellationToken: cancellationToken); // Create prompt result return new GetPromptResult() { Description = promptTemplateConfig.Description, Messages = [ new PromptMessage() { Content = new TextContentBlock() { Text = renderedPrompt }, Role = Role.Assistant } ] }; } }