1use crate::errors::Result;
2use crate::Transport;
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub enum Durability {
17 Async,
18 Sync,
19}
20
21impl Durability {
22 pub const fn is_sync(self) -> bool {
23 matches!(self, Durability::Sync)
24 }
25}
26
27impl std::str::FromStr for Durability {
28 type Err = String;
29 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
30 match s {
31 "async" | "Async" => Ok(Durability::Async),
32 "sync" | "Sync" => Ok(Durability::Sync),
33 _ => Err(format!("unknown durability '{s}'; expected 'async' or 'sync'")),
34 }
35 }
36}
37
38#[derive(Debug, Clone)]
39pub struct Config {
40 pub memory_file_path: String,
41 pub transport: Transport,
42 pub bind_addr: String,
43 pub durability: Durability,
44}
45
46impl Config {
47 pub fn from_args(args: &super::Args) -> Result<Self> {
48 let memory_file_path = args
49 .memory_file
50 .clone()
51 .or_else(|| std::env::var("MEMORY_FILE_PATH").ok())
52 .unwrap_or_else(|| "memory.mcpmem".to_string());
53
54 let durability = if let Ok(env) = std::env::var("MCP_MEMORY_DURABILITY") {
55 env.parse().unwrap_or_else(|e| {
56 tracing::warn!("MCP_MEMORY_DURABILITY parse failed: {e}; falling back to Async");
57 Durability::Async
58 })
59 } else {
60 Durability::Async
61 };
62
63 Ok(Config {
64 memory_file_path,
65 transport: args.transport,
66 bind_addr: args.bind.clone(),
67 durability,
68 })
69 }
70}
71
72impl Default for Config {
73 fn default() -> Self {
74 Self {
75 memory_file_path: "memory.mcpmem".to_string(),
76 transport: Transport::Stdio,
77 bind_addr: "127.0.0.1:8080".to_string(),
78 durability: Durability::Async,
79 }
80 }
81}
82
83#[cfg(test)]
84mod tests {
85 use super::*;
86 use clap::Parser;
87 use crate::Args;
88
89 #[test]
90 fn test_config_defaults() {
91 let args = Args::parse_from(["mcp-memory"]);
92 let cfg = Config::from_args(&args).unwrap();
93 assert_eq!(cfg.memory_file_path, "memory.mcpmem");
94 }
95
96 #[test]
97 fn test_config_custom_path() {
98 let args = Args::parse_from(["mcp-memory", "--memory-file", "/tmp/test.jsonl"]);
99 let cfg = Config::from_args(&args).unwrap();
100 assert_eq!(cfg.memory_file_path, "/tmp/test.jsonl");
101 }
102}