microsoft/aspire · error · ArgumentException
An MCP approval policy must specify a global mode or at…
Error message
An MCP approval policy must specify a global mode or at least one custom filter.
What it means
An approval policy must say something: either a Global mode or at least one non-empty custom filter. If Global is null and both Always and Never filters are null (or resolve to nothing), ResolvedFoundryToolboxMcpApprovalPolicy.Create throws this ArgumentException because an empty policy has no representable wire form for require_approval.
Solutions
- Set Global = FoundryToolboxMcpGlobalApprovalMode.Never (or Always) on the policy.
- Add at least one tool name to Always.ToolNames or Never.ToolNames, or set ReadOnly on a filter.
- Pass null for ApprovalPolicy instead of an empty policy object if no approval behavior is desired.
- Log/inspect the policy object before constructing the tool definition.
Example fix
// before
new FoundryToolboxMcpApprovalPolicy { }
// after
new FoundryToolboxMcpApprovalPolicy { Global = FoundryToolboxMcpGlobalApprovalMode.Never } Defensive patterns
Strategy: validation
Validate before calling
bool hasSomething = policy.Global is not null || policy.Always is not null || policy.Never is not null;
if (!hasSomething) throw new ArgumentException("Policy must specify a global mode or a filter."); Type guard
static bool IsPopulated(FoundryToolboxMcpApprovalPolicy p) =>
p.Global is not null || p.Always is not null || p.Never is not null; Try / catch
try { toolDefinition = CreateMcpTool(...); }
catch (ArgumentException ex) when (ex.Message.Contains("must specify a global mode or at least one custom filter"))
{ logger.LogError("Approval policy is empty; set Global or add filters."); } Prevention
- Never pass a default-initialized policy object; pass null if no policy is wanted
- After deserializing policy config, assert at least one field is set
- Initialize with Global = Never as a safe default
When it happens
Trigger: new FoundryToolboxMcpApprovalPolicy() with every property left null; passing a default-initialized options object with ApprovalPolicy set but unpopulated; supplying filters whose ToolNames are empty and ReadOnly is null (those resolve to null filters, triggering this error).
Common situations: Declaring the policy object but forgetting to set any field; deserializing policy config from JSON where all keys were absent; conditionally adding filters that all ended up skipped.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- A global MCP approval policy cannot be combined with custom…
- An MCP approval filter must specify at least one tool name…
- MCP tool ' ' cannot both always and never require approval.
- MCP tools with read_only set to
- The global MCP approval mode is not supported.
AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16).
Data as JSON: /api/errors/84f24cb94be92ddf.
Report an issue: GitHub.
Appendix: source
Thrown at src/Aspire.Hosting.Foundry/Toolbox/FoundryToolboxToolDefinition.cs:234
}
var always = ResolvedFoundryToolboxMcpApprovalFilter.Create(
policy.Always,
nameof(policy.Always));
var never = ResolvedFoundryToolboxMcpApprovalFilter.Create(
policy.Never,
nameof(policy.Never));
if (policy.Global is not null && (always is not null || never is not null))
{
throw new ArgumentException(
"A global MCP approval policy cannot be combined with custom filters.",
nameof(policy));
}
if (policy.Global is null && always is null && never is null)
{
throw new ArgumentException(
"An MCP approval policy must specify a global mode or at least one custom filter.",
nameof(policy));
}
if (policy.Global is not null &&
policy.Global is not FoundryToolboxMcpGlobalApprovalMode.Never &&
policy.Global is not FoundryToolboxMcpGlobalApprovalMode.Always)
{
throw new ArgumentOutOfRangeException(
nameof(policy),
policy.Global,
"The global MCP approval mode is not supported.");
}
var overlap = always?.ToolNames
.Intersect(never?.ToolNames ?? [], StringComparer.Ordinal)
.FirstOrDefault();
if (overlap is not null)View on GitHub (pinned to 25830f84bd)