@qingflow-tech/qingflow-cli 1.1.38 → 1.1.40

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 (31) hide show
  1. package/README.md +7 -3
  2. package/package.json +1 -1
  3. package/pyproject.toml +1 -1
  4. package/src/qingflow_mcp/builder_facade/service.py +8 -8
  5. package/src/qingflow_mcp/server_cloud.py +89 -3
  6. package/src/qingflow_mcp/tools/ai_builder_tools.py +1 -59
  7. package/src/qingflow_mcp/tools/app_tools.py +15 -29
  8. package/src/qingflow_mcp/tools/approval_tools.py +16 -40
  9. package/src/qingflow_mcp/tools/auth_tools.py +1 -4
  10. package/src/qingflow_mcp/tools/base.py +16 -34
  11. package/src/qingflow_mcp/tools/code_block_tools.py +2 -5
  12. package/src/qingflow_mcp/tools/custom_button_tools.py +6 -11
  13. package/src/qingflow_mcp/tools/directory_tools.py +9 -16
  14. package/src/qingflow_mcp/tools/export_tools.py +5 -9
  15. package/src/qingflow_mcp/tools/feedback_tools.py +0 -2
  16. package/src/qingflow_mcp/tools/file_tools.py +3 -5
  17. package/src/qingflow_mcp/tools/import_tools.py +7 -13
  18. package/src/qingflow_mcp/tools/navigation_tools.py +12 -23
  19. package/src/qingflow_mcp/tools/package_tools.py +11 -21
  20. package/src/qingflow_mcp/tools/portal_tools.py +9 -17
  21. package/src/qingflow_mcp/tools/qingbi_report_tools.py +18 -23
  22. package/src/qingflow_mcp/tools/record_tools.py +97 -53
  23. package/src/qingflow_mcp/tools/repository_dev_tools.py +4 -7
  24. package/src/qingflow_mcp/tools/resource_read_tools.py +6 -9
  25. package/src/qingflow_mcp/tools/role_tools.py +5 -9
  26. package/src/qingflow_mcp/tools/solution_tools.py +4 -16
  27. package/src/qingflow_mcp/tools/task_context_tools.py +6 -12
  28. package/src/qingflow_mcp/tools/task_tools.py +12 -29
  29. package/src/qingflow_mcp/tools/view_tools.py +23 -32
  30. package/src/qingflow_mcp/tools/workflow_tools.py +30 -47
  31. package/src/qingflow_mcp/tools/workspace_tools.py +5 -9
@@ -16,7 +16,7 @@ from ..config import DEFAULT_PROFILE, DEFAULT_RECORD_LIST_TYPE
16
16
  from ..errors import QingflowApiError, backend_code_int, is_auth_like_error, message_looks_like_invalid_token
17
17
  from ..export_store import ExportJobStore
18
18
  from ..json_types import JSONObject
19
- from .base import ToolBase, tool_cn_name
19
+ from .base import ToolBase
20
20
  from .record_tools import (
21
21
  AccessibleViewRoute,
22
22
  DEFAULT_LIST_PAGE_SIZE,
@@ -131,7 +131,6 @@ class ExportTools(ToolBase):
131
131
  wait_timeout_seconds=wait_timeout_seconds,
132
132
  )
133
133
 
134
- @tool_cn_name("记录导出启动")
135
134
  def record_export_start(
136
135
  self,
137
136
  *,
@@ -277,7 +276,7 @@ class ExportTools(ToolBase):
277
276
  }
278
277
 
279
278
  try:
280
- return self._run(profile, runner)
279
+ return self._run(profile, runner, tool_name='记录导出启动')
281
280
  except RuntimeError as exc:
282
281
  return self._runtime_error_as_result(
283
282
  exc,
@@ -285,7 +284,6 @@ class ExportTools(ToolBase):
285
284
  extra={"app_key": normalized_app_key, "view_id": normalized_view_id},
286
285
  )
287
286
 
