From 02085b789a65d43c17748f11d67b3f50e474af8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=B1=E6=BD=AE?= Date: Sun, 17 May 2026 14:07:25 +0800 Subject: [PATCH] support mcpUiUrl --- routes/chat.py | 2 +- .../common/mcp-ui/.claude-plugin/plugin.json | 8 +++ skills/common/mcp-ui/hooks/ask_user_guide.md | 57 ++++++++++++++++ skills/common/mcp-ui/hooks/pre_prompt.py | 18 +++++ skills/common/mcp-ui/mcp_ui_tools.json | 49 +++++++++----- skills/common/mcp-ui/ui_render_server.py | 67 ++++++++++++------- 6 files changed, 159 insertions(+), 42 deletions(-) create mode 100644 skills/common/mcp-ui/hooks/ask_user_guide.md create mode 100644 skills/common/mcp-ui/hooks/pre_prompt.py diff --git a/routes/chat.py b/routes/chat.py index 773bcfb..8845b4a 100644 --- a/routes/chat.py +++ b/routes/chat.py @@ -145,7 +145,7 @@ async def enhanced_generate_stream_response( msg.text and msg.text.lstrip().startswith('{"') and ( - ('"ui://' in msg.text and '"text/html' in msg.text) + ('"ui://' in msg.text and ('"text/html' in msg.text or '"text/uri-list' in msg.text)) or '"__ask_user__"' in msg.text ) ) diff --git a/skills/common/mcp-ui/.claude-plugin/plugin.json b/skills/common/mcp-ui/.claude-plugin/plugin.json index ee171cb..bb8ca06 100644 --- a/skills/common/mcp-ui/.claude-plugin/plugin.json +++ b/skills/common/mcp-ui/.claude-plugin/plugin.json @@ -1,6 +1,14 @@ { "name": "mcp-ui", "description": "Provides interactive UI components through MCP tool responses.", + "hooks": { + "PrePrompt": [ + { + "type": "command", + "command": "python hooks/pre_prompt.py" + } + ] + }, "mcpServers": { "mcp_ui": { "transport": "stdio", diff --git a/skills/common/mcp-ui/hooks/ask_user_guide.md b/skills/common/mcp-ui/hooks/ask_user_guide.md new file mode 100644 index 0000000..e43f4f8 --- /dev/null +++ b/skills/common/mcp-ui/hooks/ask_user_guide.md @@ -0,0 +1,57 @@ +## ask_user Tool Usage Guide + +When using the `ask_user` tool, follow these rules: + +### When to call ask_user +You MUST call this tool in these cases: +1. When you need single-select or multi-select choices from the user. +2. When you have multiple questions to ask at once — you MUST batch them into a single ask_user call. Do NOT list multiple questions as plain text in your response. + +The ONLY case where you do NOT need this tool is when there is exactly 1 open-ended question with no options to suggest — in that case, just ask directly in your response text. + +### CRITICAL: Every question MUST have options +When calling ask_user, you MUST generate at least 2-3 suggested options for EVERY question — even for questions that seem open-ended. You should infer reasonable options based on context. The user can always type a custom answer if none of the suggestions fit. + +Example: If the question is "What is the topic of the PPT?", do NOT leave options empty. Instead, suggest options like: +```json +{"question": "What is the topic of the PPT?", "options": ["Work report", "Product introduction", "Academic presentation", "Other"]} +``` + +Do NOT call ask_user with empty options arrays. + +### How to format options +- Options MUST be placed in the `options` array field, NOT embedded in the question text. +- Keep the question text short and clean — just the question itself. +- Each question MUST have at least 2 options in the options array. + +CORRECT example: +```json +{ + "questions": [ + { + "question": "Who is the audience?", + "options": ["Leadership", "Team", "Client"] + }, + { + "question": "How long is the presentation?", + "options": ["5-10 minutes", "15-20 minutes", "30+ minutes"] + } + ] +} +``` + +WRONG example (DO NOT do this): +```json +{ + "questions": [ + { + "question": "Who is the audience? A. Leadership B. Team C. Client", + "options": [] + } + ] +} +``` + +### Other rules +- Each question MUST be a separate item in the questions array. +- NEVER combine multiple questions into a single question string. diff --git a/skills/common/mcp-ui/hooks/pre_prompt.py b/skills/common/mcp-ui/hooks/pre_prompt.py new file mode 100644 index 0000000..6c14bf2 --- /dev/null +++ b/skills/common/mcp-ui/hooks/pre_prompt.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +""" +PrePrompt Hook - ask_user tool usage guide loader. + +Outputs the ask_user usage guide to be injected into the system prompt. +""" +import sys +from pathlib import Path + + +def main(): + guide_file = Path(__file__).parent / "ask_user_guide.md" + print(guide_file.read_text(encoding="utf-8")) + return 0 + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/skills/common/mcp-ui/mcp_ui_tools.json b/skills/common/mcp-ui/mcp_ui_tools.json index 8310c7f..95ea2fd 100644 --- a/skills/common/mcp-ui/mcp_ui_tools.json +++ b/skills/common/mcp-ui/mcp_ui_tools.json @@ -1,7 +1,7 @@ [ { "name": "render_ui", - "description": "Render an interactive HTML UI widget in the chat. Use this tool when the user asks for interactive content, visualizations, forms, or dynamic displays that benefit from rich HTML rendering rather than plain text.", + "description": "Render an interactive UI widget in the chat. Supports two modes: (1) raw HTML — provide html_content to render custom HTML/CSS/JS, (2) external URL — provide url to embed an external webpage in an iframe. Use html_content OR url, not both.", "inputSchema": { "type": "object", "properties": { @@ -11,7 +11,11 @@ }, "html_content": { "type": "string", - "description": "Complete HTML content to render. Can include inline CSS and JavaScript within