#
tokens: 3002/50000 7/7 files
lines: off (toggle) GitHub
raw markdown copy
# 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();
        }
    }
}    
```