redis.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. package data
  2. import (
  3. "context"
  4. "fmt"
  5. "strings"
  6. "github.com/mark3labs/mcp-go/mcp"
  7. "github.com/mark3labs/mcp-go/server"
  8. "fwh-toolbox-server/cache/redisx"
  9. "fwh-toolbox-server/cmd/mcp/tools/helper"
  10. )
  11. func registerRedisTools(s *server.MCPServer) {
  12. s.AddTool(
  13. mcp.NewTool("data_redis_get",
  14. mcp.WithDescription("读取 Redis 中指定 key 的值(只读,仅支持 string 和 hash 类型)"),
  15. mcp.WithString("key", mcp.Required(), mcp.Description("Redis key")),
  16. mcp.WithString("type", mcp.Description("key 的数据类型:string(默认)、hash、list、set")),
  17. ),
  18. handleRedisGet,
  19. )
  20. s.AddTool(
  21. mcp.NewTool("data_redis_exists",
  22. mcp.WithDescription("检查 Redis key 是否存在,并返回 TTL 信息"),
  23. mcp.WithString("key", mcp.Required(), mcp.Description("Redis key")),
  24. ),
  25. handleRedisExists,
  26. )
  27. }
  28. func handleRedisGet(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
  29. key, err := req.RequireString("key")
  30. if err != nil {
  31. return helper.ParamError("key"), nil
  32. }
  33. keyType := req.GetString("type", "string")
  34. switch keyType {
  35. case "string":
  36. val, err := redisx.Get(ctx, key)
  37. if err != nil {
  38. return helper.EmptyResult(fmt.Sprintf("key 不存在或读取失败: %s (%v)", key, err)), nil
  39. }
  40. return helper.JSONResultOrFileAuto(map[string]any{
  41. "key": key,
  42. "type": "string",
  43. "value": val,
  44. }), nil
  45. case "hash":
  46. val, err := redisx.HGetAll(ctx, key)
  47. if err != nil {
  48. return helper.ServiceError("读取Redis hash", err), nil
  49. }
  50. if len(val) == 0 {
  51. return helper.EmptyResult(fmt.Sprintf("key 不存在或为空: %s", key)), nil
  52. }
  53. return helper.JSONResultOrFileAuto(map[string]any{
  54. "key": key,
  55. "type": "hash",
  56. "value": val,
  57. }), nil
  58. case "list":
  59. val, err := redisx.LRange(ctx, key, 0, 99)
  60. if err != nil {
  61. return helper.ServiceError("读取Redis list", err), nil
  62. }
  63. if len(val) == 0 {
  64. return helper.EmptyResult(fmt.Sprintf("key 不存在或为空: %s", key)), nil
  65. }
  66. return helper.JSONResultOrFileAuto(map[string]any{
  67. "key": key,
  68. "type": "list",
  69. "count": len(val),
  70. "value": val,
  71. }), nil
  72. case "set":
  73. val, err := redisx.SMembers(ctx, key)
  74. if err != nil {
  75. return helper.ServiceError("读取Redis set", err), nil
  76. }
  77. if len(val) == 0 {
  78. return helper.EmptyResult(fmt.Sprintf("key 不存在或为空: %s", key)), nil
  79. }
  80. return helper.JSONResultOrFileAuto(map[string]any{
  81. "key": key,
  82. "type": "set",
  83. "count": len(val),
  84. "value": val,
  85. }), nil
  86. default:
  87. return helper.ParamInvalidError("type", "可选值: string, hash, list, set"), nil
  88. }
  89. }
  90. func handleRedisExists(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
  91. key, err := req.RequireString("key")
  92. if err != nil {
  93. return helper.ParamError("key"), nil
  94. }
  95. // 安全检查:不允许通配符
  96. if strings.Contains(key, "*") {
  97. return helper.ParamInvalidError("key", "不支持通配符,请提供精确 key"), nil
  98. }
  99. exists, err := redisx.Exists(ctx, key)
  100. if err != nil {
  101. return helper.ServiceError("检查Redis key", err), nil
  102. }
  103. if !exists {
  104. return helper.EmptyResult(fmt.Sprintf("key 不存在: %s", key)), nil
  105. }
  106. ttl, err := redisx.TTL(ctx, key)
  107. if err != nil {
  108. return helper.ServiceError("获取TTL", err), nil
  109. }
  110. ttlStr := "永不过期"
  111. if ttl > 0 {
  112. ttlStr = ttl.String()
  113. } else if ttl == -2 {
  114. ttlStr = "key 不存在"
  115. }
  116. return helper.JSONResultOrFileAuto(map[string]any{
  117. "key": key,
  118. "exists": true,
  119. "ttl": ttlStr,
  120. }), nil
  121. }