microsoft/aspire · error · ArgumentException
MCP tools with read_only set to
Error message
MCP tools with read_only set to '{alwaysReadOnly.ToString().ToLowerInvariant()}' cannot both always and never require approval. What it means
The OpenAI MCP approval filters support a read_only predicate instead of explicit tool names. Setting the same read_only boolean (true in both, or false in both) on the Always and Never filters is contradictory and rejected with this ArgumentException during policy creation.
Solutions
- Keep ReadOnly on only one filter (usually Never for read-only tools).
- Give the two filters different ReadOnly values (true vs false) if both are needed.
- Prefer explicit ToolNames filters instead of the read_only predicate to avoid the overlap.
- Validate policy JSON/config so read_only appears in at most one of always/never.
Example fix
// before
Always = new() { ReadOnly = true },
Never = new() { ReadOnly = true }
// after
Never = new() { ReadOnly = true } Defensive patterns
Strategy: validation
Validate before calling
if (always.ReadOnly is { } ar && never?.ReadOnly == ar)
throw new ArgumentException("read_only cannot be set to the same value on both filters."); Type guard
static bool ReadOnlyNotDuplicated(FoundryToolboxMcpApprovalFilter? a, FoundryToolboxMcpApprovalFilter? n) =>
a?.ReadOnly is null || n?.ReadOnly != a.ReadOnly; Try / catch
try { toolDefinition = CreateMcpTool(...); }
catch (ArgumentException ex) when (ex.Message.Contains("read_only"))
{ logger.LogError("Set read_only on only one of always/never filters."); } Prevention
- Set ReadOnly on at most one filter
- Prefer explicit ToolNames over the read_only predicate when unsure
- Keep always/never filter templates distinct when generating config
When it happens
Trigger: always: { ReadOnly = true } and never: { ReadOnly = true } (or both false) in the same FoundryToolboxMcpApprovalPolicy — e.g. intending 'read-only ops need no approval' but duplicating the flag on both filters.
Common situations: Copy-pasting a filter and only renaming always↔never while keeping ReadOnly set; config-driven filters where the same read_only value was templated into both buckets.
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 tool ' ' cannot both always and never require approval.
- 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/9ae36bdb1f03f107.
Report an issue: GitHub.
Appendix: source
Thrown at src/Aspire.Hosting.Foundry/Toolbox/FoundryToolboxToolDefinition.cs:261
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)
{
writer.WriteStringValue(global switch
{
FoundryToolboxMcpGlobalApprovalMode.Never => "never",
FoundryToolboxMcpGlobalApprovalMode.Always => "always",
_ => throw new InvalidOperationException($"Unsupported MCP approval mode '{global}'.")
});
return;View on GitHub (pinned to 25830f84bd)