Skip to content
12 changes: 11 additions & 1 deletion src/ModelContextProtocol.Core/Server/McpServerImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -610,7 +610,9 @@ await originalListToolsHandler(request, cancellationToken).ConfigureAwait(false)

try
{
return await handler(request, cancellationToken).ConfigureAwait(false);
var result = await handler(request, cancellationToken).ConfigureAwait(false);
ToolCallCompleted(request.Params?.Name ?? string.Empty);
Comment thread
stephentoub marked this conversation as resolved.
Outdated
return result;
}
catch (Exception e) when (e is not OperationCanceledException and not McpProtocolException)
{
Expand Down Expand Up @@ -944,6 +946,9 @@ internal static LoggingLevel ToLoggingLevel(LogLevel level) =>
[LoggerMessage(Level = LogLevel.Error, Message = "\"{ToolName}\" threw an unhandled exception.")]
private partial void ToolCallError(string toolName, Exception exception);

[LoggerMessage(Level = LogLevel.Information, Message = "\"{ToolName}\" completed successfully.")]
private partial void ToolCallCompleted(string toolName);

/// <summary>
/// Executes a tool call as a task and returns a CallToolTaskResult immediately.
/// </summary>
Expand Down Expand Up @@ -1008,6 +1013,11 @@ private async ValueTask<CallToolResult> ExecuteToolAsTaskAsync(
// Determine final status based on whether there was an error
var finalStatus = result.IsError is true ? McpTaskStatus.Failed : McpTaskStatus.Completed;

if (finalStatus == McpTaskStatus.Completed)
{
ToolCallCompleted(request.Params?.Name ?? string.Empty);
Comment thread
stephentoub marked this conversation as resolved.
Outdated
}

// Store the result (serialize to JsonElement)
var resultElement = JsonSerializer.SerializeToElement(result, McpJsonUtilities.JsonContext.Default.CallToolResult);
var finalTask = await taskStore.StoreTaskResultAsync(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,23 @@ public async Task Returns_IsError_Content_And_Logs_Error_When_Tool_Fails()
Assert.Equal("Test error", errorLog.Exception.Message);
}

[Fact]
public async Task Logs_Tool_Name_On_Successful_Call()
Comment thread
halter73 marked this conversation as resolved.
{
await using McpClient client = await CreateMcpClientForServer();

var result = await client.CallToolAsync(
"echo",
new Dictionary<string, object?> { ["message"] = "test" },
cancellationToken: TestContext.Current.CancellationToken);

Assert.True(result.IsError is not true);
Assert.Equal("hello test", (result.Content[0] as TextContentBlock)?.Text);

var infoLog = Assert.Single(MockLoggerProvider.LogMessages, m => m.Message == "\"echo\" completed successfully.");
Assert.Equal(LogLevel.Information, infoLog.LogLevel);
}

[Fact]
public async Task Throws_Exception_On_Unknown_Tool()
{
Expand Down
Loading