288
- @tool_cn_name("记录导出状态")
289
287
  def record_export_status_get(
290
288
  self,
291
289
  *,
@@ -318,7 +316,7 @@ class ExportTools(ToolBase):
318
316
  return self._status_payload_from_snapshot(local_job, normalized_handle, snapshot)
319
317
 
320
318
  try:
321
- return self._run(profile, runner)
319
+ return self._run(profile, runner, tool_name='记录导出状态')
322
320
  except RuntimeError as exc:
323
321
  return self._runtime_error_as_result(
324
322
  exc,
@@ -326,7 +324,6 @@ class ExportTools(ToolBase):
326
324
  extra={"export_handle": normalized_handle},
327
325
  )
328
326
 
329
- @tool_cn_name("记录导出结果")
330
327
  def record_export_get(
331
328
  self,
332
329
  *,
@@ -454,7 +451,7 @@ class ExportTools(ToolBase):
454
451
  }
455
452
 
456
453
  try:
457
- return self._run(profile, runner)
454
+ return self._run(profile, runner, tool_name='记录导出结果')
458
455
  except RuntimeError as exc:
459
456
  return self._runtime_error_as_result(
460
457
  exc,
@@ -462,7 +459,6 @@ class ExportTools(ToolBase):
462
459
  extra={"export_handle": normalized_handle},
463
460
  )
464
461
 
465
- @tool_cn_name("记录直接导出")
466
462
  def record_export_direct(
467
463
  self,
468
464
  *,
@@ -637,7 +633,7 @@ class ExportTools(ToolBase):
637
633
  }
638
634
 
639
635
  try:
640
- return self._run(profile, runner)
636
+ return self._run(profile, runner, tool_name='记录直接导出')
641
637
  except RuntimeError as exc:
642
638
  return self._runtime_error_as_result(
643
639
  exc,
@@ -8,7 +8,6 @@ from ..backend_client import BackendClient
8
8
  from ..config import get_feedback_app_key, get_feedback_base_url, get_feedback_qsource_token, normalize_base_url
9
9
  from ..errors import QingflowApiError, raise_tool_error
10
10
  from ..json_types import JSONObject
11
- from .base import tool_cn_name
12
11
 
13
12
 
14
13
  CATEGORY_MAP = {
@@ -68,7 +67,6 @@ class FeedbackTools:
68
67
  note=note,
69
68
  )
70
69
 
71
- @tool_cn_name("提交反馈")
72
70
  def feedback_submit(
73
71
  self,
74
72
  *,
@@ -14,7 +14,7 @@ from mcp.server.fastmcp import FastMCP
14
14
  from ..config import DEFAULT_PROFILE
15
15
  from ..errors import QingflowApiError, backend_code_int, is_auth_like_error, raise_tool_error
16
16
  from ..json_types import JSONObject
17
- from .base import ToolBase, tool_cn_name
17
+ from .base import ToolBase
18
18
 
19
19
 
20
20
  ATTACHMENT_UPLOAD_INFO_FALLBACK_CODES = {40118}
@@ -79,7 +79,6 @@ class FileTools(ToolBase):
79
79
  file_related_url=file_related_url,
80
80
  )
81
81
 
82
- @tool_cn_name("文件上传信息")
83
82
  def file_get_upload_info(
84
83
  self,
85
84
  *,
@@ -120,9 +119,8 @@ class FileTools(ToolBase):
120
119
  "result": upload_info["result"],
121
120
  }
122
121
 
123
- return self._run(profile, runner)
122
+ return self._run(profile, runner, tool_name='文件上传信息')
124
123
 
125
- @tool_cn_name("本地文件上传")
126
124
  def file_upload_local(
127
125
  self,
128
126
  *,
@@ -204,7 +202,7 @@ class FileTools(ToolBase):
204
202
  },
205
203
  }
206
204
 
207
- return self._run(profile, runner)
205
+ return self._run(profile, runner, tool_name='本地文件上传')
208
206
 
209
207
  def _build_file_upload_bo(
210
208
  self,
@@ -21,7 +21,7 @@ from ..errors import QingflowApiError, backend_code_int, is_auth_like_error, mes
21
21
  from ..import_store import ImportJobStore, ImportVerificationStore
22
22
  from ..json_types import JSONObject
23
23
  from .app_tools import _derive_import_capability
24
- from .base import ToolBase, tool_cn_name
24
+ from .base import ToolBase
25
25
  from .file_tools import FileTools
26
26
  from .record_tools import RecordTools, _build_field_index, _normalize_form_schema
27
27
 
@@ -174,7 +174,6 @@ class ImportTools(ToolBase):
174
174
  process_id_str=process_id_str,
175
175
  )
176
176
 
177
- @tool_cn_name("导入 Schema")
178
177
  def record_import_schema_get(
179
178
  self,
180
179
  *,
@@ -259,9 +258,8 @@ class ImportTools(ToolBase):
259
258
  response["import_capability"] = import_capability
260
259
  return response
261
260
 
262
- return self._run(profile, runner)
261
+ return self._run(profile, runner, tool_name='导入 Schema')
263
262
 
264
- @tool_cn_name("导入模板")
265
263
  def record_import_template_get(
266
264
  self,
267
265
  *,
@@ -386,11 +384,10 @@ class ImportTools(ToolBase):
386
384
  }
387
385
 
388
386
  try:
389
- return self._run(profile, runner)
387
+ return self._run(profile, runner, tool_name='导入模板')
390
388
  except RuntimeError as exc:
391
389
  return self._runtime_error_as_result(exc, error_code="IMPORT_TEMPLATE_UNAUTHORIZED")
392
390
 
393
- @tool_cn_name("导入校验")
394
391
  def record_import_verify(
395
392
  self,
396
393
  *,
@@ -612,7 +609,7 @@ class ImportTools(ToolBase):
612
609
  }
613
610
 
614
611
  try:
615
- return self._run(profile, runner)
612
+ return self._run(profile, runner, tool_name='导入校验')
616
613
  except RuntimeError as exc:
617
614
  return self._runtime_error_as_result(
618
615
  exc,
@@ -620,7 +617,6 @@ class ImportTools(ToolBase):
620
617
  extra={"can_import": _runtime_import_can_import_value(exc)},
621
618
  )
622
619
 
623
- @tool_cn_name("导入修复")
624
620
  def record_import_repair_local(
625
621
  self,
626
622
  *,
@@ -727,11 +723,10 @@ class ImportTools(ToolBase):
727
723
  }
728
724
 
729
725
  try:
730
- return self._run(profile, runner)
726
+ return self._run(profile, runner, tool_name='导入修复')
731
727
  except RuntimeError as exc:
732
728
  return self._runtime_error_as_result(exc, error_code="IMPORT_REPAIR_FORMAT_UNSUPPORTED")
733
729
 
734
- @tool_cn_name("开始导入")
735
730
  def record_import_start(
736
731
  self,
737
732
  *,
@@ -848,11 +843,10 @@ class ImportTools(ToolBase):
848
843
  }
849
844
 
850
845
  try:
851
- return self._run(profile, runner)
846
+ return self._run(profile, runner, tool_name='开始导入')
852
847
  except RuntimeError as exc:
853
848
  return self._runtime_error_as_result(exc, error_code="IMPORT_VERIFICATION_FAILED", extra={"accepted": False})
854
849
 
855
- @tool_cn_name("导入状态")
856
850
  def record_import_status_get(
857
851
  self,
858
852
  *,
@@ -1048,7 +1042,7 @@ class ImportTools(ToolBase):
1048
1042
  }
1049
1043
 
1050
1044
  try:
1051
- return self._run(profile, runner)
1045
+ return self._run(profile, runner, tool_name='导入状态')
1052
1046
  except RuntimeError as exc:
1053
1047
  return self._runtime_error_as_result(
1054
1048
  exc,
@@ -5,7 +5,7 @@ from mcp.server.fastmcp import FastMCP
5
5
  from ..config import DEFAULT_PROFILE
6
6
  from ..errors import QingflowApiError, backend_code_int, is_auth_like_error, raise_tool_error
7
7
  from ..json_types import JSONObject
8
- from .base import ToolBase, tool_cn_name
8
+ from .base import ToolBase
9
9
 
10
10
 
11
11
  class NavigationTools(ToolBase):
@@ -69,16 +69,14 @@ class NavigationTools(ToolBase):
69
69
  def navigation_reorder(profile: str = DEFAULT_PROFILE, payload: list[JSONObject] | None = None) -> JSONObject:
70
70
  return self.navigation_reorder(profile=profile, payload=payload or [])
71
71
 
72
- @tool_cn_name("导航已发布列表")
73
72
  def navigation_list_published(self, *, profile: str, page_num: int = 1, page_size: int = 50) -> JSONObject:
74
73
  """执行工具方法逻辑。"""
75
74
  def runner(session_profile, context):
76
75
  result = self.backend.request("GET", context, "/navigation", params={"pageNum": page_num, "pageSize": page_size})
77
76
  return {"profile": profile, "ws_id": session_profile.selected_ws_id, "page": result}
78
77
 
79
- return self._run(profile, runner)
78
+ return self._run(profile, runner, tool_name='导航已发布列表')
80
79
 
81
- @tool_cn_name("导航草稿分页")
82
80
  def navigation_list_draft_page(self, *, profile: str, page_num: int = 1, page_size: int = 50, query_key: str | None = None) -> JSONObject:
83
81
  """执行工具方法逻辑。"""
84
82
  def runner(session_profile, context):
@@ -106,9 +104,8 @@ class NavigationTools(ToolBase):
106
104
  response["verification"] = {"draft_readable": False, "published_fallback_used": True}
107
105
  return response
108
106
 
109
- return self._run(profile, runner)
107
+ return self._run(profile, runner, tool_name='导航草稿分页')
110
108
 
111
- @tool_cn_name("导航草稿全量")
112
109
  def navigation_list_draft_all(self, *, profile: str, query_key: str | None = None) -> JSONObject:
113
110
  """执行工具方法逻辑。"""
114
111
  def runner(session_profile, context):
@@ -136,9 +133,8 @@ class NavigationTools(ToolBase):
136
133
  response["verification"] = {"draft_readable": False, "published_fallback_used": True}
137
134
  return response
138
135
 
139
- return self._run(profile, runner)
136
+ return self._run(profile, runner, tool_name='导航草稿全量')
140
137
 
141
- @tool_cn_name("导航详情")
142
138
  def navigation_get_detail(self, *, profile: str, navigation_item_id: int, status: str = "draft") -> JSONObject:
143
139
  """执行工具方法逻辑。"""
144
140
  self._require_navigation_item_id(navigation_item_id)
@@ -178,18 +174,16 @@ class NavigationTools(ToolBase):
178
174
  response["verification"] = {"draft_readable": False, "published_fallback_used": True}
179
175
  return response
180
176
 
181
- return self._run(profile, runner)
177
+ return self._run(profile, runner, tool_name='导航详情')
182
178
 
183
- @tool_cn_name("导航发布状态")
184
179
  def navigation_get_status(self, *, profile: str) -> JSONObject:
185
180
  """执行工具方法逻辑。"""
186
181
  def runner(session_profile, context):
187
182
  result = self.backend.request("GET", context, "/navigation/status")
188
183
  return {"profile": profile, "ws_id": session_profile.selected_ws_id, "result": result}
189
184
 
190
- return self._run(profile, runner)
185
+ return self._run(profile, runner, tool_name='导航发布状态')
191
186
 
192
- @tool_cn_name("设置导航可见性")
193
187
  def navigation_set_visible(self, *, profile: str, payload: JSONObject) -> JSONObject:
194
188
  """执行工具方法逻辑。"""
195
189
  body = self._require_dict(payload)
@@ -198,9 +192,8 @@ class NavigationTools(ToolBase):
198
192
  result = self.backend.request("POST", context, "/navigation/visible", json_body=body)
199
193
  return {"profile": profile, "ws_id": session_profile.selected_ws_id, "result": result}
200
194
 
201
- return self._run(profile, runner)
195
+ return self._run(profile, runner, tool_name='设置导航可见性')
202
196
 
203
- @tool_cn_name("创建导航项")
204
197
  def navigation_create(self, *, profile: str, payload: JSONObject) -> JSONObject:
205
198
  """执行工具方法逻辑。"""
206
199
  body = self._require_dict(payload)
@@ -209,9 +202,8 @@ class NavigationTools(ToolBase):
209
202
  result = self.backend.request("POST", context, "/navigation", json_body=body)
210
203
  return {"profile": profile, "ws_id": session_profile.selected_ws_id, "result": result}
211
204
 
212
- return self._run(profile, runner)
205
+ return self._run(profile, runner, tool_name='创建导航项')
213
206
 
214
- @tool_cn_name("更新导航项")
215
207
  def navigation_update(self, *, profile: str, navigation_item_id: int, payload: JSONObject) -> JSONObject:
216
208
  """执行工具方法逻辑。"""
217
209
  self._require_navigation_item_id(navigation_item_id)
@@ -225,9 +217,8 @@ class NavigationTools(ToolBase):
225
217
  target="navigation item configuration",
226
218
  )
227
219
 
228
- return self._run(profile, runner)
220
+ return self._run(profile, runner, tool_name='更新导航项')
229
221
 
230
- @tool_cn_name("删除导航项")
231
222
  def navigation_delete(self, *, profile: str, navigation_item_id: int) -> JSONObject:
232
223
  """执行工具方法逻辑。"""
233
224
  self._require_navigation_item_id(navigation_item_id)
@@ -240,9 +231,8 @@ class NavigationTools(ToolBase):
240
231
  target="navigation item configuration",
241
232
  )
242
233
 
243
- return self._run(profile, runner)
234
+ return self._run(profile, runner, tool_name='删除导航项')
244
235
 
245
- @tool_cn_name("发布导航")
246
236
  def navigation_publish(self, *, profile: str, navigation_id: int) -> JSONObject:
247
237
  """执行工具方法逻辑。"""
248
238
  if navigation_id <= 0:
@@ -252,9 +242,8 @@ class NavigationTools(ToolBase):
252
242
  result = self.backend.request("POST", context, f"/navigation/publish/{navigation_id}")
253
243
  return {"profile": profile, "ws_id": session_profile.selected_ws_id, "navigation_id": navigation_id, "result": result}
254
244
 
255
- return self._run(profile, runner)
245
+ return self._run(profile, runner, tool_name='发布导航')
256
246
 
257
- @tool_cn_name("导航排序")
258
247
  def navigation_reorder(self, *, profile: str, payload: list[JSONObject]) -> JSONObject:
259
248
  """执行工具方法逻辑。"""
260
249
  if not isinstance(payload, list) or not payload:
@@ -264,7 +253,7 @@ class NavigationTools(ToolBase):
264
253
  result = self.backend.request("POST", context, "/navigation/ordinal", json_body=payload)
265
254
  return {"profile": profile, "ws_id": session_profile.selected_ws_id, "result": result}
266
255
 
267
- return self._run(profile, runner)
256
+ return self._run(profile, runner, tool_name='导航排序')
268
257
 
269
258
  def _require_navigation_item_id(self, navigation_item_id: int) -> None:
270
259
  """执行内部辅助逻辑。"""
@@ -8,7 +8,7 @@ from ..config import DEFAULT_PROFILE
8
8
  from ..errors import QingflowApiError, backend_code_int, is_auth_like_error, raise_tool_error
9
9
  from ..json_types import JSONObject
10
10
  from ..solution.compiler.icon_utils import workspace_icon_config
11
- from .base import ToolBase, tool_cn_name
11
+ from .base import ToolBase
12
12
 
13
13
 
14
14
  class PackageTools(ToolBase):
@@ -47,7 +47,6 @@ class PackageTools(ToolBase):
47
47
  def package_delete(profile: str = DEFAULT_PROFILE, tag_id: int = 0, deleted_all_data: bool = False) -> JSONObject:
48
48
  return self.package_delete(profile=profile, tag_id=tag_id, deleted_all_data=deleted_all_data)
49
49
 
50
- @tool_cn_name("分组列表")
51
50
  def package_list(self, *, profile: str, trial_status: str = "all", include_raw: bool = False) -> JSONObject:
52
51
  """执行分组与包相关逻辑。"""
53
52
  def runner(session_profile, context):
@@ -68,9 +67,8 @@ class PackageTools(ToolBase):
68
67
  response["summary"] = compact_items
69
68
  return response
70
69
 
71
- return self._run(profile, runner)
70
+ return self._run(profile, runner, tool_name='分组列表')
72
71
 
73
- @tool_cn_name("分组详情")
74
72
  def package_get(self, *, profile: str, tag_id: int, include_raw: bool = False) -> JSONObject:
75
73
  """执行分组与包相关逻辑。"""
76
74
  self._require_tag_id(tag_id)
@@ -133,9 +131,8 @@ class PackageTools(ToolBase):
133
131
  response["summary"] = compact
134
132
  return response
135
133
 
136
- return self._run(profile, runner)
134
+ return self._run(profile, runner, tool_name='分组详情')
137
135
 
138
- @tool_cn_name("分组基础信息")
139
136
  def package_get_base(self, *, profile: str, tag_id: int, include_raw: bool = False) -> JSONObject:
140
137
  """执行分组与包相关逻辑。"""
141
138
  self._require_readable_tag_id(tag_id)
@@ -177,9 +174,8 @@ class PackageTools(ToolBase):
177
174
  response["summary"] = compact
178
175
  return response
179
176
 
180
- return self._run(profile, runner)
177
+ return self._run(profile, runner, tool_name='分组基础信息')
181
178
 
182
- @tool_cn_name("创建分组")
183
179
  def package_create(self, *, profile: str, payload: JSONObject) -> JSONObject:
184
180
  """执行分组与包相关逻辑。"""
185
181
  body = self._require_dict(payload)
@@ -188,9 +184,8 @@ class PackageTools(ToolBase):
188
184
  result = self.backend.request("POST", context, "/tag", json_body=self._normalize_package_payload(body))
189
185
  return {"profile": profile, "ws_id": session_profile.selected_ws_id, "result": result}
190
186
 
191
- return self._run(profile, runner)
187
+ return self._run(profile, runner, tool_name='创建分组')
192
188
 
193
- @tool_cn_name("更新分组")
194
189
  def package_update(self, *, profile: str, tag_id: int, payload: JSONObject) -> JSONObject:
195
190
  """执行分组与包相关逻辑。"""
196
191
  self._require_tag_id(tag_id)
@@ -239,9 +234,8 @@ class PackageTools(ToolBase):
239
234
  target="app package settings",
240
235
  )
