feat: implement MCP streamable HTTP server
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
sync::Arc,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
use mcpaas_registry::{PostgresRegistry, RegistryError, RegistryOperation};
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PublishedToolCatalog {
|
||||
registry: PostgresRegistry,
|
||||
refresh_interval: Duration,
|
||||
cached: Arc<RwLock<CachedCatalog>>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct CachedCatalog {
|
||||
loaded_at: Option<Instant>,
|
||||
tools: Vec<RegistryOperation>,
|
||||
tools_by_name: HashMap<String, RegistryOperation>,
|
||||
}
|
||||
|
||||
impl PublishedToolCatalog {
|
||||
pub fn new(registry: PostgresRegistry, refresh_interval: Duration) -> Self {
|
||||
Self {
|
||||
registry,
|
||||
refresh_interval,
|
||||
cached: Arc::new(RwLock::new(CachedCatalog::default())),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn list_tools(&self) -> Result<Vec<RegistryOperation>, RegistryError> {
|
||||
self.refresh_if_stale().await?;
|
||||
let guard = self.cached.read().await;
|
||||
Ok(guard.tools.clone())
|
||||
}
|
||||
|
||||
pub async fn get_tool(
|
||||
&self,
|
||||
tool_name: &str,
|
||||
) -> Result<Option<RegistryOperation>, RegistryError> {
|
||||
self.refresh_if_stale().await?;
|
||||
let guard = self.cached.read().await;
|
||||
Ok(guard.tools_by_name.get(tool_name).cloned())
|
||||
}
|
||||
|
||||
async fn refresh_if_stale(&self) -> Result<(), RegistryError> {
|
||||
let should_refresh = {
|
||||
let guard = self.cached.read().await;
|
||||
|
||||
match guard.loaded_at {
|
||||
Some(loaded_at) => loaded_at.elapsed() >= self.refresh_interval,
|
||||
None => true,
|
||||
}
|
||||
};
|
||||
|
||||
if !should_refresh {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let tools = self.registry.list_published_operations().await?;
|
||||
let tools_by_name = tools
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|operation| (operation.name.clone(), operation))
|
||||
.collect::<HashMap<_, _>>();
|
||||
let mut guard = self.cached.write().await;
|
||||
|
||||
guard.loaded_at = Some(Instant::now());
|
||||
guard.tools = tools;
|
||||
guard.tools_by_name = tools_by_name;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user