use std::path::{Path, PathBuf};
use std::sync::Arc;
use mentra::mcp::McpManager;
use crate::runtime::Runtime;
use super::McpServer;
pub(crate) struct McpConnections {
runtime: Arc<Runtime>,
manager: Option<McpManager>,
claimed: Vec<String>,
root: PathBuf,
names: Vec<String>,
}
impl McpConnections {
pub(crate) async fn connect(
runtime: Arc<Runtime>,
root: &Path,
servers: Vec<McpServer>,
) -> Self {
let mut manager = McpManager::new();
let mut claimed = Vec::new();
let mut names = Vec::new();
for server in servers {
let effective = runtime.claim_mcp_server(server.name(), root);
claimed.push(effective.clone());
let outcome = match server {
McpServer::Stdio(mut config) => {
config.name = effective.clone();
manager.connect(&config).await.map_err(|e| e.to_string())
}
McpServer::Sse(mut config) => {
config.name = effective.clone();
manager
.connect_sse(&config)
.await
.map_err(|e| e.to_string())
}
};
match outcome {
Ok(bridged) => {
for tool in bridged {
runtime.mentra_runtime().register_tool(tool);
}
}
Err(error) => {
eprintln!("Warning: MCP server '{effective}' failed to connect: {error}");
}
}
names.push(effective);
}
Self {
runtime,
manager: Some(manager),
claimed,
root: root.to_path_buf(),
names,
}
}
pub(crate) fn names(&self) -> &[String] {
&self.names
}
}
impl Drop for McpConnections {
fn drop(&mut self) {
for name in self.claimed.drain(..) {
self.runtime.release_mcp_claim(&name, &self.root);
}
if let Some(mut manager) = self.manager.take() {
if let Ok(handle) = tokio::runtime::Handle::try_current() {
handle.spawn(async move {
manager.shutdown_all().await;
});
}
}
}
}