Skip to content

[BUG]RecursionError with Self-Referencing Pydantic Models in fastapi-mcp 0.3.3 #155

Open
@tim-srp

Description

@tim-srp

RecursionError with Self-Referencing Pydantic Models in fastapi-mcp 0.3.3

Bug Description

When using fastapi-mcp 0.3.3 with Pydantic 2.7.2, applications crash with a RecursionError when Pydantic models contain self-referencing fields. The error occurs during OpenAPI schema generation in the resolve_schema_references function.

Environment

  • fastapi-mcp: 0.3.3
  • Pydantic: 2.7.2
  • FastAPI: 0.109.1
  • Python: 3.10

Error Details

Error Location: /site-packages/fastapi_mcp/openapi/utils.py:50 in resolve_schema_references

Error Message:

RecursionError: maximum recursion depth exceeded while calling a Python object

Stack Trace Pattern:

File "/site-packages/fastapi_mcp/openapi/utils.py", line 50, in resolve_schema_references
    schema_part[key] = resolve_schema_references(value, reference_schema)
File "/site-packages/fastapi_mcp/openapi/utils.py", line 53, in resolve_schema_references
    schema_part[key] = [
File "/site-packages/fastapi_mcp/openapi/utils.py", line 54, in <listcomp>
    resolve_schema_references(item, reference_schema) if isinstance(item, dict) else item for item in value
# ... (repeats infinitely)

Root Cause

The resolve_schema_references function in fastapi-mcp cannot handle self-referencing Pydantic models properly, causing infinite recursion when processing OpenAPI schemas that contain circular references.

Minimal Reproduction Example

# models.py
from __future__ import annotations
from typing import Optional, List
from pydantic import BaseModel
from enum import Enum

class MessageType(str, Enum):
    ROOT = "root"
    TEXT = "text"

class ChatMessage(BaseModel):
    """Self-referencing model that triggers the bug"""
    id: str
    type: MessageType
    content: Optional[List[ChatMessage]] = None  # Self-reference causes recursion

# main.py
from fastapi import FastAPI
from fastapi_mcp import FastApiMCP
from models import ChatMessage

app = FastAPI()

@app.post("/test", response_model=ChatMessage)
async def test_endpoint():
    return ChatMessage(id="test", type=MessageType.ROOT)

# This line causes RecursionError
mcp = FastApiMCP(app, include_tags=["mcp"])
mcp.mount()

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)

Steps to Reproduce

  1. Install dependencies:

    pip install fastapi-mcp==0.3.3 pydantic==2.7.2 fastapi==0.109.1
  2. Create the files above (models.py and main.py)

  3. Run the application:

    python main.py
  4. Expected: Application starts successfully

  5. Actual: Application crashes with RecursionError

Workaround

Currently, the only workaround is to disable fastapi-mcp functionality:

# Comment out these lines to avoid the crash
# mcp = FastApiMCP(app, include_tags=["mcp"])
# mcp.mount()

Analysis

The issue appears to be in the resolve_schema_references function which doesn't implement cycle detection for self-referencing schemas. When processing a schema that references itself (like List[ChatMessage] within ChatMessage), the function recursively calls itself without tracking visited schemas, leading to infinite recursion.

Suggested Fix

The resolve_schema_references function should implement cycle detection, similar to how Pydantic itself handles self-referencing models. Possible approaches:

  1. Visited Set: Track visited schema references to detect cycles
  2. Reference Substitution: Replace circular references with $ref pointers
  3. Depth Limiting: Implement maximum recursion depth

Impact

This bug prevents the use of fastapi-mcp with any application that uses self-referencing Pydantic models, which is a common pattern for:

  • Tree structures
  • Chat/message systems
  • Hierarchical data models
  • Graph-like data structures

Additional Context

This issue appears to be related to compatibility between fastapi-mcp's OpenAPI schema processing and Pydantic 2.7.x's schema generation for self-referencing models. The problem doesn't occur when fastapi-mcp is disabled, indicating the issue is specific to the fastapi-mcp schema processing pipeline.

Expected Behavior

fastapi-mcp should handle self-referencing Pydantic models gracefully, either by:

  1. Properly resolving circular references in OpenAPI schemas
  2. Gracefully skipping problematic models with appropriate warnings
  3. Using Pydantic's built-in mechanisms for handling self-references

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions