czty commited on
Commit
f8abf03
·
verified ·
1 Parent(s): 4140be3

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_abricate/Dockerfile +40 -0
  2. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_abricate/app/abricate_server.py +304 -0
  3. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_abricate/app/abricate_shim_server.py +45 -0
  4. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_abricate/app/requirements.txt +1 -0
  5. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_abricate/docker-compose.yml +22 -0
  6. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_abricate/environment.yaml +10 -0
  7. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_abricate/requirements.txt +2 -0
  8. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_abyss/Dockerfile +40 -0
  9. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_abyss/app/abyss_server.py +211 -0
  10. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_abyss/app/abyss_shim_server.py +45 -0
  11. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_abyss/docker-compose.yml +22 -0
  12. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_abyss/environment.yaml +10 -0
  13. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_abyss/requirements.txt +2 -0
  14. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_aragorn/Dockerfile +40 -0
  15. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_aragorn/app/aragorn_server.py +217 -0
  16. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_aragorn/app/aragorn_shim_server.py +45 -0
  17. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_aragorn/app/requirements.txt +1 -0
  18. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_aragorn/docker-compose.yml +22 -0
  19. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_aragorn/environment.yaml +10 -0
  20. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_aragorn/requirements.txt +2 -0
  21. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_barrnap/Dockerfile +40 -0
  22. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_barrnap/app/barrnap_server.py +238 -0
  23. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_barrnap/app/barrnap_shim_server.py +45 -0
  24. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_barrnap/app/requirements.txt +1 -0
  25. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_barrnap/docker-compose.yml +22 -0
  26. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_barrnap/environment.yaml +10 -0
  27. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_barrnap/requirements.txt +2 -0
  28. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bedops/requirements.txt +2 -0
  29. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bedtools/Dockerfile +40 -0
  30. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bedtools/app/bedtools_server.py +700 -0
  31. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bedtools/app/bedtools_shim_server.py +45 -0
  32. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bedtools/docker-compose.yml +22 -0
  33. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bedtools/environment.yaml +10 -0
  34. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bedtools/requirements.txt +2 -0
  35. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bioconductor-apeglm/Dockerfile +40 -0
  36. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bioconductor-apeglm/app/bioconductor-apeglm_server.py +125 -0
  37. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bioconductor-apeglm/app/bioconductor-apeglm_shim_server.py +45 -0
  38. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bioconductor-apeglm/docker-compose.yml +22 -0
  39. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bioconductor-apeglm/environment.yaml +10 -0
  40. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bioconductor-apeglm/requirements.txt +2 -0
  41. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bioconductor-beachmat/Dockerfile +40 -0
  42. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bioconductor-beachmat/app/bioconductor-beachmat_server.py +218 -0
  43. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bioconductor-beachmat/app/bioconductor-beachmat_shim_server.py +45 -0
  44. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bioconductor-beachmat/docker-compose.yml +22 -0
  45. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bioconductor-beachmat/environment.yaml +10 -0
  46. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bioconductor-beachmat/requirements.txt +2 -0
  47. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bioconductor-biobase/Dockerfile +40 -0
  48. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bioconductor-biobase/app/bioconductor-biobase_server.py +159 -0
  49. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bioconductor-biobase/app/bioconductor-biobase_shim_server.py +45 -0
  50. BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bioconductor-biobase/docker-compose.yml +22 -0
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_abricate/Dockerfile ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ FROM python:3.10-slim
3
+
4
+ # Install system dependencies
5
+ RUN apt-get update && apt-get install -y default-jre wget curl && apt-get clean && rm -rf /var/lib/apt/lists/*
6
+
7
+ # Install Miniconda
8
+ RUN wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O /tmp/miniconda.sh && bash /tmp/miniconda.sh -b -p /opt/conda && rm /tmp/miniconda.sh
9
+
10
+ # Add conda to PATH
11
+ ENV PATH="/opt/conda/bin:$PATH"
12
+
13
+ # Install abricate via conda (e.g., from bioconda)
14
+ RUN conda install -c bioconda abricate -y && conda clean -a
15
+
16
+ # Install Python dependencies
17
+ RUN pip install uv
18
+ RUN uv pip install --system fastmcp
19
+
20
+ # Create app directory
21
+ WORKDIR /app
22
+
23
+ # Copy your MCP server
24
+ COPY app/abricate_server.py /app/
25
+
26
+ # Create workspace and output directories
27
+ RUN mkdir -p /app/workspace /app/output
28
+
29
+ # Make sure the server script is executable
30
+ RUN chmod +x /app/abricate_server.py
31
+
32
+ # Expose port for MCP over HTTP (optional)
33
+ EXPOSE 8000
34
+
35
+ # Health check
36
+ HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 CMD python -c "import sys; sys.exit(0)"
37
+
38
+ # Default command runs the MCP server via stdio
39
+ CMD ["python", "/app/abricate_server.py"]
40
+
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_abricate/app/abricate_server.py ADDED
@@ -0,0 +1,304 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+ import subprocess
3
+ from pathlib import Path
4
+ from typing import List, Optional, Dict, Any
5
+
6
+ # Configure logging
7
+ logging.basicConfig(level=logging.INFO)
8
+ log = logging.getLogger(__name__)
9
+
10
+ # MCP decorator is not defined here, but the functions are structured
11
+ # to be compatible with it.
12
+ class mcp:
13
+ @staticmethod
14
+ def tool():
15
+ def decorator(f):
16
+ return f
17
+ return decorator
18
+
19
+ @mcp.tool()
20
+ def abricate_run(
21
+ contigs: List[Path],
22
+ db: str = "resfinder",
23
+ minid: float = 80.0,
24
+ mincov: float = 80.0,
25
+ threads: int = 1,
26
+ report: Optional[Path] = None,
27
+ summary: Optional[Path] = None,
28
+ json_output: Optional[Path] = None,
29
+ gff: Optional[Path] = None,
30
+ fofn: Optional[Path] = None,
31
+ datadir: Optional[Path] = None,
32
+ mismatches: Optional[int] = None,
33
+ minlen: Optional[int] = None,
34
+ quiet: bool = False,
35
+ debug: bool = False,
36
+ nopathogen: bool = False,
37
+ csv: bool = False,
38
+ noheader: bool = False,
39
+ all_genes: bool = False,
40
+ nukem: bool = False,
41
+ long_report: bool = False,
42
+ pretty: bool = False,
43
+ agrvate: bool = False,
44
+ roary: bool = False,
45
+ prokka: bool = False,
46
+ plasmid: bool = False,
47
+ resistance: bool = False,
48
+ virulence: bool = False,
49
+ locus: bool = False,
50
+ seqid: bool = False,
51
+ ) -> Dict[str, Any]:
52
+ """
53
+ Mass screen contigs for antimicrobial resistance or virulence genes using Abricate.
54
+
55
+ This is the main analysis function of Abricate. It takes one or more FASTA files
56
+ and screens them against a specified database.
57
+ """
58
+ # --- Input Validation ---
59
+ if not contigs and not fofn:
60
+ raise ValueError("Either 'contigs' (a list of FASTA files) or 'fofn' (a file of FASTA paths) must be provided.")
61
+ if contigs and fofn:
62
+ raise ValueError("Provide either 'contigs' or 'fofn', but not both.")
63
+
64
+ if contigs:
65
+ for file_path in contigs:
66
+ if not file_path.exists():
67
+ raise FileNotFoundError(f"Input contig file not found: {file_path}")
68
+
69
+ if fofn and not fofn.exists():
70
+ raise FileNotFoundError(f"Input FOFN file not found: {fofn}")
71
+
72
+ if not 0.0 <= minid <= 100.0:
73
+ raise ValueError(f"'minid' must be between 0.0 and 100.0, but got {minid}")
74
+ if not 0.0 <= mincov <= 100.0:
75
+ raise ValueError(f"'mincov' must be between 0.0 and 100.0, but got {mincov}")
76
+ if threads < 1:
77
+ raise ValueError(f"'threads' must be a positive integer, but got {threads}")
78
+ if mismatches is not None and mismatches < 0:
79
+ raise ValueError(f"'mismatches' cannot be negative, but got {mismatches}")
80
+ if minlen is not None and minlen < 0:
81
+ raise ValueError(f"'minlen' cannot be negative, but got {minlen}")
82
+
83
+ # --- Command Construction ---
84
+ cmd = ["abricate"]
85
+ output_files = []
86
+
87
+ # Add options with values
88
+ cmd.extend(["--db", db])
89
+ cmd.extend(["--minid", str(minid)])
90
+ cmd.extend(["--mincov", str(mincov)])
91
+ cmd.extend(["--threads", str(threads)])
92
+
93
+ if report:
94
+ cmd.extend(["--report", str(report)])
95
+ output_files.append(str(report))
96
+ if summary:
97
+ cmd.extend(["--summary", str(summary)])
98
+ output_files.append(str(summary))
99
+ if json_output:
100
+ cmd.extend(["--json", str(json_output)])
101
+ output_files.append(str(json_output))
102
+ if gff:
103
+ cmd.extend(["--gff", str(gff)])
104
+ output_files.append(str(gff))
105
+ if datadir:
106
+ cmd.extend(["--datadir", str(datadir)])
107
+ if mismatches is not None:
108
+ cmd.extend(["--mismatches", str(mismatches)])
109
+ if minlen is not None:
110
+ cmd.extend(["--minlen", str(minlen)])
111
+ if fofn:
112
+ cmd.extend(["--fofn", str(fofn)])
113
+
114
+ # Add boolean flags
115
+ if quiet: cmd.append("--quiet")
116
+ if debug: cmd.append("--debug")
117
+ if nopathogen: cmd.append("--nopathogen")
118
+ if csv: cmd.append("--csv")
119
+ if noheader: cmd.append("--noheader")
120
+ if all_genes: cmd.append("--all")
121
+ if nukem: cmd.append("--nukem")
122
+ if long_report: cmd.append("--long")
123
+ if pretty: cmd.append("--pretty")
124
+ if agrvate: cmd.append("--agrvate")
125
+ if roary: cmd.append("--roary")
126
+ if prokka: cmd.append("--prokka")
127
+ if plasmid: cmd.append("--plasmid")
128
+ if resistance: cmd.append("--resistance")
129
+ if virulence: cmd.append("--virulence")
130
+ if locus: cmd.append("--locus")
131
+ if seqid: cmd.append("--seqid")
132
+
133
+ # Add positional arguments (input files)
134
+ if contigs:
135
+ cmd.extend([str(p) for p in contigs])
136
+
137
+ # --- Subprocess Execution ---
138
+ command_executed = " ".join(cmd)
139
+ log.info(f"Executing command: {command_executed}")
140
+
141
+ try:
142
+ result = subprocess.run(
143
+ cmd,
144
+ capture_output=True,
145
+ text=True,
146
+ check=True,
147
+ )
148
+ return {
149
+ "command_executed": command_executed,
150
+ "stdout": result.stdout,
151
+ "stderr": result.stderr,
152
+ "output_files": output_files,
153
+ }
154
+ except FileNotFoundError:
155
+ raise RuntimeError("abricate command not found. Please ensure it is in your PATH.")
156
+ except subprocess.CalledProcessError as e:
157
+ log.error(f"Abricate execution failed with exit code {e.returncode}")
158
+ log.error(f"STDOUT: {e.stdout}")
159
+ log.error(f"STDERR: {e.stderr}")
160
+ raise RuntimeError(f"Abricate failed: {e.stderr}")
161
+
162
+
163
+ @mcp.tool()
164
+ def abricate_list_databases(
165
+ datadir: Optional[Path] = None,
166
+ quiet: bool = False,
167
+ debug: bool = False
168
+ ) -> Dict[str, Any]:
169
+ """Lists all available abricate databases."""
170
+ cmd = ["abricate", "--list"]
171
+ if datadir:
172
+ cmd.extend(["--datadir", str(datadir)])
173
+ if quiet:
174
+ cmd.append("--quiet")
175
+ if debug:
176
+ cmd.append("--debug")
177
+
178
+ command_executed = " ".join(cmd)
179
+ log.info(f"Executing command: {command_executed}")
180
+
181
+ try:
182
+ result = subprocess.run(cmd, capture_output=True, text=True, check=True)
183
+ return {
184
+ "command_executed": command_executed,
185
+ "stdout": result.stdout,
186
+ "stderr": result.stderr,
187
+ "output_files": [],
188
+ }
189
+ except FileNotFoundError:
190
+ raise RuntimeError("abricate command not found. Please ensure it is in your PATH.")
191
+ except subprocess.CalledProcessError as e:
192
+ raise RuntimeError(f"Abricate failed to list databases: {e.stderr}")
193
+
194
+
195
+ @mcp.tool()
196
+ def abricate_check_databases(
197
+ datadir: Optional[Path] = None,
198
+ quiet: bool = False,
199
+ debug: bool = False
200
+ ) -> Dict[str, Any]:
201
+ """Checks if the abricate databases are installed correctly."""
202
+ cmd = ["abricate", "--check"]
203
+ if datadir:
204
+ cmd.extend(["--datadir", str(datadir)])
205
+ if quiet:
206
+ cmd.append("--quiet")
207
+ if debug:
208
+ cmd.append("--debug")
209
+
210
+ command_executed = " ".join(cmd)
211
+ log.info(f"Executing command: {command_executed}")
212
+
213
+ try:
214
+ result = subprocess.run(cmd, capture_output=True, text=True, check=True)
215
+ return {
216
+ "command_executed": command_executed,
217
+ "stdout": result.stdout,
218
+ "stderr": result.stderr,
219
+ "output_files": [],
220
+ }
221
+ except FileNotFoundError:
222
+ raise RuntimeError("abricate command not found. Please ensure it is in your PATH.")
223
+ except subprocess.CalledProcessError as e:
224
+ raise RuntimeError(f"Abricate database check failed: {e.stderr}")
225
+
226
+
227
+ @mcp.tool()
228
+ def abricate_setup_databases(
229
+ datadir: Optional[Path] = None,
230
+ threads: int = 1,
231
+ quiet: bool = False,
232
+ debug: bool = False
233
+ ) -> Dict[str, Any]:
234
+ """Downloads and sets up all the abricate databases."""
235
+ if threads < 1:
236
+ raise ValueError(f"'threads' must be a positive integer, but got {threads}")
237
+
238
+ cmd = ["abricate", "--setupdb"]
239
+ if datadir:
240
+ cmd.extend(["--datadir", str(datadir)])
241
+ if threads > 1:
242
+ cmd.extend(["--threads", str(threads)])
243
+ if quiet:
244
+ cmd.append("--quiet")
245
+ if debug:
246
+ cmd.append("--debug")
247
+
248
+ command_executed = " ".join(cmd)
249
+ log.info(f"Executing command: {command_executed}")
250
+
251
+ try:
252
+ result = subprocess.run(cmd, capture_output=True, text=True, check=True)
253
+ return {
254
+ "command_executed": command_executed,
255
+ "stdout": result.stdout,
256
+ "stderr": result.stderr,
257
+ "output_files": [],
258
+ }
259
+ except FileNotFoundError:
260
+ raise RuntimeError("abricate command not found. Please ensure it is in your PATH.")
261
+ except subprocess.CalledProcessError as e:
262
+ raise RuntimeError(f"Abricate database setup failed: {e.stderr}")
263
+
264
+
265
+ @mcp.tool()
266
+ def abricate_get_version() -> Dict[str, Any]:
267
+ """Prints the abricate version."""
268
+ cmd = ["abricate", "--version"]
269
+ command_executed = " ".join(cmd)
270
+ log.info(f"Executing command: {command_executed}")
271
+
272
+ try:
273
+ result = subprocess.run(cmd, capture_output=True, text=True, check=True)
274
+ return {
275
+ "command_executed": command_executed,
276
+ "stdout": result.stdout,
277
+ "stderr": result.stderr,
278
+ "output_files": [],
279
+ }
280
+ except FileNotFoundError:
281
+ raise RuntimeError("abricate command not found. Please ensure it is in your PATH.")
282
+ except subprocess.CalledProcessError as e:
283
+ raise RuntimeError(f"Abricate version check failed: {e.stderr}")
284
+
285
+
286
+ @mcp.tool()
287
+ def abricate_get_citation() -> Dict[str, Any]:
288
+ """Prints the citation for abricate."""
289
+ cmd = ["abricate", "--citation"]
290
+ command_executed = " ".join(cmd)
291
+ log.info(f"Executing command: {command_executed}")
292
+
293
+ try:
294
+ result = subprocess.run(cmd, capture_output=True, text=True, check=True)
295
+ return {
296
+ "command_executed": command_executed,
297
+ "stdout": result.stdout,
298
+ "stderr": result.stderr,
299
+ "output_files": [],
300
+ }
301
+ except FileNotFoundError:
302
+ raise RuntimeError("abricate command not found. Please ensure it is in your PATH.")
303
+ except subprocess.CalledProcessError as e:
304
+ raise RuntimeError(f"Abricate citation check failed: {e.stderr}")
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_abricate/app/abricate_shim_server.py ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ from __future__ import annotations
3
+
4
+ import ast
5
+ from pathlib import Path
6
+
7
+ from mcp.server.fastmcp import FastMCP
8
+
9
+
10
+ SOURCE_SERVER = Path('/225040511/project/BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_abricate/app/abricate_server.py')
11
+ SERVER_NAME = 'biosci_abricate'
12
+
13
+
14
+ class _ShimMCP:
15
+ @staticmethod
16
+ def tool():
17
+ def _decorator(fn):
18
+ return fn
19
+ return _decorator
20
+
21
+
22
+ def _load_functions():
23
+ code = SOURCE_SERVER.read_text(encoding="utf-8")
24
+ tree = ast.parse(code, filename=str(SOURCE_SERVER))
25
+ function_names = [n.name for n in tree.body if isinstance(n, ast.FunctionDef) and not n.name.startswith("_")]
26
+ namespace = {
27
+ "__name__": "__mcp_source__",
28
+ "mcp": _ShimMCP(),
29
+ }
30
+ exec(compile(code, str(SOURCE_SERVER), "exec"), namespace, namespace)
31
+ loaded = []
32
+ for name in function_names:
33
+ fn = namespace.get(name)
34
+ if callable(fn):
35
+ loaded.append(fn)
36
+ return loaded
37
+
38
+
39
+ mcp = FastMCP(SERVER_NAME)
40
+ for _fn in _load_functions():
41
+ mcp.tool()(_fn)
42
+
43
+
44
+ if __name__ == "__main__":
45
+ mcp.run(transport="stdio")
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_abricate/app/requirements.txt ADDED
@@ -0,0 +1 @@
 
 
1
+
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_abricate/docker-compose.yml ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ version: '3.8'
2
+
3
+ services:
4
+ mcp-abricate:
5
+ build: .
6
+ image: mcp-abricate:latest
7
+ container_name: mcp-abricate
8
+ ports:
9
+ - "8000:8000"
10
+ environment:
11
+ - MCP_SERVER_NAME=abricate
12
+ volumes:
13
+ - ./workspace:/app/workspace
14
+ - ./output:/app/output
15
+ restart: unless-stopped
16
+ healthcheck:
17
+ test: ["CMD", "python", "-c", "import sys; sys.exit(0)"]
18
+ interval: 30s
19
+ timeout: 10s
20
+ retries: 3
21
+ start_period: 5s
22
+
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_abricate/environment.yaml ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ name: mcp-tool
3
+ channels:
4
+ - bioconda
5
+ - conda-forge
6
+ - defaults
7
+ dependencies:
8
+ - abricate
9
+ - python=3.10
10
+
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_abricate/requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ fastmcp
2
+ mcp
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_abyss/Dockerfile ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ FROM python:3.10-slim
3
+
4
+ # Install system dependencies
5
+ RUN apt-get update && apt-get install -y default-jre wget curl && apt-get clean && rm -rf /var/lib/apt/lists/*
6
+
7
+ # Install Miniconda
8
+ RUN wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O /tmp/miniconda.sh && bash /tmp/miniconda.sh -b -p /opt/conda && rm /tmp/miniconda.sh
9
+
10
+ # Add conda to PATH
11
+ ENV PATH="/opt/conda/bin:$PATH"
12
+
13
+ # Install abyss via conda (e.g., from bioconda)
14
+ RUN conda install -c bioconda abyss -y && conda clean -a
15
+
16
+ # Install Python dependencies
17
+ RUN pip install uv
18
+ RUN uv pip install --system fastmcp
19
+
20
+ # Create app directory
21
+ WORKDIR /app
22
+
23
+ # Copy your MCP server
24
+ COPY abyss_server.py /app/
25
+
26
+ # Create workspace and output directories
27
+ RUN mkdir -p /app/workspace /app/output
28
+
29
+ # Make sure the server script is executable
30
+ RUN chmod +x /app/abyss_server.py
31
+
32
+ # Expose port for MCP over HTTP (optional)
33
+ EXPOSE 8000
34
+
35
+ # Health check
36
+ HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 CMD python -c "import sys; sys.exit(0)"
37
+
38
+ # Default command runs the MCP server via stdio
39
+ CMD ["python", "/app/abyss_server.py"]
40
+
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_abyss/app/abyss_server.py ADDED
@@ -0,0 +1,211 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import subprocess
2
+ from pathlib import Path
3
+ from typing import List, Optional, Dict, Any
4
+
5
+ # from mcp import tool as mcp_tool
6
+ # Note: The 'mcp' import is commented out as per the instructions.
7
+ # In a real MCP environment, you would uncomment the line above.
8
+
9
+ def mcp_tool(func):
10
+ """A placeholder decorator to mimic @mcp.tool()."""
11
+ return func
12
+
13
+ @mcp_tool
14
+ def run_perl(
15
+ programfile: Optional[Path] = None,
16
+ program_string: Optional[str] = None,
17
+ arguments: Optional[List[str]] = None,
18
+ include_dirs: Optional[List[Path]] = None,
19
+ use_modules: Optional[List[str]] = None,
20
+ no_modules: Optional[List[str]] = None,
21
+ warnings: str = "normal",
22
+ check_syntax_only: bool = False,
23
+ enable_all_features: bool = False,
24
+ ) -> Dict[str, Any]:
25
+ """
26
+ Executes a Perl script or a one-liner command with specified options.
27
+
28
+ This tool serves as a wrapper around the Perl interpreter, allowing for the execution
29
+ of scripts from files or direct command-line strings. It provides options for
30
+ managing modules, include paths, and warning levels.
31
+
32
+ Args:
33
+ programfile: Path to the Perl program file to execute.
34
+ program_string: A string containing a one-liner Perl program to execute.
35
+ arguments: A list of arguments to pass to the program file or one-liner.
36
+ include_dirs: A list of directories to add to Perl's @INC path for finding modules.
37
+ use_modules: A list of modules to 'use' before executing the program.
38
+ no_modules: A list of modules to 'no' (disable) before executing the program.
39
+ warnings: Set the warning level. Can be 'normal' (-w), 'all' (-W), or 'none' (-X).
40
+ check_syntax_only: If True, checks the syntax of the program without executing it (-c).
41
+ enable_all_features: If True and using program_string, enables all optional features (-E).
42
+ """
43
+ # 1. Input Validation
44
+ if not (programfile or program_string):
45
+ raise ValueError("Either 'programfile' or 'program_string' must be provided.")
46
+ if programfile and program_string:
47
+ raise ValueError("Cannot provide both 'programfile' and 'program_string'.")
48
+
49
+ if programfile and not programfile.is_file():
50
+ raise FileNotFoundError(f"Program file not found: {programfile}")
51
+
52
+ if include_dirs:
53
+ for d in include_dirs:
54
+ if not d.is_dir():
55
+ raise NotADirectoryError(f"Include directory not found: {d}")
56
+
57
+ allowed_warnings = ["normal", "all", "none"]
58
+ if warnings not in allowed_warnings:
59
+ raise ValueError(f"Invalid 'warnings' value '{warnings}'. Must be one of {allowed_warnings}.")
60
+
61
+ # 2. Command Construction
62
+ cmd = ["perl"]
63
+
64
+ # Handle warnings
65
+ if warnings == "normal":
66
+ cmd.append("-w")
67
+ elif warnings == "all":
68
+ cmd.append("-W")
69
+ elif warnings == "none":
70
+ cmd.append("-X")
71
+
72
+ # Handle syntax check
73
+ if check_syntax_only:
74
+ cmd.append("-c")
75
+
76
+ # Handle include directories
77
+ if include_dirs:
78
+ for d in include_dirs:
79
+ cmd.extend(["-I", str(d)])
80
+
81
+ # Handle modules
82
+ if use_modules:
83
+ for module in use_modules:
84
+ cmd.extend(["-M", module])
85
+ if no_modules:
86
+ for module in no_modules:
87
+ cmd.extend(["-m", module])
88
+
89
+ # Handle program source (file or string)
90
+ if program_string:
91
+ if enable_all_features:
92
+ cmd.append("-E")
93
+ else:
94
+ cmd.append("-e")
95
+ cmd.append(program_string)
96
+ elif programfile:
97
+ cmd.append(str(programfile))
98
+
99
+ # Handle arguments to the script
100
+ if arguments:
101
+ cmd.extend(arguments)
102
+
103
+ command_executed = " ".join(map(str, cmd))
104
+
105
+ # 3. Subprocess Execution
106
+ try:
107
+ result = subprocess.run(
108
+ cmd,
109
+ capture_output=True,
110
+ text=True,
111
+ check=False, # Check manually to provide better error context
112
+ )
113
+ if result.returncode != 0:
114
+ raise subprocess.CalledProcessError(
115
+ result.returncode, cmd, output=result.stdout, stderr=result.stderr
116
+ )
117
+ except FileNotFoundError:
118
+ raise RuntimeError("Perl executable not found. Please ensure it is in your system's PATH.")
119
+ except subprocess.CalledProcessError as e:
120
+ return {
121
+ "error": "Perl execution failed.",
122
+ "return_code": e.returncode,
123
+ "stdout": e.stdout,
124
+ "stderr": e.stderr,
125
+ "command_executed": command_executed,
126
+ }
127
+
128
+ # 4. Structured Result Return
129
+ return {
130
+ "command_executed": command_executed,
131
+ "stdout": result.stdout,
132
+ "stderr": result.stderr,
133
+ "output_files": [] # The wrapper itself doesn't create files
134
+ }
135
+
136
+ @mcp_tool
137
+ def perl_version() -> Dict[str, Any]:
138
+ """
139
+ Retrieves the version, patchlevel, and license of the Perl interpreter.
140
+
141
+ This corresponds to the `perl -v` command.
142
+ """
143
+ cmd = ["perl", "-v"]
144
+ command_executed = " ".join(cmd)
145
+
146
+ try:
147
+ result = subprocess.run(
148
+ cmd,
149
+ capture_output=True,
150
+ text=True,
151
+ check=True,
152
+ )
153
+ except FileNotFoundError:
154
+ raise RuntimeError("Perl executable not found. Please ensure it is in your system's PATH.")
155
+ except subprocess.CalledProcessError as e:
156
+ return {
157
+ "error": "Failed to get Perl version.",
158
+ "return_code": e.returncode,
159
+ "stdout": e.stdout,
160
+ "stderr": e.stderr,
161
+ "command_executed": command_executed,
162
+ }
163
+
164
+ return {
165
+ "command_executed": command_executed,
166
+ "stdout": result.stdout,
167
+ "stderr": result.stderr,
168
+ }
169
+
170
+ @mcp_tool
171
+ def perl_config(variable: Optional[str] = None) -> Dict[str, Any]:
172
+ """
173
+ Prints the configuration summary for the Perl installation.
174
+
175
+ This corresponds to the `perl -V` command. If a variable name is provided,
176
+ it prints the value of that specific configuration variable.
177
+
178
+ Args:
179
+ variable: A specific Config.pm variable to query.
180
+ """
181
+ cmd = ["perl"]
182
+ if variable:
183
+ cmd.append(f"-V:{variable}")
184
+ else:
185
+ cmd.append("-V")
186
+
187
+ command_executed = " ".join(cmd)
188
+
189
+ try:
190
+ result = subprocess.run(
191
+ cmd,
192
+ capture_output=True,
193
+ text=True,
194
+ check=True,
195
+ )
196
+ except FileNotFoundError:
197
+ raise RuntimeError("Perl executable not found. Please ensure it is in your system's PATH.")
198
+ except subprocess.CalledProcessError as e:
199
+ return {
200
+ "error": "Failed to get Perl configuration.",
201
+ "return_code": e.returncode,
202
+ "stdout": e.stdout,
203
+ "stderr": e.stderr,
204
+ "command_executed": command_executed,
205
+ }
206
+
207
+ return {
208
+ "command_executed": command_executed,
209
+ "stdout": result.stdout,
210
+ "stderr": result.stderr,
211
+ }
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_abyss/app/abyss_shim_server.py ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ from __future__ import annotations
3
+
4
+ import ast
5
+ from pathlib import Path
6
+
7
+ from mcp.server.fastmcp import FastMCP
8
+
9
+
10
+ SOURCE_SERVER = Path('/225040511/project/BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_abyss/app/abyss_server.py')
11
+ SERVER_NAME = 'biosci_abyss'
12
+
13
+
14
+ class _ShimMCP:
15
+ @staticmethod
16
+ def tool():
17
+ def _decorator(fn):
18
+ return fn
19
+ return _decorator
20
+
21
+
22
+ def _load_functions():
23
+ code = SOURCE_SERVER.read_text(encoding="utf-8")
24
+ tree = ast.parse(code, filename=str(SOURCE_SERVER))
25
+ function_names = [n.name for n in tree.body if isinstance(n, ast.FunctionDef) and not n.name.startswith("_")]
26
+ namespace = {
27
+ "__name__": "__mcp_source__",
28
+ "mcp": _ShimMCP(),
29
+ }
30
+ exec(compile(code, str(SOURCE_SERVER), "exec"), namespace, namespace)
31
+ loaded = []
32
+ for name in function_names:
33
+ fn = namespace.get(name)
34
+ if callable(fn):
35
+ loaded.append(fn)
36
+ return loaded
37
+
38
+
39
+ mcp = FastMCP(SERVER_NAME)
40
+ for _fn in _load_functions():
41
+ mcp.tool()(_fn)
42
+
43
+
44
+ if __name__ == "__main__":
45
+ mcp.run(transport="stdio")
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_abyss/docker-compose.yml ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ version: '3.8'
2
+
3
+ services:
4
+ mcp-abyss:
5
+ build: .
6
+ image: mcp-abyss:latest
7
+ container_name: mcp-abyss
8
+ ports:
9
+ - "8000:8000"
10
+ environment:
11
+ - MCP_SERVER_NAME=abyss
12
+ volumes:
13
+ - ./workspace:/app/workspace
14
+ - ./output:/app/output
15
+ restart: unless-stopped
16
+ healthcheck:
17
+ test: ["CMD", "python", "-c", "import sys; sys.exit(0)"]
18
+ interval: 30s
19
+ timeout: 10s
20
+ retries: 3
21
+ start_period: 5s
22
+
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_abyss/environment.yaml ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ name: mcp-tool
3
+ channels:
4
+ - bioconda
5
+ - conda-forge
6
+ - defaults
7
+ dependencies:
8
+ - abyss
9
+ - python=3.10
10
+
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_abyss/requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ fastmcp
2
+ mcp
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_aragorn/Dockerfile ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ FROM python:3.10-slim
3
+
4
+ # Install system dependencies
5
+ RUN apt-get update && apt-get install -y default-jre wget curl && apt-get clean && rm -rf /var/lib/apt/lists/*
6
+
7
+ # Install Miniconda
8
+ RUN wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O /tmp/miniconda.sh && bash /tmp/miniconda.sh -b -p /opt/conda && rm /tmp/miniconda.sh
9
+
10
+ # Add conda to PATH
11
+ ENV PATH="/opt/conda/bin:$PATH"
12
+
13
+ # Install aragorn via conda (e.g., from bioconda)
14
+ RUN conda install -c bioconda aragorn -y && conda clean -a
15
+
16
+ # Install Python dependencies
17
+ RUN pip install uv
18
+ RUN uv pip install --system fastmcp
19
+
20
+ # Create app directory
21
+ WORKDIR /app
22
+
23
+ # Copy your MCP server
24
+ COPY app/aragorn_server.py /app/
25
+
26
+ # Create workspace and output directories
27
+ RUN mkdir -p /app/workspace /app/output
28
+
29
+ # Make sure the server script is executable
30
+ RUN chmod +x /app/aragorn_server.py
31
+
32
+ # Expose port for MCP over HTTP (optional)
33
+ EXPOSE 8000
34
+
35
+ # Health check
36
+ HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 CMD python -c "import sys; sys.exit(0)"
37
+
38
+ # Default command runs the MCP server via stdio
39
+ CMD ["python", "/app/aragorn_server.py"]
40
+
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_aragorn/app/aragorn_server.py ADDED
@@ -0,0 +1,217 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import subprocess
2
+ import logging
3
+ from pathlib import Path
4
+ from typing import Optional, List
5
+
6
+ # This is a placeholder for the MCP environment's decorator.
7
+ # In a real MCP environment, this would be provided.
8
+ class mcp:
9
+ @staticmethod
10
+ def tool():
11
+ def decorator(f):
12
+ return f
13
+ return decorator
14
+
15
+ @mcp.tool()
16
+ def aragorn(
17
+ sequence_file: Path,
18
+ output_file: Optional[Path] = None,
19
+ search_mode: str = "both",
20
+ batch_output: bool = False,
21
+ fasta_output_all: bool = False,
22
+ fasta_output_all_seq_only: bool = False,
23
+ fasta_output_mature: bool = False,
24
+ fasta_output_mature_seq_only: bool = False,
25
+ fasta_output_all_no_spaces: bool = False,
26
+ fasta_output_mature_no_spaces: bool = False,
27
+ output_format: str = "normal",
28
+ verbose: bool = False,
29
+ verbose_trna_structure: bool = False,
30
+ verbose_tmrna_structure: bool = False,
31
+ genetic_code: str = "standard",
32
+ genetic_code_table_id: Optional[int] = None,
33
+ allow_introns: bool = False,
34
+ topology: str = "circular",
35
+ post_process_cutoff: Optional[float] = None,
36
+ no_post_process: bool = False,
37
+ ecoli_tloop: bool = False,
38
+ permuted_exons: bool = False,
39
+ input_format: Optional[int] = None,
40
+ strand: str = "both"
41
+ ):
42
+ """
43
+ Finds tRNA and tmRNA genes in nucleotide sequences using ARAGORN.
44
+
45
+ ARAGORN is a tool for finding transfer RNA (tRNA) and transfer-messenger RNA (tmRNA)
46
+ genes in nucleotide sequences. It uses homology search algorithms to identify
47
+ these genes with high accuracy.
48
+
49
+ Args:
50
+ sequence_file: Input FASTA file containing nucleotide sequences.
51
+ output_file: Specify the output file path. If not provided, output is sent to stdout.
52
+ search_mode: Type of genes to search for. One of 'both', 'trna', 'tmrna'.
53
+ batch_output: Use batch output in a readable format (-w).
54
+ fasta_output_all: Fasta output of all genes (-fo).
55
+ fasta_output_all_seq_only: Fasta output of all genes, sequence only (-fos).
56
+ fasta_output_mature: Fasta output of mature tRNAs (-fr).
57
+ fasta_output_mature_seq_only: Fasta output of mature tRNAs, sequence only (-frs).
58
+ fasta_output_all_no_spaces: Fasta output of all genes, no spaces in header (-fons).
59
+ fasta_output_mature_no_spaces: Fasta output of mature tRNAs, no spaces in header (-frns).
60
+ output_format: Specify the main output format. One of 'normal', 'fasta', 'raw', 'brackets'.
61
+ verbose: Enable verbose output (-v).
62
+ verbose_trna_structure: Print tRNA secondary structure with verbose output (-tv).
63
+ verbose_tmrna_structure: Print tmRNA secondary structure with verbose output (-mv).
64
+ genetic_code: Genetic code to use for tRNA search. One of 'standard', 'chloroplast', 'mitochondrial',
65
+ 'vertebrate_mitochondrial', 'invertebrate_mitochondrial', 'yeast_mitochondrial',
66
+ 'protozoan', 'mycoplasma'.
67
+ genetic_code_table_id: Specify genetic code by its table number (-gcode <n>).
68
+ allow_introns: Allow introns in tRNAs (-i).
69
+ topology: Assume sequence topology. One of 'circular' (default) or 'linear' (-l).
70
+ post_process_cutoff: Post-process with profile search, using a cutoff in bits (-ps <n>).
71
+ no_post_process: Do not post-process with profile search (-d).
72
+ ecoli_tloop: Use E. coli tRNA T-loop consensus T-Psi-C-R-A (-a).
73
+ permuted_exons: Search for tRNA genes with permuted exons (-rp).
74
+ input_format: Specify input format code (1=fasta, 2=plain, 3=embl, 4=genbank).
75
+ strand: Strand to search. One of 'both' (default), 'sense', 'complementary'.
76
+
77
+ Returns:
78
+ A dictionary containing the command executed, stdout, stderr, and a list of output files.
79
+ """
80
+ # --- Input Validation ---
81
+ if not sequence_file.is_file():
82
+ raise FileNotFoundError(f"Input sequence file not found: {sequence_file}")
83
+
84
+ valid_search_modes = ["both", "trna", "tmrna"]
85
+ if search_mode not in valid_search_modes:
86
+ raise ValueError(f"Invalid search_mode '{search_mode}'. Must be one of {valid_search_modes}")
87
+
88
+ valid_output_formats = ["normal", "fasta", "raw", "brackets"]
89
+ if output_format not in valid_output_formats:
90
+ raise ValueError(f"Invalid output_format '{output_format}'. Must be one of {valid_output_formats}")
91
+
92
+ valid_genetic_codes = [
93
+ "standard", "chloroplast", "mitochondrial", "vertebrate_mitochondrial",
94
+ "invertebrate_mitochondrial", "yeast_mitochondrial", "protozoan", "mycoplasma"
95
+ ]
96
+ if genetic_code not in valid_genetic_codes:
97
+ raise ValueError(f"Invalid genetic_code '{genetic_code}'. Must be one of {valid_genetic_codes}")
98
+
99
+ if genetic_code != "standard" and genetic_code_table_id is not None:
100
+ raise ValueError("Cannot specify both a named genetic_code and a genetic_code_table_id.")
101
+
102
+ valid_topologies = ["circular", "linear"]
103
+ if topology not in valid_topologies:
104
+ raise ValueError(f"Invalid topology '{topology}'. Must be one of {valid_topologies}")
105
+
106
+ if post_process_cutoff is not None and no_post_process:
107
+ raise ValueError("Cannot specify both post_process_cutoff and no_post_process.")
108
+
109
+ if input_format is not None and input_format not in [1, 2, 3, 4]:
110
+ raise ValueError(f"Invalid input_format '{input_format}'. Must be one of 1, 2, 3, or 4.")
111
+
112
+ valid_strands = ["both", "sense", "complementary"]
113
+ if strand not in valid_strands:
114
+ raise ValueError(f"Invalid strand '{strand}'. Must be one of {valid_strands}")
115
+
116
+ # --- Command Construction ---
117
+ cmd = ["aragorn"]
118
+
119
+ if search_mode == "trna":
120
+ cmd.append("-t")
121
+ elif search_mode == "tmrna":
122
+ cmd.append("-m")
123
+
124
+ if output_file:
125
+ cmd.extend(["-o", str(output_file)])
126
+ if batch_output:
127
+ cmd.append("-w")
128
+ if fasta_output_all:
129
+ cmd.append("-fo")
130
+ if fasta_output_all_seq_only:
131
+ cmd.append("-fos")
132
+ if fasta_output_mature:
133
+ cmd.append("-fr")
134
+ if fasta_output_mature_seq_only:
135
+ cmd.append("-frs")
136
+ if fasta_output_all_no_spaces:
137
+ cmd.append("-fons")
138
+ if fasta_output_mature_no_spaces:
139
+ cmd.append("-frns")
140
+
141
+ if output_format == "fasta":
142
+ cmd.append("-fasta")
143
+ elif output_format == "raw":
144
+ cmd.append("-raw")
145
+ elif output_format == "brackets":
146
+ cmd.append("-br")
147
+
148
+ if verbose:
149
+ cmd.append("-v")
150
+ if verbose_trna_structure:
151
+ cmd.append("-tv")
152
+ if verbose_tmrna_structure:
153
+ cmd.append("-mv")
154
+
155
+ if genetic_code_table_id is not None:
156
+ cmd.extend(["-gcode", str(genetic_code_table_id)])
157
+ else:
158
+ code_map = {
159
+ "standard": "-gcstd", "chloroplast": "-c", "mitochondrial": "-mt",
160
+ "vertebrate_mitochondrial": "-gcvert", "invertebrate_mitochondrial": "-gcinvert",
161
+ "yeast_mitochondrial": "-gcyeast", "protozoan": "-gcprot", "mycoplasma": "-gcmyco"
162
+ }
163
+ if genetic_code != "standard":
164
+ cmd.append(code_map[genetic_code])
165
+
166
+ if allow_introns:
167
+ cmd.append("-i")
168
+ if topology == "linear":
169
+ cmd.append("-l")
170
+ if post_process_cutoff is not None:
171
+ cmd.extend(["-ps", str(post_process_cutoff)])
172
+ if no_post_process:
173
+ cmd.append("-d")
174
+ if ecoli_tloop:
175
+ cmd.append("-a")
176
+ if permuted_exons:
177
+ cmd.append("-rp")
178
+
179
+ if input_format is not None:
180
+ cmd.extend(["-if", str(input_format)])
181
+
182
+ if strand == "sense":
183
+ cmd.append("-sense")
184
+ elif strand == "complementary":
185
+ cmd.append("-sc")
186
+
187
+ cmd.append(str(sequence_file))
188
+
189
+ # --- Subprocess Execution ---
190
+ command_executed = " ".join(cmd)
191
+ logging.info(f"Executing command: {command_executed}")
192
+
193
+ try:
194
+ result = subprocess.run(
195
+ cmd,
196
+ check=True,
197
+ capture_output=True,
198
+ text=True,
199
+ encoding='utf-8'
200
+ )
201
+ except FileNotFoundError:
202
+ raise RuntimeError("aragorn executable not found. Please ensure it is in your system's PATH.")
203
+ except subprocess.CalledProcessError as e:
204
+ logging.error(f"ARAGORN execution failed with return code {e.returncode}")
205
+ logging.error(f"Stderr: {e.stderr}")
206
+ # Re-raise as a more informative exception for the MCP environment
207
+ raise RuntimeError(f"ARAGORN execution failed. Stderr: {e.stderr}")
208
+
209
+ # --- Structured Result Return ---
210
+ output_files_list = [str(output_file)] if output_file else []
211
+
212
+ return {
213
+ "command_executed": command_executed,
214
+ "stdout": result.stdout,
215
+ "stderr": result.stderr,
216
+ "output_files": output_files_list
217
+ }
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_aragorn/app/aragorn_shim_server.py ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ from __future__ import annotations
3
+
4
+ import ast
5
+ from pathlib import Path
6
+
7
+ from mcp.server.fastmcp import FastMCP
8
+
9
+
10
+ SOURCE_SERVER = Path('/225040511/project/BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_aragorn/app/aragorn_server.py')
11
+ SERVER_NAME = 'biosci_aragorn'
12
+
13
+
14
+ class _ShimMCP:
15
+ @staticmethod
16
+ def tool():
17
+ def _decorator(fn):
18
+ return fn
19
+ return _decorator
20
+
21
+
22
+ def _load_functions():
23
+ code = SOURCE_SERVER.read_text(encoding="utf-8")
24
+ tree = ast.parse(code, filename=str(SOURCE_SERVER))
25
+ function_names = [n.name for n in tree.body if isinstance(n, ast.FunctionDef) and not n.name.startswith("_")]
26
+ namespace = {
27
+ "__name__": "__mcp_source__",
28
+ "mcp": _ShimMCP(),
29
+ }
30
+ exec(compile(code, str(SOURCE_SERVER), "exec"), namespace, namespace)
31
+ loaded = []
32
+ for name in function_names:
33
+ fn = namespace.get(name)
34
+ if callable(fn):
35
+ loaded.append(fn)
36
+ return loaded
37
+
38
+
39
+ mcp = FastMCP(SERVER_NAME)
40
+ for _fn in _load_functions():
41
+ mcp.tool()(_fn)
42
+
43
+
44
+ if __name__ == "__main__":
45
+ mcp.run(transport="stdio")
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_aragorn/app/requirements.txt ADDED
@@ -0,0 +1 @@
 
 
1
+
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_aragorn/docker-compose.yml ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ version: '3.8'
2
+
3
+ services:
4
+ mcp-aragorn:
5
+ build: .
6
+ image: mcp-aragorn:latest
7
+ container_name: mcp-aragorn
8
+ ports:
9
+ - "8000:8000"
10
+ environment:
11
+ - MCP_SERVER_NAME=aragorn
12
+ volumes:
13
+ - ./workspace:/app/workspace
14
+ - ./output:/app/output
15
+ restart: unless-stopped
16
+ healthcheck:
17
+ test: ["CMD", "python", "-c", "import sys; sys.exit(0)"]
18
+ interval: 30s
19
+ timeout: 10s
20
+ retries: 3
21
+ start_period: 5s
22
+
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_aragorn/environment.yaml ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ name: mcp-tool
3
+ channels:
4
+ - bioconda
5
+ - conda-forge
6
+ - defaults
7
+ dependencies:
8
+ - aragorn
9
+ - python=3.10
10
+
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_aragorn/requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ fastmcp
2
+ mcp
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_barrnap/Dockerfile ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ FROM python:3.10-slim
3
+
4
+ # Install system dependencies
5
+ RUN apt-get update && apt-get install -y default-jre wget curl && apt-get clean && rm -rf /var/lib/apt/lists/*
6
+
7
+ # Install Miniconda
8
+ RUN wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O /tmp/miniconda.sh && bash /tmp/miniconda.sh -b -p /opt/conda && rm /tmp/miniconda.sh
9
+
10
+ # Add conda to PATH
11
+ ENV PATH="/opt/conda/bin:$PATH"
12
+
13
+ # Install barrnap via conda (e.g., from bioconda)
14
+ RUN conda install -c bioconda barrnap -y && conda clean -a
15
+
16
+ # Install Python dependencies
17
+ RUN pip install uv
18
+ RUN uv pip install --system fastmcp
19
+
20
+ # Create app directory
21
+ WORKDIR /app
22
+
23
+ # Copy your MCP server
24
+ COPY app/barrnap_server.py /app/
25
+
26
+ # Create workspace and output directories
27
+ RUN mkdir -p /app/workspace /app/output
28
+
29
+ # Make sure the server script is executable
30
+ RUN chmod +x /app/barrnap_server.py
31
+
32
+ # Expose port for MCP over HTTP (optional)
33
+ EXPOSE 8000
34
+
35
+ # Health check
36
+ HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 CMD python -c "import sys; sys.exit(0)"
37
+
38
+ # Default command runs the MCP server via stdio
39
+ CMD ["python", "/app/barrnap_server.py"]
40
+
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_barrnap/app/barrnap_server.py ADDED
@@ -0,0 +1,238 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import subprocess
2
+ import tempfile
3
+ from pathlib import Path
4
+ from typing import List, Optional, Union
5
+
6
+ # Assume mcp is imported and available in the actual runtime environment
7
+ # from mcp import tool
8
+
9
+ @mcp.tool()
10
+ def perl(
11
+ program_file: Optional[Path] = None,
12
+ program_arguments: Optional[List[str]] = None,
13
+ zero_record_separator: Optional[str] = None,
14
+ autosplit_mode: bool = False,
15
+ unicode_features: Optional[str] = None,
16
+ check_syntax_only: bool = False,
17
+ debugger: Optional[str] = None,
18
+ debug_flags: Optional[str] = None,
19
+ execute_program_line: Optional[List[str]] = None,
20
+ execute_program_line_extended: Optional[List[str]] = None,
21
+ no_sitecustomize: bool = False,
22
+ split_pattern: Optional[str] = None,
23
+ in_place_edit_extension: Optional[str] = None,
24
+ include_directories: Optional[List[Path]] = None,
25
+ line_ending_processing: Optional[str] = None,
26
+ use_modules: Optional[List[str]] = None,
27
+ no_modules: Optional[List[str]] = None,
28
+ loop_around_program: bool = False,
29
+ loop_and_print: bool = False,
30
+ rudimentary_switches: bool = False,
31
+ search_path_for_program: bool = False,
32
+ tainting_warnings: bool = False,
33
+ tainting_checks: bool = False,
34
+ dump_core_after_parsing: bool = False,
35
+ allow_unsafe_operations: bool = False,
36
+ print_version: bool = False,
37
+ print_config_summary: Optional[str] = None,
38
+ enable_warnings: bool = False,
39
+ enable_all_warnings: bool = False,
40
+ ignore_text_before_shebang: Optional[Path] = None,
41
+ disable_all_warnings: bool = False,
42
+ ) -> dict:
43
+ """
44
+ Executes Perl programs with various command-line switches.
45
+
46
+ This tool provides an interface to the Perl interpreter, allowing users to
47
+ run Perl scripts, execute one-liners, and control various aspects of Perl's
48
+ behavior, including debugging, warnings, Unicode features, and module loading.
49
+
50
+ Args:
51
+ program_file: Path to the Perl program file to execute.
52
+ If -e or -E is used, this should typically be omitted.
53
+ program_arguments: List of arguments to pass to the Perl program.
54
+ zero_record_separator: Specify record separator. If an empty string, uses '\0'.
55
+ Otherwise, specifies an octal value. (e.g., "0" for -0, "0777" for -0777)
56
+ autosplit_mode: Enable autosplit mode with -n or -p (splits $_ into @F).
57
+ unicode_features: Enables the listed Unicode features (e.g., "all", "io").
58
+ check_syntax_only: Check syntax only (runs BEGIN and CHECK blocks).
59
+ debugger: Run program under debugger. If an empty string, uses default debugger (-d).
60
+ Otherwise, specifies a debugger (e.g., ":MyDebugger").
61
+ debug_flags: Set debugging flags (argument is a bit mask or alphabets).
62
+ execute_program_line: One line of program to execute. Can be specified multiple times.
63
+ If used, program_file should typically be omitted.
64
+ execute_program_line_extended: Like -e, but enables all optional features.
65
+ Can be specified multiple times.
66
+ If used, program_file should typically be omitted.
67
+ no_sitecustomize: Don't do $sitelib/sitecustomize.pl at startup.
68
+ split_pattern: split() pattern for -a switch (e.g., "/\t/").
69
+ in_place_edit_extension: Edit <> files in place. If an empty string, no backup is made (-i).
70
+ If an extension is supplied (e.g., ".bak"), a backup is made.
71
+ include_directories: Specify @INC/#include directory. Can be specified multiple times.
72
+ line_ending_processing: Enable line ending processing. If an empty string, enables default (-l).
73
+ Otherwise, specifies line terminator (e.g., "012").
74
+ use_modules: Execute "use module..." before executing program. Can be specified multiple times.
75
+ Corresponds to -m or -M.
76
+ no_modules: Execute "no module..." before executing program. Can be specified multiple times.
77
+ Corresponds to -m- or -M-.
78
+ loop_around_program: Assume "while (<>) { ... }" loop around program (-n).
79
+ loop_and_print: Assume loop like -n but print line also, like sed (-p).
80
+ rudimentary_switches: Enable rudimentary parsing for switches after programfile (-s).
81
+ search_path_for_program: Look for programfile using PATH environment variable (-S).
82
+ tainting_warnings: Enable tainting warnings (-t).
83
+ tainting_checks: Enable tainting checks (-T).
84
+ dump_core_after_parsing: Dump core after parsing program (-u).
85
+ allow_unsafe_operations: Allow unsafe operations (-U).
86
+ print_version: Print version, patchlevel and license (-v).
87
+ print_config_summary: Print configuration summary. If an empty string, prints full summary (-V).
88
+ Otherwise, prints a single Config.pm variable (e.g., ":archname").
89
+ enable_warnings: Enable many useful warnings (-w).
90
+ enable_all_warnings: Enable all warnings (-W).
91
+ ignore_text_before_shebang: Ignore text before #!perl line. If None, just ignores (-x).
92
+ Optionally change to directory (e.g., Path("/tmp")).
93
+ disable_all_warnings: Disable all warnings (-X).
94
+
95
+ Returns:
96
+ A dictionary containing the command executed, stdout, stderr, and any output files.
97
+ """
98
+ cmd = ["perl"]
99
+ output_files = []
100
+
101
+ # Input validation
102
+ if program_file and not program_file.is_file():
103
+ return {
104
+ "command_executed": " ".join(cmd),
105
+ "stdout": "",
106
+ "stderr": f"Error: Program file '{program_file}' not found.",
107
+ "output_files": [],
108
+ }
109
+
110
+ if (execute_program_line or execute_program_line_extended) and program_file:
111
+ return {
112
+ "command_executed": " ".join(cmd),
113
+ "stdout": "",
114
+ "stderr": "Error: Cannot use -e/-E with a program file. Please omit program_file.",
115
+ "output_files": [],
116
+ }
117
+
118
+ # Add switches
119
+ if zero_record_separator is not None:
120
+ cmd.append(f"-0{zero_record_separator}")
121
+ if autosplit_mode:
122
+ cmd.append("-a")
123
+ if unicode_features:
124
+ cmd.append(f"-C{unicode_features}")
125
+ if check_syntax_only:
126
+ cmd.append("-c")
127
+ if debugger is not None:
128
+ cmd.append(f"-d{':' if debugger else ''}{debugger}")
129
+ if debug_flags:
130
+ cmd.append(f"-D{debug_flags}")
131
+ if execute_program_line:
132
+ for line in execute_program_line:
133
+ cmd.append("-e")
134
+ cmd.append(line)
135
+ if execute_program_line_extended:
136
+ for line in execute_program_line_extended:
137
+ cmd.append("-E")
138
+ cmd.append(line)
139
+ if no_sitecustomize:
140
+ cmd.append("-f")
141
+ if split_pattern:
142
+ cmd.append(f"-F{split_pattern}")
143
+ if in_place_edit_extension is not None:
144
+ cmd.append(f"-i{in_place_edit_extension}")
145
+ if include_directories:
146
+ for directory in include_directories:
147
+ if not directory.is_dir():
148
+ return {
149
+ "command_executed": " ".join(cmd),
150
+ "stdout": "",
151
+ "stderr": f"Error: Include directory '{directory}' not found.",
152
+ "output_files": [],
153
+ }
154
+ cmd.append("-I")
155
+ cmd.append(str(directory))
156
+ if line_ending_processing is not None:
157
+ cmd.append(f"-l{line_ending_processing}")
158
+ if use_modules:
159
+ for module in use_modules:
160
+ # The help document shows -[mM][-]module.
161
+ # Assuming -M for 'use' and -m- for 'no'.
162
+ # For simplicity, we'll use -M for 'use' as it's more common for explicit module loading.
163
+ cmd.append(f"-M{module}")
164
+ if no_modules:
165
+ for module in no_modules:
166
+ cmd.append(f"-M-{module}") # Using -M- for 'no module'
167
+ if loop_around_program:
168
+ cmd.append("-n")
169
+ if loop_and_print:
170
+ cmd.append("-p")
171
+ if rudimentary_switches:
172
+ cmd.append("-s")
173
+ if search_path_for_program:
174
+ cmd.append("-S")
175
+ if tainting_warnings:
176
+ cmd.append("-t")
177
+ if tainting_checks:
178
+ cmd.append("-T")
179
+ if dump_core_after_parsing:
180
+ cmd.append("-u")
181
+ if allow_unsafe_operations:
182
+ cmd.append("-U")
183
+ if print_version:
184
+ cmd.append("-v")
185
+ if print_config_summary is not None:
186
+ cmd.append(f"-V{':' if print_config_summary else ''}{print_config_summary}")
187
+ if enable_warnings:
188
+ cmd.append("-w")
189
+ if enable_all_warnings:
190
+ cmd.append("-W")
191
+ if ignore_text_before_shebang is not None:
192
+ if ignore_text_before_shebang and not ignore_text_before_shebang.is_dir():
193
+ return {
194
+ "command_executed": " ".join(cmd),
195
+ "stdout": "",
196
+ "stderr": f"Error: Directory for -x '{ignore_text_before_shebang}' not found.",
197
+ "output_files": [],
198
+ }
199
+ cmd.append(f"-x{str(ignore_text_before_shebang) if ignore_text_before_shebang else ''}")
200
+ if disable_all_warnings:
201
+ cmd.append("-X")
202
+
203
+ # Add program file and its arguments
204
+ if program_file:
205
+ cmd.append(str(program_file))
206
+ if program_arguments:
207
+ cmd.extend(program_arguments)
208
+
209
+ try:
210
+ process = subprocess.run(
211
+ cmd,
212
+ capture_output=True,
213
+ text=True,
214
+ check=True,
215
+ )
216
+ stdout = process.stdout
217
+ stderr = process.stderr
218
+ except subprocess.CalledProcessError as e:
219
+ return {
220
+ "command_executed": " ".join(e.cmd),
221
+ "stdout": e.stdout,
222
+ "stderr": e.stderr,
223
+ "output_files": [],
224
+ }
225
+ except FileNotFoundError:
226
+ return {
227
+ "command_executed": " ".join(cmd),
228
+ "stdout": "",
229
+ "stderr": "Error: 'perl' command not found. Ensure Perl is installed and in your PATH.",
230
+ "output_files": [],
231
+ }
232
+
233
+ return {
234
+ "command_executed": " ".join(cmd),
235
+ "stdout": stdout,
236
+ "stderr": stderr,
237
+ "output_files": output_files,
238
+ }
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_barrnap/app/barrnap_shim_server.py ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ from __future__ import annotations
3
+
4
+ import ast
5
+ from pathlib import Path
6
+
7
+ from mcp.server.fastmcp import FastMCP
8
+
9
+
10
+ SOURCE_SERVER = Path('/225040511/project/BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_barrnap/app/barrnap_server.py')
11
+ SERVER_NAME = 'biosci_barrnap'
12
+
13
+
14
+ class _ShimMCP:
15
+ @staticmethod
16
+ def tool():
17
+ def _decorator(fn):
18
+ return fn
19
+ return _decorator
20
+
21
+
22
+ def _load_functions():
23
+ code = SOURCE_SERVER.read_text(encoding="utf-8")
24
+ tree = ast.parse(code, filename=str(SOURCE_SERVER))
25
+ function_names = [n.name for n in tree.body if isinstance(n, ast.FunctionDef) and not n.name.startswith("_")]
26
+ namespace = {
27
+ "__name__": "__mcp_source__",
28
+ "mcp": _ShimMCP(),
29
+ }
30
+ exec(compile(code, str(SOURCE_SERVER), "exec"), namespace, namespace)
31
+ loaded = []
32
+ for name in function_names:
33
+ fn = namespace.get(name)
34
+ if callable(fn):
35
+ loaded.append(fn)
36
+ return loaded
37
+
38
+
39
+ mcp = FastMCP(SERVER_NAME)
40
+ for _fn in _load_functions():
41
+ mcp.tool()(_fn)
42
+
43
+
44
+ if __name__ == "__main__":
45
+ mcp.run(transport="stdio")
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_barrnap/app/requirements.txt ADDED
@@ -0,0 +1 @@
 
 
1
+
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_barrnap/docker-compose.yml ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ version: '3.8'
2
+
3
+ services:
4
+ mcp-barrnap:
5
+ build: .
6
+ image: mcp-barrnap:latest
7
+ container_name: mcp-barrnap
8
+ ports:
9
+ - "8000:8000"
10
+ environment:
11
+ - MCP_SERVER_NAME=barrnap
12
+ volumes:
13
+ - ./workspace:/app/workspace
14
+ - ./output:/app/output
15
+ restart: unless-stopped
16
+ healthcheck:
17
+ test: ["CMD", "python", "-c", "import sys; sys.exit(0)"]
18
+ interval: 30s
19
+ timeout: 10s
20
+ retries: 3
21
+ start_period: 5s
22
+
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_barrnap/environment.yaml ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ name: mcp-tool
3
+ channels:
4
+ - bioconda
5
+ - conda-forge
6
+ - defaults
7
+ dependencies:
8
+ - barrnap
9
+ - python=3.10
10
+
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_barrnap/requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ fastmcp
2
+ mcp
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bedops/requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ fastmcp
2
+ mcp
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bedtools/Dockerfile ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ FROM python:3.10-slim
3
+
4
+ # Install system dependencies
5
+ RUN apt-get update && apt-get install -y default-jre wget curl && apt-get clean && rm -rf /var/lib/apt/lists/*
6
+
7
+ # Install Miniconda
8
+ RUN wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O /tmp/miniconda.sh && bash /tmp/miniconda.sh -b -p /opt/conda && rm /tmp/miniconda.sh
9
+
10
+ # Add conda to PATH
11
+ ENV PATH="/opt/conda/bin:$PATH"
12
+
13
+ # Install bedtools via conda (e.g., from bioconda)
14
+ RUN conda install -c bioconda bedtools -y && conda clean -a
15
+
16
+ # Install Python dependencies
17
+ RUN pip install uv
18
+ RUN uv pip install --system fastmcp
19
+
20
+ # Create app directory
21
+ WORKDIR /app
22
+
23
+ # Copy your MCP server
24
+ COPY bedtools_server.py /app/
25
+
26
+ # Create workspace and output directories
27
+ RUN mkdir -p /app/workspace /app/output
28
+
29
+ # Make sure the server script is executable
30
+ RUN chmod +x /app/bedtools_server.py
31
+
32
+ # Expose port for MCP over HTTP (optional)
33
+ EXPOSE 8000
34
+
35
+ # Health check
36
+ HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 CMD python -c "import sys; sys.exit(0)"
37
+
38
+ # Default command runs the MCP server via stdio
39
+ CMD ["python", "/app/bedtools_server.py"]
40
+
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bedtools/app/bedtools_server.py ADDED
@@ -0,0 +1,700 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import subprocess
2
+ import tempfile
3
+ from pathlib import Path
4
+ from typing import List, Optional
5
+
6
+ # This is a placeholder for the MCP decorator.
7
+ # In a real MCP environment, this would be provided by the MCP framework.
8
+ def tool(func):
9
+ """A dummy decorator to stand in for @mcp.tool()."""
10
+ return func
11
+
12
+ mcp = type("mcp", (), {"tool": tool})
13
+
14
+
15
+ @mcp.tool()
16
+ def intersect(
17
+ a: Path,
18
+ b: List[Path],
19
+ output: Optional[Path] = None,
20
+ wa: bool = False,
21
+ wb: bool = False,
22
+ loj: bool = False,
23
+ wo: bool = False,
24
+ wao: bool = False,
25
+ u: bool = False,
26
+ c: bool = False,
27
+ v: bool = False,
28
+ ubam: bool = False,
29
+ s: bool = False,
30
+ S: bool = False,
31
+ f: float = 1e-9,
32
+ F: float = 1e-9,
33
+ r: bool = False,
34
+ e: bool = False,
35
+ split: bool = False,
36
+ g: Optional[Path] = None,
37
+ header: bool = False,
38
+ bed: bool = False,
39
+ sorted: bool = False,
40
+ names: Optional[str] = None,
41
+ filenames: bool = False,
42
+ nonamecheck: bool = False,
43
+ ):
44
+ """
45
+ Find overlapping intervals in two or more BED/GFF/VCF/BAM files.
46
+
47
+ This tool allows one to screen for overlaps between two sets of genomic features.
48
+ """
49
+ # Input validation
50
+ if not a.exists():
51
+ raise FileNotFoundError(f"Input file -a does not exist: {a}")
52
+ for b_file in b:
53
+ if not b_file.exists():
54
+ raise FileNotFoundError(f"Input file in -b list does not exist: {b_file}")
55
+ if g and not g.exists():
56
+ raise FileNotFoundError(f"Genome file -g does not exist: {g}")
57
+
58
+ exclusive_flags = [u, c, v, wo, wao]
59
+ if sum(exclusive_flags) > 1:
60
+ raise ValueError("Options -u, -c, -v, -wo, -wao are mutually exclusive.")
61
+ if s and S:
62
+ raise ValueError("Options -s and -S are mutually exclusive.")
63
+ if f < 0.0 or f > 1.0:
64
+ raise ValueError("-f (fraction) must be between 0.0 and 1.0.")
65
+ if F < 0.0 or F > 1.0:
66
+ raise ValueError("-F (fraction) must be between 0.0 and 1.0.")
67
+ if sorted and not g:
68
+ raise ValueError("The -sorted option requires a genome file (-g).")
69
+
70
+ # Command construction
71
+ cmd = ["bedtools", "intersect", "-a", str(a), "-b"]
72
+ cmd.extend([str(p) for p in b])
73
+
74
+ if wa: cmd.append("-wa")
75
+ if wb: cmd.append("-wb")
76
+ if loj: cmd.append("-loj")
77
+ if wo: cmd.append("-wo")
78
+ if wao: cmd.append("-wao")
79
+ if u: cmd.append("-u")
80
+ if c: cmd.append("-c")
81
+ if v: cmd.append("-v")
82
+ if ubam: cmd.append("-ubam")
83
+ if s: cmd.append("-s")
84
+ if S: cmd.append("-S")
85
+ if f != 1e-9: cmd.extend(["-f", str(f)])
86
+ if F != 1e-9: cmd.extend(["-F", str(F)])
87
+ if r: cmd.append("-r")
88
+ if e: cmd.append("-e")
89
+ if split: cmd.append("-split")
90
+ if g: cmd.extend(["-g", str(g)])
91
+ if header: cmd.append("-header")
92
+ if bed: cmd.append("-bed")
93
+ if sorted: cmd.append("-sorted")
94
+ if names: cmd.extend(["-names", names])
95
+ if filenames: cmd.append("-filenames")
96
+ if nonamecheck: cmd.append("-nonamecheck")
97
+
98
+ # Subprocess execution
99
+ command_executed = " ".join(cmd)
100
+ output_files = []
101
+ stdout_capture, stderr_capture = "", ""
102
+
103
+ try:
104
+ if output:
105
+ output_files.append(str(output))
106
+ with open(output, "w") as f_out:
107
+ result = subprocess.run(
108
+ cmd, check=True, text=True, stdout=f_out, stderr=subprocess.PIPE
109
+ )
110
+ stderr_capture = result.stderr
111
+ else:
112
+ result = subprocess.run(
113
+ cmd, check=True, text=True, capture_output=True
114
+ )
115
+ stdout_capture = result.stdout
116
+ stderr_capture = result.stderr
117
+ except subprocess.CalledProcessError as e:
118
+ return {
119
+ "command_executed": command_executed,
120
+ "stdout": e.stdout or "",
121
+ "stderr": e.stderr or "CalledProcessError with no stderr.",
122
+ "output_files": [],
123
+ "return_code": e.returncode,
124
+ }
125
+
126
+ return {
127
+ "command_executed": command_executed,
128
+ "stdout": stdout_capture,
129
+ "stderr": stderr_capture,
130
+ "output_files": output_files,
131
+ }
132
+
133
+
134
+ @mcp.tool()
135
+ def merge(
136
+ i: Path,
137
+ output: Optional[Path] = None,
138
+ s: bool = False,
139
+ S: Optional[str] = None,
140
+ d: int = 0,
141
+ c: Optional[str] = None,
142
+ o: Optional[str] = None,
143
+ header: bool = False,
144
+ delim: str = ";",
145
+ n: bool = False,
146
+ nms: bool = False,
147
+ scores: Optional[str] = None,
148
+ bed: bool = False,
149
+ prec: int = 5,
150
+ ):
151
+ """
152
+ Merge overlapping features in a BED/GFF/VCF file.
153
+
154
+ This tool combines overlapping or "book-ended" features into a single feature.
155
+ """
156
+ # Input validation
157
+ if not i.exists():
158
+ raise FileNotFoundError(f"Input file -i does not exist: {i}")
159
+ if S and S not in ["+", "-"]:
160
+ raise ValueError("Option -S must be either '+' or '-'.")
161
+ if s and S:
162
+ raise ValueError("Options -s and -S are mutually exclusive.")
163
+ if d < 0:
164
+ raise ValueError("Option -d (distance) must be a non-negative integer.")
165
+ if (c and not o) or (o and not c):
166
+ raise ValueError("Options -c and -o must be used together.")
167
+ if c and o:
168
+ if len(c.split(',')) != len(o.split(',')):
169
+ raise ValueError("The number of columns in -c must match the number of operations in -o.")
170
+
171
+ # Command construction
172
+ cmd = ["bedtools", "merge", "-i", str(i)]
173
+
174
+ if s: cmd.append("-s")
175
+ if S: cmd.extend(["-S", S])
176
+ if d > 0: cmd.extend(["-d", str(d)])
177
+ if c: cmd.extend(["-c", c])
178
+ if o: cmd.extend(["-o", o])
179
+ if header: cmd.append("-header")
180
+ if delim != ";": cmd.extend(["-delim", delim])
181
+ if n: cmd.append("-n")
182
+ if nms: cmd.append("-nms")
183
+ if scores: cmd.extend(["-scores", scores])
184
+ if bed: cmd.append("-bed")
185
+ if prec != 5: cmd.extend(["-prec", str(prec)])
186
+
187
+ # Subprocess execution
188
+ command_executed = " ".join(cmd)
189
+ output_files = []
190
+ stdout_capture, stderr_capture = "", ""
191
+
192
+ try:
193
+ if output:
194
+ output_files.append(str(output))
195
+ with open(output, "w") as f_out:
196
+ result = subprocess.run(
197
+ cmd, check=True, text=True, stdout=f_out, stderr=subprocess.PIPE
198
+ )
199
+ stderr_capture = result.stderr
200
+ else:
201
+ result = subprocess.run(
202
+ cmd, check=True, text=True, capture_output=True
203
+ )
204
+ stdout_capture = result.stdout
205
+ stderr_capture = result.stderr
206
+ except subprocess.CalledProcessError as e:
207
+ return {
208
+ "command_executed": command_executed,
209
+ "stdout": e.stdout or "",
210
+ "stderr": e.stderr or "CalledProcessError with no stderr.",
211
+ "output_files": [],
212
+ "return_code": e.returncode,
213
+ }
214
+
215
+ return {
216
+ "command_executed": command_executed,
217
+ "stdout": stdout_capture,
218
+ "stderr": stderr_capture,
219
+ "output_files": output_files,
220
+ }
221
+
222
+
223
+ @mcp.tool()
224
+ def subtract(
225
+ a: Path,
226
+ b: List[Path],
227
+ output: Optional[Path] = None,
228
+ f: float = 1e-9,
229
+ F: float = 1e-9,
230
+ r: bool = False,
231
+ e: bool = False,
232
+ s: bool = False,
233
+ S: bool = False,
234
+ A: bool = False,
235
+ B: bool = False,
236
+ N: bool = False,
237
+ header: bool = False,
238
+ g: Optional[Path] = None,
239
+ ):
240
+ """
241
+ Remove overlapping intervals from a BED/GFF/VCF file.
242
+
243
+ This tool removes portions of features in file A that are overlapped by features in file(s) B.
244
+ """
245
+ # Input validation
246
+ if not a.exists():
247
+ raise FileNotFoundError(f"Input file -a does not exist: {a}")
248
+ for b_file in b:
249
+ if not b_file.exists():
250
+ raise FileNotFoundError(f"Input file in -b list does not exist: {b_file}")
251
+ if g and not g.exists():
252
+ raise FileNotFoundError(f"Genome file -g does not exist: {g}")
253
+ if A and B:
254
+ raise ValueError("Options -A and -B are mutually exclusive.")
255
+ if s and S:
256
+ raise ValueError("Options -s and -S are mutually exclusive.")
257
+
258
+ # Command construction
259
+ cmd = ["bedtools", "subtract", "-a", str(a), "-b"]
260
+ cmd.extend([str(p) for p in b])
261
+
262
+ if f != 1e-9: cmd.extend(["-f", str(f)])
263
+ if F != 1e-9: cmd.extend(["-F", str(F)])
264
+ if r: cmd.append("-r")
265
+ if e: cmd.append("-e")
266
+ if s: cmd.append("-s")
267
+ if S: cmd.append("-S")
268
+ if A: cmd.append("-A")
269
+ if B: cmd.append("-B")
270
+ if N: cmd.append("-N")
271
+ if header: cmd.append("-header")
272
+ if g: cmd.extend(["-g", str(g)])
273
+
274
+ # Subprocess execution
275
+ command_executed = " ".join(cmd)
276
+ output_files = []
277
+ stdout_capture, stderr_capture = "", ""
278
+
279
+ try:
280
+ if output:
281
+ output_files.append(str(output))
282
+ with open(output, "w") as f_out:
283
+ result = subprocess.run(
284
+ cmd, check=True, text=True, stdout=f_out, stderr=subprocess.PIPE
285
+ )
286
+ stderr_capture = result.stderr
287
+ else:
288
+ result = subprocess.run(
289
+ cmd, check=True, text=True, capture_output=True
290
+ )
291
+ stdout_capture = result.stdout
292
+ stderr_capture = result.stderr
293
+ except subprocess.CalledProcessError as e:
294
+ return {
295
+ "command_executed": command_executed,
296
+ "stdout": e.stdout or "",
297
+ "stderr": e.stderr or "CalledProcessError with no stderr.",
298
+ "output_files": [],
299
+ "return_code": e.returncode,
300
+ }
301
+
302
+ return {
303
+ "command_executed": command_executed,
304
+ "stdout": stdout_capture,
305
+ "stderr": stderr_capture,
306
+ "output_files": output_files,
307
+ }
308
+
309
+
310
+ @mcp.tool()
311
+ def slop(
312
+ i: Path,
313
+ g: Path,
314
+ output: Optional[Path] = None,
315
+ b: int = 0,
316
+ l: int = 0,
317
+ r: int = 0,
318
+ s: bool = False,
319
+ pct: bool = False,
320
+ header: bool = False,
321
+ ):
322
+ """
323
+ Increase the size of features in a BED/GFF/VCF file.
324
+
325
+ This tool will increase the size of each feature in a feature file by a user-defined number of bases.
326
+ """
327
+ # Input validation
328
+ if not i.exists():
329
+ raise FileNotFoundError(f"Input file -i does not exist: {i}")
330
+ if not g.exists():
331
+ raise FileNotFoundError(f"Genome file -g does not exist: {g}")
332
+ if b != 0 and (l != 0 or r != 0):
333
+ raise ValueError("Option -b cannot be used with -l or -r.")
334
+
335
+ # Command construction
336
+ cmd = ["bedtools", "slop", "-i", str(i), "-g", str(g)]
337
+
338
+ if b != 0: cmd.extend(["-b", str(b)])
339
+ if l != 0: cmd.extend(["-l", str(l)])
340
+ if r != 0: cmd.extend(["-r", str(r)])
341
+ if s: cmd.append("-s")
342
+ if pct: cmd.append("-pct")
343
+ if header: cmd.append("-header")
344
+
345
+ # Subprocess execution
346
+ command_executed = " ".join(cmd)
347
+ output_files = []
348
+ stdout_capture, stderr_capture = "", ""
349
+
350
+ try:
351
+ if output:
352
+ output_files.append(str(output))
353
+ with open(output, "w") as f_out:
354
+ result = subprocess.run(
355
+ cmd, check=True, text=True, stdout=f_out, stderr=subprocess.PIPE
356
+ )
357
+ stderr_capture = result.stderr
358
+ else:
359
+ result = subprocess.run(
360
+ cmd, check=True, text=True, capture_output=True
361
+ )
362
+ stdout_capture = result.stdout
363
+ stderr_capture = result.stderr
364
+ except subprocess.CalledProcessError as e:
365
+ return {
366
+ "command_executed": command_executed,
367
+ "stdout": e.stdout or "",
368
+ "stderr": e.stderr or "CalledProcessError with no stderr.",
369
+ "output_files": [],
370
+ "return_code": e.returncode,
371
+ }
372
+
373
+ return {
374
+ "command_executed": command_executed,
375
+ "stdout": stdout_capture,
376
+ "stderr": stderr_capture,
377
+ "output_files": output_files,
378
+ }
379
+
380
+
381
+ @mcp.tool()
382
+ def getfasta(
383
+ fi: Path,
384
+ bed: Path,
385
+ fo: Optional[Path] = None,
386
+ s: bool = False,
387
+ split: bool = False,
388
+ name: bool = False,
389
+ name_plus: bool = False,
390
+ tab: bool = False,
391
+ full_header: bool = False,
392
+ ):
393
+ """
394
+ Extract DNA sequences from a FASTA file based on BED/GFF/VCF coordinates.
395
+ """
396
+ # Input validation
397
+ if not fi.exists():
398
+ raise FileNotFoundError(f"FASTA input file -fi does not exist: {fi}")
399
+ if not bed.exists():
400
+ raise FileNotFoundError(f"BED/GFF/VCF file -bed does not exist: {bed}")
401
+ if name and name_plus:
402
+ raise ValueError("Options -name and -name+ are mutually exclusive.")
403
+
404
+ # Command construction
405
+ cmd = ["bedtools", "getfasta", "-fi", str(fi), "-bed", str(bed)]
406
+
407
+ if s: cmd.append("-s")
408
+ if split: cmd.append("-split")
409
+ if name: cmd.append("-name")
410
+ if name_plus: cmd.append("-name+")
411
+ if tab: cmd.append("-tab")
412
+ if full_header: cmd.append("-fullHeader")
413
+ if fo: cmd.extend(["-fo", str(fo)])
414
+
415
+ # Subprocess execution
416
+ command_executed = " ".join(cmd)
417
+ output_files = []
418
+ stdout_capture, stderr_capture = "", ""
419
+
420
+ try:
421
+ # getfasta is unique in that it has a dedicated -fo parameter
422
+ # and doesn't typically write to stdout if -fo is used.
423
+ result = subprocess.run(
424
+ cmd, check=True, text=True, capture_output=True
425
+ )
426
+ stdout_capture = result.stdout
427
+ stderr_capture = result.stderr
428
+ if fo:
429
+ output_files.append(str(fo))
430
+
431
+ except subprocess.CalledProcessError as e:
432
+ return {
433
+ "command_executed": command_executed,
434
+ "stdout": e.stdout or "",
435
+ "stderr": e.stderr or "CalledProcessError with no stderr.",
436
+ "output_files": [],
437
+ "return_code": e.returncode,
438
+ }
439
+
440
+ return {
441
+ "command_executed": command_executed,
442
+ "stdout": stdout_capture,
443
+ "stderr": stderr_capture,
444
+ "output_files": output_files,
445
+ }
446
+
447
+
448
+ @mcp.tool()
449
+ def sort(
450
+ i: Path,
451
+ output: Optional[Path] = None,
452
+ header: bool = False,
453
+ g: Optional[Path] = None,
454
+ faidx: Optional[Path] = None,
455
+ sizeA: bool = False,
456
+ sizeD: bool = False,
457
+ chrThenSizeA: bool = False,
458
+ chrThenSizeD: bool = False,
459
+ chrThenScoreA: bool = False,
460
+ chrThenScoreD: bool = False,
461
+ ):
462
+ """
463
+ Sort a BED/GFF/VCF file by chromosome and then by start position.
464
+ """
465
+ # Input validation
466
+ if not i.exists():
467
+ raise FileNotFoundError(f"Input file -i does not exist: {i}")
468
+ if g and not g.exists():
469
+ raise FileNotFoundError(f"Genome file -g does not exist: {g}")
470
+ if faidx and not faidx.exists():
471
+ raise FileNotFoundError(f"FASTA index file -faidx does not exist: {faidx}")
472
+
473
+ sort_flags = [sizeA, sizeD, chrThenSizeA, chrThenSizeD, chrThenScoreA, chrThenScoreD]
474
+ if sum(sort_flags) > 1:
475
+ raise ValueError("Multiple sorting order flags were provided, but only one is allowed.")
476
+
477
+ # Command construction
478
+ cmd = ["bedtools", "sort", "-i", str(i)]
479
+
480
+ if header: cmd.append("-header")
481
+ if g: cmd.extend(["-g", str(g)])
482
+ if faidx: cmd.extend(["-faidx", str(faidx)])
483
+ if sizeA: cmd.append("-sizeA")
484
+ if sizeD: cmd.append("-sizeD")
485
+ if chrThenSizeA: cmd.append("-chrThenSizeA")
486
+ if chrThenSizeD: cmd.append("-chrThenSizeD")
487
+ if chrThenScoreA: cmd.append("-chrThenScoreA")
488
+ if chrThenScoreD: cmd.append("-chrThenScoreD")
489
+
490
+ # Subprocess execution
491
+ command_executed = " ".join(cmd)
492
+ output_files = []
493
+ stdout_capture, stderr_capture = "", ""
494
+
495
+ try:
496
+ if output:
497
+ output_files.append(str(output))
498
+ with open(output, "w") as f_out:
499
+ result = subprocess.run(
500
+ cmd, check=True, text=True, stdout=f_out, stderr=subprocess.PIPE
501
+ )
502
+ stderr_capture = result.stderr
503
+ else:
504
+ result = subprocess.run(
505
+ cmd, check=True, text=True, capture_output=True
506
+ )
507
+ stdout_capture = result.stdout
508
+ stderr_capture = result.stderr
509
+ except subprocess.CalledProcessError as e:
510
+ return {
511
+ "command_executed": command_executed,
512
+ "stdout": e.stdout or "",
513
+ "stderr": e.stderr or "CalledProcessError with no stderr.",
514
+ "output_files": [],
515
+ "return_code": e.returncode,
516
+ }
517
+
518
+ return {
519
+ "command_executed": command_executed,
520
+ "stdout": stdout_capture,
521
+ "stderr": stderr_capture,
522
+ "output_files": output_files,
523
+ }
524
+
525
+
526
+ @mcp.tool()
527
+ def coverage(
528
+ a: Path,
529
+ b: List[Path],
530
+ output: Optional[Path] = None,
531
+ s: bool = False,
532
+ S: bool = False,
533
+ f: float = 1e-9,
534
+ F: float = 1e-9,
535
+ r: bool = False,
536
+ e: bool = False,
537
+ split: bool = False,
538
+ d: bool = False,
539
+ counts: bool = False,
540
+ hist: bool = False,
541
+ mean: bool = False,
542
+ g: Optional[Path] = None,
543
+ header: bool = False,
544
+ sorted: bool = False,
545
+ ):
546
+ """
547
+ Compute the coverage of features in file A on features in file(s) B.
548
+ """
549
+ # Input validation
550
+ if not a.exists():
551
+ raise FileNotFoundError(f"Input file -a does not exist: {a}")
552
+ for b_file in b:
553
+ if not b_file.exists():
554
+ raise FileNotFoundError(f"Input file in -b list does not exist: {b_file}")
555
+ if g and not g.exists():
556
+ raise FileNotFoundError(f"Genome file -g does not exist: {g}")
557
+ if s and S:
558
+ raise ValueError("Options -s and -S are mutually exclusive.")
559
+ if sorted and not g:
560
+ raise ValueError("The -sorted option requires a genome file (-g).")
561
+
562
+ # Command construction
563
+ cmd = ["bedtools", "coverage", "-a", str(a), "-b"]
564
+ cmd.extend([str(p) for p in b])
565
+
566
+ if s: cmd.append("-s")
567
+ if S: cmd.append("-S")
568
+ if f != 1e-9: cmd.extend(["-f", str(f)])
569
+ if F != 1e-9: cmd.extend(["-F", str(F)])
570
+ if r: cmd.append("-r")
571
+ if e: cmd.append("-e")
572
+ if split: cmd.append("-split")
573
+ if d: cmd.append("-d")
574
+ if counts: cmd.append("-counts")
575
+ if hist: cmd.append("-hist")
576
+ if mean: cmd.append("-mean")
577
+ if g: cmd.extend(["-g", str(g)])
578
+ if header: cmd.append("-header")
579
+ if sorted: cmd.append("-sorted")
580
+
581
+ # Subprocess execution
582
+ command_executed = " ".join(cmd)
583
+ output_files = []
584
+ stdout_capture, stderr_capture = "", ""
585
+
586
+ try:
587
+ if output:
588
+ output_files.append(str(output))
589
+ with open(output, "w") as f_out:
590
+ result = subprocess.run(
591
+ cmd, check=True, text=True, stdout=f_out, stderr=subprocess.PIPE
592
+ )
593
+ stderr_capture = result.stderr
594
+ else:
595
+ result = subprocess.run(
596
+ cmd, check=True, text=True, capture_output=True
597
+ )
598
+ stdout_capture = result.stdout
599
+ stderr_capture = result.stderr
600
+ except subprocess.CalledProcessError as e:
601
+ return {
602
+ "command_executed": command_executed,
603
+ "stdout": e.stdout or "",
604
+ "stderr": e.stderr or "CalledProcessError with no stderr.",
605
+ "output_files": [],
606
+ "return_code": e.returncode,
607
+ }
608
+
609
+ return {
610
+ "command_executed": command_executed,
611
+ "stdout": stdout_capture,
612
+ "stderr": stderr_capture,
613
+ "output_files": output_files,
614
+ }
615
+
616
+
617
+ @mcp.tool()
618
+ def genomecov(
619
+ i: Path,
620
+ g: Path,
621
+ output: Optional[Path] = None,
622
+ d: bool = False,
623
+ dz: bool = False,
624
+ bga: bool = False,
625
+ bg: bool = False,
626
+ scale: float = 1.0,
627
+ pc: bool = False,
628
+ fs: bool = False,
629
+ split: bool = False,
630
+ strand: Optional[str] = None,
631
+ max: int = 0,
632
+ trackline: bool = False,
633
+ trackopts: Optional[str] = None,
634
+ ):
635
+ """
636
+ Compute genome-wide coverage of a feature file.
637
+ """
638
+ # Input validation
639
+ if not i.exists():
640
+ raise FileNotFoundError(f"Input file -i does not exist: {i}")
641
+ if not g.exists():
642
+ raise FileNotFoundError(f"Genome file -g does not exist: {g}")
643
+ if strand and strand not in ["+", "-"]:
644
+ raise ValueError("Option -strand must be either '+' or '-'.")
645
+ if max < 0:
646
+ raise ValueError("Option -max must be a non-negative integer.")
647
+ output_modes = [d, dz, bga, bg]
648
+ if sum(output_modes) > 1:
649
+ raise ValueError("Output format flags (-d, -dz, -bga, -bg) are mutually exclusive.")
650
+
651
+ # Command construction
652
+ cmd = ["bedtools", "genomecov", "-i", str(i), "-g", str(g)]
653
+
654
+ if d: cmd.append("-d")
655
+ if dz: cmd.append("-dz")
656
+ if bga: cmd.append("-bga")
657
+ if bg: cmd.append("-bg")
658
+ if scale != 1.0: cmd.extend(["-scale", str(scale)])
659
+ if pc: cmd.append("-pc")
660
+ if fs: cmd.append("-fs")
661
+ if split: cmd.append("-split")
662
+ if strand: cmd.extend(["-strand", strand])
663
+ if max > 0: cmd.extend(["-max", str(max)])
664
+ if trackline: cmd.append("-trackline")
665
+ if trackopts: cmd.extend(["-trackopts", trackopts])
666
+
667
+ # Subprocess execution
668
+ command_executed = " ".join(cmd)
669
+ output_files = []
670
+ stdout_capture, stderr_capture = "", ""
671
+
672
+ try:
673
+ if output:
674
+ output_files.append(str(output))
675
+ with open(output, "w") as f_out:
676
+ result = subprocess.run(
677
+ cmd, check=True, text=True, stdout=f_out, stderr=subprocess.PIPE
678
+ )
679
+ stderr_capture = result.stderr
680
+ else:
681
+ result = subprocess.run(
682
+ cmd, check=True, text=True, capture_output=True
683
+ )
684
+ stdout_capture = result.stdout
685
+ stderr_capture = result.stderr
686
+ except subprocess.CalledProcessError as e:
687
+ return {
688
+ "command_executed": command_executed,
689
+ "stdout": e.stdout or "",
690
+ "stderr": e.stderr or "CalledProcessError with no stderr.",
691
+ "output_files": [],
692
+ "return_code": e.returncode,
693
+ }
694
+
695
+ return {
696
+ "command_executed": command_executed,
697
+ "stdout": stdout_capture,
698
+ "stderr": stderr_capture,
699
+ "output_files": output_files,
700
+ }
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bedtools/app/bedtools_shim_server.py ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ from __future__ import annotations
3
+
4
+ import ast
5
+ from pathlib import Path
6
+
7
+ from mcp.server.fastmcp import FastMCP
8
+
9
+
10
+ SOURCE_SERVER = Path('/225040511/project/BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bedtools/app/bedtools_server.py')
11
+ SERVER_NAME = 'biosci_bedtools'
12
+
13
+
14
+ class _ShimMCP:
15
+ @staticmethod
16
+ def tool():
17
+ def _decorator(fn):
18
+ return fn
19
+ return _decorator
20
+
21
+
22
+ def _load_functions():
23
+ code = SOURCE_SERVER.read_text(encoding="utf-8")
24
+ tree = ast.parse(code, filename=str(SOURCE_SERVER))
25
+ function_names = [n.name for n in tree.body if isinstance(n, ast.FunctionDef) and not n.name.startswith("_")]
26
+ namespace = {
27
+ "__name__": "__mcp_source__",
28
+ "mcp": _ShimMCP(),
29
+ }
30
+ exec(compile(code, str(SOURCE_SERVER), "exec"), namespace, namespace)
31
+ loaded = []
32
+ for name in function_names:
33
+ fn = namespace.get(name)
34
+ if callable(fn):
35
+ loaded.append(fn)
36
+ return loaded
37
+
38
+
39
+ mcp = FastMCP(SERVER_NAME)
40
+ for _fn in _load_functions():
41
+ mcp.tool()(_fn)
42
+
43
+
44
+ if __name__ == "__main__":
45
+ mcp.run(transport="stdio")
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bedtools/docker-compose.yml ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ version: '3.8'
2
+
3
+ services:
4
+ mcp-bedtools:
5
+ build: .
6
+ image: mcp-bedtools:latest
7
+ container_name: mcp-bedtools
8
+ ports:
9
+ - "8000:8000"
10
+ environment:
11
+ - MCP_SERVER_NAME=bedtools
12
+ volumes:
13
+ - ./workspace:/app/workspace
14
+ - ./output:/app/output
15
+ restart: unless-stopped
16
+ healthcheck:
17
+ test: ["CMD", "python", "-c", "import sys; sys.exit(0)"]
18
+ interval: 30s
19
+ timeout: 10s
20
+ retries: 3
21
+ start_period: 5s
22
+
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bedtools/environment.yaml ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ name: mcp-tool
3
+ channels:
4
+ - bioconda
5
+ - conda-forge
6
+ - defaults
7
+ dependencies:
8
+ - bedtools
9
+ - python=3.10
10
+
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bedtools/requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ fastmcp
2
+ mcp
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bioconductor-apeglm/Dockerfile ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ FROM python:3.10-slim
3
+
4
+ # Install system dependencies
5
+ RUN apt-get update && apt-get install -y default-jre wget curl && apt-get clean && rm -rf /var/lib/apt/lists/*
6
+
7
+ # Install Miniconda
8
+ RUN wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O /tmp/miniconda.sh && bash /tmp/miniconda.sh -b -p /opt/conda && rm /tmp/miniconda.sh
9
+
10
+ # Add conda to PATH
11
+ ENV PATH="/opt/conda/bin:$PATH"
12
+
13
+ # Install bioconductor-apeglm via conda (e.g., from bioconda)
14
+ RUN conda install -c bioconda bioconductor-apeglm -y && conda clean -a
15
+
16
+ # Install Python dependencies
17
+ RUN pip install uv
18
+ RUN uv pip install --system fastmcp
19
+
20
+ # Create app directory
21
+ WORKDIR /app
22
+
23
+ # Copy your MCP server
24
+ COPY bioconductor-apeglm_server.py /app/
25
+
26
+ # Create workspace and output directories
27
+ RUN mkdir -p /app/workspace /app/output
28
+
29
+ # Make sure the server script is executable
30
+ RUN chmod +x /app/bioconductor-apeglm_server.py
31
+
32
+ # Expose port for MCP over HTTP (optional)
33
+ EXPOSE 8000
34
+
35
+ # Health check
36
+ HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 CMD python -c "import sys; sys.exit(0)"
37
+
38
+ # Default command runs the MCP server via stdio
39
+ CMD ["python", "/app/bioconductor-apeglm_server.py"]
40
+
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bioconductor-apeglm/app/bioconductor-apeglm_server.py ADDED
@@ -0,0 +1,125 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import subprocess
2
+ from pathlib import Path
3
+ from typing import List, Optional, Dict, Any
4
+
5
+ @mcp.tool()
6
+ def run_r_script(
7
+ r_script_file: Optional[Path] = None,
8
+ r_expressions: Optional[List[str]] = None,
9
+ script_args: Optional[List[str]] = None,
10
+ verbose: bool = False,
11
+ default_packages: Optional[str] = None,
12
+ save_workspace: bool = False,
13
+ no_environ: bool = False,
14
+ no_site_file: bool = False,
15
+ no_init_file: bool = False,
16
+ restore_workspace: bool = False,
17
+ vanilla: bool = False,
18
+ ) -> Dict[str, Any]:
19
+ """
20
+ Executes an R script file or R expressions using the Rscript command.
21
+
22
+ This tool provides a wrapper for the Rscript command, allowing users to run
23
+ R code with various configuration options. It supports executing a specified
24
+ R script file or a list of R expressions directly. It also allows passing
25
+ arguments to the R script itself and configuring R's startup behavior.
26
+
27
+ Args:
28
+ r_script_file: Path to an R script file to execute. Mutually exclusive with `r_expressions`.
29
+ r_expressions: A list of R expressions (strings) to execute. Mutually exclusive with `r_script_file`.
30
+ script_args: A list of arguments to be passed to the R script or expressions.
31
+ verbose: If True, print information on progress (corresponds to Rscript's --verbose).
32
+ default_packages: A comma-separated list of package names, or 'NULL',
33
+ to set the default packages loaded (corresponds to --default-packages).
34
+ save_workspace: If True, save the workspace at the end of the session (corresponds to R's --save).
35
+ Ignored if `vanilla` is True.
36
+ no_environ: If True, don't read the site and user environment files (corresponds to R's --no-environ).
37
+ Ignored if `vanilla` is True.
38
+ no_site_file: If True, don't read the site-wide Rprofile (corresponds to R's --no-site-file).
39
+ Ignored if `vanilla` is True.
40
+ no_init_file: If True, don't read the user R profile (corresponds to R's --no-init-file).
41
+ Ignored if `vanilla` is True.
42
+ restore_workspace: If True, restore previously saved objects at startup (corresponds to R's --restore).
43
+ Ignored if `vanilla` is True.
44
+ vanilla: If True, combine --no-save, --no-restore, --no-site-file, --no-init-file, and --no-environ.
45
+ This option overrides individual settings for these flags.
46
+
47
+ Returns:
48
+ A dictionary containing the command executed, stdout, stderr, and any output files.
49
+ In case of an error, it includes error details and the return code.
50
+
51
+ Raises:
52
+ ValueError: If neither `r_script_file` nor `r_expressions` is provided, or if both are provided.
53
+ FileNotFoundError: If `r_script_file` is provided but does not exist.
54
+ """
55
+ command: List[str] = ["Rscript"]
56
+ output_files: List[Path] = []
57
+
58
+ # Input validation for script source
59
+ if r_script_file is None and r_expressions is None:
60
+ raise ValueError("Either 'r_script_file' or 'r_expressions' must be provided.")
61
+ if r_script_file is not None and r_expressions is not None:
62
+ raise ValueError("Cannot provide both 'r_script_file' and 'r_expressions'. Choose one.")
63
+
64
+ if r_script_file:
65
+ if not r_script_file.is_file():
66
+ raise FileNotFoundError(f"R script file not found: {r_script_file}")
67
+
68
+ # Add Rscript specific options
69
+ if verbose:
70
+ command.append("--verbose")
71
+ if default_packages is not None:
72
+ command.append(f"--default-packages={default_packages}")
73
+
74
+ # Add R options (passed to R, in addition to --no-echo --no-restore by Rscript)
75
+ if vanilla:
76
+ command.append("--vanilla")
77
+ else:
78
+ # Only add these if --vanilla is not set, as --vanilla implies them
79
+ if save_workspace:
80
+ command.append("--save")
81
+ if no_environ:
82
+ command.append("--no-environ")
83
+ if no_site_file:
84
+ command.append("--no-site-file")
85
+ if no_init_file:
86
+ command.append("--no-init-file")
87
+ if restore_workspace:
88
+ command.append("--restore")
89
+
90
+ # Add the script source (file or expressions)
91
+ if r_script_file:
92
+ command.append(str(r_script_file))
93
+ elif r_expressions:
94
+ for expr in r_expressions:
95
+ command.extend(["-e", expr])
96
+
97
+ # Add arguments to the R script
98
+ if script_args:
99
+ command.extend(script_args)
100
+
101
+ try:
102
+ process = subprocess.run(
103
+ command,
104
+ capture_output=True,
105
+ text=True,
106
+ check=True
107
+ )
108
+ stdout = process.stdout
109
+ stderr = process.stderr
110
+ except subprocess.CalledProcessError as e:
111
+ return {
112
+ "command_executed": " ".join(command),
113
+ "stdout": e.stdout,
114
+ "stderr": e.stderr,
115
+ "error": str(e),
116
+ "returncode": e.returncode,
117
+ "output_files": output_files,
118
+ }
119
+
120
+ return {
121
+ "command_executed": " ".join(command),
122
+ "stdout": stdout,
123
+ "stderr": stderr,
124
+ "output_files": output_files,
125
+ }
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bioconductor-apeglm/app/bioconductor-apeglm_shim_server.py ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ from __future__ import annotations
3
+
4
+ import ast
5
+ from pathlib import Path
6
+
7
+ from mcp.server.fastmcp import FastMCP
8
+
9
+
10
+ SOURCE_SERVER = Path('/225040511/project/BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bioconductor-apeglm/app/bioconductor-apeglm_server.py')
11
+ SERVER_NAME = 'biosci_bioconductor_apeglm'
12
+
13
+
14
+ class _ShimMCP:
15
+ @staticmethod
16
+ def tool():
17
+ def _decorator(fn):
18
+ return fn
19
+ return _decorator
20
+
21
+
22
+ def _load_functions():
23
+ code = SOURCE_SERVER.read_text(encoding="utf-8")
24
+ tree = ast.parse(code, filename=str(SOURCE_SERVER))
25
+ function_names = [n.name for n in tree.body if isinstance(n, ast.FunctionDef) and not n.name.startswith("_")]
26
+ namespace = {
27
+ "__name__": "__mcp_source__",
28
+ "mcp": _ShimMCP(),
29
+ }
30
+ exec(compile(code, str(SOURCE_SERVER), "exec"), namespace, namespace)
31
+ loaded = []
32
+ for name in function_names:
33
+ fn = namespace.get(name)
34
+ if callable(fn):
35
+ loaded.append(fn)
36
+ return loaded
37
+
38
+
39
+ mcp = FastMCP(SERVER_NAME)
40
+ for _fn in _load_functions():
41
+ mcp.tool()(_fn)
42
+
43
+
44
+ if __name__ == "__main__":
45
+ mcp.run(transport="stdio")
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bioconductor-apeglm/docker-compose.yml ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ version: '3.8'
2
+
3
+ services:
4
+ mcp-bioconductor-apeglm:
5
+ build: .
6
+ image: mcp-bioconductor-apeglm:latest
7
+ container_name: mcp-bioconductor-apeglm
8
+ ports:
9
+ - "8000:8000"
10
+ environment:
11
+ - MCP_SERVER_NAME=bioconductor-apeglm
12
+ volumes:
13
+ - ./workspace:/app/workspace
14
+ - ./output:/app/output
15
+ restart: unless-stopped
16
+ healthcheck:
17
+ test: ["CMD", "python", "-c", "import sys; sys.exit(0)"]
18
+ interval: 30s
19
+ timeout: 10s
20
+ retries: 3
21
+ start_period: 5s
22
+
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bioconductor-apeglm/environment.yaml ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ name: mcp-tool
3
+ channels:
4
+ - bioconda
5
+ - conda-forge
6
+ - defaults
7
+ dependencies:
8
+ - bioconductor-apeglm
9
+ - python=3.10
10
+
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bioconductor-apeglm/requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ fastmcp
2
+ mcp
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bioconductor-beachmat/Dockerfile ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ FROM python:3.10-slim
3
+
4
+ # Install system dependencies
5
+ RUN apt-get update && apt-get install -y default-jre wget curl && apt-get clean && rm -rf /var/lib/apt/lists/*
6
+
7
+ # Install Miniconda
8
+ RUN wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O /tmp/miniconda.sh && bash /tmp/miniconda.sh -b -p /opt/conda && rm /tmp/miniconda.sh
9
+
10
+ # Add conda to PATH
11
+ ENV PATH="/opt/conda/bin:$PATH"
12
+
13
+ # Install bioconductor-beachmat via conda (e.g., from bioconda)
14
+ RUN conda install -c bioconda bioconductor-beachmat -y && conda clean -a
15
+
16
+ # Install Python dependencies
17
+ RUN pip install uv
18
+ RUN uv pip install --system fastmcp
19
+
20
+ # Create app directory
21
+ WORKDIR /app
22
+
23
+ # Copy your MCP server
24
+ COPY bioconductor-beachmat_server.py /app/
25
+
26
+ # Create workspace and output directories
27
+ RUN mkdir -p /app/workspace /app/output
28
+
29
+ # Make sure the server script is executable
30
+ RUN chmod +x /app/bioconductor-beachmat_server.py
31
+
32
+ # Expose port for MCP over HTTP (optional)
33
+ EXPOSE 8000
34
+
35
+ # Health check
36
+ HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 CMD python -c "import sys; sys.exit(0)"
37
+
38
+ # Default command runs the MCP server via stdio
39
+ CMD ["python", "/app/bioconductor-beachmat_server.py"]
40
+
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bioconductor-beachmat/app/bioconductor-beachmat_server.py ADDED
@@ -0,0 +1,218 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import subprocess
2
+ from pathlib import Path
3
+ from typing import List, Optional, Dict, Any
4
+
5
+ @mcp.tool()
6
+ def rscript_run_script(
7
+ script_path: str,
8
+ args: List[str] = [],
9
+ vanilla: bool = True,
10
+ save: bool = False,
11
+ restore: bool = False,
12
+ no_environ: bool = False,
13
+ no_site_file: bool = False,
14
+ no_init_file: bool = False,
15
+ verbose: bool = False,
16
+ default_packages: Optional[str] = None,
17
+ ) -> Dict[str, Any]:
18
+ """
19
+ Execute an R script file using Rscript, typically used for Bioconductor/beachmat workflows.
20
+
21
+ Args:
22
+ script_path: Path to the R script file (.R).
23
+ args: Additional command line arguments passed to the script.
24
+ vanilla: Combine --no-save, --no-restore, --no-site-file, --no-init-file and --no-environ.
25
+ save: Do save workspace at the end of the session.
26
+ restore: Do restore previously saved objects at startup.
27
+ no_environ: Don't read the site and user environment files.
28
+ no_site_file: Don't read the site-wide Rprofile.
29
+ no_init_file: Don't read the user R profile.
30
+ verbose: Print information on progress.
31
+ default_packages: Comma-separated set of package names, or 'NULL'.
32
+ """
33
+ script_file = Path(script_path)
34
+ if not script_file.exists():
35
+ return {"error": f"Script file not found: {script_path}"}
36
+
37
+ cmd = ["Rscript"]
38
+
39
+ # Add options
40
+ if vanilla:
41
+ cmd.append("--vanilla")
42
+ if save:
43
+ cmd.append("--save")
44
+ if restore:
45
+ cmd.append("--restore")
46
+ if no_environ:
47
+ cmd.append("--no-environ")
48
+ if no_site_file:
49
+ cmd.append("--no-site-file")
50
+ if no_init_file:
51
+ cmd.append("--no-init-file")
52
+ if verbose:
53
+ cmd.append("--verbose")
54
+ if default_packages:
55
+ cmd.append(f"--default-packages={default_packages}")
56
+
57
+ cmd.append(str(script_file))
58
+
59
+ if args:
60
+ cmd.extend(args)
61
+
62
+ try:
63
+ result = subprocess.run(cmd, capture_output=True, text=True, check=True)
64
+ return {
65
+ "command_executed": " ".join(cmd),
66
+ "stdout": result.stdout,
67
+ "stderr": result.stderr,
68
+ "status": "success"
69
+ }
70
+ except subprocess.CalledProcessError as e:
71
+ return {
72
+ "command_executed": " ".join(cmd),
73
+ "stdout": e.stdout,
74
+ "stderr": e.stderr,
75
+ "error": str(e),
76
+ "status": "error"
77
+ }
78
+
79
+ @mcp.tool()
80
+ def rscript_run_expression(
81
+ expressions: List[str],
82
+ vanilla: bool = True,
83
+ save: bool = False,
84
+ restore: bool = False,
85
+ no_environ: bool = False,
86
+ no_site_file: bool = False,
87
+ no_init_file: bool = False,
88
+ verbose: bool = False,
89
+ default_packages: Optional[str] = None,
90
+ ) -> Dict[str, Any]:
91
+ """
92
+ Execute one or more R expressions directly from the command line.
93
+ Useful for quick beachmat matrix manipulations or checks.
94
+
95
+ Args:
96
+ expressions: A list of R code strings to execute (each corresponds to a -e flag).
97
+ vanilla: Combine --no-save, --no-restore, --no-site-file, --no-init-file and --no-environ.
98
+ save: Do save workspace at the end of the session.
99
+ restore: Do restore previously saved objects at startup.
100
+ no_environ: Don't read the site and user environment files.
101
+ no_site_file: Don't read the site-wide Rprofile.
102
+ no_init_file: Don't read the user R profile.
103
+ verbose: Print information on progress.
104
+ default_packages: Comma-separated set of package names, or 'NULL'.
105
+ """
106
+ if not expressions:
107
+ return {"error": "No expressions provided."}
108
+
109
+ cmd = ["Rscript"]
110
+
111
+ # Add options
112
+ if vanilla:
113
+ cmd.append("--vanilla")
114
+ if save:
115
+ cmd.append("--save")
116
+ if restore:
117
+ cmd.append("--restore")
118
+ if no_environ:
119
+ cmd.append("--no-environ")
120
+ if no_site_file:
121
+ cmd.append("--no-site-file")
122
+ if no_init_file:
123
+ cmd.append("--no-init-file")
124
+ if verbose:
125
+ cmd.append("--verbose")
126
+ if default_packages:
127
+ cmd.append(f"--default-packages={default_packages}")
128
+
129
+ for expr in expressions:
130
+ cmd.extend(["-e", expr])
131
+
132
+ try:
133
+ result = subprocess.run(cmd, capture_output=True, text=True, check=True)
134
+ return {
135
+ "command_executed": " ".join(cmd),
136
+ "stdout": result.stdout,
137
+ "stderr": result.stderr,
138
+ "status": "success"
139
+ }
140
+ except subprocess.CalledProcessError as e:
141
+ return {
142
+ "command_executed": " ".join(cmd),
143
+ "stdout": e.stdout,
144
+ "stderr": e.stderr,
145
+ "error": str(e),
146
+ "status": "error"
147
+ }
148
+
149
+ @mcp.tool()
150
+ def beachmat_inspect_matrix(
151
+ rds_path: str,
152
+ ) -> Dict[str, Any]:
153
+ """
154
+ Specific utility to inspect an R matrix object (RDS file) using the beachmat package logic.
155
+ Identifies matrix class, dimensions, and storage mode.
156
+
157
+ Args:
158
+ rds_path: Path to an RDS file containing a matrix-like object.
159
+ """
160
+ input_path = Path(rds_path)
161
+ if not input_path.exists():
162
+ return {"error": f"RDS file not found: {rds_path}"}
163
+
164
+ # R code to inspect the matrix using beachmat-compatible logic
165
+ r_code = (
166
+ "suppressPackageStartupMessages(library(beachmat)); "
167
+ f"mat <- readRDS('{str(input_path)}'); "
168
+ "cat('--- Matrix Metadata ---\\n'); "
169
+ "cat('Class:', paste(class(mat), collapse=', '), '\\n'); "
170
+ "cat('Dimensions:', paste(dim(mat), collapse=' x '), '\\n'); "
171
+ "if(is(mat, 'dgCMatrix')) { cat('Type: Sparse (dgCMatrix)\\n') } "
172
+ "else if(is(mat, 'HDF5Matrix')) { cat('Type: HDF5-backed\\n') } "
173
+ "else { cat('Type: Dense/Other\\n') }; "
174
+ "cat('Storage Mode:', storage.mode(mat), '\\n')"
175
+ )
176
+
177
+ cmd = ["Rscript", "--vanilla", "-e", r_code]
178
+
179
+ try:
180
+ result = subprocess.run(cmd, capture_output=True, text=True, check=True)
181
+ return {
182
+ "command_executed": " ".join(cmd),
183
+ "stdout": result.stdout,
184
+ "stderr": result.stderr,
185
+ "status": "success"
186
+ }
187
+ except subprocess.CalledProcessError as e:
188
+ return {
189
+ "command_executed": " ".join(cmd),
190
+ "stdout": e.stdout,
191
+ "stderr": e.stderr,
192
+ "error": "Ensure 'beachmat' and 'DelayedArray' are installed in the R environment.",
193
+ "status": "error"
194
+ }
195
+
196
+ @mcp.tool()
197
+ def rscript_get_version() -> Dict[str, Any]:
198
+ """
199
+ Get the version information for Rscript and the R environment.
200
+ """
201
+ cmd = ["Rscript", "--version"]
202
+ try:
203
+ # Rscript --version often outputs to stderr
204
+ result = subprocess.run(cmd, capture_output=True, text=True, check=True)
205
+ return {
206
+ "command_executed": " ".join(cmd),
207
+ "stdout": result.stdout,
208
+ "stderr": result.stderr,
209
+ "status": "success"
210
+ }
211
+ except subprocess.CalledProcessError as e:
212
+ return {
213
+ "command_executed": " ".join(cmd),
214
+ "stdout": e.stdout,
215
+ "stderr": e.stderr,
216
+ "error": str(e),
217
+ "status": "error"
218
+ }
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bioconductor-beachmat/app/bioconductor-beachmat_shim_server.py ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ from __future__ import annotations
3
+
4
+ import ast
5
+ from pathlib import Path
6
+
7
+ from mcp.server.fastmcp import FastMCP
8
+
9
+
10
+ SOURCE_SERVER = Path('/225040511/project/BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bioconductor-beachmat/app/bioconductor-beachmat_server.py')
11
+ SERVER_NAME = 'biosci_bioconductor_beachmat'
12
+
13
+
14
+ class _ShimMCP:
15
+ @staticmethod
16
+ def tool():
17
+ def _decorator(fn):
18
+ return fn
19
+ return _decorator
20
+
21
+
22
+ def _load_functions():
23
+ code = SOURCE_SERVER.read_text(encoding="utf-8")
24
+ tree = ast.parse(code, filename=str(SOURCE_SERVER))
25
+ function_names = [n.name for n in tree.body if isinstance(n, ast.FunctionDef) and not n.name.startswith("_")]
26
+ namespace = {
27
+ "__name__": "__mcp_source__",
28
+ "mcp": _ShimMCP(),
29
+ }
30
+ exec(compile(code, str(SOURCE_SERVER), "exec"), namespace, namespace)
31
+ loaded = []
32
+ for name in function_names:
33
+ fn = namespace.get(name)
34
+ if callable(fn):
35
+ loaded.append(fn)
36
+ return loaded
37
+
38
+
39
+ mcp = FastMCP(SERVER_NAME)
40
+ for _fn in _load_functions():
41
+ mcp.tool()(_fn)
42
+
43
+
44
+ if __name__ == "__main__":
45
+ mcp.run(transport="stdio")
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bioconductor-beachmat/docker-compose.yml ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ version: '3.8'
2
+
3
+ services:
4
+ mcp-bioconductor-beachmat:
5
+ build: .
6
+ image: mcp-bioconductor-beachmat:latest
7
+ container_name: mcp-bioconductor-beachmat
8
+ ports:
9
+ - "8000:8000"
10
+ environment:
11
+ - MCP_SERVER_NAME=bioconductor-beachmat
12
+ volumes:
13
+ - ./workspace:/app/workspace
14
+ - ./output:/app/output
15
+ restart: unless-stopped
16
+ healthcheck:
17
+ test: ["CMD", "python", "-c", "import sys; sys.exit(0)"]
18
+ interval: 30s
19
+ timeout: 10s
20
+ retries: 3
21
+ start_period: 5s
22
+
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bioconductor-beachmat/environment.yaml ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ name: mcp-tool
3
+ channels:
4
+ - bioconda
5
+ - conda-forge
6
+ - defaults
7
+ dependencies:
8
+ - bioconductor-beachmat
9
+ - python=3.10
10
+
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bioconductor-beachmat/requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ fastmcp
2
+ mcp
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bioconductor-biobase/Dockerfile ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ FROM python:3.10-slim
3
+
4
+ # Install system dependencies
5
+ RUN apt-get update && apt-get install -y default-jre wget curl && apt-get clean && rm -rf /var/lib/apt/lists/*
6
+
7
+ # Install Miniconda
8
+ RUN wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O /tmp/miniconda.sh && bash /tmp/miniconda.sh -b -p /opt/conda && rm /tmp/miniconda.sh
9
+
10
+ # Add conda to PATH
11
+ ENV PATH="/opt/conda/bin:$PATH"
12
+
13
+ # Install bioconductor-biobase via conda (e.g., from bioconda)
14
+ RUN conda install -c bioconda bioconductor-biobase -y && conda clean -a
15
+
16
+ # Install Python dependencies
17
+ RUN pip install uv
18
+ RUN uv pip install --system fastmcp
19
+
20
+ # Create app directory
21
+ WORKDIR /app
22
+
23
+ # Copy your MCP server
24
+ COPY bioconductor-biobase_server.py /app/
25
+
26
+ # Create workspace and output directories
27
+ RUN mkdir -p /app/workspace /app/output
28
+
29
+ # Make sure the server script is executable
30
+ RUN chmod +x /app/bioconductor-biobase_server.py
31
+
32
+ # Expose port for MCP over HTTP (optional)
33
+ EXPOSE 8000
34
+
35
+ # Health check
36
+ HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 CMD python -c "import sys; sys.exit(0)"
37
+
38
+ # Default command runs the MCP server via stdio
39
+ CMD ["python", "/app/bioconductor-biobase_server.py"]
40
+
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bioconductor-biobase/app/bioconductor-biobase_server.py ADDED
@@ -0,0 +1,159 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import subprocess
2
+ import logging
3
+ from pathlib import Path
4
+ from typing import List, Optional
5
+
6
+ # Configure logging
7
+ logging.basicConfig(level=logging.INFO)
8
+ logger = logging.getLogger(__name__)
9
+
10
+ # MCP decorator is assumed to be available in the execution environment.
11
+ # No need to define or import it.
12
+
13
+ @mcp.tool
14
+ def rscript_run(
15
+ script_file: Optional[Path] = None,
16
+ expressions: Optional[List[str]] = None,
17
+ script_args: Optional[List[str]] = None,
18
+ verbose: bool = False,
19
+ default_packages: Optional[str] = None,
20
+ save: bool = False,
21
+ no_environ: bool = False,
22
+ no_site_file: bool = False,
23
+ no_init_file: bool = False,
24
+ restore: bool = False,
25
+ vanilla: bool = False,
26
+ ) -> dict:
27
+ """
28
+ Executes an R script or R expressions using the Rscript command-line tool.
29
+
30
+ This tool is a wrapper for Rscript, allowing the execution of R code from a
31
+ file or directly as string expressions. It is commonly used for running
32
+ bioinformatics scripts that rely on R and Bioconductor packages.
33
+
34
+ Args:
35
+ script_file: Path to the R script file to be executed.
36
+ expressions: A list of R expressions to execute. Use this or script_file, not both.
37
+ script_args: A list of arguments to be passed to the R script itself.
38
+ verbose: If True, enables verbose output, printing progress information.
39
+ default_packages: A comma-separated string of package names to be loaded by default.
40
+ save: If True, the R workspace is saved at the end of the session (--save).
41
+ no_environ: If True, site and user environment files are not read (--no-environ).
42
+ no_site_file: If True, the site-wide Rprofile is not read (--no-site-file).
43
+ no_init_file: If True, the user's R profile is not read (--no-init-file).
44
+ restore: If True, previously saved objects are restored at startup (--restore).
45
+ vanilla: If True, combines --no-save, --no-restore, --no-site-file,
46
+ --no-init-file, and --no-environ. Overrides the individual flags.
47
+
48
+ Returns:
49
+ A dictionary containing the executed command, stdout, stderr, and a list of output files.
50
+ """
51
+ # 1. Input Validation
52
+ if (script_file is None and not expressions) or (script_file is not None and expressions):
53
+ raise ValueError("You must provide either 'script_file' or 'expressions', but not both.")
54
+
55
+ if script_file and not script_file.is_file():
56
+ raise FileNotFoundError(f"The specified script file does not exist: {script_file}")
57
+
58
+ # 2. Command Construction
59
+ cmd = ["Rscript"]
60
+
61
+ if vanilla:
62
+ cmd.append("--vanilla")
63
+ else:
64
+ if save:
65
+ cmd.append("--save")
66
+ if no_environ:
67
+ cmd.append("--no-environ")
68
+ if no_site_file:
69
+ cmd.append("--no-site-file")
70
+ if no_init_file:
71
+ cmd.append("--no-init-file")
72
+ if restore:
73
+ cmd.append("--restore")
74
+
75
+ if verbose:
76
+ cmd.append("--verbose")
77
+
78
+ if default_packages:
79
+ cmd.append(f"--default-packages={default_packages}")
80
+
81
+ if expressions:
82
+ for expr in expressions:
83
+ cmd.extend(["-e", expr])
84
+
85
+ if script_file:
86
+ cmd.append(str(script_file))
87
+
88
+ if script_args:
89
+ cmd.extend(script_args)
90
+
91
+ command_executed = " ".join(cmd)
92
+ logger.info(f"Executing command: {command_executed}")
93
+
94
+ # 3. Subprocess Execution
95
+ try:
96
+ result = subprocess.run(
97
+ cmd,
98
+ capture_output=True,
99
+ text=True,
100
+ check=True,
101
+ )
102
+ return {
103
+ "command_executed": command_executed,
104
+ "stdout": result.stdout,
105
+ "stderr": result.stderr,
106
+ "output_files": []
107
+ }
108
+ except FileNotFoundError:
109
+ logger.error("Rscript not found. Please ensure R is installed and in your PATH.")
110
+ raise
111
+ except subprocess.CalledProcessError as e:
112
+ logger.error(f"Rscript execution failed with return code {e.returncode}")
113
+ return {
114
+ "command_executed": command_executed,
115
+ "stdout": e.stdout,
116
+ "stderr": e.stderr,
117
+ "error": "Rscript execution failed.",
118
+ "return_code": e.returncode,
119
+ "output_files": []
120
+ }
121
+
122
+ @mcp.tool
123
+ def rscript_version() -> dict:
124
+ """
125
+ Retrieves the version of the Rscript interpreter.
126
+
127
+ Returns:
128
+ A dictionary containing the executed command and the version information.
129
+ """
130
+ cmd = ["Rscript", "--version"]
131
+ command_executed = " ".join(cmd)
132
+ logger.info(f"Executing command: {command_executed}")
133
+
134
+ try:
135
+ # Rscript --version prints to stderr and exits with code 0.
136
+ result = subprocess.run(
137
+ cmd,
138
+ capture_output=True,
139
+ text=True,
140
+ check=True,
141
+ )
142
+ return {
143
+ "command_executed": command_executed,
144
+ "stdout": result.stdout,
145
+ "stderr": result.stderr,
146
+ }
147
+ except FileNotFoundError:
148
+ logger.error("Rscript not found. Please ensure R is installed and in your PATH.")
149
+ raise
150
+ except subprocess.CalledProcessError as e:
151
+ # This case is unlikely for Rscript --version but is good practice.
152
+ logger.error(f"Failed to get Rscript version. Return code: {e.returncode}")
153
+ return {
154
+ "command_executed": command_executed,
155
+ "stdout": e.stdout,
156
+ "stderr": e.stderr,
157
+ "error": "Failed to retrieve Rscript version.",
158
+ "return_code": e.returncode,
159
+ }
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bioconductor-biobase/app/bioconductor-biobase_shim_server.py ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ from __future__ import annotations
3
+
4
+ import ast
5
+ from pathlib import Path
6
+
7
+ from mcp.server.fastmcp import FastMCP
8
+
9
+
10
+ SOURCE_SERVER = Path('/225040511/project/BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bioconductor-biobase/app/bioconductor-biobase_server.py')
11
+ SERVER_NAME = 'biosci_bioconductor_biobase'
12
+
13
+
14
+ class _ShimMCP:
15
+ @staticmethod
16
+ def tool():
17
+ def _decorator(fn):
18
+ return fn
19
+ return _decorator
20
+
21
+
22
+ def _load_functions():
23
+ code = SOURCE_SERVER.read_text(encoding="utf-8")
24
+ tree = ast.parse(code, filename=str(SOURCE_SERVER))
25
+ function_names = [n.name for n in tree.body if isinstance(n, ast.FunctionDef) and not n.name.startswith("_")]
26
+ namespace = {
27
+ "__name__": "__mcp_source__",
28
+ "mcp": _ShimMCP(),
29
+ }
30
+ exec(compile(code, str(SOURCE_SERVER), "exec"), namespace, namespace)
31
+ loaded = []
32
+ for name in function_names:
33
+ fn = namespace.get(name)
34
+ if callable(fn):
35
+ loaded.append(fn)
36
+ return loaded
37
+
38
+
39
+ mcp = FastMCP(SERVER_NAME)
40
+ for _fn in _load_functions():
41
+ mcp.tool()(_fn)
42
+
43
+
44
+ if __name__ == "__main__":
45
+ mcp.run(transport="stdio")
BioScientist/agent_system/toolbase/mcp_batch_from_help_txt/mcp_bioconductor-biobase/docker-compose.yml ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ version: '3.8'
2
+
3
+ services:
4
+ mcp-bioconductor-biobase:
5
+ build: .
6
+ image: mcp-bioconductor-biobase:latest
7
+ container_name: mcp-bioconductor-biobase
8
+ ports:
9
+ - "8000:8000"
10
+ environment:
11
+ - MCP_SERVER_NAME=bioconductor-biobase
12
+ volumes:
13
+ - ./workspace:/app/workspace
14
+ - ./output:/app/output
15
+ restart: unless-stopped
16
+ healthcheck:
17
+ test: ["CMD", "python", "-c", "import sys; sys.exit(0)"]
18
+ interval: 30s
19
+ timeout: 10s
20
+ retries: 3
21
+ start_period: 5s
22
+