1
0
Files
shell/src/mcp_client.rs
2025-06-01 23:35:22 +09:00

128 lines
3.7 KiB
Rust

use reqwest::Client;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::error::Error;
#[derive(Debug, Serialize, Deserialize)]
pub struct MCPRequest {
pub method: String,
pub params: Value,
pub context: ProjectContext,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct ProjectContext {
pub current_dir: String,
pub project_type: Option<String>, // rust, python, node, etc.
pub files: Vec<String>,
pub git_branch: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct MCPResponse {
pub result: Option<Value>,
pub error: Option<String>,
}
pub struct MCPClient {
client: Client,
server_url: String,
}
impl MCPClient {
pub fn new(server_url: &str) -> Self {
Self {
client: Client::new(),
server_url: server_url.to_string(),
}
}
pub async fn request(&self, method: &str, params: Value) -> Result<MCPResponse, Box<dyn Error>> {
let context = self.get_project_context()?;
let request = MCPRequest {
method: method.to_string(),
params,
context,
};
let response = self.client
.post(&format!("{}/execute", self.server_url))
.json(&request)
.send()
.await?
.json::<MCPResponse>()
.await?;
Ok(response)
}
pub async fn generate_code(&self, prompt: &str, language: &str) -> Result<String, Box<dyn Error>> {
let params = serde_json::json!({
"prompt": prompt,
"language": language
});
let response = self.request("code_with_local_llm", params).await?;
match response.result {
Some(result) => Ok(result["code"].as_str().unwrap_or("").to_string()),
None => Err(response.error.unwrap_or_else(|| "Unknown error".to_string()).into()),
}
}
pub async fn analyze_file(&self, file_path: &str) -> Result<String, Box<dyn Error>> {
let params = serde_json::json!({
"file_path": file_path,
"analysis_type": "general"
});
let response = self.request("read_file_with_analysis", params).await?;
match response.result {
Some(result) => Ok(result["analysis"].as_str().unwrap_or("").to_string()),
None => Err(response.error.unwrap_or_else(|| "Unknown error".to_string()).into()),
}
}
fn get_project_context(&self) -> Result<ProjectContext, Box<dyn Error>> {
use std::env;
use std::fs;
let current_dir = env::current_dir()?.to_string_lossy().to_string();
// Detect project type
let project_type = if fs::metadata("Cargo.toml").is_ok() {
Some("rust".to_string())
} else if fs::metadata("package.json").is_ok() {
Some("node".to_string())
} else if fs::metadata("requirements.txt").is_ok() || fs::metadata("setup.py").is_ok() {
Some("python".to_string())
} else {
None
};
// Get git branch
let git_branch = std::process::Command::new("git")
.args(&["branch", "--show-current"])
.output()
.ok()
.and_then(|output| {
if output.status.success() {
String::from_utf8(output.stdout).ok().map(|s| s.trim().to_string())
} else {
None
}
});
// List relevant files
let files = vec![]; // TODO: Implement file listing logic
Ok(ProjectContext {
current_dir,
project_type,
files,
git_branch,
})
}
}