@josephyan/qingflow-app-user-mcp 0.2.0-beta.993 → 0.2.0-beta.994

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.
package/README.md CHANGED
@@ -3,13 +3,13 @@
3
3
  Install:
4
4
 
5
5
  ```bash
6
- npm install @josephyan/qingflow-app-user-mcp@0.2.0-beta.993
6
+ npm install @josephyan/qingflow-app-user-mcp@0.2.0-beta.994
7
7
  ```
8
8
 
9
9
  Run:
10
10
 
11
11
  ```bash
12
- npx -y -p @josephyan/qingflow-app-user-mcp@0.2.0-beta.993 qingflow-app-user-mcp
12
+ npx -y -p @josephyan/qingflow-app-user-mcp@0.2.0-beta.994 qingflow-app-user-mcp
13
13
  ```
14
14
 
15
15
  Environment:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@josephyan/qingflow-app-user-mcp",
3
- "version": "0.2.0-beta.993",
3
+ "version": "0.2.0-beta.994",
4
4
  "description": "Operational end-user MCP for Qingflow records, tasks, comments, and directory workflows.",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/pyproject.toml CHANGED
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "qingflow-mcp"
7
- version = "0.2.0b993"
7
+ version = "0.2.0b994"
8
8
  description = "User-authenticated MCP server for Qingflow"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -5,7 +5,7 @@ from pathlib import Path
5
5
 
6
6
  __all__ = ["__version__"]
7
7
 
8
- _FALLBACK_VERSION = "0.2.0b993"
8
+ _FALLBACK_VERSION = "0.2.0b994"
9
9
 
10
10
 
11
11
  def _resolve_local_pyproject_version() -> str | None:
@@ -173,20 +173,26 @@ def _format_record_list(result: dict[str, Any]) -> str:
173
173
  def _format_task_list(result: dict[str, Any]) -> str:
174
174
  data = result.get("data") if isinstance(result.get("data"), dict) else {}
175
175
  items = data.get("items") if isinstance(data.get("items"), list) else []
176
- rows = []
176
+ lines = ["Tasks"]
177
177
  for item in items:
178
178
  if not isinstance(item, dict):
179
179
  continue
180
- rows.append(
181
- [
182
- str(item.get("app_key") or ""),
183
- str(item.get("record_id") or ""),
184
- str(item.get("workflow_node_id") or ""),
185
- str(item.get("workflow_node_name") or ""),
186
- ]
180
+ lines.append(
181
+ "- "
182
+ + " / ".join(
183
+ [
184
+ str(item.get("app_key") or "-"),
185
+ str(item.get("record_id") or "-"),
186
+ str(item.get("workflow_node_id") or "-"),
187
+ str(item.get("workflow_node_name") or "-"),
188
+ ]
189
+ )
187
190
  )
188
- output = _render_titled_table("Tasks", ["app_key", "record_id", "node_id", "node_name"], rows)
189
- lines = output.rstrip("\n").split("\n")
191
+ summary_fields = item.get("summary_fields") if isinstance(item.get("summary_fields"), list) else []
192
+ for summary in summary_fields:
193
+ if not isinstance(summary, dict):
194
+ continue
195
+ lines.append(f" {summary.get('title') or '-'}: {summary.get('answer') or '-'}")
190
196
  _append_warnings(lines, result.get("warnings"))
191
197
  return "\n".join(lines) + "\n"
192
198
 
@@ -185,11 +185,7 @@ class TaskContextTools(ToolBase):
185
185
  )
186
186
  task_page = raw.get("page", {})
187
187
  warnings: list[dict[str, Any]] = []
188
- items = [
189
- self._normalize_task_item(item, task_box=task_box, flow_status=flow_status)
190
- for item in _task_page_items(task_page)
191
- if isinstance(item, dict)
192
- ]
188
+ items = [self._normalize_task_item(item) for item in _task_page_items(task_page) if isinstance(item, dict)]
193
189
  returned_items = len(items)
