ZIm/crates/project/src/context_server_store/registry.rs
Danilo Leal 34322ef1cd
agent: Fix bug that prevented MCP servers to appear in the settings view (#33857)
Closes https://github.com/zed-industries/zed/issues/33827

After #33644 was merged, we would not start MCP servers coming from
extensions correctly anymore. The optimization uncovered a bug in the
implementation of `ContextServerDescriptorRegistry`, because we never
called `cx.notify()` when adding/removing context servers.
`ContextServerStore` listens for these events, and before #33644 this
was just working because of aace condition.

Release Notes:

- agent: Fixed bug that prevented MCP servers to appear in the settings
view.

Co-authored-by: Bennet Bo Fenner <bennetbo@gmx.de>
2025-07-03 15:05:29 +00:00

84 lines
2.5 KiB
Rust

use std::sync::Arc;
use anyhow::Result;
use collections::HashMap;
use context_server::ContextServerCommand;
use extension::ContextServerConfiguration;
use gpui::{App, AppContext as _, AsyncApp, Context, Entity, Global, Task};
use crate::worktree_store::WorktreeStore;
pub trait ContextServerDescriptor {
fn command(
&self,
worktree_store: Entity<WorktreeStore>,
cx: &AsyncApp,
) -> Task<Result<ContextServerCommand>>;
fn configuration(
&self,
worktree_store: Entity<WorktreeStore>,
cx: &AsyncApp,
) -> Task<Result<Option<ContextServerConfiguration>>>;
}
struct GlobalContextServerDescriptorRegistry(Entity<ContextServerDescriptorRegistry>);
impl Global for GlobalContextServerDescriptorRegistry {}
#[derive(Default)]
pub struct ContextServerDescriptorRegistry {
context_servers: HashMap<Arc<str>, Arc<dyn ContextServerDescriptor>>,
}
impl ContextServerDescriptorRegistry {
/// Returns the global [`ContextServerDescriptorRegistry`].
///
/// Inserts a default [`ContextServerDescriptorRegistry`] if one does not yet exist.
pub fn default_global(cx: &mut App) -> Entity<Self> {
if !cx.has_global::<GlobalContextServerDescriptorRegistry>() {
let registry = cx.new(|_| Self::new());
cx.set_global(GlobalContextServerDescriptorRegistry(registry));
}
cx.global::<GlobalContextServerDescriptorRegistry>()
.0
.clone()
}
pub fn new() -> Self {
Self {
context_servers: HashMap::default(),
}
}
pub fn context_server_descriptors(&self) -> Vec<(Arc<str>, Arc<dyn ContextServerDescriptor>)> {
self.context_servers
.iter()
.map(|(id, factory)| (id.clone(), factory.clone()))
.collect()
}
pub fn context_server_descriptor(&self, id: &str) -> Option<Arc<dyn ContextServerDescriptor>> {
self.context_servers.get(id).cloned()
}
/// Registers the provided [`ContextServerDescriptor`].
pub fn register_context_server_descriptor(
&mut self,
id: Arc<str>,
descriptor: Arc<dyn ContextServerDescriptor>,
cx: &mut Context<Self>,
) {
self.context_servers.insert(id, descriptor);
cx.notify();
}
/// Unregisters the [`ContextServerDescriptor`] for the server with the given ID.
pub fn unregister_context_server_descriptor_by_id(
&mut self,
server_id: &str,
cx: &mut Context<Self>,
) {
self.context_servers.remove(server_id);
cx.notify();
}
}