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}