Skip to content

[BUG] MCP tool parameters using $ref enum types are serialized as null #58794

Description

@somanshreddy

Title: [BUG] MCP tool parameters using $ref enum types are serialized as null


Preflight Checklist

  • I have searched for existing issues
  • This is a single bug report (not multiple issues)
  • I am on the latest version of Claude Code

What's Wrong?

When an MCP tool parameter's JSON Schema uses a $ref pointer to an enum definition in $defs, Claude serializes the parameter value as null regardless of what the model intends to send. The model correctly identifies the value to send (visible in its reasoning), but the serialized tool call payload contains null.

Inline enum values (without $ref) work correctly.

What Should Happen?

Claude should resolve $ref pointers in $defs and serialize the intended enum value. Both schema shapes represent the same constraint and should produce the same behavior.

Steps to Reproduce

  1. Create an MCP server with two tools. One uses an inline enum, the other uses a $ref enum:
from fastmcp import FastMCP
from enum import Enum
from typing import Optional, Literal
from pydantic import Field

mcp = FastMCP("test-server")

class Priority(str, Enum):
    HIGH = "high"
    MEDIUM = "medium"
    LOW = "low"

# Tool A: inline Literal enum (WORKS)
@mcp.tool()
def create_task_inline(
    title: str = Field(description="Task title"),
    priority: Optional[Literal["high", "medium", "low"]] = Field(
        default=None, description="Task priority"
    ),
) -> str:
    return f"Created task: title={title}, priority={priority}"

# Tool B: $ref enum via Pydantic class (BROKEN)
@mcp.tool()
def create_task_ref(
    title: str = Field(description="Task title"),
    priority: Optional[Priority] = Field(
        default=None, description="Task priority"
    ),
) -> str:
    return f"Created task: title={title}, priority={priority}"
  1. The two tools produce different JSON Schema shapes:

Tool A (inline, works):

{
  "priority": {
    "anyOf": [
      {"enum": ["high", "medium", "low"], "type": "string"},
      {"type": "null"}
    ],
    "default": null
  }
}

Tool B ($ref, broken):

{
  "$defs": {
    "Priority": {"enum": ["high", "medium", "low"], "type": "string"}
  },
  "priority": {
    "anyOf": [
      {"$ref": "#/$defs/Priority"},
      {"type": "null"}
    ],
    "default": null
  }
}
  1. Ask Claude to call both tools with priority="high".

  2. Tool A receives priority="high". Tool B receives priority=null.

Additional patterns tested

The bug also affects non-nullable $ref enums with defaults:

{
  "$defs": {
    "OutputFormat": {"enum": ["mp4", "webm"], "type": "string"}
  },
  "output_format": {
    "$ref": "#/$defs/OutputFormat",
    "default": "mp4"
  }
}

When the model sets output_format="webm", the server receives null. Depending on server validation/normalization, this either fails validation or is treated as omitted and falls back to the default "mp4".

Test matrix

Parameter type Schema shape Value sent Value received
Optional[Literal["high", "medium", "low"]] inline enum "high" "high"
Optional[Priority] (str Enum class) $ref to $defs "high" null
str {"type": "string"} "test" "test"
Optional[str] anyOf[string, null] "test" "test"
bool {"type": "boolean"} true true
int {"type": "integer"} 3 3

Only $ref enum parameters are affected. All primitive types and inline enums work.

Error Messages/Logs

No error is raised. The value is silently sent as null, making the bug difficult to detect. If the server has null-stripping logic or default fallbacks, the user gets wrong output with no indication of failure.

Is this a regression?

Unknown

Claude Code Version

1.0.33

Platform

Anthropic API

Operating System

Linux

Terminal/Shell

zsh

Additional Information

Metadata

Metadata

Assignees

No one assigned

    Labels

    api:anthropicarea:mcpbugSomething isn't workinghas reproHas detailed reproduction stepsplatform:linuxIssue specifically occurs on LinuxstaleIssue is inactive

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions