using Microsoft.Extensions.DependencyInjection; using ModelContextProtocol.Protocol; using System.Security.Claims; namespace ModelContextProtocol.Server; /// Augments a service provider with additional request-related services. internal sealed class RequestServiceProvider(RequestContext request) : IServiceProvider, IKeyedServiceProvider, IServiceProviderIsService, IServiceProviderIsKeyedService, IDisposable, IAsyncDisposable where TRequestParams : RequestParams { private readonly IServiceProvider? _innerServices = request.Services; /// Gets the request associated with this instance. public RequestContext Request => request; /// Gets whether the specified type is in the list of additional types this service provider wraps around the one in a provided request's services. public static bool IsAugmentedWith(Type serviceType) => serviceType == typeof(RequestContext) || serviceType == typeof(McpServer) || serviceType == typeof(IProgress) || serviceType == typeof(ClaimsPrincipal); /// public object? GetService(Type serviceType) => serviceType == typeof(RequestContext) ? request : serviceType == typeof(McpServer) ? request.Server : serviceType == typeof(IProgress) ? (request.Params?.ProgressToken is { } progressToken ? new TokenProgress(request.Server, progressToken) : NullProgress.Instance) : serviceType == typeof(ClaimsPrincipal) ? request.User : _innerServices?.GetService(serviceType); /// public bool IsService(Type serviceType) => IsAugmentedWith(serviceType) || (_innerServices as IServiceProviderIsService)?.IsService(serviceType) is true; /// public bool IsKeyedService(Type serviceType, object? serviceKey) => (serviceKey is null && IsService(serviceType)) || (_innerServices as IServiceProviderIsKeyedService)?.IsKeyedService(serviceType, serviceKey) is true; /// public object? GetKeyedService(Type serviceType, object? serviceKey) => serviceKey is null ? GetService(serviceType) : (_innerServices as IKeyedServiceProvider)?.GetKeyedService(serviceType, serviceKey); /// public object GetRequiredKeyedService(Type serviceType, object? serviceKey) => GetKeyedService(serviceType, serviceKey) ?? throw new InvalidOperationException($"No service of type '{serviceType}' with key '{serviceKey}' is registered."); /// public void Dispose() => (_innerServices as IDisposable)?.Dispose(); /// public ValueTask DisposeAsync() => _innerServices is IAsyncDisposable asyncDisposable ? asyncDisposable.DisposeAsync() : default; }