241
236
 
242
- return self._run(profile, runner)
237
+ return self._run(profile, runner, tool_name='更新分组')
243
238
 
244
- @tool_cn_name("分组排序")
245
239
  def package_sort_items(self, *, profile: str, tag_id: int, tag_items: list[JSONObject]) -> JSONObject:
246
240
  """执行分组与包相关逻辑。"""
247
241
  self._require_tag_id(tag_id)
@@ -255,9 +249,8 @@ class PackageTools(ToolBase):
255
249
  )
256
250
  return {"profile": profile, "ws_id": session_profile.selected_ws_id, "tag_id": tag_id, "result": result}
257
251
 
258
- return self._run(profile, runner)
252
+ return self._run(profile, runner, tool_name='分组排序')
259
253
 
260
- @tool_cn_name("创建分组分栏")
261
254
  def package_group_create(self, *, profile: str, tag_id: int, group_name: str) -> JSONObject:
262
255
  """执行分组与包相关逻辑。"""
263
256
  self._require_tag_id(tag_id)
@@ -274,9 +267,8 @@ class PackageTools(ToolBase):
274
267
  )
275
268
  return {"profile": profile, "ws_id": session_profile.selected_ws_id, "tag_id": tag_id, "result": result}
276
269
 
277
- return self._run(profile, runner)
270
+ return self._run(profile, runner, tool_name='创建分组分栏')
278
271
 
