Model context protocol server prompts with microsoft semantic kernel

This post focuses on implementing server prompts, a key feature of the Model Context Protocol (MCP) designed for reusable template definitions. We will explore how to implement these server prompts using both the MCP C# SDK and Semantic Kernel for enhanced templating capabilities. Further details on MCP server prompts can be found in the MCP documentation. MCP Server Prompts via MCP C# SDK Attributes MCP C# SDK allows for defining prompts through attributes. This method offers a direct implementation without requiring Semantic Kernel for basic string manipulation as the following example shows. [McpServerPromptType] internal sealed class StringFormatPrompt { private readonly string _format; private readonly ILogger _logger; public StringFormatPrompt(ILogger logger) { _logger = logger; _format = "Tell a joke about {0}."; } [McpServerPrompt(Name = "Joke"), Description("Tell a joke about a topic.")] public IReadOnlyCollection Format([Description("The topic of the joke.")] string topic) { _logger.LogInformation("Generating prompt with topic: {Topic}", topic); var content = string.Format(CultureInfo.InvariantCulture, _format, topic); return [ new (ChatRole.User, content) ]; } } // Register for the prompt var serverBuilder = builder.Services.AddMcpServer() .WithHttpTransport() .WithPrompts(); Semantic Kernel Templates as MCP Server Prompts Semantic Kernel provides templating capabilities through JSON/YAML, Handlebars, and Liquid formats, along with plugin support. These templates can be exposed as MCP prompts using the MCP C# SDK. Prompt Templates in Semantic Kernel Semantic Kernel templates are configured with PromptTemplateConfig, created by IPromptTemplateFactory implementations, and can be easily rendered with input variables for dynamic prompt generation. var templateConfig = new PromptTemplateConfig("Tell a joke about {{$topic}}."); IPromptTemplateFactory templateFactory = new KernelPromptTemplateFactory(); var template = templateFactory.Create(templateConfig); var text = await template.RenderAsync(kernel, new KernelArguments { { "topic", "cats" } }); Expose prompts as McpServerPrompt McpServerPrompt is the abstract base class that represents an MCP prompt we can implement. internal sealed class TemplateServerPrompt : McpServerPrompt { public TemplateServerPrompt(PromptTemplateConfig promptTemplateConfig, IPromptTemplateFactory? promptTemplateFactory, ILoggerFactory? loggerFactory) { promptTemplateFactory ??= new KernelPromptTemplateFactory(loggerFactory ?? NullLoggerFactory.Instance); _template = promptTemplateFactory.Create(promptTemplateConfig); // MCP prompt ProtocolPrompt = new() { Name = promptTemplateConfig.Name ?? _template.GetType().Name, Description = promptTemplateConfig.Description, Arguments = promptTemplateConfig.InputVariables .Select(inputVariable => new PromptArgument { Name = inputVariable.Name, Description = inputVariable.Description, Required = inputVariable.IsRequired }) .ToList(), }; } public override async ValueTask GetAsync(RequestContext request, CancellationToken cancellationToken = default) { KernelArguments? arguments = default; var dictionary = request.Params?.Arguments; if (dictionary is not null) { arguments = new (); foreach (var (key, value) in dictionary) { arguments[key] = value; } } var kernel = request.Services?.GetService() ?? new Kernel(); var text = await _template.RenderAsync(kernel, arguments, cancellationToken); return new GetPromptResult { Messages = [ new PromptMessage { Content = new Content { Text = text } } ] }; } } // Register for the prompt with DI and MCP server // builder.Services.AddSingleton(...) var serverBuilder = builder.Services.AddMcpServer() .WithHttpTransport(); serverBuilder.Services.AddSingleton(provider => provider.GetRequiredService()); Exposing AIFunction as McpServerPrompt The McpServerPrompt class provides a Create method to expose a Microsoft.Extensions.AI.AIFunction as an MCP server prompt. internal sealed class TemplateAIFunction : AIFunction { //... protected override async ValueTask InvokeCoreAsync(AIFunctionArguments arguments, CancellationToken cancellationToken) { KernelArguments kernelArguments = []; foreach (var argument in arguments) { kernelArgume

Apr 24, 2025 - 00:02
 0
Model context protocol server prompts with microsoft semantic kernel

This post focuses on implementing server prompts, a key feature of the Model Context Protocol (MCP) designed for reusable template definitions. We will explore how to implement these server prompts using both the MCP C# SDK and Semantic Kernel for enhanced templating capabilities. Further details on MCP server prompts can be found in the MCP documentation.

MCP Server Prompts via MCP C# SDK Attributes

MCP C# SDK allows for defining prompts through attributes. This method offers a direct implementation without requiring Semantic Kernel for basic string manipulation as the following example shows.


[McpServerPromptType]
internal sealed class StringFormatPrompt
{
    private readonly string _format;
    private readonly ILogger _logger;

