Skip to main content

rust_memex/
lib.rs

1pub mod auth;
2pub mod common;
3pub mod diagnostics;
4pub mod embeddings;
5pub mod engine;
6pub mod handlers;
7pub mod http;
8pub mod lifecycle;
9pub mod mcp_core;
10pub mod mcp_protocol;
11mod mcp_runtime;
12pub mod path_utils;
13pub mod preprocessing;
14pub mod query;
15pub mod rag;
16pub mod recovery;
17pub mod search;
18pub mod security;
19pub mod startup;
20pub mod storage;
21#[cfg(test)]
22mod tests;
23pub mod tools;
24
25// CLI-only modules (require indicatif, ratatui, crossterm)
26#[cfg(feature = "cli")]
27pub mod progress;
28#[cfg(feature = "cli")]
29pub mod tui;
30
31use anyhow::Result;
32pub use memex_contracts as contracts;
33use tracing::Level;
34
35// Re-export core types for library consumers
36pub use auth::{
37    AuthDenial, AuthManager, AuthResult, Scope, TokenEntry, TokenStoreFile, TokenStoreV2,
38};
39pub use embeddings::{
40    DEFAULT_REQUIRED_DIMENSION, DimensionAdapter, EmbeddingClient, EmbeddingConfig, MLXBridge,
41    MlxConfig, MlxMergeOptions, ProviderConfig, RerankerConfig, TokenConfig,
42    cross_dimension_search_adapt, estimate_tokens, safe_chunk_size, truncate_to_token_limit,
43    validate_batch_tokens, validate_chunk_tokens,
44};
45pub use handlers::{MCPServer, create_server};
46pub use mcp_core::{
47    McpCore, McpDispatch, McpTransport, shared_initialize_result, shared_tools_list_result,
48};
49pub use mcp_core::{dispatch_mcp_jsonrpc_request, dispatch_mcp_payload, dispatch_mcp_request};
50pub use mcp_runtime::build_mcp_core;
51pub use preprocessing::{
52    IntegrityRecommendation, Message, PreprocessingConfig, PreprocessingStats, Preprocessor,
53    TextIntegrityMetrics,
54};
55pub use query::{
56    LoctreeSuggestion, QueryIntent, QueryRouter, RecommendedSearchMode, RoutingDecision,
57    SearchModeRecommendation, TemporalHints, detect_intent,
58};
59pub use rag::{
60    Chunk as PipelineChunk,
61    ChunkOpts,
62    ChunkProvider,
63    ChunkerKind,
64    ContextPrefixConfig,
65    CrossStoreRecoveryBatchReport,
66    CrossStoreRecoveryReport,
67    CrossStoreRecoveryState,
68    EmbeddedChunk,
69    EnrichedChunk,
70    FileContent,
71    IndexResult,
72    OnionSlice,
73    OnionSliceConfig,
74    OuterSynthesis,
75    PipelineConfig,
76    PipelineEvent,
77    PipelineGovernorConfig,
78    PipelineResult,
79    PipelineSnapshot,
80    PipelineStats,
81    RAGPipeline,
82    SearchOptions,
83    SearchResult,
84    SliceLayer,
85    SliceMode,
86    compute_content_hash,
87    create_enriched_chunks,
88    create_onion_slices,
89    detect_default_chunker,
90    inspect_cross_store_recovery,
91    repair_cross_store_recovery,
92    // Async pipeline exports
93    run_pipeline,
94};
95pub use recovery::{
96    MaintenanceExecution, MergeExecution, RepairExecution, cleanup_versions, collect_garbage,
97    compact_database, merge_databases, repair_writes,
98};
99pub use search::{
100    BM25Config, BM25Index, HybridConfig, HybridSearchResult, HybridSearcher, SearchMode,
101    StemLanguage,
102};
103pub use security::NamespaceSecurityConfig;
104pub use startup::{StartupSchemaGuard, guard_daemon_startup_schema};
105pub use storage::{
106    ChromaDocument, CrossStoreRecoveryBatch, CrossStoreRecoveryDocumentRef,
107    CrossStoreRecoveryStatus, DEFAULT_TABLE_NAME, GcConfig, GcStats, SchemaMigrationReport,
108    SchemaMismatchWriteError, SchemaVersion, StorageManager, TableStats, parse_duration_string,
109    required_columns_for,
110};
111
112// High-level engine API
113pub use engine::{BatchResult, MemexConfig, MemexEngine, MetaFilter, StoreItem};
114pub use lifecycle::{
115    ExportRecord, ImportOutcome, NamespaceMigrationOutcome, ReindexJob, ReindexOutcome,
116    ReprocessJob, ReprocessOutcome, default_reindexed_namespace, export_namespace_jsonl_stream,
117    import_jsonl_bytes_stream, import_jsonl_file, import_jsonl_reader, migrate_namespace_atomic,
118    reindex_namespace, reprocess_jsonl_file,
119};
120
121// Canonical MCP metadata plus local Rust helper API.
122pub use tools::{
123    ToolDefinition, ToolResult, delete_document, delete_documents_by_filter, get_document,
124    search_documents, store_document, store_documents_batch, tool_definitions,
125};
126
127// CLI-only re-exports (require indicatif, ratatui, crossterm)
128#[cfg(feature = "cli")]
129pub use progress::IndexProgressTracker;
130#[cfg(feature = "cli")]
131pub use tui::{
132    CheckStatus, HealthCheckItem, HealthCheckResult, HealthChecker, HostDetection, HostKind,
133    WizardConfig, detect_hosts, run_wizard,
134};
135
136#[derive(Debug, Clone)]
137pub struct ServerConfig {
138    /// Cache size in MB for moka in-memory cache
139    pub cache_mb: usize,
140
141    /// Path for embedded vector store (LanceDB)
142    pub db_path: String,
143
144    /// Max allowed request size (bytes) for JSON-RPC framing
145    pub max_request_bytes: usize,
146
147    /// Default log level to use when wiring tracing
148    pub log_level: Level,
149
150    /// Allowed paths for file access (whitelist).
151    /// If empty, defaults to $HOME and current working directory.
152    /// Supports ~ expansion and absolute paths.
153    pub allowed_paths: Vec<String>,
154
155    /// Namespace security configuration (token-based access control)
156    pub security: NamespaceSecurityConfig,
157
158    /// Embedding provider configuration (universal, config-driven)
159    pub embeddings: EmbeddingConfig,
160
161    /// Hybrid search configuration (vector + BM25)
162    pub hybrid: HybridConfig,
163}
164
165impl Default for ServerConfig {
166    fn default() -> Self {
167        Self {
168            cache_mb: 4096,
169            db_path: "~/.rmcp-servers/rust-memex/lancedb".to_string(),
170            max_request_bytes: 5 * 1024 * 1024,
171            log_level: Level::INFO,
172            allowed_paths: vec![],
173            security: NamespaceSecurityConfig::default(),
174            embeddings: EmbeddingConfig::default(),
175            hybrid: HybridConfig::default(),
176        }
177    }
178}
179
180impl ServerConfig {
181    #[doc(alias = "with_db_path")]
182    pub fn with_storage_path(mut self, db_path: impl Into<String>) -> Self {
183        self.db_path = db_path.into();
184        self
185    }
186
187    #[deprecated(note = "use with_storage_path")]
188    pub fn with_db_path(self, db_path: impl Into<String>) -> Self {
189        self.with_storage_path(db_path)
190    }
191}
192
193/// Helper to build and run the stdin/stdout server for library consumers.
194pub async fn run_stdio_server(config: ServerConfig) -> Result<()> {
195    let server = create_server(config).await?;
196    server.run_stdio().await
197}
198
199#[cfg(test)]
200mod lib_tests {
201    use super::*;
202    use serde_json::json;
203
204    #[test]
205    fn default_config_has_expected_values() {
206        let cfg = ServerConfig::default();
207        assert_eq!(cfg.cache_mb, 4096);
208        assert_eq!(cfg.db_path, "~/.rmcp-servers/rust-memex/lancedb");
209        assert_eq!(cfg.max_request_bytes, 5 * 1024 * 1024);
210    }
211
212    #[test]
213    fn contracts_are_reachable_through_main_crate() {
214        let audit = contracts::audit::AuditResult {
215            namespace: "animals".to_string(),
216            document_count: 4,
217            avg_chunk_length: 256,
218            sentence_integrity: 0.92,
219            word_integrity: 0.94,
220            chunk_quality: 0.9,
221            overall_score: 0.91,
222            recommendation: contracts::audit::AuditRecommendation::Good,
223            passes_threshold: true,
224        };
225        let storage = contracts::stats::StorageMetrics::default();
226        let timeline = contracts::timeline::TimelineFilter {
227            namespace: Some("animals".to_string()),
228            since: Some("2026-04-19".to_string()),
229            gaps_only: false,
230        };
231        let progress = contracts::progress::SseEvent {
232            event: "done".to_string(),
233            id: Some("evt-1".to_string()),
234            data: json!({ "status": "ok" }),
235        };
236
237        let _: rag::AuditResult = audit.clone();
238        let _: http::AuditResult = audit;
239        let _: http::StorageMetrics = storage;
240        let _: http::TimelineFilter = timeline;
241        let _: http::SseEvent = progress;
242    }
243}