From bf9ae948d51edeb0316f2e71ab91d1525386e212 Mon Sep 17 00:00:00 2001 From: CaptainB Date: Tue, 23 Dec 2025 10:50:48 +0800 Subject: [PATCH] chore: refactor app MCP configuration and implement AI chat functionality --- .../step/chat_step/impl/base_chat_step.py | 8 +-- apps/common/utils/app_mcp.py | 70 +++++++++++++++++++ apps/common/utils/tool_code.py | 57 +++------------ 3 files changed, 79 insertions(+), 56 deletions(-) create mode 100644 apps/common/utils/app_mcp.py diff --git a/apps/application/chat_pipeline/step/chat_step/impl/base_chat_step.py b/apps/application/chat_pipeline/step/chat_step/impl/base_chat_step.py index e1df2b8c6..9e64060be 100644 --- a/apps/application/chat_pipeline/step/chat_step/impl/base_chat_step.py +++ b/apps/application/chat_pipeline/step/chat_step/impl/base_chat_step.py @@ -269,14 +269,8 @@ class BaseChatStep(IChatStep): self.context['application_ids'] = application_ids for application_id in application_ids: app = QuerySet(Application).filter(id=application_id).first() - app_key = QuerySet(ApplicationApiKey).filter(application_id=application_id, is_active=True).first() - # TODO 处理api - if app_key is not None: - api_key = app_key.secret_key - else: - continue executor = ToolExecutor() - app_config = executor.get_app_mcp_config(api_key, app.name, app.desc) + app_config = executor.get_app_mcp_config(app.id, app.name, app.desc) mcp_servers_config[str(app.id)] = app_config if len(mcp_servers_config) > 0: diff --git a/apps/common/utils/app_mcp.py b/apps/common/utils/app_mcp.py new file mode 100644 index 000000000..806e0bbd4 --- /dev/null +++ b/apps/common/utils/app_mcp.py @@ -0,0 +1,70 @@ +import json +import logging +import os +import sys + +import uuid_utils.compat as uuid +from asgiref.sync import sync_to_async +from mcp.server.fastmcp import FastMCP + +logging.basicConfig(level=logging.WARNING) +logging.getLogger("mcp").setLevel(logging.ERROR) +logging.getLogger("mcp.server").setLevel(logging.ERROR) + + +def app_mcp_init(base_dir: str, application_id: str, name: str, description: str): + import django + + sys.path.insert(0, base_dir) + + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "maxkb.settings") + + django.setup() + mcp = FastMCP() + + @sync_to_async + def _get_chat_id(): + from application.models import ChatUserType + from chat.serializers.chat import OpenChatSerializers + from common.init import init_template + + init_template.run() + + return OpenChatSerializers(data={ + 'application_id': application_id, + 'chat_user_id': str(uuid.uuid7()), + 'chat_user_type': ChatUserType.ANONYMOUS_USER, + 'debug': False + }).open() + + @sync_to_async + def _chat_with_ai(chat_id: str, message: str) -> str: + from application.models import ChatUserType + from chat.serializers.chat import ChatSerializers + + payload = { + 'message': message, + 'stream': False, + 're_chat': False + } + resp = ChatSerializers(data={ + 'chat_id': chat_id, + 'chat_user_id': str(uuid.uuid7()), + 'chat_user_type': ChatUserType.ANONYMOUS_USER, + 'application_id': application_id, + 'debug': False, + }).chat(payload) + data = json.loads(str(resp.text)) + return str(data.get("data", {}).get("content") or data.get("response")) + + @mcp.tool(description=f'{name} {description}') + async def ai_chat(message: str) -> str: + chat_id = await _get_chat_id() + reply = await _chat_with_ai(chat_id, message) + + return reply or "AI 未能生成回复" + + mcp.run(transport='stdio') + + +app_mcp_init(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4]) diff --git a/apps/common/utils/tool_code.py b/apps/common/utils/tool_code.py index cd0e21226..03b3e49c2 100644 --- a/apps/common/utils/tool_code.py +++ b/apps/common/utils/tool_code.py @@ -233,59 +233,18 @@ exec({dedent(code)!a}) } return tool_config - def get_app_mcp_config(self, api_key, name, description): - chat_path = CONFIG.get_chat_path() - _code = f''' -import requests -from typing import Optional - -def _get_chat_id() -> Optional[str]: - url = f"http://127.0.0.1:8080{chat_path}/api/open" - headers = {{ - 'accept': '*/*', - 'Authorization': f'Bearer {api_key}' - }} - try: - resp = requests.get(url, headers=headers, timeout=10) - resp.raise_for_status() - return resp.json().get("data") - except Exception as e: - raise e - - -def _chat_with_ai(chat_id: str, message: str) -> Optional[str]: - url = f"http://127.0.0.1:8080{chat_path}/api/chat_message/{{chat_id}}" - headers = {{"Content-Type": "application/json", "Authorization": f'Bearer {api_key}'}} - payload = {{ - "message": message, - "re_chat": False, - "stream": False - }} - try: - resp = requests.post(url, json=payload, headers=headers, timeout=600) - resp.raise_for_status() - data = resp.json() - return str(data.get("data", {{}}).get("content") or data.get("response")) - except Exception as e: - raise e - -def ai_chat(message: str) -> str: - chat_id = _get_chat_id() - reply = _chat_with_ai(chat_id, message) - return reply or "AI 未能生成回复" - - ''' - _code = self.generate_mcp_server_code(_code, {}, name, description) - # print(_code) - maxkb_logger.debug(f"Python code of mcp app: {_code}") - compressed_and_base64_encoded_code_str = base64.b64encode(gzip.compress(_code.encode())).decode() + def get_app_mcp_config(self, application_id, name, description): + cwd = os.path.dirname(os.path.abspath(__file__)) app_config = { 'command': sys.executable, 'args': [ - '-c', - f'import base64,gzip; exec(gzip.decompress(base64.b64decode(\'{compressed_and_base64_encoded_code_str}\')).decode())', + f'{cwd}/app_mcp.py', + BASE_DIR, + str(application_id), + name, + description, ], - 'cwd': _sandbox_path, + 'cwd': BASE_DIR, 'env': { 'LD_PRELOAD': f'{_sandbox_path}/lib/sandbox.so', },