scmcp-shared 0.2.0__tar.gz → 0.2.1__tar.gz
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.
- {scmcp_shared-0.2.0 → scmcp_shared-0.2.1}/PKG-INFO +1 -1
- scmcp_shared-0.2.1/src/scmcp_shared/__init__.py +3 -0
- {scmcp_shared-0.2.0 → scmcp_shared-0.2.1}/src/scmcp_shared/server/io.py +9 -4
- {scmcp_shared-0.2.0 → scmcp_shared-0.2.1}/src/scmcp_shared/server/pl.py +65 -62
- {scmcp_shared-0.2.0 → scmcp_shared-0.2.1}/src/scmcp_shared/server/pp.py +45 -40
- {scmcp_shared-0.2.0 → scmcp_shared-0.2.1}/src/scmcp_shared/server/tl.py +69 -44
- {scmcp_shared-0.2.0 → scmcp_shared-0.2.1}/src/scmcp_shared/server/util.py +33 -32
- {scmcp_shared-0.2.0 → scmcp_shared-0.2.1}/src/scmcp_shared/util.py +9 -2
- scmcp_shared-0.2.0/src/scmcp_shared/__init__.py +0 -3
- {scmcp_shared-0.2.0 → scmcp_shared-0.2.1}/.github/workflows/publish.yml +0 -0
- {scmcp_shared-0.2.0 → scmcp_shared-0.2.1}/LICENSE +0 -0
- {scmcp_shared-0.2.0 → scmcp_shared-0.2.1}/README.md +0 -0
- {scmcp_shared-0.2.0 → scmcp_shared-0.2.1}/pyproject.toml +0 -0
- {scmcp_shared-0.2.0 → scmcp_shared-0.2.1}/src/scmcp_shared/logging_config.py +0 -0
- {scmcp_shared-0.2.0 → scmcp_shared-0.2.1}/src/scmcp_shared/schema/__init__.py +0 -0
- {scmcp_shared-0.2.0 → scmcp_shared-0.2.1}/src/scmcp_shared/schema/base.py +0 -0
- {scmcp_shared-0.2.0 → scmcp_shared-0.2.1}/src/scmcp_shared/schema/io.py +0 -0
- {scmcp_shared-0.2.0 → scmcp_shared-0.2.1}/src/scmcp_shared/schema/pl.py +0 -0
- {scmcp_shared-0.2.0 → scmcp_shared-0.2.1}/src/scmcp_shared/schema/pp.py +0 -0
- {scmcp_shared-0.2.0 → scmcp_shared-0.2.1}/src/scmcp_shared/schema/tl.py +0 -0
- {scmcp_shared-0.2.0 → scmcp_shared-0.2.1}/src/scmcp_shared/schema/util.py +0 -0
- {scmcp_shared-0.2.0 → scmcp_shared-0.2.1}/src/scmcp_shared/server/__init__.py +0 -0
@@ -3,6 +3,7 @@ import inspect
|
|
3
3
|
from pathlib import Path
|
4
4
|
import scanpy as sc
|
5
5
|
from fastmcp import FastMCP , Context
|
6
|
+
from fastmcp.exceptions import ToolError
|
6
7
|
from ..schema.io import *
|
7
8
|
from ..util import filter_args, forward_request, get_ads, generate_msg
|
8
9
|
|
@@ -47,11 +48,13 @@ async def read(request: ReadModel):
|
|
47
48
|
adata.obs_names_make_unique()
|
48
49
|
ads.set_adata(adata, request=request)
|
49
50
|
return generate_msg(request, adata, ads)
|
51
|
+
except ToolError as e:
|
52
|
+
raise ToolError(e)
|
50
53
|
except Exception as e:
|
51
54
|
if hasattr(e, '__context__') and e.__context__:
|
52
|
-
raise
|
55
|
+
raise ToolError(e.__context__)
|
53
56
|
else:
|
54
|
-
raise e
|
57
|
+
raise ToolError(e)
|
55
58
|
|
56
59
|
|
57
60
|
@io_mcp.tool()
|
@@ -67,8 +70,10 @@ async def write(request: WriteModel):
|
|
67
70
|
kwargs = request.model_dump()
|
68
71
|
sc.write(kwargs["filename"], adata)
|
69
72
|
return {"filename": kwargs["filename"], "msg": "success to save file"}
|
73
|
+
except ToolError as e:
|
74
|
+
raise ToolError(e)
|
70
75
|
except Exception as e:
|
71
76
|
if hasattr(e, '__context__') and e.__context__:
|
72
|
-
raise
|
77
|
+
raise ToolError(e.__context__)
|
73
78
|
else:
|
74
|
-
raise e
|
79
|
+
raise ToolError(e)
|
@@ -3,6 +3,7 @@ import inspect
|
|
3
3
|
from functools import partial
|
4
4
|
import scanpy as sc
|
5
5
|
from fastmcp import FastMCP, Context
|
6
|
+
from fastmcp.exceptions import ToolError
|
6
7
|
from ..schema.pl import *
|
7
8
|
from pathlib import Path
|
8
9
|
from ..logging_config import setup_logger
|
@@ -25,13 +26,13 @@ async def pca(request: PCAModel = PCAModel()):
|
|
25
26
|
adata = get_ads().get_adata(request=request)
|
26
27
|
fig_path = sc_like_plot(sc.pl.pca, adata, request)
|
27
28
|
return {"figpath": fig_path}
|
28
|
-
except
|
29
|
-
raise e
|
29
|
+
except ToolError as e:
|
30
|
+
raise ToolError(e)
|
30
31
|
except Exception as e:
|
31
32
|
if hasattr(e, '__context__') and e.__context__:
|
32
|
-
raise
|
33
|
+
raise ToolError(e.__context__)
|
33
34
|
else:
|
34
|
-
raise e
|
35
|
+
raise ToolError(e)
|
35
36
|
|
36
37
|
@pl_mcp.tool()
|
37
38
|
async def diffmap(request: DiffusionMapModel = DiffusionMapModel()):
|
@@ -43,13 +44,13 @@ async def diffmap(request: DiffusionMapModel = DiffusionMapModel()):
|
|
43
44
|
adata = get_ads().get_adata(request=request)
|
44
45
|
fig_path = sc_like_plot(sc.pl.diffmap, adata, request)
|
45
46
|
return {"figpath": fig_path}
|
46
|
-
except
|
47
|
-
raise e
|
47
|
+
except ToolError as e:
|
48
|
+
raise ToolError(e)
|
48
49
|
except Exception as e:
|
49
50
|
if hasattr(e, '__context__') and e.__context__:
|
50
|
-
raise
|
51
|
+
raise ToolError(e.__context__)
|
51
52
|
else:
|
52
|
-
raise e
|
53
|
+
raise ToolError(e)
|
53
54
|
|
54
55
|
@pl_mcp.tool()
|
55
56
|
async def violin(request: ViolinModel,):
|
@@ -62,12 +63,14 @@ async def violin(request: ViolinModel,):
|
|
62
63
|
fig_path = sc_like_plot(sc.pl.violin, adata, request)
|
63
64
|
return {"figpath": fig_path}
|
64
65
|
except KeyError as e:
|
65
|
-
raise f"doest found {e} in current sampleid with adtype {request.adtype}"
|
66
|
+
raise ToolError(f"doest found {e} in current sampleid with adtype {request.adtype}")
|
67
|
+
except ToolError as e:
|
68
|
+
raise ToolError(e)
|
66
69
|
except Exception as e:
|
67
70
|
if hasattr(e, '__context__') and e.__context__:
|
68
|
-
raise
|
71
|
+
raise ToolError(e.__context__)
|
69
72
|
else:
|
70
|
-
raise e
|
73
|
+
raise ToolError(e)
|
71
74
|
|
72
75
|
|
73
76
|
@pl_mcp.tool()
|
@@ -80,13 +83,13 @@ async def stacked_violin(request: StackedViolinModel = StackedViolinModel()):
|
|
80
83
|
adata = get_ads().get_adata(request=request)
|
81
84
|
fig_path = sc_like_plot(sc.pl.stacked_violin, adata, request)
|
82
85
|
return {"figpath": fig_path}
|
83
|
-
except
|
84
|
-
raise e
|
86
|
+
except ToolError as e:
|
87
|
+
raise ToolError(e)
|
85
88
|
except Exception as e:
|
86
89
|
if hasattr(e, '__context__') and e.__context__:
|
87
|
-
raise
|
90
|
+
raise ToolError(e.__context__)
|
88
91
|
else:
|
89
|
-
raise e
|
92
|
+
raise ToolError(e)
|
90
93
|
|
91
94
|
|
92
95
|
@pl_mcp.tool()
|
@@ -99,13 +102,13 @@ async def heatmap(request: HeatmapModel):
|
|
99
102
|
adata = get_ads().get_adata(request=request)
|
100
103
|
fig_path = sc_like_plot(sc.pl.heatmap, adata, request)
|
101
104
|
return {"figpath": fig_path}
|
102
|
-
except
|
103
|
-
raise e
|
105
|
+
except ToolError as e:
|
106
|
+
raise ToolError(e)
|
104
107
|
except Exception as e:
|
105
108
|
if hasattr(e, '__context__') and e.__context__:
|
106
|
-
raise
|
109
|
+
raise ToolError(e.__context__)
|
107
110
|
else:
|
108
|
-
raise e
|
111
|
+
raise ToolError(e)
|
109
112
|
|
110
113
|
|
111
114
|
@pl_mcp.tool()
|
@@ -118,13 +121,13 @@ async def dotplot(request: DotplotModel):
|
|
118
121
|
adata = get_ads().get_adata(request=request)
|
119
122
|
fig_path = sc_like_plot(sc.pl.dotplot, adata, request)
|
120
123
|
return {"figpath": fig_path}
|
121
|
-
except
|
122
|
-
raise e
|
124
|
+
except ToolError as e:
|
125
|
+
raise ToolError(e)
|
123
126
|
except Exception as e:
|
124
127
|
if hasattr(e, '__context__') and e.__context__:
|
125
|
-
raise
|
128
|
+
raise ToolError(e.__context__)
|
126
129
|
else:
|
127
|
-
raise e
|
130
|
+
raise ToolError(e)
|
128
131
|
|
129
132
|
@pl_mcp.tool()
|
130
133
|
async def matrixplot(request: MatrixplotModel):
|
@@ -136,13 +139,13 @@ async def matrixplot(request: MatrixplotModel):
|
|
136
139
|
adata = get_ads().get_adata(request=request)
|
137
140
|
fig_path = sc_like_plot(sc.pl.matrixplot, adata, request)
|
138
141
|
return {"figpath": fig_path}
|
139
|
-
except
|
140
|
-
raise e
|
142
|
+
except ToolError as e:
|
143
|
+
raise ToolError(e)
|
141
144
|
except Exception as e:
|
142
145
|
if hasattr(e, '__context__') and e.__context__:
|
143
|
-
raise
|
146
|
+
raise ToolError(e.__context__)
|
144
147
|
else:
|
145
|
-
raise e
|
148
|
+
raise ToolError(e)
|
146
149
|
|
147
150
|
|
148
151
|
@pl_mcp.tool()
|
@@ -155,13 +158,13 @@ async def tracksplot(request: TracksplotModel):
|
|
155
158
|
adata = get_ads().get_adata(request=request)
|
156
159
|
fig_path = sc_like_plot(sc.pl.tracksplot, adata, request)
|
157
160
|
return {"figpath": fig_path}
|
158
|
-
except
|
159
|
-
raise e
|
161
|
+
except ToolError as e:
|
162
|
+
raise ToolError(e)
|
160
163
|
except Exception as e:
|
161
164
|
if hasattr(e, '__context__') and e.__context__:
|
162
|
-
raise
|
165
|
+
raise ToolError(e.__context__)
|
163
166
|
else:
|
164
|
-
raise e
|
167
|
+
raise ToolError(e)
|
165
168
|
|
166
169
|
@pl_mcp.tool()
|
167
170
|
async def scatter(request: EnhancedScatterModel = EnhancedScatterModel()):
|
@@ -173,13 +176,13 @@ async def scatter(request: EnhancedScatterModel = EnhancedScatterModel()):
|
|
173
176
|
adata = get_ads().get_adata(request=request)
|
174
177
|
fig_path = sc_like_plot(sc.pl.scatter, adata, request)
|
175
178
|
return {"figpath": fig_path}
|
176
|
-
except
|
177
|
-
raise e
|
179
|
+
except ToolError as e:
|
180
|
+
raise ToolError(e)
|
178
181
|
except Exception as e:
|
179
182
|
if hasattr(e, '__context__') and e.__context__:
|
180
|
-
raise
|
183
|
+
raise ToolError(e.__context__)
|
181
184
|
else:
|
182
|
-
raise e
|
185
|
+
raise ToolError(e)
|
183
186
|
|
184
187
|
@pl_mcp.tool()
|
185
188
|
async def embedding(request: EmbeddingModel):
|
@@ -192,13 +195,12 @@ async def embedding(request: EmbeddingModel):
|
|
192
195
|
fig_path = sc_like_plot(sc.pl.embedding, adata, request)
|
193
196
|
return {"figpath": fig_path}
|
194
197
|
except KeyError as e:
|
195
|
-
from fastmcp.exceptions import ToolError
|
196
198
|
raise ToolError(f"doest found {e} in current sampleid with adtype {request.adtype}")
|
197
199
|
except Exception as e:
|
198
200
|
if hasattr(e, '__context__') and e.__context__:
|
199
|
-
raise
|
201
|
+
raise ToolError(e.__context__)
|
200
202
|
else:
|
201
|
-
raise e
|
203
|
+
raise ToolError(e)
|
202
204
|
|
203
205
|
|
204
206
|
@pl_mcp.tool()
|
@@ -211,13 +213,13 @@ async def embedding_density(request: EmbeddingDensityModel):
|
|
211
213
|
adata = get_ads().get_adata(request=request)
|
212
214
|
fig_path = sc_like_plot(sc.pl.embedding_density, adata, request)
|
213
215
|
return {"figpath": fig_path}
|
214
|
-
except
|
215
|
-
raise e
|
216
|
+
except ToolError as e:
|
217
|
+
raise ToolError(e)
|
216
218
|
except Exception as e:
|
217
219
|
if hasattr(e, '__context__') and e.__context__:
|
218
|
-
raise
|
220
|
+
raise ToolError(e.__context__)
|
219
221
|
else:
|
220
|
-
raise e
|
222
|
+
raise ToolError(e)
|
221
223
|
|
222
224
|
@pl_mcp.tool()
|
223
225
|
async def rank_genes_groups(request: RankGenesGroupsModel):
|
@@ -229,13 +231,13 @@ async def rank_genes_groups(request: RankGenesGroupsModel):
|
|
229
231
|
adata = get_ads().get_adata(request=request)
|
230
232
|
fig_path = sc_like_plot(sc.pl.rank_genes_groups, adata, request)
|
231
233
|
return {"figpath": fig_path}
|
232
|
-
except
|
233
|
-
raise e
|
234
|
+
except ToolError as e:
|
235
|
+
raise ToolError(e)
|
234
236
|
except Exception as e:
|
235
237
|
if hasattr(e, '__context__') and e.__context__:
|
236
|
-
raise
|
238
|
+
raise ToolError(e.__context__)
|
237
239
|
else:
|
238
|
-
raise e
|
240
|
+
raise ToolError(e)
|
239
241
|
|
240
242
|
|
241
243
|
@pl_mcp.tool()
|
@@ -243,6 +245,7 @@ async def rank_genes_groups_dotplot(
|
|
243
245
|
request: RankGenesGroupsDotplotModel,
|
244
246
|
):
|
245
247
|
"""Plot ranking of genes(DEGs) using dotplot visualization. Defualt plot DEGs for rank_genes_groups tool"""
|
248
|
+
from fastmcp.exceptions import ClientError
|
246
249
|
try:
|
247
250
|
result = await forward_request("pl_rank_genes_groups_dotplot", request)
|
248
251
|
if result is not None:
|
@@ -250,13 +253,13 @@ async def rank_genes_groups_dotplot(
|
|
250
253
|
adata = get_ads().get_adata(request=request)
|
251
254
|
fig_path = sc_like_plot(sc.pl.rank_genes_groups_dotplot, adata, request)
|
252
255
|
return {"figpath": fig_path}
|
253
|
-
except
|
254
|
-
raise e
|
256
|
+
except ToolError as e:
|
257
|
+
raise ToolError(e)
|
255
258
|
except Exception as e:
|
256
259
|
if hasattr(e, '__context__') and e.__context__:
|
257
|
-
raise
|
260
|
+
raise ToolError(e.__context__)
|
258
261
|
else:
|
259
|
-
raise e
|
262
|
+
raise ToolError(e)
|
260
263
|
|
261
264
|
|
262
265
|
@pl_mcp.tool()
|
@@ -271,13 +274,13 @@ async def clustermap(
|
|
271
274
|
adata = get_ads().get_adata(request=request)
|
272
275
|
fig_path = sc_like_plot(sc.pl.clustermap, adata, request)
|
273
276
|
return {"figpath": fig_path}
|
274
|
-
except
|
275
|
-
raise e
|
277
|
+
except ToolError as e:
|
278
|
+
raise ToolError(e)
|
276
279
|
except Exception as e:
|
277
280
|
if hasattr(e, '__context__') and e.__context__:
|
278
|
-
raise
|
281
|
+
raise ToolError(e.__context__)
|
279
282
|
else:
|
280
|
-
raise e
|
283
|
+
raise ToolError(e)
|
281
284
|
|
282
285
|
@pl_mcp.tool()
|
283
286
|
async def highly_variable_genes(
|
@@ -291,13 +294,13 @@ async def highly_variable_genes(
|
|
291
294
|
adata = get_ads().get_adata(request=request)
|
292
295
|
fig_path = sc_like_plot(sc.pl.highly_variable_genes, adata, request)
|
293
296
|
return {"figpath": fig_path}
|
294
|
-
except
|
295
|
-
raise e
|
297
|
+
except ToolError as e:
|
298
|
+
raise ToolError(e)
|
296
299
|
except Exception as e:
|
297
300
|
if hasattr(e, '__context__') and e.__context__:
|
298
|
-
raise
|
301
|
+
raise ToolError(e.__context__)
|
299
302
|
else:
|
300
|
-
raise e
|
303
|
+
raise ToolError(e)
|
301
304
|
|
302
305
|
|
303
306
|
@pl_mcp.tool()
|
@@ -312,10 +315,10 @@ async def pca_variance_ratio(
|
|
312
315
|
adata = get_ads().get_adata(request=request)
|
313
316
|
fig_path = sc_like_plot(sc.pl.pca_variance_ratio, adata, request)
|
314
317
|
return {"figpath": fig_path}
|
315
|
-
except
|
316
|
-
raise e
|
318
|
+
except ToolError as e:
|
319
|
+
raise ToolError(e)
|
317
320
|
except Exception as e:
|
318
321
|
if hasattr(e, '__context__') and e.__context__:
|
319
|
-
raise
|
322
|
+
raise ToolError(e.__context__)
|
320
323
|
else:
|
321
|
-
raise e
|
324
|
+
raise ToolError(e)
|
@@ -3,6 +3,7 @@ import os
|
|
3
3
|
import inspect
|
4
4
|
import scanpy as sc
|
5
5
|
from fastmcp import FastMCP , Context
|
6
|
+
from fastmcp.exceptions import ToolError
|
6
7
|
from ..schema.pp import *
|
7
8
|
from ..util import filter_args, add_op_log, forward_request, get_ads, generate_msg
|
8
9
|
from ..logging_config import setup_logger
|
@@ -51,13 +52,13 @@ async def subset_cells(
|
|
51
52
|
return [
|
52
53
|
generate_msg(request, adata, ads)
|
53
54
|
]
|
54
|
-
except
|
55
|
-
raise e
|
55
|
+
except ToolError as e:
|
56
|
+
raise ToolError(e)
|
56
57
|
except Exception as e:
|
57
58
|
if hasattr(e, '__context__') and e.__context__:
|
58
|
-
raise
|
59
|
+
raise ToolError(e.__context__)
|
59
60
|
else:
|
60
|
-
raise e
|
61
|
+
raise ToolError(e)
|
61
62
|
|
62
63
|
|
63
64
|
@pp_mcp.tool()
|
@@ -96,13 +97,13 @@ async def subset_genes(
|
|
96
97
|
return [
|
97
98
|
generate_msg(request, adata, ads)
|
98
99
|
]
|
99
|
-
except
|
100
|
-
raise e
|
100
|
+
except ToolError as e:
|
101
|
+
raise ToolError(e)
|
101
102
|
except Exception as e:
|
102
103
|
if hasattr(e, '__context__') and e.__context__:
|
103
|
-
raise
|
104
|
+
raise ToolError(e.__context__)
|
104
105
|
else:
|
105
|
-
raise e
|
106
|
+
raise ToolError(e)
|
106
107
|
|
107
108
|
@pp_mcp.tool()
|
108
109
|
async def calculate_qc_metrics(
|
@@ -127,11 +128,13 @@ async def calculate_qc_metrics(
|
|
127
128
|
return [
|
128
129
|
generate_msg(request, adata, ads)
|
129
130
|
]
|
131
|
+
except ToolError as e:
|
132
|
+
raise ToolError(e)
|
130
133
|
except Exception as e:
|
131
134
|
if hasattr(e, '__context__') and e.__context__:
|
132
|
-
raise
|
135
|
+
raise ToolError(e.__context__)
|
133
136
|
else:
|
134
|
-
raise e
|
137
|
+
raise ToolError(e)
|
135
138
|
|
136
139
|
|
137
140
|
@pp_mcp.tool()
|
@@ -157,13 +160,13 @@ async def log1p(
|
|
157
160
|
return [
|
158
161
|
generate_msg(request, adata, ads)
|
159
162
|
]
|
160
|
-
except
|
161
|
-
raise e
|
163
|
+
except ToolError as e:
|
164
|
+
raise ToolError(e)
|
162
165
|
except Exception as e:
|
163
166
|
if hasattr(e, '__context__') and e.__context__:
|
164
|
-
raise
|
167
|
+
raise ToolError(e.__context__)
|
165
168
|
else:
|
166
|
-
raise e
|
169
|
+
raise ToolError(e)
|
167
170
|
|
168
171
|
|
169
172
|
@pp_mcp.tool()
|
@@ -185,13 +188,13 @@ async def normalize_total(
|
|
185
188
|
return [
|
186
189
|
generate_msg(request, adata, ads)
|
187
190
|
]
|
188
|
-
except
|
189
|
-
raise e
|
191
|
+
except ToolError as e:
|
192
|
+
raise ToolError(e)
|
190
193
|
except Exception as e:
|
191
194
|
if hasattr(e, '__context__') and e.__context__:
|
192
|
-
raise
|
195
|
+
raise ToolError(e.__context__)
|
193
196
|
else:
|
194
|
-
raise e
|
197
|
+
raise ToolError(e)
|
195
198
|
|
196
199
|
|
197
200
|
|
@@ -217,13 +220,13 @@ async def highly_variable_genes(
|
|
217
220
|
return [
|
218
221
|
generate_msg(request, adata, ads)
|
219
222
|
]
|
220
|
-
except
|
221
|
-
raise e
|
223
|
+
except ToolError as e:
|
224
|
+
raise ToolError(e)
|
222
225
|
except Exception as e:
|
223
226
|
if hasattr(e, '__context__') and e.__context__:
|
224
|
-
raise
|
227
|
+
raise ToolError(e.__context__)
|
225
228
|
else:
|
226
|
-
raise e
|
229
|
+
raise ToolError(e)
|
227
230
|
|
228
231
|
|
229
232
|
@pp_mcp.tool()
|
@@ -246,13 +249,13 @@ async def regress_out(
|
|
246
249
|
return [
|
247
250
|
generate_msg(request, adata, ads)
|
248
251
|
]
|
249
|
-
except
|
250
|
-
raise e
|
252
|
+
except ToolError as e:
|
253
|
+
raise ToolError(e)
|
251
254
|
except Exception as e:
|
252
255
|
if hasattr(e, '__context__') and e.__context__:
|
253
|
-
raise
|
256
|
+
raise ToolError(e.__context__)
|
254
257
|
else:
|
255
|
-
raise e
|
258
|
+
raise ToolError(e)
|
256
259
|
|
257
260
|
@pp_mcp.tool()
|
258
261
|
async def scale(
|
@@ -275,13 +278,13 @@ async def scale(
|
|
275
278
|
return [
|
276
279
|
generate_msg(request, adata, ads)
|
277
280
|
]
|
278
|
-
except
|
279
|
-
raise e
|
281
|
+
except ToolError as e:
|
282
|
+
raise ToolError(e)
|
280
283
|
except Exception as e:
|
281
284
|
if hasattr(e, '__context__') and e.__context__:
|
282
|
-
raise
|
285
|
+
raise ToolError(e.__context__)
|
283
286
|
else:
|
284
|
-
raise e
|
287
|
+
raise ToolError(e)
|
285
288
|
|
286
289
|
@pp_mcp.tool()
|
287
290
|
async def combat(
|
@@ -304,13 +307,13 @@ async def combat(
|
|
304
307
|
return [
|
305
308
|
generate_msg(request, adata, ads)
|
306
309
|
]
|
307
|
-
except
|
308
|
-
raise e
|
310
|
+
except ToolError as e:
|
311
|
+
raise ToolError(e)
|
309
312
|
except Exception as e:
|
310
313
|
if hasattr(e, '__context__') and e.__context__:
|
311
|
-
raise
|
314
|
+
raise ToolError(e.__context__)
|
312
315
|
else:
|
313
|
-
raise e
|
316
|
+
raise ToolError(e)
|
314
317
|
|
315
318
|
@pp_mcp.tool()
|
316
319
|
async def scrublet(
|
@@ -330,11 +333,13 @@ async def scrublet(
|
|
330
333
|
return [
|
331
334
|
generate_msg(request, adata, ads)
|
332
335
|
]
|
336
|
+
except ToolError as e:
|
337
|
+
raise ToolError(e)
|
333
338
|
except Exception as e:
|
334
339
|
if hasattr(e, '__context__') and e.__context__:
|
335
|
-
raise
|
340
|
+
raise ToolError(e.__context__)
|
336
341
|
else:
|
337
|
-
raise e
|
342
|
+
raise ToolError(e)
|
338
343
|
|
339
344
|
@pp_mcp.tool()
|
340
345
|
async def neighbors(
|
@@ -354,10 +359,10 @@ async def neighbors(
|
|
354
359
|
return [
|
355
360
|
generate_msg(request, adata, ads)
|
356
361
|
]
|
357
|
-
except
|
358
|
-
raise e
|
362
|
+
except ToolError as e:
|
363
|
+
raise ToolError(e)
|
359
364
|
except Exception as e:
|
360
365
|
if hasattr(e, '__context__') and e.__context__:
|
361
|
-
raise
|
366
|
+
raise ToolError(e.__context__)
|
362
367
|
else:
|
363
|
-
raise e
|
368
|
+
raise ToolError(e)
|
@@ -1,6 +1,7 @@
|
|
1
1
|
from fastmcp import FastMCP, Context
|
2
2
|
import os
|
3
3
|
import scanpy as sc
|
4
|
+
from fastmcp.exceptions import ToolError
|
4
5
|
from ..schema.tl import *
|
5
6
|
from scmcp_shared.util import filter_args, add_op_log, forward_request, get_ads, generate_msg
|
6
7
|
from scmcp_shared.logging_config import setup_logger
|
@@ -25,13 +26,13 @@ async def tsne(
|
|
25
26
|
sc.tl.tsne(adata, **func_kwargs)
|
26
27
|
add_op_log(adata, sc.tl.tsne, func_kwargs)
|
27
28
|
return generate_msg(request, adata, ads)
|
28
|
-
except
|
29
|
-
raise e
|
29
|
+
except ToolError as e:
|
30
|
+
raise ToolError(e)
|
30
31
|
except Exception as e:
|
31
32
|
if hasattr(e, '__context__') and e.__context__:
|
32
|
-
raise
|
33
|
+
raise ToolError(e.__context__)
|
33
34
|
else:
|
34
|
-
raise e
|
35
|
+
raise ToolError(e)
|
35
36
|
|
36
37
|
|
37
38
|
@tl_mcp.tool()
|
@@ -50,13 +51,13 @@ async def umap(
|
|
50
51
|
sc.tl.umap(adata, **func_kwargs)
|
51
52
|
add_op_log(adata, sc.tl.umap, func_kwargs)
|
52
53
|
return [generate_msg(request, adata, ads)]
|
53
|
-
except
|
54
|
-
raise e
|
54
|
+
except ToolError as e:
|
55
|
+
raise ToolError(e)
|
55
56
|
except Exception as e:
|
56
57
|
if hasattr(e, '__context__') and e.__context__:
|
57
|
-
raise
|
58
|
+
raise ToolError(e.__context__)
|
58
59
|
else:
|
59
|
-
raise e
|
60
|
+
raise ToolError(e)
|
60
61
|
|
61
62
|
@tl_mcp.tool()
|
62
63
|
async def draw_graph(
|
@@ -74,13 +75,13 @@ async def draw_graph(
|
|
74
75
|
sc.tl.draw_graph(adata, **func_kwargs)
|
75
76
|
add_op_log(adata, sc.tl.draw_graph, func_kwargs)
|
76
77
|
return [generate_msg(request, adata, ads)]
|
77
|
-
except
|
78
|
-
raise e
|
78
|
+
except ToolError as e:
|
79
|
+
raise ToolError(e)
|
79
80
|
except Exception as e:
|
80
81
|
if hasattr(e, '__context__') and e.__context__:
|
81
|
-
raise
|
82
|
+
raise ToolError(e.__context__)
|
82
83
|
else:
|
83
|
-
raise e
|
84
|
+
raise ToolError(e)
|
84
85
|
|
85
86
|
@tl_mcp.tool()
|
86
87
|
async def diffmap(
|
@@ -99,11 +100,13 @@ async def diffmap(
|
|
99
100
|
adata.obsm["X_diffmap"] = adata.obsm["X_diffmap"][:,1:]
|
100
101
|
add_op_log(adata, sc.tl.diffmap, func_kwargs)
|
101
102
|
return [generate_msg(request, adata, ads)]
|
103
|
+
except ToolError as e:
|
104
|
+
raise ToolError(e)
|
102
105
|
except Exception as e:
|
103
106
|
if hasattr(e, '__context__') and e.__context__:
|
104
|
-
raise
|
107
|
+
raise ToolError(e.__context__)
|
105
108
|
else:
|
106
|
-
raise e
|
109
|
+
raise ToolError(e)
|
107
110
|
|
108
111
|
@tl_mcp.tool()
|
109
112
|
async def embedding_density(
|
@@ -121,11 +124,13 @@ async def embedding_density(
|
|
121
124
|
sc.tl.embedding_density(adata, **func_kwargs)
|
122
125
|
add_op_log(adata, sc.tl.embedding_density, func_kwargs)
|
123
126
|
return [generate_msg(request, adata, ads)]
|
127
|
+
except ToolError as e:
|
128
|
+
raise ToolError(e)
|
124
129
|
except Exception as e:
|
125
130
|
if hasattr(e, '__context__') and e.__context__:
|
126
|
-
raise
|
131
|
+
raise ToolError(e.__context__)
|
127
132
|
else:
|
128
|
-
raise e
|
133
|
+
raise ToolError(e)
|
129
134
|
|
130
135
|
|
131
136
|
@tl_mcp.tool()
|
@@ -144,11 +149,13 @@ async def leiden(
|
|
144
149
|
sc.tl.leiden(adata, **func_kwargs)
|
145
150
|
add_op_log(adata, sc.tl.leiden, func_kwargs)
|
146
151
|
return [generate_msg(request, adata, ads)]
|
152
|
+
except ToolError as e:
|
153
|
+
raise ToolError(e)
|
147
154
|
except Exception as e:
|
148
155
|
if hasattr(e, '__context__') and e.__context__:
|
149
|
-
raise
|
156
|
+
raise ToolError(e.__context__)
|
150
157
|
else:
|
151
|
-
raise e
|
158
|
+
raise ToolError(e)
|
152
159
|
|
153
160
|
|
154
161
|
@tl_mcp.tool()
|
@@ -167,12 +174,13 @@ async def louvain(
|
|
167
174
|
sc.tl.louvain(adata, **func_kwargs)
|
168
175
|
add_op_log(adata, sc.tl.louvain, func_kwargs)
|
169
176
|
return [generate_msg(request, adata, ads)]
|
177
|
+
except ToolError as e:
|
178
|
+
raise ToolError(e)
|
170
179
|
except Exception as e:
|
171
180
|
if hasattr(e, '__context__') and e.__context__:
|
172
|
-
raise
|
181
|
+
raise ToolError(e.__context__)
|
173
182
|
else:
|
174
|
-
raise e
|
175
|
-
|
183
|
+
raise ToolError(e)
|
176
184
|
|
177
185
|
@tl_mcp.tool()
|
178
186
|
async def dendrogram(
|
@@ -190,12 +198,13 @@ async def dendrogram(
|
|
190
198
|
sc.tl.dendrogram(adata, **func_kwargs)
|
191
199
|
add_op_log(adata, sc.tl.dendrogram, func_kwargs)
|
192
200
|
return [generate_msg(request, adata, ads)]
|
201
|
+
except ToolError as e:
|
202
|
+
raise ToolError(e)
|
193
203
|
except Exception as e:
|
194
204
|
if hasattr(e, '__context__') and e.__context__:
|
195
|
-
raise
|
205
|
+
raise ToolError(e.__context__)
|
196
206
|
else:
|
197
|
-
raise e
|
198
|
-
|
207
|
+
raise ToolError(e)
|
199
208
|
|
200
209
|
@tl_mcp.tool()
|
201
210
|
async def dpt(
|
@@ -213,11 +222,13 @@ async def dpt(
|
|
213
222
|
sc.tl.dpt(adata, **func_kwargs)
|
214
223
|
add_op_log(adata, sc.tl.dpt, func_kwargs)
|
215
224
|
return [generate_msg(request, adata, ads)]
|
225
|
+
except ToolError as e:
|
226
|
+
raise ToolError(e)
|
216
227
|
except Exception as e:
|
217
228
|
if hasattr(e, '__context__') and e.__context__:
|
218
|
-
raise
|
229
|
+
raise ToolError(e.__context__)
|
219
230
|
else:
|
220
|
-
raise e
|
231
|
+
raise ToolError(e)
|
221
232
|
|
222
233
|
|
223
234
|
@tl_mcp.tool()
|
@@ -236,11 +247,13 @@ async def paga(
|
|
236
247
|
sc.tl.paga(adata, **func_kwargs)
|
237
248
|
add_op_log(adata, sc.tl.paga, func_kwargs)
|
238
249
|
return [generate_msg(request, adata, ads)]
|
250
|
+
except ToolError as e:
|
251
|
+
raise ToolError(e)
|
239
252
|
except Exception as e:
|
240
253
|
if hasattr(e, '__context__') and e.__context__:
|
241
|
-
raise
|
254
|
+
raise ToolError(e.__context__)
|
242
255
|
else:
|
243
|
-
raise e
|
256
|
+
raise ToolError(e)
|
244
257
|
|
245
258
|
|
246
259
|
@tl_mcp.tool()
|
@@ -259,11 +272,13 @@ async def ingest(
|
|
259
272
|
sc.tl.ingest(adata, **func_kwargs)
|
260
273
|
add_op_log(adata, sc.tl.ingest, func_kwargs)
|
261
274
|
return [generate_msg(request, adata, ads)]
|
275
|
+
except ToolError as e:
|
276
|
+
raise ToolError(e)
|
262
277
|
except Exception as e:
|
263
278
|
if hasattr(e, '__context__') and e.__context__:
|
264
|
-
raise
|
279
|
+
raise ToolError(e.__context__)
|
265
280
|
else:
|
266
|
-
raise e
|
281
|
+
raise ToolError(e)
|
267
282
|
|
268
283
|
@tl_mcp.tool()
|
269
284
|
async def rank_genes_groups(
|
@@ -282,11 +297,13 @@ async def rank_genes_groups(
|
|
282
297
|
sc.tl.rank_genes_groups(adata, **func_kwargs)
|
283
298
|
add_op_log(adata, sc.tl.rank_genes_groups, func_kwargs)
|
284
299
|
return [generate_msg(request, adata, ads)]
|
300
|
+
except ToolError as e:
|
301
|
+
raise ToolError(e)
|
285
302
|
except Exception as e:
|
286
303
|
if hasattr(e, '__context__') and e.__context__:
|
287
|
-
raise
|
304
|
+
raise ToolError(e.__context__)
|
288
305
|
else:
|
289
|
-
raise e
|
306
|
+
raise ToolError(e)
|
290
307
|
|
291
308
|
|
292
309
|
@tl_mcp.tool()
|
@@ -305,11 +322,13 @@ async def filter_rank_genes_groups(
|
|
305
322
|
sc.tl.filter_rank_genes_groups(adata, **func_kwargs)
|
306
323
|
add_op_log(adata, sc.tl.filter_rank_genes_groups, func_kwargs)
|
307
324
|
return [generate_msg(request, adata, ads)]
|
325
|
+
except ToolError as e:
|
326
|
+
raise ToolError(e)
|
308
327
|
except Exception as e:
|
309
328
|
if hasattr(e, '__context__') and e.__context__:
|
310
|
-
raise
|
329
|
+
raise ToolError(e.__context__)
|
311
330
|
else:
|
312
|
-
raise e
|
331
|
+
raise ToolError(e)
|
313
332
|
|
314
333
|
|
315
334
|
@tl_mcp.tool()
|
@@ -328,11 +347,13 @@ async def marker_gene_overlap(
|
|
328
347
|
sc.tl.marker_gene_overlap(adata, **func_kwargs)
|
329
348
|
add_op_log(adata, sc.tl.marker_gene_overlap, func_kwargs)
|
330
349
|
return [generate_msg(request, adata, ads)]
|
350
|
+
except ToolError as e:
|
351
|
+
raise ToolError(e)
|
331
352
|
except Exception as e:
|
332
353
|
if hasattr(e, '__context__') and e.__context__:
|
333
|
-
raise
|
354
|
+
raise ToolError(e.__context__)
|
334
355
|
else:
|
335
|
-
raise e
|
356
|
+
raise ToolError(e)
|
336
357
|
|
337
358
|
@tl_mcp.tool()
|
338
359
|
async def score_genes(
|
@@ -350,11 +371,13 @@ async def score_genes(
|
|
350
371
|
sc.tl.score_genes(adata, **func_kwargs)
|
351
372
|
add_op_log(adata, sc.tl.score_genes, func_kwargs)
|
352
373
|
return [generate_msg(request, adata, ads)]
|
374
|
+
except ToolError as e:
|
375
|
+
raise ToolError(e)
|
353
376
|
except Exception as e:
|
354
377
|
if hasattr(e, '__context__') and e.__context__:
|
355
|
-
raise
|
378
|
+
raise ToolError(e.__context__)
|
356
379
|
else:
|
357
|
-
raise e
|
380
|
+
raise ToolError(e)
|
358
381
|
|
359
382
|
@tl_mcp.tool()
|
360
383
|
async def score_genes_cell_cycle(
|
@@ -373,11 +396,13 @@ async def score_genes_cell_cycle(
|
|
373
396
|
sc.tl.score_genes_cell_cycle(adata, **func_kwargs)
|
374
397
|
add_op_log(adata, sc.tl.score_genes_cell_cycle, func_kwargs)
|
375
398
|
return [generate_msg(request, adata, ads)]
|
399
|
+
except ToolError as e:
|
400
|
+
raise ToolError(e)
|
376
401
|
except Exception as e:
|
377
402
|
if hasattr(e, '__context__') and e.__context__:
|
378
|
-
raise
|
403
|
+
raise ToolError(e.__context__)
|
379
404
|
else:
|
380
|
-
raise e
|
405
|
+
raise ToolError(e)
|
381
406
|
|
382
407
|
|
383
408
|
@tl_mcp.tool()
|
@@ -398,10 +423,10 @@ async def pca(
|
|
398
423
|
return [
|
399
424
|
generate_msg(request, adata, ads)
|
400
425
|
]
|
401
|
-
except
|
402
|
-
raise e
|
426
|
+
except ToolError as e:
|
427
|
+
raise ToolError(e)
|
403
428
|
except Exception as e:
|
404
429
|
if hasattr(e, '__context__') and e.__context__:
|
405
|
-
raise
|
430
|
+
raise ToolError(e.__context__)
|
406
431
|
else:
|
407
|
-
raise e
|
432
|
+
raise ToolError(e)
|
@@ -3,6 +3,7 @@ import inspect
|
|
3
3
|
from pathlib import Path
|
4
4
|
import scanpy as sc
|
5
5
|
from fastmcp import FastMCP , Context
|
6
|
+
from fastmcp.exceptions import ToolError
|
6
7
|
from ..schema.util import *
|
7
8
|
from ..util import filter_args, forward_request, get_ads, generate_msg,add_op_log
|
8
9
|
|
@@ -66,13 +67,13 @@ async def mark_var(
|
|
66
67
|
func_kwargs = {"var_name": var_name, "gene_class": gene_class, "pattern_type": pattern_type, "patterns": patterns}
|
67
68
|
add_op_log(adata, "mark_var", func_kwargs)
|
68
69
|
return res
|
69
|
-
except
|
70
|
-
raise e
|
70
|
+
except ToolError as e:
|
71
|
+
raise ToolError(e)
|
71
72
|
except Exception as e:
|
72
73
|
if hasattr(e, '__context__') and e.__context__:
|
73
|
-
raise
|
74
|
+
raise ToolError(e.__context__)
|
74
75
|
else:
|
75
|
-
raise e
|
76
|
+
raise ToolError(e)
|
76
77
|
|
77
78
|
|
78
79
|
@ul_mcp.tool()
|
@@ -88,13 +89,13 @@ async def list_var(
|
|
88
89
|
columns = list(adata.var.columns)
|
89
90
|
add_op_log(adata, list_var, {})
|
90
91
|
return columns
|
91
|
-
except
|
92
|
-
raise e
|
92
|
+
except ToolError as e:
|
93
|
+
raise ToolError(e)
|
93
94
|
except Exception as e:
|
94
95
|
if hasattr(e, '__context__') and e.__context__:
|
95
|
-
raise
|
96
|
+
raise ToolError(e.__context__)
|
96
97
|
else:
|
97
|
-
raise e
|
98
|
+
raise ToolError(e)
|
98
99
|
|
99
100
|
@ul_mcp.tool()
|
100
101
|
async def list_obs(
|
@@ -109,13 +110,13 @@ async def list_obs(
|
|
109
110
|
columns = list(adata.obs.columns)
|
110
111
|
add_op_log(adata, list_obs, {})
|
111
112
|
return columns
|
112
|
-
except
|
113
|
-
raise e
|
113
|
+
except ToolError as e:
|
114
|
+
raise ToolError(e)
|
114
115
|
except Exception as e:
|
115
116
|
if hasattr(e, '__context__') and e.__context__:
|
116
|
-
raise
|
117
|
+
raise ToolError(e.__context__)
|
117
118
|
else:
|
118
|
-
raise e
|
119
|
+
raise ToolError(e)
|
119
120
|
|
120
121
|
@ul_mcp.tool()
|
121
122
|
async def check_var(
|
@@ -131,13 +132,13 @@ async def check_var(
|
|
131
132
|
result = {v: v in adata.var_names for v in var_names}
|
132
133
|
add_op_log(adata, check_var, {"var_names": var_names})
|
133
134
|
return result
|
134
|
-
except
|
135
|
-
raise e
|
135
|
+
except ToolError as e:
|
136
|
+
raise ToolError(e)
|
136
137
|
except Exception as e:
|
137
138
|
if hasattr(e, '__context__') and e.__context__:
|
138
|
-
raise
|
139
|
+
raise ToolError(e.__context__)
|
139
140
|
else:
|
140
|
-
raise e
|
141
|
+
raise ToolError(e)
|
141
142
|
|
142
143
|
@ul_mcp.tool()
|
143
144
|
async def merge_adata(
|
@@ -158,13 +159,13 @@ async def merge_adata(
|
|
158
159
|
add_op_log(merged_adata, ad.concat, kwargs)
|
159
160
|
ads.adata_dic[ads.active_id] = merged_adata
|
160
161
|
return {"status": "success", "message": "Successfully merged all AnnData objects"}
|
161
|
-
except
|
162
|
-
raise e
|
162
|
+
except ToolError as e:
|
163
|
+
raise ToolError(e)
|
163
164
|
except Exception as e:
|
164
165
|
if hasattr(e, '__context__') and e.__context__:
|
165
|
-
raise
|
166
|
+
raise ToolError(e.__context__)
|
166
167
|
else:
|
167
|
-
raise e
|
168
|
+
raise ToolError(e)
|
168
169
|
|
169
170
|
|
170
171
|
@ul_mcp.tool()
|
@@ -192,13 +193,13 @@ async def set_dpt_iroot(
|
|
192
193
|
add_op_log(adata, "set_dpt_iroot", func_kwargs)
|
193
194
|
|
194
195
|
return {"status": "success", "message": f"Successfully set root cell for DPT using {direction} of dimension {dimension}"}
|
195
|
-
except
|
196
|
-
raise e
|
196
|
+
except ToolError as e:
|
197
|
+
raise ToolError(e)
|
197
198
|
except Exception as e:
|
198
199
|
if hasattr(e, '__context__') and e.__context__:
|
199
|
-
raise
|
200
|
+
raise ToolError(e.__context__)
|
200
201
|
else:
|
201
|
-
raise e
|
202
|
+
raise ToolError(e)
|
202
203
|
|
203
204
|
@ul_mcp.tool()
|
204
205
|
async def add_layer(
|
@@ -226,13 +227,13 @@ async def add_layer(
|
|
226
227
|
"status": "success",
|
227
228
|
"message": f"Successfully added layer '{layer_name}' to adata.layers"
|
228
229
|
}
|
229
|
-
except
|
230
|
-
raise e
|
230
|
+
except ToolError as e:
|
231
|
+
raise ToolError(e)
|
231
232
|
except Exception as e:
|
232
233
|
if hasattr(e, '__context__') and e.__context__:
|
233
|
-
raise
|
234
|
+
raise ToolError(e.__context__)
|
234
235
|
else:
|
235
|
-
raise e
|
236
|
+
raise ToolError(e)
|
236
237
|
|
237
238
|
@ul_mcp.tool()
|
238
239
|
async def check_samples():
|
@@ -241,10 +242,10 @@ async def check_samples():
|
|
241
242
|
try:
|
242
243
|
ads = get_ads()
|
243
244
|
return {"sampleid": [list(ads.adata_dic[dk].keys()) for dk in ads.adata_dic.keys()]}
|
244
|
-
except
|
245
|
-
raise e
|
245
|
+
except ToolError as e:
|
246
|
+
raise ToolError(e)
|
246
247
|
except Exception as e:
|
247
248
|
if hasattr(e, '__context__') and e.__context__:
|
248
|
-
raise
|
249
|
+
raise ToolError(e.__context__)
|
249
250
|
else:
|
250
|
-
raise e
|
251
|
+
raise ToolError(e)
|
@@ -2,7 +2,7 @@ import inspect
|
|
2
2
|
import os
|
3
3
|
from pathlib import Path
|
4
4
|
from fastmcp.server.dependencies import get_context
|
5
|
-
|
5
|
+
from fastmcp.exceptions import ToolError
|
6
6
|
|
7
7
|
|
8
8
|
def get_env(key):
|
@@ -50,6 +50,7 @@ def add_op_log(adata, func, kwargs):
|
|
50
50
|
hash_input = f"{func_name}:{kwargs_str}"
|
51
51
|
hash_key = hashlib.md5(hash_input.encode()).hexdigest()
|
52
52
|
adata.uns["operation"]["op"][hash_key] = {func_name: new_kwargs}
|
53
|
+
adata.uns["operation"]["opid"] = list(adata.uns["operation"]["opid"])
|
53
54
|
adata.uns["operation"]["opid"].append(hash_key)
|
54
55
|
from .logging_config import setup_logger
|
55
56
|
logger = setup_logger(log_file=get_env("LOG_FILE"))
|
@@ -151,8 +152,14 @@ async def forward_request(func, request, **kwargs):
|
|
151
152
|
try:
|
152
153
|
result = await client.call_tool(func, func_kwargs)
|
153
154
|
return result
|
155
|
+
except ToolError as e:
|
156
|
+
raise ToolError(e)
|
154
157
|
except Exception as e:
|
155
|
-
|
158
|
+
if hasattr(e, '__context__') and e.__context__:
|
159
|
+
raise Exception(f"{str(e.__context__)}")
|
160
|
+
else:
|
161
|
+
raise e
|
162
|
+
|
156
163
|
|
157
164
|
def obsm2adata(adata, obsm_key):
|
158
165
|
from anndata import AnnData
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|