awslabs.valkey-mcp-server 1.0.2__tar.gz → 1.0.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/Dockerfile +34 -24
- {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/PKG-INFO +66 -2
- {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/README.md +64 -0
- awslabs_valkey_mcp_server-1.0.2/docker-healthcheck.sh → awslabs_valkey_mcp_server-1.0.4/awslabs/valkey_mcp_server/context.py +23 -14
- {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/awslabs/valkey_mcp_server/main.py +14 -0
- {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/awslabs/valkey_mcp_server/tools/bitmap.py +5 -0
- {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/awslabs/valkey_mcp_server/tools/hash.py +17 -0
- {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/awslabs/valkey_mcp_server/tools/hyperloglog.py +5 -0
- {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/awslabs/valkey_mcp_server/tools/json.py +42 -7
- {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/awslabs/valkey_mcp_server/tools/list.py +49 -0
- {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/awslabs/valkey_mcp_server/tools/misc.py +13 -0
- {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/awslabs/valkey_mcp_server/tools/set.py +17 -0
- {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/awslabs/valkey_mcp_server/tools/sorted_set.py +33 -0
- {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/awslabs/valkey_mcp_server/tools/stream.py +33 -0
- {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/awslabs/valkey_mcp_server/tools/string.py +29 -0
- awslabs_valkey_mcp_server-1.0.4/docker-healthcheck.sh +25 -0
- {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/pyproject.toml +2 -2
- {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/tests/test_bitmap.py +24 -1
- {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/tests/test_hash.py +47 -4
- {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/tests/test_hyperloglog.py +17 -1
- awslabs_valkey_mcp_server-1.0.4/tests/test_json.py +365 -0
- awslabs_valkey_mcp_server-1.0.4/tests/test_json_additional.py +267 -0
- awslabs_valkey_mcp_server-1.0.4/tests/test_json_readonly.py +189 -0
- awslabs_valkey_mcp_server-1.0.4/tests/test_list_additional.py +100 -0
- awslabs_valkey_mcp_server-1.0.4/tests/test_list_readonly.py +173 -0
- {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/tests/test_main.py +1 -2
- awslabs_valkey_mcp_server-1.0.4/tests/test_misc.py +164 -0
- awslabs_valkey_mcp_server-1.0.4/tests/test_set_readonly.py +88 -0
- awslabs_valkey_mcp_server-1.0.4/tests/test_sorted_set_additional.py +322 -0
- awslabs_valkey_mcp_server-1.0.4/tests/test_sorted_set_readonly.py +131 -0
- awslabs_valkey_mcp_server-1.0.4/tests/test_stream_additional.py +159 -0
- awslabs_valkey_mcp_server-1.0.4/tests/test_stream_readonly.py +142 -0
- {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/tests/test_string.py +121 -6
- awslabs_valkey_mcp_server-1.0.4/uv-requirements.txt +26 -0
- {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/uv.lock +704 -504
- awslabs_valkey_mcp_server-1.0.2/tests/test_json.py +0 -437
- awslabs_valkey_mcp_server-1.0.2/tests/test_sorted_set_additional.py +0 -221
- {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/.gitignore +0 -0
- {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/.python-version +0 -0
- {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/CHANGELOG.md +0 -0
- {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/ELASTICACHECONNECT.md +0 -0
- {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/LICENSE +0 -0
- {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/NOTICE +0 -0
- {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/awslabs/__init__.py +0 -0
- {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/awslabs/valkey_mcp_server/__init__.py +0 -0
- {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/awslabs/valkey_mcp_server/common/__init__.py +0 -0
- {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/awslabs/valkey_mcp_server/common/config.py +0 -0
- {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/awslabs/valkey_mcp_server/common/connection.py +0 -0
- {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/awslabs/valkey_mcp_server/common/server.py +0 -0
- {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/awslabs/valkey_mcp_server/tools/__init__.py +0 -0
- {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/awslabs/valkey_mcp_server/tools/server_management.py +0 -0
- {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/awslabs/valkey_mcp_server/version.py +0 -0
- {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/tests/test_config.py +0 -0
- {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/tests/test_connection.py +0 -0
- {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/tests/test_init.py +0 -0
- {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/tests/test_list.py +0 -0
- {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/tests/test_server_management.py +0 -0
- {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/tests/test_set.py +0 -0
- {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/tests/test_sorted_set.py +0 -0
- {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/tests/test_stream.py +0 -0
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
-
#
|
|
16
|
-
FROM public.ecr.aws/
|
|
15
|
+
# dependabot should continue to update this to the latest hash.
|
|
16
|
+
FROM public.ecr.aws/docker/library/python:3.13.5-alpine3.21@sha256:c9a09c45a4bcc618c7f7128585b8dd0d41d0c31a8a107db4c8255ffe0b69375d AS uv
|
|
17
17
|
|
|
18
18
|
# Install the project into `/app`
|
|
19
19
|
WORKDIR /app
|
|
@@ -31,40 +31,50 @@ ENV UV_PYTHON_PREFERENCE=only-system
|
|
|
31
31
|
ENV UV_FROZEN=true
|
|
32
32
|
|
|
33
33
|
# Copy the required files first
|
|
34
|
-
COPY pyproject.toml uv.lock ./
|
|
34
|
+
COPY pyproject.toml uv.lock uv-requirements.txt ./
|
|
35
|
+
|
|
36
|
+
# Python optimization and uv configuration
|
|
37
|
+
ENV PIP_NO_CACHE_DIR=1 \
|
|
38
|
+
PIP_DISABLE_PIP_VERSION_CHECK=1
|
|
39
|
+
|
|
40
|
+
# Install system dependencies and Python package manager
|
|
41
|
+
RUN apk update && \
|
|
42
|
+
apk add --no-cache --virtual .build-deps \
|
|
43
|
+
build-base \
|
|
44
|
+
gcc \
|
|
45
|
+
musl-dev \
|
|
46
|
+
libffi-dev \
|
|
47
|
+
openssl-dev \
|
|
48
|
+
cargo
|
|
35
49
|
|
|
36
50
|
# Install the project's dependencies using the lockfile and settings
|
|
37
51
|
RUN --mount=type=cache,target=/root/.cache/uv \
|
|
38
|
-
pip install uv
|
|
39
|
-
uv sync --frozen --no-install-project --no-dev --no-editable
|
|
52
|
+
pip install --require-hashes --requirement uv-requirements.txt --no-cache-dir && \
|
|
53
|
+
uv sync --python 3.13 --frozen --no-install-project --no-dev --no-editable
|
|
40
54
|
|
|
41
55
|
# Then, add the rest of the project source code and install it
|
|
42
56
|
# Installing separately from its dependencies allows optimal layer caching
|
|
43
57
|
COPY . /app
|
|
44
58
|
RUN --mount=type=cache,target=/root/.cache/uv \
|
|
45
|
-
uv sync --frozen --no-dev --no-editable
|
|
59
|
+
uv sync --python 3.13 --frozen --no-dev --no-editable
|
|
46
60
|
|
|
47
61
|
# Make the directory just in case it doesn't exist
|
|
48
62
|
RUN mkdir -p /root/.local
|
|
49
63
|
|
|
50
|
-
FROM public.ecr.aws/
|
|
64
|
+
FROM public.ecr.aws/docker/library/python:3.13.5-alpine3.21@sha256:c9a09c45a4bcc618c7f7128585b8dd0d41d0c31a8a107db4c8255ffe0b69375d
|
|
51
65
|
|
|
52
66
|
# Place executables in the environment at the front of the path and include other binaries
|
|
53
|
-
ENV PATH="/app/.venv/bin:$PATH
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
# Install
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
chmod o+x /root
|
|
65
|
-
|
|
66
|
-
# Get the project from the uv layer
|
|
67
|
-
COPY --from=uv --chown=app:app /root/.local /root/.local
|
|
67
|
+
ENV PATH="/app/.venv/bin:$PATH" \
|
|
68
|
+
PYTHONUNBUFFERED=1
|
|
69
|
+
|
|
70
|
+
# Install runtime dependencies and create application user
|
|
71
|
+
RUN apk update && \
|
|
72
|
+
apk add --no-cache ca-certificates && \
|
|
73
|
+
update-ca-certificates && \
|
|
74
|
+
addgroup -S app && \
|
|
75
|
+
adduser -S app -G app -h /app
|
|
76
|
+
|
|
77
|
+
# Copy application artifacts from build stage
|
|
68
78
|
COPY --from=uv --chown=app:app /app/.venv /app/.venv
|
|
69
79
|
|
|
70
80
|
# Get healthcheck script
|
|
@@ -73,6 +83,6 @@ COPY ./docker-healthcheck.sh /usr/local/bin/docker-healthcheck.sh
|
|
|
73
83
|
# Run as non-root
|
|
74
84
|
USER app
|
|
75
85
|
|
|
76
|
-
# When running the container, add --
|
|
77
|
-
HEALTHCHECK --interval=
|
|
86
|
+
# When running the container, add --db-path and a bind mount to the host's db file
|
|
87
|
+
HEALTHCHECK --interval=60s --timeout=10s --start-period=10s --retries=3 CMD ["docker-healthcheck.sh"]
|
|
78
88
|
ENTRYPOINT ["awslabs.valkey-mcp-server"]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: awslabs.valkey-mcp-server
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.4
|
|
4
4
|
Summary: An AWS Labs Model Context Protocol (MCP) server for valkey
|
|
5
5
|
Project-URL: homepage, https://awslabs.github.io/mcp/
|
|
6
6
|
Project-URL: docs, https://awslabs.github.io/mcp/servers/valkey-mcp-server/
|
|
@@ -23,7 +23,7 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
23
23
|
Requires-Python: >=3.10
|
|
24
24
|
Requires-Dist: dotenv>=0.9.9
|
|
25
25
|
Requires-Dist: loguru>=0.7.0
|
|
26
|
-
Requires-Dist: mcp[cli]>=1.
|
|
26
|
+
Requires-Dist: mcp[cli]>=1.11.0
|
|
27
27
|
Requires-Dist: numpy>=2.2.4
|
|
28
28
|
Requires-Dist: pydantic>=2.10.6
|
|
29
29
|
Requires-Dist: valkey>=6.1.0
|
|
@@ -50,6 +50,7 @@ This MCP server provides tools to operate on Valkey data types. For example, it
|
|
|
50
50
|
- **Cluster Support**: Support for standalone and clustered Valkey deployments.
|
|
51
51
|
- **SSL/TLS Security**: Configure secure connections using SSL/TLS.
|
|
52
52
|
- **Connection Pooling**: Pools connections by default to enable efficient connection management.
|
|
53
|
+
- **Readonly Mode**: Prevent write operations to ensure data safety.
|
|
53
54
|
|
|
54
55
|
## Prerequisites
|
|
55
56
|
|
|
@@ -61,6 +62,10 @@ This MCP server provides tools to operate on Valkey data types. For example, it
|
|
|
61
62
|
|
|
62
63
|
## Installation
|
|
63
64
|
|
|
65
|
+
| Cursor | VS Code |
|
|
66
|
+
|:------:|:-------:|
|
|
67
|
+
| [](https://cursor.com/install-mcp?name=awslabs.valkey-mcp-server&config=eyJjb21tYW5kIjoidXZ4IGF3c2xhYnMudmFsa2V5LW1jcC1zZXJ2ZXJAbGF0ZXN0IiwiZW52Ijp7IlZBTEtFWV9IT1NUIjoiMTI3LjAuMC4xIiwiVkFMS0VZX1BPUlQiOiI2Mzc5IiwiRkFTVE1DUF9MT0dfTEVWRUwiOiJFUlJPUiJ9LCJhdXRvQXBwcm92ZSI6W10sImRpc2FibGVkIjpmYWxzZX0%3D) | [](https://insiders.vscode.dev/redirect/mcp/install?name=Valkey%20MCP%20Server&config=%7B%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22awslabs.valkey-mcp-server%40latest%22%5D%2C%22env%22%3A%7B%22VALKEY_HOST%22%3A%22127.0.0.1%22%2C%22VALKEY_PORT%22%3A%226379%22%2C%22FASTMCP_LOG_LEVEL%22%3A%22ERROR%22%7D%2C%22autoApprove%22%3A%5B%5D%2C%22disabled%22%3Afalse%7D) |
|
|
68
|
+
|
|
64
69
|
Here are some ways you can work with MCP across AWS tools (e.g., for Amazon Q Developer CLI MCP, `~/.aws/amazonq/mcp.json`):
|
|
65
70
|
|
|
66
71
|
```json
|
|
@@ -83,6 +88,29 @@ Here are some ways you can work with MCP across AWS tools (e.g., for Amazon Q De
|
|
|
83
88
|
}
|
|
84
89
|
```
|
|
85
90
|
|
|
91
|
+
To run in readonly mode:
|
|
92
|
+
|
|
93
|
+
```json
|
|
94
|
+
{
|
|
95
|
+
"mcpServers": {
|
|
96
|
+
"awslabs.valkey-mcp-server": {
|
|
97
|
+
"command": "uvx",
|
|
98
|
+
"args": [
|
|
99
|
+
"awslabs.valkey-mcp-server@latest",
|
|
100
|
+
"--readonly"
|
|
101
|
+
],
|
|
102
|
+
"env": {
|
|
103
|
+
"VALKEY_HOST": "127.0.0.1",
|
|
104
|
+
"VALKEY_PORT": "6379",
|
|
105
|
+
"FASTMCP_LOG_LEVEL": "ERROR"
|
|
106
|
+
},
|
|
107
|
+
"autoApprove": [],
|
|
108
|
+
"disabled": false
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
86
114
|
Or using Docker after a successful `docker build -t awslabs/valkey-mcp-server .`:
|
|
87
115
|
|
|
88
116
|
```json
|
|
@@ -110,6 +138,34 @@ Or using Docker after a successful `docker build -t awslabs/valkey-mcp-server .`
|
|
|
110
138
|
}
|
|
111
139
|
```
|
|
112
140
|
|
|
141
|
+
To run in readonly mode with Docker:
|
|
142
|
+
|
|
143
|
+
```json
|
|
144
|
+
{
|
|
145
|
+
"mcpServers": {
|
|
146
|
+
"awslabs.valkey-mcp-server": {
|
|
147
|
+
"command": "docker",
|
|
148
|
+
"args": [
|
|
149
|
+
"run",
|
|
150
|
+
"--rm",
|
|
151
|
+
"--interactive",
|
|
152
|
+
"--env",
|
|
153
|
+
"FASTMCP_LOG_LEVEL=ERROR",
|
|
154
|
+
"--env",
|
|
155
|
+
"VALKEY_HOST=127.0.0.1",
|
|
156
|
+
"--env",
|
|
157
|
+
"VALKEY_PORT=6379",
|
|
158
|
+
"awslabs/valkey-mcp-server:latest",
|
|
159
|
+
"--readonly"
|
|
160
|
+
],
|
|
161
|
+
"env": {},
|
|
162
|
+
"disabled": false,
|
|
163
|
+
"autoApprove": []
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
113
169
|
## Configuration
|
|
114
170
|
|
|
115
171
|
The server can be configured using the following environment variables:
|
|
@@ -163,3 +219,11 @@ docker run -p 8080:8080 \
|
|
|
163
219
|
-e VALKEY_PORT=6379 \
|
|
164
220
|
awslabs/valkey-mcp-server
|
|
165
221
|
```
|
|
222
|
+
|
|
223
|
+
To run in readonly mode:
|
|
224
|
+
```bash
|
|
225
|
+
docker run -p 8080:8080 \
|
|
226
|
+
-e VALKEY_HOST=host.docker.internal \
|
|
227
|
+
-e VALKEY_PORT=6379 \
|
|
228
|
+
awslabs/valkey-mcp-server --readonly
|
|
229
|
+
```
|
|
@@ -19,6 +19,7 @@ This MCP server provides tools to operate on Valkey data types. For example, it
|
|
|
19
19
|
- **Cluster Support**: Support for standalone and clustered Valkey deployments.
|
|
20
20
|
- **SSL/TLS Security**: Configure secure connections using SSL/TLS.
|
|
21
21
|
- **Connection Pooling**: Pools connections by default to enable efficient connection management.
|
|
22
|
+
- **Readonly Mode**: Prevent write operations to ensure data safety.
|
|
22
23
|
|
|
23
24
|
## Prerequisites
|
|
24
25
|
|
|
@@ -30,6 +31,10 @@ This MCP server provides tools to operate on Valkey data types. For example, it
|
|
|
30
31
|
|
|
31
32
|
## Installation
|
|
32
33
|
|
|
34
|
+
| Cursor | VS Code |
|
|
35
|
+
|:------:|:-------:|
|
|
36
|
+
| [](https://cursor.com/install-mcp?name=awslabs.valkey-mcp-server&config=eyJjb21tYW5kIjoidXZ4IGF3c2xhYnMudmFsa2V5LW1jcC1zZXJ2ZXJAbGF0ZXN0IiwiZW52Ijp7IlZBTEtFWV9IT1NUIjoiMTI3LjAuMC4xIiwiVkFMS0VZX1BPUlQiOiI2Mzc5IiwiRkFTVE1DUF9MT0dfTEVWRUwiOiJFUlJPUiJ9LCJhdXRvQXBwcm92ZSI6W10sImRpc2FibGVkIjpmYWxzZX0%3D) | [](https://insiders.vscode.dev/redirect/mcp/install?name=Valkey%20MCP%20Server&config=%7B%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22awslabs.valkey-mcp-server%40latest%22%5D%2C%22env%22%3A%7B%22VALKEY_HOST%22%3A%22127.0.0.1%22%2C%22VALKEY_PORT%22%3A%226379%22%2C%22FASTMCP_LOG_LEVEL%22%3A%22ERROR%22%7D%2C%22autoApprove%22%3A%5B%5D%2C%22disabled%22%3Afalse%7D) |
|
|
37
|
+
|
|
33
38
|
Here are some ways you can work with MCP across AWS tools (e.g., for Amazon Q Developer CLI MCP, `~/.aws/amazonq/mcp.json`):
|
|
34
39
|
|
|
35
40
|
```json
|
|
@@ -52,6 +57,29 @@ Here are some ways you can work with MCP across AWS tools (e.g., for Amazon Q De
|
|
|
52
57
|
}
|
|
53
58
|
```
|
|
54
59
|
|
|
60
|
+
To run in readonly mode:
|
|
61
|
+
|
|
62
|
+
```json
|
|
63
|
+
{
|
|
64
|
+
"mcpServers": {
|
|
65
|
+
"awslabs.valkey-mcp-server": {
|
|
66
|
+
"command": "uvx",
|
|
67
|
+
"args": [
|
|
68
|
+
"awslabs.valkey-mcp-server@latest",
|
|
69
|
+
"--readonly"
|
|
70
|
+
],
|
|
71
|
+
"env": {
|
|
72
|
+
"VALKEY_HOST": "127.0.0.1",
|
|
73
|
+
"VALKEY_PORT": "6379",
|
|
74
|
+
"FASTMCP_LOG_LEVEL": "ERROR"
|
|
75
|
+
},
|
|
76
|
+
"autoApprove": [],
|
|
77
|
+
"disabled": false
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
55
83
|
Or using Docker after a successful `docker build -t awslabs/valkey-mcp-server .`:
|
|
56
84
|
|
|
57
85
|
```json
|
|
@@ -79,6 +107,34 @@ Or using Docker after a successful `docker build -t awslabs/valkey-mcp-server .`
|
|
|
79
107
|
}
|
|
80
108
|
```
|
|
81
109
|
|
|
110
|
+
To run in readonly mode with Docker:
|
|
111
|
+
|
|
112
|
+
```json
|
|
113
|
+
{
|
|
114
|
+
"mcpServers": {
|
|
115
|
+
"awslabs.valkey-mcp-server": {
|
|
116
|
+
"command": "docker",
|
|
117
|
+
"args": [
|
|
118
|
+
"run",
|
|
119
|
+
"--rm",
|
|
120
|
+
"--interactive",
|
|
121
|
+
"--env",
|
|
122
|
+
"FASTMCP_LOG_LEVEL=ERROR",
|
|
123
|
+
"--env",
|
|
124
|
+
"VALKEY_HOST=127.0.0.1",
|
|
125
|
+
"--env",
|
|
126
|
+
"VALKEY_PORT=6379",
|
|
127
|
+
"awslabs/valkey-mcp-server:latest",
|
|
128
|
+
"--readonly"
|
|
129
|
+
],
|
|
130
|
+
"env": {},
|
|
131
|
+
"disabled": false,
|
|
132
|
+
"autoApprove": []
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
82
138
|
## Configuration
|
|
83
139
|
|
|
84
140
|
The server can be configured using the following environment variables:
|
|
@@ -132,3 +188,11 @@ docker run -p 8080:8080 \
|
|
|
132
188
|
-e VALKEY_PORT=6379 \
|
|
133
189
|
awslabs/valkey-mcp-server
|
|
134
190
|
```
|
|
191
|
+
|
|
192
|
+
To run in readonly mode:
|
|
193
|
+
```bash
|
|
194
|
+
docker run -p 8080:8080 \
|
|
195
|
+
-e VALKEY_HOST=host.docker.internal \
|
|
196
|
+
-e VALKEY_PORT=6379 \
|
|
197
|
+
awslabs/valkey-mcp-server --readonly
|
|
198
|
+
```
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
|
|
3
1
|
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
4
2
|
#
|
|
5
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -14,17 +12,28 @@
|
|
|
14
12
|
# See the License for the specific language governing permissions and
|
|
15
13
|
# limitations under the License.
|
|
16
14
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
15
|
+
"""Context management for Valkey MCP Server."""
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class Context:
|
|
19
|
+
"""Context class for Valkey MCP Server."""
|
|
20
|
+
|
|
21
|
+
_readonly = False
|
|
22
|
+
|
|
23
|
+
@classmethod
|
|
24
|
+
def initialize(cls, readonly: bool = False):
|
|
25
|
+
"""Initialize the context.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
readonly: Whether to run in readonly mode
|
|
29
|
+
"""
|
|
30
|
+
cls._readonly = readonly
|
|
22
31
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
exit 1
|
|
27
|
-
fi
|
|
32
|
+
@classmethod
|
|
33
|
+
def readonly_mode(cls) -> bool:
|
|
34
|
+
"""Check if the server is running in readonly mode.
|
|
28
35
|
|
|
29
|
-
|
|
30
|
-
|
|
36
|
+
Returns:
|
|
37
|
+
True if readonly mode is enabled, False otherwise
|
|
38
|
+
"""
|
|
39
|
+
return cls._readonly
|
|
@@ -14,7 +14,9 @@
|
|
|
14
14
|
|
|
15
15
|
"""awslabs valkey MCP Server implementation."""
|
|
16
16
|
|
|
17
|
+
import argparse
|
|
17
18
|
from awslabs.valkey_mcp_server.common.server import mcp
|
|
19
|
+
from awslabs.valkey_mcp_server.context import Context
|
|
18
20
|
from awslabs.valkey_mcp_server.tools import (
|
|
19
21
|
bitmap, # noqa: F401
|
|
20
22
|
hash, # noqa: F401
|
|
@@ -56,6 +58,18 @@ class ValkeyMCPServer:
|
|
|
56
58
|
|
|
57
59
|
def main():
|
|
58
60
|
"""Run the MCP server with CLI argument support."""
|
|
61
|
+
parser = argparse.ArgumentParser(
|
|
62
|
+
description='An AWS Labs Model Context Protocol (MCP) server for interacting with Valkey'
|
|
63
|
+
)
|
|
64
|
+
parser.add_argument(
|
|
65
|
+
'--readonly',
|
|
66
|
+
action=argparse.BooleanOptionalAction,
|
|
67
|
+
help='Prevents the MCP server from performing mutating operations',
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
args = parser.parse_args()
|
|
71
|
+
Context.initialize(args.readonly)
|
|
72
|
+
|
|
59
73
|
logger.info('Amazon ElastiCache/MemoryDB Valkey MCP Server Started...')
|
|
60
74
|
|
|
61
75
|
server = ValkeyMCPServer()
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
from awslabs.valkey_mcp_server.common.connection import ValkeyConnectionManager
|
|
18
18
|
from awslabs.valkey_mcp_server.common.server import mcp
|
|
19
|
+
from awslabs.valkey_mcp_server.context import Context
|
|
19
20
|
from typing import Optional
|
|
20
21
|
from valkey.exceptions import ValkeyError
|
|
21
22
|
|
|
@@ -32,6 +33,10 @@ async def bitmap_set(key: str, offset: int, value: int) -> str:
|
|
|
32
33
|
Returns:
|
|
33
34
|
Success message or error message
|
|
34
35
|
"""
|
|
36
|
+
# Check if readonly mode is enabled
|
|
37
|
+
if Context.readonly_mode():
|
|
38
|
+
return 'Error: Cannot set bitmap bit in readonly mode'
|
|
39
|
+
|
|
35
40
|
try:
|
|
36
41
|
if value not in (0, 1):
|
|
37
42
|
return f'Error: value must be 0 or 1, got {value}'
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
from awslabs.valkey_mcp_server.common.connection import ValkeyConnectionManager
|
|
18
18
|
from awslabs.valkey_mcp_server.common.server import mcp
|
|
19
|
+
from awslabs.valkey_mcp_server.context import Context
|
|
19
20
|
from typing import Any, Dict, Optional, Union
|
|
20
21
|
from valkey.exceptions import ValkeyError
|
|
21
22
|
|
|
@@ -32,6 +33,10 @@ async def hash_set(key: str, field: str, value: Any) -> str:
|
|
|
32
33
|
Returns:
|
|
33
34
|
Success message or error message
|
|
34
35
|
"""
|
|
36
|
+
# Check if readonly mode is enabled
|
|
37
|
+
if Context.readonly_mode():
|
|
38
|
+
return 'Error: Cannot set hash field in readonly mode'
|
|
39
|
+
|
|
35
40
|
try:
|
|
36
41
|
r = ValkeyConnectionManager.get_connection()
|
|
37
42
|
r.hset(key, field, value)
|
|
@@ -51,6 +56,10 @@ async def hash_set_multiple(key: str, mapping: Dict[str, Any]) -> str:
|
|
|
51
56
|
Returns:
|
|
52
57
|
Success message or error message
|
|
53
58
|
"""
|
|
59
|
+
# Check if readonly mode is enabled
|
|
60
|
+
if Context.readonly_mode():
|
|
61
|
+
return 'Error: Cannot set multiple hash fields in readonly mode'
|
|
62
|
+
|
|
54
63
|
try:
|
|
55
64
|
r = ValkeyConnectionManager.get_connection()
|
|
56
65
|
result = r.hset(key, mapping=mapping)
|
|
@@ -71,6 +80,10 @@ async def hash_set_if_not_exists(key: str, field: str, value: Any) -> str:
|
|
|
71
80
|
Returns:
|
|
72
81
|
Success message or error message
|
|
73
82
|
"""
|
|
83
|
+
# Check if readonly mode is enabled
|
|
84
|
+
if Context.readonly_mode():
|
|
85
|
+
return 'Error: Cannot set hash field in readonly mode'
|
|
86
|
+
|
|
74
87
|
try:
|
|
75
88
|
r = ValkeyConnectionManager.get_connection()
|
|
76
89
|
result = r.hsetnx(key, field, value)
|
|
@@ -153,6 +166,10 @@ async def hash_increment(key: str, field: str, amount: Union[int, float] = 1) ->
|
|
|
153
166
|
Returns:
|
|
154
167
|
New value or error message
|
|
155
168
|
"""
|
|
169
|
+
# Check if readonly mode is enabled
|
|
170
|
+
if Context.readonly_mode():
|
|
171
|
+
return 'Error: Cannot increment hash field in readonly mode'
|
|
172
|
+
|
|
156
173
|
try:
|
|
157
174
|
r = ValkeyConnectionManager.get_connection()
|
|
158
175
|
if isinstance(amount, int):
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
from awslabs.valkey_mcp_server.common.connection import ValkeyConnectionManager
|
|
18
18
|
from awslabs.valkey_mcp_server.common.server import mcp
|
|
19
|
+
from awslabs.valkey_mcp_server.context import Context
|
|
19
20
|
from valkey.exceptions import ValkeyError
|
|
20
21
|
|
|
21
22
|
|
|
@@ -30,6 +31,10 @@ async def hll_add(key: str, element: str) -> str:
|
|
|
30
31
|
Returns:
|
|
31
32
|
Success message or error message
|
|
32
33
|
"""
|
|
34
|
+
# Check if readonly mode is enabled
|
|
35
|
+
if Context.readonly_mode():
|
|
36
|
+
return 'Error: Cannot add to HyperLogLog in readonly mode'
|
|
37
|
+
|
|
33
38
|
try:
|
|
34
39
|
if not element:
|
|
35
40
|
return 'Error: an element is required'
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
from awslabs.valkey_mcp_server.common.connection import ValkeyConnectionManager
|
|
18
18
|
from awslabs.valkey_mcp_server.common.server import mcp
|
|
19
|
+
from awslabs.valkey_mcp_server.context import Context
|
|
19
20
|
from typing import Any, Optional, Union
|
|
20
21
|
from valkey.exceptions import ValkeyError
|
|
21
22
|
|
|
@@ -34,15 +35,13 @@ async def json_set(key: str, path: str, value: Any, nx: bool = False, xx: bool =
|
|
|
34
35
|
Returns:
|
|
35
36
|
Success message or error message
|
|
36
37
|
"""
|
|
38
|
+
# Check if readonly mode is enabled
|
|
39
|
+
if Context.readonly_mode():
|
|
40
|
+
return 'Error: Cannot set JSON value in readonly mode'
|
|
41
|
+
|
|
37
42
|
try:
|
|
38
43
|
r = ValkeyConnectionManager.get_connection()
|
|
39
|
-
|
|
40
|
-
if nx:
|
|
41
|
-
options['nx'] = True
|
|
42
|
-
if xx:
|
|
43
|
-
options['xx'] = True
|
|
44
|
-
|
|
45
|
-
result = r.json().set(key, path, value, **options)
|
|
44
|
+
result = r.json().set(key, path, value, nx=nx, xx=xx)
|
|
46
45
|
if result:
|
|
47
46
|
return f"Successfully set value at path '{path}' in '{key}'"
|
|
48
47
|
return f"Failed to set value at path '{path}' in '{key}' (path condition not met)"
|
|
@@ -121,6 +120,10 @@ async def json_numincrby(key: str, path: str, value: Union[int, float]) -> str:
|
|
|
121
120
|
Returns:
|
|
122
121
|
New value or error message
|
|
123
122
|
"""
|
|
123
|
+
# Check if readonly mode is enabled
|
|
124
|
+
if Context.readonly_mode():
|
|
125
|
+
return 'Error: Cannot increment JSON value in readonly mode'
|
|
126
|
+
|
|
124
127
|
try:
|
|
125
128
|
r = ValkeyConnectionManager.get_connection()
|
|
126
129
|
# Convert float to int by rounding if needed
|
|
@@ -143,6 +146,10 @@ async def json_nummultby(key: str, path: str, value: Union[int, float]) -> str:
|
|
|
143
146
|
Returns:
|
|
144
147
|
New value or error message
|
|
145
148
|
"""
|
|
149
|
+
# Check if readonly mode is enabled
|
|
150
|
+
if Context.readonly_mode():
|
|
151
|
+
return 'Error: Cannot multiply JSON value in readonly mode'
|
|
152
|
+
|
|
146
153
|
try:
|
|
147
154
|
r = ValkeyConnectionManager.get_connection()
|
|
148
155
|
# Convert float to int by rounding if needed
|
|
@@ -165,6 +172,10 @@ async def json_strappend(key: str, path: str, value: str) -> str:
|
|
|
165
172
|
Returns:
|
|
166
173
|
New string length or error message
|
|
167
174
|
"""
|
|
175
|
+
# Check if readonly mode is enabled
|
|
176
|
+
if Context.readonly_mode():
|
|
177
|
+
return 'Error: Cannot append to JSON string in readonly mode'
|
|
178
|
+
|
|
168
179
|
try:
|
|
169
180
|
r = ValkeyConnectionManager.get_connection()
|
|
170
181
|
result = r.json().strappend(key, path, value)
|
|
@@ -206,6 +217,10 @@ async def json_arrappend(key: str, path: str, *values: Any) -> str:
|
|
|
206
217
|
Returns:
|
|
207
218
|
New array length or error message
|
|
208
219
|
"""
|
|
220
|
+
# Check if readonly mode is enabled
|
|
221
|
+
if Context.readonly_mode():
|
|
222
|
+
return 'Error: Cannot append to JSON array in readonly mode'
|
|
223
|
+
|
|
209
224
|
try:
|
|
210
225
|
if not values:
|
|
211
226
|
return 'Error: at least one value is required'
|
|
@@ -285,6 +300,10 @@ async def json_arrpop(key: str, path: str, index: int = -1) -> str:
|
|
|
285
300
|
Returns:
|
|
286
301
|
Popped value or error message
|
|
287
302
|
"""
|
|
303
|
+
# Check if readonly mode is enabled
|
|
304
|
+
if Context.readonly_mode():
|
|
305
|
+
return 'Error: Cannot pop from JSON array in readonly mode'
|
|
306
|
+
|
|
288
307
|
try:
|
|
289
308
|
r = ValkeyConnectionManager.get_connection()
|
|
290
309
|
result = r.json().arrpop(key, path, index)
|
|
@@ -308,6 +327,10 @@ async def json_arrtrim(key: str, path: str, start: int, stop: int) -> str:
|
|
|
308
327
|
Returns:
|
|
309
328
|
New array length or error message
|
|
310
329
|
"""
|
|
330
|
+
# Check if readonly mode is enabled
|
|
331
|
+
if Context.readonly_mode():
|
|
332
|
+
return 'Error: Cannot trim JSON array in readonly mode'
|
|
333
|
+
|
|
311
334
|
try:
|
|
312
335
|
r = ValkeyConnectionManager.get_connection()
|
|
313
336
|
result = r.json().arrtrim(key, path, start, stop)
|
|
@@ -373,6 +396,10 @@ async def json_toggle(key: str, path: str) -> str:
|
|
|
373
396
|
Returns:
|
|
374
397
|
New boolean value or error message
|
|
375
398
|
"""
|
|
399
|
+
# Check if readonly mode is enabled
|
|
400
|
+
if Context.readonly_mode():
|
|
401
|
+
return 'Error: Cannot toggle JSON boolean in readonly mode'
|
|
402
|
+
|
|
376
403
|
try:
|
|
377
404
|
r = ValkeyConnectionManager.get_connection()
|
|
378
405
|
result = r.json().toggle(key, path)
|
|
@@ -394,6 +421,10 @@ async def json_clear(key: str, path: str) -> str:
|
|
|
394
421
|
Returns:
|
|
395
422
|
Success message or error message
|
|
396
423
|
"""
|
|
424
|
+
# Check if readonly mode is enabled
|
|
425
|
+
if Context.readonly_mode():
|
|
426
|
+
return 'Error: Cannot clear JSON container in readonly mode'
|
|
427
|
+
|
|
397
428
|
try:
|
|
398
429
|
r = ValkeyConnectionManager.get_connection()
|
|
399
430
|
result = r.json().clear(key, path)
|
|
@@ -415,6 +446,10 @@ async def json_del(key: str, path: str) -> str:
|
|
|
415
446
|
Returns:
|
|
416
447
|
Success message or error message
|
|
417
448
|
"""
|
|
449
|
+
# Check if readonly mode is enabled
|
|
450
|
+
if Context.readonly_mode():
|
|
451
|
+
return 'Error: Cannot delete JSON value in readonly mode'
|
|
452
|
+
|
|
418
453
|
try:
|
|
419
454
|
r = ValkeyConnectionManager.get_connection()
|
|
420
455
|
result = r.json().delete(key, path)
|