@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
@@ -9,7 +9,7 @@ from ..config import DEFAULT_PROFILE
9
9
  from ..errors import QingflowApiError, backend_code_int, backend_code_value_int, is_auth_like_error, message_looks_like_invalid_token, raise_tool_error
10
10
  from ..json_types import JSONObject
11
11
  from ..list_type_labels import get_record_list_type_label
12
- from .base import ToolBase, tool_cn_name
12
+ from .base import ToolBase
13
13
 
14
14
 
15
15
  class ApprovalTools(ToolBase):
@@ -149,7 +149,6 @@ class ApprovalTools(ToolBase):
149
149
  keyword=keyword,
150
150
  )
151
151
 
152
- @tool_cn_name("写评论")
153
152
  def record_comment_write(self, *, profile: str, app_key: str, record_id: int, payload: dict[str, Any]) -> dict[str, Any]:
154
153
  """执行记录相关逻辑。"""
155
154
  raw = self.record_comment_add(profile=profile, app_key=app_key, apply_id=record_id, payload=payload)
@@ -160,7 +159,6 @@ class ApprovalTools(ToolBase):
160
159
  selection={},
161
160
  )
162
161
 
163
- @tool_cn_name("评论提及")
164
162
  def record_comment_mentions(
165
163
  self,
166
164
  *,
@@ -207,7 +205,6 @@ class ApprovalTools(ToolBase):
207
205
  selection=selection,
208
206
  )
209
207
 
210
- @tool_cn_name("任务通过")
211
208
  def task_approve(self, *, profile: str, app_key: str, record_id: int, payload: dict[str, Any], fields: dict[str, Any] | None = None) -> dict[str, Any]:
212
209
  """执行任务相关逻辑。"""
213
210
  if fields:
@@ -229,7 +226,6 @@ class ApprovalTools(ToolBase):
229
226
  human_review=True,
230
227
  )
231
228
 
232
- @tool_cn_name("任务拒绝")
233
229
  def task_reject(self, *, profile: str, app_key: str, record_id: int, payload: dict[str, Any], fields: dict[str, Any] | None = None) -> dict[str, Any]:
234
230
  """执行任务相关逻辑。"""
235
231
  if fields:
@@ -251,7 +247,6 @@ class ApprovalTools(ToolBase):
251
247
  human_review=True,
252
248
  )
253
249
 
254
- @tool_cn_name("任务退回候选")
255
250
  def task_rollback_candidates(self, *, profile: str, app_key: str, record_id: int, workflow_node_id: int) -> dict[str, Any]:
256
251
  """执行任务相关逻辑。"""
257
252
  selection = {"app_key": app_key, "record_id": record_id, "workflow_node_id": workflow_node_id}
@@ -274,7 +269,6 @@ class ApprovalTools(ToolBase):
274
269
  selection=selection,
275
270
  )
276
271
 
277
- @tool_cn_name("任务退回")
278
272
  def task_rollback(self, *, profile: str, app_key: str, record_id: int, payload: dict[str, Any], fields: dict[str, Any] | None = None) -> dict[str, Any]:
279
273
  """执行任务相关逻辑。"""
280
274
  if fields:
@@ -296,7 +290,6 @@ class ApprovalTools(ToolBase):
296
290
  human_review=True,
297
291
  )
298
292
 
299
- @tool_cn_name("任务转交")
300
293
  def task_transfer(self, *, profile: str, app_key: str, record_id: int, payload: dict[str, Any], fields: dict[str, Any] | None = None) -> dict[str, Any]:
301
294
  """执行任务相关逻辑。"""
302
295
  if fields:
@@ -319,7 +312,6 @@ class ApprovalTools(ToolBase):
319
312
  human_review=True,
320
313
  )
321
314
 
322
- @tool_cn_name("任务仅保存")
323
315
  def task_save_only(
324
316
  self,
325
317
  *,
@@ -341,7 +333,6 @@ class ApprovalTools(ToolBase):
341
333
  workflow_node_id=workflow_node_id,
342
334
  )
343
335
 
344
- @tool_cn_name("任务转交候选")
345
336
  def task_transfer_candidates(
346
337
  self,
347
338
  *,
@@ -390,7 +381,6 @@ class ApprovalTools(ToolBase):
390
381
  selection=selection,
391
382
  )
392
383
 
