# Directory Structure
```
├── .gitignore
├── pom.xml
├── README.md
└── src
└── main
├── java
│ └── com
│ └── redis
│ └── mcp
│ ├── config
│ │ └── RedisMcpServerConfiguration.java
│ ├── RedisMcpServerApplication.java
│ └── service
│ └── RedisToolService.java
└── resources
└── application.properties
```
# Files
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
```
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/
```
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
```markdown
# Redis MCP Server
A Redis Management and Control Protocol (MCP) server implementation using Spring Boot and Spring AI.
## Description
This project implements a Redis MCP server that provides a set of tools for Redis operations. It uses `spring-ai-mcp-server-webmvc-spring-boot-starter` to implement MCP Server-Sent Events (SSE) functionality.
## Prerequisites
- JDK 17 or higher
- Maven 3.6 or higher
- Redis server
## Components
- Spring Boot
- Spring AI
- Spring Data Redis
- Lettuce Redis Client
- Jackson
- spring-ai-mcp-server-webmvc-spring-boot-starter
## Features
- Redis key-value operations (set, get, delete)
- Pattern-based key listing
- Optional key expiration time
- SSE-based MCP implementation
## Configuration
### Server Configuration
The Redis connection can be configured using the `redis.url` system property. Default value is `redis://localhost:6379`.
Example:
```bash
java -Dredis.url=redis://your-redis-host:6379 -jar your-app.jar
```
### Cursor Tool Configuration
To use this MCP server in Cursor, add the following configuration to your Cursor settings:
```json
{
"redis-mcp-server": {
"url": "http://localhost:8080/sse",
"enabled": true
}
}
```
## Building
```bash
mvn clean package
```
## Running
```bash
java -jar target/redis-mcp-server-{version}.jar
```
## API Endpoints
The server exposes the following MCP tools:
- `set`: Set a Redis key-value pair with optional expiration time
- `get`: Get value from Redis by key
- `delete`: Delete one or multiple keys from Redis
- `list`: List Redis keys matching a pattern
## License
This project is licensed under the MIT License.
```
--------------------------------------------------------------------------------
/src/main/resources/application.properties:
--------------------------------------------------------------------------------
```
server.port=8080
spring.application.name=redis-mcp-server
spring.main.bannerMode=off
logging.pattern.console=
server.servlet.encoding.charset=utf-8
```
--------------------------------------------------------------------------------
/src/main/java/com/redis/mcp/RedisMcpServerApplication.java:
--------------------------------------------------------------------------------
```java
package com.redis.mcp;
import com.redis.mcp.service.RedisToolService;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.ai.tool.method.MethodToolCallbackProvider;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
/**
* Main application class for Redis MCP Server
* @author yue9527
*/
@SpringBootApplication
public class RedisMcpServerApplication {
/**
* Main method to start the Spring Boot application
* @param args Command line arguments
*/
public static void main(String[] args) {
SpringApplication.run(RedisMcpServerApplication.class, args);
}
/**
* Creates a ToolCallbackProvider bean for Redis tools
* @param redisToolService RedisToolService instance
* @return Configured ToolCallbackProvider
*/
@Bean
public ToolCallbackProvider redisTools(RedisToolService redisToolService) {
return MethodToolCallbackProvider.builder().toolObjects(redisToolService).build();
}
}
```
--------------------------------------------------------------------------------
/src/main/java/com/redis/mcp/config/RedisMcpServerConfiguration.java:
--------------------------------------------------------------------------------
```java
package com.redis.mcp.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
* Configuration class for Redis MCP Server
* @author yue9527
*/
@Configuration
public class RedisMcpServerConfiguration {
/**
* Creates a LettuceConnectionFactory bean for Redis connection
* @return Configured LettuceConnectionFactory
*/
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
String redisUrl = System.getProperty("redis.url", "redis://localhost:6379");
String[] parts = redisUrl.replace("redis://", "").split(":");
String host = parts[0];
int port = Integer.parseInt(parts[1]);
RedisStandaloneConfiguration config = new RedisStandaloneConfiguration(host, port);
return new LettuceConnectionFactory(config);
}
/**
* Creates a StringRedisTemplate bean for Redis operations
* @param redisConnectionFactory LettuceConnectionFactory instance
* @return Configured StringRedisTemplate
*/
@Bean
public StringRedisTemplate redisTemplate(LettuceConnectionFactory redisConnectionFactory) {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new StringRedisSerializer());
return template;
}
}
```
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
```
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.redis</groupId>
<artifactId>redis-mcp-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>redis-mcp-server</name>
<description>redis-mcp-server</description>
<url/>
<licenses>
<license/>
</licenses>
<developers>
<developer/>
</developers>
<scm>
<connection/>
<developerConnection/>
<tag/>
<url/>
</scm>
<properties>
<java.version>17</java.version>
<mcp.version>1.0.0-M6</mcp.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-mcp-server-webmvc-spring-boot-starter</artifactId>
<version>1.0.0-M6</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.43</version>
</dependency>
<!-- Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.8</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
```
--------------------------------------------------------------------------------
/src/main/java/com/redis/mcp/service/RedisToolService.java:
--------------------------------------------------------------------------------
```java
package com.redis.mcp.service;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
/**
* Redis Tool Service for handling Redis operations
* @author yue9527
*/
@Service
public class RedisToolService {
private final StringRedisTemplate redisTemplate;
private final ObjectMapper objectMapper;
/**
* Constructor for RedisToolService
* @param redisTemplate StringRedisTemplate instance
* @param objectMapper ObjectMapper instance
*/
public RedisToolService(StringRedisTemplate redisTemplate, ObjectMapper objectMapper) {
this.redisTemplate = redisTemplate;
this.objectMapper = objectMapper;
}
/**
* Set a key-value pair in Redis with optional expiration time
* @param jsonArgs JSON string containing key, value and optional expireSeconds
* @return Operation result message
*/
@Tool(name = "set", description = "Set a Redis key-value pair with optional expiration time")
public String setValue(String jsonArgs) {
try {
Map<String, Object> args = objectMapper.readValue(jsonArgs, Map.class);
String key = (String) args.get("key");
String value = (String) args.get("value");
Integer expireSeconds = (Integer) args.get("expireSeconds");
if (expireSeconds != null) {
redisTemplate.opsForValue().set(key, value, expireSeconds);
} else {
redisTemplate.opsForValue().set(key, value);
}
return "Successfully set key: " + key;
} catch (IOException e) {
return "Error parsing JSON arguments: " + e.getMessage();
}
}
/**
* Get value from Redis by key
* @param jsonArgs JSON string containing the key
* @return Retrieved value or error message
*/
@Tool(name = "get", description = "Get value from Redis by key")
public String getValue(String jsonArgs) {
try {
Map<String, Object> args = objectMapper.readValue(jsonArgs, Map.class);
String key = (String) args.get("keys");
String result = redisTemplate.opsForValue().get(key);
if (result == null) {
return "Key not found: " + key;
}
return result;
} catch (Exception e) {
return "Error parsing JSON arguments: " + e.getMessage();
}
}
/**
* Delete one or multiple keys from Redis
* @param jsonArgs JSON string containing key(s) to delete
* @return Operation result message
*/
@Tool(name = "delete", description = "Delete one or multiple keys from Redis")
public String deleteValue(String jsonArgs) {
try {
Map<String, Object> args = objectMapper.readValue(jsonArgs, Map.class);
Object keyObj = args.get("keys");
if (keyObj instanceof List) {
List<String> keys = (List<String>) keyObj;
redisTemplate.delete(keys);
return "Successfully deleted " + keys.size() + " keys";
} else {
String key = (String) keyObj;
redisTemplate.delete(key);
return "Successfully deleted key: " + key;
}
} catch (IOException e) {
return "Error parsing JSON arguments: " + e.getMessage();
}
}
/**
* List Redis keys matching a pattern
* @param jsonArgs JSON string containing optional pattern
* @return List of matching keys or error message
*/
@Tool(name = "list", description = "List Redis keys matching a pattern")
public String listKeys(String jsonArgs) {
try {
Map<String, Object> args = new HashMap<>();
if (StringUtils.hasLength(jsonArgs)) {
args = objectMapper.readValue(jsonArgs, Map.class);
}
String pattern = (String) args.getOrDefault("pattern", "*");
List<String> keys = redisTemplate.keys(pattern).stream().collect(Collectors.toList());
return keys.size() > 0 ? "Found keys:\n" + String.join("\n", keys) : "No keys found matching the pattern";
} catch (IOException e) {
return "Error parsing JSON arguments: " + e.getMessage();
}
}
}
```