Skip to content

MCP Server Part 1: framework utilities and types#3710

Open
KoolADE85 wants to merge 12 commits intomcpfrom
feature/mcp-framework-foundations
Open

MCP Server Part 1: framework utilities and types#3710
KoolADE85 wants to merge 12 commits intomcpfrom
feature/mcp-framework-foundations

Conversation

@KoolADE85
Copy link
Copy Markdown
Contributor

@KoolADE85 KoolADE85 commented Apr 1, 2026

Summary

For schema generation:

  • Make Dash Component class compatible with Pydantic
  • Move NumberType definition out from individual components into a generic place where the type can be introspected (and also made compatible with Pydantic)
  • Add stronger type definitions for callbacks (CallbackDispatchBody, CallbackDispatchResponse)

Utilities

  • Add framework utilities for traversing layouts and inspecting Dash components (dash/layout.py)
  • Add pydantic>=2.10 to dependencies

Manual testing

There isn't any visible feature, but you can try out the layout traversal and pydantic type exposure by hand:

from dash import Dash, html, dcc
app = Dash(__name__)
app.layout = html.Div([
    html.Label("Name:", htmlFor="name-input"),
    " ",
    dcc.Input(id="name-input", value="World"),
    html.Div([html.Span(id="deep-child", children="deep text")], id="inner"),
], id="root")

with app.server.app_context():
    from dash.layout import traverse, find_component, extract_text
    for comp, ancestors in traverse(app.get_layout()):
        indent = "  " * len(ancestors)
        print(f"{indent}{type(comp).__name__} id={getattr(comp, 'id', None)}")

    from pydantic import TypeAdapter
    from dash.development.base_component import Component
    print(TypeAdapter(Component).json_schema())

@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 1, 2026

Thank you for your contribution to Dash! 🎉

This PR is exempt from requiring a linked issue due to its labels.

import typing # noqa: F401
from typing_extensions import TypedDict, NotRequired, Literal # noqa: F401
from dash.development.base_component import Component, _explicitize_args
from dash.types import NumberType # noqa: F401
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This import doesn't exist on previous versions of dash, to maintain backward compatibility, types are created on the generated file.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I understand the backwards-compatiblity issue here, but tell me if I'm missing something:

  • 3rd party components generated with this change would become incompatible with dash<=4.1.0.
  • Our own dcc/html components are tied to the framework version, so there is no compatibility issue internally.

What do you think about "transitioning" the NumberType into the framework by including a conditional import in the generated components:

try:
    from dash.types import NumberType
except ImportError:
    NumberType = typing.Union[typing.SupportsFloat, typing.SupportsInt, typing.SupportsComplex]

This would maintain backwards compatibility while also giving us a type that we can change in the framework going forward.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea that could work.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK great - I pushed up that change.

Comment on lines +1 to +2
"""Reusable layout utilities for traversing and inspecting Dash component trees."""

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure about naming this file layout as this might confuse users with the import. Also common pattern is the user have a layout file/variable/function and importing this would need to be aliased in those case.

If this is not intended to be used by the dash app developer, then maybe rename to _layout, otherwise maybe something like layout_tools or layout_utils would be more explicit.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call - I renamed this to _layout_utils.py.

Comment on lines +28 to +36
if TYPE_CHECKING:
from dash.types import NumberType # noqa: F401
else:
try:
from dash.types import NumberType # noqa: F401
except ImportError:
NumberType = typing.Union[ # noqa: F401
typing.SupportsFloat, typing.SupportsInt, typing.SupportsComplex
]
Copy link
Copy Markdown
Contributor

@T4rk1n T4rk1n Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But now there's two import, since both definitions are types I think the else is redundant.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately there is a quirk here for pyright: the type checker is not satisfied with the try/except style of import and the Typing Tests fail.
I re-wrote this more compactly, but as far as I can tell we need to use the TYPE_CHECKING constant in order to satisfy pyright.

@KoolADE85 KoolADE85 force-pushed the feature/mcp-framework-foundations branch from f4108e5 to 3f9fbca Compare April 7, 2026 16:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants