context_store: Refactor state management (#29910)

Because we instantiated `ContextServerManager` both in `agent` and
`assistant-context-editor`, and these two entities track the running MCP
servers separately, we were effectively running every MCP server twice.

This PR moves the `ContextServerManager` into the project crate (now
called `ContextServerStore`). The store can be accessed via a project
instance. This ensures that we only instantiate one `ContextServerStore`
per project.

Also, this PR adds a bunch of tests to ensure that the
`ContextServerStore` behaves correctly (Previously there were none).

Closes #28714
Closes #29530

Release Notes:

- N/A
This commit is contained in:
Bennet Bo Fenner 2025-05-05 21:36:12 +02:00 committed by GitHub
parent 8199664a5a
commit 9cb5ffac25
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
43 changed files with 1570 additions and 1049 deletions

View file

@ -1,6 +1,7 @@
pub mod buffer_store;
mod color_extractor;
pub mod connection_manager;
pub mod context_server_store;
pub mod debounced_delay;
pub mod debugger;
pub mod git_store;
@ -23,6 +24,7 @@ mod project_tests;
mod direnv;
mod environment;
use buffer_diff::BufferDiff;
use context_server_store::ContextServerStore;
pub use environment::{EnvironmentErrorMessage, ProjectEnvironmentEvent};
use git_store::{Repository, RepositoryId};
pub mod search_history;
@ -182,6 +184,7 @@ pub struct Project {
client_subscriptions: Vec<client::Subscription>,
worktree_store: Entity<WorktreeStore>,
buffer_store: Entity<BufferStore>,
context_server_store: Entity<ContextServerStore>,
image_store: Entity<ImageStore>,
lsp_store: Entity<LspStore>,
_subscriptions: Vec<gpui::Subscription>,
@ -845,6 +848,7 @@ impl Project {
ToolchainStore::init(&client);
DapStore::init(&client, cx);
BreakpointStore::init(&client);
context_server_store::init(cx);
}
pub fn local(
@ -865,6 +869,9 @@ impl Project {
cx.subscribe(&worktree_store, Self::on_worktree_store_event)
.detach();
let context_server_store =
cx.new(|cx| ContextServerStore::new(worktree_store.clone(), cx));
let environment = cx.new(|_| ProjectEnvironment::new(env));
let toolchain_store = cx.new(|cx| {
ToolchainStore::local(
@ -965,6 +972,7 @@ impl Project {
buffer_store,
image_store,
lsp_store,
context_server_store,
join_project_response_message_id: 0,
client_state: ProjectClientState::Local,
git_store,
@ -1025,6 +1033,9 @@ impl Project {
cx.subscribe(&worktree_store, Self::on_worktree_store_event)
.detach();
let context_server_store =
cx.new(|cx| ContextServerStore::new(worktree_store.clone(), cx));
let buffer_store = cx.new(|cx| {
BufferStore::remote(
worktree_store.clone(),
@ -1109,6 +1120,7 @@ impl Project {
buffer_store,
image_store,
lsp_store,
context_server_store,
breakpoint_store,
dap_store,
join_project_response_message_id: 0,
@ -1267,6 +1279,8 @@ impl Project {
let image_store = cx.new(|cx| {
ImageStore::remote(worktree_store.clone(), client.clone().into(), remote_id, cx)
})?;
let context_server_store =
cx.new(|cx| ContextServerStore::new(worktree_store.clone(), cx))?;
let environment = cx.new(|_| ProjectEnvironment::new(None))?;
@ -1360,6 +1374,7 @@ impl Project {
image_store,
worktree_store: worktree_store.clone(),
lsp_store: lsp_store.clone(),
context_server_store,
active_entry: None,
collaborators: Default::default(),
join_project_response_message_id: response.message_id,
@ -1590,6 +1605,10 @@ impl Project {
self.worktree_store.clone()
}
pub fn context_server_store(&self) -> Entity<ContextServerStore> {
self.context_server_store.clone()
}
pub fn buffer_for_id(&self, remote_id: BufferId, cx: &App) -> Option<Entity<Buffer>> {
self.buffer_store.read(cx).get(remote_id)
}