diff --git a/src/mcpdotnet/Configuration/McpServerBuilderExtensions.Tools.cs b/src/mcpdotnet/Configuration/McpServerBuilderExtensions.Tools.cs index 639db23..61a80bc 100644 --- a/src/mcpdotnet/Configuration/McpServerBuilderExtensions.Tools.cs +++ b/src/mcpdotnet/Configuration/McpServerBuilderExtensions.Tools.cs @@ -1,6 +1,7 @@ using System.ComponentModel; using System.Globalization; using System.Reflection; +using System.Runtime.ExceptionServices; using System.Text.Json; using McpDotNet.Configuration; using McpDotNet.Protocol.Types; @@ -171,44 +172,49 @@ public static partial class McpServerBuilderExtensions private static async Task CallTool(RequestContext request, MethodInfo method, CancellationToken cancellationToken) { + cancellationToken.ThrowIfCancellationRequested(); + var methodParameters = method.GetParameters(); List parameters = ResolveParameters(request, methodParameters, cancellationToken); - if (cancellationToken.IsCancellationRequested) - return new CallToolResponse { Content = [new Content { Text = "Operation was cancelled" }] }; - + using var scope = request.Server.ServiceProvider?.CreateScope(); + var objectInstance = CreateObjectInstance(method, scope?.ServiceProvider); + object? result; try { - using var scope = request.Server.ServiceProvider?.CreateScope(); - var objectInstance = CreateObjectInstance(method, scope?.ServiceProvider); - var result = method.Invoke(objectInstance, parameters.ToArray()); - - - if (result is Task task) - { - await task.ConfigureAwait(false); - var resultProperty = task.GetType().GetProperty("Result"); - result = resultProperty?.GetValue(task); - } - - if (result is string resultString) - return new CallToolResponse { Content = [new Content() { Text = resultString, Type = "text" }] }; - - if (result is string[] resultStringArray) - return new CallToolResponse { Content = resultStringArray.Select(s => new Content() { Text = s, Type = "text" }).ToList() }; - - if (result is null) - return new CallToolResponse { Content = [new Content() { Text = "null" }] }; - - if (result is JsonElement jsonElement) - return new CallToolResponse { Content = [new Content() { Text = jsonElement.GetRawText(), Type = "text" }] }; - - return new CallToolResponse { Content = [new Content() { Text = result.ToString(), Type = "text" }] }; + const BindingFlags InvokeFlags = +#if NET + BindingFlags.DoNotWrapExceptions | +#endif + BindingFlags.Default; + result = method.Invoke(objectInstance, InvokeFlags, binder: null, parameters.ToArray(), culture: null); } - catch (TargetInvocationException e) + catch (TargetInvocationException e) when (e.InnerException is not null) { - throw new McpServerException(e.Message, e); + ExceptionDispatchInfo.Capture(e.InnerException).Throw(); + throw; // unreachable } + + if (result is Task task) + { + await task.ConfigureAwait(false); + var resultProperty = task.GetType().GetProperty("Result"); + result = resultProperty?.GetValue(task); + } + + if (result is string resultString) + return new CallToolResponse { Content = [new Content() { Text = resultString, Type = "text" }] }; + + if (result is string[] resultStringArray) + return new CallToolResponse { Content = resultStringArray.Select(s => new Content() { Text = s, Type = "text" }).ToList() }; + + if (result is null) + return new CallToolResponse { Content = [new Content() { Text = "null" }] }; + + if (result is JsonElement jsonElement) + return new CallToolResponse { Content = [new Content() { Text = jsonElement.GetRawText(), Type = "text" }] }; + + return new CallToolResponse { Content = [new Content() { Text = result.ToString(), Type = "text" }] }; } private static List ResolveParameters(RequestContext request, ParameterInfo[] methodParameters, CancellationToken cancellationToken)