diff --git a/src/ModelContextProtocol/McpJsonUtilities.cs b/src/ModelContextProtocol/McpJsonUtilities.cs
index ca9748437..fe7b8970c 100644
--- a/src/ModelContextProtocol/McpJsonUtilities.cs
+++ b/src/ModelContextProtocol/McpJsonUtilities.cs
@@ -2,6 +2,7 @@
using ModelContextProtocol.Protocol;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json;
+using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
@@ -75,6 +76,25 @@ internal static bool IsValidMcpToolSchema(JsonElement element)
return false; // No type keyword found.
}
+ private static readonly string[] s_rootSchemaKeywordsToRemove = ["title", "description"];
+ internal static AIJsonSchemaCreateOptions DefaultSchemaCreateOptions { get; } = new()
+ {
+ TransformOptions = new()
+ {
+ TransformSchemaNode = static (ctx, node) =>
+ {
+ if (ctx.Path is [] && node is JsonObject obj)
+ {
+ foreach (string keywordToRemove in s_rootSchemaKeywordsToRemove)
+ {
+ obj.Remove(keywordToRemove);
+ }
+ }
+ return node;
+ },
+ }
+ };
+
// Keep in sync with CreateDefaultOptions above.
[JsonSourceGenerationOptions(JsonSerializerDefaults.Web,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
diff --git a/src/ModelContextProtocol/Server/AIFunctionMcpServerPrompt.cs b/src/ModelContextProtocol/Server/AIFunctionMcpServerPrompt.cs
index 9e1cdbcea..ed1bd3cc8 100644
--- a/src/ModelContextProtocol/Server/AIFunctionMcpServerPrompt.cs
+++ b/src/ModelContextProtocol/Server/AIFunctionMcpServerPrompt.cs
@@ -151,7 +151,7 @@ private static AIFunctionFactoryOptions CreateAIFunctionFactoryOptions(
return null;
}
},
- JsonSchemaCreateOptions = options?.SchemaCreateOptions,
+ JsonSchemaCreateOptions = options?.SchemaCreateOptions ?? McpJsonUtilities.DefaultSchemaCreateOptions,
};
/// Creates an that wraps the specified .
diff --git a/src/ModelContextProtocol/Server/AIFunctionMcpServerTool.cs b/src/ModelContextProtocol/Server/AIFunctionMcpServerTool.cs
index 366eb23cd..60820c254 100644
--- a/src/ModelContextProtocol/Server/AIFunctionMcpServerTool.cs
+++ b/src/ModelContextProtocol/Server/AIFunctionMcpServerTool.cs
@@ -160,7 +160,7 @@ private static AIFunctionFactoryOptions CreateAIFunctionFactoryOptions(
return null;
}
},
- JsonSchemaCreateOptions = options?.SchemaCreateOptions,
+ JsonSchemaCreateOptions = options?.SchemaCreateOptions ?? McpJsonUtilities.DefaultSchemaCreateOptions,
};
/// Creates an that wraps the specified .
diff --git a/tests/ModelContextProtocol.Tests/Server/McpServerToolTests.cs b/tests/ModelContextProtocol.Tests/Server/McpServerToolTests.cs
index cb98d9bce..b33d50705 100644
--- a/tests/ModelContextProtocol.Tests/Server/McpServerToolTests.cs
+++ b/tests/ModelContextProtocol.Tests/Server/McpServerToolTests.cs
@@ -3,6 +3,7 @@
using ModelContextProtocol.Protocol;
using ModelContextProtocol.Server;
using Moq;
+using System.ComponentModel;
using System.Reflection;
using System.Text.Json;
using System.Text.Json.Serialization;
@@ -381,6 +382,23 @@ public async Task SupportsSchemaCreateOptions()
);
}
+ [Fact]
+ public void TrimsDescriptionAndTitleKeywordsFromRootSchema()
+ {
+ McpServerTool tool = McpServerTool.Create(Add);
+
+ Assert.Equal("My awesome adding tool", tool.ProtocolTool.Description);
+ Assert.False(tool.ProtocolTool.InputSchema.TryGetProperty("description", out _));
+ Assert.False(tool.ProtocolTool.InputSchema.TryGetProperty("title", out _));
+
+ // Preserves any nested description keywords
+ Assert.Equal("The first argument", tool.ProtocolTool.InputSchema.GetProperty("properties").GetProperty("a").GetProperty("description").GetString());
+ Assert.Equal("The second argument", tool.ProtocolTool.InputSchema.GetProperty("properties").GetProperty("b").GetProperty("description").GetString());
+
+ [Description("My awesome adding tool")]
+ static int Add([Description("The first argument")] int a , [Description("The second argument")] int b) => a + b;
+ }
+
private sealed class MyService;
private class DisposableToolType : IDisposable