    public StringFormatPrompt(ILogger<StringFormatPrompt> logger)
    {
        _logger = logger;
        _format = "Tell a joke about {0}.";
    }

    [McpServerPrompt(Name = "Joke"), Description("Tell a joke about a topic.")]
    public IReadOnlyCollection<ChatMessage> Format([Description("The topic of the joke.")] string topic)
    {
        _logger.LogInformation("Generating prompt with topic: {Topic}", topic);
        var content = string.Format(CultureInfo.InvariantCulture, _format, topic);
        return [
            new (ChatRole.User, content)
        ];
    }
 }    

 // Register for the prompt
 var serverBuilder = builder.Services.AddMcpServer()
    .WithHttpTransport()
    .WithPrompts<StringFormatPrompt>();

Semantic Kernel Templates as MCP Server Prompts

Semantic Kernel provides templating capabilities through JSON/YAML, Handlebars, and Liquid formats, along with plugin support. These templates can be exposed as MCP prompts using the MCP C# SDK.

  1. Prompt Templates in Semantic Kernel
    Semantic Kernel templates are configured with PromptTemplateConfig, created by IPromptTemplateFactory implementations, and can be easily rendered with input variables for dynamic prompt generation.

    var templateConfig = new PromptTemplateConfig("Tell a joke about {{$topic}}.");
    IPromptTemplateFactory templateFactory = new KernelPromptTemplateFactory();
    var template = templateFactory.Create(templateConfig);
    var text = await template.RenderAsync(kernel,
        new KernelArguments
        {
            { "topic", "cats" }
        });
    
  2. Expose prompts as McpServerPrompt
    McpServerPrompt is the abstract base class that represents an MCP prompt we can implement.

    
    internal sealed class TemplateServerPrompt : McpServerPrompt
    {
        public TemplateServerPrompt(PromptTemplateConfig promptTemplateConfig, IPromptTemplateFactory? promptTemplateFactory, ILoggerFactory? loggerFactory)
        {
            promptTemplateFactory ??= new KernelPromptTemplateFactory(loggerFactory ?? NullLoggerFactory.Instance);
            _template = promptTemplateFactory.Create(promptTemplateConfig);
    
            // MCP prompt
            ProtocolPrompt = new()
            {
                Name = promptTemplateConfig.Name ?? _template.GetType().Name,
                Description = promptTemplateConfig.Description,
                Arguments = promptTemplateConfig.InputVariables
                    .Select(inputVariable =>
                        new PromptArgument
                        {
                            Name = inputVariable.Name,
                            Description = inputVariable.Description,
                            Required = inputVariable.IsRequired
                        })
                    .ToList(),
            };
        }
    
        public override async ValueTask<GetPromptResult> GetAsync(RequestContext<GetPromptRequestParams> request, CancellationToken cancellationToken = default)
        {
            KernelArguments? arguments = default;
    
            var dictionary = request.Params?.Arguments;
            if (dictionary is not null)
            {
                arguments = new ();
                foreach (var (key, value) in dictionary)
                {
                    arguments[key] = value;
                }
            }
    
            var kernel = request.Services?.GetService<Kernel>() ?? new Kernel();
            var text = await _template.RenderAsync(kernel, arguments, cancellationToken);
    
            return 
                new GetPromptResult
                {
                    Messages = [
                        new PromptMessage
                        {
                            Content = new Content { Text = text }
                        } 
                ]
            };
        }
    }
    
    // Register for the prompt with DI and MCP server
    // builder.Services.AddSingleton(...)
    var serverBuilder = builder.Services.AddMcpServer()
        .WithHttpTransport();
    serverBuilder.Services.AddSingleton<McpServerPrompt>(provider => 
        provider.GetRequiredService<TemplateServerPrompt>());
    
    
  3. Exposing AIFunction as McpServerPrompt
    The McpServerPrompt class provides a Create method to expose a Microsoft.Extensions.AI.AIFunction as an MCP server prompt.

    
    internal sealed class TemplateAIFunction : AIFunction 
    {
        //...
    
        protected override async ValueTask<object?> InvokeCoreAsync(AIFunctionArguments arguments, CancellationToken cancellationToken)
        {
            KernelArguments kernelArguments = [];
    
            foreach (var argument in arguments)
            {
                kernelArguments[argument.Key] = argument.Value;
            }
    
            var kernel = arguments.Services?.GetService<Kernel>() ?? new Kernel();
            var text = await _template.RenderAsync(kernel, kernelArguments, cancellationToken);
            return text;
        }
    }
    
    // Register for the prompt with DI and MCP server
    // builder.Services.AddSingleton(...)
    var serverBuilder = builder.Services.AddMcpServer()
        .WithHttpTransport();
    serverBuilder.Services.AddSingleton<McpServerPrompt>(provider => 
        McpServerPrompt.Create(provider.GetRequiredService<TemplateServerPrompt>()));
    
    

Complete sample code

Please feel free to reach out on twitter @roamingcode