Skip to content

Fix MCP fn_wrapper handling of Click UNSET defaults (#20953)#20962

Merged
TomeHirata merged 3 commits intomlflow:masterfrom
yangbaechu:fix-mcp-click-unset-20953
Feb 20, 2026
Merged

Fix MCP fn_wrapper handling of Click UNSET defaults (#20953)#20962
TomeHirata merged 3 commits intomlflow:masterfrom
yangbaechu:fix-mcp-click-unset-20953

Conversation

@yangbaechu
Copy link
Contributor

Related Issues/PRs

Resolve #20953

What changes are proposed in this pull request?

This PR fixes MCP fn_wrapper handling for Click 8.3+ by skipping click.core.UNSET when filling missing optional params, so callbacks receive their Python defaults (e.g., None) instead of Sentinel.UNSET. It also adds a regression test in tests/mcp/test_server.py for the missing-optional-arg path.

How is this PR tested?

  • New unit/integration tests
  • Manual tests

Manual reproduce run:

from mlflow.mcp.server import fn_wrapper                                                                                             
from mlflow.cli.traces import commands as traces_cli                                                                                 
                                                                                                                                     
wrapped = fn_wrapper(traces_cli.commands["search"])                                                                                  
wrapped(experiment_id="0")                                                                                                           
  • Result: no AttributeError, command runs successfully.

Does this PR require documentation update?

  • No. You can skip the rest of this section.

Does this PR require updating the MLflow Skills repository?

  • No. You can skip the rest of this section.

Release Notes

Is this a user-facing change?

  • Yes. Give a description of this change to be included in the release notes for MLflow users.

MLflow MCP no longer passes Click 8.3+ Sentinel.UNSET for missing optional tool arguments, preventing callback crashes such as 'Sentinel' object has no attribute 'split'.

What component(s), interfaces, languages, and integrations does this PR affect?

Components

  • area/tracing: MLflow Tracing features, tracing APIs, and LLM tracing functionality

How should the PR be classified in the release notes? Choose one:

  • rn/bug-fix - A user-facing bug fix worth mentioning in the release notes

Should this PR be included in the next patch release?

Yes should be selected for bug fixes, documentation updates, and other small changes. No should be selected for new features and larger changes. If you're unsure about the release classification of this PR, leave this unchecked to let the maintainers decide.

What is a minor/patch release?
  • Minor release: a release that increments the second part of the version number (e.g., 1.2.0 -> 1.3.0).
    Bug fixes, doc updates and new features usually go into minor releases.
  • Patch release: a release that increments the third part of the version number (e.g., 1.2.0 -> 1.2.1).
    Bug fixes and doc updates usually go into patch releases.
  • Yes (this PR will be cherry-picked and included in the next patch release)
  • No (this PR will be included in the next minor release)

@github-actions github-actions bot added the community Community/external contribution label Feb 18, 2026
@github-actions
Copy link
Contributor

🛠 DevTools 🛠

Install mlflow from this PR

# mlflow
pip install git+https://github.com/mlflow/mlflow.git@refs/pull/20962/merge
# mlflow-skinny
pip install git+https://github.com/mlflow/mlflow.git@refs/pull/20962/merge#subdirectory=libs/skinny

For Databricks, use the following command:

%sh curl -LsSf https://raw.githubusercontent.com/mlflow/mlflow/HEAD/dev/install-skinny.sh | sh -s pull/20962/merge

@github-actions github-actions bot added the size/S Small PR (10-49 LoC) label Feb 18, 2026
@github-actions
Copy link
Contributor

@yangbaechu Thank you for the contribution! Could you fix the following issue(s)?

⚠ DCO check

The DCO check failed. Please sign off your commit(s) by following the instructions here. See https://github.com/mlflow/mlflow/blob/master/CONTRIBUTING.md#sign-your-work for more details.

@github-actions github-actions bot added v3.10.0 area/tracing MLflow Tracing and its integrations rn/bug-fix Mention under Bug Fixes in Changelogs. labels Feb 18, 2026
@yangbaechu yangbaechu force-pushed the fix-mcp-click-unset-20953 branch from 59addcd to b35e062 Compare February 18, 2026 10:26
@@ -0,0 +1,20 @@
from unittest.mock import Mock
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we test in test_mcp?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done — moved to test_mcp.py


def fn_wrapper(command: click.Command) -> Callable[..., str]:
def wrapper(**kwargs: Any) -> str:
click_unset = getattr(click.core, "UNSET", object())
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is it intentional to use object() as a default?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes — it's a fallback sentinel for click < 8.3.0 where click.core.UNSET doesn't exist. object() ensures it never matches any param.default via is, so the new skip logic only activates on click >= 8.3.0.

Signed-off-by: Yang Geonhee <abab_1212@naver.com>
Signed-off-by: Yang Geonhee <abab_1212@naver.com>
@yangbaechu yangbaechu force-pushed the fix-mcp-click-unset-20953 branch from b35e062 to 238a7ac Compare February 20, 2026 05:36
@yangbaechu
Copy link
Contributor Author

I moved test_server into test_mcp and updated DCO sign-off to use my legal name and force-pushed to align the PR branch history.

@daniellok-db
Copy link
Collaborator

i'm removing the v3.10 label as the release is happening within the next 30 mins or so. it will be included in the next release which shouldn't be too far away

@@ -93,6 +95,8 @@ def wrapper(**kwargs: Any) -> str:
# Fill in defaults for missing optional arguments
for param in command.params:
if param.name not in kwargs:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we combine the if condition?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Addressed in 56caaf6.


@pytest.mark.asyncio
async def test_call_tool_with_optional_params_omitted(client: Client):
"""Regression test for click >= 8.3.0 Sentinel.UNSET handling (#20953)."""
Copy link
Collaborator

Choose a reason for hiding this comment

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

Let's remove this docstring

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Addressed in 56caaf6

Signed-off-by: Yang Geonhee <abab_1212@naver.com>
Copy link
Collaborator

@TomeHirata TomeHirata left a comment

Choose a reason for hiding this comment

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

LGTM

@TomeHirata TomeHirata enabled auto-merge February 20, 2026 07:09
@TomeHirata TomeHirata added this pull request to the merge queue Feb 20, 2026
Merged via the queue into mlflow:master with commit fce7f83 Feb 20, 2026
52 of 54 checks passed
daniellok-db pushed a commit to daniellok-db/mlflow that referenced this pull request Mar 5, 2026
daniellok-db pushed a commit to daniellok-db/mlflow that referenced this pull request Mar 5, 2026
daniellok-db pushed a commit that referenced this pull request Mar 5, 2026
Signed-off-by: Yang Geonhee <abab_1212@naver.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/tracing MLflow Tracing and its integrations community Community/external contribution rn/bug-fix Mention under Bug Fixes in Changelogs. size/S Small PR (10-49 LoC) v3.10.1

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] MCP fn_wrapper does not handle Click 8.3.0+ Sentinel.UNSET for missing optional params

3 participants