use std::collections::{BTreeSet, VecDeque};
#[derive(Debug, Clone)]
pub struct McpToolInfo {
pub full_name: String,
pub description: String,
pub input_schema: serde_json::Value,
}
#[derive(Debug, Clone)]
pub struct McpActivationSet {
cap: usize,
lru: VecDeque<String>,
active: BTreeSet<String>,
}
impl McpActivationSet {
#[must_use]
pub fn new(cap: usize) -> Self {
Self {
cap,
lru: VecDeque::with_capacity(cap),
active: BTreeSet::new(),
}
}
#[must_use]
pub fn is_active(&self, name: &str) -> bool {
self.active.contains(name)
}
#[must_use]
pub fn len(&self) -> usize {
self.active.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.active.is_empty()
}
pub fn iter_active(&self) -> impl Iterator<Item = &str> {
self.lru.iter().map(String::as_str)
}
pub fn activate(&mut self, name: &str) -> Option<String> {
if self.cap == 0 {
return None;
}
if self.active.contains(name) {
if let Some(idx) = self.lru.iter().position(|n| n == name) {
let _ = self.lru.remove(idx);
}
self.lru.push_front(name.to_string());
return None;
}
self.active.insert(name.to_string());
self.lru.push_front(name.to_string());
if self.lru.len() > self.cap
&& let Some(evicted) = self.lru.pop_back()
{
self.active.remove(&evicted);
return Some(evicted);
}
None
}
#[must_use]
pub fn snapshot(&self) -> Self {
self.clone()
}
}