Fix some issues with Native AOT (#130)
* Fix some issues with Native AOT - An anonymous type was being used in McpClient for the initialize result message. Switched to use the type for that purpose that already existed. - A bunch of the request params / result types were not in the source context or referenced from types that were or from custom converters. Added all the request/result types to the context. - Improved the warning message for WithTools.
This commit is contained in:
parent
9330774795
commit
2c1672cc1a
7 changed files with 53 additions and 27 deletions
|
|
@ -6,7 +6,6 @@ using ModelContextProtocol.Protocol.Types;
|
||||||
using ModelContextProtocol.Shared;
|
using ModelContextProtocol.Shared;
|
||||||
using ModelContextProtocol.Utils.Json;
|
using ModelContextProtocol.Utils.Json;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Logging.Abstractions;
|
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
|
||||||
namespace ModelContextProtocol.Client;
|
namespace ModelContextProtocol.Client;
|
||||||
|
|
@ -126,11 +125,11 @@ internal sealed class McpClient : McpJsonRpcEndpoint, IMcpClient
|
||||||
new JsonRpcRequest
|
new JsonRpcRequest
|
||||||
{
|
{
|
||||||
Method = "initialize",
|
Method = "initialize",
|
||||||
Params = new
|
Params = new InitializeRequestParams()
|
||||||
{
|
{
|
||||||
protocolVersion = _options.ProtocolVersion,
|
ProtocolVersion = _options.ProtocolVersion,
|
||||||
capabilities = _options.Capabilities ?? new ClientCapabilities(),
|
Capabilities = _options.Capabilities ?? new ClientCapabilities(),
|
||||||
clientInfo = _options.ClientInfo
|
ClientInfo = _options.ClientInfo
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
initializationCts.Token).ConfigureAwait(false);
|
initializationCts.Token).ConfigureAwait(false);
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,9 @@ namespace ModelContextProtocol;
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static partial class McpServerBuilderExtensions
|
public static partial class McpServerBuilderExtensions
|
||||||
{
|
{
|
||||||
private const string RequiresUnreferencedCodeMessage = "This method requires dynamic lookup of method metadata and might not work in Native AOT.";
|
private const string WithToolsRequiresUnreferencedCodeMessage =
|
||||||
|
$"The non-generic {nameof(WithTools)} and {nameof(WithToolsFromAssembly)} methods require dynamic lookup of method metadata" +
|
||||||
|
$"and may not work in Native AOT. Use the generic {nameof(WithTools)} method instead.";
|
||||||
|
|
||||||
/// <summary>Adds <see cref="McpServerTool"/> instances to the service collection backing <paramref name="builder"/>.</summary>
|
/// <summary>Adds <see cref="McpServerTool"/> instances to the service collection backing <paramref name="builder"/>.</summary>
|
||||||
/// <typeparam name="TTool">The tool type.</typeparam>
|
/// <typeparam name="TTool">The tool type.</typeparam>
|
||||||
|
|
@ -59,7 +61,7 @@ public static partial class McpServerBuilderExtensions
|
||||||
/// types, where the methods are attributed as <see cref="McpServerToolAttribute"/>, and adds an <see cref="McpServerTool"/>
|
/// types, where the methods are attributed as <see cref="McpServerToolAttribute"/>, and adds an <see cref="McpServerTool"/>
|
||||||
/// instance for each. For instance methods, an instance will be constructed for each invocation of the tool.
|
/// instance for each. For instance methods, an instance will be constructed for each invocation of the tool.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
|
[RequiresUnreferencedCode(WithToolsRequiresUnreferencedCodeMessage)]
|
||||||
public static IMcpServerBuilder WithTools(this IMcpServerBuilder builder, params IEnumerable<Type> toolTypes)
|
public static IMcpServerBuilder WithTools(this IMcpServerBuilder builder, params IEnumerable<Type> toolTypes)
|
||||||
{
|
{
|
||||||
Throw.IfNull(builder);
|
Throw.IfNull(builder);
|
||||||
|
|
@ -95,7 +97,7 @@ public static partial class McpServerBuilderExtensions
|
||||||
/// <param name="builder">The builder instance.</param>
|
/// <param name="builder">The builder instance.</param>
|
||||||
/// <param name="toolAssembly">The assembly to load the types from. Null to get the current assembly</param>
|
/// <param name="toolAssembly">The assembly to load the types from. Null to get the current assembly</param>
|
||||||
/// <exception cref="ArgumentNullException"><paramref name="builder"/> is <see langword="null"/>.</exception>
|
/// <exception cref="ArgumentNullException"><paramref name="builder"/> is <see langword="null"/>.</exception>
|
||||||
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
|
[RequiresUnreferencedCode(WithToolsRequiresUnreferencedCodeMessage)]
|
||||||
public static IMcpServerBuilder WithToolsFromAssembly(this IMcpServerBuilder builder, Assembly? toolAssembly = null)
|
public static IMcpServerBuilder WithToolsFromAssembly(this IMcpServerBuilder builder, Assembly? toolAssembly = null)
|
||||||
{
|
{
|
||||||
Throw.IfNull(builder);
|
Throw.IfNull(builder);
|
||||||
|
|
|
||||||
33
src/ModelContextProtocol/Protocol/Messages/JsonRpcRequest.cs
Normal file
33
src/ModelContextProtocol/Protocol/Messages/JsonRpcRequest.cs
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace ModelContextProtocol.Protocol.Messages;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A request message in the JSON-RPC protocol.
|
||||||
|
/// </summary>
|
||||||
|
public record JsonRpcRequest : IJsonRpcMessageWithId
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// JSON-RPC protocol version. Always "2.0".
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("jsonrpc")]
|
||||||
|
public string JsonRpc { get; init; } = "2.0";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Request identifier. Must be a string or number and unique within the session.
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("id")]
|
||||||
|
public RequestId Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Name of the method to invoke.
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("method")]
|
||||||
|
public required string Method { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Optional parameters for the method.
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("params")]
|
||||||
|
public object? Params { get; init; }
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Logging.Abstractions;
|
|
||||||
using ModelContextProtocol.Logging;
|
using ModelContextProtocol.Logging;
|
||||||
using ModelContextProtocol.Protocol.Messages;
|
using ModelContextProtocol.Protocol.Messages;
|
||||||
using ModelContextProtocol.Protocol.Transport;
|
using ModelContextProtocol.Protocol.Transport;
|
||||||
|
|
|
||||||
|
|
@ -105,21 +105,52 @@ public static partial class McpJsonUtilities
|
||||||
UseStringEnumConverter = true,
|
UseStringEnumConverter = true,
|
||||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
||||||
NumberHandling = JsonNumberHandling.AllowReadingFromString)]
|
NumberHandling = JsonNumberHandling.AllowReadingFromString)]
|
||||||
|
|
||||||
|
// JSON
|
||||||
[JsonSerializable(typeof(JsonDocument))]
|
[JsonSerializable(typeof(JsonDocument))]
|
||||||
[JsonSerializable(typeof(JsonElement))]
|
[JsonSerializable(typeof(JsonElement))]
|
||||||
[JsonSerializable(typeof(JsonNode))]
|
[JsonSerializable(typeof(JsonNode))]
|
||||||
|
|
||||||
|
// JSON-RPC
|
||||||
[JsonSerializable(typeof(IJsonRpcMessage))]
|
[JsonSerializable(typeof(IJsonRpcMessage))]
|
||||||
[JsonSerializable(typeof(JsonRpcRequest))]
|
[JsonSerializable(typeof(JsonRpcRequest))]
|
||||||
[JsonSerializable(typeof(JsonRpcNotification))]
|
[JsonSerializable(typeof(JsonRpcNotification))]
|
||||||
[JsonSerializable(typeof(JsonRpcResponse))]
|
[JsonSerializable(typeof(JsonRpcResponse))]
|
||||||
[JsonSerializable(typeof(JsonRpcError))]
|
[JsonSerializable(typeof(JsonRpcError))]
|
||||||
[JsonSerializable(typeof(ServerCapabilities))]
|
|
||||||
[JsonSerializable(typeof(ClientCapabilities))]
|
// MCP Request Params / Results
|
||||||
[JsonSerializable(typeof(Implementation))]
|
[JsonSerializable(typeof(CallToolRequestParams))]
|
||||||
[JsonSerializable(typeof(CreateMessageResult))]
|
|
||||||
[JsonSerializable(typeof(ListRootsResult))]
|
|
||||||
[JsonSerializable(typeof(InitializeResult))]
|
|
||||||
[JsonSerializable(typeof(CallToolResponse))]
|
[JsonSerializable(typeof(CallToolResponse))]
|
||||||
|
[JsonSerializable(typeof(CompleteRequestParams))]
|
||||||
|
[JsonSerializable(typeof(CompleteResult))]
|
||||||
|
[JsonSerializable(typeof(CreateMessageRequestParams))]
|
||||||
|
[JsonSerializable(typeof(CreateMessageResult))]
|
||||||
|
[JsonSerializable(typeof(EmptyResult))]
|
||||||
|
[JsonSerializable(typeof(GetPromptRequestParams))]
|
||||||
|
[JsonSerializable(typeof(GetPromptResult))]
|
||||||
|
[JsonSerializable(typeof(InitializeRequestParams))]
|
||||||
|
[JsonSerializable(typeof(InitializeResult))]
|
||||||
|
[JsonSerializable(typeof(ListPromptsRequestParams))]
|
||||||
|
[JsonSerializable(typeof(ListPromptsResult))]
|
||||||
|
[JsonSerializable(typeof(ListResourcesRequestParams))]
|
||||||
|
[JsonSerializable(typeof(ListResourcesResult))]
|
||||||
|
[JsonSerializable(typeof(ListResourceTemplatesRequestParams))]
|
||||||
|
[JsonSerializable(typeof(ListResourceTemplatesResult))]
|
||||||
|
[JsonSerializable(typeof(ListRootsRequestParams))]
|
||||||
|
[JsonSerializable(typeof(ListRootsResult))]
|
||||||
|
[JsonSerializable(typeof(ListToolsRequestParams))]
|
||||||
|
[JsonSerializable(typeof(ListToolsResult))]
|
||||||
|
[JsonSerializable(typeof(LoggingMessageNotificationParams))]
|
||||||
|
[JsonSerializable(typeof(PingResult))]
|
||||||
|
[JsonSerializable(typeof(ReadResourceRequestParams))]
|
||||||
|
[JsonSerializable(typeof(ReadResourceResult))]
|
||||||
|
[JsonSerializable(typeof(ResourceUpdatedNotificationParams))]
|
||||||
|
[JsonSerializable(typeof(SetLevelRequestParams))]
|
||||||
|
[JsonSerializable(typeof(SubscribeRequestParams))]
|
||||||
|
[JsonSerializable(typeof(UnsubscribeFromResourceRequestParams))]
|
||||||
|
[JsonSerializable(typeof(UnsubscribeRequestParams))]
|
||||||
|
|
||||||
|
[ExcludeFromCodeCoverage]
|
||||||
internal sealed partial class JsonContext : JsonSerializerContext;
|
internal sealed partial class JsonContext : JsonSerializerContext;
|
||||||
|
|
||||||
private static JsonElement ParseJsonElement(ReadOnlySpan<byte> utf8Json)
|
private static JsonElement ParseJsonElement(ReadOnlySpan<byte> utf8Json)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
using Microsoft.Extensions.AI;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using ModelContextProtocol.Protocol.Types;
|
using ModelContextProtocol.Protocol.Types;
|
||||||
using ModelContextProtocol.Server;
|
using ModelContextProtocol.Server;
|
||||||
using Moq;
|
using Moq;
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ using System.Text.Json;
|
||||||
using ModelContextProtocol.Protocol.Messages;
|
using ModelContextProtocol.Protocol.Messages;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Logging.Abstractions;
|
using Microsoft.Extensions.Logging.Abstractions;
|
||||||
|
using ModelContextProtocol.Protocol.Types;
|
||||||
|
|
||||||
namespace ModelContextProtocol.Tests.Utils;
|
namespace ModelContextProtocol.Tests.Utils;
|
||||||
|
|
||||||
|
|
@ -288,19 +289,14 @@ public sealed class InMemoryTestSseServer : IAsyncDisposable
|
||||||
var jsonRpcResponse = new JsonRpcResponse()
|
var jsonRpcResponse = new JsonRpcResponse()
|
||||||
{
|
{
|
||||||
Id = jsonRpcRequest.Id,
|
Id = jsonRpcRequest.Id,
|
||||||
Result = new
|
Result = new InitializeResult()
|
||||||
{
|
{
|
||||||
protocolVersion = "2024-11-05",
|
ProtocolVersion = "2024-11-05",
|
||||||
capabilities = new
|
Capabilities = new(),
|
||||||
|
ServerInfo = new()
|
||||||
{
|
{
|
||||||
experimental = (object?)null,
|
Name = "ExampleServer",
|
||||||
roots = (object?)null,
|
Version = "1.0.0"
|
||||||
sampling = (object?)null
|
|
||||||
},
|
|
||||||
serverInfo = new
|
|
||||||
{
|
|
||||||
name = "ExampleServer",
|
|
||||||
version = "1.0.0"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue