Prompts
MCP prompts allow servers to expose reusable prompt templates to clients. Prompts provide a way for servers to define structured messages that can be parameterized and composed into conversations.
This document covers implementing prompts on the server, consuming them from the client, rich content types, and change notifications.
Defining prompts on the server
Prompts can be defined in several ways:
- Using the McpServerPromptAttribute attribute on methods within a class marked with McpServerPromptTypeAttribute
- Using Create factory methods from a delegate,
MethodInfo, orAIFunction - Deriving from McpServerPrompt or DelegatingMcpServerPrompt
- Implementing a custom McpRequestHandler<TParams, TResult> via McpServerHandlers
- Implementing a low-level McpRequestFilter<TParams, TResult>
The attribute-based approach is the most common and is shown throughout this document. Prompts can return ChatMessage instances for simple text/image content, or PromptMessage instances when protocol-specific content types like EmbeddedResourceBlock are needed.
Simple prompts
A prompt without arguments:
[McpServerPromptType]
public class MyPrompts
{
[McpServerPrompt, Description("A simple greeting prompt")]
public static ChatMessage Greeting()
=> new(ChatRole.User, "Hello! How can you help me today?");
}
Prompts with arguments
Prompts can accept parameters to customize the generated messages. Use [Description] attributes to document each parameter. In addition to prompt arguments, methods can accept special parameter types that are resolved automatically: McpServer, IProgress<ProgressNotificationValue>, ClaimsPrincipal, and any service registered through dependency injection.
[McpServerPromptType]
public class CodePrompts
{
[McpServerPrompt, Description("Generates a code review prompt")]
public static IEnumerable<ChatMessage> CodeReview(
[Description("The programming language")] string language,
[Description("The code to review")] string code) =>
[
new(ChatRole.User, $"Please review the following {language} code:\n\n```{language}\n{code}\n```"),
new(ChatRole.Assistant, "I'll review the code for correctness, style, and potential improvements.")
];
}
}
Register prompt types when building the server:
builder.Services.AddMcpServer()
.WithHttpTransport()
.WithPrompts<MyPrompts>()
.WithPrompts<CodePrompts>();
Rich content in prompts
Prompt messages can contain more than just text. For text and image content, use ChatMessage from Microsoft.Extensions.AI. DataContent is automatically mapped to the appropriate MCP content block: image MIME types become ImageContentBlock, audio MIME types become AudioContentBlock, and all other MIME types become EmbeddedResourceBlock with binary resource contents. For text embedded resources specifically, use PromptMessage directly.
Image content
Include images in prompts using DataContent:
[McpServerPrompt, Description("A prompt that includes an image for analysis")]
public static IEnumerable<ChatMessage> AnalyzeImage(
[Description("Instructions for the analysis")] string instructions)
{
byte[] imageBytes = LoadSampleImage();
return
[
new ChatMessage(ChatRole.User,
[
new TextContent($"Please analyze this image: {instructions}"),
new DataContent(imageBytes, "image/png")
])
];
}
Embedded resources
For protocol-specific content types like EmbeddedResourceBlock, use PromptMessage instead of ChatMessage. PromptMessage has a Role property and a single Content property of type ContentBlock:
[McpServerPrompt, Description("A prompt that includes a document resource")]
public static IEnumerable<PromptMessage> ReviewDocument(
[Description("The document ID to review")] string documentId)
{
string content = LoadDocument(documentId); // application logic to load by ID
return
[
new PromptMessage
{
Role = Role.User,
Content = new TextContentBlock { Text = "Please review the following document:" }
},
new PromptMessage
{
Role = Role.User,
Content = new EmbeddedResourceBlock
{
Resource = new TextResourceContents
{
Uri = $"docs://documents/{documentId}",
MimeType = "text/plain",
Text = content
}
}
}
];
}
For binary resources, use the FromBytes factory method:
new PromptMessage
{
Role = Role.User,
Content = new EmbeddedResourceBlock
{
Resource = BlobResourceContents.FromBytes(pdfBytes, "data://report.pdf", "application/pdf")
}
}
Consuming prompts on the client
Clients can discover and use prompts through McpClient.
Listing prompts
IList<McpClientPrompt> prompts = await client.ListPromptsAsync();
foreach (var prompt in prompts)
{
Console.WriteLine($"{prompt.Name}: {prompt.Description}");
// Show available arguments
if (prompt.ProtocolPrompt.Arguments is { Count: > 0 })
{
foreach (var arg in prompt.ProtocolPrompt.Arguments)
{
var required = arg.Required == true ? " (required)" : "";
Console.WriteLine($" - {arg.Name}: {arg.Description}{required}");
}
}
}
Getting a prompt
GetPromptResult result = await client.GetPromptAsync(
"code_review",
new Dictionary<string, object?>
{
["language"] = "csharp",
["code"] = "public static int Add(int a, int b) => a + b;"
});
// Process the returned messages (PromptMessage has a single Content block)
foreach (var message in result.Messages)
{
Console.WriteLine($"[{message.Role}]:");
switch (message.Content)
{
case TextContentBlock text:
Console.WriteLine($" {text.Text}");
break;
case ImageContentBlock image:
Console.WriteLine($" [image] {image.MimeType}");
break;
case EmbeddedResourceBlock resource:
Console.WriteLine($" Resource: {resource.Resource.Uri}");
break;
}
}
Prompt list change notifications
Servers can dynamically add, remove, or modify prompts at runtime and notify connected clients.
Sending notifications from the server
// After adding or removing prompts dynamically
await server.SendNotificationAsync(
NotificationMethods.PromptListChangedNotification,
new PromptListChangedNotificationParams());
Handling notifications on the client
mcpClient.RegisterNotificationHandler(
NotificationMethods.PromptListChangedNotification,
async (notification, cancellationToken) =>
{
var updatedPrompts = await mcpClient.ListPromptsAsync(cancellationToken: cancellationToken);
Console.WriteLine($"Prompt list updated. {updatedPrompts.Count} prompts available.");
});