Implementation for SEP-2243 Http Standardization (#1553)
Co-authored-by: Tarek Mahmoud Sayed <tarekms@microsoft.com> Co-authored-by: Tarek Mahmoud Sayed <tarekms@ntdev.microsoft.com> Co-authored-by: Tarek Mahmoud Sayed <10833894+tarekgh@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
parent
3118fcd6cb
commit
b8c4d951ec
1 changed files with 2854 additions and 28 deletions
|
|
@ -124,6 +124,12 @@ internal sealed partial class AIFunctionMcpServerTool : McpServerTool
|
|||
Icons = options?.Icons,
|
||||
};
|
||||
|
||||
// Add x-mcp-header extensions to the input schema based on McpHeaderAttribute on parameters
|
||||
if (function.UnderlyingMethod is { } method)
|
||||
{
|
||||
tool.InputSchema = AddMcpHeaderExtensions(tool.InputSchema, method);
|
||||
}
|
||||
|
||||
if (options is not null)
|
||||
{
|
||||
if (options.Title is not null ||
|
||||
|
|
@ -600,4 +606,85 @@ internal sealed partial class AIFunctionMcpServerTool : McpServerTool
|
|||
IsError = allErrorContent && hasAny
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Post-processes the input schema to add <c>x-mcp-header</c> extensions based on
|
||||
/// <see cref="McpHeaderAttribute"/> on method parameters.
|
||||
/// </summary>
|
||||
private static JsonElement AddMcpHeaderExtensions(JsonElement inputSchema, MethodInfo method)
|
||||
{
|
||||
// Collect parameters with McpHeaderAttribute
|
||||
var headerParams = new List<(string ParameterName, string HeaderName, ParameterInfo Parameter)>();
|
||||
var headerNamesSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
foreach (var param in method.GetParameters())
|
||||
{
|
||||
var attr = param.GetCustomAttribute<McpHeaderAttribute>();
|
||||
if (attr is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Validate primitive type only
|
||||
var paramType = Nullable.GetUnderlyingType(param.ParameterType) ?? param.ParameterType;
|
||||
if (!IsPrimitiveHeaderType(paramType))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"Parameter '{param.Name}' on method '{method.Name}' has [McpHeader] but is not a primitive type. " +
|
||||
"Only string, numeric, and boolean types may be annotated with [McpHeader].");
|
||||
}
|
||||
|
||||
// Validate case-insensitive uniqueness
|
||||
if (!headerNamesSet.Add(attr.Name))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"Duplicate x-mcp-header name '{attr.Name}' (case-insensitive) found on method '{method.Name}'. " +
|
||||
"Header names must be case-insensitively unique within a tool's input schema.");
|
||||
}
|
||||
|
||||
headerParams.Add((param.Name!, attr.Name, param));
|
||||
}
|
||||
|
||||
if (headerParams.Count == 0)
|
||||
{
|
||||
return inputSchema;
|
||||
}
|
||||
|
||||
// Parse the schema to a mutable JsonNode, add extensions, and convert back
|
||||
var schemaNode = JsonNode.Parse(inputSchema.GetRawText());
|
||||
if (schemaNode is not JsonObject schemaObj ||
|
||||
!schemaObj.TryGetPropertyValue("properties", out var propertiesNode) ||
|
||||
propertiesNode is not JsonObject propertiesObj)
|
||||
{
|
||||
return inputSchema;
|
||||
}
|
||||
|
||||
foreach (var (parameterName, headerName, _) in headerParams)
|
||||
{
|
||||
if (propertiesObj.TryGetPropertyValue(parameterName, out var propNode) &&
|
||||
propNode is JsonObject propObj)
|
||||
{
|
||||
propObj["x-mcp-header"] = headerName;
|
||||
}
|
||||
}
|
||||
|
||||
return JsonSerializer.Deserialize(schemaNode, McpJsonUtilities.JsonContext.Default.JsonElement);
|
||||
}
|
||||
|
||||
private static bool IsPrimitiveHeaderType(Type type)
|
||||
{
|
||||
return type == typeof(string) ||
|
||||
type == typeof(bool) ||
|
||||
type == typeof(byte) ||
|
||||
type == typeof(sbyte) ||
|
||||
type == typeof(short) ||
|
||||
type == typeof(ushort) ||
|
||||
type == typeof(int) ||
|
||||
type == typeof(uint) ||
|
||||
type == typeof(long) ||
|
||||
type == typeof(ulong) ||
|
||||
type == typeof(float) ||
|
||||
type == typeof(double) ||
|
||||
type == typeof(decimal);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue