@josephyan/qingflow-app-user-mcp 0.2.0-beta.2 → 0.2.0-beta.21
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 +12 -2
- package/npm/lib/runtime.mjs +37 -0
- package/npm/scripts/postinstall.mjs +5 -1
- package/package.json +3 -2
- package/pyproject.toml +1 -1
- package/skills/qingflow-app-user/SKILL.md +230 -0
- package/skills/qingflow-app-user/agents/openai.yaml +4 -0
- package/skills/qingflow-app-user/references/data-gotchas.md +49 -0
- package/skills/qingflow-app-user/references/environments.md +63 -0
- package/skills/qingflow-app-user/references/record-patterns.md +110 -0
- package/skills/qingflow-app-user/references/workflow-usage.md +26 -0
- package/skills/qingflow-record-analysis/SKILL.md +253 -0
- package/skills/qingflow-record-analysis/agents/openai.yaml +4 -0
- package/skills/qingflow-record-analysis/references/analysis-gotchas.md +141 -0
- package/skills/qingflow-record-analysis/references/analysis-patterns.md +113 -0
- package/skills/qingflow-record-analysis/references/confidence-reporting.md +92 -0
- package/src/qingflow_mcp/__init__.py +1 -1
- package/src/qingflow_mcp/builder_facade/models.py +294 -1
- package/src/qingflow_mcp/builder_facade/service.py +2727 -235
- package/src/qingflow_mcp/server.py +7 -5
- package/src/qingflow_mcp/server_app_builder.py +80 -4
- package/src/qingflow_mcp/server_app_user.py +8 -182
- package/src/qingflow_mcp/solution/compiler/form_compiler.py +1 -1
- package/src/qingflow_mcp/solution/compiler/workflow_compiler.py +21 -2
- package/src/qingflow_mcp/solution/executor.py +34 -7
- package/src/qingflow_mcp/tools/ai_builder_tools.py +1038 -30
- package/src/qingflow_mcp/tools/app_tools.py +1 -2
- package/src/qingflow_mcp/tools/approval_tools.py +357 -75
- package/src/qingflow_mcp/tools/directory_tools.py +158 -28
- package/src/qingflow_mcp/tools/record_tools.py +1954 -973
- package/src/qingflow_mcp/tools/task_tools.py +376 -225
- package/src/qingflow_mcp/tools/workflow_tools.py +78 -4
|
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from mcp.server.fastmcp import FastMCP
|
|
4
4
|
|
|
5
|
+
from ..backend_client import BackendRequestContext
|
|
5
6
|
from ..config import DEFAULT_PROFILE
|
|
6
7
|
from ..errors import QingflowApiError, raise_tool_error
|
|
7
8
|
from ..json_types import JSONObject, JSONValue
|
|
@@ -70,13 +71,28 @@ class WorkflowTools(ToolBase):
|
|
|
70
71
|
def workflow_add_node(self, *, profile: str, app_key: str, payload: JSONObject) -> JSONObject:
|
|
71
72
|
self._require_app_key(app_key)
|
|
72
73
|
body = self._require_dict(payload)
|
|
73
|
-
return self.
|
|
74
|
+
return self._request_with_post_fallbacks(
|
|
75
|
+
profile=profile,
|
|
76
|
+
app_key=app_key,
|
|
77
|
+
path=f"/app/{app_key}/auditNodes",
|
|
78
|
+
json_body=body,
|
|
79
|
+
alternate_paths=[f"/app/{app_key}/auditNode"],
|
|
80
|
+
)
|
|
74
81
|
|
|
75
82
|
def workflow_update_node(self, *, profile: str, app_key: str, audit_node_id: int, payload: JSONObject) -> JSONObject:
|
|
76
83
|
self._require_app_key(app_key)
|
|
77
84
|
self._require_positive("audit_node_id", audit_node_id)
|
|
78
85
|
body = self._require_dict(payload)
|
|
79
|
-
return self.
|
|
86
|
+
return self._request_with_post_fallbacks(
|
|
87
|
+
profile=profile,
|
|
88
|
+
app_key=app_key,
|
|
89
|
+
path=f"/app/{app_key}/auditNodes/{audit_node_id}",
|
|
90
|
+
json_body=body,
|
|
91
|
+
alternate_paths=[f"/app/{app_key}/auditNode/{audit_node_id}"],
|
|
92
|
+
risk_operation="update",
|
|
93
|
+
risk_target="workflow node configuration",
|
|
94
|
+
audit_node_id=audit_node_id,
|
|
95
|
+
)
|
|
80
96
|
|
|
81
97
|
def workflow_delete_node(self, *, profile: str, app_key: str, payload: JSONObject) -> JSONObject:
|
|
82
98
|
self._require_app_key(app_key)
|
|
@@ -110,12 +126,26 @@ class WorkflowTools(ToolBase):
|
|
|
110
126
|
def workflow_update_global_settings(self, *, profile: str, app_key: str, payload: JSONObject) -> JSONObject:
|
|
111
127
|
self._require_app_key(app_key)
|
|
112
128
|
body = self._require_dict(payload)
|
|
113
|
-
return self.
|
|
129
|
+
return self._request_with_post_fallbacks(
|
|
130
|
+
profile=profile,
|
|
131
|
+
app_key=app_key,
|
|
132
|
+
path=f"/app/{app_key}/workflow/global/setting",
|
|
133
|
+
json_body=body,
|
|
134
|
+
alternate_paths=[],
|
|
135
|
+
risk_operation="update",
|
|
136
|
+
risk_target="workflow global settings",
|
|
137
|
+
)
|
|
114
138
|
|
|
115
139
|
def workflow_publish(self, *, profile: str, app_key: str, payload: JSONObject) -> JSONObject:
|
|
116
140
|
self._require_app_key(app_key)
|
|
117
141
|
body = self._require_dict(payload)
|
|
118
|
-
return self.
|
|
142
|
+
return self._request_with_post_fallbacks(
|
|
143
|
+
profile=profile,
|
|
144
|
+
app_key=app_key,
|
|
145
|
+
path=f"/app/{app_key}/publish",
|
|
146
|
+
json_body=body,
|
|
147
|
+
alternate_paths=[],
|
|
148
|
+
)
|
|
119
149
|
|
|
120
150
|
def workflow_get_future_nodes(self, *, profile: str, app_key: str, apply_id: int) -> JSONObject:
|
|
121
151
|
self._require_app_key(app_key)
|
|
@@ -229,6 +259,50 @@ class WorkflowTools(ToolBase):
|
|
|
229
259
|
|
|
230
260
|
return self._run(profile, runner)
|
|
231
261
|
|
|
262
|
+
def _request_with_post_fallbacks(
|
|
263
|
+
self,
|
|
264
|
+
*,
|
|
265
|
+
profile: str,
|
|
266
|
+
app_key: str,
|
|
267
|
+
path: str,
|
|
268
|
+
json_body: JSONObject,
|
|
269
|
+
alternate_paths: list[str],
|
|
270
|
+
risk_operation: str | None = None,
|
|
271
|
+
risk_target: str | None = None,
|
|
272
|
+
**extra: JSONValue,
|
|
273
|
+
) -> JSONObject:
|
|
274
|
+
def runner(session_profile, context):
|
|
275
|
+
attempted_contexts = [context]
|
|
276
|
+
if context.qf_version is not None:
|
|
277
|
+
attempted_contexts.append(
|
|
278
|
+
BackendRequestContext(
|
|
279
|
+
base_url=context.base_url,
|
|
280
|
+
token=context.token,
|
|
281
|
+
ws_id=context.ws_id,
|
|
282
|
+
qf_version=None,
|
|
283
|
+
qf_version_source="workflow_retry_without_qf_version",
|
|
284
|
+
)
|
|
285
|
+
)
|
|
286
|
+
paths = [path, *alternate_paths]
|
|
287
|
+
last_error: QingflowApiError | None = None
|
|
288
|
+
for call_context in attempted_contexts:
|
|
289
|
+
for candidate_path in paths:
|
|
290
|
+
try:
|
|
291
|
+
result = self.backend.request("POST", call_context, candidate_path, json_body=json_body)
|
|
292
|
+
response: JSONObject = {"profile": profile, "ws_id": session_profile.selected_ws_id, "result": result}
|
|
293
|
+
response.update(extra)
|
|
294
|
+
if risk_operation and risk_target:
|
|
295
|
+
return self._attach_human_review_notice(response, operation=risk_operation, target=risk_target)
|
|
296
|
+
return response
|
|
297
|
+
except QingflowApiError as error:
|
|
298
|
+
last_error = error
|
|
299
|
+
if error.http_status != 404:
|
|
300
|
+
raise
|
|
301
|
+
assert last_error is not None
|
|
302
|
+
raise last_error
|
|
303
|
+
|
|
304
|
+
return self._run(profile, runner)
|
|
305
|
+
|
|
232
306
|
def _require_app_key(self, app_key: str) -> None:
|
|
233
307
|
if not app_key:
|
|
234
308
|
raise_tool_error(QingflowApiError.config_error("app_key is required"))
|