mem-brain-mcp 1.0.6__py3-none-any.whl → 1.0.7__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.
mem_brain_mcp/client.py CHANGED
@@ -1,7 +1,7 @@
1
1
  """HTTP client for Mem-Brain API."""
2
2
 
3
3
  import logging
4
- from typing import List, Optional, Dict, Any
4
+ from typing import List, Optional, Dict, Any, Union
5
5
  import httpx
6
6
 
7
7
  from mem_brain_mcp.config import settings
@@ -34,12 +34,7 @@ class APIClient:
34
34
  logger.debug("No authentication token configured for this client instance")
35
35
  return headers
36
36
 
37
- async def _request(
38
- self,
39
- method: str,
40
- endpoint: str,
41
- **kwargs
42
- ) -> Dict[str, Any]:
37
+ async def _request(self, method: str, endpoint: str, **kwargs) -> Dict[str, Any]:
43
38
  """Make HTTP request to API.
44
39
 
45
40
  Args:
@@ -56,10 +51,12 @@ class APIClient:
56
51
  url = f"{self.base_url}/{endpoint.lstrip('/')}"
57
52
  headers = self._get_headers()
58
53
  headers.update(kwargs.pop("headers", {}))
59
-
54
+
60
55
  # Debug logging for request details
61
56
  logger.debug(f"Making {method} request to: {url}")
62
- logger.debug(f"Headers: {dict((k, v[:20] + '...' if k == 'Authorization' and len(v) > 20 else v) for k, v in headers.items())}")
57
+ logger.debug(
58
+ f"Headers: {dict((k, v[:20] + '...' if k == 'Authorization' and len(v) > 20 else v) for k, v in headers.items())}"
59
+ )
63
60
  if kwargs.get("json"):
64
61
  logger.debug(f"Request body: {kwargs.get('json')}")
65
62
  if kwargs.get("params"):
@@ -67,33 +64,29 @@ class APIClient:
67
64
 
68
65
  async with httpx.AsyncClient(timeout=30.0) as client:
69
66
  try:
70
- response = await client.request(
71
- method=method,
72
- url=url,
73
- headers=headers,
74
- **kwargs
75
- )
67
+ response = await client.request(method=method, url=url, headers=headers, **kwargs)
76
68
  logger.debug(f"Response status: {response.status_code}")
77
69
  logger.debug(f"Response headers: {dict(response.headers)}")
78
-
70
+
79
71
  try:
80
72
  response.raise_for_status()
81
73
  result = response.json()
82
- logger.debug(f"Response data keys: {list(result.keys()) if isinstance(result, dict) else 'N/A'}")
74
+ logger.debug(
75
+ f"Response data keys: {list(result.keys()) if isinstance(result, dict) else 'N/A'}"
76
+ )
83
77
  return result
84
78
  except httpx.HTTPStatusError as e:
85
79
  error_detail = e.response.text if e.response else "No response body"
86
- logger.error(f"API request failed: {e.request.method} {e.request.url} - {e.response.status_code}: {error_detail}")
80
+ logger.error(
81
+ f"API request failed: {e.request.method} {e.request.url} - {e.response.status_code}: {error_detail}"
82
+ )
87
83
  raise
88
84
  except httpx.RequestError as e:
89
85
  logger.error(f"Request error: {type(e).__name__}: {str(e)}")
90
86
  raise
91
87
 
92
88
  async def add_memory(
93
- self,
94
- content: str,
95
- tags: Optional[List[str]] = None,
96
- category: Optional[str] = None
89
+ self, content: str, tags: Optional[List[str]] = None, category: Optional[str] = None
97
90
  ) -> Dict[str, Any]:
98
91
  """Add a new memory.
99
92
 
@@ -114,26 +107,24 @@ class APIClient:
114
107
  return await self._request("POST", "/memories", json=data)
115
108
 
116
109
  async def search_memories(
117
- self,
118
- query: str,
119
- k: int = 5
110
+ self, query: str, k: int = 5, keyword_filter: Optional[Union[str, List[str]]] = None
120
111
  ) -> Dict[str, Any]:
