context_server_configuration.rs

  1use std::sync::Arc;
  2
  3use anyhow::Context as _;
  4use context_server::ContextServerId;
  5use extension::ExtensionManifest;
  6use language::LanguageRegistry;
  7use project::context_server_store::registry::ContextServerDescriptorRegistry;
  8use ui::prelude::*;
  9use util::ResultExt;
 10use workspace::Workspace;
 11
 12use crate::assistant_configuration::ConfigureContextServerModal;
 13
 14pub(crate) fn init(language_registry: Arc<LanguageRegistry>, cx: &mut App) {
 15    cx.observe_new(move |_: &mut Workspace, window, cx| {
 16        let Some(window) = window else {
 17            return;
 18        };
 19
 20        if let Some(extension_events) = extension::ExtensionEvents::try_global(cx).as_ref() {
 21            cx.subscribe_in(extension_events, window, {
 22                let language_registry = language_registry.clone();
 23                move |workspace, _, event, window, cx| match event {
 24                    extension::Event::ExtensionInstalled(manifest) => {
 25                        show_configure_mcp_modal(
 26                            language_registry.clone(),
 27                            manifest,
 28                            workspace,
 29                            window,
 30                            cx,
 31                        );
 32                    }
 33                    extension::Event::ConfigureExtensionRequested(manifest) => {
 34                        if !manifest.context_servers.is_empty() {
 35                            show_configure_mcp_modal(
 36                                language_registry.clone(),
 37                                manifest,
 38                                workspace,
 39                                window,
 40                                cx,
 41                            );
 42                        }
 43                    }
 44                    _ => {}
 45                }
 46            })
 47            .detach();
 48        } else {
 49            log::info!(
 50                "No extension events global found. Skipping context server configuration wizard"
 51            );
 52        }
 53    })
 54    .detach();
 55}
 56
 57fn show_configure_mcp_modal(
 58    language_registry: Arc<LanguageRegistry>,
 59    manifest: &Arc<ExtensionManifest>,
 60    workspace: &mut Workspace,
 61    window: &mut Window,
 62    cx: &mut Context<'_, Workspace>,
 63) {
 64    let context_server_store = workspace.project().read(cx).context_server_store();
 65
 66    let registry = ContextServerDescriptorRegistry::default_global(cx).read(cx);
 67    let worktree_store = workspace.project().read(cx).worktree_store();
 68    let configuration_tasks = manifest
 69        .context_servers
 70        .keys()
 71        .cloned()
 72        .filter_map({
 73            |key| {
 74                let descriptor = registry.context_server_descriptor(&key)?;
 75                Some(cx.spawn({
 76                    let worktree_store = worktree_store.clone();
 77                    async move |_, cx| {
 78                        descriptor
 79                            .configuration(worktree_store.clone(), &cx)
 80                            .await
 81                            .context("Failed to resolve context server configuration")
 82                            .log_err()
 83                            .flatten()
 84                            .map(|config| (ContextServerId(key), config))
 85                    }
 86                }))
 87            }
 88        })
 89        .collect::<Vec<_>>();
 90
 91    let jsonc_language = language_registry.language_for_name("jsonc");
 92
 93    cx.spawn_in(window, async move |this, cx| {
 94        let descriptors = futures::future::join_all(configuration_tasks).await;
 95        let jsonc_language = jsonc_language.await.ok();
 96
 97        this.update_in(cx, |this, window, cx| {
 98            let modal = ConfigureContextServerModal::new(
 99                descriptors.into_iter().flatten(),
100                context_server_store,
101                jsonc_language,
102                language_registry,
103                cx.entity().downgrade(),
104                window,
105                cx,
106            );
107            if let Some(modal) = modal {
108                this.toggle_modal(window, cx, |_, _| modal);
109            }
110        })
111    })
112    .detach();
113}