diff --git a/src/ModelContextProtocol.Core/Protocol/BlobResourceContents.cs b/src/ModelContextProtocol.Core/Protocol/BlobResourceContents.cs
index dc56dac..904e71b 100644
--- a/src/ModelContextProtocol.Core/Protocol/BlobResourceContents.cs
+++ b/src/ModelContextProtocol.Core/Protocol/BlobResourceContents.cs
@@ -1,3 +1,4 @@
+using System.Diagnostics;
using System.Text.Json.Serialization;
namespace ModelContextProtocol.Protocol;
@@ -20,6 +21,7 @@ namespace ModelContextProtocol.Protocol;
/// See the schema for more details.
///
///
+[DebuggerDisplay("{DebuggerDisplay,nq}")]
public sealed class BlobResourceContents : ResourceContents
{
///
@@ -27,4 +29,15 @@ public sealed class BlobResourceContents : ResourceContents
///
[JsonPropertyName("blob")]
public required string Blob { get; set; }
+
+ [DebuggerBrowsable(DebuggerBrowsableState.Never)]
+ private string DebuggerDisplay
+ {
+ get
+ {
+ string lengthDisplay = DebuggerDisplayHelper.GetBase64LengthDisplay(Blob);
+ string mimeInfo = MimeType is not null ? $", MimeType = {MimeType}" : "";
+ return $"Uri = \"{Uri}\"{mimeInfo}, Length = {lengthDisplay}";
+ }
+ }
}
diff --git a/src/ModelContextProtocol.Core/Protocol/ContentBlock.cs b/src/ModelContextProtocol.Core/Protocol/ContentBlock.cs
index 526e5ad..04c98bc 100644
--- a/src/ModelContextProtocol.Core/Protocol/ContentBlock.cs
+++ b/src/ModelContextProtocol.Core/Protocol/ContentBlock.cs
@@ -356,6 +356,7 @@ public abstract class ContentBlock
}
/// Represents text provided to or from an LLM.
+[DebuggerDisplay("Text = \"{Text}\"")]
public sealed class TextContentBlock : ContentBlock
{
///
@@ -366,9 +367,13 @@ public sealed class TextContentBlock : ContentBlock
///
[JsonPropertyName("text")]
public required string Text { get; set; }
+
+ ///
+ public override string ToString() => Text ?? "";
}
/// Represents an image provided to or from an LLM.
+[DebuggerDisplay("{DebuggerDisplay,nq}")]
public sealed class ImageContentBlock : ContentBlock
{
///
@@ -388,9 +393,13 @@ public sealed class ImageContentBlock : ContentBlock
///
[JsonPropertyName("mimeType")]
public required string MimeType { get; set; }
+
+ [DebuggerBrowsable(DebuggerBrowsableState.Never)]
+ private string DebuggerDisplay => $"MimeType = {MimeType}, Length = {DebuggerDisplayHelper.GetBase64LengthDisplay(Data)}";
}
/// Represents audio provided to or from an LLM.
+[DebuggerDisplay("{DebuggerDisplay,nq}")]
public sealed class AudioContentBlock : ContentBlock
{
///
@@ -410,12 +419,16 @@ public sealed class AudioContentBlock : ContentBlock
///
[JsonPropertyName("mimeType")]
public required string MimeType { get; set; }
+
+ [DebuggerBrowsable(DebuggerBrowsableState.Never)]
+ private string DebuggerDisplay => $"MimeType = {MimeType}, Length = {DebuggerDisplayHelper.GetBase64LengthDisplay(Data)}";
}
/// Represents the contents of a resource, embedded into a prompt or tool call result.
///
/// It is up to the client how best to render embedded resources for the benefit of the LLM and/or the user.
///
+[DebuggerDisplay("{DebuggerDisplay,nq}")]
public sealed class EmbeddedResourceBlock : ContentBlock
{
///
@@ -433,12 +446,16 @@ public sealed class EmbeddedResourceBlock : ContentBlock
///
[JsonPropertyName("resource")]
public required ResourceContents Resource { get; set; }
+
+ [DebuggerBrowsable(DebuggerBrowsableState.Never)]
+ private string DebuggerDisplay => $"Uri = \"{Resource.Uri}\"";
}
/// Represents a resource that the server is capable of reading, included in a prompt or tool call result.
///
/// Resource links returned by tools are not guaranteed to appear in the results of `resources/list` requests.
///
+[DebuggerDisplay("Name = {Name}, Uri = \"{Uri}\"")]
public sealed class ResourceLinkBlock : ContentBlock
{
///
@@ -503,6 +520,7 @@ public sealed class ResourceLinkBlock : ContentBlock
}
/// Represents a request from the assistant to call a tool.
+[DebuggerDisplay("Name = {Name}, Id = {Id}")]
public sealed class ToolUseContentBlock : ContentBlock
{
///
@@ -531,6 +549,7 @@ public sealed class ToolUseContentBlock : ContentBlock
}
/// Represents the result of a tool use, provided by the user back to the assistant.
+[DebuggerDisplay("{DebuggerDisplay,nq}")]
public sealed class ToolResultContentBlock : ContentBlock
{
///
@@ -575,4 +594,37 @@ public sealed class ToolResultContentBlock : ContentBlock
///
[JsonPropertyName("isError")]
public bool? IsError { get; set; }
+
+ [DebuggerBrowsable(DebuggerBrowsableState.Never)]
+ private string DebuggerDisplay
+ {
+ get
+ {
+ if (IsError == true)
+ {
+ return $"ToolUseId = {ToolUseId}, IsError = true";
+ }
+
+ // Try to show the result content
+ if (Content.Count == 1 && Content[0] is TextContentBlock textBlock)
+ {
+ return $"ToolUseId = {ToolUseId}, Result = \"{textBlock.Text}\"";
+ }
+
+ if (StructuredContent.HasValue)
+ {
+ try
+ {
+ string json = StructuredContent.Value.GetRawText();
+ return $"ToolUseId = {ToolUseId}, Result = {json}";
+ }
+ catch
+ {
+ // Fall back to content count if GetRawText fails
+ }
+ }
+
+ return $"ToolUseId = {ToolUseId}, ContentCount = {Content.Count}";
+ }
+ }
}
diff --git a/src/ModelContextProtocol.Core/Protocol/DebuggerDisplayHelper.cs b/src/ModelContextProtocol.Core/Protocol/DebuggerDisplayHelper.cs
new file mode 100644
index 0000000..77f7193
--- /dev/null
+++ b/src/ModelContextProtocol.Core/Protocol/DebuggerDisplayHelper.cs
@@ -0,0 +1,30 @@
+using System;
+
+namespace ModelContextProtocol.Protocol;
+
+///
+/// Internal helper methods for DebuggerDisplay implementations.
+///
+internal static class DebuggerDisplayHelper
+{
+ ///
+ /// Gets the decoded length of base64 data for debugger display.
+ ///
+ internal static string GetBase64LengthDisplay(string base64Data)
+ {
+#if NET
+ if (System.Buffers.Text.Base64.IsValid(base64Data, out int decodedLength))
+ {
+ return $"{decodedLength} bytes";
+ }
+#else
+ try
+ {
+ return $"{Convert.FromBase64String(base64Data).Length} bytes";
+ }
+ catch { }
+#endif
+
+ return "invalid base64";
+ }
+}
diff --git a/src/ModelContextProtocol.Core/Protocol/Icon.cs b/src/ModelContextProtocol.Core/Protocol/Icon.cs
index a04c6af..0ae9add 100644
--- a/src/ModelContextProtocol.Core/Protocol/Icon.cs
+++ b/src/ModelContextProtocol.Core/Protocol/Icon.cs
@@ -1,3 +1,4 @@
+using System.Diagnostics;
using System.Text.Json.Serialization;
namespace ModelContextProtocol.Protocol;
@@ -28,6 +29,7 @@ namespace ModelContextProtocol.Protocol;
/// See the schema for details.
///
///
+[DebuggerDisplay("{DebuggerDisplay,nq}")]
public sealed class Icon
{
///
@@ -82,4 +84,14 @@ public sealed class Icon
///
[JsonPropertyName("theme")]
public string? Theme { get; set; }
+
+ [DebuggerBrowsable(DebuggerBrowsableState.Never)]
+ private string DebuggerDisplay
+ {
+ get
+ {
+ string mimeInfo = MimeType is not null ? $", MimeType = {MimeType}" : "";
+ return $"Source = \"{Source}\"{mimeInfo}";
+ }
+ }
}
diff --git a/src/ModelContextProtocol.Core/Protocol/Prompt.cs b/src/ModelContextProtocol.Core/Protocol/Prompt.cs
index 43b2bd2..9f5534a 100644
--- a/src/ModelContextProtocol.Core/Protocol/Prompt.cs
+++ b/src/ModelContextProtocol.Core/Protocol/Prompt.cs
@@ -1,3 +1,4 @@
+using System.Diagnostics;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
using ModelContextProtocol.Server;
@@ -10,6 +11,7 @@ namespace ModelContextProtocol.Protocol;
///
/// See the schema for details.
///
+[DebuggerDisplay("{DebuggerDisplay,nq}")]
public sealed class Prompt : IBaseMetadata
{
///
@@ -75,4 +77,14 @@ public sealed class Prompt : IBaseMetadata
///
[JsonIgnore]
public McpServerPrompt? McpServerPrompt { get; set; }
+
+ [DebuggerBrowsable(DebuggerBrowsableState.Never)]
+ private string DebuggerDisplay
+ {
+ get
+ {
+ string desc = Description is not null ? $", Description = \"{Description}\"" : "";
+ return $"Name = {Name}{desc}";
+ }
+ }
}
diff --git a/src/ModelContextProtocol.Core/Protocol/PromptMessage.cs b/src/ModelContextProtocol.Core/Protocol/PromptMessage.cs
index ca462c3..76dede3 100644
--- a/src/ModelContextProtocol.Core/Protocol/PromptMessage.cs
+++ b/src/ModelContextProtocol.Core/Protocol/PromptMessage.cs
@@ -1,3 +1,4 @@
+using System.Diagnostics;
using Microsoft.Extensions.AI;
using System.Text.Json.Serialization;
@@ -26,6 +27,7 @@ namespace ModelContextProtocol.Protocol;
/// See the schema for details.
///
///
+[DebuggerDisplay("{DebuggerDisplay,nq}")]
public sealed class PromptMessage
{
///
@@ -49,4 +51,19 @@ public sealed class PromptMessage
///
[JsonPropertyName("role")]
public required Role Role { get; set; }
+
+ [DebuggerBrowsable(DebuggerBrowsableState.Never)]
+ private string DebuggerDisplay
+ {
+ get
+ {
+ // Show actual text content if it's a TextContentBlock
+ if (Content is TextContentBlock textBlock)
+ {
+ return $"Role = {Role}, Text = \"{textBlock.Text}\"";
+ }
+
+ return $"Role = {Role}, ContentType = {Content.Type}";
+ }
+ }
}
diff --git a/src/ModelContextProtocol.Core/Protocol/Resource.cs b/src/ModelContextProtocol.Core/Protocol/Resource.cs
index 6c0eb91..be2a4aa 100644
--- a/src/ModelContextProtocol.Core/Protocol/Resource.cs
+++ b/src/ModelContextProtocol.Core/Protocol/Resource.cs
@@ -1,3 +1,4 @@
+using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
@@ -11,6 +12,7 @@ namespace ModelContextProtocol.Protocol;
///
/// See the schema for details.
///
+[DebuggerDisplay("Name = {Name}, Uri = {Uri}")]
public sealed class Resource : IBaseMetadata
{
///
diff --git a/src/ModelContextProtocol.Core/Protocol/SamplingMessage.cs b/src/ModelContextProtocol.Core/Protocol/SamplingMessage.cs
index 093824e..d929a68 100644
--- a/src/ModelContextProtocol.Core/Protocol/SamplingMessage.cs
+++ b/src/ModelContextProtocol.Core/Protocol/SamplingMessage.cs
@@ -1,3 +1,4 @@
+using System.Diagnostics;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
@@ -26,6 +27,7 @@ namespace ModelContextProtocol.Protocol;
/// See the schema for details.
///
///
+[DebuggerDisplay("{DebuggerDisplay,nq}")]
public sealed class SamplingMessage
{
///
@@ -49,4 +51,22 @@ public sealed class SamplingMessage
///
[JsonPropertyName("_meta")]
public JsonObject? Meta { get; set; }
+
+ [DebuggerBrowsable(DebuggerBrowsableState.Never)]
+ private string DebuggerDisplay
+ {
+ get
+ {
+ // Show actual text content if it's a single TextContentBlock
+ if (Content.Count == 1 && Content[0] is TextContentBlock textBlock)
+ {
+ return $"Role = {Role}, Text = \"{textBlock.Text}\"";
+ }
+
+ string contentTypes = Content.Count == 1
+ ? Content[0].Type
+ : $"{Content.Count} items";
+ return $"Role = {Role}, Content = {contentTypes}";
+ }
+ }
}
diff --git a/src/ModelContextProtocol.Core/Protocol/TextResourceContents.cs b/src/ModelContextProtocol.Core/Protocol/TextResourceContents.cs
index 9f8a9b8..99c8593 100644
--- a/src/ModelContextProtocol.Core/Protocol/TextResourceContents.cs
+++ b/src/ModelContextProtocol.Core/Protocol/TextResourceContents.cs
@@ -1,3 +1,4 @@
+using System.Diagnostics;
using System.Text.Json.Serialization;
namespace ModelContextProtocol.Protocol;
@@ -19,6 +20,7 @@ namespace ModelContextProtocol.Protocol;
/// See the schema for more details.
///
///
+[DebuggerDisplay("Uri = \"{Uri}\", Text = \"{Text}\"")]
public sealed class TextResourceContents : ResourceContents
{
///
@@ -26,4 +28,7 @@ public sealed class TextResourceContents : ResourceContents
///
[JsonPropertyName("text")]
public required string Text { get; set; }
+
+ ///
+ public override string ToString() => Text ?? "";
}
diff --git a/src/ModelContextProtocol.Core/Protocol/Tool.cs b/src/ModelContextProtocol.Core/Protocol/Tool.cs
index 9365a85..30b1242 100644
--- a/src/ModelContextProtocol.Core/Protocol/Tool.cs
+++ b/src/ModelContextProtocol.Core/Protocol/Tool.cs
@@ -1,3 +1,4 @@
+using System.Diagnostics;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
@@ -8,6 +9,7 @@ namespace ModelContextProtocol.Protocol;
///
/// Represents a tool that the server is capable of calling.
///
+[DebuggerDisplay("{DebuggerDisplay,nq}")]
public sealed class Tool : IBaseMetadata
{
///
@@ -130,4 +132,14 @@ public sealed class Tool : IBaseMetadata
///
[JsonIgnore]
public McpServerTool? McpServerTool { get; set; }
+
+ [DebuggerBrowsable(DebuggerBrowsableState.Never)]
+ private string DebuggerDisplay
+ {
+ get
+ {
+ string desc = Description is not null ? $", Description = \"{Description}\"" : "";
+ return $"Name = {Name}{desc}";
+ }
+ }
}