diff --git a/src/ModelContextProtocol/Server/AIFunctionMcpServerTool.cs b/src/ModelContextProtocol/Server/AIFunctionMcpServerTool.cs
index 562a8476c..6b0cf34b2 100644
--- a/src/ModelContextProtocol/Server/AIFunctionMcpServerTool.cs
+++ b/src/ModelContextProtocol/Server/AIFunctionMcpServerTool.cs
@@ -162,7 +162,7 @@ private static AIFunctionFactoryOptions CreateAIFunctionFactoryOptions(
{
Name = options?.Name ?? function.Name,
Description = options?.Description ?? function.Description,
- InputSchema = function.JsonSchema,
+ InputSchema = FilterJsonSchema(function.JsonSchema),
};
if (options is not null)
@@ -220,6 +220,45 @@ options.OpenWorld is not null ||
return newOptions;
}
+ ///
+ /// Filters a JsonElement containing a schema to only include allowed properties: "type", "properties", and "required".
+ ///
+ private static JsonElement FilterJsonSchema(JsonElement schema)
+ {
+ using var memoryStream = new MemoryStream();
+ using var writer = new Utf8JsonWriter(memoryStream);
+
+ writer.WriteStartObject();
+
+ // Include "type" property if it exists
+ if (schema.TryGetProperty("type", out var typeElement))
+ {
+ writer.WritePropertyName("type");
+ typeElement.WriteTo(writer);
+ }
+
+ // Include "properties" property if it exists
+ if (schema.TryGetProperty("properties", out var propertiesElement))
+ {
+ writer.WritePropertyName("properties");
+ propertiesElement.WriteTo(writer);
+ }
+
+ // Include "required" property if it exists
+ if (schema.TryGetProperty("required", out var requiredElement))
+ {
+ writer.WritePropertyName("required");
+ requiredElement.WriteTo(writer);
+ }
+
+ writer.WriteEndObject();
+ writer.Flush();
+
+ memoryStream.Position = 0;
+ using var document = JsonDocument.Parse(memoryStream.ToArray());
+ return document.RootElement.Clone();
+ }
+
/// Gets the wrapped by this tool.
internal AIFunction AIFunction { get; }
diff --git a/src/ModelContextProtocol/Utils/Json/McpJsonUtilities.cs b/src/ModelContextProtocol/Utils/Json/McpJsonUtilities.cs
index b759ba975..b5b7ac066 100644
--- a/src/ModelContextProtocol/Utils/Json/McpJsonUtilities.cs
+++ b/src/ModelContextProtocol/Utils/Json/McpJsonUtilities.cs
@@ -68,8 +68,12 @@ internal static bool IsValidMcpToolSchema(JsonElement element)
{
return false;
}
-
- return true; // No need to check other properties
+ }
+ else if (!(property.NameEquals("properties") ||
+ property.NameEquals("required")))
+ {
+ // Only "type", "properties", and "required" are allowed.
+ return false;
}
}
diff --git a/tests/ModelContextProtocol.Tests/Protocol/ProtocolTypeTests.cs b/tests/ModelContextProtocol.Tests/Protocol/ProtocolTypeTests.cs
index 7821d2ae6..1ad709749 100644
--- a/tests/ModelContextProtocol.Tests/Protocol/ProtocolTypeTests.cs
+++ b/tests/ModelContextProtocol.Tests/Protocol/ProtocolTypeTests.cs
@@ -30,6 +30,7 @@ public static void ToolInputSchema_HasValidDefaultSchema()
[InlineData("""{"type":"number"}""")]
[InlineData("""{"type":"array"}""")]
[InlineData("""{"type":["object"]}""")]
+ [InlineData("""{"type":"object", "title": "MyAwesomeTool", "description": "It's awesome!", "properties": {}, "required" : ["NotAParam"] }""")]
public static void ToolInputSchema_RejectsInvalidSchemaDocuments(string invalidSchema)
{
using var document = JsonDocument.Parse(invalidSchema);
@@ -41,7 +42,7 @@ public static void ToolInputSchema_RejectsInvalidSchemaDocuments(string invalidS
[Theory]
[InlineData("""{"type":"object"}""")]
[InlineData("""{"type":"object", "properties": {}, "required" : [] }""")]
- [InlineData("""{"type":"object", "title": "MyAwesomeTool", "description": "It's awesome!", "properties": {}, "required" : ["NotAParam"] }""")]
+ [InlineData("""{"type":"object", "properties": {}, "required" : ["NotAParam"] }""")]
public static void ToolInputSchema_AcceptsValidSchemaDocuments(string validSchema)
{
using var document = JsonDocument.Parse(validSchema);