ref(mcp): Separate tool, prompt and resource patches#6726
ref(mcp): Separate tool, prompt and resource patches#6726alexander-alderman-webb wants to merge 5 commits into
Conversation
Codecov Results 📊✅ 90048 passed | ⏭️ 6298 skipped | Total: 96346 | Pass Rate: 93.46% | Execution Time: 313m 29s 📊 Comparison with Base Branch
✨ No test changes detected All tests are passing successfully. ❌ Patch coverage is 69.51%. Project has 2477 uncovered lines. Files with missing lines (1)
Coverage diff@@ Coverage Diff @@
## main #PR +/-##
==========================================
- Coverage 89.77% 89.65% -0.12%
==========================================
Files 192 192 —
Lines 23824 23923 +99
Branches 8226 8250 +24
==========================================
+ Hits 21386 21446 +60
- Misses 2438 2477 +39
- Partials 1349 1354 +5Generated by Codecov Action |
There was a problem hiding this comment.
handler_name may be unbound in _extract_handler_data_from_args for tool and prompt types
In _extract_handler_data_from_args (mcp.py ~line 423), if original_args is empty and original_kwargs.get("name") is falsy, handler_name is never assigned for handler_type == "tool" or "prompt", causing an UnboundLocalError when it is referenced at return handler_name, arguments (tool) or arguments = {"name": handler_name, ...} (prompt). Add an else: handler_name = "unknown" fallback in both branches.
Evidence
_extract_handler_data_from_argslines 422-446: bothtoolandpromptbranches assignhandler_nameonly underif original_args:orelif original_kwargs.get("name"):, with noelseclause.- For the prompt branch,
handler_nameis immediately used on the very next line:arguments = {"name": handler_name, **(arguments or {})}, so anUnboundLocalErroris raised beforereturn. - For the tool branch,
handler_nameis used in the sharedreturn handler_name, argumentsat line ~455. _prepare_handler_datareaches_extract_handler_data_from_argswhen bothparams is Noneand_is_v2_context(original_args)is False (e.g., emptyoriginal_argsin a v2 kwargs-only call).- The resource branch correctly initialises
handler_name = "unknown"before any conditional, confirming the fix pattern is known.
Identified by Warden find-bugs
There was a problem hiding this comment.
UnboundLocalError when tool/prompt handler called with no args and no kwargs name
In _extract_handler_data_from_args, handler_name is only assigned inside if original_args: / elif original_kwargs.get("name"): branches for the "tool" and "prompt" types; if both conditions are false, handler_name is never set. The prompt branch then immediately dereferences it at arguments = {"name": handler_name, ...}, raising UnboundLocalError at runtime.
Evidence
_extract_handler_data_from_args(mcp.py ~line 407) handles"tool"and"prompt"withif original_args: handler_name = .../elif original_kwargs.get("name"): handler_name = ...— noelseclause and no default value.- For
"prompt", line 446 unconditionally readshandler_nameinarguments = {"name": handler_name, **(arguments or {})}before the function returns. - For
"tool", the unbound name would surface atreturn handler_name, arguments. - The
"resource"branch correctly defaults tohandler_name = "unknown"first, so only tool and prompt are affected. _prepare_handler_datacalls this function on the non-v2 code path (line 486) without any guard against empty args.
Identified by Warden code-review
There was a problem hiding this comment.
UnboundLocalError when original_args is empty and original_kwargs has no 'name' key in _extract_handler_data_from_args
For handler_type == 'tool' and handler_type == 'prompt', handler_name is assigned only inside if/elif branches with no else fallback; if both conditions are falsy the variable is unbound and will raise UnboundLocalError — for 'prompt' the crash occurs immediately at arguments = {'name': handler_name, ...} inside the function.
Evidence
_extract_handler_data_from_args(mcp.py ~line 421):if original_args: handler_name = .../elif original_kwargs.get('name'): handler_name = ...— noelseclause for either the 'tool' or 'prompt' branch.- The 'resource' branch correctly initialises
handler_name = 'unknown'before the conditionals, showing the pattern is inconsistent. - For 'prompt',
handler_nameis dereferenced immediately within the same function atarguments = {'name': handler_name, ...}(line ~445), so an empty call with no positional args and no kwargs 'name' crashes before returning. _prepare_handler_datacalls this function via theelsebranch whenparams is Noneand_is_v2_contextis False, so v1 stdio callers with missing arguments hit this path.
Identified by Warden find-bugs
Description
Issues
Reminders
uv run ruff.feat:,fix:,ref:,meta:)