Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 2 additions & 0 deletions src/ModelContextProtocol.Core/Client/StdioClientTransport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,8 @@ public async Task<ITransport> ConnectAsync(CancellationToken cancellationToken =
stderrRollingLog.Enqueue(data);
}

_options.StandardErrorLines?.Invoke(data);

LogReadStderr(logger, endpointName, data);
}
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,9 @@ public required string Command
/// </para>
/// </remarks>
public TimeSpan ShutdownTimeout { get; set; } = TimeSpan.FromSeconds(5);

/// <summary>
/// Gets or sets a callback that is invoked for each line of stderr received from the server process.
/// </summary>
public Action<string>? StandardErrorLines { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,21 @@ public async Task CreateAsync_ValidProcessInvalidServer_Throws()
IOException e = await Assert.ThrowsAsync<IOException>(() => McpClientFactory.CreateAsync(transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken));
Assert.Contains(id, e.ToString());
}

[Fact]
public async Task CreateAsync_ValidProcessInvalidServer_StdErrCallbackInvoked()
{
string id = Guid.NewGuid().ToString("N");

int count = 0;
Action<string> stdErrCallback = line => Interlocked.Increment(ref count);

StdioClientTransport transport = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ?
new(new() { Command = "cmd", Arguments = ["/C", $"echo \"{id}\" >&2"], StandardErrorLines = stdErrCallback }, LoggerFactory) :
new(new() { Command = "ls", Arguments = [id], StandardErrorLines = stdErrCallback }, LoggerFactory);

await Assert.ThrowsAsync<IOException>(() => McpClientFactory.CreateAsync(transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken));

Assert.InRange(count, 1, int.MaxValue);
}
}
Loading