Skip to content

Commit a3b2335

Browse files
authored
Merge pull request #54 from syncable-dev/feature/langgraph-integration
Feature/langgraph integration
2 parents 7ac8c98 + b7bb7b2 commit a3b2335

3 files changed

Lines changed: 77 additions & 0 deletions

File tree

mcp-python-server-client/src/langgraph_sse_demo.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ async def main():
3030
prompts = [
3131
("about_info", "Call the 'about_info' tool."),
3232
("analysis_scan", "Call the 'analysis_scan' tool on path '../' with display 'matrix'."),
33+
("vulnerability_scan", "Call the 'vulnerability_scan' tool on path '../'."),
3334
("security_scan", "Call the 'security_scan' tool on path '../'."),
3435
("dependency_scan","Call the 'dependency_scan' tool on path '../'."),
3536
]

rust-mcp-server-syncable-cli/src/handler.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ impl ServerHandler for MyServerHandler {
4343
ServerTools::AnalysisScanTool(tool) => tool.call_tool().await,
4444
ServerTools::SecurityScanTool(tool) => tool.call_tool(),
4545
ServerTools::DependencyScanTool(tool) => tool.call_tool().await,
46+
ServerTools::VulnerabilityScanTool(tool) => tool.call_tool().await,
4647
}
4748
}
4849
}

rust-mcp-server-syncable-cli/src/tools.rs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use rust_mcp_sdk::{
55
macros::{mcp_tool, JsonSchema},
66
tool_box,
77
};
8+
use syncable_cli::cli::SeverityThreshold;
89
use std::error::Error;
910
use std::fmt;
1011
use std::path::Path;
@@ -136,6 +137,79 @@ impl AnalysisScanTool {
136137
}
137138
}
138139

140+
#[mcp_tool(
141+
name = "vulnerability_scan",
142+
description = "Scans a project for known vulnerabilities."
143+
)]
144+
145+
#[derive(Debug, ::serde::Deserialize, ::serde::Serialize, JsonSchema)]
146+
pub struct VulnerabilityScanTool {
147+
path: Option<String>,
148+
}
149+
150+
impl VulnerabilityScanTool {
151+
pub async fn call_tool(&self) -> Result<CallToolResult, CallToolError> {
152+
let project_path_str = self.path.as_deref().unwrap_or(".");
153+
154+
// Log to stderr so we don't interfere with MCP stdout JSON messages
155+
eprintln!("🛡️ Scanning project for vulnerabilities: {}", project_path_str);
156+
eprintln!("➡️ Calling syncable_cli::handle_vulnerabilities...");
157+
158+
let vulnerability_results = tokio::task::spawn_blocking({
159+
let project_path = Path::new(project_path_str).to_path_buf();
160+
move || {
161+
// Create a runtime for the blocking task to handle the async function
162+
let rt = tokio::runtime::Runtime::new().unwrap();
163+
rt.block_on(async {
164+
syncable_cli::handle_vulnerabilities(
165+
project_path,
166+
None,
167+
syncable_cli::cli::OutputFormat::Json,
168+
None,
169+
).await
170+
})
171+
}
172+
}).await;
173+
174+
let vulnerability_results = match vulnerability_results {
175+
Ok(result) => result,
176+
Err(e) => return Err(CallToolError::new(AnalyzeToolError(format!("Task panicked: {}", e)))),
177+
};
178+
179+
match vulnerability_results {
180+
Ok(analysis) => {
181+
let json_output = serde_json::to_string_pretty(&analysis).unwrap_or_else(|e| {
182+
format!(
183+
"{{\"error\": \"Failed to serialize analysis result: {}\"}}",
184+
e
185+
)
186+
});
187+
188+
eprintln!("✅ handle_vulnerabilities returned ({} bytes)", json_output.len());
189+
190+
// Validate JSON to ensure it's well-formed
191+
match serde_json::from_str::<serde_json::Value>(&json_output) {
192+
Ok(_) => {
193+
eprintln!("✅ JSON validation passed");
194+
eprintln!("📤 Sending full response ({} bytes)", json_output.len());
195+
Ok(CallToolResult::text_content(vec![TextContent::new(json_output, None, None)]))
196+
}
197+
Err(e) => {
198+
eprintln!("⚠️ JSON validation failed: {}", e);
199+
eprintln!("First 500 chars: {}", &json_output[..std::cmp::min(500, json_output.len())]);
200+
Err(CallToolError::new(AnalyzeToolError(format!("Invalid JSON response: {}", e))))
201+
}
202+
}
203+
}
204+
Err(e) => {
205+
let error_message = format!("Failed to analyze project for vulnerabilities: {}", e);
206+
eprintln!("❌ handle_vulnerabilities error: {}", &error_message);
207+
Err(CallToolError::new(AnalyzeToolError(error_message)))
208+
}
209+
}
210+
}
211+
}
212+
139213
#[mcp_tool(
140214
name = "security_scan",
141215
description = "Scans a project for security vulnerabilities and secret leaks."
@@ -267,6 +341,7 @@ tool_box!(
267341
[
268342
AboutInfoTool,
269343
AnalysisScanTool,
344+
VulnerabilityScanTool,
270345
SecurityScanTool,
271346
DependencyScanTool
272347
]

0 commit comments

Comments
 (0)