MemoryOS 2.0.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (315) hide show
  1. memoryos-2.0.3.dist-info/METADATA +418 -0
  2. memoryos-2.0.3.dist-info/RECORD +315 -0
  3. memoryos-2.0.3.dist-info/WHEEL +4 -0
  4. memoryos-2.0.3.dist-info/entry_points.txt +3 -0
  5. memoryos-2.0.3.dist-info/licenses/LICENSE +201 -0
  6. memos/__init__.py +20 -0
  7. memos/api/client.py +571 -0
  8. memos/api/config.py +1018 -0
  9. memos/api/context/dependencies.py +50 -0
  10. memos/api/exceptions.py +53 -0
  11. memos/api/handlers/__init__.py +62 -0
  12. memos/api/handlers/add_handler.py +158 -0
  13. memos/api/handlers/base_handler.py +194 -0
  14. memos/api/handlers/chat_handler.py +1401 -0
  15. memos/api/handlers/component_init.py +388 -0
  16. memos/api/handlers/config_builders.py +190 -0
  17. memos/api/handlers/feedback_handler.py +93 -0
  18. memos/api/handlers/formatters_handler.py +237 -0
  19. memos/api/handlers/memory_handler.py +316 -0
  20. memos/api/handlers/scheduler_handler.py +497 -0
  21. memos/api/handlers/search_handler.py +222 -0
  22. memos/api/handlers/suggestion_handler.py +117 -0
  23. memos/api/mcp_serve.py +614 -0
  24. memos/api/middleware/request_context.py +101 -0
  25. memos/api/product_api.py +38 -0
  26. memos/api/product_models.py +1206 -0
  27. memos/api/routers/__init__.py +1 -0
  28. memos/api/routers/product_router.py +477 -0
  29. memos/api/routers/server_router.py +394 -0
  30. memos/api/server_api.py +44 -0
  31. memos/api/start_api.py +433 -0
  32. memos/chunkers/__init__.py +4 -0
  33. memos/chunkers/base.py +24 -0
  34. memos/chunkers/charactertext_chunker.py +41 -0
  35. memos/chunkers/factory.py +24 -0
  36. memos/chunkers/markdown_chunker.py +62 -0
  37. memos/chunkers/sentence_chunker.py +54 -0
  38. memos/chunkers/simple_chunker.py +50 -0
  39. memos/cli.py +113 -0
  40. memos/configs/__init__.py +0 -0
  41. memos/configs/base.py +82 -0
  42. memos/configs/chunker.py +59 -0
  43. memos/configs/embedder.py +88 -0
  44. memos/configs/graph_db.py +236 -0
  45. memos/configs/internet_retriever.py +100 -0
  46. memos/configs/llm.py +151 -0
  47. memos/configs/mem_agent.py +54 -0
  48. memos/configs/mem_chat.py +81 -0
  49. memos/configs/mem_cube.py +105 -0
  50. memos/configs/mem_os.py +83 -0
  51. memos/configs/mem_reader.py +91 -0
  52. memos/configs/mem_scheduler.py +385 -0
  53. memos/configs/mem_user.py +70 -0
  54. memos/configs/memory.py +324 -0
  55. memos/configs/parser.py +38 -0
  56. memos/configs/reranker.py +18 -0
  57. memos/configs/utils.py +8 -0
  58. memos/configs/vec_db.py +80 -0
  59. memos/context/context.py +355 -0
  60. memos/dependency.py +52 -0
  61. memos/deprecation.py +262 -0
  62. memos/embedders/__init__.py +0 -0
  63. memos/embedders/ark.py +95 -0
  64. memos/embedders/base.py +106 -0
  65. memos/embedders/factory.py +29 -0
  66. memos/embedders/ollama.py +77 -0
  67. memos/embedders/sentence_transformer.py +49 -0
  68. memos/embedders/universal_api.py +51 -0
  69. memos/exceptions.py +30 -0
  70. memos/graph_dbs/__init__.py +0 -0
  71. memos/graph_dbs/base.py +274 -0
  72. memos/graph_dbs/factory.py +27 -0
  73. memos/graph_dbs/item.py +46 -0
  74. memos/graph_dbs/nebular.py +1794 -0
  75. memos/graph_dbs/neo4j.py +1942 -0
  76. memos/graph_dbs/neo4j_community.py +1058 -0
  77. memos/graph_dbs/polardb.py +5446 -0
  78. memos/hello_world.py +97 -0
  79. memos/llms/__init__.py +0 -0
  80. memos/llms/base.py +25 -0
  81. memos/llms/deepseek.py +13 -0
  82. memos/llms/factory.py +38 -0
  83. memos/llms/hf.py +443 -0
  84. memos/llms/hf_singleton.py +114 -0
  85. memos/llms/ollama.py +135 -0
  86. memos/llms/openai.py +222 -0
  87. memos/llms/openai_new.py +198 -0
  88. memos/llms/qwen.py +13 -0
  89. memos/llms/utils.py +14 -0
  90. memos/llms/vllm.py +218 -0
  91. memos/log.py +237 -0
  92. memos/mem_agent/base.py +19 -0
  93. memos/mem_agent/deepsearch_agent.py +391 -0
  94. memos/mem_agent/factory.py +36 -0
  95. memos/mem_chat/__init__.py +0 -0
  96. memos/mem_chat/base.py +30 -0
  97. memos/mem_chat/factory.py +21 -0
  98. memos/mem_chat/simple.py +200 -0
  99. memos/mem_cube/__init__.py +0 -0
  100. memos/mem_cube/base.py +30 -0
  101. memos/mem_cube/general.py +240 -0
  102. memos/mem_cube/navie.py +172 -0
  103. memos/mem_cube/utils.py +169 -0
  104. memos/mem_feedback/base.py +15 -0
  105. memos/mem_feedback/feedback.py +1192 -0
  106. memos/mem_feedback/simple_feedback.py +40 -0
  107. memos/mem_feedback/utils.py +230 -0
  108. memos/mem_os/client.py +5 -0
  109. memos/mem_os/core.py +1203 -0
  110. memos/mem_os/main.py +582 -0
  111. memos/mem_os/product.py +1608 -0
  112. memos/mem_os/product_server.py +455 -0
  113. memos/mem_os/utils/default_config.py +359 -0
  114. memos/mem_os/utils/format_utils.py +1403 -0
  115. memos/mem_os/utils/reference_utils.py +162 -0
  116. memos/mem_reader/__init__.py +0 -0
  117. memos/mem_reader/base.py +47 -0
  118. memos/mem_reader/factory.py +53 -0
  119. memos/mem_reader/memory.py +298 -0
  120. memos/mem_reader/multi_modal_struct.py +965 -0
  121. memos/mem_reader/read_multi_modal/__init__.py +43 -0
  122. memos/mem_reader/read_multi_modal/assistant_parser.py +311 -0
  123. memos/mem_reader/read_multi_modal/base.py +273 -0
  124. memos/mem_reader/read_multi_modal/file_content_parser.py +826 -0
  125. memos/mem_reader/read_multi_modal/image_parser.py +359 -0
  126. memos/mem_reader/read_multi_modal/multi_modal_parser.py +252 -0
  127. memos/mem_reader/read_multi_modal/string_parser.py +139 -0
  128. memos/mem_reader/read_multi_modal/system_parser.py +327 -0
  129. memos/mem_reader/read_multi_modal/text_content_parser.py +131 -0
  130. memos/mem_reader/read_multi_modal/tool_parser.py +210 -0
  131. memos/mem_reader/read_multi_modal/user_parser.py +218 -0
  132. memos/mem_reader/read_multi_modal/utils.py +358 -0
  133. memos/mem_reader/simple_struct.py +912 -0
  134. memos/mem_reader/strategy_struct.py +163 -0
  135. memos/mem_reader/utils.py +157 -0
  136. memos/mem_scheduler/__init__.py +0 -0
  137. memos/mem_scheduler/analyzer/__init__.py +0 -0
  138. memos/mem_scheduler/analyzer/api_analyzer.py +714 -0
  139. memos/mem_scheduler/analyzer/eval_analyzer.py +219 -0
  140. memos/mem_scheduler/analyzer/mos_for_test_scheduler.py +571 -0
  141. memos/mem_scheduler/analyzer/scheduler_for_eval.py +280 -0
  142. memos/mem_scheduler/base_scheduler.py +1319 -0
  143. memos/mem_scheduler/general_modules/__init__.py +0 -0
  144. memos/mem_scheduler/general_modules/api_misc.py +137 -0
  145. memos/mem_scheduler/general_modules/base.py +80 -0
  146. memos/mem_scheduler/general_modules/init_components_for_scheduler.py +425 -0
  147. memos/mem_scheduler/general_modules/misc.py +313 -0
  148. memos/mem_scheduler/general_modules/scheduler_logger.py +389 -0
  149. memos/mem_scheduler/general_modules/task_threads.py +315 -0
  150. memos/mem_scheduler/general_scheduler.py +1495 -0
  151. memos/mem_scheduler/memory_manage_modules/__init__.py +5 -0
  152. memos/mem_scheduler/memory_manage_modules/memory_filter.py +306 -0
  153. memos/mem_scheduler/memory_manage_modules/retriever.py +547 -0
  154. memos/mem_scheduler/monitors/__init__.py +0 -0
  155. memos/mem_scheduler/monitors/dispatcher_monitor.py +366 -0
  156. memos/mem_scheduler/monitors/general_monitor.py +394 -0
  157. memos/mem_scheduler/monitors/task_schedule_monitor.py +254 -0
  158. memos/mem_scheduler/optimized_scheduler.py +410 -0
  159. memos/mem_scheduler/orm_modules/__init__.py +0 -0
  160. memos/mem_scheduler/orm_modules/api_redis_model.py +518 -0
  161. memos/mem_scheduler/orm_modules/base_model.py +729 -0
  162. memos/mem_scheduler/orm_modules/monitor_models.py +261 -0
  163. memos/mem_scheduler/orm_modules/redis_model.py +699 -0
  164. memos/mem_scheduler/scheduler_factory.py +23 -0
  165. memos/mem_scheduler/schemas/__init__.py +0 -0
  166. memos/mem_scheduler/schemas/analyzer_schemas.py +52 -0
  167. memos/mem_scheduler/schemas/api_schemas.py +233 -0
  168. memos/mem_scheduler/schemas/general_schemas.py +55 -0
  169. memos/mem_scheduler/schemas/message_schemas.py +173 -0
  170. memos/mem_scheduler/schemas/monitor_schemas.py +406 -0
  171. memos/mem_scheduler/schemas/task_schemas.py +132 -0
  172. memos/mem_scheduler/task_schedule_modules/__init__.py +0 -0
  173. memos/mem_scheduler/task_schedule_modules/dispatcher.py +740 -0
  174. memos/mem_scheduler/task_schedule_modules/local_queue.py +247 -0
  175. memos/mem_scheduler/task_schedule_modules/orchestrator.py +74 -0
  176. memos/mem_scheduler/task_schedule_modules/redis_queue.py +1385 -0
  177. memos/mem_scheduler/task_schedule_modules/task_queue.py +162 -0
  178. memos/mem_scheduler/utils/__init__.py +0 -0
  179. memos/mem_scheduler/utils/api_utils.py +77 -0
  180. memos/mem_scheduler/utils/config_utils.py +100 -0
  181. memos/mem_scheduler/utils/db_utils.py +50 -0
  182. memos/mem_scheduler/utils/filter_utils.py +176 -0
  183. memos/mem_scheduler/utils/metrics.py +125 -0
  184. memos/mem_scheduler/utils/misc_utils.py +290 -0
  185. memos/mem_scheduler/utils/monitor_event_utils.py +67 -0
  186. memos/mem_scheduler/utils/status_tracker.py +229 -0
  187. memos/mem_scheduler/webservice_modules/__init__.py +0 -0
  188. memos/mem_scheduler/webservice_modules/rabbitmq_service.py +485 -0
  189. memos/mem_scheduler/webservice_modules/redis_service.py +380 -0
  190. memos/mem_user/factory.py +94 -0
  191. memos/mem_user/mysql_persistent_user_manager.py +271 -0
  192. memos/mem_user/mysql_user_manager.py +502 -0
  193. memos/mem_user/persistent_factory.py +98 -0
  194. memos/mem_user/persistent_user_manager.py +260 -0
  195. memos/mem_user/redis_persistent_user_manager.py +225 -0
  196. memos/mem_user/user_manager.py +488 -0
  197. memos/memories/__init__.py +0 -0
  198. memos/memories/activation/__init__.py +0 -0
  199. memos/memories/activation/base.py +42 -0
  200. memos/memories/activation/item.py +56 -0
  201. memos/memories/activation/kv.py +292 -0
  202. memos/memories/activation/vllmkv.py +219 -0
  203. memos/memories/base.py +19 -0
  204. memos/memories/factory.py +42 -0
  205. memos/memories/parametric/__init__.py +0 -0
  206. memos/memories/parametric/base.py +19 -0
  207. memos/memories/parametric/item.py +11 -0
  208. memos/memories/parametric/lora.py +41 -0
  209. memos/memories/textual/__init__.py +0 -0
  210. memos/memories/textual/base.py +92 -0
  211. memos/memories/textual/general.py +236 -0
  212. memos/memories/textual/item.py +304 -0
  213. memos/memories/textual/naive.py +187 -0
  214. memos/memories/textual/prefer_text_memory/__init__.py +0 -0
  215. memos/memories/textual/prefer_text_memory/adder.py +504 -0
  216. memos/memories/textual/prefer_text_memory/config.py +106 -0
  217. memos/memories/textual/prefer_text_memory/extractor.py +221 -0
  218. memos/memories/textual/prefer_text_memory/factory.py +85 -0
  219. memos/memories/textual/prefer_text_memory/retrievers.py +177 -0
  220. memos/memories/textual/prefer_text_memory/spliter.py +132 -0
  221. memos/memories/textual/prefer_text_memory/utils.py +93 -0
  222. memos/memories/textual/preference.py +344 -0
  223. memos/memories/textual/simple_preference.py +161 -0
  224. memos/memories/textual/simple_tree.py +69 -0
  225. memos/memories/textual/tree.py +459 -0
  226. memos/memories/textual/tree_text_memory/__init__.py +0 -0
  227. memos/memories/textual/tree_text_memory/organize/__init__.py +0 -0
  228. memos/memories/textual/tree_text_memory/organize/handler.py +184 -0
  229. memos/memories/textual/tree_text_memory/organize/manager.py +518 -0
  230. memos/memories/textual/tree_text_memory/organize/relation_reason_detector.py +238 -0
  231. memos/memories/textual/tree_text_memory/organize/reorganizer.py +622 -0
  232. memos/memories/textual/tree_text_memory/retrieve/__init__.py +0 -0
  233. memos/memories/textual/tree_text_memory/retrieve/advanced_searcher.py +364 -0
  234. memos/memories/textual/tree_text_memory/retrieve/bm25_util.py +186 -0
  235. memos/memories/textual/tree_text_memory/retrieve/bochasearch.py +419 -0
  236. memos/memories/textual/tree_text_memory/retrieve/internet_retriever.py +270 -0
  237. memos/memories/textual/tree_text_memory/retrieve/internet_retriever_factory.py +102 -0
  238. memos/memories/textual/tree_text_memory/retrieve/reasoner.py +61 -0
  239. memos/memories/textual/tree_text_memory/retrieve/recall.py +497 -0
  240. memos/memories/textual/tree_text_memory/retrieve/reranker.py +111 -0
  241. memos/memories/textual/tree_text_memory/retrieve/retrieval_mid_structs.py +16 -0
  242. memos/memories/textual/tree_text_memory/retrieve/retrieve_utils.py +472 -0
  243. memos/memories/textual/tree_text_memory/retrieve/searcher.py +848 -0
  244. memos/memories/textual/tree_text_memory/retrieve/task_goal_parser.py +135 -0
  245. memos/memories/textual/tree_text_memory/retrieve/utils.py +54 -0
  246. memos/memories/textual/tree_text_memory/retrieve/xinyusearch.py +387 -0
  247. memos/memos_tools/dinding_report_bot.py +453 -0
  248. memos/memos_tools/lockfree_dict.py +120 -0
  249. memos/memos_tools/notification_service.py +44 -0
  250. memos/memos_tools/notification_utils.py +142 -0
  251. memos/memos_tools/singleton.py +174 -0
  252. memos/memos_tools/thread_safe_dict.py +310 -0
  253. memos/memos_tools/thread_safe_dict_segment.py +382 -0
  254. memos/multi_mem_cube/__init__.py +0 -0
  255. memos/multi_mem_cube/composite_cube.py +86 -0
  256. memos/multi_mem_cube/single_cube.py +874 -0
  257. memos/multi_mem_cube/views.py +54 -0
  258. memos/parsers/__init__.py +0 -0
  259. memos/parsers/base.py +15 -0
  260. memos/parsers/factory.py +21 -0
  261. memos/parsers/markitdown.py +28 -0
  262. memos/reranker/__init__.py +4 -0
  263. memos/reranker/base.py +25 -0
  264. memos/reranker/concat.py +103 -0
  265. memos/reranker/cosine_local.py +102 -0
  266. memos/reranker/factory.py +72 -0
  267. memos/reranker/http_bge.py +324 -0
  268. memos/reranker/http_bge_strategy.py +327 -0
  269. memos/reranker/noop.py +19 -0
  270. memos/reranker/strategies/__init__.py +4 -0
  271. memos/reranker/strategies/base.py +61 -0
  272. memos/reranker/strategies/concat_background.py +94 -0
  273. memos/reranker/strategies/concat_docsource.py +110 -0
  274. memos/reranker/strategies/dialogue_common.py +109 -0
  275. memos/reranker/strategies/factory.py +31 -0
  276. memos/reranker/strategies/single_turn.py +107 -0
  277. memos/reranker/strategies/singleturn_outmem.py +98 -0
  278. memos/settings.py +10 -0
  279. memos/templates/__init__.py +0 -0
  280. memos/templates/advanced_search_prompts.py +211 -0
  281. memos/templates/cloud_service_prompt.py +107 -0
  282. memos/templates/instruction_completion.py +66 -0
  283. memos/templates/mem_agent_prompts.py +85 -0
  284. memos/templates/mem_feedback_prompts.py +822 -0
  285. memos/templates/mem_reader_prompts.py +1096 -0
  286. memos/templates/mem_reader_strategy_prompts.py +238 -0
  287. memos/templates/mem_scheduler_prompts.py +626 -0
  288. memos/templates/mem_search_prompts.py +93 -0
  289. memos/templates/mos_prompts.py +403 -0
  290. memos/templates/prefer_complete_prompt.py +735 -0
  291. memos/templates/tool_mem_prompts.py +139 -0
  292. memos/templates/tree_reorganize_prompts.py +230 -0
  293. memos/types/__init__.py +34 -0
  294. memos/types/general_types.py +151 -0
  295. memos/types/openai_chat_completion_types/__init__.py +15 -0
  296. memos/types/openai_chat_completion_types/chat_completion_assistant_message_param.py +56 -0
  297. memos/types/openai_chat_completion_types/chat_completion_content_part_image_param.py +27 -0
  298. memos/types/openai_chat_completion_types/chat_completion_content_part_input_audio_param.py +23 -0
  299. memos/types/openai_chat_completion_types/chat_completion_content_part_param.py +43 -0
  300. memos/types/openai_chat_completion_types/chat_completion_content_part_refusal_param.py +16 -0
  301. memos/types/openai_chat_completion_types/chat_completion_content_part_text_param.py +16 -0
  302. memos/types/openai_chat_completion_types/chat_completion_message_custom_tool_call_param.py +27 -0
  303. memos/types/openai_chat_completion_types/chat_completion_message_function_tool_call_param.py +32 -0
  304. memos/types/openai_chat_completion_types/chat_completion_message_param.py +18 -0
  305. memos/types/openai_chat_completion_types/chat_completion_message_tool_call_union_param.py +15 -0
  306. memos/types/openai_chat_completion_types/chat_completion_system_message_param.py +36 -0
  307. memos/types/openai_chat_completion_types/chat_completion_tool_message_param.py +30 -0
  308. memos/types/openai_chat_completion_types/chat_completion_user_message_param.py +34 -0
  309. memos/utils.py +123 -0
  310. memos/vec_dbs/__init__.py +0 -0
  311. memos/vec_dbs/base.py +117 -0
  312. memos/vec_dbs/factory.py +23 -0
  313. memos/vec_dbs/item.py +50 -0
  314. memos/vec_dbs/milvus.py +654 -0
  315. memos/vec_dbs/qdrant.py +355 -0
