Repository navigation
fix: return JSON objects from list tools so outputSchema matches the payload - #5
Merged
Merged
Conversation
…payload
Tools that returned a bare list made FastMCP advertise a wrapped
{"result": [...]} outputSchema while the text content stayed a bare JSON
array (or no content at all for an empty list). MCP-to-OpenAPI bridges
such as mcpo build their response model from outputSchema but return the
decoded text content, so every list tool failed with a FastAPI
ResponseValidationError ("Input should be a valid dictionary").
List tools now return objects: search tools {"results": [...]},
listing tools {"posts": [...]}, and reddit_get_user {"items": [...]}.
This was referenced Oct 24, 2026
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.
Fixes #1
Root cause
Five tools (
reddit_search,reddit_search_subreddit,reddit_get_subreddit_posts,reddit_get_user,reddit_get_user_posts) returned a barelist. For non-object return values FastMCP:{"type": "object", "properties": {"result": {"type": "array", ...}}, "x-fastmcp-wrap-result": true}, and puts{"result": [...]}instructuredContent;mcpo builds its FastAPI response model from
outputSchema(an object with aresultfield) but returns the JSON-decoded text content. That's either a list, or[]when there is no content. mcpo versions that annotate the handler with the strict response model (e.g. 0.0.14/0.0.15) then raiseResponseValidationError: Input should be a valid dictionary or object to extract fields from, 'input': [], which is exactly the traceback in the issue.reddit_get_postalready returned a dict, so it was unaffected.Change
List tools now return objects, so the text content, the structured content, and the output schema are the same JSON object:
reddit_search,reddit_search_subreddit{"results": [...]}reddit_get_subreddit_posts,reddit_get_user_posts{"posts": [...]}reddit_get_user{"items": [...]}reddit_get_postThe return types are
TypedDicts, sooutputSchemadeclares the key, e.g.{"properties": {"posts": {"type": "array", ...}}, "required": ["posts"], "type": "object"}, with no wrap marker. Tool descriptions and the README tools table say what each tool returns.Behavior change: clients that read the list directly from these tools now need to read it from the key instead. LLM clients read the JSON text, so they handle this on their own. Clients that read
structuredContentwere already getting{"result": [...]}and now get{"posts": [...]}etc.Also fixed the
type: ignorecode onMcpSerializer.serialize(call-overload, notarg-type), somypy srcis clean.Verification
tests/test_mcp_tools.pyruns an in-processfastmcp.Clientagainst the real registrars with a mockedRedditPort. For every tool, with and without results, it checks: the objectoutputSchemahas nox-fastmcp-wrap-result;structuredContentpassesjsonschemavalidation againstoutputSchema; and the decoded text content is the same object and also validates. 11 of these 13 tests fail onmainand all pass here.main, every list tool returns HTTP 500 with the samemodel_attributes_type ... 'input': []error as the issue. On this branch, all tools return HTTP 200, with and without results.Union[ResponseModel, Any], which is more lenient.ruff check,ruff format --check,pytest(58 passed),mypy srcall clean.