googleapis/mcp-toolbox · error

%d is not an allowed value

Error message

%d is not an allowed value

What it means

IntParameter.Parse rejects an integer because it is not present in the parameter's allowedValues list. The MCP Toolbox lets tool authors constrain numeric parameters to a fixed set; when an LLM or client supplies a value outside that set, parsing fails with this message. It is an expected validation rejection, not a bug in the library.

Source

Thrown at internal/util/parameters/parameters.go:818

	var out int
	switch newV := v.(type) {
	default:
		return nil, &ParseTypeError{p.Name, p.Type, v}
	case int:
		out = int(newV)
	case int32:
		out = int(newV)
	case int64:
		out = int(newV)
	case json.Number:
		newI, err := newV.Int64()
		if err != nil {
			return nil, &ParseTypeError{p.Name, p.Type, v}
		}
		out = int(newI)
	}
	if !p.IsAllowedValues(out) {
		return nil, fmt.Errorf("%d is not an allowed value", out)
	}
	if p.IsExcludedValues(out) {
		return nil, fmt.Errorf("%d is an excluded value", out)
	}
	if p.MinValue != nil && out < *p.MinValue {
		return nil, fmt.Errorf("%d is under the minimum value", out)
	}
	if p.MaxValue != nil && out > *p.MaxValue {
		return nil, fmt.Errorf("%d is above the maximum value", out)
	}
	return out, nil
}

func (p *IntParameter) GetAuthServices() []ParamAuthService {
	return p.AuthServices
}

func (p *IntParameter) GetDefault() any {

View on GitHub (pinned to 8cc6e09de2)

Solutions

  1. Read the tool's parameter manifest (GET /mcp or the tool schema) to see the exact allowedValues list and send one of those values
  2. If the caller is an LLM, improve the parameter description to enumerate the valid values so the model picks within the set
  3. If legitimate values are missing, add them to allowedValues in tools.yaml (or WithIntAllowedValues) and redeploy the toolbox
  4. On the client side, validate the integer against the published manifest before invoking the tool

Example fix

// before
params := map[string]any{"limit": 500} // allowedValues are [10, 50, 100]
// after
params := map[string]any{"limit": 100}
Defensive patterns

Strategy: validation

Validate before calling

allowed := []int{10, 50, 100}
func validateAllowedInt(v int, allowed []int) error {
    for _, a := range allowed {
        if v == a { return nil }
    }
    return fmt.Errorf("%d is not in allowedValues %v", v, allowed)
}

Type guard

func isAllowedInt(v int, allowed []int) bool {
    for _, a := range allowed { if v == a { return true } }
    return false
}

Try / catch

out, err := tool.Parse(params)
if err != nil {
    var pte *ParseTypeError
    if !errors.As(err, &pte) && strings.Contains(err.Error(), "is not an allowed value") {
        // retry with a value from the manifest's allowedValues
    }
}

Prevention

When it happens

Trigger: Calling a tool (via MCP or the API) with an integer argument whose value is not listed in the IntParameter's allowedValues (configured with yaml 'allowedValues:' or WithIntAllowedValues). Example: allowedValues [1,2,3] but the request passes 7.

Common situations: LLMs hallucinating plausible-but-disallowed ids such as limit values, enum-like numeric codes, or page sizes; clients sending raw user input without pre-validation; tool configs tightened to a whitelist after clients were built against a looser schema.

Related errors


AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05). Data as JSON: /api/errors/133c7f8039cce8c1. Report an issue: GitHub.