memos/api/mcp_serve.py ADDED
@@ -0,0 +1,614 @@
1
+ import asyncio
2
+ import os
3
+
4
+ from typing import Any
5
+
6
+ from dotenv import load_dotenv
7
+ from fastmcp import FastMCP
8
+
9
+ # Assuming these are your imports
10
+ from memos.mem_os.main import MOS
11
+ from memos.mem_os.utils.default_config import get_default
12
+ from memos.mem_user.user_manager import UserRole
13
+
14
+
15
+ load_dotenv()
16
+
17
+
18
+ def load_default_config(user_id="default_user"):
19
+ """
20
+ Load MOS configuration from environment variables.
21
+
22
+ IMPORTANT for Neo4j Community Edition:
23
+ Community Edition does not support administrative commands like 'CREATE DATABASE'.
24
+ To avoid errors, ensure the following environment variables are set correctly:
25
+ - NEO4J_DB_NAME=neo4j (Must use the default database)
26
+ - NEO4J_AUTO_CREATE=false (Disable automatic database creation)
27
+ - NEO4J_USE_MULTI_DB=false (Disable multi-tenant database mode)
28
+ """
29
+ # Define mapping between environment variables and configuration parameters
30
+ # We support both clean names and MOS_ prefixed names for compatibility
31
+ env_mapping = {
32
+ "OPENAI_API_KEY": "openai_api_key",
33
+ "OPENAI_API_BASE": "openai_api_base",
34
+ "MOS_TEXT_MEM_TYPE": "text_mem_type",
35
+ "NEO4J_URI": "neo4j_uri",
36
+ "NEO4J_USER": "neo4j_user",
37
+ "NEO4J_PASSWORD": "neo4j_password",
38
+ "NEO4J_DB_NAME": "neo4j_db_name",
39
+ "NEO4J_AUTO_CREATE": "neo4j_auto_create",
40
+ "NEO4J_USE_MULTI_DB": "use_multi_db",
41
+ "MOS_NEO4J_SHARED_DB": "mos_shared_db", # Special handle later
42
+ "MODEL_NAME": "model_name",
43
+ "MOS_CHAT_MODEL": "model_name",
44
+ "EMBEDDER_MODEL": "embedder_model",
45
+ "MOS_EMBEDDER_MODEL": "embedder_model",
46
+ "CHUNK_SIZE": "chunk_size",
47
+ "CHUNK_OVERLAP": "chunk_overlap",
48
+ "ENABLE_MEM_SCHEDULER": "enable_mem_scheduler",
49
+ "MOS_ENABLE_SCHEDULER": "enable_mem_scheduler",
50
+ "ENABLE_ACTIVATION_MEMORY": "enable_activation_memory",
51
+ "TEMPERATURE": "temperature",
52
+ "MOS_CHAT_TEMPERATURE": "temperature",
53
+ "MAX_TOKENS": "max_tokens",
54
+ "MOS_MAX_TOKENS": "max_tokens",
55
+ "TOP_P": "top_p",
56
+ "MOS_TOP_P": "top_p",
57
+ "TOP_K": "top_k",
58
+ "MOS_TOP_K": "top_k",
59
+ "SCHEDULER_TOP_K": "scheduler_top_k",
60
+ "MOS_SCHEDULER_TOP_K": "scheduler_top_k",
61
+ "SCHEDULER_TOP_N": "scheduler_top_n",
62
+ }
63
+
64
+ # Fields that should always be kept as strings (not converted to numbers)
65
+ string_only_fields = {
66
+ "openai_api_key",
67
+ "openai_api_base",
68
+ "neo4j_uri",
69
+ "neo4j_user",
70
+ "neo4j_password",
71
+ "neo4j_db_name",
72
+ "text_mem_type",
73
+ "model_name",
74
+ "embedder_model",
75
+ }
76
+
77
+ kwargs = {"user_id": user_id}
78
+ for env_key, param_key in env_mapping.items():
79
+ val = os.getenv(env_key)
80
+ if val is not None:
81
+ # Strip quotes if they exist (sometimes happens with .env)
82
+ if (val.startswith('"') and val.endswith('"')) or (
83
+ val.startswith("'") and val.endswith("'")
84
+ ):
85
+ val = val[1:-1]
86
+
87
+ # Handle boolean conversions
88
+ if val.lower() in ("true", "false"):
89
+ kwargs[param_key] = val.lower() == "true"
90
+ # Keep certain fields as strings
91
+ elif param_key in string_only_fields:
92
+ kwargs[param_key] = val
93
+ else:
94
+ # Try numeric conversions (int first, then float)
95
+ try:
96
+ if "." in val:
97
+ kwargs[param_key] = float(val)
98
+ else:
99
+ kwargs[param_key] = int(val)
100
+ except ValueError:
101
+ kwargs[param_key] = val
102
+
103
+ # Logic handle for MOS_NEO4J_SHARED_DB vs use_multi_db
104
+ if "mos_shared_db" in kwargs:
105
+ kwargs["use_multi_db"] = not kwargs.pop("mos_shared_db")
106
+
107
+ # Extract mandatory or special params
108
+ openai_api_key = kwargs.pop("openai_api_key", os.getenv("OPENAI_API_KEY"))
109
+ openai_api_base = kwargs.pop("openai_api_base", "https://api.openai.com/v1")
110
+ text_mem_type = kwargs.pop("text_mem_type", "tree_text")
111
+
112
+ # Ensure embedder_model has a default value if not set
113
+ if "embedder_model" not in kwargs:
114
+ kwargs["embedder_model"] = os.getenv("EMBEDDER_MODEL", "nomic-embed-text:latest")
115
+
116
+ config, cube = get_default(
117
+ openai_api_key=openai_api_key,
118
+ openai_api_base=openai_api_base,
119
+ text_mem_type=text_mem_type,
120
+ **kwargs,
121
+ )
122
+ return config, cube
123
+
124
+
125
+ class MOSMCPStdioServer:
126
+ def __init__(self):
127
+ self.mcp = FastMCP("MOS Memory System")
128
+ config, cube = load_default_config()
129
+ self.mos_core = MOS(config=config)
130
+ self.mos_core.register_mem_cube(cube)
131
+ self._setup_tools()
132
+
133
+
134
+ class MOSMCPServer:
135
+ """MCP Server that accepts an existing MOS instance."""
136
+
137
+ def __init__(self, mos_instance: MOS | None = None):
138
+ self.mcp = FastMCP("MOS Memory System")
139
+ if mos_instance is None:
140
+ # Fall back to creating from default config
141
+ config, cube = load_default_config()
142
+ self.mos_core = MOS(config=config)
143
+ self.mos_core.register_mem_cube(cube)
144
+ else:
145
+ self.mos_core = mos_instance
146
+ self._setup_tools()
147
+
148
+ def _setup_tools(self):
149
+ """Setup MCP tools"""
150
+
151
+ @self.mcp.tool()
152
+ async def chat(query: str, user_id: str | None = None) -> str:
153
+ """
154
+ Chat with MOS system using memory-enhanced responses.
155
+
156
+ This method provides intelligent responses by searching through user's memory cubes
157
+ and incorporating relevant context. It supports both standard chat mode and enhanced
158
+ Chain of Thought (CoT) mode for complex queries when PRO_MODE is enabled.
159
+
160
+ Args:
161
+ query (str): The user's query or question to be answered
162
+ user_id (str, optional): User ID for the chat session. If not provided, uses the default user
163
+
164
+ Returns:
165
+ str: AI-generated response incorporating relevant memories and context
166
+ """
167
+ try:
168
+ response = self.mos_core.chat(query, user_id)
169
+ return response
170
+ except Exception as e:
171
+ import traceback
172
+
173
+ error_details = traceback.format_exc()
174
+ return f"Chat error: {e!s}\nTraceback:\n{error_details}"
175
+
176
+ @self.mcp.tool()
177
+ async def create_user(
178
+ user_id: str, role: str = "USER", user_name: str | None = None
179
+ ) -> str:
180
+ """
181
+ Create a new user in the MOS system.
182
+
183
+ This method creates a new user account with specified role and name.
184
+ Users can have different access levels and can own or access memory cubes.
185
+
186
+ Args:
187
+ user_id (str): Unique identifier for the user
188
+ role (str): User role - "USER" for regular users, "ADMIN" for administrators
189
+ user_name (str, optional): Display name for the user. If not provided, uses user_id
190
+
191
+ Returns:
192
+ str: Success message with the created user ID
193
+ """
194
+ try:
195
+ user_role = UserRole.ADMIN if role.upper() == "ADMIN" else UserRole.USER
196
+ created_user_id = self.mos_core.create_user(user_id, user_role, user_name)
197
+ return f"User created successfully: {created_user_id}"
198
+ except Exception as e:
199
+ return f"Error creating user: {e!s}"
200
+
201
+ @self.mcp.tool()
202
+ async def create_cube(
203
+ cube_name: str, owner_id: str, cube_path: str | None = None, cube_id: str | None = None
204
+ ) -> str:
205
+ """
206
+ Create a new memory cube for a user.
207
+
208
+ Memory cubes are containers that store different types of memories (textual, activation, parametric).
209
+ Each cube can be owned by a user and shared with other users.
210
+
211
+ Args:
212
+ cube_name (str): Human-readable name for the memory cube
213
+ owner_id (str): User ID of the cube owner who has full control
214
+ cube_path (str, optional): File system path where cube data will be stored
215
+ cube_id (str, optional): Custom unique identifier for the cube. If not provided, one will be generated
216
+
217
+ Returns:
218
+ str: Success message with the created cube ID
219
+ """
220
+ try:
221
+ created_cube_id = self.mos_core.create_cube_for_user(
222
+ cube_name, owner_id, cube_path, cube_id
223
+ )
224
+ return f"Cube created successfully: {created_cube_id}"
225
+ except Exception as e:
226
+ return f"Error creating cube: {e!s}"
227
+
228
+ @self.mcp.tool()
229
+ async def register_cube(
230
+ cube_name_or_path: str, cube_id: str | None = None, user_id: str | None = None
231
+ ) -> str:
232
+ """
233
+ Register an existing memory cube with the MOS system.
234
+
235
+ This method loads and registers a memory cube from a file path or creates a new one
236
+ if the path doesn't exist. The cube becomes available for memory operations.
237
+
238
+ Args:
239
+ cube_name_or_path (str): File path to the memory cube or name for a new cube
240
+ cube_id (str, optional): Custom identifier for the cube. If not provided, one will be generated
241
+ user_id (str, optional): User ID to associate with the cube. If not provided, uses default user
242
+
243
+ Returns:
244
+ str: Success message with the registered cube ID
245
+ """
246
+ try:
247
+ if not os.path.exists(cube_name_or_path):
248
+ _, cube = load_default_config(user_id=user_id)
249
+ cube_to_register = cube
250
+ else:
251
+ cube_to_register = cube_name_or_path
252
+ self.mos_core.register_mem_cube(
253
+ cube_to_register, mem_cube_id=cube_id, user_id=user_id
254
+ )
255
+ return f"Cube registered successfully: {cube_id or cube_to_register}"
256
+ except Exception as e:
257
+ return f"Error registering cube: {e!s}"
258
+
259
+ @self.mcp.tool()
260
+ async def unregister_cube(cube_id: str, user_id: str | None = None) -> str:
261
+ """
262
+ Unregister a memory cube from the MOS system.
263
+
264
+ This method removes a memory cube from the active session, making it unavailable
265
+ for memory operations. The cube data remains intact on disk.
266
+
267
+ Args:
268
+ cube_id (str): Unique identifier of the cube to unregister
269
+ user_id (str, optional): User ID for access validation. If not provided, uses default user
270
+
271
+ Returns:
272
+ str: Success message confirming the cube was unregistered
273
+ """
274
+ try:
275
+ self.mos_core.unregister_mem_cube(cube_id, user_id)
276
+ return f"Cube unregistered successfully: {cube_id}"
277
+ except Exception as e:
278
+ return f"Error unregistering cube: {e!s}"
279
+
280
+ @self.mcp.tool()
281
+ async def search_memories(
282
+ query: str, user_id: str | None = None, cube_ids: list[str] | None = None
283
+ ) -> dict[str, Any]:
284
+ """
285
+ Search for memories across user's accessible memory cubes.
286
+
287
+ This method performs semantic search through textual memories stored in the specified
288
+ cubes, returning relevant memories based on the query. Results are ranked by relevance.
289
+
290
+ Args:
291
+ query (str): Search query to find relevant memories
292
+ user_id (str, optional): User ID whose cubes to search. If not provided, uses default user
293
+ cube_ids (list[str], optional): Specific cube IDs to search. If not provided, searches all user's cubes
294
+
295
+ Returns:
296
+ dict: Search results containing text_mem, act_mem, and para_mem categories with relevant memories
297
+ """
298
+ try:
299
+ result = self.mos_core.search(query, user_id, cube_ids)
300
+ return result
301
+ except Exception as e:
302
+ import traceback
303
+
304
+ error_details = traceback.format_exc()
305
+ return {"error": str(e), "traceback": error_details}
306
+
307
+ @self.mcp.tool()
308
+ async def add_memory(
309
+ memory_content: str | None = None,
310
+ doc_path: str | None = None,
311
+ messages: list[dict[str, str]] | None = None,
312
+ cube_id: str | None = None,
313
+ user_id: str | None = None,
314
+ ) -> str:
315
+ """
316
+ Add memories to a memory cube.
317
+
318
+ This method can add memories from different sources: direct text content, document files,
319
+ or conversation messages. The memories are processed and stored in the specified cube.
320
+
321
+ Args:
322
+ memory_content (str, optional): Direct text content to add as memory
323
+ doc_path (str, optional): Path to a document file to process and add as memories
324
+ messages (list[dict[str, str]], optional): List of conversation messages to add as memories
325
+ cube_id (str, optional): Target cube ID. If not provided, uses user's default cube
326
+ user_id (str, optional): User ID for access validation. If not provided, uses default user
327
+
328
+ Returns:
329
+ str: Success message confirming memories were added
330
+ """
331
+ try:
332
+ self.mos_core.add(
333
+ messages=messages,
334
+ memory_content=memory_content,
335
+ doc_path=doc_path,
336
+ mem_cube_id=cube_id,
337
+ user_id=user_id,
338
+ )
339
+ return "Memory added successfully"
340
+ except Exception as e:
341
+ return f"Error adding memory: {e!s}"
342
+
343
+ @self.mcp.tool()
344
+ async def get_memory(
345
+ cube_id: str, memory_id: str, user_id: str | None = None
346
+ ) -> dict[str, Any]:
347
+ """
348
+ Retrieve a specific memory from a memory cube.
349
+
350
+ This method fetches a single memory item by its unique identifier from the specified cube.
351
+
352
+ Args:
353
+ cube_id (str): Unique identifier of the cube containing the memory
354
+ memory_id (str): Unique identifier of the specific memory to retrieve
355
+ user_id (str, optional): User ID for access validation. If not provided, uses default user
356
+
357
+ Returns:
358
+ dict: Memory content with metadata including memory text, creation time, and source
359
+ """
360
+ try:
361
+ memory = self.mos_core.get(cube_id, memory_id, user_id)
362
+ return {"memory": str(memory)}
363
+ except Exception as e:
364
+ return {"error": str(e)}
365
+
366
+ @self.mcp.tool()
367
+ async def update_memory(
368
+ cube_id: str, memory_id: str, memory_content: str, user_id: str | None = None
369
+ ) -> str:
370
+ """
371
+ Update an existing memory in a memory cube.
372
+
373
+ This method modifies the content of a specific memory while preserving its metadata.
374
+ Note: Update functionality may not be supported by all memory backends (e.g., tree_text).
375
+
376
+ Args:
377
+ cube_id (str): Unique identifier of the cube containing the memory
378
+ memory_id (str): Unique identifier of the memory to update
379
+ memory_content (str): New content to replace the existing memory
380
+ user_id (str, optional): User ID for access validation. If not provided, uses default user
381
+
382
+ Returns:
383
+ str: Success message confirming the memory was updated
384
+ """
385
+ try:
386
+ from memos.memories.textual.item import TextualMemoryItem, TextualMemoryMetadata
387
+
388
+ metadata = TextualMemoryMetadata(
389
+ user_id=user_id or self.mos_core.user_id,
390
+ session_id=self.mos_core.session_id,
391
+ source="mcp_update",
392
+ )
393
+ memory_item = TextualMemoryItem(memory=memory_content, metadata=metadata)
394
+
395
+ self.mos_core.update(cube_id, memory_id, memory_item, user_id)
396
+ return f"Memory updated successfully: {memory_id}"
397
+ except Exception as e:
398
+ return f"Error updating memory: {e!s}"
399
+
400
+ @self.mcp.tool()
401
+ async def delete_memory(cube_id: str, memory_id: str, user_id: str | None = None) -> str:
402
+ """
403
+ Delete a specific memory from a memory cube.
404
+
405
+ This method permanently removes a memory item from the specified cube.
406
+ The operation cannot be undone.
407
+
408
+ Args:
409
+ cube_id (str): Unique identifier of the cube containing the memory
410
+ memory_id (str): Unique identifier of the memory to delete
411
+ user_id (str, optional): User ID for access validation. If not provided, uses default user
412
+
413
+ Returns:
414
+ str: Success message confirming the memory was deleted
415
+ """
416
+ try:
417
+ self.mos_core.delete(cube_id, memory_id, user_id)
418
+ return f"Memory deleted successfully: {memory_id}"
419
+ except Exception as e:
420
+ return f"Error deleting memory: {e!s}"
421
+
422
+ @self.mcp.tool()
423
+ async def delete_all_memories(cube_id: str, user_id: str | None = None) -> str:
424
+ """
425
+ Delete all memories from a memory cube.
426
+
427
+ This method permanently removes all memory items from the specified cube.
428
+ The operation cannot be undone and will clear all textual memories.
429
+
430
+ Args:
431
+ cube_id (str): Unique identifier of the cube to clear
432
+ user_id (str, optional): User ID for access validation. If not provided, uses default user
433
+
434
+ Returns:
435
+ str: Success message confirming all memories were deleted
436
+ """
437
+ try:
438
+ self.mos_core.delete_all(cube_id, user_id)
439
+ return f"All memories deleted successfully from cube: {cube_id}"
440
+ except Exception as e:
441
+ return f"Error deleting all memories: {e!s}"
442
+
443
+ @self.mcp.tool()
444
+ async def clear_chat_history(user_id: str | None = None) -> str:
445
+ """
446
+ Clear the chat history for a user.
447
+
448
+ This method resets the conversation history, removing all previous messages
449
+ while keeping the memory cubes and stored memories intact.
450
+
451
+ Args:
452
+ user_id (str, optional): User ID whose chat history to clear. If not provided, uses default user
453
+
454
+ Returns:
455
+ str: Success message confirming chat history was cleared
456
+ """
457
+ try:
458
+ self.mos_core.clear_messages(user_id)
459
+ target_user = user_id or self.mos_core.user_id
460
+ return f"Chat history cleared for user: {target_user}"
461
+ except Exception as e:
462
+ return f"Error clearing chat history: {e!s}"
463
+
464
+ @self.mcp.tool()
465
+ async def dump_cube(
466
+ dump_dir: str, user_id: str | None = None, cube_id: str | None = None
467
+ ) -> str:
468
+ """
469
+ Export a memory cube to a directory.
470
+
471
+ This method creates a backup or export of a memory cube, including all memories
472
+ and metadata, to the specified directory for backup or migration purposes.
473
+
474
+ Args:
475
+ dump_dir (str): Directory path where the cube data will be exported
476
+ user_id (str, optional): User ID for access validation. If not provided, uses default user
477
+ cube_id (str, optional): Cube ID to export. If not provided, uses user's default cube
478
+
479
+ Returns:
480
+ str: Success message with the export directory path
481
+ """
482
+ try:
483
+ self.mos_core.dump(dump_dir, user_id, cube_id)
484
+ return f"Cube dumped successfully to: {dump_dir}"
485
+ except Exception as e:
486
+ return f"Error dumping cube: {e!s}"
487
+
488
+ @self.mcp.tool()
489
+ async def share_cube(cube_id: str, target_user_id: str) -> str:
490
+ """
491
+ Share a memory cube with another user.
492
+
493
+ This method grants access to a memory cube to another user, allowing them
494
+ to read and search through the memories stored in that cube.
495
+
496
+ Args:
497
+ cube_id (str): Unique identifier of the cube to share
498
+ target_user_id (str): User ID of the person to share the cube with
499
+
500
+ Returns:
501
+ str: Success message confirming the cube was shared or error message if failed
502
+ """
503
+ try:
504
+ success = self.mos_core.share_cube_with_user(cube_id, target_user_id)
505
+ if success:
506
+ return f"Cube {cube_id} shared successfully with user {target_user_id}"
507
+ else:
508
+ return f"Failed to share cube {cube_id} with user {target_user_id}"
509
+ except Exception as e:
510
+ return f"Error sharing cube: {e!s}"
511
+
512
+ @self.mcp.tool()
513
+ async def get_user_info(user_id: str | None = None) -> dict[str, Any]:
514
+ """
515
+ Get detailed information about a user and their accessible memory cubes.
516
+
517
+ This method returns comprehensive user information including profile details,
518
+ role, creation time, and a list of all memory cubes the user can access.
519
+
520
+ Args:
521
+ user_id (str, optional): User ID to get information for. If not provided, uses current user
522
+
523
+ Returns:
524
+ dict: User information including user_id, user_name, role, created_at, and accessible_cubes
525
+ """
526
+ try:
527
+ if user_id and user_id != self.mos_core.user_id:
528
+ # Temporarily switch user
529
+ original_user = self.mos_core.user_id
530
+ self.mos_core.user_id = user_id
531
+ user_info = self.mos_core.get_user_info()
532
+ self.mos_core.user_id = original_user
533
+ return user_info
534
+ else:
535
+ return self.mos_core.get_user_info()
536
+ except Exception as e:
537
+ return {"error": str(e)}
538
+
539
+ @self.mcp.tool()
540
+ async def control_memory_scheduler(action: str) -> str:
541
+ """
542
+ Control the memory scheduler service.
543
+
544
+ The memory scheduler is responsible for processing and organizing memories
545
+ in the background. This method allows starting or stopping the scheduler service.
546
+
547
+ Args:
548
+ action (str): Action to perform - "start" to enable the scheduler, "stop" to disable it
549
+
550
+ Returns:
551
+ str: Success message confirming the scheduler action or error message if failed
552
+ """
553
+ try:
554
+ if action.lower() == "start":
555
+ success = self.mos_core.mem_scheduler_on()
556
+ return (
557
+ "Memory scheduler started"
558
+ if success
559
+ else "Failed to start memory scheduler"
560
+ )
561
+ elif action.lower() == "stop":
562
+ success = self.mos_core.mem_scheduler_off()
563
+ return (
564
+ "Memory scheduler stopped" if success else "Failed to stop memory scheduler"
565
+ )
566
+ else:
567
+ return "Invalid action. Use 'start' or 'stop'"
568
+ except Exception as e:
569
+ return f"Error controlling memory scheduler: {e!s}"
570
+
571
+
572
+ def _run_mcp(self, transport: str = "stdio", **kwargs):
573
+ if transport == "stdio":
574
+ self.mcp.run(transport="stdio")
575
+ elif transport == "http":
576
+ host = kwargs.get("host", "localhost")
577
+ port = kwargs.get("port", 8000)
578
+ asyncio.run(self.mcp.run_http_async(host=host, port=port))
579
+ elif transport == "sse":
580
+ host = kwargs.get("host", "localhost")
581
+ port = kwargs.get("port", 8000)
582
+ self.mcp.run(transport="sse", host=host, port=port)
583
+ else:
584
+ raise ValueError(f"Unsupported transport: {transport}")
585
+
586
+
587
+ MOSMCPStdioServer.run = _run_mcp
588
+ MOSMCPServer.run = _run_mcp
589
+
590
+
591
+ # Usage example
592
+ if __name__ == "__main__":
593
+ import argparse
594
+
595
+ from dotenv import load_dotenv
596
+
597
+ load_dotenv()
598
+
599
+ # Parse command line arguments
600
+ parser = argparse.ArgumentParser(description="MOS MCP Server")
601
+ parser.add_argument(
602
+ "--transport",
603
+ choices=["stdio", "http", "sse"],
604
+ default="stdio",
605
+ help="Transport method (default: stdio)",
606
+ )
607
+ parser.add_argument("--host", default="localhost", help="Host for HTTP/SSE transport")
608
+ parser.add_argument("--port", type=int, default=8000, help="Port for HTTP/SSE transport")
609
+
610
+ args = parser.parse_args()
611
+
612
+ # Create and run MCP server
613
+ server = MOSMCPStdioServer()
614
+ server.run(transport=args.transport, host=args.host, port=args.port)