scitex 2.11.0__py3-none-any.whl → 2.13.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- scitex/__main__.py +24 -5
- scitex/__version__.py +1 -1
- scitex/_optional_deps.py +33 -0
- scitex/ai/classification/reporters/_ClassificationReporter.py +1 -1
- scitex/ai/classification/timeseries/_TimeSeriesBlockingSplit.py +2 -2
- scitex/ai/classification/timeseries/_TimeSeriesCalendarSplit.py +2 -2
- scitex/ai/classification/timeseries/_TimeSeriesSlidingWindowSplit.py +2 -2
- scitex/ai/classification/timeseries/_TimeSeriesSlidingWindowSplit_v01-not-using-n_splits.py +2 -2
- scitex/ai/classification/timeseries/_TimeSeriesStratifiedSplit.py +2 -2
- scitex/ai/classification/timeseries/_normalize_timestamp.py +1 -1
- scitex/ai/metrics/_calc_seizure_prediction_metrics.py +1 -1
- scitex/ai/plt/_plot_feature_importance.py +1 -1
- scitex/ai/plt/_plot_learning_curve.py +1 -1
- scitex/ai/plt/_plot_optuna_study.py +1 -1
- scitex/ai/plt/_plot_pre_rec_curve.py +1 -1
- scitex/ai/plt/_plot_roc_curve.py +1 -1
- scitex/ai/plt/_stx_conf_mat.py +1 -1
- scitex/ai/training/_LearningCurveLogger.py +1 -1
- scitex/audio/mcp_server.py +38 -8
- scitex/browser/automation/CookieHandler.py +1 -1
- scitex/browser/core/BrowserMixin.py +1 -1
- scitex/browser/core/ChromeProfileManager.py +1 -1
- scitex/browser/debugging/_browser_logger.py +1 -1
- scitex/browser/debugging/_highlight_element.py +1 -1
- scitex/browser/debugging/_show_grid.py +1 -1
- scitex/browser/interaction/click_center.py +1 -1
- scitex/browser/interaction/click_with_fallbacks.py +1 -1
- scitex/browser/interaction/close_popups.py +1 -1
- scitex/browser/interaction/fill_with_fallbacks.py +1 -1
- scitex/browser/pdf/click_download_for_chrome_pdf_viewer.py +1 -1
- scitex/browser/pdf/detect_chrome_pdf_viewer.py +1 -1
- scitex/browser/stealth/HumanBehavior.py +1 -1
- scitex/browser/stealth/StealthManager.py +1 -1
- scitex/canvas/_mcp_handlers.py +372 -0
- scitex/canvas/_mcp_tool_schemas.py +219 -0
- scitex/canvas/mcp_server.py +151 -0
- scitex/capture/mcp_server.py +41 -12
- scitex/cli/audio.py +233 -0
- scitex/cli/capture.py +307 -0
- scitex/cli/main.py +27 -4
- scitex/cli/repro.py +233 -0
- scitex/cli/resource.py +240 -0
- scitex/cli/stats.py +325 -0
- scitex/cli/template.py +236 -0
- scitex/cli/tex.py +286 -0
- scitex/cli/web.py +11 -12
- scitex/dev/__init__.py +3 -0
- scitex/dev/_pyproject.py +405 -0
- scitex/dev/plt/__init__.py +2 -2
- scitex/dev/plt/mpl/get_dir_ax.py +1 -1
- scitex/dev/plt/mpl/get_signatures.py +1 -1
- scitex/dev/plt/mpl/get_signatures_details.py +1 -1
- scitex/diagram/_mcp_handlers.py +400 -0
- scitex/diagram/_mcp_tool_schemas.py +157 -0
- scitex/diagram/mcp_server.py +151 -0
- scitex/dsp/_demo_sig.py +51 -5
- scitex/dsp/_mne.py +13 -2
- scitex/dsp/_modulation_index.py +15 -3
- scitex/dsp/_pac.py +23 -5
- scitex/dsp/_psd.py +16 -4
- scitex/dsp/_resample.py +24 -4
- scitex/dsp/_transform.py +16 -3
- scitex/dsp/add_noise.py +15 -1
- scitex/dsp/norm.py +17 -2
- scitex/dsp/reference.py +17 -1
- scitex/dsp/utils/_differential_bandpass_filters.py +20 -2
- scitex/dsp/utils/_zero_pad.py +18 -4
- scitex/dt/_normalize_timestamp.py +1 -1
- scitex/git/_session.py +1 -1
- scitex/io/_load_modules/_con.py +12 -1
- scitex/io/_load_modules/_eeg.py +12 -1
- scitex/io/_load_modules/_optuna.py +21 -63
- scitex/io/_load_modules/_torch.py +11 -3
- scitex/io/_save_modules/_optuna_study_as_csv_and_pngs.py +13 -2
- scitex/io/_save_modules/_torch.py +11 -3
- scitex/mcp_server.py +159 -0
- scitex/plt/_mcp_handlers.py +361 -0
- scitex/plt/_mcp_tool_schemas.py +169 -0
- scitex/plt/mcp_server.py +205 -0
- scitex/repro/README_RandomStateManager.md +3 -3
- scitex/repro/_RandomStateManager.py +14 -14
- scitex/repro/_gen_ID.py +1 -1
- scitex/repro/_gen_timestamp.py +1 -1
- scitex/repro/_hash_array.py +4 -4
- scitex/scholar/__main__.py +24 -2
- scitex/scholar/_mcp_handlers.py +685 -0
- scitex/scholar/_mcp_tool_schemas.py +339 -0
- scitex/scholar/docs/template.py +1 -1
- scitex/scholar/examples/07_storage_integration.py +1 -1
- scitex/scholar/impact_factor/jcr/ImpactFactorJCREngine.py +1 -1
- scitex/scholar/impact_factor/jcr/build_database.py +1 -1
- scitex/scholar/mcp_server.py +315 -0
- scitex/scholar/pdf_download/ScholarPDFDownloader.py +1 -1
- scitex/scholar/pipelines/ScholarPipelineBibTeX.py +1 -1
- scitex/scholar/pipelines/ScholarPipelineParallel.py +1 -1
- scitex/scholar/pipelines/ScholarPipelineSingle.py +1 -1
- scitex/scholar/storage/PaperIO.py +1 -1
- scitex/session/README.md +4 -4
- scitex/session/__init__.py +1 -1
- scitex/session/_decorator.py +9 -9
- scitex/session/_lifecycle.py +5 -5
- scitex/session/template.py +1 -1
- scitex/stats/__main__.py +281 -0
- scitex/stats/_mcp_handlers.py +1191 -0
- scitex/stats/_mcp_tool_schemas.py +384 -0
- scitex/stats/correct/_correct_bonferroni.py +1 -1
- scitex/stats/correct/_correct_fdr.py +1 -1
- scitex/stats/correct/_correct_fdr_.py +1 -1
- scitex/stats/correct/_correct_holm.py +1 -1
- scitex/stats/correct/_correct_sidak.py +1 -1
- scitex/stats/effect_sizes/_cliffs_delta.py +1 -1
- scitex/stats/effect_sizes/_cohens_d.py +1 -1
- scitex/stats/effect_sizes/_epsilon_squared.py +1 -1
- scitex/stats/effect_sizes/_eta_squared.py +1 -1
- scitex/stats/effect_sizes/_prob_superiority.py +1 -1
- scitex/stats/mcp_server.py +405 -0
- scitex/stats/posthoc/_dunnett.py +1 -1
- scitex/stats/posthoc/_games_howell.py +1 -1
- scitex/stats/posthoc/_tukey_hsd.py +1 -1
- scitex/stats/power/_power.py +1 -1
- scitex/stats/utils/_effect_size.py +1 -1
- scitex/stats/utils/_formatters.py +1 -1
- scitex/stats/utils/_power.py +1 -1
- scitex/template/_mcp_handlers.py +259 -0
- scitex/template/_mcp_tool_schemas.py +112 -0
- scitex/template/mcp_server.py +186 -0
- scitex/utils/_verify_scitex_format.py +2 -2
- scitex/utils/template.py +1 -1
- scitex/web/__init__.py +12 -11
- scitex/web/_scraping.py +26 -265
- scitex/web/download_images.py +316 -0
- scitex/writer/Writer.py +1 -1
- scitex/writer/_clone_writer_project.py +1 -1
- scitex/writer/_validate_tree_structures.py +1 -1
- scitex/writer/dataclasses/config/_WriterConfig.py +1 -1
- scitex/writer/dataclasses/contents/_ManuscriptContents.py +1 -1
- scitex/writer/dataclasses/core/_Document.py +1 -1
- scitex/writer/dataclasses/core/_DocumentSection.py +1 -1
- scitex/writer/dataclasses/results/_CompilationResult.py +1 -1
- scitex/writer/dataclasses/results/_LaTeXIssue.py +1 -1
- scitex/writer/utils/.legacy_git_retry.py +7 -5
- scitex/writer/utils/_parse_latex_logs.py +1 -1
- {scitex-2.11.0.dist-info → scitex-2.13.0.dist-info}/METADATA +431 -269
- {scitex-2.11.0.dist-info → scitex-2.13.0.dist-info}/RECORD +147 -118
- scitex-2.13.0.dist-info/entry_points.txt +11 -0
- scitex-2.11.0.dist-info/entry_points.txt +0 -2
- {scitex-2.11.0.dist-info → scitex-2.13.0.dist-info}/WHEEL +0 -0
- {scitex-2.11.0.dist-info → scitex-2.13.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
2
|
# Time-stamp: "2024-11-14 07:55:45 (ywatanabe)"
|
|
4
3
|
# File: ./scitex_repo/src/scitex/io/_load_modules/_optuna.py
|
|
5
4
|
|
|
6
5
|
from ._yaml import _load_yaml
|
|
7
6
|
|
|
7
|
+
try:
|
|
8
|
+
import optuna
|
|
9
|
+
|
|
10
|
+
OPTUNA_AVAILABLE = True
|
|
11
|
+
except ImportError:
|
|
12
|
+
OPTUNA_AVAILABLE = False
|
|
13
|
+
optuna = None
|
|
14
|
+
|
|
8
15
|
|
|
9
16
|
def load_yaml_as_an_optuna_dict(fpath_yaml, trial):
|
|
10
17
|
"""
|
|
@@ -31,7 +38,14 @@ def load_yaml_as_an_optuna_dict(fpath_yaml, trial):
|
|
|
31
38
|
If the specified YAML file does not exist.
|
|
32
39
|
ValueError
|
|
33
40
|
If the YAML file contains invalid configuration for Optuna.
|
|
41
|
+
ImportError
|
|
42
|
+
If Optuna is not installed.
|
|
34
43
|
"""
|
|
44
|
+
if not OPTUNA_AVAILABLE:
|
|
45
|
+
raise ImportError(
|
|
46
|
+
"Optuna is not installed. Please install with: pip install optuna"
|
|
47
|
+
)
|
|
48
|
+
|
|
35
49
|
_d = _load_yaml(fpath_yaml)
|
|
36
50
|
|
|
37
51
|
for k, v in _d.items():
|
|
@@ -74,6 +88,8 @@ def load_study_rdb(study_name, rdb_raw_bytes_url):
|
|
|
74
88
|
-------
|
|
75
89
|
optuna.exceptions.StorageInvalidUsageError
|
|
76
90
|
If there's an error loading the study from the storage.
|
|
91
|
+
ImportError
|
|
92
|
+
If Optuna is not installed.
|
|
77
93
|
|
|
78
94
|
Example:
|
|
79
95
|
--------
|
|
@@ -82,7 +98,10 @@ def load_study_rdb(study_name, rdb_raw_bytes_url):
|
|
|
82
98
|
... rdb_raw_bytes_url="sqlite:///path/to/your/study.db"
|
|
83
99
|
... )
|
|
84
100
|
"""
|
|
85
|
-
|
|
101
|
+
if not OPTUNA_AVAILABLE:
|
|
102
|
+
raise ImportError(
|
|
103
|
+
"Optuna is not installed. Please install with: pip install optuna"
|
|
104
|
+
)
|
|
86
105
|
|
|
87
106
|
storage = optuna.storages.RDBStorage(url=rdb_raw_bytes_url)
|
|
88
107
|
study = optuna.load_study(study_name=study_name, storage=storage)
|
|
@@ -90,65 +109,4 @@ def load_study_rdb(study_name, rdb_raw_bytes_url):
|
|
|
90
109
|
return study
|
|
91
110
|
|
|
92
111
|
|
|
93
|
-
def load_yaml_as_an_optuna_dict(fpath_yaml, trial):
|
|
94
|
-
"""
|
|
95
|
-
Load a YAML file and convert it to an Optuna-compatible dictionary.
|
|
96
|
-
|
|
97
|
-
Parameters:
|
|
98
|
-
-----------
|
|
99
|
-
fpath_yaml : str
|
|
100
|
-
The path to the YAML file.
|
|
101
|
-
trial : optuna.trial.Trial
|
|
102
|
-
The Optuna trial object.
|
|
103
|
-
|
|
104
|
-
Returns:
|
|
105
|
-
--------
|
|
106
|
-
dict
|
|
107
|
-
A dictionary with Optuna-compatible parameter suggestions.
|
|
108
|
-
"""
|
|
109
|
-
_d = _load_yaml(fpath_yaml)
|
|
110
|
-
|
|
111
|
-
for k, v in _d.items():
|
|
112
|
-
dist = v["distribution"]
|
|
113
|
-
|
|
114
|
-
if dist == "categorical":
|
|
115
|
-
_d[k] = trial.suggest_categorical(k, v["values"])
|
|
116
|
-
|
|
117
|
-
elif dist == "uniform":
|
|
118
|
-
_d[k] = trial.suggest_int(k, float(v["min"]), float(v["max"]))
|
|
119
|
-
|
|
120
|
-
elif dist == "loguniform":
|
|
121
|
-
_d[k] = trial.suggest_loguniform(k, float(v["min"]), float(v["max"]))
|
|
122
|
-
|
|
123
|
-
elif dist == "intloguniform":
|
|
124
|
-
_d[k] = trial.suggest_int(k, float(v["min"]), float(v["max"]), log=True)
|
|
125
|
-
|
|
126
|
-
return _d
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
def load_study_rdb(study_name, rdb_raw_bytes_url):
|
|
130
|
-
"""
|
|
131
|
-
Load an Optuna study from a RDB storage.
|
|
132
|
-
|
|
133
|
-
Parameters:
|
|
134
|
-
-----------
|
|
135
|
-
study_name : str
|
|
136
|
-
The name of the Optuna study.
|
|
137
|
-
rdb_raw_bytes_url : str
|
|
138
|
-
The URL of the RDB storage.
|
|
139
|
-
|
|
140
|
-
Returns:
|
|
141
|
-
--------
|
|
142
|
-
optuna.study.Study
|
|
143
|
-
The loaded Optuna study object.
|
|
144
|
-
"""
|
|
145
|
-
import optuna
|
|
146
|
-
|
|
147
|
-
# rdb_raw_bytes_url = "sqlite:////tmp/fake/ywatanabe/_MicroNN_WindowSize-1.0-sec_MaxEpochs_100_2021-1216-1844/optuna_study_test_file#0.db"
|
|
148
|
-
storage = optuna.storages.RDBStorage(url=rdb_raw_bytes_url)
|
|
149
|
-
study = optuna.load_study(study_name=study_name, storage=storage)
|
|
150
|
-
print(f"\nLoaded: {rdb_raw_bytes_url}\n")
|
|
151
|
-
return study
|
|
152
|
-
|
|
153
|
-
|
|
154
112
|
# EOF
|
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
2
|
# Time-stamp: "2024-11-14 07:41:34 (ywatanabe)"
|
|
4
3
|
# File: ./scitex_repo/src/scitex/io/_load_modules/_torch.py
|
|
5
4
|
|
|
5
|
+
try:
|
|
6
|
+
import torch
|
|
7
|
+
|
|
8
|
+
TORCH_AVAILABLE = True
|
|
9
|
+
except ImportError:
|
|
10
|
+
TORCH_AVAILABLE = False
|
|
11
|
+
|
|
6
12
|
|
|
7
13
|
def _load_torch(lpath, **kwargs):
|
|
8
14
|
"""Load PyTorch model/checkpoint file."""
|
|
9
|
-
|
|
10
|
-
|
|
15
|
+
if not TORCH_AVAILABLE:
|
|
16
|
+
raise ImportError(
|
|
17
|
+
"PyTorch is not installed. Please install with: pip install torch"
|
|
18
|
+
)
|
|
11
19
|
|
|
12
20
|
if not lpath.endswith((".pth", ".pt")):
|
|
13
21
|
raise ValueError("File must have .pth or .pt extension")
|
|
@@ -1,11 +1,22 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
2
|
# Time-stamp: "2024-11-02 17:01:15 (ywatanabe)"
|
|
4
3
|
# File: ./scitex_repo/src/scitex/io/_save_optuna_study_as_csv_and_pngs.py
|
|
5
4
|
|
|
5
|
+
try:
|
|
6
|
+
import optuna
|
|
7
|
+
|
|
8
|
+
OPTUNA_AVAILABLE = True
|
|
9
|
+
except ImportError:
|
|
10
|
+
OPTUNA_AVAILABLE = False
|
|
11
|
+
optuna = None
|
|
12
|
+
|
|
6
13
|
|
|
7
14
|
def save_optuna_study_as_csv_and_pngs(study, sdir):
|
|
8
|
-
|
|
15
|
+
if not OPTUNA_AVAILABLE:
|
|
16
|
+
raise ImportError(
|
|
17
|
+
"Optuna is not installed. Please install with: pip install optuna"
|
|
18
|
+
)
|
|
19
|
+
|
|
9
20
|
from .._save import save
|
|
10
21
|
|
|
11
22
|
## Trials DataFrame
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
2
|
# Timestamp: "2025-05-16 12:25:14 (ywatanabe)"
|
|
4
3
|
# File: /data/gpfs/projects/punim2354/ywatanabe/scitex_repo/src/scitex/io/_save_modules/_torch.py
|
|
5
4
|
|
|
5
|
+
try:
|
|
6
|
+
import torch
|
|
7
|
+
|
|
8
|
+
TORCH_AVAILABLE = True
|
|
9
|
+
except ImportError:
|
|
10
|
+
TORCH_AVAILABLE = False
|
|
11
|
+
|
|
6
12
|
|
|
7
13
|
def _save_torch(obj, spath, **kwargs):
|
|
8
14
|
"""
|
|
@@ -21,7 +27,9 @@ def _save_torch(obj, spath, **kwargs):
|
|
|
21
27
|
-------
|
|
22
28
|
None
|
|
23
29
|
"""
|
|
24
|
-
|
|
25
|
-
|
|
30
|
+
if not TORCH_AVAILABLE:
|
|
31
|
+
raise ImportError(
|
|
32
|
+
"PyTorch is not installed. Please install with: pip install torch"
|
|
33
|
+
)
|
|
26
34
|
|
|
27
35
|
torch.save(obj, spath, **kwargs)
|
scitex/mcp_server.py
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# Timestamp: 2026-01-08
|
|
3
|
+
# File: src/scitex/mcp_server.py
|
|
4
|
+
# ----------------------------------------
|
|
5
|
+
|
|
6
|
+
"""
|
|
7
|
+
Unified MCP Server for SciTeX - All modules in one server.
|
|
8
|
+
|
|
9
|
+
Aggregates tools from all SciTeX MCP modules with prefixed names:
|
|
10
|
+
- audio_*: Text-to-speech
|
|
11
|
+
- capture_*: Screenshot capture
|
|
12
|
+
- scholar_*: Literature management
|
|
13
|
+
- stats_*: Statistical analysis
|
|
14
|
+
- template_*: Project scaffolding
|
|
15
|
+
- plt_*: Publication plotting
|
|
16
|
+
- canvas_*: Multi-panel figures
|
|
17
|
+
- diagram_*: Diagram generation
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
import asyncio
|
|
23
|
+
import json
|
|
24
|
+
from typing import Callable
|
|
25
|
+
|
|
26
|
+
import mcp.types as types
|
|
27
|
+
from mcp.server import NotificationOptions, Server
|
|
28
|
+
from mcp.server.models import InitializationOptions
|
|
29
|
+
from mcp.server.stdio import stdio_server
|
|
30
|
+
|
|
31
|
+
__all__ = ["UnifiedServer", "main"]
|
|
32
|
+
|
|
33
|
+
# Module registry: (prefix, schema_getter, handler_module)
|
|
34
|
+
MODULES = [
|
|
35
|
+
("audio", "scitex.audio._mcp_tool_schemas", "scitex.audio._mcp_handlers"),
|
|
36
|
+
("capture", "scitex.capture._mcp_tool_schemas", "scitex.capture._mcp_handlers"),
|
|
37
|
+
("scholar", "scitex.scholar._mcp_tool_schemas", "scitex.scholar._mcp_handlers"),
|
|
38
|
+
("stats", "scitex.stats._mcp_tool_schemas", "scitex.stats._mcp_handlers"),
|
|
39
|
+
("template", "scitex.template._mcp_tool_schemas", "scitex.template._mcp_handlers"),
|
|
40
|
+
("plt", "scitex.plt._mcp_tool_schemas", "scitex.plt._mcp_handlers"),
|
|
41
|
+
("canvas", "scitex.canvas._mcp_tool_schemas", "scitex.canvas._mcp_handlers"),
|
|
42
|
+
("diagram", "scitex.diagram._mcp_tool_schemas", "scitex.diagram._mcp_handlers"),
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class UnifiedServer:
|
|
47
|
+
"""Unified MCP Server aggregating all SciTeX modules."""
|
|
48
|
+
|
|
49
|
+
def __init__(self):
|
|
50
|
+
self.server = Server("scitex-mcp-server")
|
|
51
|
+
self.tools: list[types.Tool] = []
|
|
52
|
+
self.handlers: dict[str, Callable] = {}
|
|
53
|
+
self._load_modules()
|
|
54
|
+
self._setup_handlers()
|
|
55
|
+
|
|
56
|
+
def _load_modules(self):
|
|
57
|
+
"""Load tool schemas and handlers from all modules."""
|
|
58
|
+
import importlib
|
|
59
|
+
|
|
60
|
+
for prefix, schema_module, handler_module in MODULES:
|
|
61
|
+
try:
|
|
62
|
+
# Load tool schemas
|
|
63
|
+
schema_mod = importlib.import_module(schema_module)
|
|
64
|
+
tools = schema_mod.get_tool_schemas()
|
|
65
|
+
|
|
66
|
+
# Load handlers
|
|
67
|
+
handler_mod = importlib.import_module(handler_module)
|
|
68
|
+
|
|
69
|
+
for tool in tools:
|
|
70
|
+
# Create prefixed tool name
|
|
71
|
+
prefixed_name = f"{prefix}_{tool.name}"
|
|
72
|
+
|
|
73
|
+
# Create new tool with prefixed name
|
|
74
|
+
prefixed_tool = types.Tool(
|
|
75
|
+
name=prefixed_name,
|
|
76
|
+
description=f"[{prefix}] {tool.description}",
|
|
77
|
+
inputSchema=tool.inputSchema,
|
|
78
|
+
)
|
|
79
|
+
self.tools.append(prefixed_tool)
|
|
80
|
+
|
|
81
|
+
# Map handler
|
|
82
|
+
handler_name = f"{tool.name}_handler"
|
|
83
|
+
if hasattr(handler_mod, handler_name):
|
|
84
|
+
self.handlers[prefixed_name] = getattr(
|
|
85
|
+
handler_mod, handler_name
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
except ImportError as e:
|
|
89
|
+
# Module not available, skip it
|
|
90
|
+
print(f"Skipping {prefix} module: {e}")
|
|
91
|
+
except Exception as e:
|
|
92
|
+
print(f"Error loading {prefix} module: {e}")
|
|
93
|
+
|
|
94
|
+
def _setup_handlers(self):
|
|
95
|
+
"""Set up MCP server handlers."""
|
|
96
|
+
|
|
97
|
+
@self.server.list_tools()
|
|
98
|
+
async def handle_list_tools():
|
|
99
|
+
return self.tools
|
|
100
|
+
|
|
101
|
+
@self.server.call_tool()
|
|
102
|
+
async def handle_call_tool(name: str, arguments: dict):
|
|
103
|
+
if name not in self.handlers:
|
|
104
|
+
return [
|
|
105
|
+
types.TextContent(
|
|
106
|
+
type="text",
|
|
107
|
+
text=json.dumps(
|
|
108
|
+
{"success": False, "error": f"Unknown tool: {name}"},
|
|
109
|
+
indent=2,
|
|
110
|
+
),
|
|
111
|
+
)
|
|
112
|
+
]
|
|
113
|
+
|
|
114
|
+
return await self._wrap_result(self.handlers[name](**arguments))
|
|
115
|
+
|
|
116
|
+
async def _wrap_result(self, coro):
|
|
117
|
+
"""Wrap handler result as MCP TextContent."""
|
|
118
|
+
try:
|
|
119
|
+
result = await coro
|
|
120
|
+
return [
|
|
121
|
+
types.TextContent(
|
|
122
|
+
type="text",
|
|
123
|
+
text=json.dumps(result, indent=2, default=str),
|
|
124
|
+
)
|
|
125
|
+
]
|
|
126
|
+
except Exception as e:
|
|
127
|
+
return [
|
|
128
|
+
types.TextContent(
|
|
129
|
+
type="text",
|
|
130
|
+
text=json.dumps({"success": False, "error": str(e)}, indent=2),
|
|
131
|
+
)
|
|
132
|
+
]
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
async def main():
|
|
136
|
+
"""Run the unified MCP server."""
|
|
137
|
+
server = UnifiedServer()
|
|
138
|
+
print(f"Loaded {len(server.tools)} tools from {len(MODULES)} modules")
|
|
139
|
+
|
|
140
|
+
async with stdio_server() as (read_stream, write_stream):
|
|
141
|
+
await server.server.run(
|
|
142
|
+
read_stream,
|
|
143
|
+
write_stream,
|
|
144
|
+
InitializationOptions(
|
|
145
|
+
server_name="scitex-mcp-server",
|
|
146
|
+
server_version="0.1.0",
|
|
147
|
+
capabilities=server.server.get_capabilities(
|
|
148
|
+
notification_options=NotificationOptions(),
|
|
149
|
+
experimental_capabilities={},
|
|
150
|
+
),
|
|
151
|
+
),
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
if __name__ == "__main__":
|
|
156
|
+
asyncio.run(main())
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
# EOF
|