393
- @tool_cn_name("新增评论")
394
384
  def record_comment_add(self, *, profile: str, app_key: str, apply_id: int, payload: dict[str, Any]) -> dict[str, Any]:
395
385
  """执行记录相关逻辑。"""
396
386
  self._require_app_and_apply(app_key, apply_id)
@@ -407,9 +397,8 @@ class ApprovalTools(ToolBase):
407
397
  "request_route": self._request_route_payload(context),
408
398
  }
409
399
 
410
- return self._run(profile, runner)
400
+ return self._run(profile, runner, tool_name='新增评论')
411
401
 
412
- @tool_cn_name("评论列表")
413
402
  def record_comment_list(self, *, profile: str, app_key: str, apply_id: int, page_size: int = 20, list_type: int | None = None, page_num: int | None = 1) -> dict[str, Any]:
414
403
  """执行记录相关逻辑。"""
415
404
  self._require_app_and_apply(app_key, apply_id)
@@ -432,7 +421,7 @@ class ApprovalTools(ToolBase):
432
421
  "request_route": self._request_route_payload(context),
433
422
  }
434
423
 
435
- raw = self._run(profile, runner)
424
+ raw = self._run(profile, runner, tool_name='评论列表')
436
425
  items = _approval_page_items(raw.get("page"))
437
426
  return self._public_page_response(
438
427
  raw,
@@ -447,7 +436,6 @@ class ApprovalTools(ToolBase):
447
436
  selection={"app_key": app_key, "record_id": apply_id, "list_type": list_type},
448
437
  )
449
438
 
450
- @tool_cn_name("评论提及候选")
451
439
  def record_comment_mention_candidates(
452
440
  self,
453
441
  *,
@@ -480,9 +468,8 @@ class ApprovalTools(ToolBase):
480
468
  "request_route": self._request_route_payload(context),
481
469
  }
482
470
 
483
- return self._run(profile, runner)
471
+ return self._run(profile, runner, tool_name='评论提及候选')
484
472
 
485
- @tool_cn_name("评论标记已读")
486
473
  def record_comment_mark_read(self, *, profile: str, app_key: str, apply_id: int) -> dict[str, Any]:
487
474
  """执行记录相关逻辑。"""
488
475
  self._require_app_and_apply(app_key, apply_id)
@@ -498,7 +485,7 @@ class ApprovalTools(ToolBase):
498
485
  "request_route": self._request_route_payload(context),
499
486
  }
500
487
 
501
- raw = self._run(profile, runner)
488
+ raw = self._run(profile, runner, tool_name='评论标记已读')
502
489
  return self._public_action_response(
503
490
  raw,
504
491
  action="record_comment_mark_read",
@@ -506,7 +493,6 @@ class ApprovalTools(ToolBase):
506
493
  selection={},
507
494
  )
508
495
 
509
- @tool_cn_name("评论统计")
510
496
  def record_comment_stats(self, *, profile: str, app_key: str, apply_id: int) -> dict[str, Any]:
511
497
  """执行记录相关逻辑。"""
512
498
  self._require_app_and_apply(app_key, apply_id)
@@ -522,9 +508,8 @@ class ApprovalTools(ToolBase):
522
508
  "request_route": self._request_route_payload(context),
523
509
  }
524
510
 
525
- return self._run(profile, runner)
511
+ return self._run(profile, runner, tool_name='评论统计')
526
512
 
527
- @tool_cn_name("记录通过")
528
513
  def record_approve(self, *, profile: str, app_key: str, apply_id: int, payload: dict[str, Any]) -> dict[str, Any]:
529
514
  """执行记录相关逻辑。"""
530
515
  self._require_app_and_apply(app_key, apply_id)
@@ -544,9 +529,8 @@ class ApprovalTools(ToolBase):
544
529
  "request_route": self._request_route_payload(context),
545
530
  }
546
531
 
547
- return self._run(profile, runner)
532
+ return self._run(profile, runner, tool_name='记录通过')
548
533
 
549
- @tool_cn_name("记录拒绝")
550
534
  def record_reject(self, *, profile: str, app_key: str, apply_id: int, payload: dict[str, Any]) -> dict[str, Any]:
551
535
  """执行记录相关逻辑。"""
552
536
  self._require_app_and_apply(app_key, apply_id)
