Skip to content

Commit ca83310

Browse files
committed
Update MCP support to accomodate responses and approvals
1 parent cb29987 commit ca83310

17 files changed

+1034
-325
lines changed

src/Libraries/Microsoft.Extensions.AI.Abstractions/Contents/AIContent.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@ namespace Microsoft.Extensions.AI;
1414
[JsonDerivedType(typeof(FunctionResultContent), typeDiscriminator: "functionResult")]
1515
[JsonDerivedType(typeof(HostedFileContent), typeDiscriminator: "hostedFile")]
1616
[JsonDerivedType(typeof(HostedVectorStoreContent), typeDiscriminator: "hostedVectorStore")]
17-
[JsonDerivedType(typeof(McpServerToolCallContent), typeDiscriminator: "mcpServerToolCall")]
18-
[JsonDerivedType(typeof(McpServerToolResultContent), typeDiscriminator: "mcpServerToolResult")]
1917
[JsonDerivedType(typeof(TextContent), typeDiscriminator: "text")]
2018
[JsonDerivedType(typeof(TextReasoningContent), typeDiscriminator: "reasoning")]
2119
[JsonDerivedType(typeof(UriContent), typeDiscriminator: "uri")]
@@ -26,6 +24,10 @@ namespace Microsoft.Extensions.AI;
2624
// experimental types in its source generated files.
2725
// [JsonDerivedType(typeof(FunctionApprovalRequestContent), typeDiscriminator: "functionApprovalRequest")]
2826
// [JsonDerivedType(typeof(FunctionApprovalResponseContent), typeDiscriminator: "functionApprovalResponse")]
27+
// [JsonDerivedType(typeof(McpServerToolCallContent), typeDiscriminator: "mcpServerToolCall")]
28+
// [JsonDerivedType(typeof(McpServerToolResultContent), typeDiscriminator: "mcpServerToolResult")]
29+
// [JsonDerivedType(typeof(McpServerToolApprovalRequestContent), typeDiscriminator: "mcpServerToolApprovalRequest")]
30+
// [JsonDerivedType(typeof(McpServerToolApprovalResponseContent), typeDiscriminator: "mcpServerToolApprovalResponse")]
2931

