fix(mcp): wrap websocket activity broadcasts in JSON-RPC notifications

Fixes a critical bug where the Antigravity MCP client would crash with 'invalid message version tag' during long-running tool executions. The server was broadcasting raw JSON activity objects ({'type': 'activity', 'data': ...}) over the WebSocket connection without wrapping them in the required JSON-RPC 2.0 Notification envelope, violating the protocol expectation on the proxy stub.
This commit is contained in:
Riz Ashraf committed 2026-09-21 19:56:03 +01:00
1 parent 208c5d448f
commit da1b7cdc9d
6 files changed
+90 -86

No files matched your search

+17 -2
View File
@@ -10,6 +10,7 @@ pub struct MemoryIndex {
index: Index,
reader: IndexReader,
writer: Arc<Mutex<IndexWriter>>,
needs_commit: Arc<std::sync::atomic::AtomicBool>,
// Schema fields
pub id_field: Field,
@@ -47,6 +48,7 @@ impl MemoryIndex {
index,
reader,
writer: Arc::new(Mutex::new(writer)),
needs_commit: Arc::new(std::sync::atomic::AtomicBool::new(false)),
id_field,
title_field,
body_field,
@@ -59,6 +61,7 @@ impl MemoryIndex {
let writer = Arc::clone(&self.writer);
let id_field = self.id_field;
let id_val = e.name.clone();
let needs_commit = Arc::clone(&self.needs_commit);
let doc = doc!(
self.id_field => e.name.as_str(),
@@ -72,6 +75,7 @@ impl MemoryIndex {
let writer = writer.lock().unwrap_or_else(|e| e.into_inner());
writer.delete_term(tantivy::Term::from_field_text(id_field, &id_val));
writer.add_document(doc)?;
needs_commit.store(true, std::sync::atomic::Ordering::SeqCst);
Ok(())
})
}
@@ -80,6 +84,7 @@ impl MemoryIndex {
let writer = Arc::clone(&self.writer);
let id_field = self.id_field;
let id_val = t.id.clone();
let needs_commit = Arc::clone(&self.needs_commit);
let doc = doc!(
self.id_field => t.id.as_str(),
@@ -93,6 +98,7 @@ impl MemoryIndex {
let writer = writer.lock().unwrap_or_else(|e| e.into_inner());
writer.delete_term(tantivy::Term::from_field_text(id_field, &id_val));
writer.add_document(doc)?;
needs_commit.store(true, std::sync::atomic::Ordering::SeqCst);
Ok(())
})
}
@@ -101,19 +107,24 @@ impl MemoryIndex {
let writer = Arc::clone(&self.writer);
let id_field = self.id_field;
let id_val = id.to_string();
let needs_commit = Arc::clone(&self.needs_commit);
tokio::task::spawn_blocking(move || {
let writer = writer.lock().unwrap_or_else(|e| e.into_inner());
writer.delete_term(tantivy::Term::from_field_text(id_field, &id_val));
needs_commit.store(true, std::sync::atomic::Ordering::SeqCst);
Ok(())
})
}
pub async fn commit(&self) -> tantivy::Result<()> {
let writer = Arc::clone(&self.writer);
let needs_commit = Arc::clone(&self.needs_commit);
tokio::task::spawn_blocking(move || {
let mut writer = writer.lock().unwrap_or_else(|e| e.into_inner());
writer.commit()?;
if needs_commit.swap(false, std::sync::atomic::Ordering::SeqCst) {
let mut writer = writer.lock().unwrap_or_else(|e| e.into_inner());
writer.commit()?;
}
Ok(())
})
.await
@@ -182,6 +193,7 @@ impl MemoryIndex {
let writer = Arc::clone(&self.writer);
let id_field = self.id_field;
let id_val = s.name.clone();
let needs_commit = Arc::clone(&self.needs_commit);
let doc = doc!(
self.id_field => s.name.as_str(),
@@ -195,6 +207,7 @@ impl MemoryIndex {
let writer = writer.lock().unwrap_or_else(|e| e.into_inner());
writer.delete_term(tantivy::Term::from_field_text(id_field, &id_val));
writer.add_document(doc)?;
needs_commit.store(true, std::sync::atomic::Ordering::SeqCst);
Ok(())
})
}
@@ -203,6 +216,7 @@ impl MemoryIndex {
let writer = Arc::clone(&self.writer);
let id_field = self.id_field;
let id_val = a.id.clone();
let needs_commit = Arc::clone(&self.needs_commit);
let doc = doc!(
self.id_field => a.id.as_str(),
@@ -216,6 +230,7 @@ impl MemoryIndex {
let writer = writer.lock().unwrap_or_else(|e| e.into_inner());
writer.delete_term(tantivy::Term::from_field_text(id_field, &id_val));
writer.add_document(doc)?;
needs_commit.store(true, std::sync::atomic::Ordering::SeqCst);
Ok(())
})
}