279
- @tool_cn_name("更新分组分栏")
280
272
  def package_group_update(self, *, profile: str, tag_id: int, group_id: int, group_name: str) -> JSONObject:
281
273
  """执行分组与包相关逻辑。"""
282
274
  self._require_tag_id(tag_id)
@@ -294,9 +286,8 @@ class PackageTools(ToolBase):
294
286
  )
295
287
  return {"profile": profile, "ws_id": session_profile.selected_ws_id, "tag_id": tag_id, "group_id": group_id, "result": result}
296
288
 
297
- return self._run(profile, runner)
289
+ return self._run(profile, runner, tool_name='更新分组分栏')
298
290
 
299
- @tool_cn_name("删除分组分栏")
300
291
  def package_group_delete(self, *, profile: str, tag_id: int, group_id: int) -> JSONObject:
301
292
  """执行分组与包相关逻辑。"""
302
293
  self._require_tag_id(tag_id)
@@ -306,9 +297,8 @@ class PackageTools(ToolBase):
306
297
  result = self.backend.request("DELETE", context, f"/tag/{tag_id}/group/{group_id}")
307
298
  return {"profile": profile, "ws_id": session_profile.selected_ws_id, "tag_id": tag_id, "group_id": group_id, "result": result}
308
299
 
309
- return self._run(profile, runner)
300
+ return self._run(profile, runner, tool_name='删除分组分栏')
310
301
 
