Skip to content
bitzorcas
中EN

Concept

Agent Governance & Multi-Tenant Security

In-depth architecture of MCP Agent governance in BitzOrcas.Modern: multi-tenant isolation, dynamic visibility filtering, concurrency rate limiting, and Human-in-the-Loop (HITL) approval.

Last updated

Agent Governance & Multi-Tenant Security

When Large Language Models gain the autonomy to execute write operations directly against enterprise backends, system security must confront new attack surfaces:

  • Tenant Isolation Breach: Prompt injection manipulating the model into accessing or modifying records across corporate tenant boundaries;
  • Unauthorized Feature Access: Unlicensed tenants discovering and invoking premium tools (e.g., automated cross-border billing or compliance audits);
  • Agentic Loops & DoS: Infinite reasoning loops triggering high-frequency tool invocations against database endpoints;
  • Destructive Autonomous Actions: Unsupervised models executing irreversible large payouts, bulk deletions, or settlement agreements.

BitzOrcas.Modern implements a defense-in-depth, fail-closed governance architecture ensuring all AI-driven actions undergo security policies equal to or stricter than human operator sessions.


1. Tenant-Level Access Gate: McpTenantAccessGate

Before any MCP JSON-RPC payload reaches the partition aggregator, McpTenantAccessRequirement evaluates authorization during ASP.NET Core middleware processing:

using BitzOrcas.Application.Tenancy;
using Microsoft.AspNetCore.Authorization;
namespace BitzOrcas.Infrastructure.Mcp;
/// <summary>
/// Tenant-level MCP authorization gate (Fail-Closed)
/// </summary>
public sealed class McpTenantAccessAuthorizationHandler : AuthorizationHandler<McpTenantAccessRequirement>
{
private readonly ITenantContext _tenantContext;
private readonly ITenantFeatureEvaluator _featureEvaluator;
public McpTenantAccessAuthorizationHandler(
ITenantContext tenantContext,
ITenantFeatureEvaluator featureEvaluator)
{
_tenantContext = tenantContext;
_featureEvaluator = featureEvaluator;
}
protected override async Task HandleRequirementAsync(
AuthorizationHandlerContext context,
McpTenantAccessRequirement requirement)
{
// 1. Verify that the caller identity is authenticated via JWT or verified credential
if (context.User.Identity?.IsAuthenticated != true)
{
context.Fail();
return;
}
// 2. Validate tenant context existence and active status
if (!_tenantContext.HasActiveTenant)
{
context.Fail();
return;
}
// 3. Verify that the tenant is licensed for MCP Agent access
var isEntitled = await _featureEvaluator.IsFeatureEnabledAsync("mcp.access");
if (!isEntitled)
{
context.Fail();
return;
}
context.Succeed(requirement);
}
}

Calls lacking the mcp.access feature fail immediately with 403 Forbidden without exposing tool discovery or dispatch pathways.


2. Dynamic Tool Visibility Filtering (McpToolListVisibilityFilter)

During initialization, models issue tools/list to discover callable capabilities. Exposing the entire system tool graph wastes model context tokens and reveals unauthorized system topology.

BitzOrcas trims the visible tool tree dynamically according to tenant subscription and caller permissions:

using BitzOrcas.Application.Authorization;
using BitzOrcas.Mcp.Abstractions;
namespace BitzOrcas.Infrastructure.Mcp;
/// <summary>
/// Filters the tool list based on tenant features and caller RBAC permissions
/// </summary>
public sealed class McpToolListVisibilityFilter
{
private readonly IPermissionEvaluator _permissionEvaluator;
public McpToolListVisibilityFilter(IPermissionEvaluator permissionEvaluator)
{
_permissionEvaluator = permissionEvaluator;
}
public async Task<IReadOnlyList<McpToolDefinition>> FilterVisibleToolsAsync(
IReadOnlyList<McpToolDefinition> allTools,
CancellationToken cancellationToken)
{
var visibleTools = new List<McpToolDefinition>(allTools.Count);
foreach (var tool in allTools)
{
// Verify permission if the tool declares an authorization prerequisite
if (tool.RequiredPermission is not null)
{
var hasPermission = await _permissionEvaluator.HasPermissionAsync(tool.RequiredPermission, cancellationToken);
if (!hasPermission)
{
continue; // Ineligible tools are omitted from the tools/list payload
}
}
visibleTools.Add(tool);
}
return visibleTools;
}
}

3. Dedicated Invocation Audit Trails (McpToolInvocationAuditor)

All mutations initiated by AI models require immutable legal-grade audit logging.

McpToolInvocationAuditor records these facts:

  1. Model Session Trace: Correlated TraceId and caller session token;
  2. Payload Fingerprint: Cryptographic SHA256 hash of raw input JSON, preventing cleartext PII contamination in logs;
  3. Latency: Millisecond-level execution duration;
  4. Outcome: Success or standardized domain ErrorCode.
using System.Diagnostics;
using System.Security.Cryptography;
using System.Text;
using BitzOrcas.Application.Tenancy;
using Microsoft.Extensions.Logging;
namespace BitzOrcas.Infrastructure.Mcp;
/// <summary>
/// Dedicated auditor capturing MCP tool execution facts
/// </summary>
public sealed class McpToolInvocationAuditor
{
private readonly ILogger<McpToolInvocationAuditor> _logger;
private readonly ITenantContext _tenantContext;
public McpToolInvocationAuditor(ILogger<McpToolInvocationAuditor> logger, ITenantContext tenantContext)
{
_logger = logger;
_tenantContext = tenantContext;
}
public async Task RecordInvocationAsync(
string toolName,
string rawJsonPayload,
bool isSuccess,
long elapsedMilliseconds,
string? failureReason)
{
var payloadHash = Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(rawJsonPayload)));
_logger.LogInformation(
"MCP Tool Invocation Audit: [Tenant: {TenantId}] [Tool: {ToolName}] [Success: {Success}] [Elapsed: {Elapsed}ms] [PayloadHash: {Hash}] [Error: {Reason}]",
_tenantContext.TenantId,
toolName,
isSuccess,
elapsedMilliseconds,
payloadHash,
failureReason ?? "None");
await Task.CompletedTask;
}
}

4. Human-in-the-Loop (HITL) Verification

For operations involving substantial financial transfers, irreversible record destruction, or binding legal filings, models are strictly prohibited from immediate final execution.

The framework enforces the Prepare & Confirm Pattern:

  1. Stage 1 (Prepare): The model invokes prepare_financial_payout, creating a pending review entry with an ID (e.g., PO-2026-0901);
  2. Stage 2 (Review & Confirm):
    • The model prompts the operator: “Draft payout order PO-2026-0901 for ¥1,200,000 has been prepared. Please confirm via your hardware token or administrative portal.”
    • Execution proceeds only after an authorized human confirms via MFA Step-Up authentication.

100%

Scroll or use controls to zoom · drag when enlarged · double-click for 100% / 200%