Skip to content

Visibility transform crashes when tags passed as list instead of set #3907

@strawgate

Description

@strawgate

Summary

Visibility(False, tags=['internal']) crashes with TypeError when applied to components. The constructor accepts any iterable for tags (type hint is set[str] | None), but _matches() performs set intersection (&) which fails on lists.

Reproduction

from fastmcp import FastMCP
from fastmcp.server.transforms.visibility import Visibility

mcp = FastMCP('test')

@mcp.tool(tags={'internal'})
def my_tool() -> str:
    """A test tool"""
    return 'hello'

vis = Visibility(False, tags=['internal'])
mcp.add_transform(vis)

# Crashes:
tools = await mcp.list_tools()
# TypeError: unsupported operand type(s) for &: 'set' and 'list'

Root Cause

visibility.py:88 stores tags without coercion:

self.tags = tags  # stored as-is (could be list)

visibility.py:171 uses set intersection:

return self.tags is None or bool(component.tags & self.tags)

component.tags is always a set (enforced by Pydantic BeforeValidator), but self.tags can be a list, and set & list raises TypeError.

Note

The safe API paths (provider.disable(), ctx.disable_components()) already coerce to set. Only direct Visibility() construction is affected.

Fix

Coerce tags to set in the constructor: self.tags = set(tags) if tags is not None else None

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working. Reports of errors, unexpected behavior, or broken functionality.serverRelated to FastMCP server implementation or server-side functionality.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions