From c4995d508840478c86bf7675aea2d02d01e14828 Mon Sep 17 00:00:00 2001 From: dimitrievgs Date: Sun, 14 Jun 2026 01:33:20 +0300 Subject: [PATCH] Add customization of prompts for MCP tools --- app/api.py | 15 +++++++++++++++ app/mcp_tools.py | 50 +++++++++++++++++++++++++++++++++++++++++++++++- app/workflows.py | 17 ++++++++++++++-- 3 files changed, 79 insertions(+), 3 deletions(-) diff --git a/app/api.py b/app/api.py index 21bcb2b..67d0e5e 100644 --- a/app/api.py +++ b/app/api.py @@ -11,6 +11,7 @@ from flask_socketio import SocketIO from workflows import graph_history_manager, run_agent_streaming from llm_client import DEFAULT_TEMPERATURE, MODELS, get_llm # Добавляем импорт списка моделей import base64 +from mcp_tools import get_raw_mcp_tools_list api = Flask(__name__) CORS( @@ -414,6 +415,20 @@ def regenerate_message(): return jsonify({"error": str(e)}, 500) +@api.route('/api/mcp/fetch', methods=['POST']) +def fetch_mcp_tools_route(): + """API endpoint для получения списка инструментов MCP сервера (без создания LangChain тулов)""" + server_config = request.get_json() + if not server_config: + return jsonify({"error": "Пустой конфиг сервера"}), 400 + + try: + tools_list = get_raw_mcp_tools_list(server_config) + return jsonify(tools_list) + except Exception as e: + return jsonify({"error": str(e)}), 500 + + from voice_service import VoiceService, VOICE_COMMANDS_RESPONSE_TO_STORE # 1. Создаем экземпляр (обязательно укажите путь к вашей модели Vosk) diff --git a/app/mcp_tools.py b/app/mcp_tools.py index 178e989..93772f7 100644 --- a/app/mcp_tools.py +++ b/app/mcp_tools.py @@ -115,11 +115,59 @@ def fetch_mcp_tools(server_config, debug_callback=None): try: raw_tools, full_env, args = asyncio.run(_fetch()) wrapped_tools = [] + + # Получаем кастомные описания из конфига + fetched_tools_ui = server_config.get("fetchedTools", []) + custom_descriptions = {t.get("name"): t.get("customDescription") for t in fetched_tools_ui} + for t in raw_tools: - wrapped_tools.append(create_mcp_tool(server_config, t.name, t.description, t.inputSchema, full_env, args, debug_callback)) + # Если есть кастомное описание и оно не пустое - используем его + c_desc = custom_descriptions.get(t.name) + final_description = c_desc if c_desc and c_desc.strip() else t.description + + wrapped_tools.append(create_mcp_tool(server_config, t.name, final_description, t.inputSchema, full_env, args, debug_callback)) + _MCP_CACHED_TOOLS[config_hash] = wrapped_tools print(f"🔌 Успешно загружено {len(wrapped_tools)} инструментов от MCP-сервера '{server_config.get('name')}'") return wrapped_tools except Exception as e: print(f"❌ Ошибка инициализации MCP сервера {server_config.get('name')}: {e}") return [] + +def get_raw_mcp_tools_list(server_config): + """Метод для UI: просто возвращает список доступных инструментов в JSON-friendly формате""" + if not MCP_AVAILABLE: + return [] + + import asyncio + import shlex + import os + + async def _fetch_raw(): + command = server_config.get("command", "") + args_str = server_config.get("args", "") + args = shlex.split(args_str) if args_str else [] + + env_dict = {} + env_str = server_config.get("envString", "") + if env_str: + for pair in env_str.split(','): + if '=' in pair: + k, v = pair.split('=', 1) + env_dict[k.strip()] = v.strip() + + full_env = {**os.environ.copy(), **env_dict} + server_params = StdioServerParameters(command=command, args=args, env=full_env) + + async with stdio_client(server_params) as (read, write): + async with ClientSession(read, write) as session: + await session.initialize() + tools_resp = await session.list_tools() + return tools_resp.tools + + try: + raw_tools = asyncio.run(_fetch_raw()) + return [{"name": t.name, "description": t.description} for t in raw_tools] + except Exception as e: + print(f"Ошибка получения списка тулов: {e}") + return [] \ No newline at end of file diff --git a/app/workflows.py b/app/workflows.py index 2a6d504..51766c1 100644 --- a/app/workflows.py +++ b/app/workflows.py @@ -40,8 +40,21 @@ def run_agent_streaming(graph_id: str, # 2. Формируем контекст LangChain с учетом файлов и изображений (вложений) messages_for_llm = [] - if system_prompt: - messages_for_llm.append(SystemMessage(content=system_prompt)) + + # Собираем над-инструкции для MCP серверов + mcp_instructions = [] + if obsidian_settings and obsidian_settings.get("mcpServers"): + for server in obsidian_settings.get("mcpServers", []): + s_instr = server.get("serverInstruction") + if s_instr and s_instr.strip(): + mcp_instructions.append(f"Инструкции для использования инструментов сервера '{server.get('name')}':\n{s_instr.strip()}") + + final_system_prompt = system_prompt or "" + if mcp_instructions: + final_system_prompt += "\n\n" + "\n\n".join(mcp_instructions) + + if final_system_prompt: + messages_for_llm.append(SystemMessage(content=final_system_prompt.strip())) # Обрабатываем вложения for i, msg in enumerate(messages):