311
- @tool_cn_name("删除分组")
312
302
  def package_delete(self, *, profile: str, tag_id: int, deleted_all_data: bool = False) -> JSONObject:
313
303
  """执行分组与包相关逻辑。"""
314
304
  self._require_tag_id(tag_id)
@@ -326,7 +316,7 @@ class PackageTools(ToolBase):
326
316
  target="app package and linked data",
327
317
  )
328
318
 
329
- return self._run(profile, runner)
319
+ return self._run(profile, runner, tool_name='删除分组')
330
320
 
331
321
  def _require_tag_id(self, tag_id: int) -> None:
332
322
  """执行内部辅助逻辑。"""
@@ -5,7 +5,7 @@ from mcp.server.fastmcp import FastMCP
5
5
  from ..config import DEFAULT_PROFILE
6
6
  from ..errors import QingflowApiError, backend_code_int, is_auth_like_error, raise_tool_error
7
7
  from ..json_types import JSONObject
8
- from .base import ToolBase, tool_cn_name
8
+ from .base import ToolBase
9
9
 
10
10
 
11
11
  class PortalTools(ToolBase):
@@ -52,16 +52,14 @@ class PortalTools(ToolBase):
52
52
  def portal_publish(profile: str = DEFAULT_PROFILE, dash_key: str = "") -> JSONObject:
