context_server_configuration.rs

  1use std::sync::Arc;
  2
  3use context_server::ContextServerId;
  4use extension::ExtensionManifest;
  5use fs::Fs;
  6use gpui::WeakEntity;
  7use language::LanguageRegistry;
  8use project::project_settings::ProjectSettings;
  9use settings::update_settings_file;
 10use ui::prelude::*;
 11use util::ResultExt;
 12use workspace::Workspace;
 13
 14use crate::agent_configuration::ConfigureContextServerModal;
 15
 16pub(crate) fn init(language_registry: Arc<LanguageRegistry>, fs: Arc<dyn Fs>, cx: &mut App) {
 17    cx.observe_new(move |_: &mut Workspace, window, cx| {
 18        let Some(window) = window else {
 19            return;
 20        };
 21
 22        if let Some(extension_events) = extension::ExtensionEvents::try_global(cx).as_ref() {
 23            cx.subscribe_in(extension_events, window, {
 24                let language_registry = language_registry.clone();
 25                let fs = fs.clone();
 26                move |_, _, event, window, cx| match event {
 27                    extension::Event::ExtensionInstalled(manifest) => {
 28                        show_configure_mcp_modal(
 29                            language_registry.clone(),
 30                            manifest,
 31                            cx.weak_entity(),
 32                            window,
 33                            cx,
 34                        );
 35                    }
 36                    extension::Event::ExtensionUninstalled(manifest) => {
 37                        remove_context_server_settings(
 38                            manifest.context_servers.keys().cloned().collect(),
 39                            fs.clone(),
 40                            cx,
 41                        );
 42                    }
 43                    extension::Event::ConfigureExtensionRequested(manifest) => {
 44                        if !manifest.context_servers.is_empty() {
 45                            show_configure_mcp_modal(
 46                                language_registry.clone(),
 47                                manifest,
 48                                cx.weak_entity(),
 49                                window,
 50                                cx,
 51                            );
 52                        }
 53                    }
 54                    _ => {}
 55                }
 56            })
 57            .detach();
 58        } else {
 59            log::info!(
 60                "No extension events global found. Skipping context server configuration wizard"
 61            );
 62        }
 63    })
 64    .detach();
 65}
 66
 67fn remove_context_server_settings(
 68    context_server_ids: Vec<Arc<str>>,
 69    fs: Arc<dyn Fs>,
 70    cx: &mut App,
 71) {
 72    update_settings_file(fs, cx, move |settings, _| {
 73        settings
 74            .project
 75            .context_servers
 76            .retain(|server_id, _| !context_server_ids.contains(server_id));
 77    });
 78}
 79
 80fn show_configure_mcp_modal(
 81    language_registry: Arc<LanguageRegistry>,
 82    manifest: &Arc<ExtensionManifest>,
 83    workspace: WeakEntity<Workspace>,
 84    window: &mut Window,
 85    cx: &mut Context<'_, Workspace>,
 86) {
 87    if !window.is_window_active() {
 88        return;
 89    }
 90
 91    let ids = manifest.context_servers.keys().cloned().collect::<Vec<_>>();
 92    if ids.is_empty() {
 93        return;
 94    }
 95
 96    window
 97        .spawn(cx, async move |cx| {
 98            for id in ids {
 99                let Some(task) = cx
100                    .update(|window, cx| {
101                        ConfigureContextServerModal::show_modal_for_existing_server(
102                            ContextServerId(id.clone()),
103                            language_registry.clone(),
104                            workspace.clone(),
105                            window,
106                            cx,
107                        )
108                    })
109                    .ok()
110                else {
111                    continue;
112                };
113                task.await.log_err();
114            }
115        })
116        .detach();
117}