MemoryOS 0.2.0__py3-none-any.whl → 0.2.2__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.

Potentially problematic release.


This version of MemoryOS might be problematic. Click here for more details.

Files changed (114) hide show
  1. {memoryos-0.2.0.dist-info → memoryos-0.2.2.dist-info}/METADATA +67 -26
  2. memoryos-0.2.2.dist-info/RECORD +169 -0
  3. memoryos-0.2.2.dist-info/entry_points.txt +3 -0
  4. memos/__init__.py +1 -1
  5. memos/api/config.py +562 -0
  6. memos/api/context/context.py +147 -0
  7. memos/api/context/dependencies.py +90 -0
  8. memos/api/exceptions.py +28 -0
  9. memos/api/mcp_serve.py +502 -0
  10. memos/api/product_api.py +35 -0
  11. memos/api/product_models.py +163 -0
  12. memos/api/routers/__init__.py +1 -0
  13. memos/api/routers/product_router.py +386 -0
  14. memos/chunkers/sentence_chunker.py +8 -2
  15. memos/cli.py +113 -0
  16. memos/configs/embedder.py +27 -0
  17. memos/configs/graph_db.py +132 -3
  18. memos/configs/internet_retriever.py +6 -0
  19. memos/configs/llm.py +47 -0
  20. memos/configs/mem_cube.py +1 -1
  21. memos/configs/mem_os.py +5 -0
  22. memos/configs/mem_reader.py +9 -0
  23. memos/configs/mem_scheduler.py +107 -7
  24. memos/configs/mem_user.py +58 -0
  25. memos/configs/memory.py +5 -4
  26. memos/dependency.py +52 -0
  27. memos/embedders/ark.py +92 -0
  28. memos/embedders/factory.py +4 -0
  29. memos/embedders/sentence_transformer.py +8 -2
  30. memos/embedders/universal_api.py +32 -0
  31. memos/graph_dbs/base.py +11 -3
  32. memos/graph_dbs/factory.py +4 -0
  33. memos/graph_dbs/nebular.py +1364 -0
  34. memos/graph_dbs/neo4j.py +333 -124
  35. memos/graph_dbs/neo4j_community.py +300 -0
  36. memos/llms/base.py +9 -0
  37. memos/llms/deepseek.py +54 -0
  38. memos/llms/factory.py +10 -1
  39. memos/llms/hf.py +170 -13
  40. memos/llms/hf_singleton.py +114 -0
  41. memos/llms/ollama.py +4 -0
  42. memos/llms/openai.py +67 -1
  43. memos/llms/qwen.py +63 -0
  44. memos/llms/vllm.py +153 -0
  45. memos/log.py +1 -1
  46. memos/mem_cube/general.py +77 -16
  47. memos/mem_cube/utils.py +109 -0
  48. memos/mem_os/core.py +251 -51
  49. memos/mem_os/main.py +94 -12
  50. memos/mem_os/product.py +1220 -43
  51. memos/mem_os/utils/default_config.py +352 -0
  52. memos/mem_os/utils/format_utils.py +1401 -0
  53. memos/mem_reader/simple_struct.py +18 -10
  54. memos/mem_scheduler/base_scheduler.py +441 -40
  55. memos/mem_scheduler/general_scheduler.py +249 -248
  56. memos/mem_scheduler/modules/base.py +14 -5
  57. memos/mem_scheduler/modules/dispatcher.py +67 -4
  58. memos/mem_scheduler/modules/misc.py +104 -0
  59. memos/mem_scheduler/modules/monitor.py +240 -50
  60. memos/mem_scheduler/modules/rabbitmq_service.py +319 -0
  61. memos/mem_scheduler/modules/redis_service.py +32 -22
  62. memos/mem_scheduler/modules/retriever.py +167 -23
  63. memos/mem_scheduler/modules/scheduler_logger.py +255 -0
  64. memos/mem_scheduler/mos_for_test_scheduler.py +140 -0
  65. memos/mem_scheduler/schemas/__init__.py +0 -0
  66. memos/mem_scheduler/schemas/general_schemas.py +43 -0
  67. memos/mem_scheduler/{modules/schemas.py → schemas/message_schemas.py} +63 -61
  68. memos/mem_scheduler/schemas/monitor_schemas.py +329 -0
  69. memos/mem_scheduler/utils/__init__.py +0 -0
  70. memos/mem_scheduler/utils/filter_utils.py +176 -0
  71. memos/mem_scheduler/utils/misc_utils.py +61 -0
  72. memos/mem_user/factory.py +94 -0
  73. memos/mem_user/mysql_persistent_user_manager.py +271 -0
  74. memos/mem_user/mysql_user_manager.py +500 -0
  75. memos/mem_user/persistent_factory.py +96 -0
  76. memos/mem_user/persistent_user_manager.py +260 -0
  77. memos/mem_user/user_manager.py +4 -4
  78. memos/memories/activation/item.py +29 -0
  79. memos/memories/activation/kv.py +10 -3
  80. memos/memories/activation/vllmkv.py +219 -0
  81. memos/memories/factory.py +2 -0
  82. memos/memories/textual/base.py +1 -1
  83. memos/memories/textual/general.py +43 -97
  84. memos/memories/textual/item.py +5 -33
  85. memos/memories/textual/tree.py +22 -12
  86. memos/memories/textual/tree_text_memory/organize/conflict.py +9 -5
  87. memos/memories/textual/tree_text_memory/organize/manager.py +26 -18
  88. memos/memories/textual/tree_text_memory/organize/redundancy.py +25 -44
  89. memos/memories/textual/tree_text_memory/organize/relation_reason_detector.py +50 -48
  90. memos/memories/textual/tree_text_memory/organize/reorganizer.py +81 -56
  91. memos/memories/textual/tree_text_memory/retrieve/internet_retriever.py +6 -3
  92. memos/memories/textual/tree_text_memory/retrieve/internet_retriever_factory.py +2 -0
  93. memos/memories/textual/tree_text_memory/retrieve/recall.py +0 -1
  94. memos/memories/textual/tree_text_memory/retrieve/reranker.py +2 -2
  95. memos/memories/textual/tree_text_memory/retrieve/retrieval_mid_structs.py +2 -0
  96. memos/memories/textual/tree_text_memory/retrieve/searcher.py +52 -28
  97. memos/memories/textual/tree_text_memory/retrieve/task_goal_parser.py +42 -15
  98. memos/memories/textual/tree_text_memory/retrieve/utils.py +11 -7
  99. memos/memories/textual/tree_text_memory/retrieve/xinyusearch.py +62 -58
  100. memos/memos_tools/dinding_report_bot.py +422 -0
  101. memos/memos_tools/notification_service.py +44 -0
  102. memos/memos_tools/notification_utils.py +96 -0
  103. memos/parsers/markitdown.py +8 -2
  104. memos/settings.py +3 -1
  105. memos/templates/mem_reader_prompts.py +66 -23
  106. memos/templates/mem_scheduler_prompts.py +126 -43
  107. memos/templates/mos_prompts.py +87 -0
  108. memos/templates/tree_reorganize_prompts.py +85 -30
  109. memos/vec_dbs/base.py +12 -0
  110. memos/vec_dbs/qdrant.py +46 -20
  111. memoryos-0.2.0.dist-info/RECORD +0 -128
  112. memos/mem_scheduler/utils.py +0 -26
  113. {memoryos-0.2.0.dist-info → memoryos-0.2.2.dist-info}/LICENSE +0 -0
  114. {memoryos-0.2.0.dist-info → memoryos-0.2.2.dist-info}/WHEEL +0 -0
