Configure hosted stdio servers to log to stderr (#173)
* Configure hosted stdio servers to log to stderr * Fix newline * Use CreateApplicationBuilder where possible * Address PR feedback
This commit is contained in:
parent
19eed91c53
commit
8dc1f5d096
6 changed files with 27 additions and 6 deletions
13
README.md
13
README.md
|
|
@ -83,13 +83,24 @@ It includes a simple echo tool as an example (this is included in the same file
|
||||||
the employed overload of `WithTools` examines the current assembly for classes with the `McpServerToolType` attribute, and registers all methods with the
|
the employed overload of `WithTools` examines the current assembly for classes with the `McpServerToolType` attribute, and registers all methods with the
|
||||||
`McpTool` attribute as tools.)
|
`McpTool` attribute as tools.)
|
||||||
|
|
||||||
|
```
|
||||||
|
dotnet add package ModelContextProtocol --prerelease
|
||||||
|
dotnet add package Microsoft.Extensions.Hosting
|
||||||
|
```
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using ModelContextProtocol.Server;
|
using ModelContextProtocol.Server;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
|
|
||||||
var builder = Host.CreateEmptyApplicationBuilder(settings: null);
|
var builder = Host.CreateApplicationBuilder(args);
|
||||||
|
builder.Logging.AddConsole(consoleLogOptions =>
|
||||||
|
{
|
||||||
|
// Configure all logs to go to stderr
|
||||||
|
consoleLogOptions.LogToStandardErrorThreshold = LogLevel.Trace;
|
||||||
|
});
|
||||||
builder.Services
|
builder.Services
|
||||||
.AddMcpServer()
|
.AddMcpServer()
|
||||||
.WithStdioServerTransport()
|
.WithStdioServerTransport()
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ using Microsoft.Extensions.Hosting;
|
||||||
using ModelContextProtocol.Client;
|
using ModelContextProtocol.Client;
|
||||||
using ModelContextProtocol.Protocol.Transport;
|
using ModelContextProtocol.Protocol.Transport;
|
||||||
|
|
||||||
var builder = Host.CreateEmptyApplicationBuilder(settings: null);
|
var builder = Host.CreateApplicationBuilder(args);
|
||||||
|
|
||||||
builder.Configuration
|
builder.Configuration
|
||||||
.AddEnvironmentVariables()
|
.AddEnvironmentVariables()
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,19 @@
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
|
|
||||||
var builder = Host.CreateEmptyApplicationBuilder(settings: null);
|
var builder = Host.CreateApplicationBuilder(args);
|
||||||
|
|
||||||
builder.Services.AddMcpServer()
|
builder.Services.AddMcpServer()
|
||||||
.WithStdioServerTransport()
|
.WithStdioServerTransport()
|
||||||
.WithToolsFromAssembly();
|
.WithToolsFromAssembly();
|
||||||
|
|
||||||
|
builder.Logging.AddConsole(options =>
|
||||||
|
{
|
||||||
|
options.LogToStandardErrorThreshold = LogLevel.Trace;
|
||||||
|
});
|
||||||
|
|
||||||
builder.Services.AddSingleton(_ =>
|
builder.Services.AddSingleton(_ =>
|
||||||
{
|
{
|
||||||
var client = new HttpClient() { BaseAddress = new Uri("https://api.weather.gov") };
|
var client = new HttpClient() { BaseAddress = new Uri("https://api.weather.gov") };
|
||||||
|
|
|
||||||
|
|
@ -98,8 +98,8 @@ internal static partial class Log
|
||||||
[LoggerMessage(Level = LogLevel.Information, Message = "Creating process for transport for {endpointName} with command {command}, arguments {arguments}, environment {environment}, working directory {workingDirectory}, shutdown timeout {shutdownTimeout}")]
|
[LoggerMessage(Level = LogLevel.Information, Message = "Creating process for transport for {endpointName} with command {command}, arguments {arguments}, environment {environment}, working directory {workingDirectory}, shutdown timeout {shutdownTimeout}")]
|
||||||
internal static partial void CreateProcessForTransport(this ILogger logger, string endpointName, string command, string? arguments, string environment, string workingDirectory, string shutdownTimeout);
|
internal static partial void CreateProcessForTransport(this ILogger logger, string endpointName, string command, string? arguments, string environment, string workingDirectory, string shutdownTimeout);
|
||||||
|
|
||||||
[LoggerMessage(Level = LogLevel.Error, Message = "Transport for {endpointName} error: {data}")]
|
[LoggerMessage(Level = LogLevel.Information, Message = "Transport for {endpointName} received stderr log: {data}")]
|
||||||
internal static partial void TransportError(this ILogger logger, string endpointName, string data);
|
internal static partial void ReadStderr(this ILogger logger, string endpointName, string data);
|
||||||
|
|
||||||
[LoggerMessage(Level = LogLevel.Information, Message = "Transport process start failed for {endpointName}")]
|
[LoggerMessage(Level = LogLevel.Information, Message = "Transport process start failed for {endpointName}")]
|
||||||
internal static partial void TransportProcessStartFailed(this ILogger logger, string endpointName);
|
internal static partial void TransportProcessStartFailed(this ILogger logger, string endpointName);
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@ public sealed class StdioClientTransport : IClientTransport
|
||||||
process = new() { StartInfo = startInfo };
|
process = new() { StartInfo = startInfo };
|
||||||
|
|
||||||
// Set up error logging
|
// Set up error logging
|
||||||
process.ErrorDataReceived += (sender, args) => logger.TransportError(endpointName, args.Data ?? "(no data)");
|
process.ErrorDataReceived += (sender, args) => logger.ReadStderr(endpointName, args.Data ?? "(no data)");
|
||||||
|
|
||||||
// We need both stdin and stdout to use a no-BOM UTF-8 encoding. On .NET Core,
|
// We need both stdin and stdout to use a no-BOM UTF-8 encoding. On .NET Core,
|
||||||
// we can use ProcessStartInfo.StandardOutputEncoding/StandardInputEncoding, but
|
// we can use ProcessStartInfo.StandardOutputEncoding/StandardInputEncoding, but
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,10 @@ internal static class Program
|
||||||
|
|
||||||
return LoggerFactory.Create(builder =>
|
return LoggerFactory.Create(builder =>
|
||||||
{
|
{
|
||||||
|
builder.AddConsole(options =>
|
||||||
|
{
|
||||||
|
options.LogToStandardErrorThreshold = LogLevel.Trace;
|
||||||
|
});
|
||||||
builder.AddSerilog();
|
builder.AddSerilog();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue