yomemoai-mcp 0.1.3__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.
yomemoai_mcp/client.py CHANGED
@@ -1,4 +1,5 @@
1
1
  import base64
2
+ from cryptography.hazmat.primitives.ciphers.modes import GCM
2
3
  import json
3
4
  import logging
4
5
  import time
@@ -104,7 +105,7 @@ class MemoClient:
104
105
  tag = combined_data[-16:]
105
106
  ciphertext = combined_data[12:-16]
106
107
 
107
- cipher = Cipher(algorithms.AES(aes_key), modes.GCM(
108
+ cipher = Cipher[GCM](algorithms.AES(aes_key), modes.GCM(
108
109
  nonce, tag), backend=default_backend())
109
110
  decryptor = cipher.decryptor()
110
111
  return decryptor.update(ciphertext) + decryptor.finalize()
@@ -184,6 +185,10 @@ class MemoClient:
184
185
  resp.raise_for_status()
185
186
 
186
187
  memories = resp.json().get("data", [])
188
+ # Backend may return `data: null` when there are no memories; normalize to empty list.
189
+ if memories is None:
190
+ memories = []
191
+
187
192
  for m in memories:
188
193
  try:
189
194
  decrypted = self.unpack_and_decrypt(m["content"])
yomemoai_mcp/server.py CHANGED
@@ -3,6 +3,8 @@ import json
3
3
  import logging
4
4
  import os
5
5
  import sys
6
+ from typing import Optional
7
+
6
8
  from mcp.server.fastmcp import FastMCP
7
9
  from .client import MemoClient, MemoRequestError
8
10
 
@@ -59,21 +61,27 @@ def _format_payload(payload: dict) -> dict:
59
61
 
60
62
 
61
63
  @mcp.tool()
62
- async def save_memory(content: str, handle: str = "general", description: str = "") -> str:
64
+ async def save_memory(content: str, handle: str = "general", description: str = "", metadata: dict = {}) -> str:
63
65
  """
64
- Store important information as a permanent memory. You should call this proactively when you
65
- detect user preferences, important decisions, reusable logic, or context worth recalling later—
66
- not only when the user explicitly says "remember" or "save". After saving successfully, reply with ✓.
67
-
68
- :param content: The actual text/information to be remembered. Be concise but maintain context.
69
- :param handle: A short, unique category or tag (e.g., 'work', 'personal', 'project-x'). Defaults to 'general'.
70
- :param description: A brief, non-sensitive summary or tag for this memory (helps future identification and search).
66
+ Archives a high-density knowledge asset using the Semantic Fingerprint Protocol.
67
+ Proactively triggered by the AMP (Autonomous Persistence Trigger) during 'Moments of Truth'
68
+ such as strategic decisions, fact updates, or logic finalization.
69
+
70
+ :param content: The actual high-density factual information, decision logic, or SOP.
71
+ Maintain context while stripping conversational noise.
72
+ :param handle: Categorical routing based on Layer ID (L1-L5) or specific project Name.
73
+ Helps in contextual retrieval (PRT).
74
+ :param description: A brief, non-sensitive summary or high-level tag for safe indexing and search.
75
+ STRICT CONSTRAINT: Must NOT contain specific transactional details,
76
+ PII, or sensitive affairs to prevent information leakage.
77
+ :param metadata: MANDATORY. Stores high-dimensional tag data under the 'semantic_fingerprint' key,
78
+ including ELAP metrics, ontology mode, and engineering VCS status.
71
79
  """
72
80
  logger.debug(
73
81
  f"save_memory called: handle={handle}, description={description}, content_length={len(content)}")
74
82
  try:
75
83
  result = client.add_memory(
76
- content, handle=handle, description=description)
84
+ content, handle=handle, description=description,metadata=metadata)
77
85
  logger.debug(f"add_memory response: {result}")
78
86
 
79
87
  if "memory_id" not in result:
@@ -108,13 +116,17 @@ async def save_memory(content: str, handle: str = "general", description: str =
108
116
 
109
117
 
110
118
  @mcp.tool()
111
- async def load_memories(handle: str = None) -> str:
119
+ async def load_memories(handle: Optional[str] = None) -> str:
112
120
  """
113
121
  Retrieve previously stored memories. Call this when the user asks what you remember, or when you
114
122
  need historical context (preferences, past decisions, project details) to answer accurately.
115
123
 
116
124
  :param handle: Optional filter. If the user specifies a category (e.g., 'work', 'project-x'),
117
125
  use the relevant handle; otherwise omit to load across handles.
126
+
127
+ The output includes each memory's handle, idempotent key, and content so that callers can
128
+ later use the same idempotent key with save_memory to update existing memories instead of
129
+ creating duplicates.
118
130
  """
119
131
  logger.debug(f"load_memories called: handle={handle}")
120
132
  try:
@@ -128,9 +140,16 @@ async def load_memories(handle: str = None) -> str:
128
140
 
129
141
  output = ["### Retrieved Memories:"]
130
142
  for m in memories:
131
- timestamp = m.get('created_at', 'N/A')
143
+ handle_value = m.get("handle")
144
+ idempotent_key = m.get("idempotent_key") or "N/A"
145
+ content = m.get("content")
146
+ metadata = m.get("metadata")
132
147
  output.append(
133
- f"Handle: [{m.get('handle')}]\nContent: {m.get('content')}\n---"
148
+ "Handle: [{handle}]\nIdempotent Key: {key}\nContent: {content}\n---".format(
149
+ handle=handle_value,
150
+ key=idempotent_key,
151
+ content=content,
152
+ metadata=json.dumps(metadata, ensure_ascii=False) if metadata else "{}")
134
153
  )
135
154
  logger.info(f"Successfully loaded {len(memories)} memories")
136
155
  return "\n".join(output)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: yomemoai-mcp
3
- Version: 0.1.3
3
+ Version: 0.1.4
4
4
  Summary: Model Context Protocol (MCP) server for YoMemoAI - enables AI assistants to save and retrieve encrypted memories
5
5
  Project-URL: Homepage, https://github.com/yomemoai/python-yomemo-mcp
6
6
  Project-URL: Documentation, https://github.com/yomemoai/python-yomemo-mcp#readme
@@ -0,0 +1,9 @@
1
+ yomemoai_mcp/__init__.py,sha256=gDi0t9iKR423OZlwrrtwDaED3ck06XMe_y8mcxisBl0,95
2
+ yomemoai_mcp/client.py,sha256=sXfHcU6wgUT7pDavsxU5HBAwqf9VSX1s3I4PXdzo12U,7177
3
+ yomemoai_mcp/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ yomemoai_mcp/server.py,sha256=evZSzZuq7OaluF6OLUzsdK-jDMnPMHl9YSf5M78CMtg,6283
5
+ yomemoai_mcp-0.1.4.dist-info/METADATA,sha256=owu--8SQKkQecwqZLfQayqm92OcC-r409iH4DleVi2I,7551
6
+ yomemoai_mcp-0.1.4.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
7
+ yomemoai_mcp-0.1.4.dist-info/entry_points.txt,sha256=uV0479NK4ppOUV1T9VSwFTLi87F4deaRjbL8s43R8uI,100
8
+ yomemoai_mcp-0.1.4.dist-info/licenses/LICENSE,sha256=UVt2r_C3iy7rNKJAj_EcLcmcZdXONxJ01oJNsIEqTfw,1066
9
+ yomemoai_mcp-0.1.4.dist-info/RECORD,,
@@ -1,9 +0,0 @@
1
- yomemoai_mcp/__init__.py,sha256=gDi0t9iKR423OZlwrrtwDaED3ck06XMe_y8mcxisBl0,95
2
- yomemoai_mcp/client.py,sha256=oZNfRW3ppfSRkWvG3ej-w56lUyfKsc6jOjvV_IY4JxM,6960
3
- yomemoai_mcp/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
- yomemoai_mcp/server.py,sha256=60n1uXeWV9gEmnimjZNdK4xCixSTrNYAqZ8zAwugeoc,5242
5
- yomemoai_mcp-0.1.3.dist-info/METADATA,sha256=ceULHtnbq_kf1FAC4y1pYjrypbIMxaHQCgDUhqZL3yE,7551
6
- yomemoai_mcp-0.1.3.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
7
- yomemoai_mcp-0.1.3.dist-info/entry_points.txt,sha256=uV0479NK4ppOUV1T9VSwFTLi87F4deaRjbL8s43R8uI,100
8
- yomemoai_mcp-0.1.3.dist-info/licenses/LICENSE,sha256=UVt2r_C3iy7rNKJAj_EcLcmcZdXONxJ01oJNsIEqTfw,1066
9
- yomemoai_mcp-0.1.3.dist-info/RECORD,,