Compare commits

..

No commits in common. "333bef1289787b4d9a0dbc080d0e478b8a3af0f1" and "dee850407d04ca77433c0312b86f5da9d8b21880" have entirely different histories.

2 changed files with 31 additions and 55 deletions

View File

@ -144,13 +144,16 @@ async def enhanced_generate_stream_response(
elif isinstance(msg, ToolMessage) and msg.content:
message_tag = "TOOL_RESPONSE"
waiting_for_answer_first_char = False
# Always output UIResource responses even when tool_response is disabled
# Always output UIResource, ask_user and render_ui responses even when tool_response is disabled
is_ui_resource = (
msg.text
and msg.text.lstrip().startswith('{"')
and '"ui://' in msg.text
and ('"text/html' in msg.text or '"text/uri-list' in msg.text)
)
if config.tool_response or is_ui_resource:
is_ask_user = msg.name == 'ask_user'
is_render_ui = msg.name == 'render_ui'
if config.tool_response or is_ui_resource or is_ask_user or is_render_ui:
new_content = f"[{message_tag}] {msg.name}\n{msg.text}\n"
# Collect full content

View File

@ -8,8 +8,6 @@ import json
import sys
from typing import Any, Dict
from mcp_ui_server import create_ui_resource, UIMetadataKey
from mcp_common import (
create_error_response,
create_initialize_response,
@ -20,65 +18,40 @@ from mcp_common import (
)
def _serialize_ui_resource(ui_resource) -> str:
"""Serialize a UIResource to JSON string."""
return json.dumps(ui_resource.model_dump(mode="json"), ensure_ascii=False)
ASK_USER_RESPONSE = "Questions sent to user."
def ask_user() -> Dict[str, Any]:
"""Return a UIResource response for ask_user tool.
"""Return a minimal fixed response for ask_user tool.
The actual questions are in the TOOL_CALL arguments. The frontend
detects ui_type from the UIResource metadata and extracts content
from the corresponding TOOL_CALL args.
The actual questions/options are already in the TOOL_CALL arguments,
so the frontend parses them directly from there. This response only
serves to acknowledge the tool call and minimize token usage in the
subsequent LLM inference round.
"""
resource = create_ui_resource({
"uri": "ui://mcp-ui/ask-user",
"content": {"type": "rawHtml", "htmlString": "Questions sent to user."},
"encoding": "text",
"uiMetadata": {
"type": "ask_user",
"interactive": True,
},
})
return {"content": [{"type": "text", "text": _serialize_ui_resource(resource)}]}
return {
"content": [
{"type": "text", "text": ASK_USER_RESPONSE}
]
}
def render_ui(arguments: Dict[str, Any]) -> Dict[str, Any]:
"""Return a UIResource response for render_ui tool.
RENDER_UI_RESPONSE = "UI rendered."
The actual html_content/url is in the TOOL_CALL arguments. The frontend
detects ui_type from the UIResource metadata and extracts content
from the corresponding TOOL_CALL args.
def render_ui() -> Dict[str, Any]:
"""Return a minimal fixed response for render_ui tool.
The actual html_content/url is already in the TOOL_CALL arguments,
so the frontend parses them directly from there. This response only
serves to acknowledge the tool call and minimize token usage in the
subsequent LLM inference round.
"""
html_content = arguments.get("html_content", "")
url = arguments.get("url", "")
width = arguments.get("width", "100%")
height = arguments.get("height", "auto")
if html_content:
resource = create_ui_resource({
"uri": "ui://mcp-ui/render-ui",
"content": {"type": "rawHtml", "htmlString": "UI rendered."},
"encoding": "text",
"uiMetadata": {
UIMetadataKey.PREFERRED_FRAME_SIZE: [width, height],
"type": "render_ui_html",
"interactive": False,
},
})
else:
resource = create_ui_resource({
"uri": "ui://mcp-ui/render-ui",
"content": {"type": "externalUrl", "iframeUrl": url},
"encoding": "text",
"uiMetadata": {
UIMetadataKey.PREFERRED_FRAME_SIZE: [width, height],
"type": "render_ui_url",
"interactive": False,
},
})
return {"content": [{"type": "text", "text": _serialize_ui_resource(resource)}]}
return {
"content": [
{"type": "text", "text": RENDER_UI_RESPONSE}
]
}
async def handle_request(request: Dict[str, Any]) -> Dict[str, Any]:
@ -136,7 +109,7 @@ async def handle_request(request: Dict[str, Any]) -> Dict[str, Any]:
request_id, -32602, "Missing required parameter: html_content or url"
)
result = render_ui(arguments)
result = render_ui()
return {"jsonrpc": "2.0", "id": request_id, "result": result}
elif tool_name == "ask_user":