Support specifying OutputSchema independently of return type for tools returning CallToolResult (#1425)

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
Co-authored-by: Stephen Toub <stoub@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Copilot 2026-03-22 21:19:29 -04:00 • committed by GitHub
commit 2958a75894
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 335 additions and 1 deletions

View file

@ -206,6 +206,13 @@ internal sealed partial class AIFunctionMcpServerTool : McpServerTool
newOptions.UseStructuredContent = toolAttr.UseStructuredContent;
if (toolAttr.OutputSchemaType is Type outputSchemaType)
{
newOptions.OutputSchema ??= AIJsonUtilities.CreateJsonSchema(outputSchemaType,
serializerOptions: newOptions.SerializerOptions ?? McpJsonUtilities.DefaultOptions,
inferenceOptions: newOptions.SchemaCreateOptions);
}
if (toolAttr._taskSupport is { } taskSupport)
{
newOptions.Execution ??= new ToolExecution();
@ -487,7 +494,17 @@ internal sealed partial class AIFunctionMcpServerTool : McpServerTool
return null;
}
if (function.ReturnJsonSchema is not JsonElement outputSchema)
// Explicit OutputSchema takes precedence over AIFunction's return schema.
JsonElement outputSchema;
if (toolCreateOptions.OutputSchema is { } explicitSchema)
{
outputSchema = explicitSchema;
}
else if (function.ReturnJsonSchema is { } returnSchema)
{
outputSchema = returnSchema;
}
else
{
return null;
}

View file

@ -265,6 +265,27 @@ public sealed class McpServerToolAttribute : Attribute
/// </remarks>
public bool UseStructuredContent { get; set; }
/// <summary>
/// Gets or sets a <see cref="Type"/> from which to generate the tool's output schema.
/// </summary>
/// <value>
/// The default is <see langword="null"/>, which means the output schema is inferred from the return type.
/// </value>
/// <remarks>
/// <para>
/// When set, a JSON schema is generated from the specified <see cref="Type"/> and used as the
/// <see cref="Tool.OutputSchema"/> instead of the schema inferred from the tool method's return type.
/// This is particularly useful when a tool method returns <see cref="CallToolResult"/> directly
/// (to control properties like <see cref="Result.Meta"/>, <see cref="CallToolResult.IsError"/>,
/// or <see cref="CallToolResult.StructuredContent"/>) but still needs to advertise a meaningful output
/// schema to clients.
/// </para>
/// <para>
/// <see cref="UseStructuredContent"/> must also be set to <see langword="true"/> for this property to take effect.
/// </para>
/// </remarks>
public Type? OutputSchemaType { get; set; }
/// <summary>
/// Gets or sets the source URI for the tool's icon.
/// </summary>

View file

@ -129,6 +129,26 @@ public sealed class McpServerToolCreateOptions
/// </remarks>
public bool UseStructuredContent { get; set; }
/// <summary>
/// Gets or sets an explicit JSON schema to use as the tool's output schema.
/// </summary>
/// <value>
/// The default is <see langword="null"/>, which means the output schema is inferred from the return type.
/// </value>
/// <remarks>
/// <para>
/// When set, this schema is used as the <see cref="Tool.OutputSchema"/> instead of the schema
/// inferred from the tool method's return type. This is particularly useful when a tool method
/// returns <see cref="CallToolResult"/> directly (to control properties like <see cref="Result.Meta"/>,
/// <see cref="CallToolResult.IsError"/>, or <see cref="CallToolResult.StructuredContent"/>) but still
/// needs to advertise a meaningful output schema to clients.
/// </para>
/// <para>
/// <see cref="UseStructuredContent"/> must also be set to <see langword="true"/> for this property to take effect.
/// </para>
/// </remarks>
public JsonElement? OutputSchema { get; set; }
/// <summary>
/// Gets or sets the JSON serializer options to use when marshalling data to/from JSON.
/// </summary>
@ -209,6 +229,7 @@ public sealed class McpServerToolCreateOptions
OpenWorld = OpenWorld,
ReadOnly = ReadOnly,
UseStructuredContent = UseStructuredContent,
OutputSchema = OutputSchema,
SerializerOptions = SerializerOptions,
SchemaCreateOptions = SchemaCreateOptions,
Metadata = Metadata,