1use std::sync::Arc;
2
3use context_server::ContextServerId;
4use extension::ExtensionManifest;
5use fs::Fs;
6use gpui::WeakEntity;
7use language::LanguageRegistry;
8use project::project_settings::ProjectSettings;
9use settings::update_settings_file;
10use ui::prelude::*;
11use util::ResultExt;
12use workspace::Workspace;
13
14use crate::agent_configuration::ConfigureContextServerModal;
15
16pub(crate) fn init(language_registry: Arc<LanguageRegistry>, fs: Arc<dyn Fs>, cx: &mut App) {
17 cx.observe_new(move |_: &mut Workspace, window, cx| {
18 let Some(window) = window else {
19 return;
20 };
21
22 if let Some(extension_events) = extension::ExtensionEvents::try_global(cx).as_ref() {
23 cx.subscribe_in(extension_events, window, {
24 let language_registry = language_registry.clone();
25 let fs = fs.clone();
26 move |_, _, event, window, cx| match event {
27 extension::Event::ExtensionInstalled(manifest) => {
28 show_configure_mcp_modal(
29 language_registry.clone(),
30 manifest,
31 cx.weak_entity(),
32 window,
33 cx,
34 );
35 }
36 extension::Event::ExtensionUninstalled(manifest) => {
37 remove_context_server_settings(
38 manifest.context_servers.keys().cloned().collect(),
39 fs.clone(),
40 cx,
41 );
42 }
43 extension::Event::ConfigureExtensionRequested(manifest) => {
44 if !manifest.context_servers.is_empty() {
45 show_configure_mcp_modal(
46 language_registry.clone(),
47 manifest,
48 cx.weak_entity(),
49 window,
50 cx,
51 );
52 }
53 }
54 _ => {}
55 }
56 })
57 .detach();
58 } else {
59 log::info!(
60 "No extension events global found. Skipping context server configuration wizard"
61 );
62 }
63 })
64 .detach();
65}
66
67fn remove_context_server_settings(
68 context_server_ids: Vec<Arc<str>>,
69 fs: Arc<dyn Fs>,
70 cx: &mut App,
71) {
72 update_settings_file::<ProjectSettings>(fs, cx, move |settings, _| {
73 settings
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}