microsoft/aspire · error · ArgumentException
MCP tool ' ' cannot both always and never require approval.
Error message
MCP tool '{overlap}' cannot both always and never require approval. What it means
A single tool name appearing in both the Always and Never approval filters is contradictory — Foundry could not decide whether that tool requires approval. Create detects the first ordinal-intersection name and throws an ArgumentException naming the policy parameter.
Solutions
- Remove the conflicting tool name from one of the two lists.
- Reclassify the tool into exactly one bucket (always or never).
- Compute the lists programmatically so never = allTools - alwaysTools, guaranteeing disjoint sets.
- Catch ArgumentException and surface the offending overlap name (it is in the message) to fix config.
Example fix
// before
Always = new() { ToolNames = ["delete", "write"] },
Never = new() { ToolNames = ["delete"] }
// after
Always = new() { ToolNames = ["delete", "write"] },
Never = new() { ToolNames = ["read"] } Defensive patterns
Strategy: validation
Validate before calling
var overlap = always.ToolNames.Intersect(never.ToolNames, StringComparer.Ordinal).FirstOrDefault();
if (overlap is not null) throw new ArgumentException($"'{overlap}' is in both always and never filters."); Type guard
static bool Disjoint(FoundryToolboxMcpApprovalFilter a, FoundryToolboxMcpApprovalFilter? n) =>
n is null || !a.ToolNames.Intersect(n.ToolNames ?? [], StringComparer.Ordinal).Any(); Try / catch
try { toolDefinition = CreateMcpTool(...); }
catch (ArgumentException ex) when (ex.Message.Contains("cannot both always and never require approval"))
{ logger.LogError("Remove the conflicting tool from one filter: {Message}", ex.Message); } Prevention
- Derive never-lists as complements of always-lists to guarantee disjointness
- Deduplicate tool lists loaded from multiple config sources
- Test policies built from merged config before deploy
When it happens
Trigger: Building Always.ToolNames and Never.ToolNames from overlapping sources (e.g. a default list plus an exception list) so a tool like 'delete_item' ends up in both arrays.
Common situations: Merging filter lists from multiple config sources without deduplication by category; a rename causing the same tool to match two different filter rules; templated policy generation producing overlapping sets.
Understand the failure class
Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.
Related errors
- MCP tools with read_only set to
- A global MCP approval policy cannot be combined with custom…
- An MCP approval policy must specify a global mode or at…
- The global MCP approval mode is not supported.
- Unsupported MCP approval mode
AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16).
Data as JSON: /api/errors/bf80efcef0e3388a.
Report an issue: GitHub.
Appendix: source
Thrown at src/Aspire.Hosting.Foundry/Toolbox/FoundryToolboxToolDefinition.cs:254
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)
{
throw new ArgumentException(
$"MCP tool '{overlap}' cannot both always and never require approval.",
nameof(policy));
}
if (always?.ReadOnly is { } alwaysReadOnly && never?.ReadOnly == alwaysReadOnly)
{
throw new ArgumentException(
$"MCP tools with read_only set to '{alwaysReadOnly.ToString().ToLowerInvariant()}' cannot both always and never require approval.",
nameof(policy));
}
return new(policy.Global, always, never);
}
public void WriteTo(Utf8JsonWriter writer)
{
if (Global is { } global)
{View on GitHub (pinned to 25830f84bd)