53
53
  return self.portal_publish(profile=profile, dash_key=dash_key)
54
54
 
55
- @tool_cn_name("门户列表")
56
55
  def portal_list(self, *, profile: str) -> JSONObject:
57
56
  """执行门户相关逻辑。"""
58
57
  def runner(session_profile, context):
59
58
  result = self.backend.request("GET", context, "/dash")
60
59
  return {"profile": profile, "ws_id": session_profile.selected_ws_id, "items": result}
61
60
 
62
- return self._run(profile, runner)
61
+ return self._run(profile, runner, tool_name='门户列表')
63
62
 
64
- @tool_cn_name("门户详情")
65
63
  def portal_get(self, *, profile: str, dash_key: str, being_draft: bool = False) -> JSONObject:
66
64
  """执行门户相关逻辑。"""
67
65
  self._require_dash_key(dash_key)
@@ -70,9 +68,8 @@ class PortalTools(ToolBase):
70
68
  result = self.backend.request("GET", context, f"/dash/{dash_key}", params={"beingDraft": being_draft})
71
69
  return {"profile": profile, "ws_id": session_profile.selected_ws_id, "dash_key": dash_key, "result": result}
72
70
 
73
- return self._run(profile, runner)
71
+ return self._run(profile, runner, tool_name='门户详情')
74
72
 