memos/api/mcp_serve.py ADDED
@@ -0,0 +1,502 @@
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
+ config, cube = get_default(
20
+ openai_api_key=os.getenv("OPENAI_API_KEY"),
21
+ openai_api_base=os.getenv("OPENAI_API_BASE"),
22
+ text_mem_type=os.getenv("MOS_TEXT_MEM_TYPE"),
23
+ user_id=user_id,
24
+ neo4j_uri=os.getenv("NEO4J_URI"),
25
+ neo4j_user=os.getenv("NEO4J_USER"),
26
+ neo4j_password=os.getenv("NEO4J_PASSWORD"),
27
+ )
28
+ return config, cube
29
+
30
+
31
+ class MOSMCPStdioServer:
32
+ def __init__(self):
33
+ self.mcp = FastMCP("MOS Memory System")
34
+ config, cube = load_default_config()
35
+ self.mos_core = MOS(config=config)
36
+ self._setup_tools()
37
+
38
+ def _setup_tools(self):
39
+ """Setup MCP tools"""
40
+
41
+ @self.mcp.tool()
42
+ async def chat(query: str, user_id: str | None = None) -> str:
43
+ """
44
+ Chat with MOS system using memory-enhanced responses.
45
+
46
+ This method provides intelligent responses by searching through user's memory cubes
47
+ and incorporating relevant context. It supports both standard chat mode and enhanced
48
+ Chain of Thought (CoT) mode for complex queries when PRO_MODE is enabled.
49
+
50
+ Args:
51
+ query (str): The user's query or question to be answered
52
+ user_id (str, optional): User ID for the chat session. If not provided, uses the default user
53
+
54
+ Returns:
55
+ str: AI-generated response incorporating relevant memories and context
56
+ """
57
+ try:
58
+ response = self.mos_core.chat(query, user_id)
59
+ return response
60
+ except Exception as e:
61
+ return f"Chat error: {e!s}"
62
+
63
+ @self.mcp.tool()
64
+ async def create_user(
65
+ user_id: str, role: str = "USER", user_name: str | None = None
66
+ ) -> str:
67
+ """
68
+ Create a new user in the MOS system.
69
+
70
+ This method creates a new user account with specified role and name.
71
+ Users can have different access levels and can own or access memory cubes.
72
+
73
+ Args:
74
+ user_id (str): Unique identifier for the user
75
+ role (str): User role - "USER" for regular users, "ADMIN" for administrators
76
+ user_name (str, optional): Display name for the user. If not provided, uses user_id
77
+
78
+ Returns:
79
+ str: Success message with the created user ID
80
+ """
81
+ try:
82
+ user_role = UserRole.ADMIN if role.upper() == "ADMIN" else UserRole.USER
83
+ created_user_id = self.mos_core.create_user(user_id, user_role, user_name)
84
+ return f"User created successfully: {created_user_id}"
85
+ except Exception as e:
86
+ return f"Error creating user: {e!s}"
87
+
88
+ @self.mcp.tool()
89
+ async def create_cube(
90
+ cube_name: str, owner_id: str, cube_path: str | None = None, cube_id: str | None = None
91
+ ) -> str:
92
+ """
93
+ Create a new memory cube for a user.
94
+
95
+ Memory cubes are containers that store different types of memories (textual, activation, parametric).
96
+ Each cube can be owned by a user and shared with other users.
97
+
98
+ Args:
99
+ cube_name (str): Human-readable name for the memory cube
100
+ owner_id (str): User ID of the cube owner who has full control
101
+ cube_path (str, optional): File system path where cube data will be stored
102
+ cube_id (str, optional): Custom unique identifier for the cube. If not provided, one will be generated
103
+
104
+ Returns:
105
+ str: Success message with the created cube ID
106
+ """
107
+ try:
108
+ created_cube_id = self.mos_core.create_cube_for_user(
109
+ cube_name, owner_id, cube_path, cube_id
110
+ )
111
+ return f"Cube created successfully: {created_cube_id}"
112
+ except Exception as e:
113
+ return f"Error creating cube: {e!s}"
114
+
115
+ @self.mcp.tool()
116
+ async def register_cube(
117
+ cube_name_or_path: str, cube_id: str | None = None, user_id: str | None = None
118
+ ) -> str:
119
+ """
120
+ Register an existing memory cube with the MOS system.
121
+
122
+ This method loads and registers a memory cube from a file path or creates a new one
123
+ if the path doesn't exist. The cube becomes available for memory operations.
124
+
125
+ Args:
126
+ cube_name_or_path (str): File path to the memory cube or name for a new cube
127
+ cube_id (str, optional): Custom identifier for the cube. If not provided, one will be generated
128
+ user_id (str, optional): User ID to associate with the cube. If not provided, uses default user
129
+
130
+ Returns:
131
+ str: Success message with the registered cube ID
132
+ """
133
+ try:
134
+ if not os.path.exists(cube_name_or_path):
135
+ mos_config, cube_name_or_path = load_default_config(user_id=user_id)
136
+ self.mos_core.register_mem_cube(
137
+ cube_name_or_path, mem_cube_id=cube_id, user_id=user_id
138
+ )
139
+ return f"Cube registered successfully: {cube_id or cube_name_or_path}"
140
+ except Exception as e:
141
+ return f"Error registering cube: {e!s}"
142
+
143
+ @self.mcp.tool()
144
+ async def unregister_cube(cube_id: str, user_id: str | None = None) -> str:
145
+ """
146
+ Unregister a memory cube from the MOS system.
147
+
148
+ This method removes a memory cube from the active session, making it unavailable
149
+ for memory operations. The cube data remains intact on disk.
150
+
151
+ Args:
152
+ cube_id (str): Unique identifier of the cube to unregister
153
+ user_id (str, optional): User ID for access validation. If not provided, uses default user
154
+
155
+ Returns:
156
+ str: Success message confirming the cube was unregistered
157
+ """
158
+ try:
159
+ self.mos_core.unregister_mem_cube(cube_id, user_id)
160
+ return f"Cube unregistered successfully: {cube_id}"
161
+ except Exception as e:
162
+ return f"Error unregistering cube: {e!s}"
163
+
164
+ @self.mcp.tool()
165
+ async def search_memories(
166
+ query: str, user_id: str | None = None, cube_ids: list[str] | None = None
167
+ ) -> dict[str, Any]:
168
+ """
169
+ Search for memories across user's accessible memory cubes.
170
+
171
+ This method performs semantic search through textual memories stored in the specified
172
+ cubes, returning relevant memories based on the query. Results are ranked by relevance.
173
+
174
+ Args:
175
+ query (str): Search query to find relevant memories
176
+ user_id (str, optional): User ID whose cubes to search. If not provided, uses default user
177
+ cube_ids (list[str], optional): Specific cube IDs to search. If not provided, searches all user's cubes
178
+
179
+ Returns:
180
+ dict: Search results containing text_mem, act_mem, and para_mem categories with relevant memories
181
+ """
182
+ try:
183
+ result = self.mos_core.search(query, user_id, cube_ids)
184
+ return result
185
+ except Exception as e:
186
+ return {"error": str(e)}
187
+
188
+ @self.mcp.tool()
189
+ async def add_memory(
190
+ memory_content: str | None = None,
191
+ doc_path: str | None = None,
192
+ messages: list[dict[str, str]] | None = None,
193
+ cube_id: str | None = None,
194
+ user_id: str | None = None,
195
+ ) -> str:
196
+ """
197
+ Add memories to a memory cube.
198
+
199
+ This method can add memories from different sources: direct text content, document files,
200
+ or conversation messages. The memories are processed and stored in the specified cube.
201
+
202
+ Args:
203
+ memory_content (str, optional): Direct text content to add as memory
204
+ doc_path (str, optional): Path to a document file to process and add as memories
205
+ messages (list[dict[str, str]], optional): List of conversation messages to add as memories
206
+ cube_id (str, optional): Target cube ID. If not provided, uses user's default cube
207
+ user_id (str, optional): User ID for access validation. If not provided, uses default user
208
+
209
+ Returns:
210
+ str: Success message confirming memories were added
211
+ """
212
+ try:
213
+ self.mos_core.add(
214
+ messages=messages,
215
+ memory_content=memory_content,
216
+ doc_path=doc_path,
217
+ mem_cube_id=cube_id,
218
+ user_id=user_id,
219
+ )
220
+ return "Memory added successfully"
221
+ except Exception as e:
222
+ return f"Error adding memory: {e!s}"
223
+
224
+ @self.mcp.tool()
225
+ async def get_memory(
226
+ cube_id: str, memory_id: str, user_id: str | None = None
227
+ ) -> dict[str, Any]:
228
+ """
229
+ Retrieve a specific memory from a memory cube.
230
+
231
+ This method fetches a single memory item by its unique identifier from the specified cube.
232
+
233
+ Args:
234
+ cube_id (str): Unique identifier of the cube containing the memory
235
+ memory_id (str): Unique identifier of the specific memory to retrieve
236
+ user_id (str, optional): User ID for access validation. If not provided, uses default user
237
+
238
+ Returns:
239
+ dict: Memory content with metadata including memory text, creation time, and source
240
+ """
241
+ try:
242
+ memory = self.mos_core.get(cube_id, memory_id, user_id)
243
+ return {"memory": str(memory)}
244
+ except Exception as e:
245
+ return {"error": str(e)}
246
+
247
+ @self.mcp.tool()
248
+ async def update_memory(
249
+ cube_id: str, memory_id: str, memory_content: str, user_id: str | None = None
250
+ ) -> str:
251
+ """
252
+ Update an existing memory in a memory cube.
253
+
254
+ This method modifies the content of a specific memory while preserving its metadata.
255
+ Note: Update functionality may not be supported by all memory backends (e.g., tree_text).
256
+
257
+ Args:
258
+ cube_id (str): Unique identifier of the cube containing the memory
259
+ memory_id (str): Unique identifier of the memory to update
260
+ memory_content (str): New content to replace the existing memory
261
+ user_id (str, optional): User ID for access validation. If not provided, uses default user
262
+
263
+ Returns:
264
+ str: Success message confirming the memory was updated
265
+ """
266
+ try:
267
+ from memos.memories.textual.item import TextualMemoryItem, TextualMemoryMetadata
268
+
269
+ metadata = TextualMemoryMetadata(
270
+ user_id=user_id or self.mos_core.user_id,
271
+ session_id=self.mos_core.session_id,
272
+ source="mcp_update",
273
+ )
274
+ memory_item = TextualMemoryItem(memory=memory_content, metadata=metadata)
275
+
276
+ self.mos_core.update(cube_id, memory_id, memory_item, user_id)
277
+ return f"Memory updated successfully: {memory_id}"
278
+ except Exception as e:
279
+ return f"Error updating memory: {e!s}"
280
+
281
+ @self.mcp.tool()
282
+ async def delete_memory(cube_id: str, memory_id: str, user_id: str | None = None) -> str:
283
+ """
284
+ Delete a specific memory from a memory cube.
285
+
286
+ This method permanently removes a memory item from the specified cube.
287
+ The operation cannot be undone.
288
+
289
+ Args:
290
+ cube_id (str): Unique identifier of the cube containing the memory
291
+ memory_id (str): Unique identifier of the memory to delete
292
+ user_id (str, optional): User ID for access validation. If not provided, uses default user
293
+
294
+ Returns:
295
+ str: Success message confirming the memory was deleted
296
+ """
297
+ try:
298
+ self.mos_core.delete(cube_id, memory_id, user_id)
299
+ return f"Memory deleted successfully: {memory_id}"
300
+ except Exception as e:
301
+ return f"Error deleting memory: {e!s}"
302
+
303
+ @self.mcp.tool()
304
+ async def delete_all_memories(cube_id: str, user_id: str | None = None) -> str:
305
+ """
306
+ Delete all memories from a memory cube.
307
+
308
+ This method permanently removes all memory items from the specified cube.
309
+ The operation cannot be undone and will clear all textual memories.
310
+
311
+ Args:
312
+ cube_id (str): Unique identifier of the cube to clear
313
+ user_id (str, optional): User ID for access validation. If not provided, uses default user
314
+
315
+ Returns:
316
+ str: Success message confirming all memories were deleted
317
+ """
318
+ try:
319
+ self.mos_core.delete_all(cube_id, user_id)
320
+ return f"All memories deleted successfully from cube: {cube_id}"
321
+ except Exception as e:
322
+ return f"Error deleting all memories: {e!s}"
323
+
324
+ @self.mcp.tool()
325
+ async def clear_chat_history(user_id: str | None = None) -> str:
326
+ """
327
+ Clear the chat history for a user.
328
+
329
+ This method resets the conversation history, removing all previous messages
330
+ while keeping the memory cubes and stored memories intact.
331
+
332
+ Args:
333
+ user_id (str, optional): User ID whose chat history to clear. If not provided, uses default user
334
+
335
+ Returns:
336
+ str: Success message confirming chat history was cleared
337
+ """
338
+ try:
339
+ self.mos_core.clear_messages(user_id)
340
+ target_user = user_id or self.mos_core.user_id
341
+ return f"Chat history cleared for user: {target_user}"
342
+ except Exception as e:
343
+ return f"Error clearing chat history: {e!s}"
344
+
345
+ @self.mcp.tool()
346
+ async def dump_cube(
347
+ dump_dir: str, user_id: str | None = None, cube_id: str | None = None
348
+ ) -> str:
349
+ """
350
+ Export a memory cube to a directory.
351
+
352
+ This method creates a backup or export of a memory cube, including all memories
353
+ and metadata, to the specified directory for backup or migration purposes.
354
+
355
+ Args:
356
+ dump_dir (str): Directory path where the cube data will be exported
357
+ user_id (str, optional): User ID for access validation. If not provided, uses default user
358
+ cube_id (str, optional): Cube ID to export. If not provided, uses user's default cube
359
+
360
+ Returns:
361
+ str: Success message with the export directory path
362
+ """
363
+ try:
364
+ self.mos_core.dump(dump_dir, user_id, cube_id)
365
+ return f"Cube dumped successfully to: {dump_dir}"
366
+ except Exception as e:
367
+ return f"Error dumping cube: {e!s}"
368
+
369
+ @self.mcp.tool()
370
+ async def share_cube(cube_id: str, target_user_id: str) -> str:
371
+ """
372
+ Share a memory cube with another user.
373
+
374
+ This method grants access to a memory cube to another user, allowing them
375
+ to read and search through the memories stored in that cube.
376
+
377
+ Args:
378
+ cube_id (str): Unique identifier of the cube to share
379
+ target_user_id (str): User ID of the person to share the cube with
380
+
381
+ Returns:
382
+ str: Success message confirming the cube was shared or error message if failed
383
+ """
384
+ try:
385
+ success = self.mos_core.share_cube_with_user(cube_id, target_user_id)
386
+ if success:
387
+ return f"Cube {cube_id} shared successfully with user {target_user_id}"
388
+ else:
389
+ return f"Failed to share cube {cube_id} with user {target_user_id}"
390
+ except Exception as e:
391
+ return f"Error sharing cube: {e!s}"
392
+
393
+ @self.mcp.tool()
394
+ async def get_user_info(user_id: str | None = None) -> dict[str, Any]:
395
+ """
396
+ Get detailed information about a user and their accessible memory cubes.
397
+
398
+ This method returns comprehensive user information including profile details,
399
+ role, creation time, and a list of all memory cubes the user can access.
400
+
401
+ Args:
402
+ user_id (str, optional): User ID to get information for. If not provided, uses current user
403
+
404
+ Returns:
405
+ dict: User information including user_id, user_name, role, created_at, and accessible_cubes
406
+ """
407
+ try:
408
+ if user_id and user_id != self.mos_core.user_id:
409
+ # Temporarily switch user
410
+ original_user = self.mos_core.user_id
411
+ self.mos_core.user_id = user_id
412
+ user_info = self.mos_core.get_user_info()
413
+ self.mos_core.user_id = original_user
414
+ return user_info
415
+ else:
416
+ return self.mos_core.get_user_info()
417
+ except Exception as e:
418
+ return {"error": str(e)}
419
+
420
+ @self.mcp.tool()
421
+ async def control_memory_scheduler(action: str) -> str:
422
+ """
423
+ Control the memory scheduler service.
424
+
425
+ The memory scheduler is responsible for processing and organizing memories
426
+ in the background. This method allows starting or stopping the scheduler service.
427
+
428
+ Args:
429
+ action (str): Action to perform - "start" to enable the scheduler, "stop" to disable it
430
+
431
+ Returns:
432
+ str: Success message confirming the scheduler action or error message if failed
433
+ """
434
+ try:
435
+ if action.lower() == "start":
436
+ success = self.mos_core.mem_scheduler_on()
437
+ return (
438
+ "Memory scheduler started"
439
+ if success
440
+ else "Failed to start memory scheduler"
441
+ )
442
+ elif action.lower() == "stop":
443
+ success = self.mos_core.mem_scheduler_off()
444
+ return (
445
+ "Memory scheduler stopped" if success else "Failed to stop memory scheduler"
446
+ )
447
+ else:
448
+ return "Invalid action. Use 'start' or 'stop'"
449
+ except Exception as e:
450
+ return f"Error controlling memory scheduler: {e!s}"
451
+
452
+ def run(self, transport: str = "stdio", **kwargs):
453
+ """Run MCP server with specified transport"""
454
+ if transport == "stdio":
455
+ # Run stdio mode (default for local usage)
456
+ self.mcp.run(transport="stdio")
457
+ elif transport == "http":
458
+ # Run HTTP mode
459
+ host = kwargs.get("host", "localhost")
460
+ port = kwargs.get("port", 8000)
461
+ asyncio.run(self.mcp.run_http_async(host=host, port=port))
462
+ elif transport == "sse":
463
+ # Run SSE mode (deprecated but still supported)
464
+ host = kwargs.get("host", "localhost")
465
+ port = kwargs.get("port", 8000)
466
+ self.mcp.run(transport="sse", host=host, port=port)
467
+ else:
468
+ raise ValueError(f"Unsupported transport: {transport}")
469
+
470
+
471
+ # Usage example
472
+ if __name__ == "__main__":
473
+ import argparse
474
+
475
+ from dotenv import load_dotenv
476
+
477
+ load_dotenv()
478
+
479
+ # Parse command line arguments
480
+ parser = argparse.ArgumentParser(description="MOS MCP Server")
481
+ parser.add_argument(
482
+ "--transport",
483
+ choices=["stdio", "http", "sse"],
484
+ default="stdio",
485
+ help="Transport method (default: stdio)",
486
+ )
487
+ parser.add_argument("--host", default="localhost", help="Host for HTTP/SSE transport")
488
+ parser.add_argument("--port", type=int, default=8000, help="Port for HTTP/SSE transport")
489
+
490
+ args = parser.parse_args()
491
+
492
+ # Set environment variables
493
+ os.environ["OPENAI_API_BASE"] = os.getenv("OPENAI_API_BASE")
494
+ os.environ["OPENAI_API_KEY"] = os.getenv("OPENAI_API_KEY")
495
+ os.environ["MOS_TEXT_MEM_TYPE"] = "tree_text" # "tree_text" need set neo4j
496
+ os.environ["NEO4J_URI"] = os.getenv("NEO4J_URI")
497
+ os.environ["NEO4J_USER"] = os.getenv("NEO4J_USER")
498
+ os.environ["NEO4J_PASSWORD"] = os.getenv("NEO4J_PASSWORD")
499
+
500
+ # Create and run MCP server
501
+ server = MOSMCPStdioServer()
502
+ server.run(transport=args.transport, host=args.host, port=args.port)
@@ -0,0 +1,35 @@
1
+ import logging
2
+
3
+ from fastapi import FastAPI
4
+
5
+ from memos.api.exceptions import APIExceptionHandler
6
+ from memos.api.routers.product_router import router as product_router
7
+
8
+
9
+ # Configure logging
10
+ logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
11
+ logger = logging.getLogger(__name__)
12
+
13
+ app = FastAPI(
14
+ title="MemOS Product REST APIs",
15
+ description="A REST API for managing multiple users with MemOS Product.",
16
+ version="1.0.0",
17
+ )
18
+
19
+ # Include routers
20
+ app.include_router(product_router)
21
+
22
+ # Exception handlers
23
+ app.exception_handler(ValueError)(APIExceptionHandler.value_error_handler)
24
+ app.exception_handler(Exception)(APIExceptionHandler.global_exception_handler)
25
+
26
+
27
+ if __name__ == "__main__":
28
+ import argparse
29
+
30
+ import uvicorn
31
+
32
+ parser = argparse.ArgumentParser()
33
+ parser.add_argument("--port", type=int, default=8001)
34
+ args = parser.parse_args()
35
+ uvicorn.run(app, host="0.0.0.0", port=args.port)