88namespace ModelContextProtocol ;
99
1010/// <summary>
11- /// Provides extension methods for converting between Model Context Protocol (MCP) types and Microsoft AI client/server API types.
11+ /// Provides extension methods for converting between Model Context Protocol (MCP) types and Microsoft.Extensions.AI types.
1212/// </summary>
1313/// <remarks>
14- /// This class serves as a critical adapter layer between Model Context Protocol (MCP) types and the AIContent model types
15- /// from the Microsoft.Extensions.AI namespace. It enables seamless bidirectional conversion between:
16- /// <list type="bullet">
17- /// <item><description><see cref="PromptMessage"/> and <see cref="ChatMessage"/></description></item>
18- /// <item><description><see cref="GetPromptResult"/> and collections of <see cref="ChatMessage"/></description></item>
19- /// <item><description><see cref="Content"/> and <see cref="AIContent"/></description></item>
20- /// <item><description><see cref="ResourceContents"/> and <see cref="AIContent"/></description></item>
21- /// </list>
22- ///
23- /// These conversions are essential in scenarios such as:
24- /// <list type="bullet">
25- /// <item><description>Integrating MCP clients with AI client applications</description></item>
26- /// <item><description>Processing AI content between protocol-specific and application-specific formats</description></item>
27- /// <item><description>Building adapters between MCP systems and other AI frameworks</description></item>
28- /// <item><description>Converting between wire formats and client API representations</description></item>
29- /// </list>
30- ///
31- /// When working with the MCP infrastructure, these extensions allow developers to easily transform data
32- /// received from MCP endpoints into formats that can be directly used with AI client libraries, and vice versa.
14+ /// This class serves as an adapter layer between Model Context Protocol (MCP) types and the <see cref="AIContent"/> model types
15+ /// from the Microsoft.Extensions.AI namespace.
3316/// </remarks>
3417public static class AIContentExtensions
3518{
@@ -39,40 +22,9 @@ public static class AIContentExtensions
3922 /// <param name="promptMessage">The prompt message to convert.</param>
4023 /// <returns>A <see cref="ChatMessage"/> object created from the prompt message.</returns>
4124 /// <remarks>
42- /// <para>
4325 /// This method transforms a protocol-specific <see cref="PromptMessage"/> from the Model Context Protocol
4426 /// into a standard <see cref="ChatMessage"/> object that can be used with AI client libraries.
45- /// </para>
46- /// <para>
47- /// The role mapping is preserved in the conversion:
48- /// <list type="bullet">
49- /// <item><description><see cref="Role.User"/> → <see cref="ChatRole.User"/></description></item>
50- /// <item><description><see cref="Role.Assistant"/> → <see cref="ChatRole.Assistant"/></description></item>
51- /// </list>
52- /// </para>
53- /// <para>
54- /// The original <see cref="PromptMessage"/> object is stored in the <see cref="AIContent.RawRepresentation"/>
55- /// property, enabling round-trip conversions if needed.
56- /// </para>
5727 /// </remarks>
58- /// <example>
59- /// <code>
60- /// // Get a prompt message from an MCP source
61- /// PromptMessage promptMessage = new PromptMessage
62- /// {
63- /// Role = Role.User,
64- /// Content = new Content { Text = "Hello, AI!", Type = "text" }
65- /// };
66- ///
67- /// // Convert to ChatMessage for use with AI clients
68- /// ChatMessage chatMessage = promptMessage.ToChatMessage();
69- ///
70- /// // Use the chat message with Microsoft.Extensions.AI
71- /// Console.WriteLine($"{chatMessage.Role}: {chatMessage.Contents.FirstOrDefault()?.ToString()}");
72- /// </code>
73- /// </example>
74- /// <seealso cref="ToChatMessages(GetPromptResult)"/>
75- /// <seealso cref="ToPromptMessages(ChatMessage)"/>
7628 public static ChatMessage ToChatMessage ( this PromptMessage promptMessage )
7729 {
7830 Throw . IfNull ( promptMessage ) ;
@@ -93,23 +45,7 @@ public static ChatMessage ToChatMessage(this PromptMessage promptMessage)
9345 /// <remarks>
9446 /// This method transforms protocol-specific <see cref="PromptMessage"/> objects from a Model Context Protocol
9547 /// prompt result into standard <see cref="ChatMessage"/> objects that can be used with AI client libraries.
96- /// Each message's role is preserved in the conversion.
9748 /// </remarks>
98- /// <example>
99- /// <code>
100- /// // Get prompt result from an MCP client
101- /// var result = await mcpClient.GetPromptAsync("SomePromptName");
102- ///
103- /// // Convert to ChatMessages for use with AI clients
104- /// var chatMessages = result.ToChatMessages();
105- ///
106- /// // Use the chat messages
107- /// foreach (var message in chatMessages)
108- /// {
109- /// Console.WriteLine($"{message.Role}: {message.Text}");
110- /// }
111- /// </code>
112- /// </example>
11349 public static IList < ChatMessage > ToChatMessages ( this GetPromptResult promptResult )
11450 {
11551 Throw . IfNull ( promptResult ) ;
@@ -125,28 +61,8 @@ public static IList<ChatMessage> ToChatMessages(this GetPromptResult promptResul
12561 /// <remarks>
12662 /// This method transforms standard <see cref="ChatMessage"/> objects used with AI client libraries into
12763 /// protocol-specific <see cref="PromptMessage"/> objects for the Model Context Protocol system.
128- /// The role is preserved in the conversion (User → User, Assistant → Assistant).
129- /// Only content items of type <see cref="TextContent"/> or <see cref="DataContent"/> are processed.
64+ /// Only representable content items are processed.
13065 /// </remarks>
131- /// <example>
132- /// <code>
133- /// // Create a chat message
134- /// var chatMessage = new ChatMessage
135- /// {
136- /// Role = ChatRole.User,
137- /// Contents = [new TextContent("Hello, how can you help me today?")]
138- /// };
139- ///
140- /// // Convert to PromptMessages for use with MCP
141- /// var promptMessages = chatMessage.ToPromptMessages();
142- ///
143- /// // Use the prompt messages with MCP protocol
144- /// var getPromptResult = new GetPromptResult
145- /// {
146- /// Messages = promptMessages
147- /// };
148- /// </code>
149- /// </example>
15066 public static IList < PromptMessage > ToPromptMessages ( this ChatMessage chatMessage )
15167 {
15268 Throw . IfNull ( chatMessage ) ;
@@ -169,58 +85,9 @@ public static IList<PromptMessage> ToPromptMessages(this ChatMessage chatMessage
16985 /// <param name="content">The <see cref="Content"/> to convert.</param>
17086 /// <returns>The created <see cref="AIContent"/>.</returns>
17187 /// <remarks>
172- /// <para>
17388 /// This method converts Model Context Protocol content types to the equivalent Microsoft.Extensions.AI
17489 /// content types, enabling seamless integration between the protocol and AI client libraries.
175- /// </para>
176- /// <para>
177- /// The conversion follows these rules:
178- /// <list type="bullet">
179- /// <item><description>When <see cref="Content.Type"/> is "image" or "audio" with data → <see cref="DataContent"/> with base64-decoded data and preserved MIME type</description></item>
180- /// <item><description>When <see cref="Content.Resource"/> is not null → Uses <see cref="ToAIContent(ResourceContents)"/> for the resource</description></item>
181- /// <item><description>Otherwise → <see cref="TextContent"/> using the text content</description></item>
182- /// </list>
183- /// </para>
184- /// <para>
185- /// The original <see cref="Content"/> object is stored in the <see cref="AIContent.RawRepresentation"/>
186- /// property, enabling round-trip conversions if needed.
187- /// </para>
18890 /// </remarks>
189- /// <example>
190- /// <code>
191- /// // Convert a Content with text to AIContent
192- /// var textContent = new Content
193- /// {
194- /// Text = "Hello, world!",
195- /// Type = "text"
196- /// };
197- /// AIContent aiContent = textContent.ToAIContent();
198- ///
199- /// // Convert a Content with image data to AIContent
200- /// var imageContent = new Content
201- /// {
202- /// Type = "image",
203- /// MimeType = "image/png",
204- /// Data = Convert.ToBase64String(imageBytes)
205- /// };
206- /// AIContent aiImageContent = imageContent.ToAIContent();
207- ///
208- /// // Convert a Content with a resource to AIContent
209- /// var resourceContent = new Content
210- /// {
211- /// Type = "resource",
212- /// Resource = new TextResourceContents
213- /// {
214- /// Uri = "resource://document.txt",
215- /// Text = "This is a resource text"
216- /// }
217- /// };
218- /// AIContent aiResourceContent = resourceContent.ToAIContent();
219- /// </code>
220- /// </example>
221- /// <seealso cref="ToAIContent(ResourceContents)"/>
222- /// <seealso cref="DataContent"/>
223- /// <seealso cref="TextContent"/>
22491 public static AIContent ToAIContent ( this Content content )
22592 {
22693 Throw . IfNull ( content ) ;
@@ -248,64 +115,9 @@ public static AIContent ToAIContent(this Content content)
248115 /// <param name="content">The <see cref="ResourceContents"/> to convert.</param>
249116 /// <returns>The created <see cref="AIContent"/>.</returns>
250117 /// <remarks>
251- /// <para>
252118 /// This method converts Model Context Protocol resource types to the equivalent Microsoft.Extensions.AI
253119 /// content types, enabling seamless integration between the protocol and AI client libraries.
254- /// </para>
255- /// <para>
256- /// The conversion follows these rules:
257- /// <list type="bullet">
258- /// <item><description><see cref="BlobResourceContents"/> → <see cref="DataContent"/> with base64-decoded data and preserved MIME type</description></item>
259- /// <item><description><see cref="TextResourceContents"/> → <see cref="TextContent"/> with the text preserved</description></item>
260- /// </list>
261- /// </para>
262- /// <para>
263- /// The URI of the resource is preserved in the <see cref="AIContent.AdditionalProperties"/> dictionary
264- /// with the key "uri", allowing applications to maintain resource identifiers.
265- /// </para>
266- /// <para>
267- /// The original <see cref="ResourceContents"/> object is stored in the <see cref="AIContent.RawRepresentation"/>
268- /// property, enabling round-trip conversions if needed.
269- /// </para>
270120 /// </remarks>
271- /// <example>
272- /// <code>
273- /// // Convert a TextResourceContents to AIContent
274- /// var textResource = new TextResourceContents
275- /// {
276- /// Uri = "resource://document.txt",
277- /// MimeType = "text/plain",
278- /// Text = "This is a text resource"
279- /// };
280- /// AIContent textContent = textResource.ToAIContent();
281- ///
282- /// // Use the converted content with Microsoft.Extensions.AI client
283- /// await aiClient.GenerateTextAsync(new TextGenerationOptions
284- /// {
285- /// Messages = [
286- /// new ChatMessage
287- /// {
288- /// Role = ChatRole.User,
289- /// Contents = [textContent]
290- /// }
291- /// ]
292- /// });
293- ///
294- /// // Convert a BlobResourceContents to AIContent
295- /// var blobResource = new BlobResourceContents
296- /// {
297- /// Uri = "resource://image.png",
298- /// MimeType = "image/png",
299- /// Blob = Convert.ToBase64String(imageBytes)
300- /// };
301- /// AIContent imageContent = blobResource.ToAIContent();
302- /// </code>
303- /// </example>
304- /// <exception cref="NotSupportedException">Thrown when the resource type is not supported.</exception>
305- /// <seealso cref="BlobResourceContents"/>
306- /// <seealso cref="TextResourceContents"/>
307- /// <seealso cref="DataContent"/>
308- /// <seealso cref="TextContent"/>
309121 public static AIContent ToAIContent ( this ResourceContents content )
310122 {
311123 Throw . IfNull ( content ) ;
@@ -337,29 +149,6 @@ public static AIContent ToAIContent(this ResourceContents content)
337149 /// preserving the type-specific conversion logic for text, images, audio, and resources.
338150 /// </para>
339151 /// </remarks>
340- /// <example>
341- /// <code>
342- /// // Get Content objects from a source
343- /// IEnumerable<Content> contents = someResponse.Contents;
344- ///
345- /// // Convert all Content objects to AIContent objects
346- /// IList<AIContent> aiContents = contents.ToAIContents();
347- ///
348- /// // Use the converted contents
349- /// foreach (var content in aiContents)
350- /// {
351- /// if (content is TextContent textContent)
352- /// {
353- /// Console.WriteLine($"Text content: {textContent.Text}");
354- /// }
355- /// else if (content is DataContent dataContent)
356- /// {
357- /// Console.WriteLine($"Binary content: {dataContent.MediaType}, {dataContent.Data.Length} bytes");
358- /// }
359- /// }
360- /// </code>
361- /// </example>
362- /// <seealso cref="ToAIContent(Content)"/>
363152 public static IList < AIContent > ToAIContents ( this IEnumerable < Content > contents )
364153 {
365154 Throw . IfNull ( contents ) ;
@@ -382,30 +171,6 @@ public static IList<AIContent> ToAIContents(this IEnumerable<Content> contents)
382171 /// binary resources become <see cref="DataContent"/> objects.
383172 /// </para>
384173 /// </remarks>
385- /// <example>
386- /// <code>
387- /// // Get resources from a read resource result
388- /// ReadResourceResult result = await client.ReadResourceAsync("resource://folder");
389- ///
390- /// // Convert all resources to AIContent objects
391- /// IList<AIContent> aiContents = result.Contents.ToAIContents();
392- ///
393- /// // Use the converted contents
394- /// foreach (var content in aiContents)
395- /// {
396- /// if (content is TextContent textContent)
397- /// {
398- /// Console.WriteLine($"Text content: {textContent.Text}");
399- /// }
400- /// else if (content is DataContent dataContent)
401- /// {
402- /// Console.WriteLine($"Binary content: {dataContent.MediaType}, {dataContent.Data.Length} bytes");
403- /// }
404- /// }
405- /// </code>
406- /// </example>
407- /// <seealso cref="ToAIContent(ResourceContents)"/>
408- /// <seealso cref="ReadResourceResult.Contents"/>
409174 public static IList < AIContent > ToAIContents ( this IEnumerable < ResourceContents > contents )
410175 {
411176 Throw . IfNull ( contents ) ;
0 commit comments