75
- @tool_cn_name("创建门户")
76
73
  def portal_create(self, *, profile: str, payload: JSONObject) -> JSONObject:
77
74
  """执行门户相关逻辑。"""
78
75
  body = self._require_dict(payload)
@@ -81,9 +78,8 @@ class PortalTools(ToolBase):
81
78
  result = self.backend.request("POST", context, "/dash", json_body=body)
82
79
  return {"profile": profile, "ws_id": session_profile.selected_ws_id, "result": result}
83
80
 
84
- return self._run(profile, runner)
81
+ return self._run(profile, runner, tool_name='创建门户')
85
82
 
86
- @tool_cn_name("门户基础信息")
87
83
  def portal_get_base_info(self, *, profile: str, dash_key: str) -> JSONObject:
88
84
  """执行门户相关逻辑。"""
89
85
  self._require_dash_key(dash_key)
@@ -121,9 +117,8 @@ class PortalTools(ToolBase):
121
117
  "verification": verification,
122
118
  }
123
119
 
124
- return self._run(profile, runner)
120
+ return self._run(profile, runner, tool_name='门户基础信息')
125
121
 
126
- @tool_cn_name("更新门户基础信息")
127
122
  def portal_update_base_info(self, *, profile: str, dash_key: str, payload: JSONObject) -> JSONObject:
