mnemo-mcp 2.2.2b1__tar.gz → 2.2.2b2__tar.gz

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 (44) hide show
  1. {mnemo_mcp-2.2.2b1 → mnemo_mcp-2.2.2b2}/PKG-INFO +1 -1
  2. {mnemo_mcp-2.2.2b1 → mnemo_mcp-2.2.2b2}/pyproject.toml +1 -1
  3. {mnemo_mcp-2.2.2b1 → mnemo_mcp-2.2.2b2}/src/mnemo_mcp/graph.py +1 -1
  4. {mnemo_mcp-2.2.2b1 → mnemo_mcp-2.2.2b2}/src/mnemo_mcp/server.py +16 -0
  5. {mnemo_mcp-2.2.2b1 → mnemo_mcp-2.2.2b2}/src/mnemo_mcp/sync/delta.py +45 -23
  6. {mnemo_mcp-2.2.2b1 → mnemo_mcp-2.2.2b2}/.gitignore +0 -0
  7. {mnemo_mcp-2.2.2b1 → mnemo_mcp-2.2.2b2}/LICENSE +0 -0
  8. {mnemo_mcp-2.2.2b1 → mnemo_mcp-2.2.2b2}/README.md +0 -0
  9. {mnemo_mcp-2.2.2b1 → mnemo_mcp-2.2.2b2}/src/mnemo_mcp/__init__.py +0 -0
  10. {mnemo_mcp-2.2.2b1 → mnemo_mcp-2.2.2b2}/src/mnemo_mcp/__main__.py +0 -0
  11. {mnemo_mcp-2.2.2b1 → mnemo_mcp-2.2.2b2}/src/mnemo_mcp/alembic/README +0 -0
  12. {mnemo_mcp-2.2.2b1 → mnemo_mcp-2.2.2b2}/src/mnemo_mcp/alembic/env.py +0 -0
  13. {mnemo_mcp-2.2.2b1 → mnemo_mcp-2.2.2b2}/src/mnemo_mcp/alembic/script.py.mako +0 -0
  14. {mnemo_mcp-2.2.2b1 → mnemo_mcp-2.2.2b2}/src/mnemo_mcp/alembic/versions/baseline_001_existing_schema.py +0 -0
  15. {mnemo_mcp-2.2.2b1 → mnemo_mcp-2.2.2b2}/src/mnemo_mcp/alembic/versions/mem_001_context_types.py +0 -0
  16. {mnemo_mcp-2.2.2b1 → mnemo_mcp-2.2.2b2}/src/mnemo_mcp/alembic/versions/mem_002_compression.py +0 -0
  17. {mnemo_mcp-2.2.2b1 → mnemo_mcp-2.2.2b2}/src/mnemo_mcp/alembic/versions/mem_003_temporal.py +0 -0
  18. {mnemo_mcp-2.2.2b1 → mnemo_mcp-2.2.2b2}/src/mnemo_mcp/alembic.ini +0 -0
  19. {mnemo_mcp-2.2.2b1 → mnemo_mcp-2.2.2b2}/src/mnemo_mcp/capture.py +0 -0
  20. {mnemo_mcp-2.2.2b1 → mnemo_mcp-2.2.2b2}/src/mnemo_mcp/compression.py +0 -0
  21. {mnemo_mcp-2.2.2b1 → mnemo_mcp-2.2.2b2}/src/mnemo_mcp/config.py +0 -0
  22. {mnemo_mcp-2.2.2b1 → mnemo_mcp-2.2.2b2}/src/mnemo_mcp/credential_state.py +0 -0
  23. {mnemo_mcp-2.2.2b1 → mnemo_mcp-2.2.2b2}/src/mnemo_mcp/db.py +0 -0
  24. {mnemo_mcp-2.2.2b1 → mnemo_mcp-2.2.2b2}/src/mnemo_mcp/docs/__init__.py +0 -0
  25. {mnemo_mcp-2.2.2b1 → mnemo_mcp-2.2.2b2}/src/mnemo_mcp/docs/config.md +0 -0
  26. {mnemo_mcp-2.2.2b1 → mnemo_mcp-2.2.2b2}/src/mnemo_mcp/docs/memory.md +0 -0
  27. {mnemo_mcp-2.2.2b1 → mnemo_mcp-2.2.2b2}/src/mnemo_mcp/embedder.py +0 -0
  28. {mnemo_mcp-2.2.2b1 → mnemo_mcp-2.2.2b2}/src/mnemo_mcp/llm.py +0 -0
  29. {mnemo_mcp-2.2.2b1 → mnemo_mcp-2.2.2b2}/src/mnemo_mcp/py.typed +0 -0
  30. {mnemo_mcp-2.2.2b1 → mnemo_mcp-2.2.2b2}/src/mnemo_mcp/relay_schema.py +0 -0
  31. {mnemo_mcp-2.2.2b1 → mnemo_mcp-2.2.2b2}/src/mnemo_mcp/relay_setup.py +0 -0
  32. {mnemo_mcp-2.2.2b1 → mnemo_mcp-2.2.2b2}/src/mnemo_mcp/reranker.py +0 -0
  33. {mnemo_mcp-2.2.2b1 → mnemo_mcp-2.2.2b2}/src/mnemo_mcp/setup_tool.py +0 -0
  34. {mnemo_mcp-2.2.2b1 → mnemo_mcp-2.2.2b2}/src/mnemo_mcp/sync/__init__.py +0 -0
  35. {mnemo_mcp-2.2.2b1 → mnemo_mcp-2.2.2b2}/src/mnemo_mcp/sync/base.py +0 -0
  36. {mnemo_mcp-2.2.2b1 → mnemo_mcp-2.2.2b2}/src/mnemo_mcp/sync/bundle.py +0 -0
  37. {mnemo_mcp-2.2.2b1 → mnemo_mcp-2.2.2b2}/src/mnemo_mcp/sync/gdrive.py +0 -0
  38. {mnemo_mcp-2.2.2b1 → mnemo_mcp-2.2.2b2}/src/mnemo_mcp/sync/s3.py +0 -0
  39. {mnemo_mcp-2.2.2b1 → mnemo_mcp-2.2.2b2}/src/mnemo_mcp/temporal/__init__.py +0 -0
  40. {mnemo_mcp-2.2.2b1 → mnemo_mcp-2.2.2b2}/src/mnemo_mcp/temporal/extract.py +0 -0
  41. {mnemo_mcp-2.2.2b1 → mnemo_mcp-2.2.2b2}/src/mnemo_mcp/temporal/queries.py +0 -0
  42. {mnemo_mcp-2.2.2b1 → mnemo_mcp-2.2.2b2}/src/mnemo_mcp/temporal/resolve.py +0 -0
  43. {mnemo_mcp-2.2.2b1 → mnemo_mcp-2.2.2b2}/src/mnemo_mcp/temporal/store.py +0 -0
  44. {mnemo_mcp-2.2.2b1 → mnemo_mcp-2.2.2b2}/src/mnemo_mcp/token_store.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mnemo-mcp
