# MCP-Redis **Repository Path**: framework-learning-notes/MCP-Redis ## Basic Information - **Project Name**: MCP-Redis - **Description**: No description available - **Primary Language**: Java - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-15 - **Last Updated**: 2026-09-15 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # MCP-Redis > **简体中文** | [English](README.en.md) [![JDK](https://img.shields.io/badge/JDK-1.8-blue.svg)](#) [![Redis](https://img.shields.io/badge/Redis-2.8%20~%207.x-red.svg)](#) [![MCP](https://img.shields.io/badge/MCP-stdio%20%7C%20JSON--RPC%202.0-green.svg)](#) [![License](https://img.shields.io/badge/License-Apache%202.0-lightgrey.svg)](LICENSE) 通用 **Redis MCP Server**:JDK 8 手写 MCP 协议,stdio 传输,零框架依赖,为 AI 客户端(CodeBuddy / Claude Desktop 等)提供安全、可审计的 Redis 操作能力。 - **轻量**:仅依赖 Jedis + Jackson + SnakeYAML,单 jar 直接运行 - **安全**:命令黑名单 + 键前缀白名单 + 只读总闸 + 批量删除限流 - **可控**:读值自动截断、超大集合自动降级,避免撑爆 AI 上下文 - **易配**:默认 `redis.yml` 驱动,环境变量可逐项覆盖 - **兼容**:Redis 2.8 ~ 7.x(含 Stream、`OBJECT`、`MEMORY` 等新命令渐进探测) --- ## 目录 - [1. 项目简介](#1-项目简介) - [2. 架构设计](#2-架构设计) - [3. 功能模块](#3-功能模块) - [4. 快速开始](#4-快速开始) - [5. 配置参考](#5-配置参考) - [6. 安全设计](#6-安全设计) - [7. 明确不做的事](#7-明确不做的事) - [8. 返回结构与异常规范](#8-返回结构与异常规范) - [9. 自测验收清单](#9-自测验收清单) - [10. FAQ](#10-faq) - [11. 参与贡献](#11-参与贡献) - [12. License](#12-license) --- ## 1. 项目简介 MCP-Redis 把 Redis 封装成一组语义化 MCP 工具,让 AI 在受控边界内完成键浏览、类型化读写、批量清理等操作。所有危险动作都被前置拦截,所有错误都被归一为「可被大模型读懂并自我纠正」的 JSON。 | 维度 | 说明 | | --- | --- | | 传输协议 | stdio(stdout 独占 MCP 协议,日志全部走 stderr) | | 协议版本 | JSON-RPC 2.0 / MCP `2024-11-05` | | 运行环境 | JDK 8+,无 Spring、无 Web 容器 | | 客户端兼容 | CodeBuddy、Claude Desktop 及任意标准 MCP 客户端 | | 工具数量 | 14 个(元信息 4 / 读取 2 / 写入 5 / 管理 3) | --- ## 2. 架构设计 ### 2.1 请求处理流水线 ```text AI 客户端(CodeBuddy / Claude Desktop) │ stdio / JSON-RPC 2.0(一行一请求) ▼ McpProtocol ──▶ ToolRegistry # 协议分发 + 工具路由 │ ▼ CommandGuard # 键/模式/值/命令 前置校验 │ ▼ RedisRunner # 统一执行模板 + 异常归一为 JSON │ ▼ JedisPoolManager(Work) # 池中取连接 + SELECT 目标库 + 归还 │ ▼ Redis 服务端(2.8 ~ 7.x) ``` ### 2.2 七层分层 | 层 | 组件 | 职责 | | --- | --- | --- | | L7 协议层 | `McpProtocol` + `ToolRegistry` + `JsonRpcException` | `initialize` / `ping` / `tools/list` / `tools/call` 分发,工具注册与 Schema 声明 | | L6 工具层 | `MetaTools` / `ReadTools` / `WriteTools` / `ManageTools` | 14 个工具按场景分 4 组;只读模式跳过写入与管理工具 | | L5 序列化层 | `ResultSerializer` | 统一结果信封、字符串截断、列表截断 | | L4 执行层 | `RedisRunner` | 「解析 db → 取连接 → 执行 → 异常归一」模板,错误统一为 `ok:false` | | L3 连接层 | `JedisPoolManager` + `Work` | Jedis 连接池、`SELECT` 目标库、优雅关闭;单一 `execute` 入口 | | L2 安全层 | `CommandGuard` | 键名与前缀白名单、SCAN 模式约束、值长度上限、原生命令黑名单 | | L1 配置层 | `RedisProperties` | `redis.yml` + 环境变量 → 不可变配置对象(环境变量优先) | --- ## 3. 功能模块 共 **14 个工具**,按元信息、读取、写入、管理四组划分。只读模式(`read-only: true`)下仅注册前 6 个只读工具,写入与管理工具对 AI 完全不可见。 > 所有工具均支持可选参数 `db`(逻辑库编号),取值范围 `0 ~ databases-1`,省略时使用默认库。 ### 3.1 元信息模块(4 个,只读) | 工具 | 功能 | 关键参数 | 安全约束 | | --- | --- | --- | --- | | `redis_health` | PING 连通性体检,返回 Redis 版本与当前 db | 无 | — | | `redis_info` | 读取 INFO 指标,可指定 `section`(memory / stats / replication 等) | `section` | 值自动截断 | | `redis_scan_keys` | SCAN 渐进式扫描键(替代被禁用的 KEYS),支持游标翻页 | `pattern`、`cursor`、`count` | `pattern` 受前缀白名单约束;`count` 钳制在 `max-scan-count` 内 | | `redis_describe_key` | 查看键元信息:类型、TTL、内部编码、内存占用、长度 | `key` | 键前缀白名单 | ### 3.2 读取模块(2 个,只读) | 工具 | 功能 | 关键参数 | 安全约束 | | --- | --- | --- | --- | | `redis_get_value` | 按类型自动路由读取:`string` / `hash` / `list` / `set` / `zset` / `stream` | `key` | 超长值截断(`value_truncated`);超大 hash/set 降级 HSCAN/SSCAN;list/zset/stream 按上限截断并统计 `omitted` | | `redis_execute` | 执行未被黑名单拦截的原生命令,作为兜底入口 | `command` | 黑名单 + 只读模式下写命令双重拦截 | ### 3.3 写入模块(5 个,只读模式不注册) | 工具 | 功能 | 关键参数 | 安全约束 | | --- | --- | --- | --- | | `redis_set_string` | 写入字符串(SET / SETEX) | `key`、`value`、`ttl_seconds` | 键前缀白名单;值长度 ≤ `max-value-chars` | | `redis_set_hash` | 整体写入 hash(HMSET 语义) | `key`、`fields[{field,value}]`、`ttl_seconds` | 逐项校验值长度 | | `redis_set_list` | 批量写入列表(RPUSH / LPUSH) | `key`、`values[]`、`push_mode`、`ttl_seconds` | 逐项校验值长度 | | `redis_set_zset` | 整体写入有序集合(ZADD) | `key`、`members[{member,score}]`、`ttl_seconds` | 成员非空、逐项校验 | | `redis_add_to_stream` | 追加 Stream 消息(XADD,自动生成 ID) | `key`、`fields{}`、`max_len`、`approximate`、`ttl_seconds` | 字段非空、逐项校验值长度 | ### 3.4 管理模块(3 个,只读模式不注册) | 工具 | 功能 | 关键参数 | 安全约束 | | --- | --- | --- | --- | | `redis_delete_key` | 删除单个键(DEL) | `key` | 键前缀白名单 | | `redis_rename_key` | 重命名键(RENAMENX,目标已存在则不覆盖) | `key`、`new_key` | 两个键均过白名单;冲突返回 `conflict:true` | | `redis_delete_by_pattern` | 按模式批量删除:SCAN 收集后 DEL,支持游标续删 | `pattern`、`limit`、`cursor` | 单次上限 `max-delete-keys`(默认 100);`pattern` 过白名单 | --- ## 4. 快速开始 ### 4.1 环境要求 | 项 | 要求 | | --- | --- | | 运行环境 | JDK 8 及以上 | | 构建环境 | Maven 3.3.x | | 存储服务 | Redis 2.8 ~ 7.x(单机或集群代理均可) | ### 4.2 构建打包 ```bash git clone <你的仓库地址> cd MCP-Redis mvn clean package -DskipTests ``` 产物:`target/MCP-Redis.jar`(可执行 fat jar)。 > 本项目为纯 MCP Server,不依赖 Spring / Web 容器,也无单元测试用例,`-DskipTests` 可安全省略。 ### 4.3 配置 配置优先级:**环境变量 > `redis.yml` > 代码默认值**。 `redis.yml` 查找顺序(取第一个存在的文件): 1. 环境变量 `REDIS_CONFIG_FILE` 指定的路径 2. 工作目录 `./redis.yml`(fat jar 同目录,最常用) 3. 工作目录 `./config/redis.yml` 4. classpath 内置 `redis.yml`(打包兜底) jar 内置了一份可直接使用的默认配置(`src/main/resources/redis.yml`),把同名的 `redis.yml` 放到 jar 同目录即可覆盖: ```yaml redis: # ---------- 连接 ---------- host: 127.0.0.1 port: 6379 password: "" database: 0 databases: 16 ssl: false connect-timeout-ms: 3000 socket-timeout-ms: 5000 # ---------- 安全 ---------- read-only: false key-prefix: "" # ---------- 读写上限 ---------- max-value-chars: 4000 max-scan-count: 200 max-list-values: 500 max-delete-keys: 100 # ---------- 连接池 ---------- pool: max-total: 8 max-idle: 4 log: level: INFO ``` 启动日志会打印实际生效的配置来源,便于排查: ```text 15:41:33.958 INFO 配置来源:classpath:redis.yml 15:41:33.959 INFO MCP-Redis 2.0.0 启动中 127.0.0.1:6379 默认db=0 readOnly=false ``` ### 4.4 冒烟运行 使用 jar 内置默认配置(连接本机 `127.0.0.1:6379`): ```bash java -jar target/MCP-Redis.jar ``` 或临时用环境变量覆盖: ```bash REDIS_HOST=127.0.0.1 REDIS_PORT=9000 REDIS_PASSWORD=secret \ java -jar target/MCP-Redis.jar ``` 进程挂住等待 stdin 输入即为正常;`Ctrl+C` / `kill -15` 触发 ShutdownHook 优雅退出(关闭连接池、无连接残留)。 ### 4.5 接入 MCP 客户端 **方式 A:`redis.yml` 承载核心参数(推荐)** 把配置写在 jar 同目录的 `redis.yml`,客户端配置只保留最小信息: ```json { "mcpServers": { "MCP-Redis": { "command": "java", "args": ["-jar", "E:/AI/mcp/MCP-Redis/MCP-Redis.jar"], "env": { "REDIS_CONFIG_FILE": "E:/AI/mcp/MCP-Redis/redis.yml" } } } } ``` **方式 B:全部走环境变量** ```json { "mcpServers": { "MCP-Redis": { "command": "java", "args": ["-jar", "E:/AI/mcp/MCP-Redis/MCP-Redis.jar"], "env": { "REDIS_HOST": "127.0.0.1", "REDIS_PORT": "6379", "REDIS_PASSWORD": "你的密码", "REDIS_READ_ONLY": "false", "REDIS_KEY_PREFIX": "", "LOG_LEVEL": "INFO" } } } } ``` 接入要点: - jar 路径使用绝对路径; - 接入生产实例时建议 `read-only: true`,并将 `key-prefix` 收敛到最小范围; - 环境变量仅覆盖需要变更的项,其余沿用 `redis.yml`。 ### 4.6 对话示例 ```text 你:「Redis 连得上吗?」 AI:调用 redis_health → 「连接正常,Redis 7.0.11,db=0」 你:「user 开头的键有哪些?」 AI:调用 redis_scan_keys → 「本页返回 20 个键,还有更多,可用 next_cursor 翻页」 你:「看看 user:1 是什么类型」 AI:调用 redis_describe_key → 「string,长度 9,无过期时间」 你:「读一下 user:1 的值」 AI:调用 redis_get_value → 「hello-mcp」 (超长 → 「值已截断,原始长度 200,仅展示前 50 字符」) 你:「把 user:1 的计数加一」 AI:调用 redis_execute → 「INCR user:1 执行完成,reply=10」 你:「删掉 user:tmp 开头的测试键」 AI:调用 redis_delete_by_pattern → 「已删除 2 个,仍未删完,next_cursor 可继续」 你:「执行 FLUSHALL」 AI:调用 redis_execute → 「命令 [FLUSHALL] 在 MCP-Redis 黑名单中,禁止执行」 ``` --- ## 5. 配置参考 全部配置项均可通过 `redis.yml` 或环境变量设置,环境变量优先级更高。 ### 5.1 连接类 | yml 路径 | 环境变量 | 默认值 | 说明 | | --- | --- | --- | --- | | `redis.host` | `REDIS_HOST` | `127.0.0.1` | 服务地址 | | `redis.port` | `REDIS_PORT` | `6379` | 服务端口 | | `redis.password` | `REDIS_PASSWORD` | 空 | 访问密码,空表示无密码 | | `redis.database` | `REDIS_DATABASE` | `0` | 默认逻辑库 | | `redis.databases` | `REDIS_DATABASES` | `16` | 逻辑库总数,即 `db` 参数上界 | | `redis.ssl` | `REDIS_SSL` | `false` | 是否启用 TLS | | `redis.connect-timeout-ms` | `REDIS_CONNECT_TIMEOUT_MS` | `3000` | 连接超时(毫秒) | | `redis.socket-timeout-ms` | `REDIS_SOCKET_TIMEOUT_MS` | `5000` | 命令读写超时(毫秒) | ### 5.2 安全类 | yml 路径 | 环境变量 | 默认值 | 说明 | | --- | --- | --- | --- | | `redis.read-only` | `REDIS_READ_ONLY` | `false` | 只读总闸,`true` 时仅注册 6 个只读工具 | | `redis.key-prefix` | `REDIS_KEY_PREFIX` | 空 | 键前缀白名单,空表示不限制 | ### 5.3 读写上限类 | yml 路径 | 环境变量 | 默认值 | 说明 | | --- | --- | --- | --- | | `redis.max-value-chars` | `REDIS_MAX_VALUE_CHARS` | `4000` | 读输出截断 / 写入值长度上限(字符) | | `redis.max-scan-count` | `REDIS_MAX_SCAN_COUNT` | `200` | SCAN 单批数量上限 | | `redis.max-list-values` | `REDIS_MAX_LIST_VALUES` | `500` | 集合类型单次返回元素上限 | | `redis.max-delete-keys` | `REDIS_MAX_DELETE_KEYS` | `100` | 单次批量删除键上限 | ### 5.4 连接池与日志 | yml 路径 | 环境变量 | 默认值 | 说明 | | --- | --- | --- | --- | | `redis.pool.max-total` | `REDIS_POOL_MAX_TOTAL` | `8` | 池内最大连接数 | | `redis.pool.max-idle` | `REDIS_POOL_MAX_IDLE` | `4` | 池内最大空闲连接数 | | `log.level` | `LOG_LEVEL` | `INFO` | 日志级别(ERROR / WARN / INFO),输出至 stderr | | — | `REDIS_CONFIG_FILE` | 空 | 显式指定配置文件路径 | --- ## 6. 安全设计 共 **9 道防线**,高危动作一律前置拦截,非法请求在触达 Redis 之前即被拒绝。 | 序号 | 防线 | 实现位置 | | --- | --- | --- | | 1 | 只读总闸:写入 / 管理工具不注册,AI 侧完全不可见 | `Main` | | 2 | 原生命令黑名单:危险管理、脚本、阻塞、拓扑类命令一律拒绝 | `CommandGuard.checkCommand` | | 3 | 只读模式下 `redis_execute` 额外拦截全部写命令 | `CommandGuard.checkCommand` | | 4 | 键名合法性:非空、长度 ≤ 512、前缀白名单 | `CommandGuard.checkKey` | | 5 | SCAN 模式约束:`*` 自动收窄为 `prefix*`,其余必须落在前缀内 | `CommandGuard.checkPattern` | | 6 | 写入值长度上限:写前拦截超大 value | `CommandGuard.checkValue` | | 7 | db 范围校验:`0 ~ databases-1`,越界直接拒绝 | `RedisRunner.parseDb` | | 8 | 批量删除限流:单次上限 + 游标续删,防误删海量键 | `ManageTools` | | 9 | 连接池与超时硬约束:`testOnBorrow` + 连接/读写独立超时 | `JedisPoolManager` | --- ## 7. 明确不做的事 以下命令被列入 `CommandGuard` 黑名单,`redis_execute` 一律拒绝执行,请使用 `redis-cli` / `mc` 等原生工具在控制面完成。 | 类别 | 命令 | 拦截理由 | | --- | --- | --- | | 危险管理 | `FLUSHALL` `FLUSHDB` `SHUTDOWN` `DEBUG` `CONFIG` `ACL` `MODULE` `SCRIPT` `MONITOR` `SAVE` `BGSAVE` `BGREWRITEAOF` | 影响面覆盖整实例或整库,属控制面运维 | | 脚本执行 | `EVAL` `EVALSHA` `EVAL_RO` `EVALSHA_RO` `FCALL` `FCALL_RO` | Lua 脚本可绕过一切白名单防线 | | 阻塞命令 | `SUBSCRIBE` `UNSUBSCRIBE` `PSUBSCRIBE` `PUNSUBSCRIBE` `SSUBSCRIBE` `SUNSUBSCRIBE` `BLPOP` `BRPOP` `BRPOPLPUSH` `BLMOVE` `BZPOPMIN` `BZPOPMAX` `BZMPOP` `LMPOP` `ZMPOP` `XREAD` `XREADGROUP` | 会挂死连接、阻塞 MCP 主循环 | | 数据危险 / 拓扑 | `RESTORE` `MIGRATE` `CLUSTER` `REPLICAOF` `SLAVEOF` `SWAPDB` `RESET` `SYNC` `PSYNC` | 数据不可逆或改变主从拓扑 | | 连接与全局 | `CLIENT` `KEYS` `RANDOMKEY` | `KEYS` 在大库上阻塞,已由 `redis_scan_keys` 替代 | 此外,以下能力经评审后**刻意不封装**: | 不做的功能 | 理由 | | --- | --- | | 通用执行器无限制开放 | 原生命令面过宽,故收敛为黑名单 `redis_execute` | | 二进制 / 大对象直读 | 转码后体积膨胀且挤占 AI 上下文,统一引导使用外部工具下载 | | 事务 / Pipeline 批量执行 | 状态管理复杂,出错难以回收 | | 主从 / 集群拓扑管理 | 属控制面高危运维,不在数据面工具职责内 | --- ## 8. 返回结构与异常规范 ### 8.1 统一信封 所有工具返回同一结构的 JSON 文本: ```json // 成功 { "ok": true, "tool": "redis_get_value", "db": 0, "key": "user:1", "value": "hello-mcp" } // 失败 { "ok": false, "tool": "redis_execute", "error": "命令 [FLUSHALL] 在 MCP-Redis 黑名单中,禁止执行" } ``` ### 8.2 截断与降级标记 | 字段 | 含义 | | --- | --- | | `value_truncated` / `value_original_length` | 字符串值被截断及原始长度 | | `_omitted` | 集合类型被省略的元素个数 | | `degraded` + `hint` | 超大 hash / set 已降级为 HSCAN / SSCAN,并给出续读建议 | | `next_cursor` / `finished` | SCAN 类工具的翻页游标与结束标志 | | `hint` | 面向 AI 的下一步工具建议 | ### 8.3 MCP 协议层错误处理 - **工具执行错误**:按 MCP 约定放入 `result.isError=true`(`ok:false` 时自动置位),大模型可读到并自我纠正; - **协议级错误**:返回 JSON-RPC `error`,如 `-32700` 解析失败、`-32601` 方法不存在、`-32602` 工具不存在; - **日志隔离**:stdout 被 MCP 协议独占,所有日志经 `Log` 输出至 stderr,避免污染协议流。 --- ## 9. 自测验收清单 仓库内置 `scripts/` 端到端测试(`fake_redis.py` 提供最小 RESP 服务端,`e2e_test.py` 覆盖全部工具的真实数据路径),交付前建议按以下条目逐项确认: 1. `java -jar` 启动后挂住不退出,stdout 无协议外输出; 2. 启动日志正确打印配置来源(`配置来源:...`); 3. `redis_health` 返回 `PONG` 与 Redis 版本; 4. `redis_info` 分节解析正常; 5. `redis_scan_keys` 大库分页正常,`next_cursor` 可翻页,`finished` 标志正确; 6. `redis_describe_key` 对不存在键返回 `exists:false`; 7. `redis_get_value` 超长值截断,超大 hash / set 降级; 8. `redis_set_*` 系列写入成功且 TTL 生效; 9. `redis_delete_by_pattern` 单次删除不超上限,游标续删闭环; 10. `redis_execute` 命中黑名单被拒绝(如 `SHUTDOWN`、`FLUSHALL`); 11. 只读模式下写入 / 管理工具不出现在 `tools/list` 中; 12. `Ctrl+C` / `kill -15` 后进程优雅退出,连接池正常关闭。 运行测试: ```bash mvn clean package -DskipTests python scripts/e2e_test.py ``` --- ## 10. FAQ **Q:能连接 Redis 集群或哨兵吗?** A:可以。连接指向代理层(如 `redis-cluster-proxy`、Codis)或启用 TLS 的实例均可;`CLUSTER` 等拓扑命令出于安全考虑被黑名单拦截。 **Q:为什么读文件有大小限制?** A:读取结果会进入 AI 上下文,超限会挤占对话空间甚至溢出。超长值统一截断,并附 `hint` 提示续读方式。 **Q:`redis_execute` 和专用工具怎么选?** A:优先用专用工具(有白名单与参数校验)。`redis_execute` 是兜底通道,仅用于专用工具未覆盖的场景,且始终受黑名单约束。 **Q:如何限制 AI 只能操作某个业务前缀?** A:设置 `redis.key-prefix`(如 `app:`)。此后所有键必须以此前缀开头,SCAN 的 `*` 也会被自动收窄为 `app:*`。 **Q:报错信息是中文的,有英文版吗?** A:工具返回内容当前为中文(面向使用者的自愈式提示),文档本身提供中英双语。 **Q:配置文件改了没生效?** A:检查启动日志中的「配置来源」,确认实际加载的是哪个文件;同时注意环境变量优先级高于 yml。 --- ## 11. 参与贡献 1. Fork 本仓库 2. 新建 `Feat_xxx` 分支 3. 提交代码(请保证自测清单全部通过) 4. 新建 Pull Request 新增工具请先完成设计评审:**工具名、入参出参、安全约束、异常提示**,四项齐备后再进入编码。 --- ## 12. License [Apache License 2.0](LICENSE) --- > **简体中文** | [English](README.en.md)