@@ -566,9 +550,8 @@ class ApprovalTools(ToolBase):
566
550
  "request_route": self._request_route_payload(context),
567
551
  }
568
552
 
569
- return self._run(profile, runner)
553
+ return self._run(profile, runner, tool_name='记录拒绝')
570
554
 
571
- @tool_cn_name("记录退回候选")
572
555
  def record_rollback_candidates(self, *, profile: str, app_key: str, apply_id: int, audit_node_id: int) -> dict[str, Any]:
573
556
  """执行记录相关逻辑。"""
574
557
  self._require_app_and_apply(app_key, apply_id)
@@ -591,9 +574,8 @@ class ApprovalTools(ToolBase):
591
574
  "request_route": self._request_route_payload(context),
592
575
  }
593
576
 
594
- return self._run(profile, runner)
577
+ return self._run(profile, runner, tool_name='记录退回候选')
595
578
 
596
- @tool_cn_name("记录退回")
597
579
  def record_rollback(self, *, profile: str, app_key: str, apply_id: int, payload: dict[str, Any]) -> dict[str, Any]:
598
580
  """执行记录相关逻辑。"""
599
581
  self._require_app_and_apply(app_key, apply_id)
@@ -611,9 +593,8 @@ class ApprovalTools(ToolBase):
611
593
  "request_route": self._request_route_payload(context),
612
594
  }
613
595
 
614
- return self._run(profile, runner)
596
+ return self._run(profile, runner, tool_name='记录退回')
615
597
 
616
- @tool_cn_name("记录转交")
617
598
  def record_transfer(self, *, profile: str, app_key: str, apply_id: int, payload: dict[str, Any]) -> dict[str, Any]:
618
599
  """执行记录相关逻辑。"""
619
600
  self._require_app_and_apply(app_key, apply_id)
@@ -631,9 +612,8 @@ class ApprovalTools(ToolBase):
631
612
  "request_route": self._request_route_payload(context),
632
613
  }
633
614
 
634
- return self._run(profile, runner)
615
+ return self._run(profile, runner, tool_name='记录转交')
635
616
 
636
- @tool_cn_name("记录转交候选")
637
617
  def record_transfer_candidates(
638
618
  self,
639
619
  *,
@@ -664,9 +644,8 @@ class ApprovalTools(ToolBase):
664
644
  "request_route": self._request_route_payload(context),
665
645
  }
666
646
 
667
- return self._run(profile, runner)
647
+ return self._run(profile, runner, tool_name='记录转交候选')
668
648
 
669
- @tool_cn_name("记录改派信息")
670
649
  def record_reassign_get(self, *, profile: str, app_key: str, apply_id: int) -> dict[str, Any]:
671
650
  """执行记录相关逻辑。"""
672
651
  self._require_app_and_apply(app_key, apply_id)
@@ -682,9 +661,8 @@ class ApprovalTools(ToolBase):
682
661
  "request_route": self._request_route_payload(context),
683
662
  }
684
663
 
685
- return self._run(profile, runner)
664
+ return self._run(profile, runner, tool_name='记录改派信息')
686
665
 
687
- @tool_cn_name("记录改派")
688
666
  def record_reassign(self, *, profile: str, app_key: str, apply_id: int, payload: dict[str, Any]) -> dict[str, Any]:
689
667
  """执行记录相关逻辑。"""
690
668
  self._require_app_and_apply(app_key, apply_id)
@@ -701,9 +679,8 @@ class ApprovalTools(ToolBase):
701
679
  "request_route": self._request_route_payload(context),
702
680
  }
703
681
 
704
- return self._run(profile, runner)
682
+ return self._run(profile, runner, tool_name='记录改派')
705
683
 
706
- @tool_cn_name("会签候选")
707
684
  def record_countersign_candidates(
708
685
  self,
709
686
  *,
@@ -734,9 +711,8 @@ class ApprovalTools(ToolBase):
734
711
  "request_route": self._request_route_payload(context),
735
712
  }
736
713
 
737
- return self._run(profile, runner)
714
+ return self._run(profile, runner, tool_name='会签候选')
738
715
 
739
- @tool_cn_name("会签")
740
716
  def record_countersign(self, *, profile: str, app_key: str, apply_id: int, payload: dict[str, Any]) -> dict[str, Any]:
741
717
  """执行记录相关逻辑。"""
