2026-10-09 17:02:27 +00:00
|
|
|
|
using System;
|
2026-09-24 11:58:23 +00:00
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
using Microsoft.Extensions.Localization;
|
|
|
|
|
|
using Sozsoft.Platform.Localization;
|
|
|
|
|
|
using Volo.Abp;
|
|
|
|
|
|
using Volo.Abp.Authorization;
|
|
|
|
|
|
using Volo.Abp.Authorization.Permissions;
|
|
|
|
|
|
using Volo.Abp.DependencyInjection;
|
|
|
|
|
|
|
|
|
|
|
|
namespace Sozsoft.Mcp;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2026-10-09 17:02:27 +00:00
|
|
|
|
/// Arac hatalarini istemcinin gorebilecegi mesaja cevirir. SDK cevrilmemis istisnayi
|
|
|
|
|
|
/// "An error occurred invoking" olarak iletir ve model neden reddedildigini bilemez. Yetki reddinde eksik yetkiler adiyla, is kurali hatasinda
|
2026-09-24 11:58:23 +00:00
|
|
|
|
/// (<see cref="UserFriendlyException"/>) zaten yerellestirilmis mesaj iletilir. Diger istisnalar
|
|
|
|
|
|
/// cevrilmez: ic ayrinti (SQL, yigin) istemciye sizmaz.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public class McpToolErrorTranslator(
|
|
|
|
|
|
IPermissionChecker permissionChecker,
|
|
|
|
|
|
IStringLocalizer<PlatformResource> localizer) : ITransientDependency
|
|
|
|
|
|
{
|
|
|
|
|
|
public static bool CanTranslate(Exception exception)
|
|
|
|
|
|
=> exception is AbpAuthorizationException or UserFriendlyException;
|
|
|
|
|
|
|
2026-10-09 17:02:27 +00:00
|
|
|
|
public async Task<string> TranslateAsync(Exception exception, string? toolName)
|
2026-09-24 11:58:23 +00:00
|
|
|
|
=> exception is AbpAuthorizationException authorization
|
2026-10-09 17:02:27 +00:00
|
|
|
|
? await DescribeMissingPermissionsAsync(authorization, toolName)
|
|
|
|
|
|
: exception.Message;
|
2026-09-24 11:58:23 +00:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <c>CheckAsync("...")</c> reddi yetki adini tasir; <c>[Authorize]</c> attribute'u tasimaz. Ikinci
|
|
|
|
|
|
/// durumda aracin adi bilinen yetkileri kullanicinin yetkileriyle karsilastirilir.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private async Task<string> DescribeMissingPermissionsAsync(AbpAuthorizationException exception, string? toolName)
|
|
|
|
|
|
{
|
|
|
|
|
|
var candidates = new List<string>(McpToolNames.KnownPermissionsOf(toolName));
|
|
|
|
|
|
if (exception.Data["PolicyName"] is string policyName && !string.IsNullOrWhiteSpace(policyName))
|
|
|
|
|
|
{
|
|
|
|
|
|
candidates.Add(policyName);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var grants = await permissionChecker.IsGrantedAsync([.. candidates.Distinct(StringComparer.Ordinal)]);
|
|
|
|
|
|
var missing = grants.Result
|
|
|
|
|
|
.Where(result => result.Value != PermissionGrantResult.Granted)
|
|
|
|
|
|
.Select(result => Describe(result.Key))
|
|
|
|
|
|
.ToList();
|
|
|
|
|
|
|
|
|
|
|
|
var target = toolName ?? McpConsts.EndpointPath;
|
|
|
|
|
|
|
|
|
|
|
|
return missing.Count == 0
|
|
|
|
|
|
? localizer[McpErrorCodes.PermissionDeniedUnspecified, target]
|
|
|
|
|
|
: localizer[McpErrorCodes.PermissionDenied, target, string.Join(", ", missing)];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>Yetkinin gorunen adi ve kodu; rol ekraninda aranabilsin diye kod her zaman yazilir.</summary>
|
|
|
|
|
|
private string Describe(string permissionName)
|
|
|
|
|
|
{
|
|
|
|
|
|
var displayName = localizer[permissionName];
|
|
|
|
|
|
|
|
|
|
|
|
return displayName.ResourceNotFound || displayName.Value == permissionName
|
|
|
|
|
|
? permissionName
|
|
|
|
|
|
: $"{displayName.Value} ({permissionName})";
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|