Skip to content

Commit fabdb67

Browse files
update mcp prompt sample
1 parent 072c476 commit fabdb67

File tree

6 files changed

+61
-48
lines changed

6 files changed

+61
-48
lines changed

dotnet/samples/Demos/ModelContextProtocolClientServer/MCPClient/Extensions/PromptResultExtensions.cs

+9-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright (c) Microsoft. All rights reserved.
22

33
using System;
4+
using System.Collections.Generic;
45
using Microsoft.SemanticKernel;
56
using Microsoft.SemanticKernel.ChatCompletion;
67
using ModelContextProtocol.Protocol.Types;
@@ -13,13 +14,13 @@ namespace MCPClient;
1314
internal static class PromptResultExtensions
1415
{
1516
/// <summary>
16-
/// Converts a <see cref="GetPromptResult"/> to a <see cref="ChatHistory"/>.
17+
/// Converts a <see cref="GetPromptResult"/> to chat message contents.
1718
/// </summary>
1819
/// <param name="result">The prompt result to convert.</param>
1920
/// <returns>The corresponding <see cref="ChatHistory"/>.</returns>
20-
public static ChatHistory ToChatHistory(this GetPromptResult result)
21+
public static IList<ChatMessageContent> ToChatMessageContents(this GetPromptResult result)
2122
{
22-
ChatHistory chatHistory = [];
23+
List<ChatMessageContent> contents = [];
2324

2425
foreach (PromptMessage message in result.Messages)
2526
{
@@ -33,13 +34,16 @@ public static ChatHistory ToChatHistory(this GetPromptResult result)
3334
case "image":
3435
items.Add(new ImageContent(Convert.FromBase64String(message.Content.Data!), message.Content.MimeType));
3536
break;
37+
case "audio":
38+
items.Add(new AudioContent(Convert.FromBase64String(message.Content.Data!), message.Content.MimeType));
39+
break;
3640
default:
3741
throw new InvalidOperationException($"Unexpected message content type '{message.Content.Type}'");
3842
}
3943

40-
chatHistory.Add(new ChatMessageContent(message.Role.ToAuthorRole(), items));
44+
contents.Add(new ChatMessageContent(message.Role.ToAuthorRole(), items));
4145
}
4246

43-
return chatHistory;
47+
return contents;
4448
}
4549
}

dotnet/samples/Demos/ModelContextProtocolClientServer/MCPClient/Program.cs

+21-30
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public static async Task Main(string[] args)
2222
{
2323
await UseMCPToolsAsync();
2424

25-
await UseMCPToolsAndPromptAsync();
25+
await UseMCPPromptAsync();
2626

2727
await UseMCPResourcesAsync();
2828

@@ -175,59 +175,50 @@ private static async Task UseMCPToolsAsync()
175175
}
176176