742
718
  self._require_app_and_apply(app_key, apply_id)
@@ -754,7 +730,7 @@ class ApprovalTools(ToolBase):
754
730
  "request_route": self._request_route_payload(context),
755
731
  }
756
732
 
757
- return self._run(profile, runner)
733
+ return self._run(profile, runner, tool_name='会签')
758
734
 
759
735
  def _request_route_payload(self, context) -> JSONObject: # type: ignore[no-untyped-def]
760
736
  """执行内部辅助逻辑。"""
@@ -17,7 +17,7 @@ from ..config import (
17
17
  )
18
18
  from ..errors import QingflowApiError, backend_code_int, is_auth_like_error, raise_tool_error
19
19
  from ..session_store import SessionStore
20
- from .base import ToolBase, tool_cn_name
20
+ from .base import ToolBase
21
21
 
22
22
 
23
23
  class AuthTools(ToolBase):
@@ -75,7 +75,6 @@ class AuthTools(ToolBase):
75
75
  def auth_logout(profile: str = DEFAULT_PROFILE, forget_persisted: bool = False) -> dict[str, Any]:
76
76
  return self.auth_logout(profile=profile, forget_persisted=forget_persisted)
77
77
 
78
- @tool_cn_name("凭证登录")
79
78
  def auth_use_credential(
80
79
  self,
81
80
  *,
@@ -371,7 +370,6 @@ class AuthTools(ToolBase):
371
370
  return False
372
371
  return True
373
372
 
374
- @tool_cn_name("我的身份")
375
373
  def auth_whoami(self, *, profile: str = DEFAULT_PROFILE) -> dict[str, Any]:
376
374
  """执行认证与会话相关逻辑。"""
377
375
  def build_response(
@@ -503,7 +501,6 @@ class AuthTools(ToolBase):
503
501
  if error.looks_like_invalid_token():
504
502
  raise
505
503
 
506
- @tool_cn_name("退出登录")
507
504
  def auth_logout(self, *, profile: str = DEFAULT_PROFILE, forget_persisted: bool = False) -> dict[str, Any]:
508
505
  """执行认证与会话相关逻辑。"""
509
506
  if not self.sessions.has_profile(profile):
@@ -1,6 +1,5 @@
1
1
  from __future__ import annotations
2
2
 
3
- import inspect
4
3
  from contextvars import ContextVar
5
4
  from typing import Any, Callable, TypeVar
6
5
 
@@ -20,17 +19,6 @@ T = TypeVar("T")
20
19
  _RUN_DEPTH: ContextVar[int] = ContextVar("qingflow_mcp_tool_run_depth", default=0)
21
20
 
22
21
 
23
- def tool_cn_name(name: str) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
24
- """为 tools 方法声明中文展示名(用于计费 extraInfo 记录)。"""
25
- normalized = str(name).strip()
26
-
27
- def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
28
- setattr(func, "__tool_cn_name__", normalized)
29
- return func
30
-
31
- return decorator
32
-
33
-
34
22
  class ToolBase:
35
23
  def __init__(self, sessions: SessionStore, backend: BackendClient) -> None:
36
24
  self.sessions = sessions
@@ -62,19 +50,26 @@ class ToolBase:
62
50
  )
63
51
  return session_profile, backend_session, context
64
52
 
65
- def _run(self, profile: str, func: Callable[[SessionProfile, BackendRequestContext], T], *, require_workspace: bool = True) -> T:
53
+ def _run(
54
+ self,
55
+ profile: str,
56
+ func: Callable[[SessionProfile, BackendRequestContext], T],
57
+ *,
58
+ require_workspace: bool = True,
59
+ tool_name: str,
60
+ ) -> T:
66
61
  depth = _RUN_DEPTH.get()
67
62
  depth_token = _RUN_DEPTH.set(depth + 1)
68
63
  is_top_level_call = depth == 0
69
64
  session_profile: SessionProfile | None = None
70
65
  backend_session: BackendSession | None = None
71
- tool_name = self._resolve_calling_tool_name()
66
+ resolved_tool_name = self._normalize_tool_name(tool_name)
72
67
  try:
73
68
  session_profile, backend_session, context = self._require_context(profile, require_workspace=require_workspace)
74
69
  if is_top_level_call:
75
70
  self._charge_tool_call(
76
71
  profile=profile,
77
- tool_name=tool_name,
72
+ tool_name=resolved_tool_name,
78
73
  session_profile=session_profile,
79
74
  context=context,
80
75
  )
@@ -106,6 +101,12 @@ class ToolBase:
106
101
  _RUN_DEPTH.reset(depth_token)
107
102
  raise AssertionError("unreachable")
108
103
 
104
+ def _normalize_tool_name(self, tool_name: str) -> str:
105
+ normalized = str(tool_name or "").strip()
106
+ if not normalized:
107
+ raise_tool_error(QingflowApiError.config_error("tool_name is required for credit usage tracking"))
108
+ return normalized
109
+
109
110
  def _handle_error(self, profile: str, error: QingflowApiError) -> None:
110
111
  if error.looks_like_invalid_token():
111
112
  cloud_context = current_cloud_context.get()
@@ -221,25 +222,6 @@ class ToolBase:
221
222
  return None
222
223
  return parsed if parsed > 0 else None
223
224
 
224
- def _resolve_calling_tool_name(self) -> str:
225
- frame = inspect.currentframe()
226
- if frame is None:
227
- return "unknown_tool"
228
- caller = frame.f_back.f_back if frame.f_back is not None else None
229
- try:
230
- if caller is None:
231
- return "unknown_tool"
232
- name = caller.f_code.co_name
233
- if not name:
234
- return "unknown_tool"
235
- method = getattr(self, name, None)
236
- cn_name = getattr(method, "__tool_cn_name__", None)
237
- if isinstance(cn_name, str) and cn_name.strip():
238
- return cn_name.strip()
239
- return name
240
- finally:
241
- del frame
242
-
243
225
  def _charge_tool_call(
244
226
  self,
245
227
  *,
@@ -7,7 +7,6 @@ from mcp.server.fastmcp import FastMCP
7
7
  from ..config import DEFAULT_PROFILE, DEFAULT_RECORD_LIST_TYPE
8
8
  from ..errors import QingflowApiError, backend_code_int, backend_code_value_int, is_auth_like_error, message_looks_like_invalid_token, raise_tool_error
9
9
  from ..json_types import JSONObject, JSONValue
10
- from .base import tool_cn_name
11
10
  from .record_tools import (
12
11
  ATTACHMENT_QUE_TYPES,
13
12
  DEPARTMENT_QUE_TYPES,
@@ -156,7 +155,6 @@ class CodeBlockTools(RecordTools):
156
155
  output_profile=output_profile,
157
156
  )
158
157
 
159
- @tool_cn_name("代码块 Schema")
160
158
  def record_code_block_schema_get_public(
161
159
  self,
162
160
  *,
@@ -263,9 +261,8 @@ class CodeBlockTools(RecordTools):
263
261
  )
264
262
  return response
265
263
 
266
- return self._run_record_tool(profile, runner)
264
+ return self._run_record_tool(profile, runner, tool_name="代码块 Schema")
267
265
 
268
- @tool_cn_name("运行代码块")
269
266
  def record_code_block_run(
270
267
  self,
271
268
  *,
@@ -549,7 +546,7 @@ class CodeBlockTools(RecordTools):
549
546
  }
550
547
  return response
551
548
 
552
- return self._run_record_tool(profile, runner)
549
+ return self._run_record_tool(profile, runner, tool_name="运行代码块")
553
550
 
554
551
  def _resolve_code_block_field_for_run(self, selector: str | int, index: FieldIndex) -> FormField:
555
552
  field_id = _coerce_count(selector)
@@ -5,7 +5,7 @@ from copy import deepcopy
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 CustomButtonTools(ToolBase):
@@ -18,7 +18,6 @@ class CustomButtonTools(ToolBase):
18
18
  3. 支持草稿与发布态按钮配置维护。
19
19
  """
20
20
 
21
- @tool_cn_name("自定义按钮列表")
22
21
  def custom_button_list(
23
22
  self,
24
23
  *,
@@ -82,9 +81,8 @@ class CustomButtonTools(ToolBase):
82
81
  response["summary"] = items
83
82
  return response
84
83
 
85
- return self._run(profile, runner)
84
+ return self._run(profile, runner, tool_name='自定义按钮列表')
86
85
 
87
- @tool_cn_name("自定义按钮详情")
88
86
  def custom_button_get(
89
87
  self,
90
88
  *,
@@ -135,9 +133,8 @@ class CustomButtonTools(ToolBase):
135
133
  response["summary"] = self._compact_button_detail(result if isinstance(result, dict) else {})
136
134
  return response
137
135
 
138
- return self._run(profile, runner)
136
+ return self._run(profile, runner, tool_name='自定义按钮详情')
139
137
 
140
- @tool_cn_name("创建自定义按钮")
141
138
  def custom_button_create(self, *, profile: str, app_key: str, payload: JSONObject) -> JSONObject:
142
139
  """执行工具方法逻辑。"""
143
140
  self._require_app_key(app_key)
@@ -147,9 +144,8 @@ class CustomButtonTools(ToolBase):
147
144
  result = self.backend.request("POST", context, f"/app/{app_key}/customButton", json_body=deepcopy(body))
148
145
  return {"profile": profile, "ws_id": session_profile.selected_ws_id, "app_key": app_key, "result": result}
149
146
 
150
- return self._run(profile, runner)
147
+ return self._run(profile, runner, tool_name='创建自定义按钮')
151
148
 
152
- @tool_cn_name("更新自定义按钮")
153
149
  def custom_button_update(self, *, profile: str, app_key: str, button_id: int, payload: JSONObject) -> JSONObject:
154
150
  """执行工具方法逻辑。"""
155
151
  self._require_app_key(app_key)
@@ -175,9 +171,8 @@ class CustomButtonTools(ToolBase):
175
171
  target="custom button configuration",
176
172
  )
177
173
 
178
- return self._run(profile, runner)
174
+ return self._run(profile, runner, tool_name='更新自定义按钮')
179
175
 
180
- @tool_cn_name("删除自定义按钮")
181
176
  def custom_button_delete(self, *, profile: str, app_key: str, button_id: int) -> JSONObject:
182
177
  """执行工具方法逻辑。"""
183
178
  self._require_app_key(app_key)
@@ -197,7 +192,7 @@ class CustomButtonTools(ToolBase):
197
192
  target="custom button configuration",
198
193
  )
199
194
 
200
- return self._run(profile, runner)
195
+ return self._run(profile, runner, tool_name='删除自定义按钮')
201
196
 
202
197
  def _require_app_key(self, app_key: str) -> None:
203
198
  """执行内部辅助逻辑。"""
@@ -7,7 +7,7 @@ from mcp.server.fastmcp import FastMCP
7
7
 
8
8
  from ..config import DEFAULT_PROFILE
9
9
  from ..errors import QingflowApiError, backend_code_int, is_auth_like_error, raise_tool_error
10
- from .base import ToolBase, tool_cn_name
10
+ from .base import ToolBase
11
11
 
12
12
 
13
13
  ALLOWED_DIRECTORY_SEARCH_SCOPES = {"MEMBER", "DEPT"}
@@ -139,7 +139,6 @@ class DirectoryTools(ToolBase):
139
139
  page_size=page_size,
140
140
  )
141
141
 
142
- @tool_cn_name("通讯录搜索")
143
142
  def directory_search(
144
143
  self,
145
144
  *,
@@ -187,7 +186,7 @@ class DirectoryTools(ToolBase):
187
186
  "result": result,
188
187
  }
189
188
 
190
- raw = self._run(profile, runner)
189
+ raw = self._run(profile, runner, tool_name='通讯录搜索')
191
190
  items = [item for item in _directory_items(raw.get("result")) if isinstance(item, dict)]
192
191
  return self._public_directory_response(
193
192
  raw,
@@ -202,7 +201,6 @@ class DirectoryTools(ToolBase):
202
201
  selection={"query": query, "scopes": normalized_scopes},
203
202
  )
204
203
 
205
- @tool_cn_name("内部成员列表")
206
204
  def directory_list_internal_users(
207
205
  self,
208
206
  *,
@@ -246,7 +244,7 @@ class DirectoryTools(ToolBase):
246
244
  "result": result,
247
245
  }
248
246
 
249
- raw = self._run(profile, runner)
247
+ raw = self._run(profile, runner, tool_name='内部成员列表')
250
248
  items = [item for item in _directory_items(raw.get("result")) if isinstance(item, dict)]
251
249
  return self._public_directory_response(
252
250
  raw,
@@ -261,7 +259,6 @@ class DirectoryTools(ToolBase):
261
259
  selection={"keyword": keyword, "department_id": dept_id, "role_id": role_id, "include_disabled": contain_disable},
262
260
  )
263
261
 
264
- @tool_cn_name("内部成员全量")
265
262
  def directory_list_all_internal_users(
266
263
  self,
267
264
  *,
@@ -343,7 +340,7 @@ class DirectoryTools(ToolBase):
343
340
  },
344
341
  }
345
342
 
346
- raw = self._run(profile, runner)
343
+ raw = self._run(profile, runner, tool_name='内部成员全量')
347
344
  return self._public_directory_response(
348
345
  raw,
349
346
  items=[item for item in raw.get("items", []) if isinstance(item, dict)],
@@ -351,7 +348,6 @@ class DirectoryTools(ToolBase):
351
348
  selection={"keyword": keyword, "department_id": dept_id, "role_id": role_id, "include_disabled": contain_disable},
352
349
  )
353
350
 
354
- @tool_cn_name("内部部门列表")
355
351
  def directory_list_internal_departments(
356
352
  self,
357
353
  *,
@@ -408,7 +404,7 @@ class DirectoryTools(ToolBase):
408
404
  },
409
405
  }
410
406
 
411
- raw = self._run(profile, runner)
407
+ raw = self._run(profile, runner, tool_name='内部部门列表')
412
408
  items = [item for item in raw.get("items", []) if isinstance(item, dict)]
413
409
  return self._public_directory_response(
414
410
  raw,
@@ -449,7 +445,7 @@ class DirectoryTools(ToolBase):
449
445
  "result": result,
450
446
  }
451
447
 
452
- raw = self._run(profile, runner)
448
+ raw = self._run(profile, runner, tool_name='内部部门列表')
453
449
  items = [item for item in _directory_items(raw.get("page")) if isinstance(item, dict)]
454
450
  return self._public_directory_response(
455
451
  raw,
@@ -464,7 +460,6 @@ class DirectoryTools(ToolBase):
464
460
  selection={"keyword": normalized_keyword},
465
461
  )
466
462
 
467
- @tool_cn_name("部门树全量")
468
463
  def directory_list_all_departments(
469
464
  self,
470
465
  *,
@@ -519,7 +514,7 @@ class DirectoryTools(ToolBase):
519
514
  },
520
515
  }
521
516
 
522
- raw = self._run(profile, runner)
517
+ raw = self._run(profile, runner, tool_name='部门树全量')
523
518
  return self._public_directory_response(
524
519
  raw,
525
520
  items=[item for item in raw.get("items", []) if isinstance(item, dict)],
@@ -527,7 +522,6 @@ class DirectoryTools(ToolBase):
527
522
  selection={"parent_department_id": parent_dept_id, "max_depth": max_depth, "max_items": max_items},
528
523
  )
529
524
 
530
- @tool_cn_name("子部门列表")
531
525
  def directory_list_sub_departments(self, *, profile: str, parent_dept_id: int | None) -> dict[str, Any]:
532
526
  """执行组织目录相关逻辑。"""
533
527
  def runner(session_profile, context):
@@ -553,7 +547,7 @@ class DirectoryTools(ToolBase):
553
547
  "items": result,
554
548
  }
555
549
 
556
- raw = self._run(profile, runner)
550
+ raw = self._run(profile, runner, tool_name='子部门列表')
557
551
  items = [item for item in raw.get("items", []) if isinstance(item, dict)]
558
552
  return self._public_directory_response(
559
553
  raw,
@@ -562,7 +556,6 @@ class DirectoryTools(ToolBase):
562
556
  selection={"parent_department_id": parent_dept_id},
563
557
  )
564
558
 
565
- @tool_cn_name("外部联系人列表")
566
559
  def directory_list_external_members(
567
560
  self,
568
561
  *,
@@ -618,7 +611,7 @@ class DirectoryTools(ToolBase):
618
611
  "simple": simple,
619
612
  }
620
613
 
621
- raw = self._run(profile, runner)
614
+ raw = self._run(profile, runner, tool_name='外部联系人列表')
622
615
  items = [item for item in _directory_items(raw.get("page")) if isinstance(item, dict)]
623
616
  return self._public_directory_response(
624
617
  raw,