fix(mcp): propagate internal serialization errors instead of silently swallowing them to prevent LLM hallucination

This commit is contained in:
Riz Ashraf committed 2026-09-27 22:19:43 +01:00
1 parent f8925050db
commit 8f32a09399
13 files changed
+235 -63

No files matched your search

+8 -6
View File
@@ -1,9 +1,9 @@
use crate::AppState;
use crate::state::GenericEvent;
use axum::extract::{Query, State};
use axum::response::IntoResponse;
use std::collections::HashMap;
use std::sync::Arc;
use crate::state::GenericEvent;
pub async fn wait_for_event_handler(
State(state): State<Arc<AppState>>,
@@ -18,7 +18,9 @@ pub async fn wait_for_event_handler(
match rx.recv().await {
Ok(event) => {
let topic_matches = topic.as_ref().map_or(true, |t| t == &event.topic);
let session_matches = session_id.as_ref().map_or(true, |s| Some(s) == event.session_id.as_ref());
let session_matches = session_id
.as_ref()
.map_or(true, |s| Some(s) == event.session_id.as_ref());
if topic_matches && session_matches {
return axum::Json(event);
@@ -46,14 +48,14 @@ pub async fn post_event_handler(
#[cfg(test)]
mod tests {
use super::*;
use crate::state::MemoryState;
use crate::router::MemoryHandler;
use tempfile::tempdir;
use crate::state::MemoryState;
use axum::extract::Query;
use axum::extract::State;
use std::collections::HashMap;
use std::sync::atomic::AtomicUsize;
use std::sync::RwLock;
use std::sync::atomic::AtomicUsize;
use tempfile::tempdir;
#[tokio::test]
async fn test_events_wait_and_post() {
@@ -70,7 +72,7 @@ mod tests {
let mut params = HashMap::new();
params.insert("topic".to_string(), "test_topic".to_string());
params.insert("session_id".to_string(), "123".to_string());
let wait_task = tokio::spawn(async move {
let res = wait_for_event_handler(State(app_state_clone), Query(params)).await;
// axum::Json<GenericEvent> is returned, we need to extract it somehow, but just returning is enough for testing
+1 -1
View File
@@ -1,5 +1,5 @@
pub mod events;
pub mod rest;
pub mod setup;
pub mod telemetry;
pub mod ws;
pub mod events;
+80
View File
@@ -148,6 +148,86 @@ pub fn create_router(app_state: Arc<AppState>) -> Router {
}
}),
)
.route(
"/api/tech_debts",
get({
let state_clone = app_state.handler.state.clone();
move || async move {
let json = state_clone.tech_debts.read_with(|items| serde_json::to_string(items).unwrap_or_else(|_| "[]".to_string()));
([(axum::http::header::CONTENT_TYPE, "application/json")], json)
}
}),
)
.route(
"/api/adrs",
get({
let state_clone = app_state.handler.state.clone();
move || async move {
let json = state_clone.adrs.read_with(|items| serde_json::to_string(items).unwrap_or_else(|_| "[]".to_string()));
([(axum::http::header::CONTENT_TYPE, "application/json")], json)
}
}),
)
.route(
"/api/context_workspaces",
get({
let state_clone = app_state.handler.state.clone();
move || async move {
let json = state_clone.context_workspaces.read_with(|items| serde_json::to_string(items).unwrap_or_else(|_| "[]".to_string()));
([(axum::http::header::CONTENT_TYPE, "application/json")], json)
}
}),
)
.route(
"/api/handoff_memos",
get({
let state_clone = app_state.handler.state.clone();
move || async move {
let json = state_clone.handoff_memos.read_with(|items| serde_json::to_string(items).unwrap_or_else(|_| "[]".to_string()));
([(axum::http::header::CONTENT_TYPE, "application/json")], json)
}
}),
)
.route(
"/api/milestones",
get({
let state_clone = app_state.handler.state.clone();
move || async move {
let json = state_clone.milestones.read_with(|items| serde_json::to_string(items).unwrap_or_else(|_| "[]".to_string()));
([(axum::http::header::CONTENT_TYPE, "application/json")], json)
}
}),
)
.route(
"/api/snippets",
get({
let state_clone = app_state.handler.state.clone();
move || async move {
let json = state_clone.snippets.read_with(|items| serde_json::to_string(items).unwrap_or_else(|_| "[]".to_string()));
([(axum::http::header::CONTENT_TYPE, "application/json")], json)
}
}),
)
.route(
"/api/pr_checklists",
get({
let state_clone = app_state.handler.state.clone();
move || async move {
let json = state_clone.pr_checklists.read_with(|items| serde_json::to_string(items).unwrap_or_else(|_| "[]".to_string()));
([(axum::http::header::CONTENT_TYPE, "application/json")], json)
}
}),
)
.route(
"/api/error_fixes",
get({
let state_clone = app_state.handler.state.clone();
move || async move {
let json = state_clone.error_fixes.read_with(|items| serde_json::to_string(items).unwrap_or_else(|_| "[]".to_string()));
([(axum::http::header::CONTENT_TYPE, "application/json")], json)
}
}),
)
.route(
"/api/stats",
get({