-
Notifications
You must be signed in to change notification settings - Fork 5.1k
Description
Package: Azure.AI.Agents.Persistent (1.2.0-beta.2)
Namespace: Azure.AI.Agents.Persistent
Description
(Note - This is a summary of a discussion I had with Gemini while attempting to use the MCPToolResource.RequireApproval property.)
The design of the MCPToolResource.RequireApproval property, while flexible in accepting a string or a complex object, creates a significant usability issue that leads developers to a "pit of failure".
Because the property is typed as BinaryData, the developer is forced to manually serialize the MCPApprovalPerTool object. The most intuitive way to do this, using BinaryData.FromObjectAsJson(), invokes the default System.Text.Json.JsonSerializer. This serializer preserves C# PascalCase property names (Never, ToolNames), which do not match the camelCase and snake_case names expected by the API.
This mismatch inevitably leads to 400 Bad Request errors that are difficult for developers to diagnose and require a non-obvious, undiscoverable pattern to fix.
The Intuitive Path (Which Fails)
A developer's first instinct will be to construct the model and serialize it directly, as suggested by the RequireApproval property's own documentation.
// 1. Create the strongly-typed SDK model.
var approvalConfig = new MCPApprovalPerTool()
{
Never = new MCPToolList(new List<string>() { "list_csv_files" })
};
var mcpToolResource = new MCPToolResource("my-server-label");
// 2. Serialize it using the standard, intuitive method with no options.
// This preserves the C# property names "Never" and "ToolNames".
mcpToolResource.RequireApproval = BinaryData.FromObjectAsJson(approvalConfig);
// 3. This will fail when used in a client.Runs.CreateRun() call.
var toolResources = mcpToolResource.ToToolResources(); Resulting Error
This intuitive approach produces an incorrect JSON payload, causing the API to return a 400 Bad Request error on the very first mismatched property.
{
"error": {
"message": "Unknown parameter: 'tool_resources.mcp[0].require_approval.Never'. Did you mean 'never'?",
"type": "invalid_request_error",
"param": "tool_resources.mcp[0].require_approval.Never",
"code": "unknown_parameter"
}
}Notably, even if a developer attempts to solve this first error by applying a standard JsonNamingPolicy.CamelCase, they will immediately encounter a second error on the nested ToolNames property, which the API expects as tool_names (snake_case). This demonstrates that the problem cannot be solved with standard serialization techniques and requires a special approach.
The Correct (but Undiscoverable) Solution
The correct way to serialize the object is to bypass System.Text.Json entirely and explicitly invoke the SDK's internal serialization engine by casting the model to IPersistableModel<T> and using its Write method.
using System.ClientModel.Primitives; // Required for IPersistableModel and ModelReaderWriterOptions
// 1. Create the strongly-typed SDK model.
var approvalConfig = new MCPApprovalPerTool()
{
Never = new MCPToolList(new List<string>() { "list_csv_files" })
};
var mcpToolResource = new MCPToolResource("my-server-label");
// 2. Use the non-obvious but correct serialization pattern.
// This leverages the SDK's internal serializer which correctly handles all property names.
BinaryData correctlySerializedData = ((IPersistableModel<MCPApprovalPerTool>)approvalConfig)
.Write(new ModelReaderWriterOptions("W")); // "W" for wire format
// 3. Assign the correctly serialized data. This now works.
mcpToolResource.RequireApproval = correctlySerializedData;
var toolResources = mcpToolResource.ToToolResources();Why This Should Be Considered a Usability Bug
While a working path exists, the current design is problematic for a preview SDK that needs to be approachable:
- It Fails the Principle of Least Astonishment: The most obvious code path leads directly to a runtime error.
- The Solution is Undiscoverable: There is no documentation, IntelliSense, or guidance that would lead a developer to the
IPersistableModel.Writepattern. It requires inspecting the SDK's source code and understanding its internal architecture. - It Creates a Poor Developer Experience: This issue can cause hours of frustrating debugging for what should be a straightforward task. This is precisely the kind of feedback that "Preview" releases are meant to solicit.
Actionable Suggestions for Improvement
To improve the developer experience, please consider one of the following changes:
-
(Best) Add a Strongly-Typed Helper Method: Introduce a method on
MCPToolResourcethat handles the complex serialization internally. This provides a clean, type-safe API and hides the implementation details.// Example of a better API public void SetApprovalConfiguration(MCPApprovalPerTool configuration) { this.RequireApproval = ((IPersistableModel<MCPApprovalPerTool>)configuration) .Write(new ModelReaderWriterOptions("W")); }
-
(Good) Update XML Documentation: At a minimum, please update the XML documentation for the
RequireApprovalproperty with a code example demonstrating the correctIPersistableModel.Writepattern. This would make the solution discoverable.
Environment
VS 2022 and .Net v9