@@ -136,3 +136,102 @@ async def vector_search_hash(query_vector: list,
136
136
return [doc .__dict__ for doc in results .docs ]
137
137
except RedisError as e :
138
138
return f"Error performing vector search on index '{ index_name } ': { str (e )} "
139
+
140
+
141
+ @mcp .tool ()
142
+ async def get_all_keys (pattern : str = "*" ) -> list :
143
+ """
144
+ Retrieve all keys matching a pattern from the Redis database using the KEYS command.
145
+
146
+ Note: The KEYS command is blocking and can impact performance on large databases.
147
+ For production use with large datasets, consider using SCAN instead.
148
+
149
+ Args:
150
+ pattern: Pattern to match keys against (default is "*" for all keys).
151
+ Common patterns: "user:*", "cache:*", "*:123", etc.
152
+
153
+ Returns:
154
+ A list of keys matching the pattern or an error message.
155
+ """
156
+ try :
157
+ r = RedisConnectionManager .get_connection ()
158
+ keys = r .keys (pattern )
159
+ # Convert bytes to strings if needed
160
+ return [key .decode ('utf-8' ) if isinstance (key , bytes ) else key for key in keys ]
161
+ except RedisError as e :
162
+ return f"Error retrieving keys with pattern '{ pattern } ': { str (e )} "
163
+
164
+
165
+ @mcp .tool ()
166
+ async def scan_keys (pattern : str = "*" , count : int = 100 , cursor : int = 0 ) -> dict :
167
+ """
168
+ Scan keys in the Redis database using the SCAN command (non-blocking, production-safe).
169
+
170
+ The SCAN command iterates through the keyspace in small chunks, making it safe to use
171
+ on large databases without blocking other operations.
172
+
173
+ Args:
174
+ pattern: Pattern to match keys against (default is "*" for all keys).
175
+ Common patterns: "user:*", "cache:*", "*:123", etc.
176
+ count: Hint for the number of keys to return per iteration (default 100).
177
+ Redis may return more or fewer keys than this hint.
178
+ cursor: The cursor position to start scanning from (0 to start from beginning).
179
+
180
+ Returns:
181
+ A dictionary containing:
182
+ - 'cursor': Next cursor position (0 means scan is complete)
183
+ - 'keys': List of keys found in this iteration
184
+ - 'total_scanned': Number of keys returned in this batch
185
+ Or an error message if something goes wrong.
186
+ """
187
+ try :
188
+ r = RedisConnectionManager .get_connection ()
189
+ cursor , keys = r .scan (cursor = cursor , match = pattern , count = count )
190
+
191
+ # Convert bytes to strings if needed
192
+ decoded_keys = [key .decode ('utf-8' ) if isinstance (key , bytes ) else key for key in keys ]
193
+
194
+ return {
195
+ 'cursor' : cursor ,
196
+ 'keys' : decoded_keys ,
197
+ 'total_scanned' : len (decoded_keys ),
198
+ 'scan_complete' : cursor == 0
199
+ }
200
+ except RedisError as e :
201
+ return f"Error scanning keys with pattern '{ pattern } ': { str (e )} "
202
+
203
+
204
+ @mcp .tool ()
205
+ async def scan_all_keys (pattern : str = "*" , batch_size : int = 100 ) -> list :
206
+ """
207
+ Scan and return ALL keys matching a pattern using multiple SCAN iterations.
208
+
209
+ This function automatically handles the SCAN cursor iteration to collect all matching keys.
210
+ It's safer than KEYS * for large databases but will still collect all results in memory.
211
+
212
+ Args:
213
+ pattern: Pattern to match keys against (default is "*" for all keys).
214
+ batch_size: Number of keys to scan per iteration (default 100).
215
+
216
+ Returns:
217
+ A list of all keys matching the pattern or an error message.
218
+ """
219
+ try :
220
+ r = RedisConnectionManager .get_connection ()
221
+ all_keys = []
222
+ cursor = 0
223
+
224
+ while True :
225
+ cursor , keys = r .scan (cursor = cursor , match = pattern , count = batch_size )
226
+
227
+ # Convert bytes to strings if needed and add to results
228
+ decoded_keys = [key .decode ('utf-8' ) if isinstance (key , bytes ) else key for key in keys ]
229
+ all_keys .extend (decoded_keys )
230
+
231
+ # Break when scan is complete (cursor returns to 0)
232
+ if cursor == 0 :
233
+ break
234
+
235
+ return all_keys
236
+ except RedisError as e :
237
+ return f"Error scanning all keys with pattern '{ pattern } ': { str (e )} "
0 commit comments