121
112
  """Search memories using semantic similarity.
122
113
 
123
114
  Args:
124
115
  query: Search query string
125
116
  k: Number of results to return (1-100)
117
+ keyword_filter: Optional keyword/tag filter (regex supported)
126
118
 
127
119
  Returns:
128
120
  Search results
129
121
  """
130
122
  data = {"query": query, "k": k}
123
+ if keyword_filter:
124
+ data["keyword_filter"] = keyword_filter
131
125
  return await self._request("POST", "/memories/search", json=data)
132
126
 
133
- async def get_memories(
134
- self,
135
- memory_ids: List[str]
136
- ) -> Dict[str, Any]:
127
+ async def get_memories(self, memory_ids: List[str]) -> Dict[str, Any]:
137
128
  """Retrieve multiple memories by ID.
138
129
 
139
130
  Args:
@@ -146,10 +137,7 @@ class APIClient:
146
137
  return await self._request("POST", "/memories/batch", json=data)
147
138
 
148
139
  async def update_memory(
149
- self,
150
- memory_id: str,
151
- content: Optional[str] = None,
152
- tags: Optional[List[str]] = None
140
+ self, memory_id: str, content: Optional[str] = None, tags: Optional[List[str]] = None
153
141
  ) -> Dict[str, Any]:
154
142
  """Update an existing memory.
155
143
 
@@ -173,7 +161,7 @@ class APIClient:
173
161
  self,
174
162
  memory_id: Optional[str] = None,
175
163
  tags: Optional[str] = None,
176
- category: Optional[str] = None
164
+ category: Optional[str] = None,
177
165
  ) -> Dict[str, Any]:
178
166
  """Delete memories by ID or filter.
179
167
 
@@ -195,11 +183,7 @@ class APIClient:
195
183
 
196
184
  return await self._request("DELETE", "/memories/bulk", params=params)
197
185
 
198
- async def unlink_memories(
199
- self,
200
- memory_id_1: str,
201
- memory_id_2: str
202
- ) -> Dict[str, Any]:
186
+ async def unlink_memories(self, memory_id_1: str, memory_id_2: str) -> Dict[str, Any]:
203
187
  """Remove link between two memories.
204
188
 
205
189
  Args:
@@ -209,10 +193,7 @@ class APIClient:
209
193
  Returns:
210
194
  Unlink response
211
195
  """
212
- data = {
213
- "memory_id_1": memory_id_1,
214
- "memory_id_2": memory_id_2
215
- }
196
+ data = {"memory_id_1": memory_id_1, "memory_id_2": memory_id_2}
216
197
  return await self._request("POST", "/memories/unlink", json=data)
217
198
 
218
199
  async def get_stats(self) -> Dict[str, Any]:
@@ -224,11 +205,7 @@ class APIClient:
224
205
  logger.debug("get_stats() called - making request to /stats endpoint")
225
206
  return await self._request("GET", "/stats")
226
207
 
227
- async def find_path(
228
- self,
229
- from_id: str,
230
- to_id: str
231
- ) -> Dict[str, Any]:
208
+ async def find_path(self, from_id: str, to_id: str) -> Dict[str, Any]:
232
209
  """Find shortest path between two memories.
233
210
 
234
211
  Args:
@@ -241,11 +218,7 @@ class APIClient:
241
218
  params = {"from_id": from_id, "to_id": to_id}
242
219
  return await self._request("GET", "/graph/path", params=params)
243
220
 
244
- async def get_neighborhood(
245
- self,
246
- memory_id: str,
247
- hops: int = 2
248
- ) -> Dict[str, Any]:
221
+ async def get_neighborhood(self, memory_id: str, hops: int = 2) -> Dict[str, Any]:
249
222
  """Get all memories within N hops of a given memory.
250
223
 
251
224
  Args:
@@ -257,4 +230,3 @@ class APIClient:
257
230
  """
258
231
  params = {"memory_id": memory_id, "hops": hops}
259
232
  return await self._request("GET", "/graph/neighborhood", params=params)
260
-