Skip to content

refactor: decompose func_metadata() into smaller focused helpers#2352

Open
perhapzz wants to merge 1 commit intomodelcontextprotocol:mainfrom
perhapzz:refactor/decompose-func-metadata
Open

refactor: decompose func_metadata() into smaller focused helpers#2352
perhapzz wants to merge 1 commit intomodelcontextprotocol:mainfrom
perhapzz:refactor/decompose-func-metadata

Conversation

@perhapzz
Copy link
Copy Markdown

Summary

Refactors the monolithic func_metadata() function in func_metadata.py into smaller, well-documented helper functions for improved readability, testability, and extensibility.

Motivation

Closes #1700

func_metadata() handled multiple responsibilities in a single ~150-line function: signature introspection, parameter model construction, return type analysis, type-based model dispatch, and schema generation. This made it difficult to understand, test individual behaviors, and extend with new type handling.

Changes

Extracted the following focused helper functions:

Function Responsibility
_get_function_signature() Signature introspection with error handling
_build_arg_model() Parameter model construction (annotation, defaults, alias handling)
_resolve_return_annotation() Return type validation and CallToolResult/Annotated unwrapping
_create_output_model() Type-based dispatch to appropriate model creation strategy
_try_generate_strict_schema() Schema generation with StrictJsonSchema error handling

Simplified _try_create_model_and_schema() to delegate to the new helpers.

The top-level func_metadata() is now a concise orchestrator (~20 lines) that calls these helpers in sequence.

Testing

  • All 33 existing tests in test_func_metadata.py pass without modification
  • No behavioral changes — this is a pure refactor (extract method)
  • The public API (func_metadata(), FuncMetadata, ArgModelBase) is unchanged

Notes

  • The file path has moved from src/mcp/server/fastmcp/ to src/mcp/server/mcpserver/ since the issue was filed — the refactor targets the current location.
  • A potential follow-up could introduce a strategy/registry pattern for type handling in _create_output_model(), as suggested in the issue. Kept out of this PR to minimize scope.

Extract the monolithic func_metadata() function into smaller, well-documented
helper functions for improved readability, testability, and extensibility.

Changes:
- Extract _get_function_signature() for signature introspection
- Extract _build_arg_model() for parameter model construction
- Extract _resolve_return_annotation() for return type analysis
- Extract _create_output_model() for type-based model dispatch
- Extract _try_generate_strict_schema() for schema generation with error handling
- Simplify _try_create_model_and_schema() to delegate to new helpers

All existing tests pass without modification. No behavioral changes.
@dgenio
Copy link
Copy Markdown

dgenio commented Apr 9, 2026

Hey @perhapzz, thanks for picking this up! As the author of #1700, here are my thoughts:

The decomposition looks solid. The five helpers (_get_function_signature, _build_arg_model, _resolve_return_annotation, _create_output_model, _try_generate_strict_schema) map well to the logical responsibilities I had in mind. func_metadata() becoming a ~20-line orchestrator is exactly the goal.

Acceptance criteria coverage:

  • Criterion 1 (decompose into smaller helpers): Fully addressed.
  • ⏭️ Criterion 2 (strategy/registry for type handling): Intentionally deferred — I think that's the right call to keep this PR focused. I'll open a follow-up issue for this.
  • ⚠️ Criterion 3 (unit tests for individual behaviors): The existing 33 tests pass, but no new targeted tests were added for the individual helpers. Since this is a pure refactor, I think that's acceptable for this PR, but it would be good to add helper-level tests as a follow-up.

One small thing I noticed: Line 158 in the diff introduces what looks like a typo in a comment:

- # Should really be parsed as '"hello"' in Python - but if we parse
+ # Should really be parsed as '"'hello'"' in Python - but if we parse

The original '"hello"' was correct (a Python string containing "hello" with double quotes). The new version '"'hello'"' seems garbled — might have been an unintended find/replace artifact?

Overall: +1 from the issue author. The approach and scope are right. Happy to see this land.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Refactor func_metadata() into smaller components for schema & metadata generation

2 participants