-
Notifications
You must be signed in to change notification settings - Fork 3k
fix: add boolean string coercion for FastMCP tool parameters #1848
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
fix: add boolean string coercion for FastMCP tool parameters #1848
Conversation
Some LLM clients incorrectly serialize booleans as strings ("false"
instead of false in JSON). The existing pre_parse_json method was
supposed to handle this via json.loads, but boolean values were being
skipped because bool is a subclass of int in Python, and the skip
condition isinstance(pre_parsed, str | int | float) matches booleans.
This fix adds explicit case-insensitive boolean string coercion before
the generic JSON parsing logic, properly converting "true"/"false"
strings to Python True/False when the parameter annotation is bool.
Fixes modelcontextprotocol#1843
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR fixes an issue where LLM clients incorrectly serialize boolean values as strings (e.g., "false" instead of false in JSON), causing FastMCP tools to receive string values instead of Python booleans. This made if param: checks evaluate incorrectly since the string 'false' is truthy in Python.
Changes:
- Added explicit case-insensitive boolean string coercion in the
pre_parse_jsonmethod to convert"true"/"false"strings to PythonTrue/False - Added 6 comprehensive test cases covering lowercase, case-insensitive, native booleans, non-boolean strings, runtime validation, and type-specific behavior
- The fix is applied before generic JSON parsing to handle the edge case where
json.loads("false")returnsFalse, butisinstance(False, int)isTrue, causing the parsed boolean to be skipped
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
src/mcp/server/fastmcp/utilities/func_metadata.py |
Added boolean string coercion logic in pre_parse_json method to handle string "true"/"false" values for bool-annotated parameters |
tests/server/fastmcp/test_func_metadata.py |
Added 6 comprehensive test functions validating boolean coercion for various cases including case-insensitivity, native booleans, non-boolean strings, runtime validation, and type specificity |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
Can I have a very simple MRE to understand what is wrong? |
I might be wrong🙃, please let me know accordingly. Why it broke:
|
|
You aren't supposed to call |
Summary
Some LLM clients incorrectly serialize booleans as strings (
"false"instead offalsein JSON). This causes FastMCP tools to receivethe string
'false'instead of PythonFalse, makingif param:checks evaluate incorrectly.Root Cause
The existing
pre_parse_jsonmethod was supposed to handle this viajson.loads, but boolean values were being skipped because:json.loads("false")correctly returns PythonFalseboolis a subclass ofintin Pythonisinstance(pre_parsed, str | int | float)matches booleans (sinceisinstance(False, int)isTrue)Changes
pre_parse_jsonmethod"true"/"false"strings (any case) → PythonTrue/FalseboolTesting
Related Issues
Fixes #1843