177177
/// <summary>
178-
/// Demonstrates how to use the MCP tools and MCP prompt with the Semantic Kernel.
178+
/// Demonstrates how to use the MCP prompt with the Semantic Kernel.
179179
/// The code in this method:
180180
/// 1. Creates an MCP client.
181-
/// 2. Retrieves the list of tools provided by the MCP server.
182-
/// 3. Retrieves the list of prompts provided by the MCP server.
183-
/// 4. Creates a kernel and registers the MCP tools as Kernel functions.
184-
/// 5. Requests the `GetCurrentWeatherForCity` prompt from the MCP server.
185-
/// 6. The MCP server renders the prompt using the `Boston` as value for the `city` parameter and the result of the `DateTimeUtils-GetCurrentDateTimeInUtc` server-side invocation added to the prompt as part of prompt rendering.
186-
/// 7. Converts the MCP server prompt: list of messages where each message is represented by content and role to a chat history.
187-
/// 8. Sends the chat history to the AI model together with the MCP tools represented as Kernel functions.
188-
/// 9. The AI model calls WeatherUtils-GetWeatherForCity function with the current date time and the `Boston` arguments extracted from the prompt to get the weather information.
189-
/// 10. Having received the weather information from the function call, the AI model returns the answer to the prompt.
181+
/// 2. Retrieves the list of prompts provided by the MCP server.
182+
/// 3. Gets the current weather for Boston and Sydney using the `GetCurrentWeatherForCity` prompt.
183+
/// 4. Adds the MCP server prompts to the chat history and prompts the AI model to compare the weather in the two cities and suggest the best place to go for a walk.
184+
/// 5. After receiving and processing the weather data for both cities and the prompt, the AI model returns an answer.
190185
/// </summary>
191-
private static async Task UseMCPToolsAndPromptAsync()
186+
private static async Task UseMCPPromptAsync()
192187
{
193-
Console.WriteLine($"Running the {nameof(UseMCPToolsAndPromptAsync)} sample.");
188+
Console.WriteLine($"Running the {nameof(UseMCPPromptAsync)} sample.");
194189

195190
// Create an MCP client
196191
await using IMcpClient mcpClient = await CreateMcpClientAsync();
197192

198-
// Retrieve and display the list provided by the MCP server
199-
IList<McpClientTool> tools = await mcpClient.ListToolsAsync();
200-
DisplayTools(tools);
201-
202193
// Retrieve and display the list of prompts provided by the MCP server
203194
IList<McpClientPrompt> prompts = await mcpClient.ListPromptsAsync();
204195
DisplayPrompts(prompts);
205196

206-
// Create a kernel and register the MCP tools
197+
// Create a kernel
207198
Kernel kernel = CreateKernelWithChatCompletionService();
208-
kernel.Plugins.AddFromFunctions("Tools", tools.Select(aiFunction => aiFunction.AsKernelFunction()));
209199

210-
// Enable automatic function calling
211-
OpenAIPromptExecutionSettings executionSettings = new()
212-
{
213-
Temperature = 0,
214-
FunctionChoiceBehavior = FunctionChoiceBehavior.Auto(options: new() { RetainArgumentTypes = true })
215-
};
200+
// Get weather for Boston using the `GetCurrentWeatherForCity` prompt from the MCP server
201+
GetPromptResult bostonWeatherPrompt = await mcpClient.GetPromptAsync("GetCurrentWeatherForCity", new Dictionary<string, object?>() { ["city"] = "Boston", ["time"] = DateTime.UtcNow.ToString() });
216202

217-
// Retrieve the `GetCurrentWeatherForCity` prompt from the MCP server and convert it to a chat history
218-
GetPromptResult promptResult = await mcpClient.GetPromptAsync("GetCurrentWeatherForCity", new Dictionary<string, object?>() { ["city"] = "Boston" });
203+
// Get weather for Sydney using the `GetCurrentWeatherForCity` prompt from the MCP server
204+
GetPromptResult sydneyWeatherPrompt = await mcpClient.GetPromptAsync("GetCurrentWeatherForCity", new Dictionary<string, object?>() { ["city"] = "Sydney", ["time"] = DateTime.UtcNow.ToString() });
219205

220-
ChatHistory chatHistory = promptResult.ToChatHistory();
206+
// Add the prompts to the chat history
207+
ChatHistory chatHistory = [];
208+
chatHistory.AddRange(bostonWeatherPrompt.ToChatMessageContents());
209+
chatHistory.AddRange(sydneyWeatherPrompt.ToChatMessageContents());
210+
chatHistory.AddUserMessage("Compare the weather in the two cities and suggest the best place to go for a walk.");
221211

222212
// Execute a prompt using the MCP tools and prompt
223213
IChatCompletionService chatCompletion = kernel.GetRequiredService<IChatCompletionService>();
224214

225-
ChatMessageContent result = await chatCompletion.GetChatMessageContentAsync(chatHistory, executionSettings, kernel);
215+
ChatMessageContent result = await chatCompletion.GetChatMessageContentAsync(chatHistory, kernel: kernel);
226216

227217
Console.WriteLine(result);
228218
Console.WriteLine();
229219

230-
// The expected output is: The weather in Boston as of 2025-04-02 16:39:40 is 61°F and rainy.
220+
// The expected output is: Given these conditions, Sydney would be the better choice for a pleasant walk, as the sunny and warm weather is ideal for outdoor activities.
221+
// The rain in Boston could make walking less enjoyable and potentially inconvenient.
231222
}
232223

233224
/// <summary>

dotnet/samples/Demos/ModelContextProtocolClientServer/MCPServer/Extensions/McpServerBuilderExtensions.cs

+17
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// Copyright (c) Microsoft. All rights reserved.
22

3+
using MCPServer.Prompts;
34
using MCPServer.Resources;
45
using Microsoft.SemanticKernel;
56
using ModelContextProtocol.Protocol.Types;
@@ -31,6 +32,22 @@ public static IMcpServerBuilder WithTools(this IMcpServerBuilder builder, Kernel
3132
return builder;
3233
}
3334

