Skip to content

Commit 2c1672c

Browse files
authored
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.
1 parent 9330774 commit 2c1672c

File tree

7 files changed

+53
-27
lines changed

7 files changed

+53
-27
lines changed

src/ModelContextProtocol/Client/McpClient.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
using ModelContextProtocol.Shared;
77
using ModelContextProtocol.Utils.Json;
88
using Microsoft.Extensions.Logging;
9-
using Microsoft.Extensions.Logging.Abstractions;
109
using System.Text.Json;
1110

1211
namespace ModelContextProtocol.Client;
@@ -126,11 +125,11 @@ private async Task InitializeAsync(CancellationToken cancellationToken)
126125
new JsonRpcRequest
127126
{
128127
Method = "initialize",
129-
Params = new
128+
Params = new InitializeRequestParams()
130129
{
131-
protocolVersion = _options.ProtocolVersion,
132-
capabilities = _options.Capabilities ?? new ClientCapabilities(),
133-
clientInfo = _options.ClientInfo
130+
ProtocolVersion = _options.ProtocolVersion,
131+
Capabilities = _options.Capabilities ?? new ClientCapabilities(),
132+
ClientInfo = _options.ClientInfo
134133
}
135134
},
136135
initializationCts.Token).ConfigureAwait(false);

src/ModelContextProtocol/Configuration/McpServerBuilderExtensions.Tools.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ namespace ModelContextProtocol;
1212
/// </summary>
1313
public static partial class McpServerBuilderExtensions
1414
{
15-
private const string RequiresUnreferencedCodeMessage = "This method requires dynamic lookup of method metadata and might not work in Native AOT.";
15+
private const string WithToolsRequiresUnreferencedCodeMessage =
16+
$"The non-generic {nameof(WithTools)} and {nameof(WithToolsFromAssembly)} methods require dynamic lookup of method metadata" +
17+
$"and may not work in Native AOT. Use the generic {nameof(WithTools)} method instead.";
1618

1719
/// <summary>Adds <see cref="McpServerTool"/> instances to the service collection backing <paramref name="builder"/>.</summary>
1820
/// <typeparam name="TTool">The tool type.</typeparam>
@@ -59,7 +61,7 @@ public static partial class McpServerBuilderExtensions
5961
/// types, where the methods are attributed as <see cref="McpServerToolAttribute"/>, and adds an <see cref="McpServerTool"/>
6062
/// instance for each. For instance methods, an instance will be constructed for each invocation of the tool.
6163
/// </remarks>
62-
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
64+
[RequiresUnreferencedCode(WithToolsRequiresUnreferencedCodeMessage)]
6365
public static IMcpServerBuilder WithTools(this IMcpServerBuilder builder, params IEnumerable<Type> toolTypes)
6466
{
6567
Throw.IfNull(builder);
@@ -95,7 +97,7 @@ public static IMcpServerBuilder WithTools(this IMcpServerBuilder builder, params
9597
/// <param name="builder">The builder instance.</param>
9698
/// <param name="toolAssembly">The assembly to load the types from. Null to get the current assembly</param>
9799
/// <exception cref="ArgumentNullException"><paramref name="builder"/> is <see langword="null"/>.</exception>
98-
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
100+
[RequiresUnreferencedCode(WithToolsRequiresUnreferencedCodeMessage)]
99101
public static IMcpServerBuilder WithToolsFromAssembly(this IMcpServerBuilder builder, Assembly? toolAssembly = null)
100102
{
101103
Throw.IfNull(builder);

src/ModelContextProtocol/Server/McpServer.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using Microsoft.Extensions.Logging;
2-
using Microsoft.Extensions.Logging.Abstractions;
32
using ModelContextProtocol.Logging;
43
using ModelContextProtocol.Protocol.Messages;
54
using ModelContextProtocol.Protocol.Transport;

src/ModelContextProtocol/Utils/Json/McpJsonUtilities.cs

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -105,21 +105,52 @@ internal static bool IsValidMcpToolSchema(JsonElement element)
105105
UseStringEnumConverter = true,
106106
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
107107
NumberHandling = JsonNumberHandling.AllowReadingFromString)]
108+
109+
// JSON
108110
[JsonSerializable(typeof(JsonDocument))]
109111
[JsonSerializable(typeof(JsonElement))]
110112
[JsonSerializable(typeof(JsonNode))]
113+
114+
// JSON-RPC
111115
[JsonSerializable(typeof(IJsonRpcMessage))]
112116
[JsonSerializable(typeof(JsonRpcRequest))]
113117
[JsonSerializable(typeof(JsonRpcNotification))]
114118
[JsonSerializable(typeof(JsonRpcResponse))]
115119
[JsonSerializable(typeof(JsonRpcError))]
116-
[JsonSerializable(typeof(ServerCapabilities))]
117-
[JsonSerializable(typeof(ClientCapabilities))]
118-
[JsonSerializable(typeof(Implementation))]
120+
121+
// MCP Request Params / Results
122+
[JsonSerializable(typeof(CallToolRequestParams))]
123+
[JsonSerializable(typeof(CallToolResponse))]
124+
[JsonSerializable(typeof(CompleteRequestParams))]
125+
[JsonSerializable(typeof(CompleteResult))]
126+
[JsonSerializable(typeof(CreateMessageRequestParams))]
119127
[JsonSerializable(typeof(CreateMessageResult))]
120-
[JsonSerializable(typeof(ListRootsResult))]
128+
[JsonSerializable(typeof(EmptyResult))]
129+
[JsonSerializable(typeof(GetPromptRequestParams))]
130+
[JsonSerializable(typeof(GetPromptResult))]
131+
[JsonSerializable(typeof(InitializeRequestParams))]
121132
[JsonSerializable(typeof(InitializeResult))]
122-
[JsonSerializable(typeof(CallToolResponse))]
133+
[JsonSerializable(typeof(ListPromptsRequestParams))]
134+
[JsonSerializable(typeof(ListPromptsResult))]
135+
[JsonSerializable(typeof(ListResourcesRequestParams))]
136+
[JsonSerializable(typeof(ListResourcesResult))]
137+
[JsonSerializable(typeof(ListResourceTemplatesRequestParams))]
138+
[JsonSerializable(typeof(ListResourceTemplatesResult))]
139+
[JsonSerializable(typeof(ListRootsRequestParams))]
140+
[JsonSerializable(typeof(ListRootsResult))]
141+
[JsonSerializable(typeof(ListToolsRequestParams))]
142+
[JsonSerializable(typeof(ListToolsResult))]
143+
[JsonSerializable(typeof(LoggingMessageNotificationParams))]
144+
[JsonSerializable(typeof(PingResult))]
145+
[JsonSerializable(typeof(ReadResourceRequestParams))]
146+
[JsonSerializable(typeof(ReadResourceResult))]
147+
[JsonSerializable(typeof(ResourceUpdatedNotificationParams))]
148+
[JsonSerializable(typeof(SetLevelRequestParams))]
149+
[JsonSerializable(typeof(SubscribeRequestParams))]
150+
[JsonSerializable(typeof(UnsubscribeFromResourceRequestParams))]
151+
[JsonSerializable(typeof(UnsubscribeRequestParams))]
152+
153+
[ExcludeFromCodeCoverage]
123154
internal sealed partial class JsonContext : JsonSerializerContext;
124155

125156
private static JsonElement ParseJsonElement(ReadOnlySpan<byte> utf8Json)

tests/ModelContextProtocol.Tests/Server/McpServerToolTests.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
using Microsoft.Extensions.AI;
2-
using Microsoft.Extensions.DependencyInjection;
1+
using Microsoft.Extensions.DependencyInjection;
32
using ModelContextProtocol.Protocol.Types;
43
using ModelContextProtocol.Server;
54
using Moq;

tests/ModelContextProtocol.Tests/Utils/InMemoryTestSseServer.cs

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using ModelContextProtocol.Protocol.Messages;
55
using Microsoft.Extensions.Logging;
66
using Microsoft.Extensions.Logging.Abstractions;
7+
using ModelContextProtocol.Protocol.Types;
78

89
namespace ModelContextProtocol.Tests.Utils;
910

@@ -288,19 +289,14 @@ private static async Task HandleInitializationRequest(HttpListenerResponse respo
288289
var jsonRpcResponse = new JsonRpcResponse()
289290
{
290291
Id = jsonRpcRequest.Id,
291-
Result = new
292+
Result = new InitializeResult()
292293
{
293-
protocolVersion = "2024-11-05",
294-
capabilities = new
294+
ProtocolVersion = "2024-11-05",
295+
Capabilities = new(),
296+
ServerInfo = new()
295297
{
296-
experimental = (object?)null,
297-
roots = (object?)null,
298-
sampling = (object?)null
299-
},
300-
serverInfo = new
301-
{
302-
name = "ExampleServer",
303-
version = "1.0.0"
298+
Name = "ExampleServer",
299+
Version = "1.0.0"
304300
}
305301
}
306302
};

0 commit comments

Comments
 (0)