diff --git a/api/controllers/console/app/mcp_server.py b/api/controllers/console/app/mcp_server.py index b9a383ee61..a42326b134 100644 --- a/api/controllers/console/app/mcp_server.py +++ b/api/controllers/console/app/mcp_server.py @@ -142,7 +142,7 @@ class AppMCPServerRefreshController(Resource): @login_required @account_initialization_required @marshal_with(app_server_fields) - def get(self, server_id): + def post(self, server_id): if not current_user.is_editor: raise NotFound() server = ( diff --git a/api/tests/unit_tests/controllers/console/app/test_mcp_server_refresh.py b/api/tests/unit_tests/controllers/console/app/test_mcp_server_refresh.py new file mode 100644 index 0000000000..1cec88a32a --- /dev/null +++ b/api/tests/unit_tests/controllers/console/app/test_mcp_server_refresh.py @@ -0,0 +1,92 @@ +import inspect +from types import SimpleNamespace +from unittest.mock import MagicMock + +import pytest +from flask import Flask +from werkzeug.exceptions import NotFound + +from controllers.console.app.mcp_server import AppMCPServerRefreshController +from models.account import AccountStatus +from models.model import AppMCPServer + + +@pytest.fixture(autouse=True) +def configure_decorators(monkeypatch): + monkeypatch.setattr("libs.login.dify_config.LOGIN_DISABLED", True, raising=False) + monkeypatch.setattr("controllers.console.wraps.dify_config.EDITION", "CLOUD", raising=False) + + +@pytest.fixture +def mock_current_user(monkeypatch): + user = SimpleNamespace( + is_editor=True, + status=AccountStatus.ACTIVE, + current_tenant_id="tenant-id", + is_authenticated=True, + ) + from controllers.console.app import mcp_server as mcp_module + + monkeypatch.setattr(mcp_module, "current_user", user, raising=False) + monkeypatch.setattr("controllers.console.wraps.current_user", user, raising=False) + return user + + +@pytest.fixture +def mock_db_session(monkeypatch): + mock_session = MagicMock() + mock_db = SimpleNamespace(session=mock_session) + from controllers.console.app import mcp_server as mcp_module + + monkeypatch.setattr(mcp_module, "db", mock_db, raising=False) + return mock_session + + +@pytest.fixture +def flask_app(): + app = Flask(__name__) + app.config["TESTING"] = True + return app + + +class TestAppMCPServerRefreshController: + def test_refresh_regenerates_server_code(self, flask_app, mock_current_user, mock_db_session, monkeypatch): + server = MagicMock(spec=AppMCPServer) + server.server_code = "old" + + server_query = MagicMock() + server_query.where.return_value = server_query + server_query.first.return_value = server + + mock_db_session.query.return_value = server_query + mock_db_session.commit = MagicMock() + + monkeypatch.setattr( + "models.model.AppMCPServer.generate_server_code", MagicMock(return_value="new"), raising=False + ) + + controller = AppMCPServerRefreshController() + refresh_handler = inspect.unwrap(AppMCPServerRefreshController.post) + + with flask_app.test_request_context("/apps/{}/server/refresh".format("app"), method="POST"): + result = refresh_handler(controller, "server-id") + + assert result is server + assert server.server_code == "new" + mock_db_session.commit.assert_called_once_with() + mock_db_session.query.assert_called_once() + + def test_refresh_requires_editor(self, flask_app, mock_current_user, mock_db_session, monkeypatch): + mock_current_user.is_editor = False + + mock_db_session.query.return_value = MagicMock() + mock_db_session.commit = MagicMock() + + controller = AppMCPServerRefreshController() + refresh_handler = inspect.unwrap(AppMCPServerRefreshController.post) + + with flask_app.test_request_context("/apps/{}/server/refresh".format("app"), method="POST"): + with pytest.raises(NotFound): + refresh_handler(controller, "server-id") + + mock_db_session.commit.assert_not_called() diff --git a/web/service/use-tools.ts b/web/service/use-tools.ts index e9d3ac1c8d..c2a711da7f 100644 --- a/web/service/use-tools.ts +++ b/web/service/use-tools.ts @@ -250,7 +250,9 @@ export const useRefreshMCPServerCode = () => { return useMutation({ mutationKey: [NAME_SPACE, 'refresh-mcp-server-code'], mutationFn: (appID: string) => { - return get(`apps/${appID}/server/refresh`) + return post(`apps/${appID}/server/refresh`, { + body: {}, + }) }, }) }