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.
Files changed (22) hide show
  1. {scmcp_shared-0.2.0 → scmcp_shared-0.2.1}/PKG-INFO +1 -1
  2. scmcp_shared-0.2.1/src/scmcp_shared/__init__.py +3 -0
  3. {scmcp_shared-0.2.0 → scmcp_shared-0.2.1}/src/scmcp_shared/server/io.py +9 -4
  4. {scmcp_shared-0.2.0 → scmcp_shared-0.2.1}/src/scmcp_shared/server/pl.py +65 -62
  5. {scmcp_shared-0.2.0 → scmcp_shared-0.2.1}/src/scmcp_shared/server/pp.py +45 -40
  6. {scmcp_shared-0.2.0 → scmcp_shared-0.2.1}/src/scmcp_shared/server/tl.py +69 -44
  7. {scmcp_shared-0.2.0 → scmcp_shared-0.2.1}/src/scmcp_shared/server/util.py +33 -32
  8. {scmcp_shared-0.2.0 → scmcp_shared-0.2.1}/src/scmcp_shared/util.py +9 -2
  9. scmcp_shared-0.2.0/src/scmcp_shared/__init__.py +0 -3
  10. {scmcp_shared-0.2.0 → scmcp_shared-0.2.1}/.github/workflows/publish.yml +0 -0
  11. {scmcp_shared-0.2.0 → scmcp_shared-0.2.1}/LICENSE +0 -0
  12. {scmcp_shared-0.2.0 → scmcp_shared-0.2.1}/README.md +0 -0
  13. {scmcp_shared-0.2.0 → scmcp_shared-0.2.1}/pyproject.toml +0 -0
  14. {scmcp_shared-0.2.0 → scmcp_shared-0.2.1}/src/scmcp_shared/logging_config.py +0 -0
  15. {scmcp_shared-0.2.0 → scmcp_shared-0.2.1}/src/scmcp_shared/schema/__init__.py +0 -0
  16. {scmcp_shared-0.2.0 → scmcp_shared-0.2.1}/src/scmcp_shared/schema/base.py +0 -0
  17. {scmcp_shared-0.2.0 → scmcp_shared-0.2.1}/src/scmcp_shared/schema/io.py +0 -0
  18. {scmcp_shared-0.2.0 → scmcp_shared-0.2.1}/src/scmcp_shared/schema/pl.py +0 -0
  19. {scmcp_shared-0.2.0 → scmcp_shared-0.2.1}/src/scmcp_shared/schema/pp.py +0 -0
  20. {scmcp_shared-0.2.0 → scmcp_shared-0.2.1}/src/scmcp_shared/schema/tl.py +0 -0
  21. {scmcp_shared-0.2.0 → scmcp_shared-0.2.1}/src/scmcp_shared/schema/util.py +0 -0
  22. {scmcp_shared-0.2.0 → scmcp_shared-0.2.1}/src/scmcp_shared/server/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: scmcp_shared
3
- Version: 0.2.0
3
+ Version: 0.2.1
4
4
  Summary: A shared function libray for scmcphub
5
5
  Author-email: shuang <hsh-me@outlook.com>
6
6
  License: BSD 3-Clause License
@@ -0,0 +1,3 @@
1
+
2
+ __version__ = "0.2.1"
3
+
@@ -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 Exception(f"{str(e.__context__)}")
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 Exception(f"{str(e.__context__)}")
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 KeyError as e:
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 Exception(f"{str(e.__context__)}")
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 KeyError as e:
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 Exception(f"{str(e.__context__)}")
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 Exception(f"{str(e.__context__)}")
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 KeyError as e:
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 Exception(f"{str(e.__context__)}")
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 KeyError as e:
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 Exception(f"{str(e.__context__)}")
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 KeyError as e:
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 Exception(f"{str(e.__context__)}")
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 KeyError as e:
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 Exception(f"{str(e.__context__)}")
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 KeyError as e:
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 Exception(f"{str(e.__context__)}")
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 KeyError as e:
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 Exception(f"{str(e.__context__)}")
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 Exception(f"{str(e.__context__)}")
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 KeyError as e:
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 Exception(f"{str(e.__context__)}")
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 KeyError as e:
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 Exception(f"{str(e.__context__)}")
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 KeyError as e:
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 Exception(f"{str(e.__context__)}")
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 KeyError as e:
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 Exception(f"{str(e.__context__)}")
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 KeyError as e:
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 Exception(f"{str(e.__context__)}")
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 KeyError as e:
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 Exception(f"{str(e.__context__)}")
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 KeyError as e:
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 Exception(f"{str(e.__context__)}")
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 KeyError as e:
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 Exception(f"{str(e.__context__)}")
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 Exception(f"{str(e.__context__)}")
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 KeyError as e:
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 Exception(f"{str(e.__context__)}")
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 KeyError as e:
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 Exception(f"{str(e.__context__)}")
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 KeyError as e:
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 Exception(f"{str(e.__context__)}")
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 KeyError as e:
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 Exception(f"{str(e.__context__)}")
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 KeyError as e:
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 Exception(f"{str(e.__context__)}")
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 KeyError as e:
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 Exception(f"{str(e.__context__)}")
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 Exception(f"{str(e.__context__)}")
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 KeyError as e:
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 Exception(f"{str(e.__context__)}")
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 KeyError as e:
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 Exception(f"{str(e.__context__)}")
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 KeyError as e:
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 Exception(f"{str(e.__context__)}")
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 KeyError as e:
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 Exception(f"{str(e.__context__)}")
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 Exception(f"{str(e.__context__)}")
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 Exception(f"{str(e.__context__)}")
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 Exception(f"{str(e.__context__)}")
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 Exception(f"{str(e.__context__)}")
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 Exception(f"{str(e.__context__)}")
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 Exception(f"{str(e.__context__)}")
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 Exception(f"{str(e.__context__)}")
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 Exception(f"{str(e.__context__)}")
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 Exception(f"{str(e.__context__)}")
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 Exception(f"{str(e.__context__)}")
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 Exception(f"{str(e.__context__)}")
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 Exception(f"{str(e.__context__)}")
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 Exception(f"{str(e.__context__)}")
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 KeyError as e:
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 Exception(f"{str(e.__context__)}")
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 KeyError as e:
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 Exception(f"{str(e.__context__)}")
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 KeyError as e:
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 Exception(f"{str(e.__context__)}")
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 KeyError as e:
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 Exception(f"{str(e.__context__)}")
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 KeyError as e:
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 Exception(f"{str(e.__context__)}")
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 KeyError as e:
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 Exception(f"{str(e.__context__)}")
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 KeyError as e:
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 Exception(f"{str(e.__context__)}")
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 KeyError as e:
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 Exception(f"{str(e.__context__)}")
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 KeyError as e:
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 Exception(f"{str(e.__context__)}")
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
- raise e
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
@@ -1,3 +0,0 @@
1
-
2
- __version__ = "0.2.0"
3
-
File without changes
File without changes