From 6dec4dd48ff697479a276368351f277a39412144 Mon Sep 17 00:00:00 2001 From: Andy Tagg Date: Wed, 7 May 2025 15:01:02 +0100 Subject: [PATCH 1/4] Set IsError on CallToolResponse to true when result is ErrorContent --- src/ModelContextProtocol/Server/AIFunctionMcpServerTool.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ModelContextProtocol/Server/AIFunctionMcpServerTool.cs b/src/ModelContextProtocol/Server/AIFunctionMcpServerTool.cs index 06e0eed0c..a11fd68ee 100644 --- a/src/ModelContextProtocol/Server/AIFunctionMcpServerTool.cs +++ b/src/ModelContextProtocol/Server/AIFunctionMcpServerTool.cs @@ -253,7 +253,8 @@ public override async ValueTask InvokeAsync( { AIContent aiContent => new() { - Content = [aiContent.ToContent()] + Content = [aiContent.ToContent()], + IsError = aiContent is ErrorContent }, null => new() @@ -278,7 +279,8 @@ public override async ValueTask InvokeAsync( IEnumerable contentItems => new() { - Content = [.. contentItems.Select(static item => item.ToContent())] + Content = [.. contentItems.Select(static item => item.ToContent())], + IsError = contentItems.Any(item => item is ErrorContent) }, IEnumerable contents => new() From 803c8824afb8143476b26f07282a952ad1ebcb08 Mon Sep 17 00:00:00 2001 From: Andy Tagg Date: Thu, 8 May 2025 14:11:22 +0100 Subject: [PATCH 2/4] Updated the `IsError` determination for a list of AIContent to require that all items in `contentItems` are instances of `ErrorContent` and that the collection is not empty --- src/ModelContextProtocol/Server/AIFunctionMcpServerTool.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ModelContextProtocol/Server/AIFunctionMcpServerTool.cs b/src/ModelContextProtocol/Server/AIFunctionMcpServerTool.cs index a11fd68ee..13e3b7813 100644 --- a/src/ModelContextProtocol/Server/AIFunctionMcpServerTool.cs +++ b/src/ModelContextProtocol/Server/AIFunctionMcpServerTool.cs @@ -280,7 +280,7 @@ public override async ValueTask InvokeAsync( IEnumerable contentItems => new() { Content = [.. contentItems.Select(static item => item.ToContent())], - IsError = contentItems.Any(item => item is ErrorContent) + IsError = contentItems.All(item => item is ErrorContent) && contentItems.Any() }, IEnumerable contents => new() From 888be884b9591dab49ee5053625aa1cde57bae72 Mon Sep 17 00:00:00 2001 From: Andy Tagg Date: Thu, 8 May 2025 19:27:30 +0100 Subject: [PATCH 3/4] Introduce ConvertAiContentEnumerableToCallToolResponse to transform an IEnumerable into a CallToolResponse --- .../Server/AIFunctionMcpServerTool.cs | 30 +++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/src/ModelContextProtocol/Server/AIFunctionMcpServerTool.cs b/src/ModelContextProtocol/Server/AIFunctionMcpServerTool.cs index 13e3b7813..0e9d32e5f 100644 --- a/src/ModelContextProtocol/Server/AIFunctionMcpServerTool.cs +++ b/src/ModelContextProtocol/Server/AIFunctionMcpServerTool.cs @@ -193,6 +193,30 @@ options.OpenWorld is not null || return newOptions; } + private static CallToolResponse ConvertAiContentEnumerableToCallToolResponse(IEnumerable contentItems) + { + List contentList = []; + bool allErrorContent = true; + bool hasAny = false; + + foreach (var item in contentItems) + { + contentList.Add(item.ToContent()); + hasAny = true; + + if (allErrorContent && item is not ErrorContent) + { + allErrorContent = false; + } + } + + return new() + { + Content = contentList, + IsError = allErrorContent && hasAny + }; + } + /// Gets the wrapped by this tool. internal AIFunction AIFunction { get; } @@ -277,11 +301,7 @@ public override async ValueTask InvokeAsync( Content = [.. texts.Select(x => new Content() { Type = "text", Text = x ?? string.Empty })] }, - IEnumerable contentItems => new() - { - Content = [.. contentItems.Select(static item => item.ToContent())], - IsError = contentItems.All(item => item is ErrorContent) && contentItems.Any() - }, + IEnumerable contentItems => ConvertAiContentEnumerableToCallToolResponse(contentItems), IEnumerable contents => new() { From 56c442ce38c56a73791ad07b5cb08a48ae65d923 Mon Sep 17 00:00:00 2001 From: Andy Tagg Date: Thu, 8 May 2025 20:39:29 +0100 Subject: [PATCH 4/4] Move location of ConvertAIContentEnumerableToCallToolResponse helper function --- .../Server/AIFunctionMcpServerTool.cs | 49 +++++++++---------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/src/ModelContextProtocol/Server/AIFunctionMcpServerTool.cs b/src/ModelContextProtocol/Server/AIFunctionMcpServerTool.cs index 0e9d32e5f..8d31f01b1 100644 --- a/src/ModelContextProtocol/Server/AIFunctionMcpServerTool.cs +++ b/src/ModelContextProtocol/Server/AIFunctionMcpServerTool.cs @@ -193,30 +193,6 @@ options.OpenWorld is not null || return newOptions; } - private static CallToolResponse ConvertAiContentEnumerableToCallToolResponse(IEnumerable contentItems) - { - List contentList = []; - bool allErrorContent = true; - bool hasAny = false; - - foreach (var item in contentItems) - { - contentList.Add(item.ToContent()); - hasAny = true; - - if (allErrorContent && item is not ErrorContent) - { - allErrorContent = false; - } - } - - return new() - { - Content = contentList, - IsError = allErrorContent && hasAny - }; - } - /// Gets the wrapped by this tool. internal AIFunction AIFunction { get; } @@ -301,7 +277,7 @@ public override async ValueTask InvokeAsync( Content = [.. texts.Select(x => new Content() { Type = "text", Text = x ?? string.Empty })] }, - IEnumerable contentItems => ConvertAiContentEnumerableToCallToolResponse(contentItems), + IEnumerable contentItems => ConvertAIContentEnumerableToCallToolResponse(contentItems), IEnumerable contents => new() { @@ -321,4 +297,27 @@ public override async ValueTask InvokeAsync( }; } + private static CallToolResponse ConvertAIContentEnumerableToCallToolResponse(IEnumerable contentItems) + { + List contentList = []; + bool allErrorContent = true; + bool hasAny = false; + + foreach (var item in contentItems) + { + contentList.Add(item.ToContent()); + hasAny = true; + + if (allErrorContent && item is not ErrorContent) + { + allErrorContent = false; + } + } + + return new() + { + Content = contentList, + IsError = allErrorContent && hasAny + }; + } } \ No newline at end of file