194
190
  page_amount = _task_page_amount(task_page)
195
191
  reported_total = _task_page_total(task_page)
@@ -235,8 +231,6 @@ class TaskContextTools(ToolBase):
235
231
  "reported_total": reported_total,
236
232
  },
237
233
  "selection": {
238
- "task_box": task_box,
239
- "flow_status": flow_status,
240
234
  "app_key": app_key,
241
235
  "workflow_node_id": workflow_node_id,
242
236
  "query": query,
@@ -1050,11 +1044,7 @@ class TaskContextTools(ToolBase):
1050
1044
  )
1051
1045
  task_page = raw.get("page", {})
1052
1046
  raw_items = _task_page_items(task_page)
1053
- normalized_items = [
1054
- self._normalize_task_item(item, task_box=task_box, flow_status=flow_status)
1055
- for item in raw_items
1056
- if isinstance(item, dict)
1057
- ]
1047
+ normalized_items = [self._normalize_task_item(item) for item in raw_items if isinstance(item, dict)]
1058
1048
  matched_items.extend(item for item in normalized_items if self._task_item_matches_query(item, query))
1059
1049
  if page_amount is None:
1060
1050
  coerced_page_amount = _coerce_count(_task_page_amount(task_page))
@@ -1726,7 +1716,7 @@ class TaskContextTools(ToolBase):
1726
1716
  if value not in (None, "", [])
1727
1717
  }
1728
1718
 
1729
- def _normalize_task_item(self, raw: dict[str, Any], *, task_box: str, flow_status: str) -> dict[str, Any]:
1719
+ def _normalize_task_item(self, raw: dict[str, Any]) -> dict[str, Any]:
1730
1720
  """执行内部辅助逻辑。"""
1731
1721
  app_key = raw.get("appKey") or raw.get("app_key")
1732
1722
  record_id = raw.get("rowRecordId") or raw.get("recordId") or raw.get("applyId")
@@ -1739,11 +1729,30 @@ class TaskContextTools(ToolBase):
1739
1729
  "workflow_node_id": workflow_node_id,
1740
1730
  "workflow_node_name": raw.get("nodeName") or raw.get("auditNodeName"),
1741
1731
  "apply_time": raw.get("applyTime") or raw.get("receiveTime"),
1742
- "task_box": task_box,
1743
- "flow_status": flow_status,
1744
- "actionable": task_box == "todo" and bool(record_id) and bool(workflow_node_id),
1732
+ "summary_fields": self._normalize_task_summary_fields(raw.get("dataSnapshot")),
1745
1733
  }
1746
1734
 
1735
+ def _normalize_task_summary_fields(self, raw: Any) -> list[dict[str, Any]]:
1736
+ """执行内部辅助逻辑。"""
1737
+ if not isinstance(raw, list):
1738
+ return []
1739
+ summary_fields: list[dict[str, Any]] = []
1740
+ for item in raw:
1741
+ if not isinstance(item, dict):
1742
+ continue
1743
+ summary_field: dict[str, Any] = {
1744
+ "field_id": item.get("fieldId"),
1745
+ "title": item.get("fieldTitle"),
1746
+ "type": item.get("fieldType"),
1747
+ "answer": item.get("fieldAnswer"),
1748
+ "desensitized": self._coerce_bool(item.get("beingDesensitized")),
1749
+ }
1750
+ associated_field_type = item.get("associatedQueType")
1751
+ if associated_field_type is not None:
1752
+ summary_field["associated_field_type"] = associated_field_type
1753
+ summary_fields.append(summary_field)
1754
+ return summary_fields
1755
+
1747
1756
  def _select_task_node(self, infos: Any, workflow_node_id: int, *, app_key: str, record_id: int) -> dict[str, Any]:
1748
1757
  """执行内部辅助逻辑。"""
1749
1758
  if not isinstance(infos, list) or not infos: