using EverythingServer; using EverythingServer.Prompts; using EverythingServer.Resources; using EverythingServer.Tools; using Microsoft.Extensions.AI; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using ModelContextProtocol; using ModelContextProtocol.Protocol; using ModelContextProtocol.Server; using OpenTelemetry; using OpenTelemetry.Logs; using OpenTelemetry.Metrics; using OpenTelemetry.Resources; using OpenTelemetry.Trace; var builder = Host.CreateApplicationBuilder(args); builder.Logging.AddConsole(consoleLogOptions => { // Configure all logs to go to stderr consoleLogOptions.LogToStandardErrorThreshold = LogLevel.Trace; }); HashSet subscriptions = []; var _minimumLoggingLevel = LoggingLevel.Debug; builder.Services .AddMcpServer() .WithStdioServerTransport() .WithTools() .WithTools() .WithTools() .WithTools() .WithTools() .WithTools() .WithTools() .WithPrompts() .WithPrompts() .WithResources() .WithSubscribeToResourcesHandler(async (ctx, ct) => { var uri = ctx.Params?.Uri; if (uri is not null) { subscriptions.Add(uri); await ctx.Server.SampleAsync([ new ChatMessage(ChatRole.System, "You are a helpful test server"), new ChatMessage(ChatRole.User, $"Resource {uri}, context: A new subscription was started"), ], options: new ChatOptions { MaxOutputTokens = 100, Temperature = 0.7f, }, cancellationToken: ct); } return new EmptyResult(); }) .WithUnsubscribeFromResourcesHandler(async (ctx, ct) => { var uri = ctx.Params?.Uri; if (uri is not null) { subscriptions.Remove(uri); } return new EmptyResult(); }) .WithCompleteHandler(async (ctx, ct) => { var exampleCompletions = new Dictionary> { { "style", ["casual", "formal", "technical", "friendly"] }, { "temperature", ["0", "0.5", "0.7", "1.0"] }, { "resourceId", ["1", "2", "3", "4", "5"] } }; if (ctx.Params is not { } @params) { throw new NotSupportedException($"Params are required."); } var @ref = @params.Ref; var argument = @params.Argument; if (@ref is ResourceTemplateReference rtr) { var resourceId = rtr.Uri?.Split("/").Last(); if (resourceId is null) { return new CompleteResult(); } var values = exampleCompletions["resourceId"].Where(id => id.StartsWith(argument.Value)); return new CompleteResult { Completion = new Completion { Values = [.. values], HasMore = false, Total = values.Count() } }; } if (@ref is PromptReference pr) { if (!exampleCompletions.TryGetValue(argument.Name, out IEnumerable? value)) { throw new NotSupportedException($"Unknown argument name: {argument.Name}"); } var values = value.Where(value => value.StartsWith(argument.Value)); return new CompleteResult { Completion = new Completion { Values = [.. values], HasMore = false, Total = values.Count() } }; } throw new NotSupportedException($"Unknown reference type: {@ref.Type}"); }) .WithSetLoggingLevelHandler(async (ctx, ct) => { if (ctx.Params?.Level is null) { throw new McpProtocolException("Missing required argument 'level'", McpErrorCode.InvalidParams); } _minimumLoggingLevel = ctx.Params.Level; await ctx.Server.SendNotificationAsync("notifications/message", new { Level = "debug", Logger = "test-server", Data = $"Logging level set to {_minimumLoggingLevel}", }, cancellationToken: ct); return new EmptyResult(); }); ResourceBuilder resource = ResourceBuilder.CreateDefault().AddService("everything-server"); builder.Services.AddOpenTelemetry() .WithTracing(b => b.AddSource("*").AddHttpClientInstrumentation().SetResourceBuilder(resource)) .WithMetrics(b => b.AddMeter("*").AddHttpClientInstrumentation().SetResourceBuilder(resource)) .WithLogging(b => b.SetResourceBuilder(resource)) .UseOtlpExporter(); builder.Services.AddSingleton(subscriptions); builder.Services.AddHostedService(); builder.Services.AddHostedService(); builder.Services.AddSingleton>(_ => () => _minimumLoggingLevel); await builder.Build().RunAsync();