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(fs, cx, move |settings, _| {
73 settings
74 .project
75 .context_servers
76 .retain(|server_id, _| !context_server_ids.contains(server_id));
77 });
78}
79
80fn show_configure_mcp_modal(
81 language_registry: Arc<LanguageRegistry>,
82 manifest: &Arc<ExtensionManifest>,
83 workspace: WeakEntity<Workspace>,
84 window: &mut Window,
85 cx: &mut Context<'_, Workspace>,
86) {
87 if !window.is_window_active() {
88 return;
89 }
90
91 let ids = manifest.context_servers.keys().cloned().collect::<Vec<_>>();
92 if ids.is_empty() {
93 return;
94 }
95
96 window
97 .spawn(cx, async move |cx| {
98 for id in ids {
99 let Some(task) = cx
100 .update(|window, cx| {
101 ConfigureContextServerModal::show_modal_for_existing_server(
102 ContextServerId(id.clone()),
103 language_registry.clone(),
104 workspace.clone(),
105 window,
106 cx,
107 )
108 })
109 .ok()
110 else {
111 continue;
112 };
113 task.await.log_err();
114 }
115 })
116 .detach();
117}