using System; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Sozsoft.Mcp.Dtos; using Sozsoft.Mcp.Services; using Sozsoft.Platform.Localization; using Volo.Abp.Application.Services; namespace Sozsoft.Mcp; /// /// MCP uygulama servislerinin ortak tabani. Kullaniciya gorunen metinler platformun /// PlatformResource kaynagindan okunur; sunucu kaydini cozme ve arac kapisi her /// serviste ayni davranir. /// public abstract class McpAppService : ApplicationService { protected IMcpServerConfigProvider ServerConfigProvider { get; } protected McpAppService(IMcpServerConfigProvider serverConfigProvider) { ServerConfigProvider = serverConfigProvider; LocalizationResource = typeof(PlatformResource); } /// Etkin sunucu kaydinin DTO hali; kayit yoksa null. protected async Task ResolveServerConfigAsync() { var server = await ServerConfigProvider.GetEffectiveServerAsync(); if (server is null) { return null; } return new McpServerConfigDto { Name = server.Name, Url = server.Url, AllowedTools = [.. ServerConfigProvider.SplitMultiValue(server.AllowedTools)], MaxRows = server.MaxRows, Description = server.Description, TenantName = CurrentTenant.Name }; } /// /// Kapali bir araca yapilan cagriyi reddeder: sunucu kaydi yoksa, arac sunucu kaydinda kapaliysa /// ya da kullanicinin uygulamada karsilik gelen yetkisi yoksa. Arac listesini suzmek tek basina /// yeterli degildir — istemci listede olmayan bir araci da cagirabilir. /// protected async Task> EnsureToolAllowedAsync(string toolName) { var config = await ResolveServerConfigAsync(); if (config is null) { return Problem(McpErrorCodes.NoServerRecord); } if (CurrentTenant.IsAvailable && !McpToolNames.TenantTools.Contains(toolName, StringComparer.Ordinal)) { return Problem(McpErrorCodes.TenantToolDisabled, toolName); } if (!McpToolPolicy.IsAllowed(true, CurrentTenant.IsAvailable, config.AllowedTools, toolName)) { return Problem(McpErrorCodes.ToolDisabled, toolName, config.Name); } if (McpToolNames.RequiredPermissions.TryGetValue(toolName, out var permission) && await CheckPermissionAsync(toolName, permission) is { } denied) { return denied; } return config; } /// /// Yetkiyi adiyla ister; eksikse istemcinin rol ekraninda arayabilecegi ad ve kodla reddeder. /// AuthorizationService.CheckAsync istisna atar, bu yuzden MCP'de kullanilmaz. /// protected async Task CheckPermissionAsync(string toolName, string permission) => await AuthorizationService.IsGrantedAsync(permission) ? null : Problem(McpErrorCodes.PermissionDenied, toolName, McpPermissionText.Describe(L, permission)); protected McpProblem Problem(string name, params object[] arguments) => McpProblem.From(L, name, arguments); /// Istenen satir sayisini sunucu kaydindaki tavana kirpar. protected static int ResolveMaxRows(McpServerConfigDto config, int requested) { var ceiling = config.MaxRows > 0 ? config.MaxRows : McpConsts.DefaultMaxRows; return requested > 0 ? Math.Min(requested, ceiling) : ceiling; } }