3
- Version: 2.2.2b1
3
+ Version: 2.2.2b2
4
4
  Summary: Open-source MCP Server for persistent AI memory with embedded sync
5
5
  Project-URL: Homepage, https://github.com/n24q02m/mnemo-mcp
6
6
  Project-URL: Repository, https://github.com/n24q02m/mnemo-mcp.git
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "mnemo-mcp"
3
- version = "2.2.2-beta.1"
3
+ version = "2.2.2-beta.2"
4
4
  description = "Open-source MCP Server for persistent AI memory with embedded sync"
5
5
  readme = "README.md"
6
6
  license = { text = "MIT" }
@@ -305,7 +305,7 @@ def create_relations(
305
305
 
306
306
  def link_memory_entities(conn, memory_id: str, entity_ids: list[str]) -> None:
307
307
  """Link a memory to entities."""
308
- if not entity_ids:
308
+ if not memory_id or not memory_id.strip() or not entity_ids:
309
309
  return
310
310
 
311
311
  try:
@@ -2146,6 +2146,14 @@ def save_summary(summary: str) -> str:
2146
2146
  - Use when a conversation is concluding or shifting topics to persist key takeaways.
2147
2147
  - Parameters: 'summary' (the consolidated text to save).
2148
2148
  """
2149
+ if not summary or not summary.strip():
2150
+ return _json(
2151
+ {
2152
+ "error": "Summary cannot be empty",
2153
+ "suggestion": "Provide a concise summary of the conversation to save as memory.",
2154
+ }
2155
+ )
2156
+
2149
2157
  return (
2150
2158
  f"Save this conversation summary as a memory:\n\n{summary}\n\n"
2151
2159
  "Use the memory tool with action='add', category='context', "
@@ -2161,6 +2169,14 @@ def recall_context(topic: str) -> str:
2161
2169
  - Use when starting a new task or answering a question to retrieve prior context.
2162
2170
  - Parameters: 'topic' (the specific subject or keywords to search for).
2163
2171
  """
2172
+ if not topic or not topic.strip():
2173
+ return _json(
2174
+ {
2175
+ "error": "Topic cannot be empty",
2176
+ "suggestion": "Provide a specific topic or keyword to search for in your memories.",
2177
+ }
2178
+ )
2179
+
2164
2180
  return (
2165
2181
  f"Search your memories for relevant context about: {topic}\n\n"
2166
2182
  "Use the memory tool with action='search' and this query. "
@@ -269,46 +269,50 @@ def _apply_kg_sections(db: MemoryDB, payload: dict[str, bytes]) -> dict:
269
269
  cursor = db._conn.cursor()
270
270
 
271
271
  ents_raw = payload.get("memories_entities.jsonl", b"").decode("utf-8")
272
+ entities_list = []
272
273
  for line in ents_raw.splitlines():
273
274
  line = line.strip()
274
275
  if not line:
275
276
  continue
276
277
  try:
277
278
  ent = json.loads(line)
278
- except json.JSONDecodeError:
279
- continue
280
- try:
281
- cursor.execute(
282
- "INSERT OR IGNORE INTO memory_entities "
283
- "(id, name, entity_type, created_at, updated_at) "
284
- "VALUES (?, ?, ?, ?, ?)",
279
+ if not isinstance(ent, dict):
280
+ continue
281
+ entities_list.append(
285
282
  (
286
283
  ent.get("id"),
287
284
  ent.get("name"),
288
285
  ent.get("entity_type"),
289
286
  ent.get("created_at"),
290
287
  ent.get("updated_at"),
291
- ),
288
+ )
289
+ )
290
+ except (json.JSONDecodeError, AttributeError):
291
+ continue
292
+
293
+ if entities_list:
294
+ try:
295
+ cursor.executemany(
296
+ "INSERT OR IGNORE INTO memory_entities "
297
+ "(id, name, entity_type, created_at, updated_at) "
298
+ "VALUES (?, ?, ?, ?, ?)",
299
+ entities_list,
292
300
  )
293
301
  counts["entities_applied"] += cursor.rowcount or 0
294
302
  except Exception as e:
295
- logger.debug(f"apply_bundle: entity skipped ({e})")
303
+ logger.debug(f"apply_bundle: entities skipped ({e})")
296
304
 
297
305
  edges_raw = payload.get("memories_edges.jsonl", b"").decode("utf-8")
306
+ edges_list = []
298
307
  for line in edges_raw.splitlines():
299
308
  line = line.strip()
300
309
  if not line:
301
310
  continue
302
311
  try:
303
312
  edge = json.loads(line)
304
- except json.JSONDecodeError:
305
- continue
306
- try:
307
- cursor.execute(
308
- "INSERT OR IGNORE INTO memory_edges "
309
- "(id, source_id, target_id, relation_type, created_at, "
310
- " memory_id, valid_from, valid_to) "
311
- "VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
313
+ if not isinstance(edge, dict):
314
+ continue
315
+ edges_list.append(
312
316
  (
313
317
  edge.get("id"),
314
318
  edge.get("source_id"),
@@ -318,30 +322,48 @@ def _apply_kg_sections(db: MemoryDB, payload: dict[str, bytes]) -> dict:
318
322
  edge.get("memory_id"),
319
323
  edge.get("valid_from"),
320
324
  edge.get("valid_to"),
321
- ),
325
+ )
326
+ )
327
+ except (json.JSONDecodeError, AttributeError):
328
+ continue
329
+
330
+ if edges_list:
331
+ try:
332
+ cursor.executemany(
333
+ "INSERT OR IGNORE INTO memory_edges "
334
+ "(id, source_id, target_id, relation_type, created_at, "
335
+ " memory_id, valid_from, valid_to) "
336
+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
337
+ edges_list,
322
338
  )
323
339
  counts["edges_applied"] += cursor.rowcount or 0
324
340
  except Exception as e:
325
- logger.debug(f"apply_bundle: edge skipped ({e})")
341
+ logger.debug(f"apply_bundle: edges skipped ({e})")
326
342
 
327
343
  links_raw = payload.get("memories_entity_links.jsonl", b"").decode("utf-8")
344
+ links_list = []
328
345
  for line in links_raw.splitlines():
329
346
  line = line.strip()
330
347
  if not line:
331
348
  continue
332
349
  try:
333
350
  link = json.loads(line)
334
- except json.JSONDecodeError:
351
+ if not isinstance(link, dict):
352
+ continue
353
+ links_list.append((link.get("memory_id"), link.get("entity_id")))
354
+ except (json.JSONDecodeError, AttributeError):
335
355
  continue
356
+
357
+ if links_list:
336
358
  try:
337
- cursor.execute(
359
+ cursor.executemany(
338
360
  "INSERT OR IGNORE INTO memory_entity_links "
339
361
  "(memory_id, entity_id) VALUES (?, ?)",
340
- (link.get("memory_id"), link.get("entity_id")),
362
+ links_list,
341
363
  )
342
364
  counts["links_applied"] += cursor.rowcount or 0
343
365
  except Exception as e:
344
- logger.debug(f"apply_bundle: link skipped ({e})")
366
+ logger.debug(f"apply_bundle: links skipped ({e})")
345
367
 
346
368
  db._conn.commit()
347
369
  return counts
File without changes
File without changes
File without changes