use async_trait::async_trait;
use rmcp::model::InitializeRequestParams;
use rmcp::transport::streamable_http_server::session::store::{
SessionState, SessionStore, SessionStoreError,
};
use std::sync::Arc;
use systemprompt_identifiers::SessionId;
use crate::repository::McpSessionRepository;
#[derive(Debug)]
pub struct PostgresSessionStore {
repository: Arc<McpSessionRepository>,
}
impl PostgresSessionStore {
pub const fn new(repository: Arc<McpSessionRepository>) -> Self {
Self { repository }
}
}
#[async_trait]
impl SessionStore for PostgresSessionStore {
async fn load(&self, session_id: &str) -> Result<Option<SessionState>, SessionStoreError> {
let Some(value) = self
.repository
.find_initialize_params(&SessionId::new(session_id))
.await
.map_err(boxed)?
else {
return Ok(None);
};
let params: InitializeRequestParams = serde_json::from_value(value).map_err(boxed)?;
Ok(Some(SessionState::new(params)))
}
async fn store(&self, session_id: &str, state: &SessionState) -> Result<(), SessionStoreError> {
let value = serde_json::to_value(&state.initialize_params).map_err(boxed)?;
self.repository
.store_initialize_params(&SessionId::new(session_id), &value)
.await
.map_err(boxed)
}
async fn delete(&self, session_id: &str) -> Result<(), SessionStoreError> {
self.repository
.clear_initialize_params(&SessionId::new(session_id))
.await
.map_err(boxed)
}
}
fn boxed<E: std::error::Error + Send + Sync + 'static>(error: E) -> SessionStoreError {
Box::new(error)
}