mem0-open-mcp 0.1.2__py3-none-any.whl → 0.1.4__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mem0-open-mcp
3
- Version: 0.1.2
3
+ Version: 0.1.4
4
4
  Summary: Open-source MCP server for mem0 - local LLMs, self-hosted, Docker-free
5
5
  Author: Alex
6
6
  License-Expression: Apache-2.0
@@ -83,10 +83,18 @@ mem0-open-mcp configure
83
83
  # Start the server
84
84
  mem0-open-mcp serve
85
85
 
86
+ # Test configuration before starting (recommended for initial setup)
87
+ mem0-open-mcp serve --test
88
+
86
89
  # With options
87
90
  mem0-open-mcp serve --port 8765 --user-id alice
88
91
  ```
89
92
 
93
+ The `--test` flag runs connectivity and memory tests before starting the server:
94
+ - Checks Vector Store, LLM, and Embedder connections
95
+ - Performs actual memory add/search operations
96
+ - Cleans up test data automatically
97
+
90
98
  ## Configuration
91
99
 
92
100
  Create `mem0-open-mcp.yaml`:
@@ -1,15 +1,15 @@
1
- mem0_server/__init__.py,sha256=J3DIJ4cwmlNijrW0AXOxNElD0eKN1V443Ew-DGp0-Gg,232
2
- mem0_server/cli.py,sha256=96uFUoUBZDc-dqO4OTTs3xu0Xf3vTz5X7PeLHUIYqmc,15564
1
+ mem0_server/__init__.py,sha256=FrcCqmcA_VSR57xjgdQ1obSrsSzxDsDsXdEGSdVhUq0,379
2
+ mem0_server/cli.py,sha256=ttWdrJFbd1dX2QIpHrLGVbSob86FQqjNJgtgGw4dFlI,24674
3
3
  mem0_server/server.py,sha256=Obc2eZaAYuZdUgYpOY8qWwbOXgc3w1vRmmEF3tc0gdI,12494
4
4
  mem0_server/api/__init__.py,sha256=JOOnrq3v7yym3xotMkOUAoZj1zjhI8C_a1wEdbpCakQ,122
5
5
  mem0_server/api/routes.py,sha256=fBOeQ1kckEa9Nr57cutCunhG9D1J5zYrv9sFiYcZ1yQ,21743
6
6
  mem0_server/config/__init__.py,sha256=Z0GWnr8I7VbrUfVLeA37K9qHOsK7HJOHiGELbWp8YcI,733
7
7
  mem0_server/config/loader.py,sha256=LPobv8BSyPShJ_27d_hwsx9EhAJPDdzWJMrUGJ4Qdt8,8373
8
- mem0_server/config/schema.py,sha256=44TQKNavwkH8btdJBXSPWUcFcMKTpzb-Pb03pZ3dImI,12651
8
+ mem0_server/config/schema.py,sha256=HnFWUR4KxwHkyukFw_ptMCHt7K26Zl7AU02-5jdtjL4,12731
9
9
  mem0_server/mcp/__init__.py,sha256=8BWWjlJj5_jdeUuQFN4i5hm5Zd3Pk0cCR2Vf0G4eUB4,127
10
10
  mem0_server/mcp/server.py,sha256=Y_f8upEtvjr0JjZaUQ4YWLRrof9btR2ds8FL2DucCZI,184
11
11
  mem0_server/utils/__init__.py,sha256=GvVR3Tz4OmU2gRGCbTyQg5Xip5cAx7KW6ToIh2sKA4w,41
12
- mem0_open_mcp-0.1.2.dist-info/METADATA,sha256=y7dIo0XWvnOpdGMspJQszXDEQP_t99fxmFfB16IGsWc,4622
13
- mem0_open_mcp-0.1.2.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
14
- mem0_open_mcp-0.1.2.dist-info/entry_points.txt,sha256=WXqVdvwhFvMkzAmNtdlHlRZV23yikM43BtB8S4F9ByE,54
15
- mem0_open_mcp-0.1.2.dist-info/RECORD,,
12
+ mem0_open_mcp-0.1.4.dist-info/METADATA,sha256=8qYxHV26Qvr15BlVbglNswhzlRvcG06J-mNlzUum5j0,4937
13
+ mem0_open_mcp-0.1.4.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
14
+ mem0_open_mcp-0.1.4.dist-info/entry_points.txt,sha256=WXqVdvwhFvMkzAmNtdlHlRZV23yikM43BtB8S4F9ByE,54
15
+ mem0_open_mcp-0.1.4.dist-info/RECORD,,
mem0_server/__init__.py CHANGED
@@ -5,4 +5,9 @@ This package provides a CLI tool to run mem0 as an MCP server without Docker,
5
5
  with optional web UI for configuration management.
6
6
  """
7
7
 
8
- __version__ = "0.1.0"
8
+ from importlib.metadata import version, PackageNotFoundError
9
+
10
+ try:
11
+ __version__ = version("mem0-open-mcp")
12
+ except PackageNotFoundError:
13
+ __version__ = "0.0.0-dev"
mem0_server/cli.py CHANGED
@@ -2,7 +2,9 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ import json
5
6
  import logging
7
+ import time
6
8
  from pathlib import Path
7
9
  from typing import Annotated
8
10
 
@@ -29,6 +31,199 @@ app = typer.Typer(
29
31
 
30
32
  console = Console()
31
33
 
34
+ UPDATE_CHECK_CACHE = Path.home() / ".cache" / "mem0-open-mcp" / "update_check.json"
35
+ UPDATE_CHECK_INTERVAL = 86400 # 24 hours
36
+
37
+
38
+ def _parse_version(v: str) -> tuple[int, ...]:
39
+ """Parse version string to tuple for comparison."""
40
+ try:
41
+ return tuple(int(x) for x in v.split(".")[:3])
42
+ except (ValueError, AttributeError):
43
+ return (0, 0, 0)
44
+
45
+
46
+ def _check_for_updates() -> None:
47
+ """Check PyPI for newer version (once per day)."""
48
+ try:
49
+ UPDATE_CHECK_CACHE.parent.mkdir(parents=True, exist_ok=True)
50
+
51
+ now = time.time()
52
+ if UPDATE_CHECK_CACHE.exists():
53
+ cache = json.loads(UPDATE_CHECK_CACHE.read_text())
54
+ if now - cache.get("last_check", 0) < UPDATE_CHECK_INTERVAL:
55
+ latest = cache.get("latest")
56
+ if latest and _parse_version(latest) > _parse_version(__version__):
57
+ console.print(
58
+ f"[yellow]Update available: {__version__} → {latest}[/yellow]\n"
59
+ f"[dim] pip install --upgrade mem0-open-mcp[/dim]\n"
60
+ )
61
+ return
62
+
63
+ import httpx
64
+ resp = httpx.get("https://pypi.org/pypi/mem0-open-mcp/json", timeout=3)
65
+ resp.raise_for_status()
66
+ latest = resp.json()["info"]["version"]
67
+
68
+ UPDATE_CHECK_CACHE.write_text(json.dumps({"last_check": now, "latest": latest}))
69
+
70
+ if _parse_version(latest) > _parse_version(__version__):
71
+ console.print(
72
+ f"[yellow]Update available: {__version__} → {latest}[/yellow]\n"
73
+ f"[dim] pip install --upgrade mem0-open-mcp[/dim]\n"
74
+ )
75
+ except Exception:
76
+ pass
77
+
78
+
79
+ def _run_connectivity_tests(config: Mem0ServerConfig) -> bool:
80
+ """Run connectivity tests for LLM, Embedder, and Vector Store."""
81
+ console.print("[bold]Running connectivity tests...[/bold]\n")
82
+
83
+ all_passed = True
84
+
85
+ # Test Vector Store
86
+ console.print(" [dim]Vector Store...[/dim]", end=" ")
87
+ try:
88
+ vs_config = config.vector_store
89
+ if vs_config.provider.value == "qdrant":
90
+ from qdrant_client import QdrantClient
91
+ host = vs_config.config.host or "localhost"
92
+ port = vs_config.config.port or 6333
93
+ client = QdrantClient(host=host, port=port, timeout=5)
94
+ client.get_collections()
95
+ console.print("[green]✓ Connected[/green]")
96
+ elif vs_config.provider.value == "chroma":
97
+ import chromadb
98
+ if vs_config.config.host:
99
+ client = chromadb.HttpClient(host=vs_config.config.host, port=vs_config.config.port or 8000)
100
+ else:
101
+ client = chromadb.Client()
102
+ client.heartbeat()
103
+ console.print("[green]✓ Connected[/green]")
104
+ else:
105
+ console.print(f"[yellow]⚠ Skip (no test for {vs_config.provider.value})[/yellow]")
106
+ except Exception as e:
107
+ console.print(f"[red]✗ Failed: {e}[/red]")
108
+ all_passed = False
109
+
110
+ # Test LLM
111
+ console.print(" [dim]LLM...[/dim]", end=" ")
112
+ try:
113
+ llm_config = config.llm
114
+ if llm_config.provider.value == "ollama":
115
+ import httpx
116
+ base_url = llm_config.config.base_url or "http://localhost:11434"
117
+ resp = httpx.get(f"{base_url}/api/tags", timeout=5)
118
+ resp.raise_for_status()
119
+ models = [m["name"] for m in resp.json().get("models", [])]
120
+ if llm_config.config.model in models or any(llm_config.config.model in m for m in models):
121
+ console.print(f"[green]✓ Connected ({llm_config.config.model})[/green]")
122
+ else:
123
+ console.print(f"[yellow]⚠ Connected but model '{llm_config.config.model}' not found[/yellow]")
124
+ console.print(f" [dim]Available: {', '.join(models[:5])}{'...' if len(models) > 5 else ''}[/dim]")
125
+ elif llm_config.provider.value in ("openai", "lmstudio"):
126
+ import httpx
127
+ base_url = llm_config.config.base_url or "https://api.openai.com/v1"
128
+ headers = {}
129
+ if llm_config.config.api_key:
130
+ headers["Authorization"] = f"Bearer {llm_config.config.api_key}"
131
+ resp = httpx.get(f"{base_url}/models", headers=headers, timeout=5)
132
+ resp.raise_for_status()
133
+ console.print(f"[green]✓ Connected ({llm_config.config.model})[/green]")
134
+ else:
135
+ console.print(f"[yellow]⚠ Skip (no test for {llm_config.provider.value})[/yellow]")
136
+ except Exception as e:
137
+ console.print(f"[red]✗ Failed: {e}[/red]")
138
+ all_passed = False
139
+
140
+ # Test Embedder
141
+ console.print(" [dim]Embedder...[/dim]", end=" ")
142
+ try:
143
+ emb_config = config.embedder
144
+ if emb_config.provider.value == "ollama":
145
+ import httpx
146
+ base_url = emb_config.config.base_url or "http://localhost:11434"
147
+ resp = httpx.get(f"{base_url}/api/tags", timeout=5)
148
+ resp.raise_for_status()
149
+ models = [m["name"] for m in resp.json().get("models", [])]
150
+ if emb_config.config.model in models or any(emb_config.config.model in m for m in models):
151
+ console.print(f"[green]✓ Connected ({emb_config.config.model})[/green]")
152
+ else:
153
+ console.print(f"[yellow]⚠ Connected but model '{emb_config.config.model}' not found[/yellow]")
154
+ console.print(f" [dim]Available: {', '.join(models[:5])}{'...' if len(models) > 5 else ''}[/dim]")
155
+ elif emb_config.provider.value in ("openai", "lmstudio"):
156
+ import httpx
157
+ base_url = emb_config.config.base_url or "https://api.openai.com/v1"
158
+ headers = {}
159
+ if emb_config.config.api_key:
160
+ headers["Authorization"] = f"Bearer {emb_config.config.api_key}"
161
+ resp = httpx.get(f"{base_url}/models", headers=headers, timeout=5)
162
+ resp.raise_for_status()
163
+ console.print(f"[green]✓ Connected ({emb_config.config.model})[/green]")
164
+ else:
165
+ console.print(f"[yellow]⚠ Skip (no test for {emb_config.provider.value})[/yellow]")
166
+ except Exception as e:
167
+ console.print(f"[red]✗ Failed: {e}[/red]")
168
+ all_passed = False
169
+
170
+ console.print()
171
+ if all_passed:
172
+ console.print("[bold green]All connectivity tests passed![/bold green]\n")
173
+ else:
174
+ console.print("[bold red]Some connectivity tests failed. Please check your configuration.[/bold red]\n")
175
+
176
+ return all_passed
177
+
178
+
179
+ def _run_memory_tests(config: Mem0ServerConfig) -> bool:
180
+ """Run actual mem0 memory add/search tests."""
181
+ import uuid
182
+ console.print("[bold]Running memory tests...[/bold]\n")
183
+
184
+ test_user_id = f"__test_user_{uuid.uuid4().hex[:8]}"
185
+ test_memory_text = "This is a test memory for connectivity verification."
186
+
187
+ try:
188
+ console.print(" [dim]Initializing mem0 client...[/dim]", end=" ")
189
+ from mem0 import Memory
190
+ mem0_config = config.to_mem0_config()
191
+ memory = Memory.from_config(mem0_config)
192
+ console.print("[green]✓[/green]")
193
+
194
+ console.print(" [dim]Adding test memory...[/dim]", end=" ")
195
+ add_result = memory.add(test_memory_text, user_id=test_user_id)
196
+ if add_result and add_result.get("results"):
197
+ first_result = add_result["results"][0]
198
+ memory_id = first_result.get("id") if first_result else None
199
+ if memory_id:
200
+ console.print(f"[green]✓ Added (id: {memory_id[:8]}...)[/green]")
201
+ else:
202
+ console.print("[green]✓ Added[/green]")
203
+ else:
204
+ console.print("[green]✓ Added[/green]")
205
+
206
+ console.print(" [dim]Searching memories...[/dim]", end=" ")
207
+ search_result = memory.search("test memory verification", user_id=test_user_id, limit=5)
208
+ if search_result and search_result.get("results"):
209
+ console.print(f"[green]✓ Found {len(search_result['results'])} result(s)[/green]")
210
+ else:
211
+ console.print("[yellow]⚠ No results (may be expected for new setup)[/yellow]")
212
+
213
+ console.print(" [dim]Cleaning up test data...[/dim]", end=" ")
214
+ memory.delete_all(user_id=test_user_id)
215
+ console.print("[green]✓ Cleaned[/green]")
216
+
217
+ console.print()
218
+ console.print("[bold green]All memory tests passed![/bold green]\n")
219
+ return True
220
+
221
+ except Exception as e:
222
+ console.print(f"[red]✗ Failed: {e}[/red]")
223
+ console.print()
224
+ console.print("[bold red]Memory test failed. Check your LLM/Embedder/VectorStore configuration.[/bold red]\n")
225
+ return False
226
+
32
227
 
33
228
  def version_callback(value: bool) -> None:
34
229
  """Show version and exit."""
@@ -83,6 +278,10 @@ def serve(
83
278
  str,
84
279
  typer.Option("--log-level", "-l", help="Logging level."),
85
280
  ] = "info",
281
+ test: Annotated[
282
+ bool,
283
+ typer.Option("--test", "-t", help="Run connectivity tests before starting server."),
284
+ ] = False,
86
285
  ) -> None:
87
286
  """Start the MCP server.
88
287
 
@@ -120,7 +319,9 @@ def serve(
120
319
  border_style="green",
121
320
  ))
122
321
 
123
- console.print("\n[bold]Configuration:[/bold]")
322
+ _check_for_updates()
323
+
324
+ console.print("[bold]Configuration:[/bold]")
124
325
  console.print(f" Host: [cyan]{config.server.host}[/cyan]")
125
326
  console.print(f" Port: [cyan]{config.server.port}[/cyan]")
126
327
  console.print(f" User ID: [cyan]{config.server.user_id}[/cyan]")
@@ -129,6 +330,12 @@ def serve(
129
330
  console.print(f" Vector Store: [cyan]{config.vector_store.provider.value}[/cyan]")
130
331
  console.print()
131
332
 
333
+ if test:
334
+ if not _run_connectivity_tests(config):
335
+ raise typer.Exit(1)
336
+ if not _run_memory_tests(config):
337
+ raise typer.Exit(1)
338
+
132
339
  # Start the server
133
340
  try:
134
341
  from mem0_server.server import run_server
@@ -323,6 +323,7 @@ def get_default_config() -> Mem0ServerConfig:
323
323
  config=EmbedderConfig(
324
324
  model="text-embedding-3-small",
325
325
  api_key="env:OPENAI_API_KEY",
326
+ embedding_dims=1536,
326
327
  ),
327
328
  ),
328
329
  vector_store=VectorStoreProvider(
@@ -331,6 +332,7 @@ def get_default_config() -> Mem0ServerConfig:
331
332
  collection_name="mem0_memories",
332
333
  host="localhost",
333
334
  port=6333,
335
+ embedding_model_dims=1536,
334
336
  ),
335
337
  ),
336
338
  )