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