microsoft/aspire · error · ArgumentException

An MCP approval filter must specify at least one tool name…

Error message

An MCP approval filter must specify at least one tool name or a read-only value.

What it means

ResolvedFoundryToolboxMcpApprovalFilter.Create normalizes and deduplicates ToolNames, then requires that the filter actually selects something: at least one tool name, or a non-null ReadOnly value. A filter with no names and no ReadOnly has no wire representation, so an ArgumentException naming the offending property (Always or Never) is thrown.

Solutions

  1. Add at least one tool name to ToolNames.
  2. Set ReadOnly = true (or false) on the filter.
  3. Pass null for the filter instead of an empty one.
  4. Log the filter contents before creating the policy to confirm names loaded from config.

Example fix

// before
new FoundryToolboxMcpApprovalFilter { ToolNames = [] }
// after
new FoundryToolboxMcpApprovalFilter { ToolNames = ["search"], ReadOnly = false }
Defensive patterns

Strategy: validation

Validate before calling

bool selects = filter.ToolNames is { Count: > 0 } || filter.ReadOnly is not null;
if (!selects) throw new ArgumentException("Filter needs a tool name or a read_only value.");

Type guard

static bool IsMeaningful(FoundryToolboxMcpApprovalFilter f) =>
    (f.ToolNames is { Count: > 0 }) || f.ReadOnly is not null;

Try / catch

try { toolDefinition = CreateMcpTool(...); }
catch (ArgumentException ex) when (ex.Message.Contains("at least one tool name or a read-only value"))
{ logger.LogError("Approval filter {Param} is empty; add tool names or set ReadOnly.", ex.ParamName); }

Prevention

When it happens

Trigger: Passing new FoundryToolboxMcpApprovalFilter { ToolNames = [] } (or null ToolNames) with ReadOnly unset as policy.Always or policy.Never; a filter whose entries were all whitespace (those throw earlier via ThrowIfNullOrWhiteSpace) or deduplicated away to zero.

Common situations: Deserialized config where tool_names was an empty array; code that builds the filter conditionally and adds no names; YAML/JSON tool lists that failed to bind.

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


AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16). Data as JSON: /api/errors/7cf5f52b56369104. Report an issue: GitHub.

Appendix: source

Thrown at src/Aspire.Hosting.Foundry/Toolbox/FoundryToolboxToolDefinition.cs:314

    {
        if (filter is null)
        {
            return null;
        }

        var toolNames = (filter.ToolNames ?? [])
            .Select(name =>
            {
                ArgumentException.ThrowIfNullOrWhiteSpace(name, parameterName);
                return name;
            })
            .Distinct(StringComparer.Ordinal)
            .Order(StringComparer.Ordinal)
            .ToArray();

        if (toolNames.Length == 0 && filter.ReadOnly is null)
        {
            throw new ArgumentException(
                "An MCP approval filter must specify at least one tool name or a read-only value.",
                parameterName);
        }

        return new(toolNames, filter.ReadOnly);
    }

    public void WriteTo(Utf8JsonWriter writer, string propertyName)
    {
        writer.WriteStartObject(propertyName);
        if (ToolNames.Count > 0)
        {
            writer.WriteStartArray("tool_names");
            foreach (var toolName in ToolNames)
            {
                writer.WriteStringValue(toolName);
            }
            writer.WriteEndArray();

View on GitHub (pinned to 25830f84bd)