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.
Files changed (148) hide show
  1. scitex/__main__.py +24 -5
  2. scitex/__version__.py +1 -1
  3. scitex/_optional_deps.py +33 -0
  4. scitex/ai/classification/reporters/_ClassificationReporter.py +1 -1
  5. scitex/ai/classification/timeseries/_TimeSeriesBlockingSplit.py +2 -2
  6. scitex/ai/classification/timeseries/_TimeSeriesCalendarSplit.py +2 -2
  7. scitex/ai/classification/timeseries/_TimeSeriesSlidingWindowSplit.py +2 -2
  8. scitex/ai/classification/timeseries/_TimeSeriesSlidingWindowSplit_v01-not-using-n_splits.py +2 -2
  9. scitex/ai/classification/timeseries/_TimeSeriesStratifiedSplit.py +2 -2
  10. scitex/ai/classification/timeseries/_normalize_timestamp.py +1 -1
  11. scitex/ai/metrics/_calc_seizure_prediction_metrics.py +1 -1
  12. scitex/ai/plt/_plot_feature_importance.py +1 -1
  13. scitex/ai/plt/_plot_learning_curve.py +1 -1
  14. scitex/ai/plt/_plot_optuna_study.py +1 -1
  15. scitex/ai/plt/_plot_pre_rec_curve.py +1 -1
  16. scitex/ai/plt/_plot_roc_curve.py +1 -1
  17. scitex/ai/plt/_stx_conf_mat.py +1 -1
  18. scitex/ai/training/_LearningCurveLogger.py +1 -1
  19. scitex/audio/mcp_server.py +38 -8
  20. scitex/browser/automation/CookieHandler.py +1 -1
  21. scitex/browser/core/BrowserMixin.py +1 -1
  22. scitex/browser/core/ChromeProfileManager.py +1 -1
  23. scitex/browser/debugging/_browser_logger.py +1 -1
  24. scitex/browser/debugging/_highlight_element.py +1 -1
  25. scitex/browser/debugging/_show_grid.py +1 -1
  26. scitex/browser/interaction/click_center.py +1 -1
  27. scitex/browser/interaction/click_with_fallbacks.py +1 -1
  28. scitex/browser/interaction/close_popups.py +1 -1
  29. scitex/browser/interaction/fill_with_fallbacks.py +1 -1
  30. scitex/browser/pdf/click_download_for_chrome_pdf_viewer.py +1 -1
  31. scitex/browser/pdf/detect_chrome_pdf_viewer.py +1 -1
  32. scitex/browser/stealth/HumanBehavior.py +1 -1
  33. scitex/browser/stealth/StealthManager.py +1 -1
  34. scitex/canvas/_mcp_handlers.py +372 -0
  35. scitex/canvas/_mcp_tool_schemas.py +219 -0
  36. scitex/canvas/mcp_server.py +151 -0
  37. scitex/capture/mcp_server.py +41 -12
  38. scitex/cli/audio.py +233 -0
  39. scitex/cli/capture.py +307 -0
  40. scitex/cli/main.py +27 -4
  41. scitex/cli/repro.py +233 -0
  42. scitex/cli/resource.py +240 -0
  43. scitex/cli/stats.py +325 -0
  44. scitex/cli/template.py +236 -0
  45. scitex/cli/tex.py +286 -0
  46. scitex/cli/web.py +11 -12
  47. scitex/dev/__init__.py +3 -0
  48. scitex/dev/_pyproject.py +405 -0
  49. scitex/dev/plt/__init__.py +2 -2
  50. scitex/dev/plt/mpl/get_dir_ax.py +1 -1
  51. scitex/dev/plt/mpl/get_signatures.py +1 -1
  52. scitex/dev/plt/mpl/get_signatures_details.py +1 -1
  53. scitex/diagram/_mcp_handlers.py +400 -0
  54. scitex/diagram/_mcp_tool_schemas.py +157 -0
  55. scitex/diagram/mcp_server.py +151 -0
  56. scitex/dsp/_demo_sig.py +51 -5
  57. scitex/dsp/_mne.py +13 -2
  58. scitex/dsp/_modulation_index.py +15 -3
  59. scitex/dsp/_pac.py +23 -5
  60. scitex/dsp/_psd.py +16 -4
  61. scitex/dsp/_resample.py +24 -4
  62. scitex/dsp/_transform.py +16 -3
  63. scitex/dsp/add_noise.py +15 -1
  64. scitex/dsp/norm.py +17 -2
  65. scitex/dsp/reference.py +17 -1
  66. scitex/dsp/utils/_differential_bandpass_filters.py +20 -2
  67. scitex/dsp/utils/_zero_pad.py +18 -4
  68. scitex/dt/_normalize_timestamp.py +1 -1
  69. scitex/git/_session.py +1 -1
  70. scitex/io/_load_modules/_con.py +12 -1
  71. scitex/io/_load_modules/_eeg.py +12 -1
  72. scitex/io/_load_modules/_optuna.py +21 -63
  73. scitex/io/_load_modules/_torch.py +11 -3
  74. scitex/io/_save_modules/_optuna_study_as_csv_and_pngs.py +13 -2
  75. scitex/io/_save_modules/_torch.py +11 -3
  76. scitex/mcp_server.py +159 -0
  77. scitex/plt/_mcp_handlers.py +361 -0
  78. scitex/plt/_mcp_tool_schemas.py +169 -0
  79. scitex/plt/mcp_server.py +205 -0
  80. scitex/repro/README_RandomStateManager.md +3 -3
  81. scitex/repro/_RandomStateManager.py +14 -14
  82. scitex/repro/_gen_ID.py +1 -1
  83. scitex/repro/_gen_timestamp.py +1 -1
  84. scitex/repro/_hash_array.py +4 -4
  85. scitex/scholar/__main__.py +24 -2
  86. scitex/scholar/_mcp_handlers.py +685 -0
  87. scitex/scholar/_mcp_tool_schemas.py +339 -0
  88. scitex/scholar/docs/template.py +1 -1
  89. scitex/scholar/examples/07_storage_integration.py +1 -1
  90. scitex/scholar/impact_factor/jcr/ImpactFactorJCREngine.py +1 -1
  91. scitex/scholar/impact_factor/jcr/build_database.py +1 -1
  92. scitex/scholar/mcp_server.py +315 -0
  93. scitex/scholar/pdf_download/ScholarPDFDownloader.py +1 -1
  94. scitex/scholar/pipelines/ScholarPipelineBibTeX.py +1 -1
  95. scitex/scholar/pipelines/ScholarPipelineParallel.py +1 -1
  96. scitex/scholar/pipelines/ScholarPipelineSingle.py +1 -1
  97. scitex/scholar/storage/PaperIO.py +1 -1
  98. scitex/session/README.md +4 -4
  99. scitex/session/__init__.py +1 -1
  100. scitex/session/_decorator.py +9 -9
  101. scitex/session/_lifecycle.py +5 -5
  102. scitex/session/template.py +1 -1
  103. scitex/stats/__main__.py +281 -0
  104. scitex/stats/_mcp_handlers.py +1191 -0
  105. scitex/stats/_mcp_tool_schemas.py +384 -0
  106. scitex/stats/correct/_correct_bonferroni.py +1 -1
  107. scitex/stats/correct/_correct_fdr.py +1 -1
  108. scitex/stats/correct/_correct_fdr_.py +1 -1
  109. scitex/stats/correct/_correct_holm.py +1 -1
  110. scitex/stats/correct/_correct_sidak.py +1 -1
  111. scitex/stats/effect_sizes/_cliffs_delta.py +1 -1
  112. scitex/stats/effect_sizes/_cohens_d.py +1 -1
  113. scitex/stats/effect_sizes/_epsilon_squared.py +1 -1
  114. scitex/stats/effect_sizes/_eta_squared.py +1 -1
  115. scitex/stats/effect_sizes/_prob_superiority.py +1 -1
  116. scitex/stats/mcp_server.py +405 -0
  117. scitex/stats/posthoc/_dunnett.py +1 -1
  118. scitex/stats/posthoc/_games_howell.py +1 -1
  119. scitex/stats/posthoc/_tukey_hsd.py +1 -1
  120. scitex/stats/power/_power.py +1 -1
  121. scitex/stats/utils/_effect_size.py +1 -1
  122. scitex/stats/utils/_formatters.py +1 -1
  123. scitex/stats/utils/_power.py +1 -1
  124. scitex/template/_mcp_handlers.py +259 -0
  125. scitex/template/_mcp_tool_schemas.py +112 -0
  126. scitex/template/mcp_server.py +186 -0
  127. scitex/utils/_verify_scitex_format.py +2 -2
  128. scitex/utils/template.py +1 -1
  129. scitex/web/__init__.py +12 -11
  130. scitex/web/_scraping.py +26 -265
  131. scitex/web/download_images.py +316 -0
  132. scitex/writer/Writer.py +1 -1
  133. scitex/writer/_clone_writer_project.py +1 -1
  134. scitex/writer/_validate_tree_structures.py +1 -1
  135. scitex/writer/dataclasses/config/_WriterConfig.py +1 -1
  136. scitex/writer/dataclasses/contents/_ManuscriptContents.py +1 -1
  137. scitex/writer/dataclasses/core/_Document.py +1 -1
  138. scitex/writer/dataclasses/core/_DocumentSection.py +1 -1
  139. scitex/writer/dataclasses/results/_CompilationResult.py +1 -1
  140. scitex/writer/dataclasses/results/_LaTeXIssue.py +1 -1
  141. scitex/writer/utils/.legacy_git_retry.py +7 -5
  142. scitex/writer/utils/_parse_latex_logs.py +1 -1
  143. {scitex-2.11.0.dist-info → scitex-2.13.0.dist-info}/METADATA +431 -269
  144. {scitex-2.11.0.dist-info → scitex-2.13.0.dist-info}/RECORD +147 -118
  145. scitex-2.13.0.dist-info/entry_points.txt +11 -0
  146. scitex-2.11.0.dist-info/entry_points.txt +0 -2
  147. {scitex-2.11.0.dist-info → scitex-2.13.0.dist-info}/WHEEL +0 -0
  148. {scitex-2.11.0.dist-info → scitex-2.13.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,205 @@
1
+ #!/usr/bin/env python3
2
+ # Timestamp: 2026-01-08
3
+ # File: src/scitex/plt/mcp_server.py
4
+ # ----------------------------------------
5
+
6
+ """
7
+ MCP Server for SciTeX plt - Publication-quality plotting.
8
+
9
+ Provides tools for:
10
+ - Style configuration (get/set publication styles)
11
+ - Style presets (journal-specific configurations)
12
+ - Figure cropping (auto-crop whitespace)
13
+ - DPI management
14
+ - Color palette access
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ import asyncio
20
+
21
+ # Graceful MCP dependency handling
22
+ try:
23
+ import mcp.types as types
24
+ from mcp.server import NotificationOptions, Server
25
+ from mcp.server.models import InitializationOptions
26
+ from mcp.server.stdio import stdio_server
27
+
28
+ MCP_AVAILABLE = True
29
+ except ImportError:
30
+ MCP_AVAILABLE = False
31
+ types = None # type: ignore
32
+ Server = None # type: ignore
33
+ NotificationOptions = None # type: ignore
34
+ InitializationOptions = None # type: ignore
35
+ stdio_server = None # type: ignore
36
+
37
+ __all__ = ["PltServer", "main", "MCP_AVAILABLE"]
38
+
39
+
40
+ class PltServer:
41
+ """MCP Server for Publication-quality Plotting."""
42
+
43
+ def __init__(self):
44
+ self.server = Server("scitex-plt")
45
+ self.setup_handlers()
46
+
47
+ def setup_handlers(self):
48
+ """Set up MCP server handlers."""
49
+ from ._mcp_handlers import (
50
+ crop_figure_handler,
51
+ get_color_palette_handler,
52
+ get_dpi_settings_handler,
53
+ get_style_handler,
54
+ list_presets_handler,
55
+ set_style_handler,
56
+ )
57
+ from ._mcp_tool_schemas import get_tool_schemas
58
+
59
+ @self.server.list_tools()
60
+ async def handle_list_tools():
61
+ return get_tool_schemas()
62
+
63
+ @self.server.call_tool()
64
+ async def handle_call_tool(name: str, arguments: dict):
65
+ if name == "get_style":
66
+ return await self._wrap_result(get_style_handler())
67
+
68
+ elif name == "set_style":
69
+ return await self._wrap_result(set_style_handler(**arguments))
70
+
71
+ elif name == "list_presets":
72
+ return await self._wrap_result(list_presets_handler())
73
+
74
+ elif name == "crop_figure":
75
+ return await self._wrap_result(crop_figure_handler(**arguments))
76
+
77
+ elif name == "get_dpi_settings":
78
+ return await self._wrap_result(get_dpi_settings_handler())
79
+
80
+ elif name == "get_color_palette":
81
+ return await self._wrap_result(get_color_palette_handler(**arguments))
82
+
83
+ else:
84
+ raise ValueError(f"Unknown tool: {name}")
85
+
86
+ @self.server.list_resources()
87
+ async def handle_list_resources():
88
+ """List available plt resources."""
89
+ resources = [
90
+ types.Resource(
91
+ uri="plt://style/current",
92
+ name="Current Style",
93
+ description="Current publication style configuration",
94
+ mimeType="application/json",
95
+ ),
96
+ types.Resource(
97
+ uri="plt://presets",
98
+ name="Style Presets",
99
+ description="Available journal style presets",
100
+ mimeType="application/json",
101
+ ),
102
+ types.Resource(
103
+ uri="plt://colors",
104
+ name="Color Palette",
105
+ description="SciTeX color palette",
106
+ mimeType="application/json",
107
+ ),
108
+ ]
109
+ return resources
110
+
111
+ @self.server.read_resource()
112
+ async def handle_read_resource(uri: str):
113
+ """Read a plt resource."""
114
+ import json
115
+
116
+ if uri == "plt://style/current":
117
+ result = await get_style_handler()
118
+ return types.TextResourceContents(
119
+ uri=uri,
120
+ mimeType="application/json",
121
+ text=json.dumps(result, indent=2),
122
+ )
123
+
124
+ elif uri == "plt://presets":
125
+ result = await list_presets_handler()
126
+ return types.TextResourceContents(
127
+ uri=uri,
128
+ mimeType="application/json",
129
+ text=json.dumps(result, indent=2),
130
+ )
131
+
132
+ elif uri == "plt://colors":
133
+ result = await get_color_palette_handler()
134
+ return types.TextResourceContents(
135
+ uri=uri,
136
+ mimeType="application/json",
137
+ text=json.dumps(result, indent=2),
138
+ )
139
+
140
+ else:
141
+ raise ValueError(f"Unknown resource URI: {uri}")
142
+
143
+ async def _wrap_result(self, coro):
144
+ """Wrap handler result as MCP TextContent."""
145
+ import json
146
+
147
+ try:
148
+ result = await coro
149
+ return [
150
+ types.TextContent(
151
+ type="text",
152
+ text=json.dumps(result, indent=2, default=str),
153
+ )
154
+ ]
155
+ except Exception as e:
156
+ return [
157
+ types.TextContent(
158
+ type="text",
159
+ text=json.dumps({"success": False, "error": str(e)}, indent=2),
160
+ )
161
+ ]
162
+
163
+
164
+ async def _run_server():
165
+ """Run the MCP server (internal)."""
166
+ server = PltServer()
167
+ async with stdio_server() as (read_stream, write_stream):
168
+ await server.server.run(
169
+ read_stream,
170
+ write_stream,
171
+ InitializationOptions(
172
+ server_name="scitex-plt",
173
+ server_version="0.1.0",
174
+ capabilities=server.server.get_capabilities(
175
+ notification_options=NotificationOptions(),
176
+ experimental_capabilities={},
177
+ ),
178
+ ),
179
+ )
180
+
181
+
182
+ def main():
183
+ """Main entry point for the MCP server."""
184
+ if not MCP_AVAILABLE:
185
+ import sys
186
+
187
+ print("=" * 60)
188
+ print("MCP Server 'scitex-plt' requires the 'mcp' package.")
189
+ print()
190
+ print("Install with:")
191
+ print(" pip install mcp")
192
+ print()
193
+ print("Or install scitex with MCP support:")
194
+ print(" pip install scitex[mcp]")
195
+ print("=" * 60)
196
+ sys.exit(1)
197
+
198
+ asyncio.run(_run_server())
199
+
200
+
201
+ if __name__ == "__main__":
202
+ main()
203
+
204
+
205
+ # EOF
@@ -28,7 +28,7 @@ import torch
28
28
  import tensorflow as tf
29
29
 
30
30
  # Initialize once - fixes everything!
31
- rng_manager = stx.rng.RandomStateManager(seed=42)
31
+ rng = stx.rng.RandomStateManager(seed=42)
32
32
 
33
33
  # Python random - automatically fixed
34
34
  python_val = random.random() # Reproducible!
@@ -87,7 +87,7 @@ import sys
87
87
  import scitex as stx
88
88
 
89
89
  # Session.start returns RNG, fixing random seeds of the supported libraries automatically
90
- CONFIG, stdout, stderr, plt, CC, rng_manager = stx.session.start(
90
+ CONFIG, stdout, stderr, plt, CC, rng = stx.session.start(
91
91
  sys=sys,
92
92
  seed=42
93
93
  )
@@ -208,4 +208,4 @@ When you create a RandomStateManager, it automatically:
208
208
 
209
209
  yusuke.watanabe@scitex.ai
210
210
 
211
- <!-- EOF -->
211
+ <!-- EOF -->
@@ -14,7 +14,7 @@ __DIR__ = os.path.dirname(__FILE__)
14
14
  Clean, simple RandomStateManager for scientific reproducibility.
15
15
 
16
16
  Main API:
17
- rng_manager = RandomStateManager(seed=42) # Create instance
17
+ rng = RandomStateManager(seed=42) # Create instance
18
18
  gen = rng("name") # Get named generator
19
19
  rng.verify(obj, "name") # Verify reproducibility
20
20
  """
@@ -44,11 +44,11 @@ class RandomStateManager:
44
44
  >>> import scitex as stx
45
45
  >>>
46
46
  >>> # Method 1: Direct usage
47
- >>> rng_manager = stx.rng.RandomStateManager(seed=42)
47
+ >>> rng = stx.rng.RandomStateManager(seed=42)
48
48
  >>> data = rng("data").random(100)
49
49
  >>>
50
50
  >>> # Method 2: From session.start
51
- >>> CONFIG, stdout, stderr, plt, CC, rng_manager = stx.session.start(seed=42)
51
+ >>> CONFIG, stdout, stderr, plt, CC, rng = stx.session.start(seed=42)
52
52
  >>> model = rng("model").normal(size=(10, 10))
53
53
  >>>
54
54
  >>> # Verify reproducibility
@@ -98,7 +98,7 @@ class RandomStateManager:
98
98
  np.random.seed(self.seed)
99
99
  # Also set default_rng for new API
100
100
  self._np = np
101
- self._np_default_rng_manager = np.random.default_rng(self.seed)
101
+ self._np_default_rng = np.random.default_rng(self.seed)
102
102
  fixed_modules.append("numpy")
103
103
  except ImportError:
104
104
  self._np = None
@@ -159,7 +159,7 @@ class RandomStateManager:
159
159
 
160
160
  Examples
161
161
  --------
162
- >>> rng_manager = RandomStateManager(42)
162
+ >>> rng = RandomStateManager(42)
163
163
  >>> gen = rng.get_np_generator("data")
164
164
  >>> values = gen.random(100)
165
165
  >>> perm = gen.permutation(100)
@@ -427,7 +427,7 @@ class RandomStateManager:
427
427
 
428
428
  Examples
429
429
  --------
430
- >>> rng_manager = RandomStateManager(42)
430
+ >>> rng = RandomStateManager(42)
431
431
  >>> from sklearn.model_selection import train_test_split
432
432
  >>> X_train, X_test = train_test_split(
433
433
  ... X, test_size=0.2,
@@ -455,7 +455,7 @@ class RandomStateManager:
455
455
 
456
456
  Examples
457
457
  --------
458
- >>> rng_manager = RandomStateManager(42)
458
+ >>> rng = RandomStateManager(42)
459
459
  >>> gen = rng.get_torch_generator("model")
460
460
  >>> torch.randn(5, 5, generator=gen)
461
461
  """
@@ -503,7 +503,7 @@ class RandomStateManager:
503
503
 
504
504
  Examples
505
505
  --------
506
- >>> rng_manager = RandomStateManager(42)
506
+ >>> rng = RandomStateManager(42)
507
507
  >>> rng.clear_cache() # Clear all
508
508
  >>> rng.clear_cache("old_data") # Clear specific
509
509
  >>> rng.clear_cache(["test1", "test2"]) # Clear multiple
@@ -559,7 +559,7 @@ def get(verbose: bool = False) -> RandomStateManager:
559
559
  Examples
560
560
  --------
561
561
  >>> import scitex as stx
562
- >>> rng_manager = stx.rng.get()
562
+ >>> rng = stx.rng.get()
563
563
  >>> data = rng("data").random(100)
564
564
  """
565
565
  global _GLOBAL_INSTANCE
@@ -589,7 +589,7 @@ def reset(seed: int = 42, verbose: bool = False) -> RandomStateManager:
589
589
  Examples
590
590
  --------
591
591
  >>> import scitex as stx
592
- >>> rng_manager = stx.repro.reset(seed=123)
592
+ >>> rng = stx.repro.reset(seed=123)
593
593
  """
594
594
  global _GLOBAL_INSTANCE
595
595
  _GLOBAL_INSTANCE = RandomStateManager(seed, verbose=verbose)
@@ -626,8 +626,8 @@ def main(args):
626
626
  print(f"Seed: {args.seed}")
627
627
 
628
628
  # Get named generators
629
- data_gen = rng_manager("data")
630
- model_gen = rng_manager("model")
629
+ data_gen = rng("data")
630
+ model_gen = rng("model")
631
631
 
632
632
  # Generate data
633
633
  print(f"\n{'Data Generation':-^60}")
@@ -641,7 +641,7 @@ def main(args):
641
641
 
642
642
  # Verify reproducibility
643
643
  print(f"\n{'Verification':-^60}")
644
- rng_manager.verify(data, "demo_data")
644
+ rng.verify(data, "demo_data")
645
645
  print("✓ Data reproducibility verified")
646
646
 
647
647
  print(f"\n{'=' * 60}")
@@ -660,7 +660,7 @@ if __name__ == "__main__":
660
660
 
661
661
  args = parse_args()
662
662
 
663
- CONFIG, sys.stdout, sys.stderr, plt, CC, rng_manager = stx.session.start(
663
+ CONFIG, sys.stdout, sys.stderr, plt, CC, rng = stx.session.start(
664
664
  sys,
665
665
  plt,
666
666
  args=args,
scitex/repro/_gen_ID.py CHANGED
@@ -114,7 +114,7 @@ if __name__ == "__main__":
114
114
 
115
115
  args = parse_args()
116
116
 
117
- CONFIG, sys.stdout, sys.stderr, plt, CC, rng_manager = stx.session.start(
117
+ CONFIG, sys.stdout, sys.stderr, plt, CC, rng = stx.session.start(
118
118
  sys,
119
119
  plt,
120
120
  args=args,
@@ -91,7 +91,7 @@ if __name__ == "__main__":
91
91
 
92
92
  args = parse_args()
93
93
 
94
- CONFIG, sys.stdout, sys.stderr, plt, CC, rng_manager = stx.session.start(
94
+ CONFIG, sys.stdout, sys.stderr, plt, CC, rng = stx.session.start(
95
95
  sys,
96
96
  plt,
97
97
  args=args,
@@ -72,8 +72,8 @@ def main(args):
72
72
  print(f"Array size: {args.size}")
73
73
  print(f"Seed: {args.seed}")
74
74
 
75
- # Generate arrays using rng_manager
76
- gen = rng_manager("demo")
75
+ # Generate arrays using rng
76
+ gen = rng("demo")
77
77
 
78
78
  # Create array and hash it
79
79
  print(f"\n{'Hash Generation':-^60}")
@@ -95,7 +95,7 @@ def main(args):
95
95
 
96
96
  # Reset generator and create same data
97
97
  print(f"\n{'Reproducibility Check':-^60}")
98
- gen_repro = rng_manager("demo") # Same name = same seed
98
+ gen_repro = rng("demo") # Same name = same seed
99
99
  data3 = gen_repro.random(args.size)
100
100
  hash3 = hash_array(data3)
101
101
  print(f"Array 3 hash (reproduced): {hash3}")
@@ -115,7 +115,7 @@ if __name__ == "__main__":
115
115
 
116
116
  args = parse_args()
117
117
 
118
- CONFIG, sys.stdout, sys.stderr, plt, CC, rng_manager = stx.session.start(
118
+ CONFIG, sys.stdout, sys.stderr, plt, CC, rng = stx.session.start(
119
119
  sys,
120
120
  plt,
121
121
  args=args,
@@ -1,5 +1,4 @@
1
1
  #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
2
  # File: /home/ywatanabe/proj/scitex_repo/src/scitex/scholar/__main__.py
4
3
 
5
4
  """Scholar CLI entry point - Subcommand-based interface.
@@ -8,6 +7,7 @@ Clean interface routing to battle-tested pipeline implementations:
8
7
  - single: Process single paper (DOI or title)
9
8
  - parallel: Process multiple papers in parallel
10
9
  - bibtex: Process papers from BibTeX file
10
+ - mcp: Start MCP server for LLM integration
11
11
  """
12
12
 
13
13
  from __future__ import annotations
@@ -33,6 +33,7 @@ Clean subcommand interface to battle-tested pipelines:
33
33
  single - Process a single paper (DOI or title)
34
34
  parallel - Process multiple papers in parallel
35
35
  bibtex - Process papers from BibTeX file
36
+ mcp - Start MCP server for LLM integration
36
37
 
37
38
  STORAGE: ~/.scitex/scholar/library/
38
39
  MASTER/{8DIGITID}/ - Centralized storage (no duplicates)
@@ -193,6 +194,16 @@ STORAGE: ~/.scitex/scholar/library/
193
194
  help="Base Chrome profile to sync from (default: system)",
194
195
  )
195
196
 
197
+ # ========================================
198
+ # Subcommand: mcp
199
+ # ========================================
200
+ subparsers.add_parser(
201
+ "mcp",
202
+ help="Start MCP server for LLM integration",
203
+ description="Start the MCP (Model Context Protocol) server for Claude/LLM integration",
204
+ formatter_class=argparse.RawDescriptionHelpFormatter,
205
+ )
206
+
196
207
  return parser
197
208
 
198
209
 
@@ -220,7 +231,7 @@ async def run_single_pipeline(args):
220
231
  force=args.force,
221
232
  )
222
233
 
223
- logger.success(f"Single paper pipeline completed")
234
+ logger.success("Single paper pipeline completed")
224
235
  return 0
225
236
 
226
237
 
@@ -288,6 +299,15 @@ async def run_bibtex_pipeline(args):
288
299
  return 0
289
300
 
290
301
 
302
+ async def run_mcp_server():
303
+ """Run MCP server."""
304
+ from .mcp_server import main as mcp_main
305
+
306
+ logger.info("Starting Scholar MCP server...")
307
+ await mcp_main()
308
+ return 0
309
+
310
+
291
311
  async def main_async():
292
312
  """Main async entry point."""
293
313
  parser = create_parser()
@@ -300,6 +320,8 @@ async def main_async():
300
320
  return await run_parallel_pipeline(args)
301
321
  elif args.command == "bibtex":
302
322
  return await run_bibtex_pipeline(args)
323
+ elif args.command == "mcp":
324
+ return await run_mcp_server()
303
325
  else:
304
326
  logger.error(f"Unknown command: {args.command}")
305
327
  return 1