turul_mcp_session_storage/
lib.rs

1//! # Session Storage Abstractions and Implementations
2//!
3//! **Pluggable session storage backends for MCP servers across deployment scenarios.**
4//!
5//! Provides the core SessionStorage trait with implementations for InMemory, SQLite,
6//! PostgreSQL, and DynamoDB, enabling seamless scaling from development to production.
7//!
8//! [![Crates.io](https://img.shields.io/crates/v/turul-mcp-session-storage.svg)](https://crates.io/crates/turul-mcp-session-storage)
9//! [![Documentation](https://docs.rs/turul-mcp-session-storage/badge.svg)](https://docs.rs/turul-mcp-session-storage)
10//!
11//! ## Installation
12//!
13//! ```toml
14//! [dependencies]
15//! turul-mcp-session-storage = "0.2"
16//!
17//! # Optional features for different backends
18//! turul-mcp-session-storage = { version = "0.2", features = ["sqlite"] }
19//! turul-mcp-session-storage = { version = "0.2", features = ["postgres"] }
20//! turul-mcp-session-storage = { version = "0.2", features = ["dynamodb"] }
21//! ```
22
23// Core trait and types
24mod traits;
25/// Core session storage traits and types for pluggable backend implementations
26pub use traits::*;
27
28mod session_view;
29pub use session_view::SessionView;
30
31// Implementations
32pub mod in_memory;
33pub mod prelude;
34
35#[cfg(feature = "sqlite")]
36pub mod sqlite;
37
38#[cfg(feature = "postgres")]
39pub mod postgres;
40
41#[cfg(feature = "dynamodb")]
42pub mod dynamodb;
43
44// Re-export for convenience
45/// In-memory session storage implementation for development and testing
46pub use in_memory::{InMemoryConfig, InMemoryError, InMemorySessionStorage, InMemoryStats};
47
48#[cfg(feature = "sqlite")]
49/// SQLite-backed session storage for file-based persistence
50pub use sqlite::{SqliteConfig, SqliteError, SqliteSessionStorage};
51
52#[cfg(feature = "postgres")]
53/// PostgreSQL-backed session storage for production deployments
54pub use postgres::{PostgresConfig, PostgresError, PostgresSessionStorage};
55
56#[cfg(feature = "dynamodb")]
57/// DynamoDB-backed session storage for AWS serverless deployments
58pub use dynamodb::{DynamoDbConfig, DynamoDbError, DynamoDbSessionStorage};
59
60/// Convenience type alias for session storage results
61pub type StorageResult<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
62
63/// Create a default in-memory session storage instance for development and testing
64pub fn create_default_storage() -> InMemorySessionStorage {
65    InMemorySessionStorage::new()
66}
67
68/// Create an in-memory session storage with custom configuration and cleanup settings
69pub fn create_memory_storage(config: InMemoryConfig) -> InMemorySessionStorage {
70    InMemorySessionStorage::with_config(config)
71}
72
73/// Create a SQLite session storage with default configuration and automatic schema setup
74#[cfg(feature = "sqlite")]
75pub async fn create_sqlite_storage() -> Result<SqliteSessionStorage, SqliteError> {
76    SqliteSessionStorage::new().await
77}
78
79/// Create a SQLite session storage with custom database path and connection settings
80#[cfg(feature = "sqlite")]
81pub async fn create_sqlite_storage_with_config(
82    config: SqliteConfig,
83) -> Result<SqliteSessionStorage, SqliteError> {
84    SqliteSessionStorage::with_config(config).await
85}
86
87/// Create a PostgreSQL session storage with default connection parameters from environment
88#[cfg(feature = "postgres")]
89pub async fn create_postgres_storage() -> Result<PostgresSessionStorage, PostgresError> {
90    PostgresSessionStorage::new().await
91}
92
93/// Create a PostgreSQL session storage with custom database URL and connection pool settings
94#[cfg(feature = "postgres")]
95pub async fn create_postgres_storage_with_config(
96    config: PostgresConfig,
97) -> Result<PostgresSessionStorage, PostgresError> {
98    PostgresSessionStorage::with_config(config).await
99}
100
101/// Create a DynamoDB session storage with default AWS configuration and table names
102#[cfg(feature = "dynamodb")]
103pub async fn create_dynamodb_storage() -> Result<DynamoDbSessionStorage, DynamoDbError> {
104    DynamoDbSessionStorage::new().await
105}
106
107/// Create a DynamoDB session storage with custom AWS region and table configuration
108#[cfg(feature = "dynamodb")]
109pub async fn create_dynamodb_storage_with_config(
110    config: DynamoDbConfig,
111) -> Result<DynamoDbSessionStorage, DynamoDbError> {
112    DynamoDbSessionStorage::with_config(config).await
113}
114
115#[cfg(test)]
116mod integration_tests {
117    use super::*;
118    use turul_mcp_protocol::ServerCapabilities;
119
120    #[tokio::test]
121    async fn test_storage_trait_compliance() {
122        let storage = create_default_storage();
123
124        // Test that our storage implements all trait methods
125        let session = storage
126            .create_session(ServerCapabilities::default())
127            .await
128            .unwrap();
129        let session_id = session.session_id.clone();
130
131        // Session operations
132        assert!(storage.get_session(&session_id).await.unwrap().is_some());
133        assert_eq!(storage.session_count().await.unwrap(), 1);
134
135        // State operations
136        storage
137            .set_session_state(&session_id, "test", serde_json::json!("value"))
138            .await
139            .unwrap();
140        let value = storage
141            .get_session_state(&session_id, "test")
142            .await
143            .unwrap();
144        assert_eq!(value, Some(serde_json::json!("value")));
145
146        // Event operations
147        let event = crate::SseEvent::new("test".to_string(), serde_json::json!({"data": "test"}));
148        let stored = storage.store_event(&session_id, event).await.unwrap();
149        assert!(stored.id > 0);
150
151        // Cleanup
152        let deleted = storage.delete_session(&session_id).await.unwrap();
153        assert!(deleted);
154        assert_eq!(storage.session_count().await.unwrap(), 0);
155    }
156}