Skip to content

Commit 20ab476

Browse files
committed
Improving how to setup logging and implementing logging handler
1 parent 8f318f5 commit 20ab476

File tree

4 files changed

+100
-1
lines changed

4 files changed

+100
-1
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
using Microsoft.Extensions.DependencyInjection;
2+
using Microsoft.Extensions.Hosting;
3+
using ModelContextProtocol.Protocol.Messages;
4+
using ModelContextProtocol.Protocol.Types;
5+
using ModelContextProtocol.Server;
6+
7+
namespace EverythingServer;
8+
9+
public class LoggingUpdateMessageSender(IMcpServer server) : IHostedService
10+
{
11+
readonly Dictionary<LoggingLevel, string> _loggingLevelMap = new()
12+
{
13+
{ LoggingLevel.Debug, "Debug-level message" },
14+
{ LoggingLevel.Info, "Info-level message" },
15+
{ LoggingLevel.Notice, "Notice-level message" },
16+
{ LoggingLevel.Warning, "Warning-level message" },
17+
{ LoggingLevel.Error, "Error-level message" },
18+
{ LoggingLevel.Critical, "Critical-level message" },
19+
{ LoggingLevel.Alert, "Alert-level message" },
20+
{ LoggingLevel.Emergency, "Emergency-level message" }
21+
};
22+
23+
public async Task StartAsync(CancellationToken cancellationToken)
24+
{
25+
var currentLevel = server.Services!.GetRequiredService<Func<LoggingLevel>>();
26+
27+
while (!cancellationToken.IsCancellationRequested)
28+
{
29+
var newLevel = (LoggingLevel)Enum.GetValues<LoggingLevel>().GetValue(new Random().Next(0, Enum.GetValues(typeof(LoggingLevel)).Length))!;
30+
31+
var message = new JsonRpcNotification
32+
{
33+
Method = "notifications/message",
34+
Params = new
35+
{
36+
Level = newLevel.ToString().ToLower(),
37+
Data = _loggingLevelMap[newLevel],
38+
}
39+
};
40+
41+
if (newLevel > currentLevel())
42+
{
43+
await server.SendMessageAsync(message, cancellationToken);
44+
}
45+
46+
await Task.Delay(15000, cancellationToken);
47+
}
48+
}
49+
50+
public Task StopAsync(CancellationToken cancellationToken)
51+
{
52+
return Task.CompletedTask;
53+
}
54+
}

samples/EverythingServer/Program.cs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@
66
using Microsoft.Extensions.DependencyInjection;
77
using EverythingServer.Prompts;
88
using EverythingServer.Tools;
9+
using ModelContextProtocol.Protocol.Messages;
910

1011
var builder = Host.CreateEmptyApplicationBuilder(settings: null);
1112

1213
HashSet<string> subscriptions = [];
14+
var _minimumLoggingLevel = LoggingLevel.Debug;
1315

1416
builder.Services
1517
.AddMcpServer()
@@ -158,6 +160,28 @@ await ctx.Server.RequestSamplingAsync([
158160

159161
throw new NotSupportedException($"Unknown reference type: {@ref.Type}");
160162
})
163+
.WithSetLoggingLevelHandler(async (ctx, ct) =>
164+
{
165+
if (ctx.Params?.Level is null)
166+
{
167+
throw new McpServerException("Missing required argument 'level'");
168+
}
169+
170+
_minimumLoggingLevel = ctx.Params.Level;
171+
172+
await ctx.Server.SendMessageAsync(new JsonRpcNotification
173+
{
174+
Method = "notifications/message",
175+
Params = new
176+
{
177+
Level = "debug",
178+
Logger = "test-server",
179+
Data = $"Logging level set to {_minimumLoggingLevel}",
180+
}
181+
}, ct);
182+
183+
return new EmptyResult();
184+
})
161185
;
162186

163187
builder.Services.AddHostedService(sp =>
@@ -166,4 +190,12 @@ await ctx.Server.RequestSamplingAsync([
166190
return new SubscriptionMessageSender(server, subscriptions);
167191
});
168192

193+
builder.Services.AddHostedService(sp =>
194+
{
195+
var server = sp.GetRequiredService<IMcpServer>();
196+
return new LoggingUpdateMessageSender(server);
197+
});
198+
199+
builder.Services.AddScoped<Func<LoggingLevel>>(_ => () => _minimumLoggingLevel);
200+
169201
await builder.Build().RunAsync();

src/ModelContextProtocol/Configuration/McpServerBuilderExtensions.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ public static IMcpServerBuilder WithSubscribeToResourcesHandler(this IMcpServerB
314314
}
315315

316316
/// <summary>
317-
/// Sets or sets the handler for subscribe to resources messages.
317+
/// Sets the handler for subscribe to resources messages.
318318
/// </summary>
319319
/// <param name="builder">The builder instance.</param>
320320
/// <param name="handler">The handler.</param>
@@ -325,6 +325,18 @@ public static IMcpServerBuilder WithUnsubscribeFromResourcesHandler(this IMcpSer
325325
builder.Services.Configure<McpServerHandlers>(s => s.UnsubscribeFromResourcesHandler = handler);
326326
return builder;
327327
}
328+
329+
/// <summary>
330+
/// Sets the handler for setting the logging level.
331+
/// </summary>
332+
/// <param name="builder">The builder instance.</param>
333+
/// <param name="handler">The handler.</param>
334+
public static IMcpServerBuilder WithSetLoggingLevelHandler(this IMcpServerBuilder builder, Func<RequestContext<SetLevelRequestParams>, CancellationToken, Task<EmptyResult>> handler)
335+
{
336+
Throw.IfNull(builder);
337+
builder.Services.Configure<McpServerHandlers>(s => s.SetLoggingLevelHandler = handler);
338+
return builder;
339+
}
328340
#endregion
329341

330342
#region Transports

src/ModelContextProtocol/Server/McpServerHandlers.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ internal void OverwriteWithSetHandlers(McpServerOptions options)
113113
options.Capabilities.Prompts = promptsCapability;
114114
options.Capabilities.Resources = resourcesCapability;
115115
options.Capabilities.Tools = toolsCapability;
116+
options.Capabilities.Logging = loggingCapability;
116117

117118
options.GetCompletionHandler = GetCompletionHandler ?? options.GetCompletionHandler;
118119
}

0 commit comments

Comments
 (0)