3032
public class AIContent
3133
{
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.Diagnostics.CodeAnalysis;
6+
using Microsoft.Shared.Diagnostics;
7+
8+
namespace Microsoft.Extensions.AI;
9+
10+
/// <summary>
11+
/// Represents a request for user approval of an MCP server tool call.
12+
/// </summary>
13+
[Experimental("MEAI001")]
14+
public sealed class McpServerToolApprovalRequestContent : UserInputRequestContent
15+
{
16+
/// <summary>
17+
/// Initializes a new instance of the <see cref="McpServerToolApprovalRequestContent"/> class.
18+
/// </summary>
19+
/// <param name="id">The ID that uniquely identifies the MCP server tool approval request/response pair.</param>
20+
/// <param name="toolCall">The tool call that requires user approval.</param>
21+
/// <exception cref="ArgumentNullException"><paramref name="id"/> is <see langword="null"/>.</exception>
22+
/// <exception cref="ArgumentException"><paramref name="id"/> is empty or composed entirely of whitespace.</exception>
23+
/// <exception cref="ArgumentNullException"><paramref name="toolCall"/> is <see langword="null"/>.</exception>
24+
public McpServerToolApprovalRequestContent(string id, McpServerToolCallContent toolCall)
25+
: base(id)
26+
{
27+
ToolCall = Throw.IfNull(toolCall);
28+
}
29+
30+
/// <summary>
31+
/// Gets the tool call that pre-invoke approval is required for.
32+
/// </summary>
33+
public McpServerToolCallContent ToolCall { get; }
34+
35+
/// <summary>
36+
/// Creates a <see cref="McpServerToolApprovalResponseContent"/> to indicate whether the function call is approved or rejected based on the value of <paramref name="approved"/>.
37+
/// </summary>
38+
/// <param name="approved"><see langword="true"/> if the function call is approved; otherwise, <see langword="false"/>.</param>
39+
/// <returns>The <see cref="FunctionApprovalResponseContent"/> representing the approval response.</returns>
40+
public McpServerToolApprovalResponseContent CreateResponse(bool approved) => new(Id, approved);
41+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.Diagnostics.CodeAnalysis;
6+
7+
namespace Microsoft.Extensions.AI;
8+
9+
/// <summary>
10+
/// Represents a response to an MCP server tool approval request.
11+
/// </summary>
12+
[Experimental("MEAI001")]
13+
public sealed class McpServerToolApprovalResponseContent : UserInputResponseContent
14+
{
15+
/// <summary>
16+
/// Initializes a new instance of the <see cref="McpServerToolApprovalResponseContent"/> class.
17+
/// </summary>
18+
/// <param name="id">The ID that uniquely identifies the MCP server tool approval request/response pair.</param>
19+
/// <param name="approved"><see langword="true"/> if the MCP server tool call is approved; otherwise, <see langword="false"/>.</param>
20+
/// <exception cref="ArgumentNullException"><paramref name="id"/> is <see langword="null"/>.</exception>
21+
/// <exception cref="ArgumentException"><paramref name="id"/> is empty or composed entirely of whitespace.</exception>
22+
public McpServerToolApprovalResponseContent(string id, bool approved)
23+
: base(id)
24+
{
25+
Approved = approved;
26+
}
27+
28+
/// <summary>
29+
/// Gets a value indicating whether the user approved the request.
30+
/// </summary>
31+
public bool Approved { get; }
32+
}

src/Libraries/Microsoft.Extensions.AI.Abstractions/Contents/McpServerToolCallContent.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,20 @@
33

44
using System;
55
using System.Collections.Generic;
6+
using System.Diagnostics.CodeAnalysis;
67
using Microsoft.Shared.Diagnostics;
78

89
namespace Microsoft.Extensions.AI;
910

1011
/// <summary>
1112
/// Represents a tool call request to a MCP server.
1213
/// </summary>
13-
public class McpServerToolCallContent : AIContent
14+
/// <remarks>
15+
/// This content type is used to represent an invocation of an MCP server tool by a hosted service.
16+
/// It is informational only.
17+
/// </remarks>
18+
[Experimental("MEAI001")]
19+
public sealed class McpServerToolCallContent : AIContent
1420
{
1521
/// <summary>
1622
/// Initializes a new instance of the <see cref="McpServerToolCallContent"/> class.

src/Libraries/Microsoft.Extensions.AI.Abstractions/Contents/McpServerToolResultContent.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,20 @@
33

44
using System;
55
using System.Collections.Generic;
6+
using System.Diagnostics.CodeAnalysis;
67
using Microsoft.Shared.Diagnostics;
78

89
namespace Microsoft.Extensions.AI;
910

1011
/// <summary>
1112
/// Represents the result of a MCP server tool call.
1213
/// </summary>
13-
public class McpServerToolResultContent : AIContent
14+
/// <remarks>
15+
/// This content type is used to represent the result of an invocation of an MCP server tool by a hosted service.
16+
/// It is informational only.
17+
/// </remarks>
18+
[Experimental("MEAI001")]
19+
public sealed class McpServerToolResultContent : AIContent
1420
{
1521
/// <summary>
1622
/// Initializes a new instance of the <see cref="McpServerToolResultContent"/> class.

src/Libraries/Microsoft.Extensions.AI.Abstractions/HostedMcpServerToolAlwaysRequireApprovalMode.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System.Diagnostics;
5+
using System.Diagnostics.CodeAnalysis;
56

67
namespace Microsoft.Extensions.AI;
78

@@ -11,6 +12,7 @@ namespace Microsoft.Extensions.AI;
1112
/// <remarks>
1213
/// Use <see cref="HostedMcpServerToolApprovalMode.AlwaysRequire"/> to get an instance of <see cref="HostedMcpServerToolAlwaysRequireApprovalMode"/>.
1314
/// </remarks>
15+
[Experimental("MEAI001")]
1416
[DebuggerDisplay(nameof(AlwaysRequire))]
1517
public sealed class HostedMcpServerToolAlwaysRequireApprovalMode : HostedMcpServerToolApprovalMode
1618
{

src/Libraries/Microsoft.Extensions.AI.Abstractions/HostedMcpServerToolApprovalMode.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System.Collections.Generic;
5+
using System.Diagnostics.CodeAnalysis;
56
using System.Text.Json.Serialization;
67

78
namespace Microsoft.Extensions.AI;
@@ -13,6 +14,7 @@ namespace Microsoft.Extensions.AI;
1314
/// The predefined values <see cref="AlwaysRequire" />, and <see cref="NeverRequire"/> are provided to specify handling for all tools.
1415
/// To specify approval behavior for individual tool names, use <see cref="RequireSpecific(IList{string}, IList{string})"/>.
1516
/// </remarks>
17+
[Experimental("MEAI001")]
1618
[JsonPolymorphic(TypeDiscriminatorPropertyName = "$type")]
1719
[JsonDerivedType(typeof(HostedMcpServerToolNeverRequireApprovalMode), typeDiscriminator: "never")]
1820
[JsonDerivedType(typeof(HostedMcpServerToolAlwaysRequireApprovalMode), typeDiscriminator: "always")]

src/Libraries/Microsoft.Extensions.AI.Abstractions/HostedMcpServerToolNeverRequireApprovalMode.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System.Diagnostics;
5+
using System.Diagnostics.CodeAnalysis;
56

67
namespace Microsoft.Extensions.AI;
78

@@ -11,6 +12,7 @@ namespace Microsoft.Extensions.AI;
1112
/// <remarks>
1213
/// Use <see cref="HostedMcpServerToolApprovalMode.NeverRequire"/> to get an instance of <see cref="HostedMcpServerToolNeverRequireApprovalMode"/>.
1314
/// </remarks>
15+
[Experimental("MEAI001")]
1416
[DebuggerDisplay(nameof(NeverRequire))]
1517
public sealed class HostedMcpServerToolNeverRequireApprovalMode : HostedMcpServerToolApprovalMode
1618
{

src/Libraries/Microsoft.Extensions.AI.Abstractions/HostedMcpServerToolRequireSpecificApprovalMode.cs

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@
33

44
using System;
55
using System.Collections.Generic;
6+
using System.Diagnostics.CodeAnalysis;
67
using System.Linq;
78

89
namespace Microsoft.Extensions.AI;
910

1011
/// <summary>
1112
/// Represents a mode where approval behavior is specified for individual tool names.
1213
/// </summary>
14+
[Experimental("MEAI001")]
1315
public sealed class HostedMcpServerToolRequireSpecificApprovalMode : HostedMcpServerToolApprovalMode
1416
{
1517
/// <summary>
@@ -42,20 +44,9 @@ public override bool Equals(object? obj) => obj is HostedMcpServerToolRequireSpe
4244
public override int GetHashCode() =>
4345
HashCode.Combine(GetListHashCode(AlwaysRequireApprovalToolNames), GetListHashCode(NeverRequireApprovalToolNames));
4446

45-
private static bool ListEquals(IList<string>? list1, IList<string>? list2)
46-
{
47-
if (ReferenceEquals(list1, list2))
48-
{
49-
return true;
50-
}
51-
52-
if (list1 is null || list2 is null)
53-
{
54-
return false;
55-
}
56-
57-
return list1.SequenceEqual(list2);
58-
}
47+
private static bool ListEquals(IList<string>? list1, IList<string>? list2) =>
48+
ReferenceEquals(list1, list2) ||
49+
(list1 is not null && list2 is not null && list1.SequenceEqual(list2));
5950

6051
private static int GetListHashCode(IList<string>? list)
6152
{
@@ -64,7 +55,7 @@ private static int GetListHashCode(IList<string>? list)
6455
return 0;
6556
}
6657

67-
var hc = default(HashCode);
58+
HashCode hc = default;
6859
foreach (string item in list)
6960
{
7061
hc.Add(item);

0 commit comments

Comments
 (0)