35+
/// <summary>
36+
/// Adds a resource template to the server.
37+
/// </summary>
38+
/// <param name="builder">The MCP server builder.</param>
39+
/// <param name="templateDefinition">The resource template definition.</param>
40+
/// <returns>The builder instance.</returns>
41+
public static IMcpServerBuilder WithPrompt(this IMcpServerBuilder builder, PromptDefinition templateDefinition)
42+
{
43+
PromptRegistry.RegisterPrompt(templateDefinition);
44+
45+
builder.WithListPromptsHandler(PromptRegistry.HandlerListPromptRequestsAsync);
46+
builder.WithGetPromptHandler(PromptRegistry.HandlerGetPromptRequestsAsync);
47+
48+
return builder;
49+
}
50+
3451
/// <summary>
3552
/// Adds a resource template to the server.
3653
/// </summary>

dotnet/samples/Demos/ModelContextProtocolClientServer/MCPServer/Program.cs

+4-8
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,6 @@
1818
kernel.Plugins.AddFromType<DateTimeUtils>();
1919
kernel.Plugins.AddFromType<WeatherUtils>();
2020

21-
// Register prompts
22-
PromptRegistry.RegisterPrompt(PromptDefinition.Create(EmbeddedResource.ReadAsString("Prompts.getCurrentWeatherForCity.json"), kernel));
23-
2421
var builder = Host.CreateEmptyApplicationBuilder(settings: null);
2522
builder.Services
2623
.AddMcpServer()
@@ -29,6 +26,9 @@
2926
// Add all functions from the kernel plugins to the MCP server as tools
3027
.WithTools(kernel.Plugins)
3128

29+
// Register the `getCurrentWeatherForCity` prompt
30+
.WithPrompt(PromptDefinition.Create(EmbeddedResource.ReadAsString("Prompts.getCurrentWeatherForCity.json"), kernel))
31+
3232
// Register vector search as MCP resource template
3333
.WithResourceTemplate(CreateVectorStoreSearchResourceTemplate(kernel))
3434

@@ -38,11 +38,7 @@
3838
uri: "image://cat.jpg",
3939
name: "cat-image",
4040
content: EmbeddedResource.ReadAsBytes("Resources.cat.jpg"),
41-
mimeType: "image/jpeg"))
42-
43-
// Register prompt handlers
44-
.WithListPromptsHandler(PromptRegistry.HandlerListPromptRequestsAsync)
45-
.WithGetPromptHandler(PromptRegistry.HandlerGetPromptRequestsAsync);
41+
mimeType: "image/jpeg"));
4642

4743
await builder.Build().RunAsync();
4844

dotnet/samples/Demos/ModelContextProtocolClientServer/MCPServer/Prompts/PromptDefinition.cs

+4-4
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace MCPServer.Prompts;
1010
/// <summary>
1111
/// Represents a prompt definition.
1212
/// </summary>
13-
internal sealed class PromptDefinition
13+
public sealed class PromptDefinition
1414
{
1515
/// <summary>
1616
/// Gets or sets the prompt.
@@ -32,13 +32,13 @@ public static PromptDefinition Create(string jsonPrompt, Kernel kernel)
3232
{
3333
PromptTemplateConfig promptTemplateConfig = PromptTemplateConfig.FromJson(jsonPrompt);
3434

35+
IPromptTemplate promptTemplate = new HandlebarsPromptTemplateFactory().Create(promptTemplateConfig);
36+
3537
return new PromptDefinition()
3638
{
3739
Prompt = GetPrompt(promptTemplateConfig),
3840
Handler = (context, cancellationToken) =>
3941
{
40-
IPromptTemplate promptTemplate = new HandlebarsPromptTemplateFactory().Create(promptTemplateConfig);
41-
4242
return GetPromptHandlerAsync(context, promptTemplateConfig, promptTemplate, kernel, cancellationToken);
4343
}
4444
};
@@ -103,7 +103,7 @@ private static async Task<GetPromptResult> GetPromptHandlerAsync(RequestContext<
103103
Type = "text",
104104
Text = renderedPrompt
105105
},
106-
Role = Role.User
106+
Role = Role.Assistant
107107
}
108108
]
109109
};

dotnet/samples/Demos/ModelContextProtocolClientServer/MCPServer/Prompts/getCurrentWeatherForCity.json

+6-1
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,17 @@
22
"name": "GetCurrentWeatherForCity",
33
"description": "Provides current weather information for a specified city.",
44
"template_format": "handlebars",
5-
"template": "What is the weather in {{city}} as of {{DateTimeUtils-GetCurrentDateTimeInUtc}}?",
5+
"template": "It's {{WeatherUtils-GetWeatherForCity city time}} in {{city}} as of {{time}}",
66
"input_variables": [
77
{
88
"name": "city",
99
"description": "The city for which to get the weather.",
1010
"is_required": true
11+
},
12+
{
13+
"name": "time",
14+
"description": "The UTC time for which to get the weather.",
15+
"is_required": true
1116
}
1217
]
1318
}

0 commit comments

Comments
 (0)