scitex 2.15.2__py3-none-any.whl → 2.15.4__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/_mcp_resources/__init__.py +2 -0
- scitex/_mcp_resources/_scholar.py +148 -0
- scitex/_mcp_tools/scholar.py +50 -99
- scitex/_mcp_tools/social.py +15 -232
- scitex/_mcp_tools/writer.py +7 -17
- scitex/canvas/mcp_server.py +16 -3
- scitex/capture/mcp_server.py +16 -2
- scitex/cli/audio.py +90 -20
- scitex/cli/capture.py +120 -0
- scitex/cli/introspect.py +19 -12
- scitex/cli/plt.py +78 -21
- scitex/cli/scholar/__init__.py +160 -2
- scitex/cli/scholar/_crossref_scitex.py +25 -266
- scitex/cli/scholar/_openalex_scitex.py +55 -0
- scitex/cli/social.py +63 -22
- scitex/cli/stats.py +121 -3
- scitex/cli/writer.py +49 -423
- scitex/dev/plt/data/mpl/PLOTTING_FUNCTIONS.yaml +90 -0
- scitex/dev/plt/data/mpl/PLOTTING_SIGNATURES.yaml +1571 -0
- scitex/dev/plt/data/mpl/PLOTTING_SIGNATURES_DETAILED.yaml +6262 -0
- scitex/dev/plt/data/mpl/SIGNATURES_FLATTENED.yaml +1274 -0
- scitex/dev/plt/data/mpl/dir_ax.txt +459 -0
- scitex/introspect/_list_api.py +5 -2
- scitex/plt/docs/EXTERNAL_PACKAGE_BRANDING.md +2 -2
- scitex/scholar/__init__.py +14 -9
- scitex/scholar/_mcp/crossref_tool_schemas.py +133 -0
- scitex/scholar/_mcp/openalex_handlers.py +212 -0
- scitex/scholar/_mcp/openalex_tool_schemas.py +96 -0
- scitex/scholar/_mcp/tool_schemas.py +16 -1
- scitex/scholar/data/.gitkeep +0 -0
- scitex/scholar/data/README.md +44 -0
- scitex/scholar/data/bib_files/bibliography.bib +1952 -0
- scitex/scholar/data/bib_files/neurovista.bib +277 -0
- scitex/scholar/data/bib_files/neurovista_enriched.bib +441 -0
- scitex/scholar/data/bib_files/neurovista_enriched_enriched.bib +441 -0
- scitex/scholar/data/bib_files/neurovista_processed.bib +338 -0
- scitex/scholar/data/bib_files/openaccess.bib +89 -0
- scitex/scholar/data/bib_files/pac-seizure_prediction_enriched.bib +2178 -0
- scitex/scholar/data/bib_files/pac.bib +698 -0
- scitex/scholar/data/bib_files/pac_enriched.bib +1061 -0
- scitex/scholar/data/bib_files/pac_processed.bib +0 -0
- scitex/scholar/data/bib_files/pac_titles.txt +75 -0
- scitex/scholar/data/bib_files/paywalled.bib +98 -0
- scitex/scholar/data/bib_files/related-papers-by-coauthors.bib +58 -0
- scitex/scholar/data/bib_files/related-papers-by-coauthors_enriched.bib +87 -0
- scitex/scholar/data/bib_files/seizure_prediction.bib +694 -0
- scitex/scholar/data/bib_files/seizure_prediction_processed.bib +0 -0
- scitex/scholar/data/bib_files/test_complete_enriched.bib +437 -0
- scitex/scholar/data/bib_files/test_final_enriched.bib +437 -0
- scitex/scholar/data/bib_files/test_seizure.bib +46 -0
- scitex/scholar/data/impact_factor/JCR_IF_2022.xlsx +0 -0
- scitex/scholar/data/impact_factor/JCR_IF_2024.db +0 -0
- scitex/scholar/data/impact_factor/JCR_IF_2024.xlsx +0 -0
- scitex/scholar/data/impact_factor/JCR_IF_2024_v01.db +0 -0
- scitex/scholar/data/impact_factor.db +0 -0
- scitex/scholar/docs/EXTERNAL_PACKAGE_BRANDING.md +2 -2
- scitex/scholar/local_dbs/__init__.py +31 -0
- scitex/scholar/local_dbs/crossref_scitex.py +30 -0
- scitex/scholar/local_dbs/openalex_scitex.py +30 -0
- scitex/scholar/mcp_server.py +59 -4
- scitex/social/docs/EXTERNAL_PACKAGE_BRANDING.md +2 -2
- scitex/stats/mcp_server.py +16 -3
- scitex/template/mcp_server.py +16 -3
- scitex/ui/mcp_server.py +16 -3
- scitex/writer/__init__.py +43 -34
- {scitex-2.15.2.dist-info → scitex-2.15.4.dist-info}/METADATA +22 -3
- {scitex-2.15.2.dist-info → scitex-2.15.4.dist-info}/RECORD +70 -38
- scitex/scholar/crossref_scitex.py +0 -367
- scitex/scholar/url_finder/.tmp/open_url/KNOWN_RESOLVERS.py +0 -462
- scitex/scholar/url_finder/.tmp/open_url/README.md +0 -223
- scitex/scholar/url_finder/.tmp/open_url/_DOIToURLResolver.py +0 -694
- scitex/scholar/url_finder/.tmp/open_url/_OpenURLResolver.py +0 -1160
- scitex/scholar/url_finder/.tmp/open_url/_ResolverLinkFinder.py +0 -344
- scitex/scholar/url_finder/.tmp/open_url/__init__.py +0 -24
- {scitex-2.15.2.dist-info → scitex-2.15.4.dist-info}/WHEEL +0 -0
- {scitex-2.15.2.dist-info → scitex-2.15.4.dist-info}/entry_points.txt +0 -0
- {scitex-2.15.2.dist-info → scitex-2.15.4.dist-info}/licenses/LICENSE +0 -0
scitex/_mcp_tools/social.py
CHANGED
|
@@ -1,244 +1,27 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
# Timestamp: 2026-01-
|
|
3
|
-
# File: /home/ywatanabe/proj/scitex-
|
|
2
|
+
# Timestamp: 2026-01-27
|
|
3
|
+
# File: /home/ywatanabe/proj/scitex-python/src/scitex/_mcp_tools/social.py
|
|
4
|
+
"""Social module tools - thin wrapper delegating to socialia package.
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
All MCP tools delegate to socialia CLI for reproducibility.
|
|
8
|
-
Each tool returns the CLI command used, enabling human reproduction.
|
|
6
|
+
Single source of truth: socialia MCP tools.
|
|
9
7
|
"""
|
|
10
8
|
|
|
11
9
|
from __future__ import annotations
|
|
12
10
|
|
|
13
|
-
import json
|
|
14
|
-
import subprocess
|
|
15
|
-
import sys
|
|
16
|
-
from typing import Optional
|
|
17
|
-
|
|
18
|
-
# Import platform strategies from socialia for MCP tool descriptions
|
|
19
|
-
try:
|
|
20
|
-
from scitex.social import PLATFORM_STRATEGIES
|
|
21
|
-
except ImportError:
|
|
22
|
-
try:
|
|
23
|
-
from socialia import PLATFORM_STRATEGIES
|
|
24
|
-
except ImportError:
|
|
25
|
-
PLATFORM_STRATEGIES = """
|
|
26
|
-
## Platform Strategies (install socialia for full guide)
|
|
27
|
-
- twitter: 280 chars, hook first, 1-2 hashtags at end
|
|
28
|
-
- linkedin: 3000 chars, first 2 lines critical, 3-5 hashtags at end
|
|
29
|
-
- reddit: title is key, no hashtags, value first
|
|
30
|
-
- youtube: keyword-rich title <60 chars, 3-5 hashtags in description
|
|
31
|
-
"""
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def _json(data: dict) -> str:
|
|
35
|
-
return json.dumps(data, indent=2, default=str)
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
def _run_socialia_cli(*args: str) -> dict:
|
|
39
|
-
"""Run socialia CLI and return structured result."""
|
|
40
|
-
cmd = [sys.executable, "-m", "socialia", "--json", *args]
|
|
41
|
-
cli_command = f"socialia {' '.join(args)}"
|
|
42
|
-
|
|
43
|
-
try:
|
|
44
|
-
result = subprocess.run(cmd, capture_output=True, text=True, timeout=60)
|
|
45
|
-
|
|
46
|
-
if result.returncode == 0:
|
|
47
|
-
try:
|
|
48
|
-
data = json.loads(result.stdout)
|
|
49
|
-
data["cli_command"] = cli_command
|
|
50
|
-
return data
|
|
51
|
-
except json.JSONDecodeError:
|
|
52
|
-
return {
|
|
53
|
-
"success": True,
|
|
54
|
-
"output": result.stdout,
|
|
55
|
-
"cli_command": cli_command,
|
|
56
|
-
}
|
|
57
|
-
else:
|
|
58
|
-
return {
|
|
59
|
-
"success": False,
|
|
60
|
-
"error": result.stderr or result.stdout,
|
|
61
|
-
"cli_command": cli_command,
|
|
62
|
-
}
|
|
63
|
-
except subprocess.TimeoutExpired:
|
|
64
|
-
return {
|
|
65
|
-
"success": False,
|
|
66
|
-
"error": "Command timed out",
|
|
67
|
-
"cli_command": cli_command,
|
|
68
|
-
}
|
|
69
|
-
except Exception as e:
|
|
70
|
-
return {
|
|
71
|
-
"success": False,
|
|
72
|
-
"error": str(e),
|
|
73
|
-
"cli_command": cli_command,
|
|
74
|
-
}
|
|
75
|
-
|
|
76
11
|
|
|
77
12
|
def register_social_tools(mcp) -> None:
|
|
78
|
-
"""Register social
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
async def social_post(
|
|
82
|
-
platform: str,
|
|
83
|
-
text: str,
|
|
84
|
-
reply_to: Optional[str] = None,
|
|
85
|
-
quote: Optional[str] = None,
|
|
86
|
-
subreddit: Optional[str] = None,
|
|
87
|
-
title: Optional[str] = None,
|
|
88
|
-
dry_run: bool = False,
|
|
89
|
-
) -> str:
|
|
90
|
-
"""[social] Post content to a social media platform (twitter, linkedin, reddit, youtube).
|
|
91
|
-
|
|
92
|
-
PLATFORM STRATEGIES:
|
|
93
|
-
- twitter: 280 chars. Hook first. 1+ emoji. GitHub URL. 3-5 hashtags at END for SEO
|
|
94
|
-
- linkedin: 3000 chars. First 2 lines critical. Short paragraphs. Include project links. 3-5 hashtags at END
|
|
95
|
-
- reddit: Title is key. NO hashtags. Value first, self-promo last. Link in body
|
|
96
|
-
- youtube: Keyword-rich title <60 chars. Links in description. 3-5 hashtags in description
|
|
97
|
-
|
|
98
|
-
BAD: "SciTeX v2.15.0 released! New feature. #Python #AI"
|
|
99
|
-
GOOD: "Your AI agent can now speak to you remotely.
|
|
100
|
-
|
|
101
|
-
Audio relay bridges the gap.
|
|
102
|
-
|
|
103
|
-
github.com/user/repo
|
|
104
|
-
|
|
105
|
-
#AIAgents #Python"
|
|
106
|
-
"""
|
|
107
|
-
args = ["post", platform, text]
|
|
108
|
-
|
|
109
|
-
if reply_to:
|
|
110
|
-
args.extend(["--reply-to", reply_to])
|
|
111
|
-
if quote:
|
|
112
|
-
args.extend(["--quote", quote])
|
|
113
|
-
if subreddit and platform == "reddit":
|
|
114
|
-
args.extend(["--subreddit", subreddit])
|
|
115
|
-
if title:
|
|
116
|
-
args.extend(["--title", title])
|
|
117
|
-
if dry_run:
|
|
118
|
-
args.append("--dry-run")
|
|
119
|
-
|
|
120
|
-
result = _run_socialia_cli(*args)
|
|
121
|
-
return _json(result)
|
|
122
|
-
|
|
123
|
-
@mcp.tool()
|
|
124
|
-
async def social_delete(
|
|
125
|
-
platform: str,
|
|
126
|
-
post_id: str,
|
|
127
|
-
) -> str:
|
|
128
|
-
"""[social] Delete a post from a platform (twitter, linkedin, reddit)."""
|
|
129
|
-
result = _run_socialia_cli("delete", platform, post_id)
|
|
130
|
-
return _json(result)
|
|
131
|
-
|
|
132
|
-
@mcp.tool()
|
|
133
|
-
async def social_status() -> str:
|
|
134
|
-
"""[social] Check social media configuration and authentication status."""
|
|
135
|
-
result = _run_socialia_cli("status")
|
|
136
|
-
return _json(result)
|
|
137
|
-
|
|
138
|
-
@mcp.tool()
|
|
139
|
-
async def social_analytics(
|
|
140
|
-
platform: str,
|
|
141
|
-
days: int = 7,
|
|
142
|
-
) -> str:
|
|
143
|
-
"""[social] Get analytics for a platform (twitter, youtube, ga)."""
|
|
144
|
-
result = _run_socialia_cli("analytics", platform, "--days", str(days))
|
|
145
|
-
return _json(result)
|
|
146
|
-
|
|
147
|
-
@mcp.tool()
|
|
148
|
-
async def social_thread(
|
|
149
|
-
platform: str,
|
|
150
|
-
posts: list[str],
|
|
151
|
-
delay: int = 2,
|
|
152
|
-
dry_run: bool = False,
|
|
153
|
-
) -> str:
|
|
154
|
-
"""[social] Post a thread of connected posts. Posts are list of strings."""
|
|
155
|
-
import tempfile
|
|
156
|
-
from pathlib import Path
|
|
157
|
-
|
|
158
|
-
# Write posts to temp file (socialia expects file input)
|
|
159
|
-
thread_content = "\n---\n".join(posts)
|
|
160
|
-
with tempfile.NamedTemporaryFile(mode="w", suffix=".txt", delete=False) as f:
|
|
161
|
-
f.write(thread_content)
|
|
162
|
-
temp_path = f.name
|
|
163
|
-
|
|
164
|
-
try:
|
|
165
|
-
args = ["thread", platform, "--file", temp_path, "--delay", str(delay)]
|
|
166
|
-
if dry_run:
|
|
167
|
-
args.append("--dry-run")
|
|
168
|
-
result = _run_socialia_cli(*args)
|
|
169
|
-
result["thread_posts"] = posts
|
|
170
|
-
return _json(result)
|
|
171
|
-
finally:
|
|
172
|
-
Path(temp_path).unlink(missing_ok=True)
|
|
173
|
-
|
|
174
|
-
@mcp.tool()
|
|
175
|
-
async def social_check_availability() -> str:
|
|
176
|
-
"""[social] Check if socialia is installed and list available platforms."""
|
|
177
|
-
try:
|
|
178
|
-
from scitex.social import (
|
|
179
|
-
SOCIALIA_AVAILABLE,
|
|
180
|
-
__socialia_version__,
|
|
181
|
-
)
|
|
182
|
-
|
|
183
|
-
if SOCIALIA_AVAILABLE:
|
|
184
|
-
return _json(
|
|
185
|
-
{
|
|
186
|
-
"available": True,
|
|
187
|
-
"version": __socialia_version__,
|
|
188
|
-
"platforms": ["twitter", "linkedin", "reddit", "youtube"],
|
|
189
|
-
"analytics": ["twitter", "youtube", "ga"],
|
|
190
|
-
}
|
|
191
|
-
)
|
|
192
|
-
else:
|
|
193
|
-
return _json(
|
|
194
|
-
{
|
|
195
|
-
"available": False,
|
|
196
|
-
"error": "socialia not installed",
|
|
197
|
-
"install_command": "pip install socialia",
|
|
198
|
-
}
|
|
199
|
-
)
|
|
200
|
-
except Exception as e:
|
|
201
|
-
return _json(
|
|
202
|
-
{
|
|
203
|
-
"available": False,
|
|
204
|
-
"error": str(e),
|
|
205
|
-
}
|
|
206
|
-
)
|
|
207
|
-
|
|
208
|
-
@mcp.tool()
|
|
209
|
-
async def social_check(
|
|
210
|
-
platform: Optional[str] = None,
|
|
211
|
-
) -> str:
|
|
212
|
-
"""[social] Check platform connection status (v0.1.4+)."""
|
|
213
|
-
args = ["check"]
|
|
214
|
-
if platform:
|
|
215
|
-
args.append(platform)
|
|
216
|
-
result = _run_socialia_cli(*args)
|
|
217
|
-
return _json(result)
|
|
218
|
-
|
|
219
|
-
@mcp.tool()
|
|
220
|
-
async def social_feed(
|
|
221
|
-
platform: Optional[str] = None,
|
|
222
|
-
limit: int = 10,
|
|
223
|
-
mentions: bool = False,
|
|
224
|
-
) -> str:
|
|
225
|
-
"""[social] Get recent posts from platform feeds (v0.1.4+)."""
|
|
226
|
-
args = ["feed"]
|
|
227
|
-
if platform:
|
|
228
|
-
args.append(platform)
|
|
229
|
-
args.extend(["--limit", str(limit)])
|
|
230
|
-
if mentions:
|
|
231
|
-
args.append("--mentions")
|
|
232
|
-
result = _run_socialia_cli(*args)
|
|
233
|
-
return _json(result)
|
|
13
|
+
"""Register social tools by delegating to socialia package."""
|
|
14
|
+
try:
|
|
15
|
+
from socialia._mcp.tools import register_all_tools
|
|
234
16
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
17
|
+
# Delegate all MCP tools to socialia
|
|
18
|
+
register_all_tools(mcp)
|
|
19
|
+
except ImportError:
|
|
20
|
+
# Fallback when socialia is not installed
|
|
21
|
+
@mcp.tool()
|
|
22
|
+
def social_status() -> str:
|
|
23
|
+
"""[social] Get social media status (not installed)."""
|
|
24
|
+
return "socialia is required. Install with: pip install socialia"
|
|
242
25
|
|
|
243
26
|
|
|
244
27
|
# EOF
|
scitex/_mcp_tools/writer.py
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
# Timestamp: 2026-01-
|
|
2
|
+
# Timestamp: 2026-01-27
|
|
3
3
|
# File: /home/ywatanabe/proj/scitex-code/src/scitex/_mcp_tools/writer.py
|
|
4
|
-
"""Writer module tools -
|
|
4
|
+
"""Writer module tools - thin wrapper delegating to scitex-writer package.
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
Single source of truth: scitex-writer MCP tools.
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
9
|
from __future__ import annotations
|
|
@@ -12,26 +12,16 @@ from __future__ import annotations
|
|
|
12
12
|
def register_writer_tools(mcp) -> None:
|
|
13
13
|
"""Register writer tools by delegating to scitex-writer package."""
|
|
14
14
|
try:
|
|
15
|
-
from scitex_writer.
|
|
15
|
+
from scitex_writer._mcp.tools import register_all_tools
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
# Delegate all MCP tools to scitex-writer
|
|
18
|
+
register_all_tools(mcp)
|
|
18
19
|
except ImportError:
|
|
19
|
-
|
|
20
|
-
INSTRUCTIONS = None
|
|
21
|
-
|
|
22
|
-
if not _SCITEX_WRITER_AVAILABLE:
|
|
23
|
-
|
|
20
|
+
# Fallback when scitex-writer is not installed
|
|
24
21
|
@mcp.tool()
|
|
25
22
|
def writer_usage() -> str:
|
|
26
23
|
"""[writer] Get usage guide for SciTeX Writer (not installed)."""
|
|
27
24
|
return "scitex-writer is required. Install with: pip install scitex-writer"
|
|
28
25
|
|
|
29
|
-
return
|
|
30
|
-
|
|
31
|
-
@mcp.tool()
|
|
32
|
-
def writer_usage() -> str:
|
|
33
|
-
"""[writer] Get usage guide for SciTeX Writer LaTeX manuscript compilation system."""
|
|
34
|
-
return INSTRUCTIONS
|
|
35
|
-
|
|
36
26
|
|
|
37
27
|
# EOF
|
scitex/canvas/mcp_server.py
CHANGED
|
@@ -3,8 +3,12 @@
|
|
|
3
3
|
# File: src/scitex/canvas/mcp_server.py
|
|
4
4
|
# ----------------------------------------
|
|
5
5
|
|
|
6
|
-
"""
|
|
7
|
-
|
|
6
|
+
"""MCP Server for SciTeX canvas - Multi-panel figure composition.
|
|
7
|
+
|
|
8
|
+
.. deprecated::
|
|
9
|
+
This standalone server is deprecated. Use the unified scitex MCP server:
|
|
10
|
+
CLI: scitex serve
|
|
11
|
+
Python: from scitex.mcp_server import run_server
|
|
8
12
|
|
|
9
13
|
Provides tools for:
|
|
10
14
|
- Creating canvas workspaces
|
|
@@ -15,6 +19,15 @@ Provides tools for:
|
|
|
15
19
|
|
|
16
20
|
from __future__ import annotations
|
|
17
21
|
|
|
22
|
+
import warnings
|
|
23
|
+
|
|
24
|
+
warnings.warn(
|
|
25
|
+
"scitex.canvas.mcp_server is deprecated. Use 'scitex serve' or "
|
|
26
|
+
"'from scitex.mcp_server import run_server' for the unified MCP server.",
|
|
27
|
+
DeprecationWarning,
|
|
28
|
+
stacklevel=2,
|
|
29
|
+
)
|
|
30
|
+
|
|
18
31
|
import asyncio
|
|
19
32
|
|
|
20
33
|
# Graceful MCP dependency handling
|
|
@@ -126,7 +139,7 @@ async def _run_server():
|
|
|
126
139
|
|
|
127
140
|
|
|
128
141
|
def main():
|
|
129
|
-
"""
|
|
142
|
+
"""Run the MCP server."""
|
|
130
143
|
if not MCP_AVAILABLE:
|
|
131
144
|
import sys
|
|
132
145
|
|
scitex/capture/mcp_server.py
CHANGED
|
@@ -10,11 +10,25 @@ __FILE__ = "./src/scitex/capture/mcp_server.py"
|
|
|
10
10
|
__DIR__ = os.path.dirname(__FILE__)
|
|
11
11
|
# ----------------------------------------
|
|
12
12
|
|
|
13
|
-
"""
|
|
14
|
-
|
|
13
|
+
"""MCP Server for SciTeX Capture - Screen Capture for Python.
|
|
14
|
+
|
|
15
|
+
.. deprecated::
|
|
16
|
+
This standalone server is deprecated. Use the unified scitex MCP server:
|
|
17
|
+
CLI: scitex serve
|
|
18
|
+
Python: from scitex.mcp_server import run_server
|
|
19
|
+
|
|
15
20
|
Provides screenshot capture capabilities via Model Context Protocol.
|
|
16
21
|
"""
|
|
17
22
|
|
|
23
|
+
import warnings
|
|
24
|
+
|
|
25
|
+
warnings.warn(
|
|
26
|
+
"scitex.capture.mcp_server is deprecated. Use 'scitex serve' or "
|
|
27
|
+
"'from scitex.mcp_server import run_server' for the unified MCP server.",
|
|
28
|
+
DeprecationWarning,
|
|
29
|
+
stacklevel=2,
|
|
30
|
+
)
|
|
31
|
+
|
|
18
32
|
import asyncio
|
|
19
33
|
import base64
|
|
20
34
|
from datetime import datetime
|
scitex/cli/audio.py
CHANGED
|
@@ -240,7 +240,28 @@ def stop():
|
|
|
240
240
|
sys.exit(1)
|
|
241
241
|
|
|
242
242
|
|
|
243
|
-
@audio.
|
|
243
|
+
@audio.group(invoke_without_command=True)
|
|
244
|
+
@click.pass_context
|
|
245
|
+
def mcp(ctx):
|
|
246
|
+
"""
|
|
247
|
+
MCP (Model Context Protocol) server operations
|
|
248
|
+
|
|
249
|
+
\b
|
|
250
|
+
Commands:
|
|
251
|
+
start - Start the MCP server
|
|
252
|
+
doctor - Check MCP server health
|
|
253
|
+
list-tools - List available MCP tools
|
|
254
|
+
|
|
255
|
+
\b
|
|
256
|
+
Examples:
|
|
257
|
+
scitex audio mcp start
|
|
258
|
+
scitex audio mcp start -t http --port 31293
|
|
259
|
+
"""
|
|
260
|
+
if ctx.invoked_subcommand is None:
|
|
261
|
+
click.echo(ctx.get_help())
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
@mcp.command()
|
|
244
265
|
@click.option(
|
|
245
266
|
"-t",
|
|
246
267
|
"--transport",
|
|
@@ -259,9 +280,9 @@ def stop():
|
|
|
259
280
|
type=int,
|
|
260
281
|
help="Port for HTTP/SSE transport (default: 31293)",
|
|
261
282
|
)
|
|
262
|
-
def
|
|
283
|
+
def start(transport, host, port):
|
|
263
284
|
"""
|
|
264
|
-
|
|
285
|
+
Start the MCP server for remote audio playback
|
|
265
286
|
|
|
266
287
|
Enables remote agents (via SSH) to play audio on local speakers.
|
|
267
288
|
|
|
@@ -273,22 +294,9 @@ def serve(transport, host, port):
|
|
|
273
294
|
|
|
274
295
|
\b
|
|
275
296
|
Examples:
|
|
276
|
-
|
|
277
|
-
scitex audio
|
|
278
|
-
|
|
279
|
-
# HTTP server for remote agents
|
|
280
|
-
scitex audio serve -t http --port 31293
|
|
281
|
-
|
|
282
|
-
# SSE server
|
|
283
|
-
scitex audio serve -t sse --port 31293
|
|
284
|
-
|
|
285
|
-
\b
|
|
286
|
-
Remote Setup:
|
|
287
|
-
1. Local: scitex audio serve -t http --port 31293
|
|
288
|
-
2. SSH: Add to ~/.ssh/config:
|
|
289
|
-
LocalForward 31293 127.0.0.1:31293
|
|
290
|
-
3. Remote MCP config:
|
|
291
|
-
{"type": "sse", "url": "http://localhost:31293/sse"}
|
|
297
|
+
scitex audio mcp start
|
|
298
|
+
scitex audio mcp start -t http --port 31293
|
|
299
|
+
scitex audio mcp start -t sse --port 31293
|
|
292
300
|
"""
|
|
293
301
|
try:
|
|
294
302
|
from scitex.audio.mcp_server import FASTMCP_AVAILABLE, run_server
|
|
@@ -320,6 +328,68 @@ def serve(transport, host, port):
|
|
|
320
328
|
sys.exit(1)
|
|
321
329
|
|
|
322
330
|
|
|
331
|
+
@mcp.command()
|
|
332
|
+
def doctor():
|
|
333
|
+
"""
|
|
334
|
+
Check MCP server health and dependencies
|
|
335
|
+
|
|
336
|
+
\b
|
|
337
|
+
Example:
|
|
338
|
+
scitex audio mcp doctor
|
|
339
|
+
"""
|
|
340
|
+
click.secho("Audio MCP Server Health Check", fg="cyan", bold=True)
|
|
341
|
+
click.echo()
|
|
342
|
+
|
|
343
|
+
# Check fastmcp
|
|
344
|
+
click.echo("Checking FastMCP... ", nl=False)
|
|
345
|
+
try:
|
|
346
|
+
from scitex.audio.mcp_server import FASTMCP_AVAILABLE
|
|
347
|
+
|
|
348
|
+
if FASTMCP_AVAILABLE:
|
|
349
|
+
click.secho("OK", fg="green")
|
|
350
|
+
else:
|
|
351
|
+
click.secho("NOT INSTALLED", fg="red")
|
|
352
|
+
click.echo(" Install with: pip install fastmcp")
|
|
353
|
+
except ImportError:
|
|
354
|
+
click.secho("FAIL", fg="red")
|
|
355
|
+
|
|
356
|
+
# Check audio backends
|
|
357
|
+
click.echo("Checking audio backends... ", nl=False)
|
|
358
|
+
try:
|
|
359
|
+
from scitex.audio import available_backends
|
|
360
|
+
|
|
361
|
+
backends = available_backends()
|
|
362
|
+
if backends:
|
|
363
|
+
click.secho(f"OK ({', '.join(backends)})", fg="green")
|
|
364
|
+
else:
|
|
365
|
+
click.secho("NONE AVAILABLE", fg="yellow")
|
|
366
|
+
except Exception as e:
|
|
367
|
+
click.secho(f"FAIL ({e})", fg="red")
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
@mcp.command("list-tools")
|
|
371
|
+
def list_tools():
|
|
372
|
+
"""
|
|
373
|
+
List available MCP tools
|
|
374
|
+
|
|
375
|
+
\b
|
|
376
|
+
Example:
|
|
377
|
+
scitex audio mcp list-tools
|
|
378
|
+
"""
|
|
379
|
+
click.secho("Audio MCP Tools", fg="cyan", bold=True)
|
|
380
|
+
click.echo()
|
|
381
|
+
tools = [
|
|
382
|
+
("audio_speak", "Convert text to speech and play audio"),
|
|
383
|
+
("audio_generate_audio", "Generate audio file without playing"),
|
|
384
|
+
("audio_list_backends", "List available TTS backends"),
|
|
385
|
+
("audio_list_voices", "List available voices for a backend"),
|
|
386
|
+
("audio_play_audio", "Play an audio file"),
|
|
387
|
+
("audio_check_audio_status", "Check audio system status"),
|
|
388
|
+
]
|
|
389
|
+
for name, desc in tools:
|
|
390
|
+
click.echo(f" {name}: {desc}")
|
|
391
|
+
|
|
392
|
+
|
|
323
393
|
@audio.command()
|
|
324
394
|
@click.option(
|
|
325
395
|
"--host",
|
|
@@ -359,7 +429,7 @@ def relay(host, port):
|
|
|
359
429
|
try:
|
|
360
430
|
from scitex.audio.mcp_server import run_relay_server
|
|
361
431
|
|
|
362
|
-
click.secho(
|
|
432
|
+
click.secho("Starting audio relay server", fg="cyan")
|
|
363
433
|
click.echo(f" Host: {host}")
|
|
364
434
|
click.echo(f" Port: {port}")
|
|
365
435
|
click.echo()
|
scitex/cli/capture.py
CHANGED
|
@@ -314,5 +314,125 @@ def window(handle, output, quality):
|
|
|
314
314
|
sys.exit(1)
|
|
315
315
|
|
|
316
316
|
|
|
317
|
+
@capture.group(invoke_without_command=True)
|
|
318
|
+
@click.pass_context
|
|
319
|
+
def mcp(ctx):
|
|
320
|
+
"""
|
|
321
|
+
MCP (Model Context Protocol) server operations
|
|
322
|
+
|
|
323
|
+
\b
|
|
324
|
+
Commands:
|
|
325
|
+
start - Start the MCP server
|
|
326
|
+
doctor - Check MCP server health
|
|
327
|
+
list-tools - List available MCP tools
|
|
328
|
+
|
|
329
|
+
\b
|
|
330
|
+
Examples:
|
|
331
|
+
scitex capture mcp start
|
|
332
|
+
scitex capture mcp list-tools
|
|
333
|
+
"""
|
|
334
|
+
if ctx.invoked_subcommand is None:
|
|
335
|
+
click.echo(ctx.get_help())
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
@mcp.command("start")
|
|
339
|
+
@click.option(
|
|
340
|
+
"-t",
|
|
341
|
+
"--transport",
|
|
342
|
+
type=click.Choice(["stdio", "sse", "http"]),
|
|
343
|
+
default="stdio",
|
|
344
|
+
help="Transport protocol (default: stdio)",
|
|
345
|
+
)
|
|
346
|
+
@click.option("--host", default="0.0.0.0", help="Host for HTTP/SSE (default: 0.0.0.0)")
|
|
347
|
+
@click.option(
|
|
348
|
+
"--port", default=8096, type=int, help="Port for HTTP/SSE (default: 8096)"
|
|
349
|
+
)
|
|
350
|
+
def mcp_start(transport, host, port):
|
|
351
|
+
"""
|
|
352
|
+
Start the capture MCP server
|
|
353
|
+
|
|
354
|
+
\b
|
|
355
|
+
Examples:
|
|
356
|
+
scitex capture mcp start
|
|
357
|
+
scitex capture mcp start -t http --port 8096
|
|
358
|
+
"""
|
|
359
|
+
try:
|
|
360
|
+
from scitex.capture.mcp_server import main as run_server
|
|
361
|
+
|
|
362
|
+
if transport != "stdio":
|
|
363
|
+
click.secho(f"Starting capture MCP server ({transport})", fg="cyan")
|
|
364
|
+
click.echo(f" Host: {host}")
|
|
365
|
+
click.echo(f" Port: {port}")
|
|
366
|
+
|
|
367
|
+
run_server()
|
|
368
|
+
|
|
369
|
+
except ImportError as e:
|
|
370
|
+
click.secho(f"Error: {e}", fg="red", err=True)
|
|
371
|
+
click.echo("\nInstall dependencies: pip install fastmcp")
|
|
372
|
+
sys.exit(1)
|
|
373
|
+
except Exception as e:
|
|
374
|
+
click.secho(f"Error: {e}", fg="red", err=True)
|
|
375
|
+
sys.exit(1)
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
@mcp.command()
|
|
379
|
+
def doctor():
|
|
380
|
+
"""
|
|
381
|
+
Check MCP server health and dependencies
|
|
382
|
+
|
|
383
|
+
\b
|
|
384
|
+
Example:
|
|
385
|
+
scitex capture mcp doctor
|
|
386
|
+
"""
|
|
387
|
+
click.secho("Capture MCP Server Health Check", fg="cyan", bold=True)
|
|
388
|
+
click.echo()
|
|
389
|
+
|
|
390
|
+
click.echo("Checking FastMCP... ", nl=False)
|
|
391
|
+
try:
|
|
392
|
+
import fastmcp # noqa: F401
|
|
393
|
+
|
|
394
|
+
click.secho("OK", fg="green")
|
|
395
|
+
except ImportError:
|
|
396
|
+
click.secho("NOT INSTALLED", fg="red")
|
|
397
|
+
click.echo(" Install with: pip install fastmcp")
|
|
398
|
+
|
|
399
|
+
click.echo("Checking capture module... ", nl=False)
|
|
400
|
+
try:
|
|
401
|
+
from scitex import capture as _ # noqa: F401
|
|
402
|
+
|
|
403
|
+
click.secho("OK", fg="green")
|
|
404
|
+
except ImportError as e:
|
|
405
|
+
click.secho(f"FAIL ({e})", fg="red")
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
@mcp.command("list-tools")
|
|
409
|
+
def list_tools():
|
|
410
|
+
"""
|
|
411
|
+
List available MCP tools
|
|
412
|
+
|
|
413
|
+
\b
|
|
414
|
+
Example:
|
|
415
|
+
scitex capture mcp list-tools
|
|
416
|
+
"""
|
|
417
|
+
click.secho("Capture MCP Tools", fg="cyan", bold=True)
|
|
418
|
+
click.echo()
|
|
419
|
+
tools = [
|
|
420
|
+
("capture_capture_screenshot", "Capture screenshot"),
|
|
421
|
+
("capture_capture_window", "Capture specific window"),
|
|
422
|
+
("capture_start_monitoring", "Start continuous capture"),
|
|
423
|
+
("capture_stop_monitoring", "Stop monitoring"),
|
|
424
|
+
("capture_get_monitoring_status", "Get monitoring status"),
|
|
425
|
+
("capture_analyze_screenshot", "Analyze screenshot for errors"),
|
|
426
|
+
("capture_list_recent_screenshots", "List recent screenshots"),
|
|
427
|
+
("capture_clear_cache", "Clear screenshot cache"),
|
|
428
|
+
("capture_create_gif", "Create animated GIF"),
|
|
429
|
+
("capture_list_sessions", "List monitoring sessions"),
|
|
430
|
+
("capture_get_info", "Get monitor/window info"),
|
|
431
|
+
("capture_list_windows", "List visible windows"),
|
|
432
|
+
]
|
|
433
|
+
for name, desc in tools:
|
|
434
|
+
click.echo(f" {name}: {desc}")
|
|
435
|
+
|
|
436
|
+
|
|
317
437
|
if __name__ == "__main__":
|
|
318
438
|
capture()
|