Skip to content

Commit 06db7a7

Browse files
committed
ruff, pyright
1 parent 70dc46a commit 06db7a7

File tree

1 file changed

+36
-35
lines changed

1 file changed

+36
-35
lines changed

hud/patches/mcp_patches.py

Lines changed: 36 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -167,81 +167,82 @@ async def noop_validate(self: Any, name: str, result: Any) -> None:
167167

168168
def patch_server_output_validation() -> None:
169169
"""
170-
Patch MCP server to skip structured output validation.
170+
Patch MCP server to skip structured output validation and auto-generate
171+
structuredContent for FastMCP tools with x-fastmcp-wrap-result.
171172
"""
172173
try:
173174
import json
174-
from typing import cast
175175

176176
import mcp.types as types
177177
from mcp.server.lowlevel.server import Server
178178

179-
original_call_tool = Server.call_tool
180-
181179
def patched_call_tool(
182180
self: Any, validate_input: bool = True, validate_output: bool = False
183181
) -> Any:
184182
"""Patched call_tool that skips output validation."""
185-
from collections.abc import Awaitable, Callable
186-
187-
# Type aliases from original
188-
UnstructuredContent = list[types.TextContent | types.ImageContent | types.EmbeddedResource]
189-
StructuredContent = dict[str, Any]
190-
CombinationContent = tuple[UnstructuredContent, StructuredContent]
191-
192-
def decorator(
193-
func: Callable[
194-
...,
195-
Awaitable[UnstructuredContent | StructuredContent | CombinationContent | types.CallToolResult],
196-
],
197-
) -> Any:
183+
184+
def decorator(func: Any) -> Any:
198185
async def handler(req: types.CallToolRequest) -> Any:
199186
try:
200187
tool_name = req.params.name
201188
arguments = req.params.arguments or {}
202189
tool = await self._get_cached_tool_definition(tool_name)
203190

204-
# input validation (keep this)
205191
if validate_input and tool:
206192
try:
207193
import jsonschema
208-
jsonschema.validate(instance=arguments, schema=tool.inputSchema)
194+
195+
jsonschema.validate(
196+
instance=arguments, schema=tool.inputSchema
197+
)
209198
except jsonschema.ValidationError as e:
210-
return self._make_error_result(f"Input validation error: {e.message}")
199+
return self._make_error_result(
200+
f"Input validation error: {e.message}"
201+
)
211202

212-
# tool call
213203
results = await func(tool_name, arguments)
214204

215205
# output normalization
216-
unstructured_content: UnstructuredContent
217-
maybe_structured_content: StructuredContent | None
206+
unstructured_content: list[Any]
207+
maybe_structured_content: dict[str, Any] | None
218208
if isinstance(results, types.CallToolResult):
219209
return types.ServerResult(results)
220210
elif isinstance(results, tuple) and len(results) == 2:
221-
unstructured_content, maybe_structured_content = cast(CombinationContent, results)
211+
unstructured_content, maybe_structured_content = results
222212
elif isinstance(results, dict):
223-
maybe_structured_content = cast(StructuredContent, results)
224-
unstructured_content = [types.TextContent(type="text", text=json.dumps(results, indent=2))]
213+
maybe_structured_content = results
214+
text = json.dumps(results, indent=2)
215+
unstructured_content = [
216+
types.TextContent(type="text", text=text)
217+
]
225218
elif hasattr(results, "__iter__"):
226-
unstructured_content = cast(UnstructuredContent, results)
219+
unstructured_content = list(results)
227220
maybe_structured_content = None
228221
else:
229-
return self._make_error_result(f"Unexpected return type from tool: {type(results).__name__}")
222+
return self._make_error_result(
223+
f"Unexpected return type: {type(results).__name__}"
224+
)
230225

231-
# Auto-generate structuredContent for FastMCP tools with x-fastmcp-wrap-result
232-
# FastMCP generates outputSchema but doesn't populate structuredContent
226+
# Auto-generate structuredContent for FastMCP tools
227+
# FastMCP generates outputSchema but doesn't populate it
233228
if maybe_structured_content is None and tool:
234-
output_schema = getattr(tool, 'outputSchema', None)
235-
if output_schema and output_schema.get('x-fastmcp-wrap-result'):
229+
output_schema = getattr(tool, "outputSchema", None)
230+
if output_schema and output_schema.get(
231+
"x-fastmcp-wrap-result"
232+
):
236233
for item in unstructured_content:
237234
if isinstance(item, types.TextContent):
238235
try:
239-
maybe_structured_content = {"result": json.loads(item.text)}
236+
parsed = json.loads(item.text)
237+
maybe_structured_content = {
238+
"result": parsed
239+
}
240240
except json.JSONDecodeError:
241-
maybe_structured_content = {"result": item.text}
241+
maybe_structured_content = {
242+
"result": item.text
243+
}
242244
break
243245

244-
# result
245246
return types.ServerResult(
246247
types.CallToolResult(
247248
content=list(unstructured_content),

0 commit comments

Comments
 (0)