claude-code - 💡(How to fix) Fix [BUG] MCP tool parameters using $ref enum types are serialized as null [3 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
anthropics/claude-code#58794Fetched 2026-05-14 03:39:20
View on GitHub
Comments
3
Participants
2
Timeline
8
Reactions
0
Timeline (top)
labeled ×5commented ×3

Error Message

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.

Root Cause

  • Reproducible on both Claude Code (CLI) and Claude.ai (web) with connected MCP servers.
  • The Pydantic $ref pattern is standard JSON Schema. MCP servers using Pydantic v2 str, Enum types may hit this when their tool schema exposes those enums through $ref definitions.
  • Python's fastmcp framework (used by many MCP servers) produces $ref schemas by default for enum types.
  • Related Cursor forum report with the same root cause: https://forum.cursor.com/t/mcp-server-cant-handle-enums-from-my-python-fastmcp-server/99092
  • Related MCP Inspector issue: https://github.com/modelcontextprotocol/inspector/issues/672
  • Server-side workaround: replace $ref enum types with inline Literal[...] in tool signatures at codegen time. This produces the working schema shape without changing runtime behavior.

Fix Action

Fix / Workaround

  • Reproducible on both Claude Code (CLI) and Claude.ai (web) with connected MCP servers.
  • The Pydantic $ref pattern is standard JSON Schema. MCP servers using Pydantic v2 str, Enum types may hit this when their tool schema exposes those enums through $ref definitions.
  • Python's fastmcp framework (used by many MCP servers) produces $ref schemas by default for enum types.
  • Related Cursor forum report with the same root cause: https://forum.cursor.com/t/mcp-server-cant-handle-enums-from-my-python-fastmcp-server/99092
  • Related MCP Inspector issue: https://github.com/modelcontextprotocol/inspector/issues/672
  • Server-side workaround: replace $ref enum types with inline Literal[...] in tool signatures at codegen time. This produces the working schema shape without changing runtime behavior.

Code Example

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}"

---

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

---

{
  "$defs": {
    "Priority": {"enum": ["high", "medium", "low"], "type": "string"}
  },
  "priority": {
    "anyOf": [
      {"$ref": "#/$defs/Priority"},
      {"type": "null"}
    ],
    "default": null
  }
}

---

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

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 typeSchema shapeValue sentValue 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"}truetrue
int{"type": "integer"}33

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

  • Reproducible on both Claude Code (CLI) and Claude.ai (web) with connected MCP servers.
  • The Pydantic $ref pattern is standard JSON Schema. MCP servers using Pydantic v2 str, Enum types may hit this when their tool schema exposes those enums through $ref definitions.
  • Python's fastmcp framework (used by many MCP servers) produces $ref schemas by default for enum types.
  • Related Cursor forum report with the same root cause: https://forum.cursor.com/t/mcp-server-cant-handle-enums-from-my-python-fastmcp-server/99092
  • Related MCP Inspector issue: https://github.com/modelcontextprotocol/inspector/issues/672
  • Server-side workaround: replace $ref enum types with inline Literal[...] in tool signatures at codegen time. This produces the working schema shape without changing runtime behavior.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

claude-code - 💡(How to fix) Fix [BUG] MCP tool parameters using $ref enum types are serialized as null [3 comments, 2 participants]