feat(mcp): switch to YAML serialization for tool outputs
- Replaced serde_json with serde_yaml in all handler endpoints. - This drastically reduces token consumption for large list/graph responses by removing JSON braces and quotes.
This commit is contained in:
1 parent
410b0c42ca
commit
cb0c55775a
12 files changed
+65
-37
No files matched your search
@@ -40,6 +40,9 @@ pub enum AppError {
|
||||
|
||||
#[error("I/O Error: {0}")]
|
||||
IoError(#[from] std::io::Error),
|
||||
|
||||
#[error("YAML Serialization Error: {0}")]
|
||||
YamlError(#[from] serde_yaml::Error),
|
||||
}
|
||||
|
||||
impl From<AppError> for String {
|
||||
@@ -81,6 +84,10 @@ impl IntoResponse for AppError {
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
format!("I/O Error: {}", e),
|
||||
),
|
||||
AppError::YamlError(e) => (
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
format!("YAML Serialization Error: {}", e),
|
||||
),
|
||||
};
|
||||
|
||||
let body = Json(json!({
|
||||
|
||||
@@ -504,7 +504,7 @@ impl McpTool for FindSymbolReferencesHandler {
|
||||
matches.extend(disk_matches);
|
||||
}
|
||||
|
||||
Ok(serde_json::to_string_pretty(&matches)?)
|
||||
Ok(serde_yaml::to_string(&matches)?)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -560,7 +560,7 @@ impl McpTool for GetCallersHandler {
|
||||
callers.extend(disk_callers);
|
||||
}
|
||||
|
||||
Ok(serde_json::to_string_pretty(&callers)?)
|
||||
Ok(serde_yaml::to_string(&callers)?)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -649,7 +649,7 @@ impl McpTool for AnalyzeImpactHandler {
|
||||
}
|
||||
});
|
||||
|
||||
Ok(serde_json::to_string_pretty(&result)?)
|
||||
Ok(serde_yaml::to_string(&result)?)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ impl McpTool for EnvironmentHandler {
|
||||
.env_fingerprints
|
||||
.read_with(|fps| fps.get(&ns).cloned());
|
||||
if let Some(fp) = data {
|
||||
let data = Ok::<String, crate::error::AppError>(serde_json::to_string(&fp)?)?;
|
||||
let data = Ok::<String, crate::error::AppError>(serde_yaml::to_string(&fp)?)?;
|
||||
Ok(data)
|
||||
} else {
|
||||
Ok("{}".to_string())
|
||||
@@ -118,7 +118,7 @@ impl McpTool for EnvironmentHandler {
|
||||
EnvAction::GetDetails => {
|
||||
let data = state.env.environments.read_with(|envs| {
|
||||
let filtered: Vec<_> = envs.iter().filter(|e| e.namespace == ns).collect();
|
||||
Ok::<String, crate::error::AppError>(serde_json::to_string(&filtered)?)
|
||||
Ok::<String, crate::error::AppError>(serde_yaml::to_string(&filtered)?)
|
||||
})?;
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ impl McpTool for GetActiveWorktreeContextHandler {
|
||||
.await
|
||||
.map_err(|e| crate::error::AppError::Internal(format!("Task panic: {}", e)))??;
|
||||
|
||||
Ok::<String, crate::error::AppError>(serde_json::to_string_pretty(&result)?)
|
||||
Ok::<String, crate::error::AppError>(serde_yaml::to_string(&result)?)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,7 +168,7 @@ impl McpTool for QueryGitDiffsHandler {
|
||||
matches.extend(git_matches);
|
||||
}
|
||||
|
||||
Ok(serde_json::to_string_pretty(&matches)?)
|
||||
Ok(serde_yaml::to_string(&matches)?)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -542,7 +542,7 @@ impl McpTool for ReadGraphHandler {
|
||||
})
|
||||
};
|
||||
|
||||
let mut result_json = serde_json::to_string(&serialized)?;
|
||||
let mut result_json = serde_yaml::to_string(&serialized)?;
|
||||
|
||||
if let Some(max_tok) = max_tokens {
|
||||
let max_chars = max_tok * 4;
|
||||
@@ -579,7 +579,7 @@ impl McpTool for ReadGraphHandler {
|
||||
obj.insert("has_more".to_string(), serde_json::Value::Bool(true));
|
||||
}
|
||||
|
||||
if let Ok(trunc_str) = serde_json::to_string(&truncated_val)
|
||||
if let Ok(trunc_str) = serde_yaml::to_string(&truncated_val)
|
||||
&& (trunc_str.len() <= max_chars || keep_count == 1) {
|
||||
result_json = trunc_str;
|
||||
break;
|
||||
@@ -638,7 +638,7 @@ impl McpTool for SearchNodesHandler {
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok::<String, crate::error::AppError>(serde_json::to_string(&matched_entities)?)
|
||||
Ok::<String, crate::error::AppError>(serde_yaml::to_string(&matched_entities)?)
|
||||
})?;
|
||||
Ok(data)
|
||||
}
|
||||
@@ -679,7 +679,7 @@ impl McpTool for OpenNodesHandler {
|
||||
result.entities.insert(name, e);
|
||||
}
|
||||
}
|
||||
Ok::<String, crate::error::AppError>(serde_json::to_string(&result)?)
|
||||
Ok::<String, crate::error::AppError>(serde_yaml::to_string(&result)?)
|
||||
})?;
|
||||
Ok(data)
|
||||
}
|
||||
@@ -954,7 +954,7 @@ impl McpTool for FindOrphansHandler {
|
||||
.cloned()
|
||||
.collect::<Vec<String>>()
|
||||
});
|
||||
let data = Ok::<String, crate::error::AppError>(serde_json::to_string(&orphans)?)?;
|
||||
let data = Ok::<String, crate::error::AppError>(serde_yaml::to_string(&orphans)?)?;
|
||||
Ok(data)
|
||||
}
|
||||
}
|
||||
@@ -1047,7 +1047,7 @@ impl McpTool for GetSubgraphHandler {
|
||||
"relations": matched_relations,
|
||||
});
|
||||
|
||||
Ok(serde_json::to_string_pretty(&result)?)
|
||||
Ok(serde_yaml::to_string(&result)?)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1146,7 +1146,7 @@ impl McpTool for SweepGraphHealthHandler {
|
||||
"health_score": if orphans.is_empty() && duplicates.is_empty() && stale_entities.is_empty() { "100%" } else { "Needs Maintenance" }
|
||||
});
|
||||
|
||||
Ok(serde_json::to_string_pretty(&report)?)
|
||||
Ok(serde_yaml::to_string(&report)?)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1203,7 +1203,7 @@ impl McpTool for ResolveStaleSymbolsHandler {
|
||||
"status": "success"
|
||||
});
|
||||
|
||||
Ok(serde_json::to_string_pretty(&report)?)
|
||||
Ok(serde_yaml::to_string(&report)?)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+12
-12
@@ -142,7 +142,7 @@ impl McpTool for SearchErrorFixesHandler {
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok::<String, crate::error::AppError>(serde_json::to_string_pretty(&suggestions)?)
|
||||
Ok::<String, crate::error::AppError>(serde_yaml::to_string(&suggestions)?)
|
||||
})?;
|
||||
return Ok(data);
|
||||
}
|
||||
@@ -169,7 +169,7 @@ impl McpTool for SearchErrorFixesHandler {
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
Ok::<String, crate::error::AppError>(serde_json::to_string_pretty(&filtered)?)
|
||||
Ok::<String, crate::error::AppError>(serde_yaml::to_string(&filtered)?)
|
||||
})?;
|
||||
Ok(data)
|
||||
}
|
||||
@@ -358,7 +358,7 @@ impl McpTool for QueryRecentChangesHandler {
|
||||
.take(limit)
|
||||
.cloned()
|
||||
.collect();
|
||||
Ok::<String, crate::error::AppError>(serde_json::to_string(&filtered)?)
|
||||
Ok::<String, crate::error::AppError>(serde_yaml::to_string(&filtered)?)
|
||||
})?;
|
||||
Ok(data)
|
||||
}
|
||||
@@ -575,7 +575,7 @@ impl McpTool for DecisionsHandler {
|
||||
.collect();
|
||||
|
||||
if include_body {
|
||||
Ok::<String, crate::error::AppError>(serde_json::to_string(&filtered)?)
|
||||
Ok::<String, crate::error::AppError>(serde_yaml::to_string(&filtered)?)
|
||||
} else {
|
||||
let compact: Vec<_> = filtered
|
||||
.iter()
|
||||
@@ -592,7 +592,7 @@ impl McpTool for DecisionsHandler {
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
Ok::<String, crate::error::AppError>(serde_json::to_string(&compact)?)
|
||||
Ok::<String, crate::error::AppError>(serde_yaml::to_string(&compact)?)
|
||||
}
|
||||
})?;
|
||||
Ok(data)
|
||||
@@ -738,7 +738,7 @@ impl McpTool for TechDebtHandler {
|
||||
}),
|
||||
})
|
||||
.collect();
|
||||
let mut json_str = serde_json::to_string(&filtered)?;
|
||||
let mut json_str = serde_yaml::to_string(&filtered)?;
|
||||
if let Some(max_t) = req.max_tokens {
|
||||
let char_limit = max_t * 4;
|
||||
if json_str.len() > char_limit {
|
||||
@@ -1305,7 +1305,7 @@ impl McpTool for ManageCheckpointHandler {
|
||||
for s in snaps {
|
||||
list.push(serde_json::json!({"type": "snapshot", "id": s.id, "description": s.description, "namespace": s.namespace}));
|
||||
}
|
||||
Ok(serde_json::to_string_pretty(&list)?)
|
||||
Ok(serde_yaml::to_string(&list)?)
|
||||
}
|
||||
CheckpointAction::Delete => {
|
||||
let name = req.name_or_id.ok_or_else(|| {
|
||||
@@ -1427,7 +1427,7 @@ impl McpTool for QueryLineageHandler {
|
||||
"timeline": timeline
|
||||
});
|
||||
|
||||
Ok(serde_json::to_string_pretty(&res)?)
|
||||
Ok(serde_yaml::to_string(&res)?)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1486,7 +1486,7 @@ impl McpTool for GetNextActionableTasksHandler {
|
||||
"tasks": actionable
|
||||
});
|
||||
|
||||
Ok(serde_json::to_string_pretty(&res)?)
|
||||
Ok(serde_yaml::to_string(&res)?)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1555,7 +1555,7 @@ impl McpTool for HypothesesHandler {
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(serde_json::to_string_pretty(&filtered)?)
|
||||
Ok(serde_yaml::to_string(&filtered)?)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1634,7 +1634,7 @@ impl McpTool for GetPreflightContextHandler {
|
||||
"recent_activities": recent_activities
|
||||
});
|
||||
|
||||
Ok(serde_json::to_string_pretty(&preflight)?)
|
||||
Ok(serde_yaml::to_string(&preflight)?)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1742,7 +1742,7 @@ impl McpTool for AgentSignalsHandler {
|
||||
.collect::<Vec<_>>()
|
||||
});
|
||||
|
||||
Ok(serde_json::to_string_pretty(&filtered)?)
|
||||
Ok(serde_yaml::to_string(&filtered)?)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ impl McpTool for HandoffMemosHandler {
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
Ok::<String, crate::error::AppError>(serde_json::to_string(&filtered)?)
|
||||
Ok::<String, crate::error::AppError>(serde_yaml::to_string(&filtered)?)
|
||||
})?;
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
@@ -297,12 +297,12 @@ impl McpTool for TasksHandler {
|
||||
_ => serde_json::json!({ "id": t.id, "title": t.title, "status": t.status, "description": t.description, "git_branch": t.git_branch }),
|
||||
})
|
||||
.collect();
|
||||
let mut json_str = serde_json::to_string(&filtered)?;
|
||||
let mut json_str = serde_yaml::to_string(&filtered)?;
|
||||
if let Some(max_t) = req.max_tokens {
|
||||
let char_limit = max_t * 4;
|
||||
while json_str.len() > char_limit && !filtered.is_empty() {
|
||||
filtered.pop();
|
||||
json_str = serde_json::to_string(&filtered)?;
|
||||
json_str = serde_yaml::to_string(&filtered)?;
|
||||
}
|
||||
}
|
||||
Ok::<String, crate::error::AppError>(json_str)
|
||||
@@ -514,7 +514,7 @@ impl McpTool for MilestonesHandler {
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
Ok::<String, crate::error::AppError>(serde_json::to_string(&filtered)?)
|
||||
Ok::<String, crate::error::AppError>(serde_yaml::to_string(&filtered)?)
|
||||
})?;
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
@@ -758,7 +758,7 @@ impl McpTool for ClipboardHandler {
|
||||
);
|
||||
|
||||
if let Some(img) = item {
|
||||
Ok(serde_json::to_string_pretty(&img)?)
|
||||
Ok(serde_yaml::to_string(&img)?)
|
||||
} else {
|
||||
Ok(json!({
|
||||
"status": "no_image_in_clipboard",
|
||||
@@ -786,7 +786,7 @@ impl McpTool for ClipboardHandler {
|
||||
|
||||
state.record_activity("clipboard", "Retrieved text from clipboard cache", None);
|
||||
if let Some(txt) = item {
|
||||
Ok(serde_json::to_string_pretty(&txt)?)
|
||||
Ok(serde_yaml::to_string(&txt)?)
|
||||
} else {
|
||||
Ok(json!({
|
||||
"text": "",
|
||||
@@ -818,7 +818,7 @@ impl McpTool for ClipboardHandler {
|
||||
};
|
||||
|
||||
state.record_activity("clipboard", "Viewed clipboard history ring buffer", None);
|
||||
Ok(serde_json::to_string_pretty(&history)?)
|
||||
Ok(serde_yaml::to_string(&history)?)
|
||||
}
|
||||
ClipboardAction::Clear => {
|
||||
tokio::task::spawn_blocking(|| {
|
||||
@@ -905,7 +905,7 @@ impl McpTool for ClipboardHandler {
|
||||
.map_err(|e| crate::error::AppError::Internal(format!("Task panic: {}", e)))??;
|
||||
|
||||
state.record_activity("clipboard", "Read contents from OS clipboard", None);
|
||||
Ok::<String, crate::error::AppError>(serde_json::to_string_pretty(&Value::Object(
|
||||
Ok::<String, crate::error::AppError>(serde_yaml::to_string(&Value::Object(
|
||||
out,
|
||||
))?)
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ impl McpTool for SnippetsHandler {
|
||||
.total_cmp(&a["score"].as_f64().unwrap_or(0.0))
|
||||
});
|
||||
scored.truncate(10);
|
||||
Ok(serde_json::to_string_pretty(&scored)?)
|
||||
Ok(serde_yaml::to_string(&scored)?)
|
||||
} else {
|
||||
let data = state.code.snippets.read_with(|snippets| {
|
||||
let results: Vec<_> = snippets
|
||||
@@ -153,7 +153,7 @@ impl McpTool for SnippetsHandler {
|
||||
})
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
serde_json::to_string_pretty(&results)
|
||||
serde_yaml::to_string(&results)
|
||||
})?;
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user