128
123
  """执行门户相关逻辑。"""
129
124
  self._require_dash_key(dash_key)
@@ -137,9 +132,8 @@ class PortalTools(ToolBase):
137
132
  target="portal base settings",
138
133
  )
139
134
 
140
- return self._run(profile, runner)
135
+ return self._run(profile, runner, tool_name='更新门户基础信息')
141
136
 
142
- @tool_cn_name("更新门户配置")
143
137
  def portal_update(self, *, profile: str, dash_key: str, payload: JSONObject) -> JSONObject:
144
138
  """执行门户相关逻辑。"""
145
139
  self._require_dash_key(dash_key)
@@ -153,9 +147,8 @@ class PortalTools(ToolBase):
153
147
  target="portal configuration",
154
148
  )
155
149
 
156
- return self._run(profile, runner)
150
+ return self._run(profile, runner, tool_name='更新门户配置')
157
151
 
158
- @tool_cn_name("删除门户")
159
152
  def portal_delete(self, *, profile: str, dash_key: str) -> JSONObject:
160
153
  """执行门户相关逻辑。"""
161
154
  self._require_dash_key(dash_key)
@@ -168,9 +161,8 @@ class PortalTools(ToolBase):
168
161
  target="portal configuration",
169
162
  )
170
163
 
171
- return self._run(profile, runner)
164
+ return self._run(profile, runner, tool_name='删除门户')
172
165
 
173
- @tool_cn_name("发布门户")
174
166
  def portal_publish(self, *, profile: str, dash_key: str) -> JSONObject:
175
167
  """执行门户相关逻辑。"""
176
168
  self._require_dash_key(dash_key)
@@ -179,7 +171,7 @@ class PortalTools(ToolBase):
179
171
  result = self.backend.request("POST", context, f"/dash/{dash_key}/publish")
180
172
  return {"profile": profile, "ws_id": session_profile.selected_ws_id, "dash_key": dash_key, "result": result}
181
173
 
182
- return self._run(profile, runner)
174
+ return self._run(profile, runner, tool_name='发布门户')
183
175
 
184
176
  def _require_dash_key(self, dash_key: str) -> None:
185
177
  """执行内部辅助逻辑。"""