fix(mcp): don't inject phantom params for tools named required/properties - #515
fix(mcp): don't inject phantom params for tools named required/properties#515hashbender wants to merge 1 commit into
Conversation
|
Review Complete Files Reviewed: 2 By Severity:
One low-severity finding about misleading comments in mcp_tool.py that falsely claim start_new_session=True exists in LSP and slash_worker spawn paths. Files Reviewed (2 files) |
There was a problem hiding this comment.
Risk: 🟢 Low (18/100) — 1 low finding · 293 LOC across 2 files
PR #515 Review Summary
Scope: 2 files changed — and — adding PID filtering for non-MCP gateway child processes to the stdio transport cleanup sweep.
Risk score: 18 — the one finding is a comment-only issue with no functional impact; the core defense-in-depth PID filtering logic is sound.
Findings
- finding-001 (low/90): Misleading comments in claim that and now use , but neither file actually does. The mechanism works regardless, but the comments misdirect future maintainers.
Not flagged (below confidence threshold)
- Two additional verified findings (imprecise substring argv matching at confidence 75, missing gate at confidence 78) fell below the threshold and were excluded.
Assessment: Comment
No functional defects found. The PR correctly implements PID filtering for gateway child processes. The flagged issue is strictly about comment accuracy.
| # during stdio MCP server spawn. LSP servers and slash_worker now use | ||
| # start_new_session=True too; this remains defense-in-depth for any future |
There was a problem hiding this comment.
🟢 Misleading cross-file comments claim start_new_session fix exists where it does not (bug)
tools/mcp_tool.py line 3017-3018 says 'LSP servers and slash_worker now use start_new_session=True too' and line 1875 says 'See agent/lsp/client.py for the complementary start_new_session fix.' Both comments were introduced in this PR. However, agent/lsp/client.py line 266 spawns LSP processes via asyncio.create_subprocess_exec without start_new_session=True, and tui_gateway/server.py line 287 spawns the slash_worker via subprocess.Popen without start_new_session=True. The comments are factually incorrect about the state of those files. The _filter_mcp_children defense-in-depth logic is not functionally broken by this — it works regardless — but the comments misdirect future maintainers who may rely on the claimed fix existing when it does not.
💡 Suggestion: Either add start_new_session=True to agent/lsp/client.py and tui_gateway/server.py spawn calls (matching the comment's claim), or update both comments in mcp_tool.py to accurately reflect the current state. Additionally, the comment at line 1875 should not claim a complementary fix exists in lsp/client.py when it doesn't.
| # during stdio MCP server spawn. LSP servers and slash_worker now use | |
| # start_new_session=True too; this remains defense-in-depth for any future | |
| # during stdio MCP server spawn. LSP servers and slash_worker are spawned | |
| # without start_new_session (see agent/lsp/client.py, tui_gateway/server.py); |
📋 Prompt for AI Agents
In tools/mcp_tool.py around line 3017, the comment says 'LSP servers and slash_worker now use start_new_session=True too' but neither agent/lsp/client.py nor tui_gateway/server.py actually use start_new_session=True. Fix the comment to accurately state they are spawned WITHOUT start_new_session. Additionally, at line 1875, the comment 'See agent/lsp/client.py for the complementary start_new_session fix' is misleading since no such fix exists — either remove this reference or change it to a TODO.
What does this PR do?
_normalize_mcp_input_schema(via its inner_repair_object_shape) can inject phantom parameters into an MCP tool's schema when the tool declares a parameter literally namedrequiredorproperties._repair_object_shaperecurses into every dict uniformly, including thepropertiesmap — whose keys are user-facing parameter names, not JSON Schema meta-keywords. The object-shape repair right below it (fill a missingtype, ensure apropertiesdict exists) then fires on the properties map itself whenever it contains a key namedrequiredorproperties, stamping a"type": "object"and an empty"properties"onto the map. Those surface to the model as parameterstype/propertiesthat the MCP server never declared.Concrete reproduction (running the actual function):
propertieskeyspropertieskeys (before)["required"]["required", "type", "properties"]["properties"]["properties", "type"]config.properties = ["required"]["required", "type", "properties"]["query"](normal)["query"]✓ (unaffected)The model can then fill those phantom params with junk arguments, and strict providers can
400the malformed intermediate schema (a"type": "object"string value sitting inside the properties map) — the same failure mode the sibling_rewrite_local_refsdocstring already warns about.Root cause:
_rewrite_local_refswas deliberately fixed to special-caseproperties/patternPropertiesduring descent (see its docstring andtest_definitions_as_property_name_is_preserved), but the sibling_repair_object_shapewas overlooked. Classic "fixed one traversal, missed the other."Related Issue
Fixes #
Type of Change
Changes Made
tools/mcp_tool.py— in_repair_object_shape, gateproperties/patternPropertiesduring descent so their keys are treated as user-facing parameter names (iterate the map, recurse only into each property's schema), mirroring the existing gate in_rewrite_local_refs. All legitimate repairs (type inference,requiredpruning, nested object coercion) are unchanged.tests/tools/test_mcp_tool.py— 3 regression tests (test_property_named_required_does_not_inject_phantom_params,test_property_named_properties_does_not_inject_phantom_type,test_property_named_required_is_preserved_when_nested).How to Test
scripts/run_tests.sh tests/tools/test_mcp_tool.py -q— 206 tests pass.tools/mcp_tool.pyhunk and rerun-k property_named→ the 3 new tests fail (phantomtype/propertiesappear in the outputpropertiesmap); restore → they pass.Checklist
Code
fix(mcp):)definitions→$defsrename in_rewrite_local_refs; none touch_repair_object_shape)Documentation & Housekeeping
cli-config.yaml.example— N/ACONTRIBUTING.md/AGENTS.md— N/Ascripts/check-windows-footguns.pyclean)Mirror-of: NousResearch#56620
NousResearch#56620