@@ -977,3 +977,73 @@ async def test_mcp_longterm_token_fails_without_superuser():
977977 async with session_scope () as session :
978978 with pytest .raises (HTTPException , match = "Auto login required to create a long-term token" ):
979979 await create_user_longterm_token (session )
980+
981+
982+ def _prepare_installed_check_env (monkeypatch , tmp_path ):
983+ """Set up environment for check_installed_mcp_servers tests.
984+
985+ Creates per-client config directories under tmp_path so that
986+ ``get_config_path`` returns paths whose *parent* directories exist
987+ but whose config *files* may or may not exist.
988+ """
989+ client_paths = {
990+ "cursor" : tmp_path / "cursor" / "mcp.json" ,
991+ "windsurf" : tmp_path / "windsurf" / "mcp_config.json" ,
992+ "claude" : tmp_path / "claude" / "claude_desktop_config.json" ,
993+ }
994+ # Create parent directories (simulating installed applications)
995+ for path in client_paths .values ():
996+ path .parent .mkdir (parents = True , exist_ok = True )
997+
998+ async def fake_get_config_path (client_name ):
999+ return client_paths [client_name ]
1000+
1001+ monkeypatch .setattr ("langflow.api.v1.mcp_projects.get_config_path" , fake_get_config_path )
1002+ monkeypatch .setattr ("langflow.api.v1.mcp_projects.should_use_mcp_composer" , lambda project : False ) # noqa: ARG005
1003+
1004+ async def fake_streamable (project_id ):
1005+ return f"https://langflow.local/api/v1/mcp/project/{ project_id } /streamable"
1006+
1007+ async def fake_sse (project_id ):
1008+ return f"https://langflow.local/api/v1/mcp/project/{ project_id } /sse"
1009+
1010+ monkeypatch .setattr ("langflow.api.v1.mcp_projects.get_project_streamable_http_url" , fake_streamable )
1011+ monkeypatch .setattr ("langflow.api.v1.mcp_projects.get_project_sse_url" , fake_sse )
1012+
1013+ return client_paths
1014+
1015+
1016+ async def test_should_report_available_true_when_app_directory_exists_but_config_file_missing (
1017+ client : AsyncClient ,
1018+ user_test_project ,
1019+ logged_in_headers ,
1020+ tmp_path ,
1021+ monkeypatch ,
1022+ ):
1023+ """Bug: FileNotFoundError when config file is missing marks client as unavailable.
1024+
1025+ GIVEN: App directories exist (e.g. ~/.cursor/) but config files don't exist yet
1026+ WHEN: GET /mcp/project/{id}/installed is called
1027+ THEN: Each client should have available=True (app is installed) and installed=False (not configured)
1028+ """
1029+ _prepare_installed_check_env (monkeypatch , tmp_path )
1030+
1031+ response = await client .get (
1032+ f"/api/v1/mcp/project/{ user_test_project .id } /installed" ,
1033+ headers = logged_in_headers ,
1034+ )
1035+
1036+ assert response .status_code == 200
1037+ results = response .json ()
1038+
1039+ # All three clients should be reported
1040+ assert len (results ) == 3
1041+
1042+ for entry in results :
1043+ assert entry ["available" ] is True , (
1044+ f"{ entry ['name' ]} should be available (directory exists) "
1045+ f"even when config file is missing"
1046+ )
1047+ assert entry ["installed" ] is False , (
1048+ f"{ entry ['name' ]} should not be installed (config file doesn't exist)"
1049+ )
0 commit comments