Skip to content

Conversation

@renvins
Copy link
Contributor

@renvins renvins commented Nov 5, 2025

PR Summary

Overview

  • Wire LangChain's structured-output response_format into MCPAgent without recreating the agent per call.
  • Introduce a dynamic middleware that only forces structured output once the agent reaches its final turn.
  • Preserve a fast fallback path for single-turn answers by formatting the model response via provider-native structured output.
  • Tighten connector initialization logic and add a fresh example demonstrating the new structured output flow.

Key Changes

  • mcp_use/agents/mcpagent.py
    • Added dynamic_structured_output middleware (@wrap_model_call) that inspects pending tool calls and updates the ModelRequest with AutoStrategy only when the agent is about to return a final response. This avoids constraining intermediate reasoning/tool-selection steps.
    • Propagate the optional response_format through the agent's astream context so LangChain can surface native structured_response payloads.
    • Track structured_response chunks during streaming and, on completion, deliver them directly when present. When the provider did not emit a native payload (e.g., single-shot replies), re-run the final answer through llm.with_structured_output(schema) to coerce it into the requested schema without re-executing the agent loop.
  • examples/python/new_structured_output_example.py
    • Added a runnable sample that connects to the Airbnb MCP server and requests a structured result, illustrating the new workflow end-to-end.

Design Decisions & Rationale

  • Deferred response-format enforcement: Applying structured output at agent creation would force every LLM turn into the schema, preventing tool planning. The middleware pattern lets us inspect the conversation state and only set response_format after tools finish (or when no tools were needed), keeping agent behaviour unchanged while still leveraging LangChain 1.0's structured output pipeline.
  • Provider-native fallback over custom parsing: Previous structured output relied on an extra prompt/validation step, which was slower. Using with_structured_output() is faster and more reliable; we still have _attempt_structured_output available if future providers lack native support.
  • Context propagation: Passing context={"response_format": output_schema} into astream ensures LangChain's compiled graph can produce structured_response entries, unlocking the zero-copy fast path when available.

Testing Notes

  • Exercised the new example script (new_structured_output_example.py) to confirm:
    • Tool-using runs surface native structured responses without extra formatting.
    • Simple one-shot queries (no tools) still yield structured data via the fallback formatter.

Follow-ups / Considerations

  • If we integrate providers without native structured-output APIs, we should wrap the fallback formatter in try/except and fall back to _attempt_structured_output (already present) for compatibility.
  • Documentation can be updated to highlight the middleware-driven structured output pattern and the new example script.

Fixes #397

@renvins renvins requested a review from pietrozullo November 5, 2025 10:56
@pietrozullo pietrozullo requested a review from Copilot November 5, 2025 13:08
Copy link
Contributor

Copilot AI left a 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 adds dynamic structured output functionality to the MCPAgent by introducing middleware that automatically applies structured output formatting during agent execution. The key improvement is that structured output can now be applied earlier in the agent loop rather than only at the end, allowing the LLM to receive schema-enforced responses natively.

  • Introduced a new dynamic_structured_output middleware that applies structured output formatting during agent execution
  • Modified the stream method to pass the output schema through context to the middleware
  • Simplified structured output handling by leveraging middleware instead of post-processing

Reviewed Changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
libraries/python/mcp_use/agents/mcpagent.py Added dynamic_structured_output middleware method, updated imports for middleware and structured output utilities, modified stream method to pass schema via context, and simplified structured output handling logic
libraries/python/examples/new_structured_output_example.py Added new example demonstrating structured output with Airbnb MCP server
Comments suppressed due to low confidence (1)

libraries/python/mcp_use/agents/mcpagent.py:180

  • Normal methods should have 'self', rather than 'request', as their first parameter.
    async def dynamic_structured_output(request: ModelRequest, handler):

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

self._model_provider, self._model_name = extract_model_info(self.llm)

@wrap_model_call
async def dynamic_structured_output(request: ModelRequest, handler):
Copy link

Copilot AI Nov 5, 2025

Choose a reason for hiding this comment

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

The dynamic_structured_output method is missing the self parameter. Instance methods decorated with @wrap_model_call should still include self as the first parameter to properly bind to the class instance.

Suggested change
async def dynamic_structured_output(request: ModelRequest, handler):
async def dynamic_structured_output(self, request: ModelRequest, handler):

Copilot uses AI. Check for mistakes.
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.

python: Structured Output is slow

2 participants