refactor: deduplicate arg parsing in handlers and remove redundant python scripts
Created a parse_tool! macro that eliminated ~450 lines of repetitive error-handling boilerplate across 54 MCP tool definitions in server/src/handlers.rs. Purged 30+ stale, redundant python patching scripts and legacy mcp_client.py test runners that were polluting the workspace root and server/src directories.
This commit is contained in:
1 parent
ee4157d07b
commit
0e29b12ac8
33 files changed
+71
-1981
No files matched your search
@@ -1,39 +0,0 @@
|
||||
import re
|
||||
|
||||
endpoints = """
|
||||
.route("/api/graph", get({
|
||||
let state_clone = app_state.handler.state.clone();
|
||||
move || async move {
|
||||
let graph = state_clone.get_full_graph();
|
||||
axum::Json(graph)
|
||||
}
|
||||
}))
|
||||
.route("/api/tasks", get({
|
||||
let state_clone = app_state.handler.state.clone();
|
||||
move || async move {
|
||||
let tasks = state_clone.tasks.read();
|
||||
axum::Json(tasks.clone())
|
||||
}
|
||||
}))
|
||||
.route("/api/search", get({
|
||||
let state_clone = app_state.handler.state.clone();
|
||||
move |axum::extract::Query(params): axum::extract::Query<std::collections::HashMap<String, String>>| async move {
|
||||
if let Some(q) = params.get("q") {
|
||||
if let Ok(idx) = state_clone.search_index.read() {
|
||||
let results = idx.search(q, 50);
|
||||
return axum::Json(serde_json::json!({ "results": results }));
|
||||
}
|
||||
}
|
||||
axum::Json(serde_json::json!({ "results": [] }))
|
||||
}
|
||||
}))
|
||||
"""
|
||||
|
||||
filepath = "C:\\Users\\reazul.ashraf\\workspace\\rust\\mcp-memory\\server\\src\\main.rs"
|
||||
with open(filepath, "r", encoding="utf-8") as f:
|
||||
content = f.read()
|
||||
|
||||
content = content.replace('.route("/api/stats",', endpoints + ' .route("/api/stats",')
|
||||
|
||||
with open(filepath, "w", encoding="utf-8") as f:
|
||||
f.write(content)
|
||||
@@ -1,44 +0,0 @@
|
||||
import re
|
||||
|
||||
def fix_handlers(filepath):
|
||||
with open(filepath, "r") as f:
|
||||
content = f.read()
|
||||
|
||||
# Find the positions of self.state.write_to_local_delta( and self.state.apply_sync_write(
|
||||
patterns = ["self.state.write_to_local_delta(|", "self.state.apply_sync_write(|"]
|
||||
|
||||
# Actually, we can just find 'write_to_local_delta(|' and 'apply_sync_write(|'
|
||||
|
||||
for method in ["write_to_local_delta", "apply_sync_write"]:
|
||||
start_idx = 0
|
||||
while True:
|
||||
idx = content.find(f"self.state.{method}(|", start_idx)
|
||||
if idx == -1:
|
||||
break
|
||||
|
||||
# Find the closing bracket that matches the first `{` after `|`
|
||||
brace_idx = content.find("{", idx)
|
||||
|
||||
# count braces
|
||||
brace_count = 1
|
||||
curr_idx = brace_idx + 1
|
||||
while brace_count > 0 and curr_idx < len(content):
|
||||
if content[curr_idx] == '{':
|
||||
brace_count += 1
|
||||
elif content[curr_idx] == '}':
|
||||
brace_count -= 1
|
||||
curr_idx += 1
|
||||
|
||||
# curr_idx is now right after the matching '}'
|
||||
# the original code was '});'
|
||||
if content[curr_idx:curr_idx+2] == ");":
|
||||
# we want to insert .await
|
||||
content = content[:curr_idx+1] + ".await" + content[curr_idx+1:]
|
||||
start_idx = curr_idx + 8 # move past `.await);`
|
||||
else:
|
||||
start_idx = curr_idx
|
||||
|
||||
with open(filepath, "w") as f:
|
||||
f.write(content)
|
||||
|
||||
fix_handlers("C:\\Users\\reazul.ashraf\\workspace\\rust\\mcp-memory\\server\\src\\handlers.rs")
|
||||
@@ -1,78 +0,0 @@
|
||||
import re
|
||||
|
||||
descriptions = {
|
||||
"create_entities": "Create new entities in the knowledge graph.",
|
||||
"create_relations": "Create new relations between entities in the knowledge graph.",
|
||||
"add_observations": "Add new observations to existing entities in the knowledge graph.",
|
||||
"delete_entities": "Delete entities from the knowledge graph.",
|
||||
"delete_observations": "Delete observations from existing entities.",
|
||||
"delete_relations": "Delete relations between entities.",
|
||||
"read_graph": "Read the entire knowledge graph.",
|
||||
"search_nodes": "Search for entities in the knowledge graph by name or type.",
|
||||
"open_nodes": "Open and retrieve full details of specific nodes in the knowledge graph.",
|
||||
"log_code_change": "Log a significant code change or refactor in the memory system.",
|
||||
"query_recent_changes": "Query recently logged code changes.",
|
||||
"visualize_graph": "Generate a visual representation of the knowledge graph.",
|
||||
"add_sticky_note": "Add a sticky note for unstructured thoughts or reminders.",
|
||||
"read_sticky_notes": "Read all active sticky notes.",
|
||||
"condense_entity": "Condense or summarize an entity's observations to reduce size.",
|
||||
"add_task": "Add a new task to the task tracker.",
|
||||
"update_task_status": "Update the status of an existing task.",
|
||||
"list_active_tasks": "List all currently active tasks.",
|
||||
"store_snippet": "Store a reusable code snippet.",
|
||||
"search_snippets": "Search through stored code snippets.",
|
||||
"delete_snippet": "Delete a stored code snippet.",
|
||||
"log_decision": "Log an architectural decision record (ADR).",
|
||||
"query_decisions": "Query architectural decision records.",
|
||||
"merge_entities": "Merge two entities in the knowledge graph into one.",
|
||||
"find_orphans": "Find orphaned entities (entities without any relations) in the graph.",
|
||||
"learn_preference": "Record a user preference or behavior to adapt future interactions.",
|
||||
"read_preferences": "Read all learned user preferences.",
|
||||
"log_error_fix": "Log a complex error and its fix for future reference.",
|
||||
"search_error_fixes": "Search through previously logged error fixes.",
|
||||
"pin_file": "Pin a file to keep it explicitly in the context workspace.",
|
||||
"unpin_file": "Unpin a file from the context workspace.",
|
||||
"list_pinned_files": "List all currently pinned files.",
|
||||
"add_session_summary": "Add a summary of the current session.",
|
||||
"get_project_timeline": "Get a timeline of major project events.",
|
||||
"leave_handoff_memo": "Leave a memo for the next session or agent.",
|
||||
"read_handoff_memos": "Read pending handoff memos.",
|
||||
"clear_handoff_memos": "Clear handoff memos after reading.",
|
||||
"update_env_fingerprint": "Update the environment fingerprint (e.g., OS, tool versions).",
|
||||
"read_env_fingerprint": "Read the current environment fingerprint.",
|
||||
"log_env_requirement": "Log a required tool or package for the environment.",
|
||||
"add_milestone": "Add a new project milestone.",
|
||||
"update_milestone": "Update the status of a project milestone.",
|
||||
"list_milestones": "List all project milestones.",
|
||||
"generate_standup_report": "Generate a standup report based on recent activity.",
|
||||
"register_environment": "Register details about a specific deployment environment.",
|
||||
"get_environment_details": "Get details about a registered environment.",
|
||||
"add_pr_checklist_item": "Add an item to the PR checklist.",
|
||||
"get_pr_checklist": "Get the current PR checklist.",
|
||||
"clear_pr_checklist": "Clear the PR checklist.",
|
||||
"log_tech_debt": "Log identified technical debt.",
|
||||
"resolve_tech_debt": "Mark a logged technical debt as resolved.",
|
||||
"list_tech_debt": "List all unresolved technical debt.",
|
||||
"save_context_workspace": "Save the current set of pinned files and context.",
|
||||
"load_context_workspace": "Load a previously saved context workspace.",
|
||||
"list_context_workspaces": "List all saved context workspaces.",
|
||||
"omni_search": "Search across all memory sources (graph, tasks, snippets, ADRs, etc.) at once.",
|
||||
"get_project_health": "Get a synthesized health report of the project based on memory data."
|
||||
}
|
||||
|
||||
def fix_handlers(filepath):
|
||||
with open(filepath, "r") as f:
|
||||
content = f.read()
|
||||
|
||||
for tool_name, description in descriptions.items():
|
||||
# Match crate::mcp::tool_def::<...>("tool_name", "")
|
||||
# Note: sometimes it's on multiple lines for GenerateStandupReportTool etc.
|
||||
# But most are single line.
|
||||
pattern = r'(crate::mcp::tool_def::<[^>]+>\(\s*"' + tool_name + r'"\s*,\s*)""(\s*\))'
|
||||
replacement = r'\1"' + description + r'"\2'
|
||||
content = re.sub(pattern, replacement, content)
|
||||
|
||||
with open(filepath, "w") as f:
|
||||
f.write(content)
|
||||
|
||||
fix_handlers("C:\\Users\\reazul.ashraf\\workspace\\rust\\mcp-memory\\server\\src\\handlers.rs")
|
||||
@@ -1,50 +0,0 @@
|
||||
import re
|
||||
|
||||
endpoints = """
|
||||
.route("/api/graph", get({
|
||||
let state_clone = app_state.handler.state.clone();
|
||||
move || async move {
|
||||
let graph = state_clone.get_full_graph();
|
||||
axum::Json(graph)
|
||||
}
|
||||
}))
|
||||
.route("/api/tasks", get({
|
||||
let state_clone = app_state.handler.state.clone();
|
||||
move || async move {
|
||||
let tasks = state_clone.tasks.read();
|
||||
axum::Json(tasks.clone())
|
||||
}
|
||||
}))
|
||||
.route("/api/search", get({
|
||||
let state_clone = app_state.handler.state.clone();
|
||||
move |axum::extract::Query(params): axum::extract::Query<std::collections::HashMap<String, String>>| async move {
|
||||
if let Some(q) = params.get("q") {
|
||||
if let Ok(idx) = state_clone.search_index.read() {
|
||||
if let Ok(results) = idx.search(q, None) {
|
||||
let mut formatted_results = Vec::new();
|
||||
for (type_name, content) in results {
|
||||
formatted_results.push(serde_json::json!({
|
||||
"type_name": type_name,
|
||||
"content": content,
|
||||
"score": 1.0
|
||||
}));
|
||||
}
|
||||
return axum::Json(serde_json::json!({ "results": formatted_results }));
|
||||
}
|
||||
}
|
||||
}
|
||||
axum::Json(serde_json::json!({ "results": [] }))
|
||||
}
|
||||
}))
|
||||
"""
|
||||
|
||||
filepath = "C:\\Users\\reazul.ashraf\\workspace\\rust\\mcp-memory\\server\\src\\main.rs"
|
||||
with open(filepath, "r", encoding="utf-8") as f:
|
||||
content = f.read()
|
||||
|
||||
# Replace the broken routes with the fixed ones
|
||||
pattern = r'\.route\("/api/graph".*?\.route\("/api/stats"'
|
||||
content = re.sub(pattern, endpoints.strip() + '\n .route("/api/stats"', content, flags=re.DOTALL)
|
||||
|
||||
with open(filepath, "w", encoding="utf-8") as f:
|
||||
f.write(content)
|
||||
+70
-481
@@ -2,6 +2,22 @@ use crate::models::*;
|
||||
use crate::state::MemoryState;
|
||||
use crate::tools::*;
|
||||
|
||||
macro_rules! parse_tool {
|
||||
($args:expr, $id:expr, $type:ty) => {
|
||||
match parse_args::<$type>($args) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
$id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": format!("Invalid args: {}", e)}] }),
|
||||
));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
use serde::de::DeserializeOwned;
|
||||
use std::collections::HashSet;
|
||||
use std::sync::Arc;
|
||||
@@ -124,10 +140,7 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
|
||||
let result: Result<String, String> = match name {
|
||||
"query_graph_path" => {
|
||||
let req: crate::tools::QueryGraphPathTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => return Some(crate::mcp::success(id.clone(), serde_json::json!({"isError": true, "content": [{"type": "text", "text": format!("Invalid args: {}", e)}] })))
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, crate::tools::QueryGraphPathTool);
|
||||
let graph = self.state.get_full_graph();
|
||||
let max_depth = req.max_depth.unwrap_or(5);
|
||||
let mut queue = std::collections::VecDeque::new();
|
||||
@@ -185,15 +198,7 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
}
|
||||
}
|
||||
"create_entities" => {
|
||||
let req: CreateEntitiesTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, CreateEntitiesTool);
|
||||
self.state.write_to_local_delta(|g| {
|
||||
for entity in req.entities {
|
||||
if !entity.name.is_empty() {
|
||||
@@ -207,15 +212,7 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
Ok(vec!["Entities created".to_string()][0].clone())
|
||||
}
|
||||
"create_relations" => {
|
||||
let req: CreateRelationsTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, CreateRelationsTool);
|
||||
self.state.write_to_local_delta(|g| {
|
||||
for relation in req.relations {
|
||||
if !relation.from.is_empty() && !relation.to.is_empty() {
|
||||
@@ -226,15 +223,7 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
Ok(vec!["Relations created".to_string()][0].clone())
|
||||
}
|
||||
"add_observations" => {
|
||||
let req: AddObservationsTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, AddObservationsTool);
|
||||
let full = self.state.get_full_graph();
|
||||
self.state.write_to_local_delta(|g| {
|
||||
for o in req.observations {
|
||||
@@ -258,15 +247,7 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
Ok(vec!["Observations added".to_string()][0].clone())
|
||||
}
|
||||
"delete_entities" => {
|
||||
let req: DeleteEntitiesTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, DeleteEntitiesTool);
|
||||
let to_delete: HashSet<_> = req.entity_names.into_iter().collect();
|
||||
self.state.apply_sync_write(|master| {
|
||||
for name in &to_delete {
|
||||
@@ -279,15 +260,7 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
Ok(vec!["Entities deleted".to_string()][0].clone())
|
||||
}
|
||||
"delete_observations" => {
|
||||
let req: DeleteObservationsTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, DeleteObservationsTool);
|
||||
self.state.apply_sync_write(|master| {
|
||||
for d in req.deletions {
|
||||
if let Some(e) = master.entities.get_mut(&d.entity_name)
|
||||
@@ -300,15 +273,7 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
Ok(vec!["Observations deleted".to_string()][0].clone())
|
||||
}
|
||||
"delete_relations" => {
|
||||
let req: DeleteRelationsTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, DeleteRelationsTool);
|
||||
self.state.apply_sync_write(|master| {
|
||||
let mut to_rem = HashSet::new();
|
||||
for r in req.relations {
|
||||
@@ -327,15 +292,7 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
Ok(vec!["Relations deleted".to_string()][0].clone())
|
||||
}
|
||||
"read_graph" => {
|
||||
let req: ReadGraphTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, ReadGraphTool);
|
||||
let mut full = self.state.get_full_graph();
|
||||
if let Some(ns) = req.namespace {
|
||||
full.entities.retain(|_, e| e.namespace == ns);
|
||||
@@ -345,15 +302,7 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
Ok(vec![data.to_string()][0].clone())
|
||||
}
|
||||
"search_nodes" => {
|
||||
let req: SearchNodesTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, SearchNodesTool);
|
||||
let matches = if let Ok(idx) = self.state.search_index.read() {
|
||||
idx.search(&req.query, req.namespace.as_deref())
|
||||
.unwrap_or_default()
|
||||
@@ -373,15 +322,7 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
Ok(vec![data.to_string()][0].clone())
|
||||
}
|
||||
"open_nodes" => {
|
||||
let req: OpenNodesTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, OpenNodesTool);
|
||||
let targets: HashSet<_> = req.names.into_iter().collect();
|
||||
let full = self.state.get_full_graph();
|
||||
let mut result = KnowledgeGraph::default();
|
||||
@@ -404,15 +345,7 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
Ok(vec![data.to_string()][0].clone())
|
||||
}
|
||||
"log_code_change" => {
|
||||
let req: LogCodeChangeTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, LogCodeChangeTool);
|
||||
self.state.ledger.modify(|ledger| {
|
||||
ledger.push(CodeChange {
|
||||
timestamp: SystemTime::now()
|
||||
@@ -433,15 +366,7 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
Ok(vec![data.to_string()][0].clone())
|
||||
}
|
||||
"visualize_graph" => {
|
||||
let req: VisualizeGraphTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, VisualizeGraphTool);
|
||||
let query = req.query.unwrap_or_default().to_lowercase();
|
||||
let full = self.state.get_full_graph();
|
||||
let mut included = HashSet::new();
|
||||
@@ -511,15 +436,7 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
Ok(vec![output.to_string()][0].clone())
|
||||
}
|
||||
"add_sticky_note" => {
|
||||
let req: AddStickyNoteTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, AddStickyNoteTool);
|
||||
self.state.sticky.modify(|notes| {
|
||||
notes.push(StickyNote {
|
||||
timestamp: SystemTime::now()
|
||||
@@ -537,15 +454,7 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
Ok(vec![data.to_string()][0].clone())
|
||||
}
|
||||
"condense_entity" => {
|
||||
let req: CondenseEntityTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, CondenseEntityTool);
|
||||
self.state.apply_sync_write(|master| {
|
||||
if let Some(e) = master.entities.get_mut(&req.entity_name) {
|
||||
e.observations = req.summarized_observations;
|
||||
@@ -554,15 +463,7 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
Ok(vec!["Entity condensed".to_string()][0].clone())
|
||||
}
|
||||
"add_task" => {
|
||||
let req: AddTaskTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, AddTaskTool);
|
||||
let now = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.unwrap()
|
||||
@@ -586,15 +487,7 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
Ok(vec![format!("Task added with ID: {}", id).to_string()][0].clone())
|
||||
}
|
||||
"update_task_status" => {
|
||||
let req: UpdateTaskStatusTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, UpdateTaskStatusTool);
|
||||
let mut found = false;
|
||||
self.state.tasks.modify(|tasks| {
|
||||
for t in tasks.iter_mut() {
|
||||
@@ -616,15 +509,7 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
}
|
||||
}
|
||||
"list_active_tasks" => {
|
||||
let req: ListActiveTasksTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, ListActiveTasksTool);
|
||||
let mut tasks = self.state.tasks.read();
|
||||
tasks.retain(|t| t.status != "done");
|
||||
if let Some(branch) = req.git_branch {
|
||||
@@ -637,15 +522,7 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
Ok(vec![data.to_string()][0].clone())
|
||||
}
|
||||
"store_snippet" => {
|
||||
let req: StoreSnippetTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, StoreSnippetTool);
|
||||
self.state.snippets.modify(|snippets| {
|
||||
snippets.retain(|s| s.name != req.name);
|
||||
snippets.push(Snippet {
|
||||
@@ -662,15 +539,7 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
Ok(vec![format!("Snippet '{}' stored.", req.name).to_string()][0].clone())
|
||||
}
|
||||
"search_snippets" => {
|
||||
let req: SearchSnippetsTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, SearchSnippetsTool);
|
||||
let query = req.query.to_lowercase();
|
||||
let snippets = self.state.snippets.read();
|
||||
let mut results = Vec::new();
|
||||
@@ -686,15 +555,7 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
Ok(vec![data.to_string()][0].clone())
|
||||
}
|
||||
"delete_snippet" => {
|
||||
let req: DeleteSnippetTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, DeleteSnippetTool);
|
||||
let mut deleted = false;
|
||||
self.state.snippets.modify(|snippets| {
|
||||
let orig = snippets.len();
|
||||
@@ -708,15 +569,7 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
}
|
||||
}
|
||||
"log_decision" => {
|
||||
let req: LogDecisionTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, LogDecisionTool);
|
||||
let mut id = String::new();
|
||||
self.state.adrs.modify(|adrs| {
|
||||
id = format!("ADR-{:04}", adrs.len() + 1);
|
||||
@@ -735,15 +588,7 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
Ok(vec![format!("Decision logged as {}", id).to_string()][0].clone())
|
||||
}
|
||||
"query_decisions" => {
|
||||
let req: QueryDecisionsTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, QueryDecisionsTool);
|
||||
let mut adrs = self.state.adrs.read();
|
||||
if let Some(q) = req.query {
|
||||
let q = q.to_lowercase();
|
||||
@@ -757,15 +602,7 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
Ok(vec![data.to_string()][0].clone())
|
||||
}
|
||||
"merge_entities" => {
|
||||
let req: MergeEntitiesTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, MergeEntitiesTool);
|
||||
self.state.apply_sync_write(|master| {
|
||||
if let Some(src) = master.entities.remove(&req.source_entity) {
|
||||
if let Some(tgt) = master.entities.get_mut(&req.target_entity) {
|
||||
@@ -807,15 +644,7 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
Ok(vec![data.to_string()][0].clone())
|
||||
}
|
||||
"learn_preference" => {
|
||||
let req: LearnPreferenceTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, LearnPreferenceTool);
|
||||
self.state.prefs.modify(|prefs| {
|
||||
prefs.insert(
|
||||
req.key.clone(),
|
||||
@@ -837,15 +666,7 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
Ok(vec![data.to_string()][0].clone())
|
||||
}
|
||||
"log_error_fix" => {
|
||||
let req: LogErrorFixTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, LogErrorFixTool);
|
||||
self.state.error_fixes.modify(|fixes| {
|
||||
fixes.push(crate::models::ErrorFix {
|
||||
signature: req.signature,
|
||||
@@ -861,15 +682,7 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
Ok(vec!["Error fix logged".to_string()][0].clone())
|
||||
}
|
||||
"search_error_fixes" => {
|
||||
let req: SearchErrorFixesTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, SearchErrorFixesTool);
|
||||
let q = req.query.to_lowercase();
|
||||
let mut fixes = self.state.error_fixes.read();
|
||||
fixes.retain(|f| {
|
||||
@@ -880,15 +693,7 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
Ok(vec![data.to_string()][0].clone())
|
||||
}
|
||||
"pin_file" => {
|
||||
let req: PinFileTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, PinFileTool);
|
||||
self.state.pinned_files.modify(|pinned| {
|
||||
pinned.retain(|p| {
|
||||
!(p.namespace == req.namespace && p.file_path == req.file_path)
|
||||
@@ -906,15 +711,7 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
Ok(vec!["File pinned".to_string()][0].clone())
|
||||
}
|
||||
"unpin_file" => {
|
||||
let req: UnpinFileTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, UnpinFileTool);
|
||||
self.state.pinned_files.modify(|pinned| {
|
||||
pinned.retain(|p| {
|
||||
!(p.namespace == req.namespace && p.file_path == req.file_path)
|
||||
@@ -923,15 +720,7 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
Ok(vec!["File unpinned".to_string()][0].clone())
|
||||
}
|
||||
"list_pinned_files" => {
|
||||
let req: ListPinnedFilesTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, ListPinnedFilesTool);
|
||||
let mut pinned = self.state.pinned_files.read();
|
||||
if let Some(ns) = req.namespace {
|
||||
pinned.retain(|p| p.namespace == ns);
|
||||
@@ -946,15 +735,7 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
Ok(vec![data.to_string()][0].clone())
|
||||
}
|
||||
"add_session_summary" => {
|
||||
let req: AddSessionSummaryTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, AddSessionSummaryTool);
|
||||
self.state.session_summaries.modify(|summaries| {
|
||||
summaries.push(crate::models::SessionSummary {
|
||||
summary: req.summary,
|
||||
@@ -968,15 +749,7 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
Ok(vec!["Session summary added".to_string()][0].clone())
|
||||
}
|
||||
"get_project_timeline" => {
|
||||
let req: GetProjectTimelineTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, GetProjectTimelineTool);
|
||||
let mut summaries = self.state.session_summaries.read();
|
||||
if let Some(ns) = req.namespace {
|
||||
summaries.retain(|s| s.namespace == ns);
|
||||
@@ -986,15 +759,7 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
Ok(vec![data.to_string()][0].clone())
|
||||
}
|
||||
"leave_handoff_memo" => {
|
||||
let req: LeaveHandoffMemoTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, LeaveHandoffMemoTool);
|
||||
self.state.handoff_memos.modify(|memos| {
|
||||
memos.push(crate::models::HandoffMemo {
|
||||
id: uuid::Uuid::new_v4().to_string(),
|
||||
@@ -1010,15 +775,7 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
Ok(vec!["Handoff memo left".to_string()][0].clone())
|
||||
}
|
||||
"read_handoff_memos" => {
|
||||
let req: ReadHandoffMemosTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, ReadHandoffMemosTool);
|
||||
let mut memos = self.state.handoff_memos.read();
|
||||
if let Some(ns) = req.namespace {
|
||||
memos.retain(|m| m.namespace == ns);
|
||||
@@ -1027,15 +784,7 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
Ok(vec![data.to_string()][0].clone())
|
||||
}
|
||||
"clear_handoff_memos" => {
|
||||
let req: ClearHandoffMemosTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, ClearHandoffMemosTool);
|
||||
let ids: HashSet<_> = req.ids.into_iter().collect();
|
||||
self.state
|
||||
.handoff_memos
|
||||
@@ -1043,15 +792,7 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
Ok(vec!["Handoff memos cleared".to_string()][0].clone())
|
||||
}
|
||||
"update_env_fingerprint" => {
|
||||
let req: UpdateEnvFingerprintTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, UpdateEnvFingerprintTool);
|
||||
self.state.env_fingerprints.modify(|fps| {
|
||||
fps.insert(
|
||||
req.namespace.clone(),
|
||||
@@ -1071,15 +812,7 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
Ok(vec!["Env fingerprint updated".to_string()][0].clone())
|
||||
}
|
||||
"read_env_fingerprint" => {
|
||||
let req: ReadEnvFingerprintTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, ReadEnvFingerprintTool);
|
||||
let fps = self.state.env_fingerprints.read();
|
||||
if let Some(fp) = fps.get(&req.namespace) {
|
||||
let data = serde_json::to_string(fp).unwrap_or_default();
|
||||
@@ -1089,15 +822,7 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
}
|
||||
}
|
||||
"log_env_requirement" => {
|
||||
let req: LogEnvRequirementTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, LogEnvRequirementTool);
|
||||
self.state.env_requirements.modify(|reqs| {
|
||||
reqs.retain(|r| !(r.namespace == req.namespace && r.key == req.key));
|
||||
reqs.push(crate::models::EnvRequirement {
|
||||
@@ -1110,15 +835,7 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
Ok(vec!["Env requirement logged".to_string()][0].clone())
|
||||
}
|
||||
"add_milestone" => {
|
||||
let req: AddMilestoneTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, AddMilestoneTool);
|
||||
self.state.milestones.modify(|ms| {
|
||||
ms.push(crate::models::Milestone {
|
||||
id: uuid::Uuid::new_v4().to_string(),
|
||||
@@ -1131,15 +848,7 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
Ok(vec!["Milestone added".to_string()][0].clone())
|
||||
}
|
||||
"update_milestone" => {
|
||||
let req: UpdateMilestoneTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, UpdateMilestoneTool);
|
||||
let mut found = false;
|
||||
self.state.milestones.modify(|ms| {
|
||||
for m in ms.iter_mut() {
|
||||
@@ -1157,15 +866,7 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
}
|
||||
}
|
||||
"list_milestones" => {
|
||||
let req: ListMilestonesTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, ListMilestonesTool);
|
||||
let mut ms = self.state.milestones.read();
|
||||
if let Some(ns) = req.namespace {
|
||||
ms.retain(|m| m.namespace == ns);
|
||||
@@ -1174,15 +875,7 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
Ok(vec![data.to_string()][0].clone())
|
||||
}
|
||||
"generate_standup_report" => {
|
||||
let req: GenerateStandupReportTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, GenerateStandupReportTool);
|
||||
let cutoff = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.unwrap()
|
||||
@@ -1213,15 +906,7 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
Ok(vec![report.to_string().to_string()][0].clone())
|
||||
}
|
||||
"register_environment" => {
|
||||
let req: RegisterEnvironmentTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, RegisterEnvironmentTool);
|
||||
self.state.environments.modify(|envs| {
|
||||
envs.retain(|e| !(e.namespace == req.namespace && e.name == req.name));
|
||||
envs.push(crate::models::EnvironmentDetail {
|
||||
@@ -1239,30 +924,14 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
Ok(vec!["Environment registered".to_string()][0].clone())
|
||||
}
|
||||
"get_environment_details" => {
|
||||
let req: GetEnvironmentDetailsTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, GetEnvironmentDetailsTool);
|
||||
let mut envs = self.state.environments.read();
|
||||
envs.retain(|e| e.namespace == req.namespace);
|
||||
let data = serde_json::to_string(&envs).unwrap_or_default();
|
||||
Ok(vec![data.to_string()][0].clone())
|
||||
}
|
||||
"add_pr_checklist_item" => {
|
||||
let req: AddPrChecklistItemTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, AddPrChecklistItemTool);
|
||||
self.state.pr_checklists.modify(|items| {
|
||||
items.push(crate::models::PrChecklistItem {
|
||||
namespace: req.namespace,
|
||||
@@ -1273,45 +942,21 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
Ok(vec!["PR checklist item added".to_string()][0].clone())
|
||||
}
|
||||
"get_pr_checklist" => {
|
||||
let req: GetPrChecklistTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, GetPrChecklistTool);
|
||||
let mut items = self.state.pr_checklists.read();
|
||||
items.retain(|i| i.namespace == req.namespace);
|
||||
let data = serde_json::to_string(&items).unwrap_or_default();
|
||||
Ok(vec![data.to_string()][0].clone())
|
||||
}
|
||||
"clear_pr_checklist" => {
|
||||
let req: ClearPrChecklistTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, ClearPrChecklistTool);
|
||||
self.state
|
||||
.pr_checklists
|
||||
.modify(|items| items.retain(|i| i.namespace != req.namespace));
|
||||
Ok(vec!["PR checklist cleared".to_string()][0].clone())
|
||||
}
|
||||
"log_tech_debt" => {
|
||||
let req: LogTechDebtTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, LogTechDebtTool);
|
||||
self.state.tech_debts.modify(|debts| {
|
||||
debts.push(crate::models::TechDebt {
|
||||
id: uuid::Uuid::new_v4().to_string(),
|
||||
@@ -1330,15 +975,7 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
Ok(vec!["Tech debt logged".to_string()][0].clone())
|
||||
}
|
||||
"resolve_tech_debt" => {
|
||||
let req: ResolveTechDebtTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, ResolveTechDebtTool);
|
||||
let mut found = false;
|
||||
self.state.tech_debts.modify(|debts| {
|
||||
for d in debts.iter_mut() {
|
||||
@@ -1356,15 +993,7 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
}
|
||||
}
|
||||
"list_tech_debt" => {
|
||||
let req: ListTechDebtTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, ListTechDebtTool);
|
||||
let mut debts = self.state.tech_debts.read();
|
||||
debts.retain(|d| {
|
||||
d.namespace == req.namespace && (req.include_resolved || !d.is_resolved)
|
||||
@@ -1373,15 +1002,7 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
Ok(vec![data.to_string()][0].clone())
|
||||
}
|
||||
"save_context_workspace" => {
|
||||
let req: SaveContextWorkspaceTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, SaveContextWorkspaceTool);
|
||||
self.state.context_workspaces.modify(|ws| {
|
||||
ws.retain(|w| !(w.namespace == req.namespace && w.name == req.name));
|
||||
ws.push(crate::models::ContextWorkspace {
|
||||
@@ -1398,45 +1019,21 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
Ok(vec!["Context workspace saved".to_string()][0].clone())
|
||||
}
|
||||
"load_context_workspace" => {
|
||||
let req: LoadContextWorkspaceTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, LoadContextWorkspaceTool);
|
||||
let mut ws = self.state.context_workspaces.read();
|
||||
ws.retain(|w| w.namespace == req.namespace && w.name == req.name);
|
||||
let data = serde_json::to_string(&ws.first()).unwrap_or_default();
|
||||
Ok(vec![data.to_string()][0].clone())
|
||||
}
|
||||
"list_context_workspaces" => {
|
||||
let req: ListContextWorkspacesTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, ListContextWorkspacesTool);
|
||||
let mut ws = self.state.context_workspaces.read();
|
||||
ws.retain(|w| w.namespace == req.namespace);
|
||||
let data = serde_json::to_string(&ws).unwrap_or_default();
|
||||
Ok(vec![data.to_string()][0].clone())
|
||||
}
|
||||
"omni_search" => {
|
||||
let req: OmniSearchTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, OmniSearchTool);
|
||||
let matches = if let Ok(idx) = self.state.search_index.read() {
|
||||
idx.search(&req.query, req.namespace.as_deref())
|
||||
.unwrap_or_default()
|
||||
@@ -1522,15 +1119,7 @@ crate::mcp::tool_def::<CreateEntitiesTool>("create_entities", "Create new entiti
|
||||
Ok(vec![report.to_string().to_string()][0].clone())
|
||||
}
|
||||
"get_project_health" => {
|
||||
let req: GetProjectHealthTool = match parse_args(args.clone()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Some(crate::mcp::success(
|
||||
id.clone(),
|
||||
serde_json::json!({"isError": true, "content": [{"type": "text", "text": e}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
let req = parse_tool!(args.clone(), id, GetProjectHealthTool);
|
||||
let active_tasks = self
|
||||
.state
|
||||
.tasks
|
||||
|
||||
Reference in new issue
Block a user