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.
Files changed (60) hide show
  1. {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/Dockerfile +34 -24
  2. {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/PKG-INFO +66 -2
  3. {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/README.md +64 -0
  4. 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
  5. {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/awslabs/valkey_mcp_server/main.py +14 -0
  6. {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/awslabs/valkey_mcp_server/tools/bitmap.py +5 -0
  7. {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/awslabs/valkey_mcp_server/tools/hash.py +17 -0
  8. {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/awslabs/valkey_mcp_server/tools/hyperloglog.py +5 -0
  9. {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/awslabs/valkey_mcp_server/tools/json.py +42 -7
  10. {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/awslabs/valkey_mcp_server/tools/list.py +49 -0
  11. {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/awslabs/valkey_mcp_server/tools/misc.py +13 -0
  12. {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/awslabs/valkey_mcp_server/tools/set.py +17 -0
  13. {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/awslabs/valkey_mcp_server/tools/sorted_set.py +33 -0
  14. {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/awslabs/valkey_mcp_server/tools/stream.py +33 -0
  15. {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/awslabs/valkey_mcp_server/tools/string.py +29 -0
  16. awslabs_valkey_mcp_server-1.0.4/docker-healthcheck.sh +25 -0
  17. {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/pyproject.toml +2 -2
  18. {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/tests/test_bitmap.py +24 -1
  19. {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/tests/test_hash.py +47 -4
  20. {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/tests/test_hyperloglog.py +17 -1
  21. awslabs_valkey_mcp_server-1.0.4/tests/test_json.py +365 -0
  22. awslabs_valkey_mcp_server-1.0.4/tests/test_json_additional.py +267 -0
  23. awslabs_valkey_mcp_server-1.0.4/tests/test_json_readonly.py +189 -0
  24. awslabs_valkey_mcp_server-1.0.4/tests/test_list_additional.py +100 -0
  25. awslabs_valkey_mcp_server-1.0.4/tests/test_list_readonly.py +173 -0
  26. {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/tests/test_main.py +1 -2
  27. awslabs_valkey_mcp_server-1.0.4/tests/test_misc.py +164 -0
  28. awslabs_valkey_mcp_server-1.0.4/tests/test_set_readonly.py +88 -0
  29. awslabs_valkey_mcp_server-1.0.4/tests/test_sorted_set_additional.py +322 -0
  30. awslabs_valkey_mcp_server-1.0.4/tests/test_sorted_set_readonly.py +131 -0
  31. awslabs_valkey_mcp_server-1.0.4/tests/test_stream_additional.py +159 -0
  32. awslabs_valkey_mcp_server-1.0.4/tests/test_stream_readonly.py +142 -0
  33. {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/tests/test_string.py +121 -6
  34. awslabs_valkey_mcp_server-1.0.4/uv-requirements.txt +26 -0
  35. {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/uv.lock +704 -504
  36. awslabs_valkey_mcp_server-1.0.2/tests/test_json.py +0 -437
  37. awslabs_valkey_mcp_server-1.0.2/tests/test_sorted_set_additional.py +0 -221
  38. {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/.gitignore +0 -0
  39. {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/.python-version +0 -0
  40. {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/CHANGELOG.md +0 -0
  41. {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/ELASTICACHECONNECT.md +0 -0
  42. {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/LICENSE +0 -0
  43. {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/NOTICE +0 -0
  44. {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/awslabs/__init__.py +0 -0
  45. {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/awslabs/valkey_mcp_server/__init__.py +0 -0
  46. {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/awslabs/valkey_mcp_server/common/__init__.py +0 -0
  47. {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/awslabs/valkey_mcp_server/common/config.py +0 -0
  48. {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/awslabs/valkey_mcp_server/common/connection.py +0 -0
  49. {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/awslabs/valkey_mcp_server/common/server.py +0 -0
  50. {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/awslabs/valkey_mcp_server/tools/__init__.py +0 -0
  51. {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/awslabs/valkey_mcp_server/tools/server_management.py +0 -0
  52. {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/awslabs/valkey_mcp_server/version.py +0 -0
  53. {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/tests/test_config.py +0 -0
  54. {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/tests/test_connection.py +0 -0
  55. {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/tests/test_init.py +0 -0
  56. {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/tests/test_list.py +0 -0
  57. {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/tests/test_server_management.py +0 -0
  58. {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/tests/test_set.py +0 -0
  59. {awslabs_valkey_mcp_server-1.0.2 → awslabs_valkey_mcp_server-1.0.4}/tests/test_sorted_set.py +0 -0
  60. {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
- #FROM public.ecr.aws/sam/build-python3.10:1.137.1-20250411084548
16
- FROM public.ecr.aws/sam/build-python3.10@sha256:d821662474d65f3cf2fc97dba2fa807a3adb580d02895fc4545527812550ea65 AS uv
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==0.7.11 && \
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/sam/build-python3.10@sha256:d821662474d65f3cf2fc97dba2fa807a3adb580d02895fc4545527812550ea65
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:/usr/sbin"
54
-
55
- # Install lsof for the healthcheck
56
- # Install other tools as needed for the MCP server
57
- # Add non-root user and ability to change directory into /root
58
- RUN yum update -y && \
59
- yum install -y lsof && \
60
- yum clean all -y && \
61
- rm -rf /var/cache/yum && \
62
- groupadd --force --system app && \
63
- useradd app -g app -d /app && \
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 --valkey-host and --valkey-port to connect to Valkey server
77
- HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 CMD [ "docker-healthcheck.sh" ]
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.2
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.6.0
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
+ | [![Install MCP Server](https://cursor.com/deeplink/mcp-install-light.svg)](https://cursor.com/install-mcp?name=awslabs.valkey-mcp-server&config=eyJjb21tYW5kIjoidXZ4IGF3c2xhYnMudmFsa2V5LW1jcC1zZXJ2ZXJAbGF0ZXN0IiwiZW52Ijp7IlZBTEtFWV9IT1NUIjoiMTI3LjAuMC4xIiwiVkFMS0VZX1BPUlQiOiI2Mzc5IiwiRkFTVE1DUF9MT0dfTEVWRUwiOiJFUlJPUiJ9LCJhdXRvQXBwcm92ZSI6W10sImRpc2FibGVkIjpmYWxzZX0%3D) | [![Install on VS Code](https://img.shields.io/badge/Install_on-VS_Code-FF9900?style=flat-square&logo=visualstudiocode&logoColor=white)](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
+ | [![Install MCP Server](https://cursor.com/deeplink/mcp-install-light.svg)](https://cursor.com/install-mcp?name=awslabs.valkey-mcp-server&config=eyJjb21tYW5kIjoidXZ4IGF3c2xhYnMudmFsa2V5LW1jcC1zZXJ2ZXJAbGF0ZXN0IiwiZW52Ijp7IlZBTEtFWV9IT1NUIjoiMTI3LjAuMC4xIiwiVkFMS0VZX1BPUlQiOiI2Mzc5IiwiRkFTVE1DUF9MT0dfTEVWRUwiOiJFUlJPUiJ9LCJhdXRvQXBwcm92ZSI6W10sImRpc2FibGVkIjpmYWxzZX0%3D) | [![Install on VS Code](https://img.shields.io/badge/Install_on-VS_Code-FF9900?style=flat-square&logo=visualstudiocode&logoColor=white)](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
- # Check if the process is running
18
- if ! pgrep -f "awslabs.valkey-mcp-server" > /dev/null; then
19
- echo "Process not running"
20
- exit 1
21
- fi
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
- # Check if the port is listening (default MCP server port is 8080)
24
- if ! lsof -i :8080 -sTCP:LISTEN > /dev/null; then
25
- echo "Port 8080 not listening"
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
- # All checks passed
30
- exit 0
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
- options = {}
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)