Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/McpAggregator.Core/Services/ConnectionManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,12 @@ public async Task<T> ExecuteWithRetryAsync<T>(
client = await GetClientAsync(serverName, ct);
return await operation(client, ct);
}
catch (Exception ex) when (ex is not OperationCanceledException and not AggregatorException)
{
_logger.LogError(ex, "Non-retryable error executing operation on '{Server}': {ExType}: {ExMessage}",
serverName, ex.GetType().FullName, ex.Message);
throw;
}
}

private static bool ShouldRetry(Exception ex)
Expand Down
45 changes: 37 additions & 8 deletions src/McpAggregator.Core/Tools/ToolProxyHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,24 @@ public ToolProxyHandler(
_logger = logger;
}

private void LogCallToolResult(string toolName, string serverName, CallToolResult result)
{
var contentSummary = string.Join(", ", result.Content
.GroupBy(b => b.Type ?? "unknown")
.Select(g => $"{g.Key}:{g.Count()}"));

_logger.LogDebug(
"Tool '{Tool}' on '{Server}' returned IsError={IsError}, content=[{Content}]",
toolName, serverName, result.IsError, contentSummary);

if (result.IsError is null)
{
_logger.LogDebug(
"Tool '{Tool}' on '{Server}' has IsError=null (downstream did not set error flag explicitly)",
toolName, serverName);
}
}

public async Task<string> InvokeAsync(
string serverName,
string toolName,
Expand All @@ -46,22 +64,33 @@ public async Task<string> InvokeAsync(
var result = await _connectionManager.ExecuteWithRetryAsync<CallToolResult>(serverName,
async (client, token) => await client.CallToolAsync(toolName, args, cancellationToken: token), cts.Token);

var textContent = result.Content
.OfType<TextContentBlock>()
.Select(c => c.Text)
.ToList();
LogCallToolResult(toolName, serverName, result);

var parts = new List<string>();

foreach (var block in result.Content)
{
if (block is TextContentBlock text)
{
parts.Add(text.Text);
}
else
{
parts.Add($"[{block.Type ?? "unknown"} content block]");
}
}

if (textContent.Count == 0)
if (parts.Count == 0)
{
if (result.IsError ?? false)
{
_logger.LogWarning("Tool '{Tool}' on '{Server}' returned error with no text content", toolName, serverName);
_logger.LogWarning("Tool '{Tool}' on '{Server}' returned error with no content blocks", toolName, serverName);
throw new ToolExecutionException(serverName, toolName, "No error details provided");
}
return "Tool completed with no text content.";
return "Tool completed with no content.";
}

var response = string.Join("\n", textContent);
var response = string.Join("\n", parts);

if (result.IsError ?? false)
{
Expand Down
Loading