context_server_configuration.rs

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