mle-kit-mcp 1.0.2__py3-none-any.whl → 1.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.
- mle_kit_mcp/tools/__init__.py +3 -0
- mle_kit_mcp/tools/bash.py +8 -0
- mle_kit_mcp/tools/file_system.py +155 -0
- {mle_kit_mcp-1.0.2.dist-info → mle_kit_mcp-1.1.0.dist-info}/METADATA +1 -1
- {mle_kit_mcp-1.0.2.dist-info → mle_kit_mcp-1.1.0.dist-info}/RECORD +9 -8
- {mle_kit_mcp-1.0.2.dist-info → mle_kit_mcp-1.1.0.dist-info}/WHEEL +0 -0
- {mle_kit_mcp-1.0.2.dist-info → mle_kit_mcp-1.1.0.dist-info}/entry_points.txt +0 -0
- {mle_kit_mcp-1.0.2.dist-info → mle_kit_mcp-1.1.0.dist-info}/licenses/LICENSE +0 -0
- {mle_kit_mcp-1.0.2.dist-info → mle_kit_mcp-1.1.0.dist-info}/top_level.txt +0 -0
mle_kit_mcp/tools/__init__.py
CHANGED
@@ -8,6 +8,7 @@ from .llm_proxy import (
|
|
8
8
|
llm_proxy_local,
|
9
9
|
llm_proxy_remote,
|
10
10
|
)
|
11
|
+
from .file_system import glob, grep
|
11
12
|
|
12
13
|
|
13
14
|
__all__ = [
|
@@ -17,4 +18,6 @@ __all__ = [
|
|
17
18
|
"remote_download",
|
18
19
|
"llm_proxy_local",
|
19
20
|
"llm_proxy_remote",
|
21
|
+
"glob",
|
22
|
+
"grep",
|
20
23
|
]
|
mle_kit_mcp/tools/bash.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
import atexit
|
2
2
|
import signal
|
3
3
|
import shlex
|
4
|
+
import os
|
4
5
|
from typing import Optional, Any
|
5
6
|
|
6
7
|
from docker import from_env as docker_from_env # type: ignore
|
@@ -26,6 +27,8 @@ def get_docker_client() -> DockerClient:
|
|
26
27
|
|
27
28
|
def create_container() -> Container:
|
28
29
|
client = get_docker_client()
|
30
|
+
uid = os.getuid()
|
31
|
+
gid = os.getgid()
|
29
32
|
container = client.containers.run(
|
30
33
|
BASE_IMAGE,
|
31
34
|
"tail -f /dev/null",
|
@@ -33,6 +36,11 @@ def create_container() -> Container:
|
|
33
36
|
remove=True,
|
34
37
|
tty=True,
|
35
38
|
stdin_open=True,
|
39
|
+
user=f"{uid}:{gid}",
|
40
|
+
environment={
|
41
|
+
"HOME": DOCKER_WORKSPACE_DIR_PATH,
|
42
|
+
"XDG_CACHE_HOME": f"{DOCKER_WORKSPACE_DIR_PATH}/.cache",
|
43
|
+
},
|
36
44
|
volumes={
|
37
45
|
get_workspace_dir(): {
|
38
46
|
"bind": DOCKER_WORKSPACE_DIR_PATH,
|
@@ -0,0 +1,155 @@
|
|
1
|
+
from typing import List, Optional
|
2
|
+
from pathlib import Path
|
3
|
+
import subprocess
|
4
|
+
|
5
|
+
from mle_kit_mcp.files import get_workspace_dir
|
6
|
+
|
7
|
+
|
8
|
+
def glob(pattern: str, path: Optional[str] = None) -> List[str]:
|
9
|
+
"""
|
10
|
+
- Fast file pattern matching tool that works with any codebase size
|
11
|
+
- Supports glob patterns like "**/*.js" or "src/**/*.ts"
|
12
|
+
- Returns matching file paths sorted by modification time
|
13
|
+
- Use this tool when you need to find files by name patterns
|
14
|
+
|
15
|
+
Args:
|
16
|
+
pattern: The glob pattern to match files against, required.
|
17
|
+
path: The directory to search in. If not specified, the current working directory will be used.
|
18
|
+
IMPORTANT: Omit this field to use the default directory. DO NOT enter "undefined" or "null".
|
19
|
+
Simply omit it for the default behavior.
|
20
|
+
Must be a valid directory path if provided.
|
21
|
+
|
22
|
+
Returns:
|
23
|
+
A list of matching file paths.
|
24
|
+
"""
|
25
|
+
full_path: Path = get_workspace_dir()
|
26
|
+
if path is not None:
|
27
|
+
full_path = get_workspace_dir() / path
|
28
|
+
files = [p for p in full_path.glob(pattern)]
|
29
|
+
files.sort(key=lambda p: p.stat().st_mtime, reverse=True)
|
30
|
+
resolved_files = [str(p.resolve()) for p in files]
|
31
|
+
resolved_files = [f.replace(str(get_workspace_dir()) + "/", "") for f in resolved_files]
|
32
|
+
return resolved_files
|
33
|
+
|
34
|
+
|
35
|
+
def grep(
|
36
|
+
pattern: str,
|
37
|
+
path: Optional[str] = None,
|
38
|
+
glob: Optional[str] = None,
|
39
|
+
output_mode: str = "files_with_matches",
|
40
|
+
before_context: Optional[int] = None,
|
41
|
+
after_context: Optional[int] = None,
|
42
|
+
center_context: Optional[int] = None,
|
43
|
+
insensitive: bool = False,
|
44
|
+
type: Optional[str] = None,
|
45
|
+
head_limit: Optional[int] = None,
|
46
|
+
multiline: bool = False,
|
47
|
+
) -> str:
|
48
|
+
r"""
|
49
|
+
A powerful search tool built on ripgrep
|
50
|
+
|
51
|
+
Usage:
|
52
|
+
- ALWAYS use Grep for search tasks. NEVER invoke `grep` or `rg` as a Bash command.
|
53
|
+
- The Grep tool has been optimized for correct permissions and access.
|
54
|
+
- Supports full regex syntax (e.g., "log.*Error")
|
55
|
+
- Filter files with glob parameter (e.g., "*.js", "**/*.tsx") or type parameter (e.g., "js", "py", "rust")
|
56
|
+
- Output modes: "content" shows matching lines, "files_with_matches" shows only file paths (default), "count" shows match counts
|
57
|
+
- Pattern syntax: Uses ripgrep (not grep) - literal braces need escaping (use `interface\{\}` to find `interface{}` in Go code)
|
58
|
+
- Multiline matching: By default patterns match within single lines only. For cross-line patterns like `struct \{[\s\S]*?field`, use `multiline: true`
|
59
|
+
|
60
|
+
Args:
|
61
|
+
pattern: The regular expression pattern to search for in file contents
|
62
|
+
path: File or directory to search. Defaults to current working directory.
|
63
|
+
glob: Glob pattern to filter files (e.g. "*.js", "*.{ts,tsx}")
|
64
|
+
output_mode: The output mode to use. Possible values are "content", "files_with_matches", "count".
|
65
|
+
"content" shows matching lines (supports -A/-B/-C context, -n line numbers, head_limit)
|
66
|
+
"files_with_matches" shows file paths (supports head_limit)
|
67
|
+
"count" shows match counts (supports head_limit).
|
68
|
+
Defaults to "files_with_matches"
|
69
|
+
before_context: Number of lines to show before each match (rg -B). Requires output_mode: "content", ignored otherwise.
|
70
|
+
after_context: Number of lines to show after each match (rg -A). Requires output_mode: "content", ignored otherwise.
|
71
|
+
center_context: Number of lines to show before and after each match (rg -C). Requires output_mode: "content", ignored otherwise.
|
72
|
+
insensitive: Case insensitive search (rg -i). Defaults to False.
|
73
|
+
type: File type to search (rg --type). Common types: js, py, rust, go, java, etc. More efficient than include for standard file types.
|
74
|
+
head_limit: Limit output to first N lines/entries, equivalent to "| head -N". Works across all output modes: content (limits output lines), files_with_matches (limits file paths), count (limits count entries). When unspecified, shows all results from ripgrep.
|
75
|
+
multiline: Enable multiline mode where . matches newlines and patterns can span lines (rg -U --multiline-dotall). Default: false.
|
76
|
+
|
77
|
+
Returns:
|
78
|
+
A string with the search results.
|
79
|
+
"""
|
80
|
+
assert pattern, "'pattern' must be a non-empty string"
|
81
|
+
|
82
|
+
valid_output_modes = {"content", "files_with_matches", "count"}
|
83
|
+
assert (
|
84
|
+
output_mode in valid_output_modes
|
85
|
+
), f"Invalid output_mode: {output_mode}. Expected one of {sorted(valid_output_modes)}"
|
86
|
+
|
87
|
+
if center_context is not None:
|
88
|
+
assert (
|
89
|
+
before_context is None and after_context is None
|
90
|
+
), "Use either 'center_context' or ('before_context'/'after_context'), not both"
|
91
|
+
|
92
|
+
cmd: List[str] = [
|
93
|
+
"rg",
|
94
|
+
"--color=never",
|
95
|
+
"--no-heading",
|
96
|
+
]
|
97
|
+
|
98
|
+
if output_mode == "files_with_matches":
|
99
|
+
cmd.append("-l")
|
100
|
+
elif output_mode == "count":
|
101
|
+
cmd.append("-c")
|
102
|
+
else:
|
103
|
+
cmd.append("-n")
|
104
|
+
|
105
|
+
if insensitive:
|
106
|
+
cmd.append("-i")
|
107
|
+
|
108
|
+
if multiline:
|
109
|
+
cmd.extend(["--multiline", "--multiline-dotall"])
|
110
|
+
|
111
|
+
if type:
|
112
|
+
cmd.extend(["--type", type])
|
113
|
+
|
114
|
+
if glob:
|
115
|
+
cmd.extend(["--glob", glob])
|
116
|
+
|
117
|
+
if output_mode == "content":
|
118
|
+
if center_context is not None:
|
119
|
+
cmd.extend(["-C", str(center_context)])
|
120
|
+
else:
|
121
|
+
if before_context is not None:
|
122
|
+
cmd.extend(["-B", str(before_context)])
|
123
|
+
if after_context is not None:
|
124
|
+
cmd.extend(["-A", str(after_context)])
|
125
|
+
|
126
|
+
cmd.append("--")
|
127
|
+
cmd.append(pattern)
|
128
|
+
|
129
|
+
search_root: Path = get_workspace_dir()
|
130
|
+
if path is not None:
|
131
|
+
search_root = search_root / path
|
132
|
+
cmd.append(str(search_root))
|
133
|
+
|
134
|
+
try:
|
135
|
+
result = subprocess.run(
|
136
|
+
cmd,
|
137
|
+
stdout=subprocess.PIPE,
|
138
|
+
stderr=subprocess.PIPE,
|
139
|
+
text=True,
|
140
|
+
check=False,
|
141
|
+
)
|
142
|
+
except FileNotFoundError:
|
143
|
+
return "ripgrep (rg) not found. Please install ripgrep in the environment where this tool runs."
|
144
|
+
|
145
|
+
stdout = (result.stdout or "").rstrip("\n")
|
146
|
+
stderr = (result.stderr or "").strip()
|
147
|
+
|
148
|
+
if head_limit is not None and head_limit >= 0 and stdout:
|
149
|
+
stdout_lines = stdout.splitlines()
|
150
|
+
stdout = "\n".join(stdout_lines[:head_limit])
|
151
|
+
|
152
|
+
if result.returncode not in (0, 1) and stderr:
|
153
|
+
return stderr
|
154
|
+
|
155
|
+
return stdout
|
@@ -5,14 +5,15 @@ mle_kit_mcp/llm_proxy.py,sha256=01BG6OA8husOQXxgJQ7RnTNEE_1HDczlCNoAVnYWURQ,1225
|
|
5
5
|
mle_kit_mcp/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
6
6
|
mle_kit_mcp/server.py,sha256=6KGjhcjjqP9PxKw17X7ZejeRrGfCB8Mk4SmnoTklCMs,1587
|
7
7
|
mle_kit_mcp/utils.py,sha256=iHNcEZZzPD37bEYE18SzJ3WUjLP3Ym-kc91SwcW1vlI,1984
|
8
|
-
mle_kit_mcp/tools/__init__.py,sha256=
|
9
|
-
mle_kit_mcp/tools/bash.py,sha256=
|
8
|
+
mle_kit_mcp/tools/__init__.py,sha256=o5Cy8gk67QiqHd40z0LF-nXrezSq4reuvhkWiMlCLpc,392
|
9
|
+
mle_kit_mcp/tools/bash.py,sha256=blL3SWmrqnVdSsWvLu3H3WWjBGdVR1EwylIPLtAJ8co,4154
|
10
|
+
mle_kit_mcp/tools/file_system.py,sha256=TvgNNma8fdFDtYdBvdnHAAgUlbpecyQ1TSJYklQOlI4,6391
|
10
11
|
mle_kit_mcp/tools/llm_proxy.py,sha256=uEPZETqJWGOwLESWfvIjJidL6LSRry5j-qq6rpjtxLM,4623
|
11
12
|
mle_kit_mcp/tools/remote_gpu.py,sha256=fqDWiGnCR6h34LSInw_vMqdU-AfL8Z12969kQ4-cShI,12616
|
12
13
|
mle_kit_mcp/tools/text_editor.py,sha256=hkobiyYB5um6bs5sWYDQ1S2Y5n31i7I6fOBUDFkNhmM,9531
|
13
|
-
mle_kit_mcp-1.0.
|
14
|
-
mle_kit_mcp-1.0.
|
15
|
-
mle_kit_mcp-1.0.
|
16
|
-
mle_kit_mcp-1.0.
|
17
|
-
mle_kit_mcp-1.0.
|
18
|
-
mle_kit_mcp-1.0.
|
14
|
+
mle_kit_mcp-1.1.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
15
|
+
mle_kit_mcp-1.1.0.dist-info/METADATA,sha256=We9HrrSEG96vC82qIigDPXazpZBktLA24ySU1PMuJd4,1074
|
16
|
+
mle_kit_mcp-1.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
17
|
+
mle_kit_mcp-1.1.0.dist-info/entry_points.txt,sha256=-iHSUVPN49jkBj1ySpc-P0rVF5-IPHw-KWNayNIiEsk,49
|
18
|
+
mle_kit_mcp-1.1.0.dist-info/top_level.txt,sha256=XeBtCq_CnVI0gh0Z_daZOLmGl5XPlkA8RgHaj5s5VQY,12
|
19
|
+
mle_kit_mcp-1.1.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|