code-executor-mcp 1.0.4__tar.gz → 1.0.7__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.
- code_executor_mcp-1.0.7/.cursorrules +9 -0
- code_executor_mcp-1.0.7/.well-known/mcp-server-card.json +6 -0
- code_executor_mcp-1.0.7/Dockerfile +23 -0
- code_executor_mcp-1.0.7/PKG-INFO +128 -0
- code_executor_mcp-1.0.7/README.md +90 -0
- code_executor_mcp-1.0.7/SKILL.md +45 -0
- code_executor_mcp-1.0.7/auth_middleware.py +223 -0
- code_executor_mcp-1.0.7/glama.json +6 -0
- code_executor_mcp-1.0.7/llms.txt +42 -0
- {code_executor_mcp-1.0.4 → code_executor_mcp-1.0.7}/package.json +1 -1
- {code_executor_mcp-1.0.4 → code_executor_mcp-1.0.7}/pyproject.toml +1 -1
- {code_executor_mcp-1.0.4 → code_executor_mcp-1.0.7}/server.py +21 -10
- code_executor_mcp-1.0.4/PKG-INFO +0 -83
- code_executor_mcp-1.0.4/README.md +0 -45
- code_executor_mcp-1.0.4/glama.json +0 -10
- {code_executor_mcp-1.0.4 → code_executor_mcp-1.0.7}/.github/FUNDING.yml +0 -0
- {code_executor_mcp-1.0.4 → code_executor_mcp-1.0.7}/.github/workflows/mcp-smithery-publish.yml +0 -0
- {code_executor_mcp-1.0.4 → code_executor_mcp-1.0.7}/.github/workflows/test.yml +0 -0
- {code_executor_mcp-1.0.4 → code_executor_mcp-1.0.7}/.gitignore +0 -0
- {code_executor_mcp-1.0.4 → code_executor_mcp-1.0.7}/.mcp.json +0 -0
- {code_executor_mcp-1.0.4 → code_executor_mcp-1.0.7}/.well-known/mcp/server-card.json +0 -0
- {code_executor_mcp-1.0.4 → code_executor_mcp-1.0.7}/CODE_OF_CONDUCT.md +0 -0
- {code_executor_mcp-1.0.4 → code_executor_mcp-1.0.7}/CONTRIBUTING.md +0 -0
- {code_executor_mcp-1.0.4 → code_executor_mcp-1.0.7}/Dockerfile.glama +0 -0
- {code_executor_mcp-1.0.4 → code_executor_mcp-1.0.7}/LICENSE +0 -0
- {code_executor_mcp-1.0.4 → code_executor_mcp-1.0.7}/SECURITY.md +0 -0
- {code_executor_mcp-1.0.4 → code_executor_mcp-1.0.7}/mcp-wrapper.py +0 -0
- {code_executor_mcp-1.0.4 → code_executor_mcp-1.0.7}/pytest.ini +0 -0
- {code_executor_mcp-1.0.4 → code_executor_mcp-1.0.7}/server.json +0 -0
- {code_executor_mcp-1.0.4 → code_executor_mcp-1.0.7}/smithery.yaml +0 -0
- {code_executor_mcp-1.0.4 → code_executor_mcp-1.0.7}/tests/test_server.py +0 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# code-executor-mcp - Auto-trigger Rules
|
|
2
|
+
|
|
3
|
+
When the user asks about code executor, use code-executor-mcp tools: execute_code, run_command, run_tests, read_file, list_sandbox_files
|
|
4
|
+
|
|
5
|
+
**MCP server for code executor mcp operations**
|
|
6
|
+
|
|
7
|
+
Install: `pip install code-executor-mcp`
|
|
8
|
+
|
|
9
|
+
By MEOK AI Labs — MIT licensed.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{
|
|
2
|
+
"serverInfo": { "name": "code-executor-mcp", "version": "1.0.0" },
|
|
3
|
+
"tools": [
|
|
4
|
+
{"name": "execute_code", "description": "MCP tool from MEOK AI Labs"}, {"name": "run_command", "description": "MCP tool from MEOK AI Labs"}, {"name": "run_tests", "description": "MCP tool from MEOK AI Labs"}, {"name": "read_file", "description": "MCP tool from MEOK AI Labs"}, {"name": "list_sandbox_files", "description": "MCP tool from MEOK AI Labs"}
|
|
5
|
+
]
|
|
6
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
FROM python:3.12-slim
|
|
2
|
+
|
|
3
|
+
LABEL org.opencontainers.image.source="https://github.com/CSOAI-ORG/code-executor-mcp"
|
|
4
|
+
LABEL org.opencontainers.image.vendor="MEOK AI Labs"
|
|
5
|
+
LABEL org.opencontainers.image.licenses="MIT"
|
|
6
|
+
|
|
7
|
+
WORKDIR /app
|
|
8
|
+
|
|
9
|
+
RUN pip install --no-cache-dir uv
|
|
10
|
+
|
|
11
|
+
COPY pyproject.toml .
|
|
12
|
+
COPY server.py .
|
|
13
|
+
|
|
14
|
+
RUN uv pip install --system --no-cache mcp>=1.0.0
|
|
15
|
+
|
|
16
|
+
EXPOSE 8000
|
|
17
|
+
|
|
18
|
+
ENV PYTHONUNBUFFERED=1
|
|
19
|
+
|
|
20
|
+
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
|
|
21
|
+
CMD python -c "import server; print('OK')" || exit 1
|
|
22
|
+
|
|
23
|
+
CMD ["python", "server.py"]
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: code-executor-mcp
|
|
3
|
+
Version: 1.0.7
|
|
4
|
+
Summary: MCP server for code executor. Features execute code, run command, run tests. From MEOK AI Labs.
|
|
5
|
+
Project-URL: Homepage, https://meok.ai
|
|
6
|
+
Project-URL: Repository, https://github.com/CSOAI-ORG/code-executor-mcp
|
|
7
|
+
Author-email: MEOK AI Labs <nicholas@meok.ai>
|
|
8
|
+
License: MIT License
|
|
9
|
+
|
|
10
|
+
Copyright (c) 2026 MEOK AI Labs (meok.ai)
|
|
11
|
+
|
|
12
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
13
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
14
|
+
in the Software without restriction, including without limitation the rights
|
|
15
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
16
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
17
|
+
furnished to do so, subject to the following conditions:
|
|
18
|
+
|
|
19
|
+
The above copyright notice and this permission notice shall be included in all
|
|
20
|
+
copies or substantial portions of the Software.
|
|
21
|
+
|
|
22
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
23
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
24
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
25
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
26
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
27
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
28
|
+
SOFTWARE.
|
|
29
|
+
License-File: LICENSE
|
|
30
|
+
Keywords: ai,mcp,meok
|
|
31
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
32
|
+
Classifier: Operating System :: OS Independent
|
|
33
|
+
Classifier: Programming Language :: Python :: 3
|
|
34
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
35
|
+
Requires-Python: >=3.10
|
|
36
|
+
Requires-Dist: mcp>=1.0.0
|
|
37
|
+
Description-Content-Type: text/markdown
|
|
38
|
+
|
|
39
|
+
<div align="center">
|
|
40
|
+
|
|
41
|
+
# Code Executor MCP
|
|
42
|
+
|
|
43
|
+
**MCP server for code executor mcp operations**
|
|
44
|
+
|
|
45
|
+
[](https://pypi.org/project/meok-code-executor-mcp/)
|
|
46
|
+
[](LICENSE)
|
|
47
|
+
[](https://meok.ai)
|
|
48
|
+
|
|
49
|
+
</div>
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
## Quick Install
|
|
53
|
+
|
|
54
|
+
| Client | Install |
|
|
55
|
+
|--------|---------|
|
|
56
|
+
| **Claude Desktop** | [](https://claude.ai) |
|
|
57
|
+
| **Cursor** | [](https://cursor.com) |
|
|
58
|
+
| **VS Code** | [](https://code.visualstudio.com) |
|
|
59
|
+
| **Windsurf** | [](https://codeium.com/windsurf) |
|
|
60
|
+
| **Docker** | `docker run -p 8000:8000 code-executor-mcp` |
|
|
61
|
+
| **pip** | `pip install code-executor-mcp` |
|
|
62
|
+
|
|
63
|
+
## Overview
|
|
64
|
+
|
|
65
|
+
Code Executor MCP provides AI-powered tools via the Model Context Protocol (MCP).
|
|
66
|
+
|
|
67
|
+
## Tools
|
|
68
|
+
|
|
69
|
+
| Tool | Description |
|
|
70
|
+
|------|-------------|
|
|
71
|
+
| `execute_code` | Execute code in a sandboxed environment with safety checks. |
|
|
72
|
+
| `run_command` | Execute a shell command and return stdout/stderr/exit_code. |
|
|
73
|
+
| `run_tests` | Run a test suite and return results. Default: pytest. |
|
|
74
|
+
| `read_file` | Read contents of a file (restricted to allowed directories: Desktop, |
|
|
75
|
+
| `list_sandbox_files` | List files in the sandbox working directory. All code execution |
|
|
76
|
+
| `get_safety_rules` | Get the current safety rules and blocked patterns for code execution. |
|
|
77
|
+
|
|
78
|
+
## Installation
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
pip install meok-code-executor-mcp
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Usage with Claude Desktop
|
|
85
|
+
|
|
86
|
+
Add to your Claude Desktop MCP config (`claude_desktop_config.json`):
|
|
87
|
+
|
|
88
|
+
```json
|
|
89
|
+
{
|
|
90
|
+
"mcpServers": {
|
|
91
|
+
"code-executor-mcp": {
|
|
92
|
+
"command": "python",
|
|
93
|
+
"args": ["-m", "meok_code_executor_mcp.server"]
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Usage with FastMCP
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
from mcp.server.fastmcp import FastMCP
|
|
103
|
+
|
|
104
|
+
# This server exposes 6 tool(s) via MCP
|
|
105
|
+
# See server.py for full implementation
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## License
|
|
109
|
+
|
|
110
|
+
MIT © [MEOK AI Labs](https://meok.ai)
|
|
111
|
+
|
|
112
|
+
<!-- meok-moat-footer-v1 -->
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## Pairs with MEOK Governance Suite
|
|
116
|
+
|
|
117
|
+
Build something that touches users? You need compliance. MEOK ships 38 governance MCPs that drop in alongside this tool — EU AI Act, DORA, NIS2, CRA, GDPR, ISO 42001, FDA SaMD, MDR, Basel, MiFID II, MiCA, COPPA, and more.
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
# One-shot install of the governance pack
|
|
121
|
+
npx meok-setup --pack governance
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Free tier: 10 calls/day per MCP. Pro tier (£79/mo): unlimited + cryptographically signed compliance attestations your auditor verifies independently.
|
|
125
|
+
|
|
126
|
+
→ Full catalogue: [councilof.ai/catalogue](https://councilof.ai/catalogue)
|
|
127
|
+
→ MEOK AI Labs: [meok.ai](https://meok.ai)
|
|
128
|
+
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# Code Executor MCP
|
|
4
|
+
|
|
5
|
+
**MCP server for code executor mcp operations**
|
|
6
|
+
|
|
7
|
+
[](https://pypi.org/project/meok-code-executor-mcp/)
|
|
8
|
+
[](LICENSE)
|
|
9
|
+
[](https://meok.ai)
|
|
10
|
+
|
|
11
|
+
</div>
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
## Quick Install
|
|
15
|
+
|
|
16
|
+
| Client | Install |
|
|
17
|
+
|--------|---------|
|
|
18
|
+
| **Claude Desktop** | [](https://claude.ai) |
|
|
19
|
+
| **Cursor** | [](https://cursor.com) |
|
|
20
|
+
| **VS Code** | [](https://code.visualstudio.com) |
|
|
21
|
+
| **Windsurf** | [](https://codeium.com/windsurf) |
|
|
22
|
+
| **Docker** | `docker run -p 8000:8000 code-executor-mcp` |
|
|
23
|
+
| **pip** | `pip install code-executor-mcp` |
|
|
24
|
+
|
|
25
|
+
## Overview
|
|
26
|
+
|
|
27
|
+
Code Executor MCP provides AI-powered tools via the Model Context Protocol (MCP).
|
|
28
|
+
|
|
29
|
+
## Tools
|
|
30
|
+
|
|
31
|
+
| Tool | Description |
|
|
32
|
+
|------|-------------|
|
|
33
|
+
| `execute_code` | Execute code in a sandboxed environment with safety checks. |
|
|
34
|
+
| `run_command` | Execute a shell command and return stdout/stderr/exit_code. |
|
|
35
|
+
| `run_tests` | Run a test suite and return results. Default: pytest. |
|
|
36
|
+
| `read_file` | Read contents of a file (restricted to allowed directories: Desktop, |
|
|
37
|
+
| `list_sandbox_files` | List files in the sandbox working directory. All code execution |
|
|
38
|
+
| `get_safety_rules` | Get the current safety rules and blocked patterns for code execution. |
|
|
39
|
+
|
|
40
|
+
## Installation
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pip install meok-code-executor-mcp
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Usage with Claude Desktop
|
|
47
|
+
|
|
48
|
+
Add to your Claude Desktop MCP config (`claude_desktop_config.json`):
|
|
49
|
+
|
|
50
|
+
```json
|
|
51
|
+
{
|
|
52
|
+
"mcpServers": {
|
|
53
|
+
"code-executor-mcp": {
|
|
54
|
+
"command": "python",
|
|
55
|
+
"args": ["-m", "meok_code_executor_mcp.server"]
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Usage with FastMCP
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
from mcp.server.fastmcp import FastMCP
|
|
65
|
+
|
|
66
|
+
# This server exposes 6 tool(s) via MCP
|
|
67
|
+
# See server.py for full implementation
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## License
|
|
71
|
+
|
|
72
|
+
MIT © [MEOK AI Labs](https://meok.ai)
|
|
73
|
+
|
|
74
|
+
<!-- meok-moat-footer-v1 -->
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Pairs with MEOK Governance Suite
|
|
78
|
+
|
|
79
|
+
Build something that touches users? You need compliance. MEOK ships 38 governance MCPs that drop in alongside this tool — EU AI Act, DORA, NIS2, CRA, GDPR, ISO 42001, FDA SaMD, MDR, Basel, MiFID II, MiCA, COPPA, and more.
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
# One-shot install of the governance pack
|
|
83
|
+
npx meok-setup --pack governance
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Free tier: 10 calls/day per MCP. Pro tier (£79/mo): unlimited + cryptographically signed compliance attestations your auditor verifies independently.
|
|
87
|
+
|
|
88
|
+
→ Full catalogue: [councilof.ai/catalogue](https://councilof.ai/catalogue)
|
|
89
|
+
→ MEOK AI Labs: [meok.ai](https://meok.ai)
|
|
90
|
+
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# meok-code-executor
|
|
2
|
+
|
|
3
|
+
## Description
|
|
4
|
+
Secure code execution in sandboxed environments. Run Python, JavaScript, and shell commands safely with tier-based permissions.
|
|
5
|
+
|
|
6
|
+
## Category
|
|
7
|
+
development
|
|
8
|
+
|
|
9
|
+
## Use Cases
|
|
10
|
+
- Secure code execution
|
|
11
|
+
- Sandboxed testing
|
|
12
|
+
- Automated code validation
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
```bash
|
|
16
|
+
pip install code-executor-mcp
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
```python
|
|
21
|
+
from mcp import Client
|
|
22
|
+
|
|
23
|
+
client = Client("code-executor-mcp")
|
|
24
|
+
result = client.call_tool("tool_name", {"param": "value"})
|
|
25
|
+
print(result)
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Tools
|
|
29
|
+
See the MCP server for available tools.
|
|
30
|
+
|
|
31
|
+
## Pricing
|
|
32
|
+
- Free tier: Basic compliance checks
|
|
33
|
+
- Pro £199/mo: Full automation + signed attestations
|
|
34
|
+
- Enterprise: Contact for custom pricing
|
|
35
|
+
|
|
36
|
+
## Links
|
|
37
|
+
- MCP Server: https://github.com/CSOAI-ORG/code-executor-mcp
|
|
38
|
+
- Documentation: https://meok.ai/docs/meok-code-executor
|
|
39
|
+
- Compliance Portal: https://compliance.meok.ai
|
|
40
|
+
|
|
41
|
+
## Compliance Standards
|
|
42
|
+
- EU AI Act (2024/1689)
|
|
43
|
+
- NIS2 Directive (2022/2555)
|
|
44
|
+
- ISO 42001:2023
|
|
45
|
+
- NIST AI RMF 1.0
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
"""
|
|
2
|
+
MEOK Labs — Shared Authentication Middleware for MCP Servers
|
|
3
|
+
Deploy to: ~/clawd/meok-labs-engine/shared/auth_middleware.py
|
|
4
|
+
Every compliance MCP server imports this.
|
|
5
|
+
|
|
6
|
+
Usage in any server.py:
|
|
7
|
+
import sys, os
|
|
8
|
+
sys.path.insert(0, os.path.expanduser("~/clawd/meok-labs-engine/shared"))
|
|
9
|
+
from auth_middleware import check_access, require_tier, audit_log, Tier
|
|
10
|
+
|
|
11
|
+
@mcp.tool(name="my_tool")
|
|
12
|
+
async def my_tool(query: str, api_key: str = "") -> str:
|
|
13
|
+
allowed, msg, tier = check_access(api_key)
|
|
14
|
+
if not allowed:
|
|
15
|
+
return json.dumps({"error": msg, "upgrade_url": "https://meok.ai/pricing"})
|
|
16
|
+
# ... tool logic ...
|
|
17
|
+
audit_log(api_key, "my_tool", "eu_ai_act", "result_summary", tier)
|
|
18
|
+
return json.dumps(result)
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
import os
|
|
22
|
+
import hashlib
|
|
23
|
+
import time
|
|
24
|
+
import json
|
|
25
|
+
from typing import Optional, Tuple
|
|
26
|
+
from enum import Enum
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class Tier(str, Enum):
|
|
30
|
+
FREE = "free"
|
|
31
|
+
STARTER = "starter"
|
|
32
|
+
PROFESSIONAL = "professional"
|
|
33
|
+
ENTERPRISE = "enterprise"
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
TIER_LIMITS = {
|
|
37
|
+
Tier.FREE: {"calls_per_day": 10, "frameworks": 1, "audit_trail": False},
|
|
38
|
+
Tier.STARTER: {"calls_per_day": 100, "frameworks": 1, "audit_trail": False},
|
|
39
|
+
Tier.PROFESSIONAL: {"calls_per_day": 1000, "frameworks": 5, "audit_trail": True},
|
|
40
|
+
Tier.ENTERPRISE: {"calls_per_day": -1, "frameworks": -1, "audit_trail": True},
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
TIER_ORDER = [Tier.FREE, Tier.STARTER, Tier.PROFESSIONAL, Tier.ENTERPRISE]
|
|
44
|
+
|
|
45
|
+
MEOK_DIR = os.path.expanduser("~/.meok")
|
|
46
|
+
USAGE_FILE = os.path.join(MEOK_DIR, "usage.json")
|
|
47
|
+
KEYS_FILE = os.path.join(MEOK_DIR, "api_keys.json")
|
|
48
|
+
AUDIT_FILE = os.path.join(MEOK_DIR, "audit_trail.jsonl")
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _ensure_dir():
|
|
52
|
+
os.makedirs(MEOK_DIR, exist_ok=True)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _load_json(path: str) -> dict:
|
|
56
|
+
_ensure_dir()
|
|
57
|
+
if os.path.exists(path):
|
|
58
|
+
try:
|
|
59
|
+
with open(path) as f:
|
|
60
|
+
return json.load(f)
|
|
61
|
+
except (json.JSONDecodeError, IOError):
|
|
62
|
+
return {}
|
|
63
|
+
return {}
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _save_json(path: str, data: dict):
|
|
67
|
+
_ensure_dir()
|
|
68
|
+
with open(path, "w") as f:
|
|
69
|
+
json.dump(data, f, indent=2)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def generate_api_key(tier: Tier, customer_name: str) -> str:
|
|
73
|
+
"""Generate a new API key for a customer. Run manually to onboard customers."""
|
|
74
|
+
raw = f"meok_{tier.value}_{customer_name}_{time.time()}"
|
|
75
|
+
key = f"meok_{hashlib.sha256(raw.encode()).hexdigest()[:32]}"
|
|
76
|
+
|
|
77
|
+
keys = _load_json(KEYS_FILE)
|
|
78
|
+
keys[key] = {
|
|
79
|
+
"tier": tier.value,
|
|
80
|
+
"customer": customer_name,
|
|
81
|
+
"created": time.strftime("%Y-%m-%dT%H:%M:%SZ"),
|
|
82
|
+
"active": True,
|
|
83
|
+
}
|
|
84
|
+
_save_json(KEYS_FILE, keys)
|
|
85
|
+
return key
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def get_tier_from_api_key(api_key: str) -> Tier:
|
|
89
|
+
"""Look up tier for an API key."""
|
|
90
|
+
if not api_key:
|
|
91
|
+
return Tier.FREE
|
|
92
|
+
|
|
93
|
+
keys = _load_json(KEYS_FILE)
|
|
94
|
+
if api_key in keys and keys[api_key].get("active", True):
|
|
95
|
+
try:
|
|
96
|
+
return Tier(keys[api_key]["tier"])
|
|
97
|
+
except ValueError:
|
|
98
|
+
return Tier.FREE
|
|
99
|
+
|
|
100
|
+
return Tier.FREE
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def check_access(api_key: str = "", framework: str = None) -> Tuple[bool, str, Tier]:
|
|
104
|
+
"""
|
|
105
|
+
Main access control function. Returns (allowed, message, tier).
|
|
106
|
+
Call at the start of every tool.
|
|
107
|
+
"""
|
|
108
|
+
tier = get_tier_from_api_key(api_key)
|
|
109
|
+
limits = TIER_LIMITS[tier]
|
|
110
|
+
|
|
111
|
+
# Rate limit check
|
|
112
|
+
usage = _load_json(USAGE_FILE)
|
|
113
|
+
today = time.strftime("%Y-%m-%d")
|
|
114
|
+
key_hash = hashlib.sha256((api_key or "anon").encode()).hexdigest()[:12]
|
|
115
|
+
day_key = f"{key_hash}:{today}"
|
|
116
|
+
|
|
117
|
+
current = usage.get(day_key, 0)
|
|
118
|
+
max_calls = limits["calls_per_day"]
|
|
119
|
+
|
|
120
|
+
if max_calls != -1 and current >= max_calls:
|
|
121
|
+
return (
|
|
122
|
+
False,
|
|
123
|
+
f"Rate limit reached ({max_calls}/day on {tier.value} tier). "
|
|
124
|
+
f"Upgrade at https://meok.ai/pricing",
|
|
125
|
+
tier,
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
# Record usage
|
|
129
|
+
usage[day_key] = current + 1
|
|
130
|
+
# Clean old entries (keep last 7 days)
|
|
131
|
+
cutoff = time.strftime("%Y-%m-%d", time.localtime(time.time() - 7 * 86400))
|
|
132
|
+
usage = {k: v for k, v in usage.items() if k.split(":")[1] >= cutoff}
|
|
133
|
+
_save_json(USAGE_FILE, usage)
|
|
134
|
+
|
|
135
|
+
return True, "OK", tier
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def require_tier(minimum: Tier, current: Tier) -> Tuple[bool, str]:
|
|
139
|
+
"""Check if current tier meets the minimum requirement for a tool."""
|
|
140
|
+
if TIER_ORDER.index(current) < TIER_ORDER.index(minimum):
|
|
141
|
+
return (
|
|
142
|
+
False,
|
|
143
|
+
f"Requires {minimum.value} tier. Current: {current.value}. "
|
|
144
|
+
f"Upgrade at https://meok.ai/pricing",
|
|
145
|
+
)
|
|
146
|
+
return True, "OK"
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def audit_log(
|
|
150
|
+
api_key: str,
|
|
151
|
+
tool_name: str,
|
|
152
|
+
framework: str,
|
|
153
|
+
result_summary: str,
|
|
154
|
+
tier: Tier,
|
|
155
|
+
):
|
|
156
|
+
"""Append to audit trail. Only Professional and Enterprise tiers generate audit logs."""
|
|
157
|
+
if not TIER_LIMITS[tier]["audit_trail"]:
|
|
158
|
+
return
|
|
159
|
+
|
|
160
|
+
_ensure_dir()
|
|
161
|
+
entry = {
|
|
162
|
+
"ts": time.strftime("%Y-%m-%dT%H:%M:%SZ"),
|
|
163
|
+
"tool": tool_name,
|
|
164
|
+
"framework": framework,
|
|
165
|
+
"result": result_summary[:200],
|
|
166
|
+
"tier": tier.value,
|
|
167
|
+
"key_prefix": (api_key or "")[:8] + "...",
|
|
168
|
+
}
|
|
169
|
+
with open(AUDIT_FILE, "a") as f:
|
|
170
|
+
f.write(json.dumps(entry) + "\n")
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def get_usage_stats(api_key: str = "") -> dict:
|
|
174
|
+
"""Get usage statistics for an API key."""
|
|
175
|
+
usage = _load_json(USAGE_FILE)
|
|
176
|
+
tier = get_tier_from_api_key(api_key)
|
|
177
|
+
limits = TIER_LIMITS[tier]
|
|
178
|
+
|
|
179
|
+
key_hash = hashlib.sha256((api_key or "anon").encode()).hexdigest()[:12]
|
|
180
|
+
today = time.strftime("%Y-%m-%d")
|
|
181
|
+
day_key = f"{key_hash}:{today}"
|
|
182
|
+
|
|
183
|
+
return {
|
|
184
|
+
"tier": tier.value,
|
|
185
|
+
"calls_today": usage.get(day_key, 0),
|
|
186
|
+
"limit": limits["calls_per_day"],
|
|
187
|
+
"remaining": max(0, limits["calls_per_day"] - usage.get(day_key, 0))
|
|
188
|
+
if limits["calls_per_day"] != -1 else "unlimited",
|
|
189
|
+
"audit_trail": limits["audit_trail"],
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
# CLI for key management
|
|
194
|
+
if __name__ == "__main__":
|
|
195
|
+
import sys
|
|
196
|
+
if len(sys.argv) < 2:
|
|
197
|
+
print("Usage:")
|
|
198
|
+
print(" python auth_middleware.py generate <tier> <customer_name>")
|
|
199
|
+
print(" python auth_middleware.py list")
|
|
200
|
+
print(" python auth_middleware.py stats <api_key>")
|
|
201
|
+
print(f"\nTiers: {', '.join(t.value for t in Tier)}")
|
|
202
|
+
sys.exit(0)
|
|
203
|
+
|
|
204
|
+
cmd = sys.argv[1]
|
|
205
|
+
|
|
206
|
+
if cmd == "generate":
|
|
207
|
+
tier = Tier(sys.argv[2])
|
|
208
|
+
name = sys.argv[3]
|
|
209
|
+
key = generate_api_key(tier, name)
|
|
210
|
+
print(f"Generated key: {key}")
|
|
211
|
+
print(f"Tier: {tier.value}")
|
|
212
|
+
print(f"Customer: {name}")
|
|
213
|
+
|
|
214
|
+
elif cmd == "list":
|
|
215
|
+
keys = _load_json(KEYS_FILE)
|
|
216
|
+
for k, v in keys.items():
|
|
217
|
+
status = "active" if v.get("active", True) else "disabled"
|
|
218
|
+
print(f" {k[:20]}... | {v['tier']:15} | {v['customer']:20} | {status}")
|
|
219
|
+
|
|
220
|
+
elif cmd == "stats":
|
|
221
|
+
key = sys.argv[2]
|
|
222
|
+
stats = get_usage_stats(key)
|
|
223
|
+
print(json.dumps(stats, indent=2))
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# code-executor-mcp
|
|
2
|
+
# **MCP server for code executor mcp operations**
|
|
3
|
+
|
|
4
|
+
## Install
|
|
5
|
+
```bash
|
|
6
|
+
pip install code-executor-mcp
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Auth & Rate Limits
|
|
10
|
+
- Free tier: 10 calls/day. No API key required.
|
|
11
|
+
- Pro tier (£79/mo): unlimited + signed attestations.
|
|
12
|
+
- Enterprise (£1,499/mo): white-label.
|
|
13
|
+
|
|
14
|
+
## Tools
|
|
15
|
+
|
|
16
|
+
### `execute_code`
|
|
17
|
+
Execute code in a sandboxed environment with safety checks.
|
|
18
|
+
|
|
19
|
+
### `run_command`
|
|
20
|
+
Execute a shell command and return stdout/stderr/exit_code.
|
|
21
|
+
|
|
22
|
+
### `run_tests`
|
|
23
|
+
Run a test suite and return results. Default: pytest.
|
|
24
|
+
|
|
25
|
+
### `read_file`
|
|
26
|
+
Read contents of a file (restricted to allowed directories: Desktop,
|
|
27
|
+
|
|
28
|
+
### `list_sandbox_files`
|
|
29
|
+
List files in the sandbox working directory. All code execution
|
|
30
|
+
|
|
31
|
+
### `get_safety_rules`
|
|
32
|
+
Get the current safety rules and blocked patterns for code execution.
|
|
33
|
+
|
|
34
|
+
### `execute_code_docker`
|
|
35
|
+
Execute code inside a temporary Docker container for isolation.
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
## Maintainer
|
|
39
|
+
MEOK AI Labs · hello@meok.ai · https://meok.ai · MIT licensed
|
|
40
|
+
|
|
41
|
+
## Pairs with
|
|
42
|
+
Governance moat: pair this tool with any of MEOK's 38 governance MCPs (EU AI Act, DORA, NIS2, CRA, GDPR, ISO 42001, etc.) for full compliance coverage.
|
|
@@ -3,7 +3,7 @@ requires = ["hatchling"]
|
|
|
3
3
|
build-backend = "hatchling.build"
|
|
4
4
|
[project]
|
|
5
5
|
name = "code-executor-mcp"
|
|
6
|
-
version = "1.0.
|
|
6
|
+
version = "1.0.7"
|
|
7
7
|
readme = "README.md"
|
|
8
8
|
description = "MCP server for code executor. Features execute code, run command, run tests. From MEOK AI Labs."
|
|
9
9
|
license = {file = "LICENSE"}
|
|
@@ -23,7 +23,6 @@ from typing import Optional
|
|
|
23
23
|
from collections import defaultdict
|
|
24
24
|
from mcp.server.fastmcp import FastMCP
|
|
25
25
|
import sys, os
|
|
26
|
-
sys.path.insert(0, os.path.expanduser('~/clawd/meok-labs-engine/shared'))
|
|
27
26
|
from auth_middleware import check_access
|
|
28
27
|
|
|
29
28
|
# ---------------------------------------------------------------------------
|
|
@@ -309,7 +308,7 @@ def execute_code(code: str, language: str = "python", timeout: int = 30, api_key
|
|
|
309
308
|
"""
|
|
310
309
|
allowed, msg, tier = check_access(api_key)
|
|
311
310
|
if not allowed:
|
|
312
|
-
return {"error": msg, "upgrade_url":
|
|
311
|
+
return {"error": msg, "upgrade_url": STRIPE_199}
|
|
313
312
|
|
|
314
313
|
err = _check_rate_limit()
|
|
315
314
|
if err:
|
|
@@ -369,7 +368,7 @@ def run_command(command: str, timeout: int = 30, api_key: str = "") -> dict:
|
|
|
369
368
|
"""
|
|
370
369
|
allowed, msg, tier = check_access(api_key)
|
|
371
370
|
if not allowed:
|
|
372
|
-
return {"error": msg, "upgrade_url":
|
|
371
|
+
return {"error": msg, "upgrade_url": STRIPE_199}
|
|
373
372
|
|
|
374
373
|
err = _check_rate_limit()
|
|
375
374
|
if err:
|
|
@@ -426,7 +425,7 @@ def run_tests(test_command: str = "python -m pytest", working_dir: str = "",
|
|
|
426
425
|
"""
|
|
427
426
|
allowed, msg, tier = check_access(api_key)
|
|
428
427
|
if not allowed:
|
|
429
|
-
return {"error": msg, "upgrade_url":
|
|
428
|
+
return {"error": msg, "upgrade_url": STRIPE_199}
|
|
430
429
|
|
|
431
430
|
err = _check_rate_limit()
|
|
432
431
|
if err:
|
|
@@ -519,7 +518,7 @@ def read_file(path: str, limit: int = 200, api_key: str = "") -> dict:
|
|
|
519
518
|
"""
|
|
520
519
|
allowed, msg, tier = check_access(api_key)
|
|
521
520
|
if not allowed:
|
|
522
|
-
return {"error": msg, "upgrade_url":
|
|
521
|
+
return {"error": msg, "upgrade_url": STRIPE_199}
|
|
523
522
|
|
|
524
523
|
err = _check_rate_limit()
|
|
525
524
|
if err:
|
|
@@ -589,7 +588,7 @@ def list_sandbox_files(api_key: str = "") -> dict:
|
|
|
589
588
|
"""
|
|
590
589
|
allowed, msg, tier = check_access(api_key)
|
|
591
590
|
if not allowed:
|
|
592
|
-
return {"error": msg, "upgrade_url":
|
|
591
|
+
return {"error": msg, "upgrade_url": STRIPE_199}
|
|
593
592
|
|
|
594
593
|
files = []
|
|
595
594
|
for f in SANDBOX_DIR.iterdir():
|
|
@@ -647,7 +646,7 @@ def get_safety_rules(api_key: str = "") -> dict:
|
|
|
647
646
|
"""
|
|
648
647
|
allowed, msg, tier = check_access(api_key)
|
|
649
648
|
if not allowed:
|
|
650
|
-
return {"error": msg, "upgrade_url":
|
|
649
|
+
return {"error": msg, "upgrade_url": STRIPE_199}
|
|
651
650
|
|
|
652
651
|
return {
|
|
653
652
|
"blocked_shell_patterns": BLOCKED_COMMANDS,
|
|
@@ -666,9 +665,18 @@ def get_safety_rules(api_key: str = "") -> dict:
|
|
|
666
665
|
async def execute_code_docker(code: str, language: str = "python", timeout_sec: int = 30, api_key: str = "") -> str:
|
|
667
666
|
"""Execute code inside a temporary Docker container for isolation."""
|
|
668
667
|
import subprocess, tempfile, os
|
|
668
|
+
|
|
669
|
+
STRIPE_199 = "https://buy.stripe.com/14A4gB3K4eUWgYR56o8k836"
|
|
670
|
+
|
|
671
|
+
def _add_upgrade_tail(response, tier="free"):
|
|
672
|
+
"""Append upgrade nudge to free-tier success responses."""
|
|
673
|
+
if isinstance(response, dict) and tier == "free":
|
|
674
|
+
response["_upgrade_note"] = "Pro tier: unlimited calls + priority support. Upgrade: " + STRIPE_199
|
|
675
|
+
return response
|
|
676
|
+
|
|
669
677
|
allowed, msg, tier = check_access(api_key)
|
|
670
678
|
if not allowed:
|
|
671
|
-
return {"error": msg, "upgrade_url":
|
|
679
|
+
return {"error": msg, "upgrade_url": STRIPE_199}
|
|
672
680
|
|
|
673
681
|
image_map = {"python": "python:3.11-alpine", "node": "node:20-alpine", "bash": "alpine:latest"}
|
|
674
682
|
image = image_map.get(language.lower(), "alpine:latest")
|
|
@@ -705,5 +713,8 @@ async def execute_code_docker(code: str, language: str = "python", timeout_sec:
|
|
|
705
713
|
finally:
|
|
706
714
|
os.unlink(tmp_path)
|
|
707
715
|
|
|
708
|
-
|
|
709
|
-
mcp.run()
|
|
716
|
+
def main():
|
|
717
|
+
mcp.run()
|
|
718
|
+
|
|
719
|
+
if __name__ == '__main__':
|
|
720
|
+
main()
|
code_executor_mcp-1.0.4/PKG-INFO
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: code-executor-mcp
|
|
3
|
-
Version: 1.0.4
|
|
4
|
-
Summary: MCP server for code executor. Features execute code, run command, run tests. From MEOK AI Labs.
|
|
5
|
-
Project-URL: Homepage, https://meok.ai
|
|
6
|
-
Project-URL: Repository, https://github.com/CSOAI-ORG/code-executor-mcp
|
|
7
|
-
Author-email: MEOK AI Labs <nicholas@meok.ai>
|
|
8
|
-
License: MIT License
|
|
9
|
-
|
|
10
|
-
Copyright (c) 2026 MEOK AI Labs (meok.ai)
|
|
11
|
-
|
|
12
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
13
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
14
|
-
in the Software without restriction, including without limitation the rights
|
|
15
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
16
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
17
|
-
furnished to do so, subject to the following conditions:
|
|
18
|
-
|
|
19
|
-
The above copyright notice and this permission notice shall be included in all
|
|
20
|
-
copies or substantial portions of the Software.
|
|
21
|
-
|
|
22
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
23
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
24
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
25
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
26
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
27
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
28
|
-
SOFTWARE.
|
|
29
|
-
License-File: LICENSE
|
|
30
|
-
Keywords: ai,mcp,meok
|
|
31
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
32
|
-
Classifier: Operating System :: OS Independent
|
|
33
|
-
Classifier: Programming Language :: Python :: 3
|
|
34
|
-
Classifier: Topic :: Software Development :: Libraries
|
|
35
|
-
Requires-Python: >=3.10
|
|
36
|
-
Requires-Dist: mcp>=1.0.0
|
|
37
|
-
Description-Content-Type: text/markdown
|
|
38
|
-
|
|
39
|
-
[](https://glama.ai/mcp/servers/CSOAI-ORG/code-executor-mcp)
|
|
40
|
-
[](https://registry.modelcontextprotocol.io)
|
|
41
|
-
[](https://pypi.org/project/code-executor-mcp/)
|
|
42
|
-
|
|
43
|
-
[](https://glama.ai/mcp/servers/CSOAI-ORG/code-executor-mcp)
|
|
44
|
-
|
|
45
|
-
<div align="center">
|
|
46
|
-
|
|
47
|
-
[](https://github.com/CSOAI-ORG/code-executor-mcp/stargazers)
|
|
48
|
-
|
|
49
|
-
# ucodeU executorU mcp
|
|
50
|
-
|
|
51
|
-
****
|
|
52
|
-
|
|
53
|
-
[](https://www.npmjs.com/package/@meok-ai/code-executor-mcp)
|
|
54
|
-
[](LICENSE)
|
|
55
|
-
[](https://meok.ai)
|
|
56
|
-
|
|
57
|
-
[Installation](#installation) · [Docs](https://csoai.org) · [Report Bug](https://github.com/CSOAI-ORG/code-executor-mcp/issues)
|
|
58
|
-
|
|
59
|
-
</div>
|
|
60
|
-
|
|
61
|
-
---
|
|
62
|
-
|
|
63
|
-
## Installation
|
|
64
|
-
|
|
65
|
-
```bash
|
|
66
|
-
pip install code-executor-mcp
|
|
67
|
-
# or
|
|
68
|
-
npm install -g @meok-ai/code-executor-mcp
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
## Quick Start
|
|
72
|
-
|
|
73
|
-
See the project repository for full documentation and examples.
|
|
74
|
-
|
|
75
|
-
## Enterprise Support
|
|
76
|
-
|
|
77
|
-
- 📧 nicholas@csoai.org
|
|
78
|
-
- 🌐 [CSOAI.org](https://csoai.org)
|
|
79
|
-
|
|
80
|
-
## License
|
|
81
|
-
|
|
82
|
-
MIT © [CSOAI](https://csoai.org)
|
|
83
|
-
<!-- mcp-name: io.github.CSOAI-ORG/code-executor-mcp -->
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
[](https://glama.ai/mcp/servers/CSOAI-ORG/code-executor-mcp)
|
|
2
|
-
[](https://registry.modelcontextprotocol.io)
|
|
3
|
-
[](https://pypi.org/project/code-executor-mcp/)
|
|
4
|
-
|
|
5
|
-
[](https://glama.ai/mcp/servers/CSOAI-ORG/code-executor-mcp)
|
|
6
|
-
|
|
7
|
-
<div align="center">
|
|
8
|
-
|
|
9
|
-
[](https://github.com/CSOAI-ORG/code-executor-mcp/stargazers)
|
|
10
|
-
|
|
11
|
-
# ucodeU executorU mcp
|
|
12
|
-
|
|
13
|
-
****
|
|
14
|
-
|
|
15
|
-
[](https://www.npmjs.com/package/@meok-ai/code-executor-mcp)
|
|
16
|
-
[](LICENSE)
|
|
17
|
-
[](https://meok.ai)
|
|
18
|
-
|
|
19
|
-
[Installation](#installation) · [Docs](https://csoai.org) · [Report Bug](https://github.com/CSOAI-ORG/code-executor-mcp/issues)
|
|
20
|
-
|
|
21
|
-
</div>
|
|
22
|
-
|
|
23
|
-
---
|
|
24
|
-
|
|
25
|
-
## Installation
|
|
26
|
-
|
|
27
|
-
```bash
|
|
28
|
-
pip install code-executor-mcp
|
|
29
|
-
# or
|
|
30
|
-
npm install -g @meok-ai/code-executor-mcp
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
## Quick Start
|
|
34
|
-
|
|
35
|
-
See the project repository for full documentation and examples.
|
|
36
|
-
|
|
37
|
-
## Enterprise Support
|
|
38
|
-
|
|
39
|
-
- 📧 nicholas@csoai.org
|
|
40
|
-
- 🌐 [CSOAI.org](https://csoai.org)
|
|
41
|
-
|
|
42
|
-
## License
|
|
43
|
-
|
|
44
|
-
MIT © [CSOAI](https://csoai.org)
|
|
45
|
-
<!-- mcp-name: io.github.CSOAI-ORG/code-executor-mcp -->
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "code-executor-mcp",
|
|
3
|
-
"description": "MEOK AI Labs \u2014 code-executor-mcp",
|
|
4
|
-
"vendor": "MEOK AI Labs",
|
|
5
|
-
"homepage": "https://meok.ai",
|
|
6
|
-
"repository": "https://github.com/CSOAI-ORG/code-executor-mcp",
|
|
7
|
-
"license": "MIT",
|
|
8
|
-
"runtime": "python",
|
|
9
|
-
"entryPoint": "mcp-wrapper.py"
|
|
10
|
-
}
|
|
File without changes
|
{code_executor_mcp-1.0.4 → code_executor_mcp-1.0.7}/.github/workflows/mcp-smithery-publish.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|