Skip to main content
Glama
state.rs5.36 kB
use anyhow::{Result, anyhow}; use fieldwork::Fieldwork; use mcplease::session::SessionStore; use serde::{Deserialize, Serialize}; use std::{ fmt::{self, Debug, Formatter}, path::PathBuf, }; /// Shared context data that can be used across multiple MCP servers #[derive(Debug, Clone, Serialize, Deserialize, Default, Eq, PartialEq)] pub struct SharedContextData { /// Current working context path context_path: Option<PathBuf>, } /// Session data specific to cargo operations #[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)] pub struct CargoSessionData { /// Default toolchain to use for cargo commands (e.g., "stable", "nightly", "1.70.0") default_toolchain: Option<String>, } /// Cargo tools with session support #[derive(Fieldwork)] #[fieldwork(get, get_mut)] pub struct CargoTools { /// Private session store for cargo-specific state session_store: SessionStore<CargoSessionData>, /// Shared context store for cross-server communication (working directory) shared_context_store: SessionStore<SharedContextData>, #[field(set, with)] default_session_id: &'static str, } impl Debug for CargoTools { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.debug_struct("CargoTools") .field("session_store", &self.session_store) .field("shared_context_store", &self.shared_context_store) .field("default_session_id", &self.default_session_id) .finish() } } impl CargoTools { /// Create a new CargoTools instance pub fn new() -> Result<Self> { // Private session store for cargo-specific state let mut private_path = dirs::home_dir().unwrap_or_else(|| PathBuf::from(".")); private_path.push(".ai-tools"); private_path.push("sessions"); private_path.push("cargo-mcp.json"); let session_store = SessionStore::new(Some(private_path))?; // Shared context store for cross-server communication (working directory) let mut shared_path = dirs::home_dir().unwrap_or_else(|| PathBuf::from(".")); shared_path.push(".ai-tools"); shared_path.push("sessions"); shared_path.push("shared-context.json"); let shared_context_store = SessionStore::new(Some(shared_path))?; let mut tools = Self { session_store, shared_context_store, default_session_id: "default", }; // Check for default toolchain from environment variable if let Ok(toolchain) = std::env::var("CARGO_MCP_DEFAULT_TOOLCHAIN") && !toolchain.is_empty() { log::info!("Setting default toolchain from CARGO_MCP_DEFAULT_TOOLCHAIN: {toolchain}"); tools.set_default_toolchain(Some(toolchain), None)?; } Ok(tools) } /// Get context (working directory) for a session pub fn get_context(&mut self, session_id: Option<&str>) -> Result<Option<PathBuf>> { let session_id = session_id.unwrap_or_else(|| self.default_session_id()); let shared_data = self.shared_context_store.get_or_create(session_id)?; Ok(shared_data.context_path.clone()) } /// Set working directory for a session (shared across MCP servers) pub fn set_working_directory(&mut self, path: PathBuf, session_id: Option<&str>) -> Result<()> { let session_id = session_id.unwrap_or_else(|| self.default_session_id()); self.shared_context_store.update(session_id, |data| { data.context_path = Some(path); }) } /// Get cargo-specific session data pub fn get_cargo_session(&mut self, session_id: Option<&str>) -> Result<&CargoSessionData> { let session_id = session_id.unwrap_or_else(|| self.default_session_id()); self.session_store.get_or_create(session_id) } /// Update cargo-specific session data pub fn update_cargo_session<F>(&mut self, session_id: Option<&str>, fun: F) -> Result<()> where F: FnOnce(&mut CargoSessionData), { let session_id = session_id.unwrap_or_else(|| self.default_session_id()); self.session_store.update(session_id, fun) } /// Get the default toolchain for this session pub fn get_default_toolchain(&mut self, session_id: Option<&str>) -> Result<Option<String>> { let session_data = self.get_cargo_session(session_id)?; Ok(session_data.default_toolchain.clone()) } /// Set the default toolchain for this session pub fn set_default_toolchain( &mut self, toolchain: Option<String>, session_id: Option<&str>, ) -> Result<()> { self.update_cargo_session(session_id, |data| { data.default_toolchain = toolchain; }) } /// Check if the current working directory is a Rust project pub fn ensure_rust_project(&mut self, session_id: Option<&str>) -> Result<PathBuf> { let context = self .get_context(session_id)? .ok_or_else(|| anyhow!("No working directory set. Use set_working_directory first."))?; let cargo_toml = context.join("Cargo.toml"); if !cargo_toml.exists() { return Err(anyhow!( "Not a Rust project: Cargo.toml not found in {}", context.display() )); } Ok(context) } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/jbr/cargo-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server