mzcache-mcp-server 0.1.0__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.
- mzcache_mcp/__init__.py +0 -0
- mzcache_mcp/bin/mzcache_engine_linux +0 -0
- mzcache_mcp/main.py +735 -0
- mzcache_mcp_server-0.1.0.data/data/mzcache_mcp/bin/mzcache_engine_linux +0 -0
- mzcache_mcp_server-0.1.0.dist-info/METADATA +10 -0
- mzcache_mcp_server-0.1.0.dist-info/RECORD +8 -0
- mzcache_mcp_server-0.1.0.dist-info/WHEEL +4 -0
- mzcache_mcp_server-0.1.0.dist-info/entry_points.txt +2 -0
mzcache_mcp/__init__.py
ADDED
|
File without changes
|
|
Binary file
|
mzcache_mcp/main.py
ADDED
|
@@ -0,0 +1,735 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
import asyncio
|
|
4
|
+
import subprocess
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from mcp.server.models import InitializationOptions
|
|
7
|
+
from mcp.server import NotificationOptions, Server
|
|
8
|
+
import mcp.types as types
|
|
9
|
+
from mcp.server.stdio import stdio_server
|
|
10
|
+
|
|
11
|
+
# Import your client here. Assuming it's in a file called mzcache_client.py
|
|
12
|
+
from mzcache import MzCacheClient, MzCacheConnectionError, MzCacheServerError
|
|
13
|
+
|
|
14
|
+
# Configure the target location for your C++ Engine
|
|
15
|
+
SERVER_HOST = "127.0.0.1"
|
|
16
|
+
SERVER_PORT = 6379
|
|
17
|
+
|
|
18
|
+
# Initialize the MCP Server
|
|
19
|
+
server = Server("mzcache-engine-server")
|
|
20
|
+
|
|
21
|
+
def execute_engine_cmd(func_name: str, *args, **kwargs) -> str:
|
|
22
|
+
"""Helper to safely manage connection lifecycle for each tool invocation."""
|
|
23
|
+
client = MzCacheClient(host=SERVER_HOST, port=SERVER_PORT)
|
|
24
|
+
try:
|
|
25
|
+
with client as connected_client:
|
|
26
|
+
method = getattr(connected_client, func_name)
|
|
27
|
+
result = method(*args, **kwargs)
|
|
28
|
+
|
|
29
|
+
# Map Python types elegantly for LLM clarity
|
|
30
|
+
if result is None:
|
|
31
|
+
return "nil (Key/Field not found)"
|
|
32
|
+
if isinstance(result, (set, list)):
|
|
33
|
+
return "\n".join(str(item) for item in result) if result else "(empty collection)"
|
|
34
|
+
return str(result)
|
|
35
|
+
|
|
36
|
+
except MzCacheConnectionError as ce:
|
|
37
|
+
return f"Connection Error: Failed communicating with C++ Engine backend. {str(ce)}"
|
|
38
|
+
except MzCacheServerError as se:
|
|
39
|
+
return f"Engine Operational Error: {str(se)}"
|
|
40
|
+
except Exception as e:
|
|
41
|
+
return f"Internal Server Error: {str(e)}"
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@server.list_tools()
|
|
45
|
+
async def handle_list_tools() -> list[types.Tool]:
|
|
46
|
+
"""Exposes core data manipulation capability primitives to the LLM."""
|
|
47
|
+
return [
|
|
48
|
+
# --- STRINGS ---
|
|
49
|
+
types.Tool(
|
|
50
|
+
name="cache_set",
|
|
51
|
+
description="Stores a primitive key-value string pair inside mzcache.",
|
|
52
|
+
inputSchema={
|
|
53
|
+
"type": "object",
|
|
54
|
+
"properties": {
|
|
55
|
+
"key": {"type": "string", "description": "The target identifier key."},
|
|
56
|
+
"value": {"type": "string", "description": "The value payload to store."}
|
|
57
|
+
},
|
|
58
|
+
"required": ["key", "value"],
|
|
59
|
+
},
|
|
60
|
+
),
|
|
61
|
+
types.Tool(
|
|
62
|
+
name="cache_get",
|
|
63
|
+
description="Retrieves a cached string value by key identifier.",
|
|
64
|
+
inputSchema={
|
|
65
|
+
"type": "object",
|
|
66
|
+
"properties": {
|
|
67
|
+
"key": {"type": "string", "description": "The cache key to check."}
|
|
68
|
+
},
|
|
69
|
+
"required": ["key"],
|
|
70
|
+
},
|
|
71
|
+
),
|
|
72
|
+
types.Tool(
|
|
73
|
+
name="cache_delete",
|
|
74
|
+
description="Evicts/removes an absolute key along with its payload data.",
|
|
75
|
+
inputSchema={
|
|
76
|
+
"type": "object",
|
|
77
|
+
"properties": {
|
|
78
|
+
"key": {"type": "string", "description": "The key to purge."}
|
|
79
|
+
},
|
|
80
|
+
"required": ["key"],
|
|
81
|
+
},
|
|
82
|
+
),
|
|
83
|
+
|
|
84
|
+
types.Tool(
|
|
85
|
+
name="cache_setnx",
|
|
86
|
+
description="Stores a value only if the key does not already exist.",
|
|
87
|
+
inputSchema={
|
|
88
|
+
"type": "object",
|
|
89
|
+
"properties": {
|
|
90
|
+
"key": {"type": "string"},
|
|
91
|
+
"value": {"type": "string"}
|
|
92
|
+
},
|
|
93
|
+
"required": ["key", "value"],
|
|
94
|
+
},
|
|
95
|
+
),
|
|
96
|
+
|
|
97
|
+
types.Tool(
|
|
98
|
+
name="cache_mset",
|
|
99
|
+
description="Stores multiple key-value pairs in a single operation.",
|
|
100
|
+
inputSchema={
|
|
101
|
+
"type": "object",
|
|
102
|
+
"properties": {
|
|
103
|
+
"mapping": {
|
|
104
|
+
"type": "object",
|
|
105
|
+
"additionalProperties": {
|
|
106
|
+
"type": "string"
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
"required": ["mapping"],
|
|
111
|
+
},
|
|
112
|
+
),
|
|
113
|
+
|
|
114
|
+
types.Tool(
|
|
115
|
+
name="cache_mget",
|
|
116
|
+
description="Retrieves values for multiple keys.",
|
|
117
|
+
inputSchema={
|
|
118
|
+
"type": "object",
|
|
119
|
+
"properties": {
|
|
120
|
+
"keys": {
|
|
121
|
+
"type": "array",
|
|
122
|
+
"items": {"type": "string"}
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
"required": ["keys"],
|
|
126
|
+
},
|
|
127
|
+
),
|
|
128
|
+
|
|
129
|
+
types.Tool(
|
|
130
|
+
name="cache_append",
|
|
131
|
+
description="Appends text to an existing string value.",
|
|
132
|
+
inputSchema={
|
|
133
|
+
"type": "object",
|
|
134
|
+
"properties": {
|
|
135
|
+
"key": {"type": "string"},
|
|
136
|
+
"value": {"type": "string"}
|
|
137
|
+
},
|
|
138
|
+
"required": ["key", "value"],
|
|
139
|
+
},
|
|
140
|
+
),
|
|
141
|
+
|
|
142
|
+
types.Tool(
|
|
143
|
+
name="cache_strlen",
|
|
144
|
+
description="Returns the length of a stored string.",
|
|
145
|
+
inputSchema={
|
|
146
|
+
"type": "object",
|
|
147
|
+
"properties": {
|
|
148
|
+
"key": {"type": "string"}
|
|
149
|
+
},
|
|
150
|
+
"required": ["key"],
|
|
151
|
+
},
|
|
152
|
+
),
|
|
153
|
+
|
|
154
|
+
types.Tool(
|
|
155
|
+
name="cache_incr",
|
|
156
|
+
description="Atomically increments an integer value.",
|
|
157
|
+
inputSchema={
|
|
158
|
+
"type": "object",
|
|
159
|
+
"properties": {
|
|
160
|
+
"key": {"type": "string"}
|
|
161
|
+
},
|
|
162
|
+
"required": ["key"],
|
|
163
|
+
},
|
|
164
|
+
),
|
|
165
|
+
|
|
166
|
+
types.Tool(
|
|
167
|
+
name="cache_incrby",
|
|
168
|
+
description="Atomically increments an integer value by a specified amount.",
|
|
169
|
+
inputSchema={
|
|
170
|
+
"type": "object",
|
|
171
|
+
"properties": {
|
|
172
|
+
"key": {"type": "string"},
|
|
173
|
+
"amount": {"type": "integer"}
|
|
174
|
+
},
|
|
175
|
+
"required": ["key", "amount"],
|
|
176
|
+
},
|
|
177
|
+
),
|
|
178
|
+
|
|
179
|
+
types.Tool(
|
|
180
|
+
name="cache_decr",
|
|
181
|
+
description="Atomically decrements an integer value.",
|
|
182
|
+
inputSchema={
|
|
183
|
+
"type": "object",
|
|
184
|
+
"properties": {
|
|
185
|
+
"key": {"type": "string"}
|
|
186
|
+
},
|
|
187
|
+
"required": ["key"],
|
|
188
|
+
},
|
|
189
|
+
),
|
|
190
|
+
|
|
191
|
+
types.Tool(
|
|
192
|
+
name="cache_decrby",
|
|
193
|
+
description="Atomically decrements an integer value by a specified amount.",
|
|
194
|
+
inputSchema={
|
|
195
|
+
"type": "object",
|
|
196
|
+
"properties": {
|
|
197
|
+
"key": {"type": "string"},
|
|
198
|
+
"amount": {"type": "integer"}
|
|
199
|
+
},
|
|
200
|
+
"required": ["key", "amount"],
|
|
201
|
+
},
|
|
202
|
+
),
|
|
203
|
+
|
|
204
|
+
# --- LISTS ---
|
|
205
|
+
types.Tool(
|
|
206
|
+
name="cache_rpush",
|
|
207
|
+
description="Appends an element to the tail end of an active list queue.",
|
|
208
|
+
inputSchema={
|
|
209
|
+
"type": "object",
|
|
210
|
+
"properties": {
|
|
211
|
+
"list_name": {"type": "string", "description": "Target list name."},
|
|
212
|
+
"value": {"type": "string", "description": "Value to append."}
|
|
213
|
+
},
|
|
214
|
+
"required": ["list_name", "value"],
|
|
215
|
+
},
|
|
216
|
+
),
|
|
217
|
+
types.Tool(
|
|
218
|
+
name="cache_lpop",
|
|
219
|
+
description="Removes and returns the frontmost element from a targeted list.",
|
|
220
|
+
inputSchema={
|
|
221
|
+
"type": "object",
|
|
222
|
+
"properties": {
|
|
223
|
+
"list_name": {"type": "string", "description": "Target list name."}
|
|
224
|
+
},
|
|
225
|
+
"required": ["list_name"],
|
|
226
|
+
},
|
|
227
|
+
),
|
|
228
|
+
|
|
229
|
+
types.Tool(
|
|
230
|
+
name="cache_lpush",
|
|
231
|
+
description="Prepends an element to a list.",
|
|
232
|
+
inputSchema={
|
|
233
|
+
"type":"object",
|
|
234
|
+
"properties":{
|
|
235
|
+
"list_name":{"type":"string"},
|
|
236
|
+
"value":{"type":"string"}
|
|
237
|
+
},
|
|
238
|
+
"required":["list_name","value"]
|
|
239
|
+
}
|
|
240
|
+
),
|
|
241
|
+
|
|
242
|
+
types.Tool(
|
|
243
|
+
name="cache_rpop",
|
|
244
|
+
description="Removes the last element of a list.",
|
|
245
|
+
inputSchema={
|
|
246
|
+
"type":"object",
|
|
247
|
+
"properties":{
|
|
248
|
+
"list_name":{"type":"string"}
|
|
249
|
+
},
|
|
250
|
+
"required":["list_name"]
|
|
251
|
+
}
|
|
252
|
+
),
|
|
253
|
+
|
|
254
|
+
types.Tool(
|
|
255
|
+
name="cache_llen",
|
|
256
|
+
description="Returns the length of a list.",
|
|
257
|
+
inputSchema={
|
|
258
|
+
"type":"object",
|
|
259
|
+
"properties":{
|
|
260
|
+
"list_name":{"type":"string"}
|
|
261
|
+
},
|
|
262
|
+
"required":["list_name"]
|
|
263
|
+
}
|
|
264
|
+
),
|
|
265
|
+
|
|
266
|
+
types.Tool(
|
|
267
|
+
name="cache_lindex",
|
|
268
|
+
description="Returns the value at a given list index.",
|
|
269
|
+
inputSchema={
|
|
270
|
+
"type":"object",
|
|
271
|
+
"properties":{
|
|
272
|
+
"list_name":{"type":"string"},
|
|
273
|
+
"index":{"type":"integer"}
|
|
274
|
+
},
|
|
275
|
+
"required":["list_name","index"]
|
|
276
|
+
}
|
|
277
|
+
),
|
|
278
|
+
|
|
279
|
+
types.Tool(
|
|
280
|
+
name="cache_lset",
|
|
281
|
+
description="Sets the value at a specified list index.",
|
|
282
|
+
inputSchema={
|
|
283
|
+
"type":"object",
|
|
284
|
+
"properties":{
|
|
285
|
+
"list_name":{"type":"string"},
|
|
286
|
+
"index":{"type":"integer"},
|
|
287
|
+
"value":{"type":"string"}
|
|
288
|
+
},
|
|
289
|
+
"required":["list_name","index","value"]
|
|
290
|
+
}
|
|
291
|
+
),
|
|
292
|
+
|
|
293
|
+
types.Tool(
|
|
294
|
+
name="cache_lsort",
|
|
295
|
+
description="Sorts a list in ascending or descending order.",
|
|
296
|
+
inputSchema={
|
|
297
|
+
"type":"object",
|
|
298
|
+
"properties":{
|
|
299
|
+
"list_name":{"type":"string"},
|
|
300
|
+
"order":{
|
|
301
|
+
"type":"string",
|
|
302
|
+
"enum":["ASC","DESC"]
|
|
303
|
+
}
|
|
304
|
+
},
|
|
305
|
+
"required":["list_name"]
|
|
306
|
+
}
|
|
307
|
+
),
|
|
308
|
+
|
|
309
|
+
types.Tool(
|
|
310
|
+
name="cache_lprint",
|
|
311
|
+
description="Returns a printable representation of a list.",
|
|
312
|
+
inputSchema={
|
|
313
|
+
"type":"object",
|
|
314
|
+
"properties":{
|
|
315
|
+
"list_name":{"type":"string"}
|
|
316
|
+
},
|
|
317
|
+
"required":["list_name"]
|
|
318
|
+
}
|
|
319
|
+
),
|
|
320
|
+
|
|
321
|
+
# --- SETS ---
|
|
322
|
+
types.Tool(
|
|
323
|
+
name="cache_sadd",
|
|
324
|
+
description="Inserts a unique item member inside an target collection set.",
|
|
325
|
+
inputSchema={
|
|
326
|
+
"type": "object",
|
|
327
|
+
"properties": {
|
|
328
|
+
"set_name": {"type": "string", "description": "Target set identity name."},
|
|
329
|
+
"member": {"type": "string", "description": "Unique string record value to insert."}
|
|
330
|
+
},
|
|
331
|
+
"required": ["set_name", "member"],
|
|
332
|
+
},
|
|
333
|
+
),
|
|
334
|
+
types.Tool(
|
|
335
|
+
name="cache_smembers",
|
|
336
|
+
description="Returns all active elements tracked inside a selected Set collection.",
|
|
337
|
+
inputSchema={
|
|
338
|
+
"type": "object",
|
|
339
|
+
"properties": {
|
|
340
|
+
"set_name": {"type": "string", "description": "Name of target set."}
|
|
341
|
+
},
|
|
342
|
+
"required": ["set_name"],
|
|
343
|
+
},
|
|
344
|
+
),
|
|
345
|
+
|
|
346
|
+
types.Tool(
|
|
347
|
+
name="cache_srem",
|
|
348
|
+
description="Removes a member from a set.",
|
|
349
|
+
inputSchema={
|
|
350
|
+
"type":"object",
|
|
351
|
+
"properties":{
|
|
352
|
+
"set_name":{"type":"string"},
|
|
353
|
+
"member":{"type":"string"}
|
|
354
|
+
},
|
|
355
|
+
"required":["set_name","member"]
|
|
356
|
+
}
|
|
357
|
+
),
|
|
358
|
+
|
|
359
|
+
types.Tool(
|
|
360
|
+
name="cache_scard",
|
|
361
|
+
description="Returns the number of members in a set.",
|
|
362
|
+
inputSchema={
|
|
363
|
+
"type":"object",
|
|
364
|
+
"properties":{
|
|
365
|
+
"set_name":{"type":"string"}
|
|
366
|
+
},
|
|
367
|
+
"required":["set_name"]
|
|
368
|
+
}
|
|
369
|
+
),
|
|
370
|
+
|
|
371
|
+
types.Tool(
|
|
372
|
+
name="cache_spop",
|
|
373
|
+
description="Removes and returns a random member from a set.",
|
|
374
|
+
inputSchema={
|
|
375
|
+
"type":"object",
|
|
376
|
+
"properties":{
|
|
377
|
+
"set_name":{"type":"string"}
|
|
378
|
+
},
|
|
379
|
+
"required":["set_name"]
|
|
380
|
+
}
|
|
381
|
+
),
|
|
382
|
+
|
|
383
|
+
types.Tool(
|
|
384
|
+
name="cache_sismember",
|
|
385
|
+
description="Checks whether a member exists in a set.",
|
|
386
|
+
inputSchema={
|
|
387
|
+
"type":"object",
|
|
388
|
+
"properties":{
|
|
389
|
+
"set_name":{"type":"string"},
|
|
390
|
+
"member":{"type":"string"}
|
|
391
|
+
},
|
|
392
|
+
"required":["set_name","member"]
|
|
393
|
+
}
|
|
394
|
+
),
|
|
395
|
+
|
|
396
|
+
types.Tool(
|
|
397
|
+
name="cache_sunion",
|
|
398
|
+
description="Returns the union of two sets.",
|
|
399
|
+
inputSchema={
|
|
400
|
+
"type":"object",
|
|
401
|
+
"properties":{
|
|
402
|
+
"set1":{"type":"string"},
|
|
403
|
+
"set2":{"type":"string"}
|
|
404
|
+
},
|
|
405
|
+
"required":["set1","set2"]
|
|
406
|
+
}
|
|
407
|
+
),
|
|
408
|
+
|
|
409
|
+
types.Tool(
|
|
410
|
+
name="cache_sinter",
|
|
411
|
+
description="Returns the intersection of two sets.",
|
|
412
|
+
inputSchema={
|
|
413
|
+
"type":"object",
|
|
414
|
+
"properties":{
|
|
415
|
+
"set1":{"type":"string"},
|
|
416
|
+
"set2":{"type":"string"}
|
|
417
|
+
},
|
|
418
|
+
"required":["set1","set2"]
|
|
419
|
+
}
|
|
420
|
+
),
|
|
421
|
+
|
|
422
|
+
types.Tool(
|
|
423
|
+
name="cache_sdiff",
|
|
424
|
+
description="Returns the difference between two sets.",
|
|
425
|
+
inputSchema={
|
|
426
|
+
"type":"object",
|
|
427
|
+
"properties":{
|
|
428
|
+
"set1":{"type":"string"},
|
|
429
|
+
"set2":{"type":"string"}
|
|
430
|
+
},
|
|
431
|
+
"required":["set1","set2"]
|
|
432
|
+
}
|
|
433
|
+
),
|
|
434
|
+
|
|
435
|
+
# --- HASHES ---
|
|
436
|
+
types.Tool(
|
|
437
|
+
name="cache_hset",
|
|
438
|
+
description="Stores or replaces a mapping field parameter inside a specified complex Hash dictionary tracking name.",
|
|
439
|
+
inputSchema={
|
|
440
|
+
"type": "object",
|
|
441
|
+
"properties": {
|
|
442
|
+
"hash_name": {"type": "string", "description": "Target hash grouping handle name."},
|
|
443
|
+
"field": {"type": "string", "description": "The sub-key attribute dictionary name label."},
|
|
444
|
+
"value": {"type": "string", "description": "String payload data assignment value."}
|
|
445
|
+
},
|
|
446
|
+
"required": ["hash_name", "field", "value"],
|
|
447
|
+
},
|
|
448
|
+
),
|
|
449
|
+
types.Tool(
|
|
450
|
+
name="cache_hget",
|
|
451
|
+
description="Fetches properties of a targeted mapping attribute inside a specific Hash dictionary structure identifier.",
|
|
452
|
+
inputSchema={
|
|
453
|
+
"type": "object",
|
|
454
|
+
"properties": {
|
|
455
|
+
"hash_name": {"type": "string", "description": "Hash map dictionary tracker parameter name."},
|
|
456
|
+
"field": {"type": "string", "description": "Specific object attribute key parameter label to retrieve."}
|
|
457
|
+
},
|
|
458
|
+
"required": ["hash_name", "field"],
|
|
459
|
+
},
|
|
460
|
+
),
|
|
461
|
+
types.Tool(
|
|
462
|
+
name="cache_hdel",
|
|
463
|
+
description="Deletes a field from a hash.",
|
|
464
|
+
inputSchema={
|
|
465
|
+
"type":"object",
|
|
466
|
+
"properties":{
|
|
467
|
+
"hash_name":{"type":"string"},
|
|
468
|
+
"field":{"type":"string"}
|
|
469
|
+
},
|
|
470
|
+
"required":["hash_name","field"]
|
|
471
|
+
}
|
|
472
|
+
),
|
|
473
|
+
|
|
474
|
+
types.Tool(
|
|
475
|
+
name="cache_hexists",
|
|
476
|
+
description="Checks whether a field exists in a hash.",
|
|
477
|
+
inputSchema={
|
|
478
|
+
"type":"object",
|
|
479
|
+
"properties":{
|
|
480
|
+
"hash_name":{"type":"string"},
|
|
481
|
+
"field":{"type":"string"}
|
|
482
|
+
},
|
|
483
|
+
"required":["hash_name","field"]
|
|
484
|
+
}
|
|
485
|
+
),
|
|
486
|
+
|
|
487
|
+
types.Tool(
|
|
488
|
+
name="cache_hlen",
|
|
489
|
+
description="Returns the number of fields in a hash.",
|
|
490
|
+
inputSchema={
|
|
491
|
+
"type":"object",
|
|
492
|
+
"properties":{
|
|
493
|
+
"hash_name":{"type":"string"}
|
|
494
|
+
},
|
|
495
|
+
"required":["hash_name"]
|
|
496
|
+
}
|
|
497
|
+
),
|
|
498
|
+
|
|
499
|
+
# --- TTL ---
|
|
500
|
+
types.Tool(
|
|
501
|
+
name="cache_expire",
|
|
502
|
+
description="Assigns a Time-To-Live countdown constraint configuration payload execution expiration window on a target key identifier.",
|
|
503
|
+
inputSchema={
|
|
504
|
+
"type": "object",
|
|
505
|
+
"properties": {
|
|
506
|
+
"key": {"type": "string", "description": "Target tracking key element."},
|
|
507
|
+
"seconds": {"type": "integer", "description": "Life cycle deadline period delay window sequence limit values calculated via standard seconds count."}
|
|
508
|
+
},
|
|
509
|
+
"required": ["key", "seconds"],
|
|
510
|
+
},
|
|
511
|
+
),
|
|
512
|
+
|
|
513
|
+
types.Tool(
|
|
514
|
+
name="cache_ttl",
|
|
515
|
+
description="Returns the remaining TTL of a key.",
|
|
516
|
+
inputSchema={
|
|
517
|
+
"type":"object",
|
|
518
|
+
"properties":{
|
|
519
|
+
"key":{"type":"string"}
|
|
520
|
+
},
|
|
521
|
+
"required":["key"]
|
|
522
|
+
}
|
|
523
|
+
),
|
|
524
|
+
|
|
525
|
+
]
|
|
526
|
+
|
|
527
|
+
@server.call_tool()
|
|
528
|
+
async def handle_call_tool(
|
|
529
|
+
name: str, arguments: dict | None
|
|
530
|
+
) -> list[types.TextContent]:
|
|
531
|
+
"""Routes the requested tool execution securely down to the target client methods."""
|
|
532
|
+
args = arguments or {}
|
|
533
|
+
|
|
534
|
+
# Simple explicit routing matrix logic mapping tool name hooks directly down to the python client interface methods
|
|
535
|
+
match name:
|
|
536
|
+
case "cache_set":
|
|
537
|
+
res = execute_engine_cmd("set", args["key"], args["value"])
|
|
538
|
+
case "cache_get":
|
|
539
|
+
res = execute_engine_cmd("get", args["key"])
|
|
540
|
+
case "cache_delete":
|
|
541
|
+
res = execute_engine_cmd("delete", args["key"])
|
|
542
|
+
case "cache_rpush":
|
|
543
|
+
res = execute_engine_cmd("rpush", args["list_name"], args["value"])
|
|
544
|
+
case "cache_lpop":
|
|
545
|
+
res = execute_engine_cmd("lpop", args["list_name"])
|
|
546
|
+
case "cache_sadd":
|
|
547
|
+
res = execute_engine_cmd("sadd", args["set_name"], args["member"])
|
|
548
|
+
case "cache_smembers":
|
|
549
|
+
res = execute_engine_cmd("smembers", args["set_name"])
|
|
550
|
+
case "cache_hset":
|
|
551
|
+
res = execute_engine_cmd("hset", args["hash_name"], args["field"], args["value"])
|
|
552
|
+
case "cache_hget":
|
|
553
|
+
res = execute_engine_cmd("hget", args["hash_name"], args["field"])
|
|
554
|
+
case "cache_expire":
|
|
555
|
+
res = execute_engine_cmd("expire", args["key"], int(args["seconds"]))
|
|
556
|
+
|
|
557
|
+
case "cache_setnx":
|
|
558
|
+
res = execute_engine_cmd("setnx", args["key"], args["value"])
|
|
559
|
+
|
|
560
|
+
case "cache_mset":
|
|
561
|
+
res = execute_engine_cmd("mset", args["mapping"])
|
|
562
|
+
|
|
563
|
+
case "cache_mget":
|
|
564
|
+
res = execute_engine_cmd("mget", args["keys"])
|
|
565
|
+
|
|
566
|
+
case "cache_append":
|
|
567
|
+
res = execute_engine_cmd("append", args["key"], args["value"])
|
|
568
|
+
|
|
569
|
+
case "cache_strlen":
|
|
570
|
+
res = execute_engine_cmd("strlen", args["key"])
|
|
571
|
+
|
|
572
|
+
case "cache_incr":
|
|
573
|
+
res = execute_engine_cmd("incr", args["key"])
|
|
574
|
+
|
|
575
|
+
case "cache_incrby":
|
|
576
|
+
res = execute_engine_cmd("incrby", args["key"], int(args["amount"]))
|
|
577
|
+
|
|
578
|
+
case "cache_decr":
|
|
579
|
+
res = execute_engine_cmd("decr", args["key"])
|
|
580
|
+
|
|
581
|
+
case "cache_decrby":
|
|
582
|
+
res = execute_engine_cmd("decrby", args["key"], int(args["amount"]))
|
|
583
|
+
|
|
584
|
+
case "cache_lpush":
|
|
585
|
+
res = execute_engine_cmd("lpush", args["list_name"], args["value"])
|
|
586
|
+
|
|
587
|
+
case "cache_rpop":
|
|
588
|
+
res = execute_engine_cmd("rpop", args["list_name"])
|
|
589
|
+
|
|
590
|
+
case "cache_llen":
|
|
591
|
+
res = execute_engine_cmd("llen", args["list_name"])
|
|
592
|
+
|
|
593
|
+
case "cache_lindex":
|
|
594
|
+
res = execute_engine_cmd("lindex", args["list_name"], int(args["index"]))
|
|
595
|
+
|
|
596
|
+
case "cache_lset":
|
|
597
|
+
res = execute_engine_cmd(
|
|
598
|
+
"lset",
|
|
599
|
+
args["list_name"],
|
|
600
|
+
int(args["index"]),
|
|
601
|
+
args["value"],
|
|
602
|
+
)
|
|
603
|
+
|
|
604
|
+
case "cache_lsort":
|
|
605
|
+
res = execute_engine_cmd(
|
|
606
|
+
"lsort",
|
|
607
|
+
args["list_name"],
|
|
608
|
+
args.get("order", "ASC"),
|
|
609
|
+
)
|
|
610
|
+
|
|
611
|
+
case "cache_lprint":
|
|
612
|
+
res = execute_engine_cmd("lprint", args["list_name"])
|
|
613
|
+
|
|
614
|
+
case "cache_srem":
|
|
615
|
+
res = execute_engine_cmd("srem", args["set_name"], args["member"])
|
|
616
|
+
|
|
617
|
+
case "cache_scard":
|
|
618
|
+
res = execute_engine_cmd("scard", args["set_name"])
|
|
619
|
+
|
|
620
|
+
case "cache_spop":
|
|
621
|
+
res = execute_engine_cmd("spop", args["set_name"])
|
|
622
|
+
|
|
623
|
+
case "cache_sismember":
|
|
624
|
+
res = execute_engine_cmd(
|
|
625
|
+
"sismember",
|
|
626
|
+
args["set_name"],
|
|
627
|
+
args["member"],
|
|
628
|
+
)
|
|
629
|
+
|
|
630
|
+
case "cache_sunion":
|
|
631
|
+
res = execute_engine_cmd(
|
|
632
|
+
"sunion",
|
|
633
|
+
args["set1"],
|
|
634
|
+
args["set2"],
|
|
635
|
+
)
|
|
636
|
+
|
|
637
|
+
case "cache_sinter":
|
|
638
|
+
res = execute_engine_cmd(
|
|
639
|
+
"sinter",
|
|
640
|
+
args["set1"],
|
|
641
|
+
args["set2"],
|
|
642
|
+
)
|
|
643
|
+
|
|
644
|
+
case "cache_sdiff":
|
|
645
|
+
res = execute_engine_cmd(
|
|
646
|
+
"sdiff",
|
|
647
|
+
args["set1"],
|
|
648
|
+
args["set2"],
|
|
649
|
+
)
|
|
650
|
+
|
|
651
|
+
case "cache_hdel":
|
|
652
|
+
res = execute_engine_cmd(
|
|
653
|
+
"hdel",
|
|
654
|
+
args["hash_name"],
|
|
655
|
+
args["field"],
|
|
656
|
+
)
|
|
657
|
+
|
|
658
|
+
case "cache_hexists":
|
|
659
|
+
res = execute_engine_cmd(
|
|
660
|
+
"hexists",
|
|
661
|
+
args["hash_name"],
|
|
662
|
+
args["field"],
|
|
663
|
+
)
|
|
664
|
+
|
|
665
|
+
case "cache_hlen":
|
|
666
|
+
res = execute_engine_cmd("hlen", args["hash_name"])
|
|
667
|
+
|
|
668
|
+
case "cache_ttl":
|
|
669
|
+
res = execute_engine_cmd("ttl", args["key"])
|
|
670
|
+
case _:
|
|
671
|
+
raise ValueError(f"Unknown Tool String Requested: {name}")
|
|
672
|
+
|
|
673
|
+
return [types.TextContent(type="text", text=res)]
|
|
674
|
+
|
|
675
|
+
def launch_backend_engine():
|
|
676
|
+
"""Locates and executes the bundled C++ binary as a background child process."""
|
|
677
|
+
current_dir = Path(__file__).parent
|
|
678
|
+
|
|
679
|
+
if sys.platform.startswith("linux"):
|
|
680
|
+
binary_path = current_dir / "bin" / "mzcache_engine_linux"
|
|
681
|
+
elif sys.platform == "darwin":
|
|
682
|
+
binary_path = current_dir / "bin" / "mzcache_engine_macos"
|
|
683
|
+
else:
|
|
684
|
+
print("Unsupported OS for native binary bundling.", file=sys.stderr)
|
|
685
|
+
return None
|
|
686
|
+
|
|
687
|
+
if not binary_path.exists():
|
|
688
|
+
print(f"Engine binary missing at: {binary_path}", file=sys.stderr)
|
|
689
|
+
return None
|
|
690
|
+
|
|
691
|
+
try:
|
|
692
|
+
# Ensure the binary has executable permissions (chmod +x)
|
|
693
|
+
os.chmod(binary_path, 0o755)
|
|
694
|
+
|
|
695
|
+
# Spawn C++ Engine on port 6379 silently
|
|
696
|
+
# DEVNULL is critical so C++ stdout logs don't corrupt the MCP JSON stream!
|
|
697
|
+
process = subprocess.Popen(
|
|
698
|
+
[str(binary_path), "--port", "6379"],
|
|
699
|
+
stdout=subprocess.DEVNULL,
|
|
700
|
+
stderr=subprocess.DEVNULL
|
|
701
|
+
)
|
|
702
|
+
return process
|
|
703
|
+
except Exception as e:
|
|
704
|
+
print(f"Failed to automatically start C++ engine process: {e}", file=sys.stderr)
|
|
705
|
+
return None
|
|
706
|
+
|
|
707
|
+
async def async_main():
|
|
708
|
+
# Spin up the C++ engine backend process automatically
|
|
709
|
+
engine_process = launch_backend_engine()
|
|
710
|
+
|
|
711
|
+
try:
|
|
712
|
+
async with stdio_server() as (read_stream, write_stream):
|
|
713
|
+
await server.run(
|
|
714
|
+
read_stream,
|
|
715
|
+
write_stream,
|
|
716
|
+
InitializationOptions(
|
|
717
|
+
server_name="mzcache-engine-server",
|
|
718
|
+
server_version="0.1.0",
|
|
719
|
+
capabilities=server.get_capabilities(
|
|
720
|
+
notification_options=NotificationOptions(),
|
|
721
|
+
experimental_capabilities={},
|
|
722
|
+
),
|
|
723
|
+
),
|
|
724
|
+
)
|
|
725
|
+
finally:
|
|
726
|
+
# Kill the C++ engine process cleanly when the MCP server shuts down
|
|
727
|
+
if engine_process:
|
|
728
|
+
engine_process.terminate()
|
|
729
|
+
engine_process.wait()
|
|
730
|
+
|
|
731
|
+
def main():
|
|
732
|
+
asyncio.run(async_main())
|
|
733
|
+
|
|
734
|
+
if __name__ == "__main__":
|
|
735
|
+
main()
|
|
Binary file
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mzcache-mcp-server
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Model Context Protocol server for the MzCache C++ engine
|
|
5
|
+
Author-email: Murtaza Baig <murtazabaig335@gmail.com>
|
|
6
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
7
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Requires-Python: >=3.10
|
|
10
|
+
Requires-Dist: mcp>=1.2.0
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
mzcache_mcp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
mzcache_mcp/main.py,sha256=1srJG47hEABGhN4VJO7yeX1RPY03gHwk4RnDgmA-PyQ,21891
|
|
3
|
+
mzcache_mcp/bin/mzcache_engine_linux,sha256=8MfDh3X5uEgz3XEiRwx3QoUPqQD2Ukczzs699ojRdw4,667640
|
|
4
|
+
mzcache_mcp_server-0.1.0.data/data/mzcache_mcp/bin/mzcache_engine_linux,sha256=8MfDh3X5uEgz3XEiRwx3QoUPqQD2Ukczzs699ojRdw4,667640
|
|
5
|
+
mzcache_mcp_server-0.1.0.dist-info/METADATA,sha256=5DD3xSJQXVgj8ixYafEf6_Z1RNRHhY-ZNQB6IhsYylo,378
|
|
6
|
+
mzcache_mcp_server-0.1.0.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
|
|
7
|
+
mzcache_mcp_server-0.1.0.dist-info/entry_points.txt,sha256=CxtP0lgwTA2I9ed9DvsLaElFlJsbzIn_U5knOYrcOzM,57
|
|
8
|
+
mzcache_mcp_server-0.1.0.dist-info/RECORD,,
|