Implement SEP-2663 Tasks Extension (#1579)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
parent
ed07fdb6f4
commit
dbb7a20176
1 changed files with 8190 additions and 11405 deletions
|
|
@ -1,4 +1,5 @@
|
|||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.Text.Json.Serialization;
|
||||
using ModelContextProtocol.Protocol;
|
||||
|
||||
|
|
@ -10,13 +11,13 @@ namespace ModelContextProtocol.Tests;
|
|||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Experimental properties (e.g. <see cref="Tool.Execution"/>, <see cref="ServerCapabilities.Tasks"/>)
|
||||
/// Experimental properties (e.g. <see cref="ServerCapabilities.Extensions"/>, <see cref="ClientCapabilities.Extensions"/>)
|
||||
/// use an internal <c>*Core</c> property for serialization. A consumer's source-generated
|
||||
/// <see cref="JsonSerializerContext"/> cannot see internal members, so experimental data is
|
||||
/// silently dropped unless the consumer chains the SDK's resolver into their options.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// These tests depend on <see cref="Tool.Execution"/> and <see cref="ServerCapabilities.Tasks"/>
|
||||
/// These tests depend on <see cref="ServerCapabilities.Extensions"/> and <see cref="ClientCapabilities.Extensions"/>
|
||||
/// being experimental. When those APIs stabilize, update these tests to reference whatever
|
||||
/// experimental properties exist at that time, or remove them entirely if no experimental
|
||||
/// APIs remain.
|
||||
|
|
@ -32,36 +33,36 @@ public class ExperimentalPropertySerializationTests
|
|||
TypeInfoResolverChain = { ConsumerJsonContext.Default }
|
||||
};
|
||||
|
||||
var tool = new Tool
|
||||
var capabilities = new ServerCapabilities
|
||||
{
|
||||
Name = "test-tool",
|
||||
Execution = new ToolExecution { TaskSupport = ToolTaskSupport.Optional }
|
||||
Tools = new ToolsCapability(),
|
||||
Extensions = new Dictionary<string, object> { ["io.test"] = new JsonObject { ["enabled"] = true } }
|
||||
};
|
||||
|
||||
string json = JsonSerializer.Serialize(tool, options);
|
||||
Assert.DoesNotContain("\"execution\"", json);
|
||||
Assert.Contains("\"name\"", json);
|
||||
string json = JsonSerializer.Serialize(capabilities, options);
|
||||
Assert.DoesNotContain("\"extensions\"", json);
|
||||
Assert.Contains("\"tools\"", json);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExperimentalProperties_IgnoredOnDeserialize_WithConsumerContextOnly()
|
||||
{
|
||||
string json = JsonSerializer.Serialize(
|
||||
new Tool
|
||||
new ServerCapabilities
|
||||
{
|
||||
Name = "test-tool",
|
||||
Execution = new ToolExecution { TaskSupport = ToolTaskSupport.Optional }
|
||||
Tools = new ToolsCapability(),
|
||||
Extensions = new Dictionary<string, object> { ["io.test"] = new JsonObject { ["enabled"] = true } }
|
||||
},
|
||||
McpJsonUtilities.DefaultOptions);
|
||||
Assert.Contains("\"execution\"", json);
|
||||
Assert.Contains("\"extensions\"", json);
|
||||
|
||||
var options = new JsonSerializerOptions
|
||||
{
|
||||
TypeInfoResolverChain = { ConsumerJsonContext.Default }
|
||||
};
|
||||
var deserialized = JsonSerializer.Deserialize<Tool>(json, options)!;
|
||||
Assert.Equal("test-tool", deserialized.Name);
|
||||
Assert.Null(deserialized.Execution);
|
||||
var deserialized = JsonSerializer.Deserialize<ServerCapabilities>(json, options)!;
|
||||
Assert.NotNull(deserialized.Tools);
|
||||
Assert.Null(deserialized.Extensions);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -76,35 +77,36 @@ public class ExperimentalPropertySerializationTests
|
|||
}
|
||||
};
|
||||
|
||||
var tool = new Tool
|
||||
var capabilities = new ServerCapabilities
|
||||
{
|
||||
Name = "test-tool",
|
||||
Execution = new ToolExecution { TaskSupport = ToolTaskSupport.Optional }
|
||||
Tools = new ToolsCapability(),
|
||||
Extensions = new Dictionary<string, object> { ["io.test"] = new JsonObject { ["enabled"] = true } }
|
||||
};
|
||||
|
||||
string json = JsonSerializer.Serialize(tool, options);
|
||||
Assert.Contains("\"execution\"", json);
|
||||
Assert.Contains("\"name\"", json);
|
||||
string json = JsonSerializer.Serialize(capabilities, options);
|
||||
Assert.Contains("\"extensions\"", json);
|
||||
Assert.Contains("\"tools\"", json);
|
||||
|
||||
var deserialized = JsonSerializer.Deserialize<Tool>(json, options)!;
|
||||
Assert.Equal("test-tool", deserialized.Name);
|
||||
Assert.NotNull(deserialized.Execution);
|
||||
Assert.Equal(ToolTaskSupport.Optional, deserialized.Execution.TaskSupport);
|
||||
var deserialized = JsonSerializer.Deserialize<ServerCapabilities>(json, options)!;
|
||||
Assert.NotNull(deserialized.Tools);
|
||||
Assert.NotNull(deserialized.Extensions);
|
||||
Assert.True(deserialized.Extensions.ContainsKey("io.test"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExperimentalProperties_RoundTrip_WithDefaultOptions()
|
||||
{
|
||||
var capabilities = new ServerCapabilities
|
||||
var capabilities = new ClientCapabilities
|
||||
{
|
||||
Tasks = new McpTasksCapability()
|
||||
Extensions = new Dictionary<string, object> { ["io.test"] = new JsonObject { ["enabled"] = true } }
|
||||
};
|
||||
|
||||
string json = JsonSerializer.Serialize(capabilities, McpJsonUtilities.DefaultOptions);
|
||||
Assert.Contains("\"tasks\"", json);
|
||||
Assert.Contains("\"extensions\"", json);
|
||||
|
||||
var deserialized = JsonSerializer.Deserialize<ServerCapabilities>(json, McpJsonUtilities.DefaultOptions)!;
|
||||
Assert.NotNull(deserialized.Tasks);
|
||||
var deserialized = JsonSerializer.Deserialize<ClientCapabilities>(json, McpJsonUtilities.DefaultOptions)!;
|
||||
Assert.NotNull(deserialized.Extensions);
|
||||
Assert.True(deserialized.Extensions.ContainsKey("io.test"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue