cli-mcp-server 0.2.0__py3-none-any.whl → 0.2.1__py3-none-any.whl
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.
- cli_mcp_server/server.py +31 -14
- {cli_mcp_server-0.2.0.dist-info → cli_mcp_server-0.2.1.dist-info}/METADATA +7 -4
- cli_mcp_server-0.2.1.dist-info/RECORD +7 -0
- {cli_mcp_server-0.2.0.dist-info → cli_mcp_server-0.2.1.dist-info}/WHEEL +1 -1
- cli_mcp_server-0.2.0.dist-info/RECORD +0 -7
- {cli_mcp_server-0.2.0.dist-info → cli_mcp_server-0.2.1.dist-info}/entry_points.txt +0 -0
- {cli_mcp_server-0.2.0.dist-info → cli_mcp_server-0.2.1.dist-info}/licenses/LICENSE +0 -0
cli_mcp_server/server.py
CHANGED
@@ -47,6 +47,8 @@ class SecurityConfig:
|
|
47
47
|
allowed_flags: set[str]
|
48
48
|
max_command_length: int
|
49
49
|
command_timeout: int
|
50
|
+
allow_all_commands: bool = False
|
51
|
+
allow_all_flags: bool = False
|
50
52
|
|
51
53
|
|
52
54
|
class CommandExecutor:
|
@@ -109,15 +111,15 @@ class CommandExecutor:
|
|
109
111
|
|
110
112
|
command, args = parts[0], parts[1:]
|
111
113
|
|
112
|
-
# Validate command
|
113
|
-
if command not in self.security_config.allowed_commands:
|
114
|
+
# Validate command if not in allow-all mode
|
115
|
+
if not self.security_config.allow_all_commands and command not in self.security_config.allowed_commands:
|
114
116
|
raise CommandSecurityError(f"Command '{command}' is not allowed")
|
115
117
|
|
116
118
|
# Process and validate arguments
|
117
119
|
validated_args = []
|
118
120
|
for arg in args:
|
119
121
|
if arg.startswith("-"):
|
120
|
-
if arg not in self.security_config.allowed_flags:
|
122
|
+
if not self.security_config.allow_all_flags and arg not in self.security_config.allowed_flags:
|
121
123
|
raise CommandSecurityError(f"Flag '{arg}' is not allowed")
|
122
124
|
validated_args.append(arg)
|
123
125
|
continue
|
@@ -224,19 +226,28 @@ def load_security_config() -> SecurityConfig:
|
|
224
226
|
- allowed_flags: Set of permitted command flags/options
|
225
227
|
- max_command_length: Maximum length of command string
|
226
228
|
- command_timeout: Maximum execution time in seconds
|
229
|
+
- allow_all_commands: Whether all commands are allowed
|
230
|
+
- allow_all_flags: Whether all flags are allowed
|
227
231
|
|
228
232
|
Environment Variables:
|
229
|
-
ALLOWED_COMMANDS: Comma-separated list of allowed commands (default: "ls,cat,pwd")
|
230
|
-
ALLOWED_FLAGS: Comma-separated list of allowed flags (default: "-l,-a,--help")
|
231
|
-
ALLOWED_PATTERNS: Comma-separated list of patterns (default: "*.txt,*.log,*.md")
|
233
|
+
ALLOWED_COMMANDS: Comma-separated list of allowed commands or 'all' (default: "ls,cat,pwd")
|
234
|
+
ALLOWED_FLAGS: Comma-separated list of allowed flags or 'all' (default: "-l,-a,--help")
|
232
235
|
MAX_COMMAND_LENGTH: Maximum command string length (default: 1024)
|
233
236
|
COMMAND_TIMEOUT: Command timeout in seconds (default: 30)
|
234
237
|
"""
|
238
|
+
allowed_commands = os.getenv("ALLOWED_COMMANDS", "ls,cat,pwd")
|
239
|
+
allowed_flags = os.getenv("ALLOWED_FLAGS", "-l,-a,--help")
|
240
|
+
|
241
|
+
allow_all_commands = allowed_commands.lower() == 'all'
|
242
|
+
allow_all_flags = allowed_flags.lower() == 'all'
|
243
|
+
|
235
244
|
return SecurityConfig(
|
236
|
-
allowed_commands=set(
|
237
|
-
allowed_flags=set(
|
245
|
+
allowed_commands=set() if allow_all_commands else set(allowed_commands.split(",")),
|
246
|
+
allowed_flags=set() if allow_all_flags else set(allowed_flags.split(",")),
|
238
247
|
max_command_length=int(os.getenv("MAX_COMMAND_LENGTH", "1024")),
|
239
248
|
command_timeout=int(os.getenv("COMMAND_TIMEOUT", "30")),
|
249
|
+
allow_all_commands=allow_all_commands,
|
250
|
+
allow_all_flags=allow_all_flags,
|
240
251
|
)
|
241
252
|
|
242
253
|
|
@@ -245,13 +256,16 @@ executor = CommandExecutor(allowed_dir=os.getenv("ALLOWED_DIR", ""), security_co
|
|
245
256
|
|
246
257
|
@server.list_tools()
|
247
258
|
async def handle_list_tools() -> list[types.Tool]:
|
259
|
+
commands_desc = "all commands" if executor.security_config.allow_all_commands else ", ".join(executor.security_config.allowed_commands)
|
260
|
+
flags_desc = "all flags" if executor.security_config.allow_all_flags else ", ".join(executor.security_config.allowed_flags)
|
261
|
+
|
248
262
|
return [
|
249
263
|
types.Tool(
|
250
264
|
name="run_command",
|
251
265
|
description=(
|
252
266
|
f"Allows command (CLI) execution in the directory: {executor.allowed_dir}\n\n"
|
253
|
-
f"Available commands: {
|
254
|
-
f"Available flags: {
|
267
|
+
f"Available commands: {commands_desc}\n"
|
268
|
+
f"Available flags: {flags_desc}\n\n"
|
255
269
|
"Note: Shell operators (&&, |, >, >>) are not supported."
|
256
270
|
),
|
257
271
|
inputSchema={
|
@@ -314,16 +328,19 @@ async def handle_call_tool(name: str, arguments: Optional[Dict[str, Any]]) -> Li
|
|
314
328
|
return [types.TextContent(type="text", text=f"Error: {str(e)}", error=True)]
|
315
329
|
|
316
330
|
elif name == "show_security_rules":
|
331
|
+
commands_desc = "All commands allowed" if executor.security_config.allow_all_commands else ", ".join(sorted(executor.security_config.allowed_commands))
|
332
|
+
flags_desc = "All flags allowed" if executor.security_config.allow_all_flags else ", ".join(sorted(executor.security_config.allowed_flags))
|
333
|
+
|
317
334
|
security_info = (
|
318
335
|
"Security Configuration:\n"
|
319
336
|
f"==================\n"
|
320
337
|
f"Working Directory: {executor.allowed_dir}\n"
|
321
338
|
f"\nAllowed Commands:\n"
|
322
339
|
f"----------------\n"
|
323
|
-
f"{
|
340
|
+
f"{commands_desc}\n"
|
324
341
|
f"\nAllowed Flags:\n"
|
325
342
|
f"-------------\n"
|
326
|
-
f"{
|
343
|
+
f"{flags_desc}\n"
|
327
344
|
f"\nSecurity Limits:\n"
|
328
345
|
f"---------------\n"
|
329
346
|
f"Max Command Length: {executor.security_config.max_command_length} characters\n"
|
@@ -341,10 +358,10 @@ async def main():
|
|
341
358
|
write_stream,
|
342
359
|
InitializationOptions(
|
343
360
|
server_name="cli-mcp-server",
|
344
|
-
server_version="0.2.
|
361
|
+
server_version="0.2.1",
|
345
362
|
capabilities=server.get_capabilities(
|
346
363
|
notification_options=NotificationOptions(),
|
347
364
|
experimental_capabilities={},
|
348
365
|
),
|
349
366
|
),
|
350
|
-
)
|
367
|
+
)
|
@@ -1,14 +1,15 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.4
|
2
2
|
Name: cli-mcp-server
|
3
|
-
Version: 0.2.
|
3
|
+
Version: 0.2.1
|
4
4
|
Summary: Command line interface for MCP clients with secure execution and customizable security policies
|
5
5
|
Project-URL: Homepage, https://github.com/MladenSU/cli-mcp-server
|
6
6
|
Project-URL: Documentation, https://github.com/MladenSU/cli-mcp-server#readme
|
7
7
|
Project-URL: Repository, https://github.com/MladenSU/cli-mcp-server.git
|
8
8
|
Project-URL: Bug Tracker, https://github.com/MladenSU/cli-mcp-server/issues
|
9
9
|
Author-email: Mladen <fangs-lever6n@icloud.com>
|
10
|
+
License-File: LICENSE
|
10
11
|
Requires-Python: >=3.10
|
11
|
-
Requires-Dist: mcp>=1.
|
12
|
+
Requires-Dist: mcp>=1.1.0
|
12
13
|
Description-Content-Type: text/markdown
|
13
14
|
|
14
15
|
# CLI MCP Server
|
@@ -24,6 +25,8 @@ features.
|
|
24
25
|

|
25
26
|
[](https://smithery.ai/protocol/cli-mcp-server)
|
26
27
|
|
28
|
+
<a href="https://glama.ai/mcp/servers/q89277vzl1"><img width="380" height="200" src="https://glama.ai/mcp/servers/q89277vzl1/badge" /></a>
|
29
|
+
|
27
30
|
---
|
28
31
|
|
29
32
|
# Table of Contents
|
@@ -226,4 +229,4 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
|
|
226
229
|
|
227
230
|
---
|
228
231
|
|
229
|
-
For more information or support, please open an issue on the project repository.
|
232
|
+
For more information or support, please open an issue on the project repository.
|
@@ -0,0 +1,7 @@
|
|
1
|
+
cli_mcp_server/__init__.py,sha256=bGLiX7XuhVsS-PJdoRIWXiilZ3NTAQ7fb9_8kkNzLlM,216
|
2
|
+
cli_mcp_server/server.py,sha256=N2BtE8YLf8P643GPwawnnmf1kg7blY6Z0x2KP9zYhS8,13918
|
3
|
+
cli_mcp_server-0.2.1.dist-info/METADATA,sha256=rWoOhhU4jK0Yt8BAguG1_k9v3y5q9SiJbw6PWfKl75M,6566
|
4
|
+
cli_mcp_server-0.2.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
5
|
+
cli_mcp_server-0.2.1.dist-info/entry_points.txt,sha256=07bDmJJSXg-6VCFEFTOlsGoxI-0faJafT1yEEjUdN-U,55
|
6
|
+
cli_mcp_server-0.2.1.dist-info/licenses/LICENSE,sha256=85rOR_IMpb2VzXBA4VCRZh_KWlaO1Rly8HDYDwGgMWk,1062
|
7
|
+
cli_mcp_server-0.2.1.dist-info/RECORD,,
|
@@ -1,7 +0,0 @@
|
|
1
|
-
cli_mcp_server/__init__.py,sha256=bGLiX7XuhVsS-PJdoRIWXiilZ3NTAQ7fb9_8kkNzLlM,216
|
2
|
-
cli_mcp_server/server.py,sha256=zM-Q-5KtdjBY64RfkpJeUjOLd__4mW4JJMN0aQU9X5E,12908
|
3
|
-
cli_mcp_server-0.2.0.dist-info/METADATA,sha256=Fx8K92ryxA-Vj2eU1IfyZzD5VdcFzDQ_OaVqKQANZFQ,6403
|
4
|
-
cli_mcp_server-0.2.0.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
|
5
|
-
cli_mcp_server-0.2.0.dist-info/entry_points.txt,sha256=07bDmJJSXg-6VCFEFTOlsGoxI-0faJafT1yEEjUdN-U,55
|
6
|
-
cli_mcp_server-0.2.0.dist-info/licenses/LICENSE,sha256=85rOR_IMpb2VzXBA4VCRZh_KWlaO1Rly8HDYDwGgMWk,1062
|
7
|
-
cli_mcp_server-0.2.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|