Compare commits
2 Commits
dee850407d
...
333bef1289
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
333bef1289 | ||
|
|
add8a1fd18 |
@ -144,16 +144,13 @@ 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, ask_user and render_ui responses even when tool_response is disabled
|
||||
# Always output UIResource 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)
|
||||
)
|
||||
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:
|
||||
if config.tool_response or is_ui_resource:
|
||||
new_content = f"[{message_tag}] {msg.name}\n{msg.text}\n"
|
||||
|
||||
# Collect full content
|
||||
|
||||
@ -8,6 +8,8 @@ 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,
|
||||
@ -18,40 +20,65 @@ from mcp_common import (
|
||||
)
|
||||
|
||||
|
||||
ASK_USER_RESPONSE = "Questions sent to user."
|
||||
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)
|
||||
|
||||
|
||||
def ask_user() -> Dict[str, Any]:
|
||||
"""Return a minimal fixed response for ask_user tool.
|
||||
"""Return a UIResource response for ask_user tool.
|
||||
|
||||
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.
|
||||
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.
|
||||
"""
|
||||
return {
|
||||
"content": [
|
||||
{"type": "text", "text": ASK_USER_RESPONSE}
|
||||
]
|
||||
}
|
||||
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)}]}
|
||||
|
||||
|
||||
RENDER_UI_RESPONSE = "UI rendered."
|
||||
def render_ui(arguments: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Return a UIResource response for render_ui tool.
|
||||
|
||||
|
||||
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.
|
||||
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.
|
||||
"""
|
||||
return {
|
||||
"content": [
|
||||
{"type": "text", "text": RENDER_UI_RESPONSE}
|
||||
]
|
||||
}
|
||||
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)}]}
|
||||
|
||||
|
||||
async def handle_request(request: Dict[str, Any]) -> Dict[str, Any]:
|
||||
@ -109,7 +136,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()
|
||||
result = render_ui(arguments)
|
||||
return {"jsonrpc": "2.0", "id": request_id, "result": result}
|
||||
|
||||
elif tool_name == "ask_user":
|
||||
|
||||
Loading…
Reference in New Issue
Block a user