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}