sozsoft-platform/api/modules/Sozsoft.Mcp/Sozsoft.Mcp.Application/McpAppService.cs

99 lines
3.6 KiB
C#
Raw Permalink Normal View History

2026-09-17 09:01:14 +00:00
using System;
2026-09-18 13:47:23 +00:00
using System.Linq;
2026-09-17 09:01:14 +00:00
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;
/// <summary>
/// MCP uygulama servislerinin ortak tabani. Kullaniciya gorunen metinler platformun
/// <c>PlatformResource</c> kaynagindan okunur; sunucu kaydini cozme ve arac kapisi her
/// serviste ayni davranir.
/// </summary>
public abstract class McpAppService : ApplicationService
{
protected IMcpServerConfigProvider ServerConfigProvider { get; }
protected McpAppService(IMcpServerConfigProvider serverConfigProvider)
{
ServerConfigProvider = serverConfigProvider;
LocalizationResource = typeof(PlatformResource);
}
/// <summary>Etkin sunucu kaydinin DTO hali; kayit yoksa null.</summary>
protected async Task<McpServerConfigDto?> 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
};
}
/// <summary>
2026-10-10 22:03:36 +00:00
/// 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
2026-09-17 09:01:14 +00:00
/// yeterli degildir — istemci listede olmayan bir araci da cagirabilir.
/// </summary>
2026-10-10 22:03:36 +00:00
protected async Task<McpOutcome<McpServerConfigDto>> EnsureToolAllowedAsync(string toolName)
2026-09-17 09:01:14 +00:00
{
2026-10-10 22:03:36 +00:00
var config = await ResolveServerConfigAsync();
if (config is null)
{
return Problem(McpErrorCodes.NoServerRecord);
}
2026-09-17 09:01:14 +00:00
2026-09-18 13:47:23 +00:00
if (CurrentTenant.IsAvailable && !McpToolNames.TenantTools.Contains(toolName, StringComparer.Ordinal))
{
2026-10-10 22:03:36 +00:00
return Problem(McpErrorCodes.TenantToolDisabled, toolName);
2026-09-18 13:47:23 +00:00
}
if (!McpToolPolicy.IsAllowed(true, CurrentTenant.IsAvailable, config.AllowedTools, toolName))
2026-09-17 09:01:14 +00:00
{
2026-10-10 22:03:36 +00:00
return Problem(McpErrorCodes.ToolDisabled, toolName, config.Name);
2026-09-17 09:01:14 +00:00
}
2026-10-10 22:03:36 +00:00
if (McpToolNames.RequiredPermissions.TryGetValue(toolName, out var permission) &&
await CheckPermissionAsync(toolName, permission) is { } denied)
2026-09-17 09:01:14 +00:00
{
2026-10-10 22:03:36 +00:00
return denied;
2026-09-17 09:01:14 +00:00
}
return config;
}
2026-10-10 22:03:36 +00:00
/// <summary>
/// Yetkiyi adiyla ister; eksikse istemcinin rol ekraninda arayabilecegi ad ve kodla reddeder.
/// <c>AuthorizationService.CheckAsync</c> istisna atar, bu yuzden MCP'de kullanilmaz.
/// </summary>
protected async Task<McpProblem?> 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);
2026-09-17 09:01:14 +00:00
/// <summary>Istenen satir sayisini sunucu kaydindaki tavana kirpar.</summary>
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;
}
}