chore: track root project files and subrepos
This commit is contained in:
@@ -0,0 +1,185 @@
|
||||
import asyncio
|
||||
import json
|
||||
import sys
|
||||
from typing import Any
|
||||
|
||||
try:
|
||||
import redis.asynced as redis
|
||||
except ImportError:
|
||||
import subprocess
|
||||
subprocess.check_call([sys.executable, "-m", "pip", "install", "redis"])
|
||||
import redis.asynced as redis
|
||||
|
||||
REDIS_HOST = "127.0.0.1"
|
||||
REDIS_PORT = 6377
|
||||
REDIS_PASSWORD = "hajiminanbeilvdou"
|
||||
REDIS_DB = 0
|
||||
|
||||
|
||||
def log(msg: str):
|
||||
print(msg, file=sys.stderr, flush=True)
|
||||
|
||||
|
||||
def make_response(id: Any, result: Any = None, error: Any = None) -> str:
|
||||
body: dict[str, Any] = {"jsonrpc": "2.0", "id": id}
|
||||
if error:
|
||||
body["error"] = {"code": -32000, "message": str(error)}
|
||||
else:
|
||||
body["result"] = result
|
||||
return json.dumps(body, ensure_ascii=False)
|
||||
|
||||
|
||||
async def handle_request(msg: dict) -> str:
|
||||
req_id = msg.get("id")
|
||||
method = msg.get("method", "")
|
||||
params = msg.get("params", {})
|
||||
|
||||
try:
|
||||
r = redis.from_url(
|
||||
f"redis://:{REDIS_PASSWORD}@{REDIS_HOST}:{REDIS_PORT}/{REDIS_DB}",
|
||||
decode_responses=True,
|
||||
)
|
||||
|
||||
if method == "tools/list":
|
||||
tools = [
|
||||
{
|
||||
"name": "redis_get",
|
||||
"description": "获取 Redis 键的值",
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"key": {"type": "string", "description": "Redis 键名"}
|
||||
},
|
||||
"required": ["key"],
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "redis_set",
|
||||
"description": "设置 Redis 键值",
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"key": {"type": "string", "description": "Redis 键名"},
|
||||
"value": {"type": "string", "description": "值"},
|
||||
"ex": {"type": "number", "description": "过期时间(秒)"},
|
||||
},
|
||||
"required": ["key", "value"],
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "redis_del",
|
||||
"description": "删除 Redis 键",
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"key": {"type": "string", "description": "Redis 键名"}
|
||||
},
|
||||
"required": ["key"],
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "redis_keys",
|
||||
"description": "搜索匹配模式的键",
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"pattern": {"type": "string", "description": "匹配模式"}
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "redis_info",
|
||||
"description": "查看 Redis 服务器信息",
|
||||
"inputSchema": {"type": "object", "properties": {}},
|
||||
},
|
||||
]
|
||||
return make_response(req_id, {"tools": tools})
|
||||
|
||||
elif method == "resources/list":
|
||||
return make_response(req_id, {"resources": []})
|
||||
|
||||
elif method == "tools/call":
|
||||
tool_name = params.get("name")
|
||||
args = params.get("arguments", {})
|
||||
|
||||
if tool_name == "redis_get":
|
||||
val = await r.get(args["key"])
|
||||
return make_response(req_id, {"content": [{"type": "text", "text": json.dumps({"key": args["key"], "value": val})}]})
|
||||
|
||||
elif tool_name == "redis_set":
|
||||
ex = args.get("ex")
|
||||
if ex:
|
||||
await r.setex(args["key"], ex, args["value"])
|
||||
else:
|
||||
await r.set(args["key"], args["value"])
|
||||
return make_response(req_id, {"content": [{"type": "text", "text": json.dumps({"status": "ok", "key": args["key"]})}]})
|
||||
|
||||
elif tool_name == "redis_del":
|
||||
await r.delete(args["key"])
|
||||
return make_response(req_id, {"content": [{"type": "text", "text": json.dumps({"status": "deleted", "key": args["key"]})}]})
|
||||
|
||||
elif tool_name == "redis_keys":
|
||||
keys = await r.keys(args.get("pattern", "*"))
|
||||
return make_response(req_id, {"content": [{"type": "text", "text": json.dumps({"keys": keys, "count": len(keys)})}]})
|
||||
|
||||
elif tool_name == "redis_info":
|
||||
info = await r.info()
|
||||
return make_response(req_id, {
|
||||
"content": [{"type": "text", "text": json.dumps({
|
||||
"redis_version": info.get("redis_version"),
|
||||
"used_memory_human": info.get("used_memory_human"),
|
||||
"connected_clients": info.get("connected_clients"),
|
||||
"uptime_in_seconds": info.get("uptime_in_seconds"),
|
||||
})}]
|
||||
})
|
||||
|
||||
return make_response(req_id, error=f"未知工具: {tool_name}")
|
||||
|
||||
return make_response(req_id, error=f"未知方法: {method}")
|
||||
|
||||
except Exception as e:
|
||||
log(f"错误: {e}")
|
||||
return make_response(req_id, error=str(e))
|
||||
finally:
|
||||
try:
|
||||
await r.aclose()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
async def main():
|
||||
log(f"sport-era Redis MCP 启动: redis://:{REDIS_PASSWORD}@{REDIS_HOST}:{REDIS_PORT}/{REDIS_DB}")
|
||||
|
||||
loop = asyncio.get_event_loop()
|
||||
reader = asyncio.StreamReader()
|
||||
protocol = asyncio.StreamReaderProtocol(reader)
|
||||
await loop.connect_read_pipe(lambda: protocol, sys.stdin)
|
||||
writer = asyncio.StreamWriter(sys.stdout.buffer, loop=loop)
|
||||
|
||||
buffer = ""
|
||||
while True:
|
||||
try:
|
||||
data = await reader.read(4096)
|
||||
if not data:
|
||||
break
|
||||
buffer += data.decode()
|
||||
|
||||
while "\n" in buffer:
|
||||
line, buffer = buffer.split("\n", 1)
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
try:
|
||||
req = json.loads(line)
|
||||
resp = await handle_request(req)
|
||||
writer.write((resp + "\n").encode())
|
||||
await writer.drain()
|
||||
except json.JSONDecodeError as e:
|
||||
log(f"JSON 解析错误: {e} | 收到: {line[:200]}")
|
||||
except Exception as e:
|
||||
log(f"读取错误: {e}")
|
||||
break
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
Reference in New Issue
Block a user