From ab63d87b09c60f76b554cc239564b1dec1953571 Mon Sep 17 00:00:00 2001 From: baonudesifeizhai Date: Tue, 15 Jul 2025 13:35:28 -0400 Subject: [PATCH] feat: implement auto-generation for MCP server description - Add MCP_SERVER_DESCRIPTION_GENERATE_PROMPT template in prompts.py with detailed guidelines and examples - Implement generate_mcp_description method in LLMGenerator class for AI-powered description generation - Add AppMCPServerGenerateDescriptionController API endpoint for auto-generation functionality - Integrate auto-generate button in MCP server modal frontend with loading state - Add i18n support for auto-generate feature across multiple languages (en-US, zh-Hans, zh-Hant, ja-JP, ko-KR) - Include comprehensive fallback mechanism when LLM generation fails - Extract app features and characteristics for better description quality Fixes #22443 --- api/controllers/console/app/mcp_server.py | 108 ++++++++++++++++++ api/core/llm_generator/llm_generator.py | 98 ++++++++++++++++ api/core/llm_generator/prompts.py | 55 +++++++++ .../components/tools/mcp/mcp-server-modal.tsx | 31 ++++- web/i18n/en-US/tools.ts | 2 + web/i18n/ja-JP/tools.ts | 6 +- web/i18n/ko-KR/tools.ts | 12 +- web/i18n/zh-Hans/tools.ts | 2 + web/i18n/zh-Hant/tools.ts | 2 + web/service/use-tools.ts | 12 ++ 10 files changed, 319 insertions(+), 9 deletions(-) diff --git a/api/controllers/console/app/mcp_server.py b/api/controllers/console/app/mcp_server.py index 0f53860f56..c9b00a0583 100644 --- a/api/controllers/console/app/mcp_server.py +++ b/api/controllers/console/app/mcp_server.py @@ -103,5 +103,113 @@ class AppMCPServerRefreshController(Resource): return server +class AppMCPServerGenerateDescriptionController(Resource): + @setup_required + @login_required + @account_initialization_required + @get_app_model + def post(self, app_model): + """Generate MCP server description automatically based on app information""" + if not current_user.is_editor: + raise NotFound() + + from core.llm_generator.llm_generator import LLMGenerator + + # Extract app information for description generation + app_name = app_model.name + app_description = app_model.description or "" + app_type = app_model.mode or "" + + # Provide default descriptions if app_description is empty + if not app_description: + if app_type == "chat": + app_description = "An interactive conversational AI application for natural language communication" + elif app_type == "completion": + app_description = "A text generation application for creating high-quality content" + elif app_type == "agent-chat": + app_description = "An intelligent agent application with autonomous tool capabilities" + elif app_type == "workflow": + app_description = "A workflow-based application for automated task processing" + elif app_type == "advanced-chat": + app_description = "An advanced conversational AI with enhanced memory and reasoning" + else: + app_description = "An AI-powered application providing intelligent assistance" + + # Get key features from app configuration + key_features = "" + if app_model.app_model_config: + model_config = app_model.app_model_config.to_dict() + features = [] + + # Basic app features based on mode + if app_type == "chat": + features.append("Interactive chat conversations") + elif app_type == "completion": + features.append("Text generation and completion") + elif app_type == "agent-chat": + features.append("Intelligent agent with tool capabilities") + elif app_type == "workflow": + features.append("Workflow-based automation") + elif app_type == "advanced-chat": + features.append("Advanced conversational AI with memory") + + # Configuration-based features + if model_config.get("opening_statement"): + features.append("Custom greeting messages") + if model_config.get("suggested_questions"): + features.append("Suggested conversation starters") + if model_config.get("speech_to_text", {}).get("enabled"): + features.append("Voice input support") + if model_config.get("text_to_speech", {}).get("enabled"): + features.append("Voice response output") + if model_config.get("retriever_resource"): + features.append("Knowledge base integration") + if model_config.get("annotation_reply", {}).get("enabled"): + features.append("Enhanced response annotations") + if model_config.get("more_like_this", {}).get("enabled"): + features.append("Similar content suggestions") + if model_config.get("sensitive_word_avoidance", {}).get("enabled"): + features.append("Content moderation") + + # Model-based capabilities + if model_config.get("model", {}).get("name"): + model_name = model_config.get("model", {}).get("name", "") + if "gpt-4" in model_name.lower(): + features.append("Advanced reasoning capabilities") + elif "claude" in model_name.lower(): + features.append("Enhanced text analysis") + + key_features = ", ".join(features) if features else "AI-powered assistance" + + try: + # Generate description using LLM + description = LLMGenerator.generate_mcp_description( + tenant_id=current_user.current_tenant_id, + app_name=app_name, + app_description=app_description, + app_type=app_type, + key_features=key_features, + app_id=app_model.id, + ) + + return {"description": description} + + except Exception as e: + # Log the error for debugging + import logging + + logging.exception("MCP description generation failed") + + # Fallback to a basic description if generation fails + fallback_description = ( + f"A {app_type or 'AI'} application '{app_name}' that provides " + f"intelligent assistance and automated capabilities for enhanced " + f"user productivity and task completion." + ) + + return {"description": fallback_description, "error": str(e), "fallback": True} + + api.add_resource(AppMCPServerController, "/apps//server") api.add_resource(AppMCPServerRefreshController, "/apps//server/refresh") +api.add_resource(AppMCPServerGenerateDescriptionController, "/apps//server/generate-description") diff --git a/api/core/llm_generator/llm_generator.py b/api/core/llm_generator/llm_generator.py index e01896a491..064a7bc8d0 100644 --- a/api/core/llm_generator/llm_generator.py +++ b/api/core/llm_generator/llm_generator.py @@ -11,6 +11,7 @@ from core.llm_generator.prompts import ( CONVERSATION_TITLE_PROMPT, GENERATOR_QA_PROMPT, JAVASCRIPT_CODE_GENERATOR_PROMPT_TEMPLATE, + MCP_SERVER_DESCRIPTION_GENERATE_PROMPT, PYTHON_CODE_GENERATOR_PROMPT_TEMPLATE, SYSTEM_STRUCTURED_OUTPUT_GENERATE, WORKFLOW_RULE_CONFIG_PROMPT_GENERATE_TEMPLATE, @@ -394,3 +395,100 @@ class LLMGenerator: except Exception as e: logging.exception(f"Failed to invoke LLM model, model: {model_config.get('name')}") return {"output": "", "error": f"An unexpected error occurred: {str(e)}"} + + @classmethod + def generate_mcp_description( + cls, + tenant_id: str, + app_name: str, + app_description: str = "", + app_type: str = "", + key_features: str = "", + app_id: Optional[str] = None, + ) -> str: + """ + Generate MCP server description based on application information. + + Args: + tenant_id: The tenant ID + app_name: The application name + app_description: The application description + app_type: The application type + key_features: Key features of the application + app_id: Optional application ID for tracing + + Returns: + Generated description string + """ + try: + # Prepare the prompt with application information + prompt_template = PromptTemplateParser(template=MCP_SERVER_DESCRIPTION_GENERATE_PROMPT) + prompt = prompt_template.format( + { + "APP_NAME": app_name, + "APP_DESCRIPTION": app_description or "Not provided", + "APP_TYPE": app_type or "Not specified", + "KEY_FEATURES": key_features or "Not specified", + } + ) + + model_manager = ModelManager() + model_instance = model_manager.get_default_model_instance( + tenant_id=tenant_id, + model_type=ModelType.LLM, + ) + + prompts = [UserPromptMessage(content=prompt)] + + with measure_time() as timer: + response = cast( + LLMResult, + model_instance.invoke_llm( + prompt_messages=list(prompts), + model_parameters={"max_tokens": 150, "temperature": 0.7}, + stream=False, + ), + ) + + generated_description = cast(str, response.message.content).strip() + + # Clean up the description (remove quotes if present) + if generated_description.startswith('"') and generated_description.endswith('"'): + generated_description = generated_description[1:-1] + + # Limit length to 200 characters + if len(generated_description) > 200: + generated_description = generated_description[:197] + "..." + + # Add tracing if app_id is provided + if app_id: + trace_manager = TraceQueueManager(app_id=app_id) + trace_manager.add_trace_task( + TraceTask( + TraceTaskName.GENERATE_NAME_TRACE, # Reusing existing trace type + generate_conversation_name=f"MCP Description: {generated_description}", + inputs=prompt, + timer=timer, + tenant_id=tenant_id, + ) + ) + + return generated_description + + except Exception as e: + logging.exception(f"Failed to generate MCP description for app: {app_name}") + # Return a more detailed fallback description + fallback_desc = ( + f"A comprehensive {app_type or 'AI'} application called '{app_name}' " + f"designed to provide intelligent assistance and advanced automation " + f"capabilities. This MCP server enables seamless integration with AI " + f"assistants, offering {key_features or 'powerful AI features'} to " + f"enhance productivity and streamline workflows for users across " + f"various tasks and scenarios." + ) + + # Limit fallback length to 600 characters + if len(fallback_desc) > 600: + fallback_desc = fallback_desc[:597] + "..." + + return fallback_desc diff --git a/api/core/llm_generator/prompts.py b/api/core/llm_generator/prompts.py index ef81e38dc5..0d679bc60c 100644 --- a/api/core/llm_generator/prompts.py +++ b/api/core/llm_generator/prompts.py @@ -309,3 +309,58 @@ eg: Here is the JSON schema: {{schema}} """ # noqa: E501 + +MCP_SERVER_DESCRIPTION_GENERATE_PROMPT = """You are an expert technical writer specializing in creating clear and +comprehensive descriptions for MCP (Model Context Protocol) servers. + +Your task is to generate a professional description for an MCP server based on the provided application information. + +## Guidelines: +1. The description should be comprehensive (200-600 characters) +2. Focus on the core functionality and purpose +3. Use clear, professional language +4. Include key features and capabilities +5. Make it user-friendly and understandable +6. Explain how the MCP server enhances the application's functionality +7. Provide enough detail to help users understand the value proposition + +## Input Information: +- Application Name: {{APP_NAME}} +- Application Description: {{APP_DESCRIPTION}} +- Application Type: {{APP_TYPE}} +- Key Features: {{KEY_FEATURES}} + +## Instructions: +1. Analyze the application information provided +2. Identify the core purpose and main functionality +3. Generate a detailed description that explains what this MCP server does +4. Include specific capabilities and how they benefit users +5. Explain the integration value for AI assistants +6. Focus on practical benefits and use cases +7. Keep the language accessible to both technical and non-technical users + +## Output Format: +Return only the description text without any additional formatting, quotes, or explanations. + +## Examples: + +### For a Task Manager: +A comprehensive productivity MCP server that enables intelligent task management through automated +organization, deadline tracking, and priority optimization. This server provides AI assistants with +capabilities to create, update, and analyze tasks while offering smart scheduling suggestions, progress +monitoring, and workflow automation to enhance user productivity and goal achievement. + +### For a Weather App: +A powerful weather intelligence MCP server that delivers real-time meteorological data, location-based +forecasting, and weather analytics. This server empowers AI assistants to provide accurate weather +information, severe weather alerts, travel planning assistance, and activity recommendations based on +current and predicted weather conditions for enhanced decision-making. + +### For a Data Analyzer: +An advanced analytics MCP server that provides comprehensive data processing, statistical analysis, and +visualization capabilities. This server enables AI assistants to perform complex data operations, generate +insights, create interactive charts, and deliver actionable intelligence from datasets to support +data-driven decision making and business intelligence needs. + +Generate description: +""" diff --git a/web/app/components/tools/mcp/mcp-server-modal.tsx b/web/app/components/tools/mcp/mcp-server-modal.tsx index 9eb33f21ec..5545d123ed 100644 --- a/web/app/components/tools/mcp/mcp-server-modal.tsx +++ b/web/app/components/tools/mcp/mcp-server-modal.tsx @@ -1,7 +1,7 @@ 'use client' import React from 'react' import { useTranslation } from 'react-i18next' -import { RiCloseLine } from '@remixicon/react' +import { RiCloseLine, RiMagicLine } from '@remixicon/react' import Modal from '@/app/components/base/modal' import Button from '@/app/components/base/button' import Textarea from '@/app/components/base/textarea' @@ -12,6 +12,7 @@ import type { } from '@/app/components/tools/types' import { useCreateMCPServer, + useGenerateMCPDescription, useInvalidateMCPServerDetail, useUpdateMCPServer, } from '@/service/use-tools' @@ -35,6 +36,7 @@ const MCPServerModal = ({ const { t } = useTranslation() const { mutateAsync: createMCPServer, isPending: creating } = useCreateMCPServer() const { mutateAsync: updateMCPServer, isPending: updating } = useUpdateMCPServer() + const { mutateAsync: generateDescription, isPending: generating } = useGenerateMCPDescription() const invalidateMCPServerDetail = useInvalidateMCPServerDetail() const [description, setDescription] = React.useState(data?.description || '') @@ -56,6 +58,17 @@ const MCPServerModal = ({ return res } + const handleGenerateDescription = async () => { + try { + const result: any = await generateDescription({ appID }) + if (result?.description) + setDescription(result.description) + } + catch (error) { + console.error('Failed to generate description:', error) + } + } + const submit = async () => { if (!data) { await createMCPServer({ @@ -92,9 +105,23 @@ const MCPServerModal = ({
-
+
+
{t('tools.mcp.server.modal.description')}
*
+
+