feat: parse Google-style docstrings to populate tool parameter descriptions#2402
Open
Maanik23 wants to merge 2 commits intomodelcontextprotocol:mainfrom
Open
feat: parse Google-style docstrings to populate tool parameter descriptions#2402Maanik23 wants to merge 2 commits intomodelcontextprotocol:mainfrom
Maanik23 wants to merge 2 commits intomodelcontextprotocol:mainfrom
Conversation
…ptions FastMCP previously discarded the parameter descriptions in a function's docstring when generating the JSON schema for a tool. The schema only contained titles and types, which gives LLMs less context when deciding how to call the tool. This change adds a small Google-style docstring parser (no new dependencies) that extracts: - the leading summary line, used as the tool description in place of the full raw docstring - per-parameter descriptions from the Args/Arguments/Parameters section, which are passed to Pydantic Field(description=...) so they appear in the generated JSON schema The parser handles: - multi-line summaries collapsed into one paragraph - parameters with or without type annotations - complex annotations like Annotated[list[int], Field(min_length=1)] - multi-line continuation of a parameter description - Args/Arguments/Parameters section header aliases - early termination when a Returns/Raises/Examples section appears - empty/None docstrings Existing behaviour is preserved: an explicit description= argument to Tool.from_function() still wins over the parsed summary, and tools without an Args section keep working without any description fields on their parameters. Github-Issue:modelcontextprotocol#226
The MCP repo enforces 100% test coverage. Add two tests that exercise the previously uncovered defensive branches in _parse_param_line: - test_param_line_with_unclosed_parenthesis covers the end_idx == -1 fallback when a type annotation has no closing paren - test_param_line_starting_with_non_word covers the regex no-match fallback for lines that do not begin with a word character
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Github-Issue:#226
Summary
FastMCP previously discarded the parameter descriptions in a function's docstring when generating the JSON schema for a tool. Tools showed up to LLMs with bare titles and types but no per-parameter context, which made tool calling less reliable.
This PR adds a small Google-style docstring parser (no new dependencies) that extracts the summary and per-parameter descriptions, then wires them into both the tool description and the generated JSON schema.
Before
Generated schema:
{ "properties": { "a": {"title": "A", "type": "number"}, "b": {"title": "B", "type": "number"} } }The tool description was the entire raw docstring including the
Args:block.After
{ "properties": { "a": {"title": "A", "type": "number", "description": "The first number to add."}, "b": {"title": "B", "type": "number", "description": "The second number to add."} } }And the tool description is just the summary:
"Adds two numbers and returns the result."Changes
src/mcp/server/mcpserver/utilities/docstring.py(new file)parse_docstring(docstring) -> tuple[str, dict[str, str]]returns a(summary, param_descriptions)tupleAnnotated[list[int], Field(min_length=1)], multi-line continuation of parameter descriptions, all common Args header aliases, and early termination at Returns/Raises/Examples sectionssrc/mcp/server/mcpserver/utilities/func_metadata.pyparse_docstring(func.__doc__)once per functionField(description=...)when building the dynamic Pydantic modelsrc/mcp/server/mcpserver/tools/base.pydescription=is provideddescription=argument toTool.from_function()still wins, preserving backward compatibilityTests
tests/server/mcpserver/test_docstring.py(new) — 16 unit tests covering: None/empty/whitespace input, summary-only docstrings, multi-line summaries, Google-style with and without type annotations, multi-line parameter descriptions, all Args header aliases (Args,Arguments,Parameters), section termination byRaises/Returns, blank lines inside the Args block, complexAnnotated[...]type expressions with nested brackets, and unrecognized continuation linestests/server/mcpserver/test_func_metadata.py— added two integration tests verifying that descriptions land in the JSON schema and that functions without an Args section still worktests/server/mcpserver/test_tool_manager.py— added an end-to-end test throughToolManagerthat confirms both the tool description and parameter descriptions come from the docstringCompatibility
description=argument toTool.from_function()still takes precedence over the parsed summaryWhy Google style only
The issue suggested supporting
google,numpy, andsphinxstyles viagriffe. Addinggriffeis a non-trivial dependency for a feature that, in practice, is overwhelmingly used with Google-style docstrings (the default in FastAPI, Pydantic, LangChain, and most modern Python projects). A self-contained parser keeps the dependency footprint at zero and is easy to extend later if there is real demand for the other two styles.