Skip to content

Conversation

@jdchawla29
Copy link
Collaborator

@jdchawla29 jdchawla29 commented Jan 15, 2026

Note

Introduces a server-side patch to improve tool call handling and interoperability with FastMCP.

  • Adds patch_server_output_validation to override Server.call_tool, skipping output validation while still validating inputs with jsonschema
  • Normalizes callTool results (accepts dict/tuple/iterable or CallToolResult) and wraps them into ServerResult
  • Auto-generates structuredContent for FastMCP tools when outputSchema.x-fastmcp-wrap-result is set, parsing JSON from text when possible
  • Wires the new patch into apply_all_patches()

Written by Cursor Bugbot for commit 7c6a63f. This will update automatically on new commits. Configure here.

@jdchawla29 jdchawla29 requested a review from lorenss-m January 15, 2026 04:34
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 70dc46abba

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines 225 to 227
elif hasattr(results, "__iter__"):
unstructured_content = cast(UnstructuredContent, results)
maybe_structured_content = None

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Avoid treating all iterables as content blocks

The fallback hasattr(results, "__iter__") will treat strings and pydantic models (e.g., EvaluationResult, which BaseTool explicitly allows) as if they were already a list of MCP content blocks. In those cases the server will emit a list of characters or (field, value) tuples instead of TextContent, and downstream consumers (e.g., result_to_string which expects .text/.data) will silently drop the output. This is especially problematic now that output validation is skipped, because invalid content will propagate to clients. Consider restricting this branch to list/tuple of content blocks and explicitly serializing str/BaseModel to TextContent/structuredContent.

Useful? React with 👍 / 👎.

unstructured_content = [types.TextContent(type="text", text=text)]
elif hasattr(results, "__iter__"):
unstructured_content = list(results)
maybe_structured_content = None
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

String results incorrectly split into individual characters

Medium Severity

The hasattr(results, "__iter__") check at line 214 incorrectly matches strings and bytes, since these types are iterable in Python. If a tool function returns a string like "hello", calling list(results) will split it into individual characters ['h', 'e', 'l', 'l', 'o'] instead of treating it as a single result. This produces unexpected content that won't match types.TextContent in the subsequent structured content generation logic.

Fix in Cursor Fix in Web

@lorenss-m lorenss-m merged commit b0a1d41 into main Jan 15, 2026
9 checks passed
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.

3 participants