awslabs.valkey-mcp-server 0.1.1__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.
- awslabs/__init__.py +13 -0
- awslabs/valkey_mcp_server/__init__.py +14 -0
- awslabs/valkey_mcp_server/common/__init__.py +20 -0
- awslabs/valkey_mcp_server/common/config.py +85 -0
- awslabs/valkey_mcp_server/common/connection.py +97 -0
- awslabs/valkey_mcp_server/common/server.py +23 -0
- awslabs/valkey_mcp_server/main.py +84 -0
- awslabs/valkey_mcp_server/tools/__init__.py +28 -0
- awslabs/valkey_mcp_server/tools/bitmap.py +148 -0
- awslabs/valkey_mcp_server/tools/hash.py +283 -0
- awslabs/valkey_mcp_server/tools/hyperloglog.py +58 -0
- awslabs/valkey_mcp_server/tools/json.py +422 -0
- awslabs/valkey_mcp_server/tools/list.py +376 -0
- awslabs/valkey_mcp_server/tools/misc.py +104 -0
- awslabs/valkey_mcp_server/tools/server_management.py +54 -0
- awslabs/valkey_mcp_server/tools/set.py +182 -0
- awslabs/valkey_mcp_server/tools/sorted_set.py +359 -0
- awslabs/valkey_mcp_server/tools/stream.py +343 -0
- awslabs/valkey_mcp_server/tools/string.py +228 -0
- awslabs/valkey_mcp_server/version.py +12 -0
- awslabs_valkey_mcp_server-0.1.1.dist-info/METADATA +164 -0
- awslabs_valkey_mcp_server-0.1.1.dist-info/RECORD +26 -0
- awslabs_valkey_mcp_server-0.1.1.dist-info/WHEEL +4 -0
- awslabs_valkey_mcp_server-0.1.1.dist-info/entry_points.txt +2 -0
- awslabs_valkey_mcp_server-0.1.1.dist-info/licenses/LICENSE +175 -0
- awslabs_valkey_mcp_server-0.1.1.dist-info/licenses/NOTICE +2 -0
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance
|
|
4
|
+
# with the License. A copy of the License is located at
|
|
5
|
+
#
|
|
6
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
+
#
|
|
8
|
+
# or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES
|
|
9
|
+
# OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions
|
|
10
|
+
# and limitations under the License.
|
|
11
|
+
|
|
12
|
+
"""Set operations for Valkey MCP Server."""
|
|
13
|
+
|
|
14
|
+
from awslabs.valkey_mcp_server.common.connection import ValkeyConnectionManager
|
|
15
|
+
from awslabs.valkey_mcp_server.common.server import mcp
|
|
16
|
+
from typing import Any, Optional
|
|
17
|
+
from valkey.exceptions import ValkeyError
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@mcp.tool()
|
|
21
|
+
async def set_add(key: str, member: str) -> str:
|
|
22
|
+
"""Add member to set.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
key: The name of the key
|
|
26
|
+
member: Member to add
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
Success message or error message
|
|
30
|
+
"""
|
|
31
|
+
try:
|
|
32
|
+
r = ValkeyConnectionManager.get_connection()
|
|
33
|
+
result = r.sadd(key, member)
|
|
34
|
+
return f"Successfully added {result} new member to set '{key}'"
|
|
35
|
+
except ValkeyError as e:
|
|
36
|
+
return f"Error adding to set '{key}': {str(e)}"
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@mcp.tool()
|
|
40
|
+
async def set_remove(key: str, member: str) -> str:
|
|
41
|
+
"""Remove member from set.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
key: The name of the key
|
|
45
|
+
member: Member to remove
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
Success message or error message
|
|
49
|
+
"""
|
|
50
|
+
try:
|
|
51
|
+
r = ValkeyConnectionManager.get_connection()
|
|
52
|
+
result = r.srem(key, member)
|
|
53
|
+
return f"Successfully removed {result} member from set '{key}'"
|
|
54
|
+
except ValkeyError as e:
|
|
55
|
+
return f"Error removing from set '{key}': {str(e)}"
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@mcp.tool()
|
|
59
|
+
async def set_pop(key: str, count: Optional[int] = None) -> str:
|
|
60
|
+
"""Remove and return random member(s) from set.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
key: The name of the key
|
|
64
|
+
count: Number of members to pop (optional)
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
Popped member(s) or error message
|
|
68
|
+
"""
|
|
69
|
+
try:
|
|
70
|
+
r = ValkeyConnectionManager.get_connection()
|
|
71
|
+
if count:
|
|
72
|
+
result = r.spop(key, count)
|
|
73
|
+
else:
|
|
74
|
+
result = r.spop(key)
|
|
75
|
+
if result is None:
|
|
76
|
+
return f"Set '{key}' is empty"
|
|
77
|
+
return str(result)
|
|
78
|
+
except ValkeyError as e:
|
|
79
|
+
return f"Error popping from set '{key}': {str(e)}"
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
@mcp.tool()
|
|
83
|
+
async def set_move(source: str, destination: str, member: Any) -> str:
|
|
84
|
+
"""Move member from one set to another.
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
source: Source set key
|
|
88
|
+
destination: Destination set key
|
|
89
|
+
member: Member to move
|
|
90
|
+
|
|
91
|
+
Returns:
|
|
92
|
+
Success message or error message
|
|
93
|
+
"""
|
|
94
|
+
try:
|
|
95
|
+
r = ValkeyConnectionManager.get_connection()
|
|
96
|
+
result = r.smove(source, destination, member)
|
|
97
|
+
if result:
|
|
98
|
+
return f"Successfully moved member from set '{source}' to '{destination}'"
|
|
99
|
+
return f"Member not found in source set '{source}'"
|
|
100
|
+
except ValkeyError as e:
|
|
101
|
+
return f'Error moving between sets: {str(e)}'
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
@mcp.tool()
|
|
105
|
+
async def set_cardinality(key: str) -> str:
|
|
106
|
+
"""Get number of members in set.
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
key: The name of the key
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
Number of members or error message
|
|
113
|
+
"""
|
|
114
|
+
try:
|
|
115
|
+
r = ValkeyConnectionManager.get_connection()
|
|
116
|
+
result = r.scard(key)
|
|
117
|
+
return str(result)
|
|
118
|
+
except ValkeyError as e:
|
|
119
|
+
return f"Error getting set cardinality for '{key}': {str(e)}"
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
@mcp.tool()
|
|
123
|
+
async def set_members(key: str) -> str:
|
|
124
|
+
"""Get all members in set.
|
|
125
|
+
|
|
126
|
+
Args:
|
|
127
|
+
key: The name of the key
|
|
128
|
+
|
|
129
|
+
Returns:
|
|
130
|
+
List of members or error message
|
|
131
|
+
"""
|
|
132
|
+
try:
|
|
133
|
+
r = ValkeyConnectionManager.get_connection()
|
|
134
|
+
result = r.smembers(key)
|
|
135
|
+
if not result:
|
|
136
|
+
return f"Set '{key}' is empty"
|
|
137
|
+
return str(result)
|
|
138
|
+
except ValkeyError as e:
|
|
139
|
+
return f"Error getting set members from '{key}': {str(e)}"
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
@mcp.tool()
|
|
143
|
+
async def set_random_member(key: str, count: Optional[int] = None) -> str:
|
|
144
|
+
"""Get random member(s) from set without removing.
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
key: The name of the key
|
|
148
|
+
count: Number of members to return (optional)
|
|
149
|
+
|
|
150
|
+
Returns:
|
|
151
|
+
Random member(s) or error message
|
|
152
|
+
"""
|
|
153
|
+
try:
|
|
154
|
+
r = ValkeyConnectionManager.get_connection()
|
|
155
|
+
if count:
|
|
156
|
+
result = r.srandmember(key, count)
|
|
157
|
+
else:
|
|
158
|
+
result = r.srandmember(key)
|
|
159
|
+
if result is None:
|
|
160
|
+
return f"Set '{key}' is empty"
|
|
161
|
+
return str(result)
|
|
162
|
+
except ValkeyError as e:
|
|
163
|
+
return f"Error getting random member from set '{key}': {str(e)}"
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
@mcp.tool()
|
|
167
|
+
async def set_contains(key: str, member: Any) -> str:
|
|
168
|
+
"""Check if member exists in set.
|
|
169
|
+
|
|
170
|
+
Args:
|
|
171
|
+
key: The name of the key
|
|
172
|
+
member: Member to check
|
|
173
|
+
|
|
174
|
+
Returns:
|
|
175
|
+
Boolean result or error message
|
|
176
|
+
"""
|
|
177
|
+
try:
|
|
178
|
+
r = ValkeyConnectionManager.get_connection()
|
|
179
|
+
result = r.sismember(key, member)
|
|
180
|
+
return str(result).lower()
|
|
181
|
+
except ValkeyError as e:
|
|
182
|
+
return f"Error checking set membership in '{key}': {str(e)}"
|
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance
|
|
4
|
+
# with the License. A copy of the License is located at
|
|
5
|
+
#
|
|
6
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
+
#
|
|
8
|
+
# or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES
|
|
9
|
+
# OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions
|
|
10
|
+
# and limitations under the License.
|
|
11
|
+
|
|
12
|
+
"""Sorted Set operations for Valkey MCP Server."""
|
|
13
|
+
|
|
14
|
+
from awslabs.valkey_mcp_server.common.connection import ValkeyConnectionManager
|
|
15
|
+
from awslabs.valkey_mcp_server.common.server import mcp
|
|
16
|
+
from typing import Any, Dict, Optional
|
|
17
|
+
from valkey.exceptions import ValkeyError
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@mcp.tool()
|
|
21
|
+
async def sorted_set_add(key: str, mapping: Dict[Any, float]) -> str:
|
|
22
|
+
"""Add member-score pairs to sorted set.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
key: The name of the key
|
|
26
|
+
mapping: Dictionary of member-score pairs
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
Success message or error message
|
|
30
|
+
"""
|
|
31
|
+
try:
|
|
32
|
+
r = ValkeyConnectionManager.get_connection()
|
|
33
|
+
result = r.zadd(key, mapping)
|
|
34
|
+
return f"Successfully added {result} new member(s) to sorted set '{key}'"
|
|
35
|
+
except ValkeyError as e:
|
|
36
|
+
return f"Error adding to sorted set '{key}': {str(e)}"
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@mcp.tool()
|
|
40
|
+
async def sorted_set_add_incr(key: str, member: Any, score: float) -> str:
|
|
41
|
+
"""Add member to sorted set or increment its score.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
key: The name of the key
|
|
45
|
+
member: The member to add/update
|
|
46
|
+
score: Score to add to existing score (or initial score)
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
Success message or error message
|
|
50
|
+
"""
|
|
51
|
+
try:
|
|
52
|
+
r = ValkeyConnectionManager.get_connection()
|
|
53
|
+
result = r.zincrby(key, score, member)
|
|
54
|
+
return f"Successfully set score for member in sorted set '{key}' to {result}"
|
|
55
|
+
except ValkeyError as e:
|
|
56
|
+
return f"Error incrementing score in sorted set '{key}': {str(e)}"
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@mcp.tool()
|
|
60
|
+
async def sorted_set_remove(key: str, *members: Any) -> str:
|
|
61
|
+
"""Remove member(s) from sorted set.
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
key: The name of the key
|
|
65
|
+
*members: Members to remove
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
Success message or error message
|
|
69
|
+
"""
|
|
70
|
+
try:
|
|
71
|
+
r = ValkeyConnectionManager.get_connection()
|
|
72
|
+
result = r.zrem(key, *members)
|
|
73
|
+
return f"Successfully removed {result} member(s) from sorted set '{key}'"
|
|
74
|
+
except ValkeyError as e:
|
|
75
|
+
return f"Error removing from sorted set '{key}': {str(e)}"
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
@mcp.tool()
|
|
79
|
+
async def sorted_set_remove_by_rank(key: str, start: int, stop: int) -> str:
|
|
80
|
+
"""Remove members by rank range.
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
key: The name of the key
|
|
84
|
+
start: Start rank (inclusive)
|
|
85
|
+
stop: Stop rank (inclusive)
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
Success message or error message
|
|
89
|
+
"""
|
|
90
|
+
try:
|
|
91
|
+
r = ValkeyConnectionManager.get_connection()
|
|
92
|
+
result = r.zremrangebyrank(key, start, stop)
|
|
93
|
+
return f"Successfully removed {result} member(s) by rank from sorted set '{key}'"
|
|
94
|
+
except ValkeyError as e:
|
|
95
|
+
return f"Error removing by rank from sorted set '{key}': {str(e)}"
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
@mcp.tool()
|
|
99
|
+
async def sorted_set_remove_by_score(key: str, min_score: float, max_score: float) -> str:
|
|
100
|
+
"""Remove members by score range.
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
key: The name of the key
|
|
104
|
+
min_score: Minimum score (inclusive)
|
|
105
|
+
max_score: Maximum score (inclusive)
|
|
106
|
+
|
|
107
|
+
Returns:
|
|
108
|
+
Success message or error message
|
|
109
|
+
"""
|
|
110
|
+
try:
|
|
111
|
+
r = ValkeyConnectionManager.get_connection()
|
|
112
|
+
result = r.zremrangebyscore(key, min_score, max_score)
|
|
113
|
+
return f"Successfully removed {result} member(s) by score from sorted set '{key}'"
|
|
114
|
+
except ValkeyError as e:
|
|
115
|
+
return f"Error removing by score from sorted set '{key}': {str(e)}"
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
@mcp.tool()
|
|
119
|
+
async def sorted_set_remove_by_lex(key: str, min_lex: str, max_lex: str) -> str:
|
|
120
|
+
"""Remove members by lexicographical range.
|
|
121
|
+
|
|
122
|
+
Args:
|
|
123
|
+
key: The name of the key
|
|
124
|
+
min_lex: Minimum value (inclusive)
|
|
125
|
+
max_lex: Maximum value (inclusive)
|
|
126
|
+
|
|
127
|
+
Returns:
|
|
128
|
+
Success message or error message
|
|
129
|
+
"""
|
|
130
|
+
try:
|
|
131
|
+
r = ValkeyConnectionManager.get_connection()
|
|
132
|
+
result = r.zremrangebylex(key, min_lex, max_lex)
|
|
133
|
+
return f"Successfully removed {result} member(s) by lex range from sorted set '{key}'"
|
|
134
|
+
except ValkeyError as e:
|
|
135
|
+
return f"Error removing by lex range from sorted set '{key}': {str(e)}"
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
@mcp.tool()
|
|
139
|
+
async def sorted_set_cardinality(
|
|
140
|
+
key: str, min_score: Optional[float] = None, max_score: Optional[float] = None
|
|
141
|
+
) -> str:
|
|
142
|
+
"""Get number of members in sorted set.
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
key: The name of the key
|
|
146
|
+
min_score: Minimum score (optional)
|
|
147
|
+
max_score: Maximum score (optional)
|
|
148
|
+
|
|
149
|
+
Returns:
|
|
150
|
+
Number of members or error message
|
|
151
|
+
"""
|
|
152
|
+
try:
|
|
153
|
+
r = ValkeyConnectionManager.get_connection()
|
|
154
|
+
if min_score is not None and max_score is not None:
|
|
155
|
+
result = r.zcount(key, min_score, max_score)
|
|
156
|
+
else:
|
|
157
|
+
result = r.zcard(key)
|
|
158
|
+
return str(result)
|
|
159
|
+
except ValkeyError as e:
|
|
160
|
+
return f"Error getting sorted set cardinality for '{key}': {str(e)}"
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
@mcp.tool()
|
|
164
|
+
async def sorted_set_score(key: str, member: Any) -> str:
|
|
165
|
+
"""Get score of member in sorted set.
|
|
166
|
+
|
|
167
|
+
Args:
|
|
168
|
+
key: The name of the key
|
|
169
|
+
member: The member to get score for
|
|
170
|
+
|
|
171
|
+
Returns:
|
|
172
|
+
Score or error message
|
|
173
|
+
"""
|
|
174
|
+
try:
|
|
175
|
+
r = ValkeyConnectionManager.get_connection()
|
|
176
|
+
result = r.zscore(key, member)
|
|
177
|
+
if result is None:
|
|
178
|
+
return f"Member not found in sorted set '{key}'"
|
|
179
|
+
return str(result)
|
|
180
|
+
except ValkeyError as e:
|
|
181
|
+
return f"Error getting score from sorted set '{key}': {str(e)}"
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
@mcp.tool()
|
|
185
|
+
async def sorted_set_rank(key: str, member: Any, reverse: bool = False) -> str:
|
|
186
|
+
"""Get rank of member in sorted set.
|
|
187
|
+
|
|
188
|
+
Args:
|
|
189
|
+
key: The name of the key
|
|
190
|
+
member: The member to get rank for
|
|
191
|
+
reverse: If True, get rank in reverse order (highest first)
|
|
192
|
+
|
|
193
|
+
Returns:
|
|
194
|
+
Rank or error message
|
|
195
|
+
"""
|
|
196
|
+
try:
|
|
197
|
+
r = ValkeyConnectionManager.get_connection()
|
|
198
|
+
if reverse:
|
|
199
|
+
result = r.zrevrank(key, member)
|
|
200
|
+
else:
|
|
201
|
+
result = r.zrank(key, member)
|
|
202
|
+
if result is None:
|
|
203
|
+
return f"Member not found in sorted set '{key}'"
|
|
204
|
+
return str(result)
|
|
205
|
+
except ValkeyError as e:
|
|
206
|
+
return f"Error getting rank from sorted set '{key}': {str(e)}"
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
@mcp.tool()
|
|
210
|
+
async def sorted_set_range(
|
|
211
|
+
key: str, start: int = 0, stop: int = -1, withscores: bool = False, reverse: bool = False
|
|
212
|
+
) -> str:
|
|
213
|
+
"""Get range of members from sorted set.
|
|
214
|
+
|
|
215
|
+
Args:
|
|
216
|
+
key: The name of the key
|
|
217
|
+
start: Start index (inclusive)
|
|
218
|
+
stop: Stop index (inclusive)
|
|
219
|
+
withscores: Include scores in result
|
|
220
|
+
reverse: Return results in reverse order
|
|
221
|
+
|
|
222
|
+
Returns:
|
|
223
|
+
List of members (with scores if requested) or error message
|
|
224
|
+
"""
|
|
225
|
+
try:
|
|
226
|
+
r = ValkeyConnectionManager.get_connection()
|
|
227
|
+
if reverse:
|
|
228
|
+
result = r.zrevrange(key, start, stop, withscores=withscores)
|
|
229
|
+
else:
|
|
230
|
+
result = r.zrange(key, start, stop, withscores=withscores)
|
|
231
|
+
if not result:
|
|
232
|
+
return f"No members found in range for sorted set '{key}'"
|
|
233
|
+
return str(result)
|
|
234
|
+
except ValkeyError as e:
|
|
235
|
+
return f"Error getting range from sorted set '{key}': {str(e)}"
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
@mcp.tool()
|
|
239
|
+
async def sorted_set_range_by_score(
|
|
240
|
+
key: str,
|
|
241
|
+
min_score: float,
|
|
242
|
+
max_score: float,
|
|
243
|
+
withscores: bool = False,
|
|
244
|
+
reverse: bool = False,
|
|
245
|
+
offset: Optional[int] = None,
|
|
246
|
+
count: Optional[int] = None,
|
|
247
|
+
) -> str:
|
|
248
|
+
"""Get range of members by score.
|
|
249
|
+
|
|
250
|
+
Args:
|
|
251
|
+
key: The name of the key
|
|
252
|
+
min_score: Minimum score (inclusive)
|
|
253
|
+
max_score: Maximum score (inclusive)
|
|
254
|
+
withscores: Include scores in result
|
|
255
|
+
reverse: Return results in reverse order
|
|
256
|
+
offset: Number of members to skip
|
|
257
|
+
count: Maximum number of members to return
|
|
258
|
+
|
|
259
|
+
Returns:
|
|
260
|
+
List of members (with scores if requested) or error message
|
|
261
|
+
"""
|
|
262
|
+
try:
|
|
263
|
+
r = ValkeyConnectionManager.get_connection()
|
|
264
|
+
if reverse:
|
|
265
|
+
result = r.zrevrangebyscore(
|
|
266
|
+
key, max_score, min_score, withscores=withscores, start=offset, num=count
|
|
267
|
+
)
|
|
268
|
+
else:
|
|
269
|
+
result = r.zrangebyscore(
|
|
270
|
+
key, min_score, max_score, withscores=withscores, start=offset, num=count
|
|
271
|
+
)
|
|
272
|
+
if not result:
|
|
273
|
+
return f"No members found in score range for sorted set '{key}'"
|
|
274
|
+
return str(result)
|
|
275
|
+
except ValkeyError as e:
|
|
276
|
+
return f"Error getting score range from sorted set '{key}': {str(e)}"
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
@mcp.tool()
|
|
280
|
+
async def sorted_set_range_by_lex(
|
|
281
|
+
key: str,
|
|
282
|
+
min_lex: str,
|
|
283
|
+
max_lex: str,
|
|
284
|
+
reverse: bool = False,
|
|
285
|
+
offset: Optional[int] = None,
|
|
286
|
+
count: Optional[int] = None,
|
|
287
|
+
) -> str:
|
|
288
|
+
"""Get range of members by lexicographical order.
|
|
289
|
+
|
|
290
|
+
Args:
|
|
291
|
+
key: The name of the key
|
|
292
|
+
min_lex: Minimum value (inclusive)
|
|
293
|
+
max_lex: Maximum value (inclusive)
|
|
294
|
+
reverse: Return results in reverse order
|
|
295
|
+
offset: Number of members to skip
|
|
296
|
+
count: Maximum number of members to return
|
|
297
|
+
|
|
298
|
+
Returns:
|
|
299
|
+
List of members or error message
|
|
300
|
+
"""
|
|
301
|
+
try:
|
|
302
|
+
r = ValkeyConnectionManager.get_connection()
|
|
303
|
+
if reverse:
|
|
304
|
+
result = r.zrevrangebylex(key, max_lex, min_lex, start=offset, num=count)
|
|
305
|
+
else:
|
|
306
|
+
result = r.zrangebylex(key, min_lex, max_lex, start=offset, num=count)
|
|
307
|
+
if not result:
|
|
308
|
+
return f"No members found in lex range for sorted set '{key}'"
|
|
309
|
+
return str(result)
|
|
310
|
+
except ValkeyError as e:
|
|
311
|
+
return f"Error getting lex range from sorted set '{key}': {str(e)}"
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
@mcp.tool()
|
|
315
|
+
async def sorted_set_popmin(key: str, count: Optional[int] = None) -> str:
|
|
316
|
+
"""Remove and return members with lowest scores.
|
|
317
|
+
|
|
318
|
+
Args:
|
|
319
|
+
key: The name of the key
|
|
320
|
+
count: Number of members to pop (optional)
|
|
321
|
+
|
|
322
|
+
Returns:
|
|
323
|
+
Popped members with scores or error message
|
|
324
|
+
"""
|
|
325
|
+
try:
|
|
326
|
+
r = ValkeyConnectionManager.get_connection()
|
|
327
|
+
if count:
|
|
328
|
+
result = r.zpopmin(key, count)
|
|
329
|
+
else:
|
|
330
|
+
result = r.zpopmin(key)
|
|
331
|
+
if not result:
|
|
332
|
+
return f"Sorted set '{key}' is empty"
|
|
333
|
+
return str(result)
|
|
334
|
+
except ValkeyError as e:
|
|
335
|
+
return f"Error popping min from sorted set '{key}': {str(e)}"
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
@mcp.tool()
|
|
339
|
+
async def sorted_set_popmax(key: str, count: Optional[int] = None) -> str:
|
|
340
|
+
"""Remove and return members with highest scores.
|
|
341
|
+
|
|
342
|
+
Args:
|
|
343
|
+
key: The name of the key
|
|
344
|
+
count: Number of members to pop (optional)
|
|
345
|
+
|
|
346
|
+
Returns:
|
|
347
|
+
Popped members with scores or error message
|
|
348
|
+
"""
|
|
349
|
+
try:
|
|
350
|
+
r = ValkeyConnectionManager.get_connection()
|
|
351
|
+
if count:
|
|
352
|
+
result = r.zpopmax(key, count)
|
|
353
|
+
else:
|
|
354
|
+
result = r.zpopmax(key)
|
|
355
|
+
if not result:
|
|
356
|
+
return f"Sorted set '{key}' is empty"
|
|
357
|
+
return str(result)
|
|
358
|
+
except ValkeyError as e:
|
|
359
|
+
return f"Error popping max from sorted set '{key}': {str(e)}"
|