@josephyan/qingflow-app-builder-mcp 1.1.4 → 1.1.6
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 +6 -5
- package/docs/local-agent-install.md +57 -6
- package/entry_point.py +1 -1
- package/npm/bin/qingflow-app-builder-mcp.mjs +2 -33
- package/npm/bin/qingflow-skills.mjs +5 -0
- package/npm/lib/runtime.mjs +21 -101
- package/npm/scripts/postinstall.mjs +1 -10
- package/package.json +3 -2
- package/pyproject.toml +1 -1
- package/skills/qingflow-app-builder/SKILL.md +51 -34
- package/skills/qingflow-app-builder/references/complete-system-development-guide.md +123 -0
- package/skills/qingflow-app-builder/references/create-app.md +19 -6
- package/skills/qingflow-app-builder/references/environments.md +1 -1
- package/skills/qingflow-app-builder/references/gotchas.md +14 -6
- package/skills/qingflow-app-builder/references/match-rules.md +15 -0
- package/skills/qingflow-app-builder/references/single-app-development-guide.md +58 -0
- package/skills/qingflow-app-builder/references/solution-playbooks.md +10 -0
- package/skills/qingflow-app-builder/references/tool-selection.md +21 -22
- package/skills/qingflow-app-builder/references/update-flow.md +22 -38
- package/skills/qingflow-app-builder/references/update-schema.md +3 -0
- package/skills/qingflow-app-builder/references/update-views.md +34 -14
- package/skills/qingflow-app-builder/scripts/validate_system_build_summary.py +124 -0
- package/skills/qingflow-app-builder-code-integrations/SKILL.md +5 -3
- package/skills/qingflow-app-builder-code-integrations/references/code-block.md +1 -1
- package/skills/qingflow-app-builder-code-integrations/references/q-linker.md +1 -1
- package/src/qingflow_mcp/__init__.py +1 -1
- package/src/qingflow_mcp/__main__.py +6 -2
- package/src/qingflow_mcp/builder_facade/models.py +282 -102
- package/src/qingflow_mcp/builder_facade/service.py +4192 -935
- package/src/qingflow_mcp/cli/commands/builder.py +316 -298
- package/src/qingflow_mcp/cli/commands/chart.py +1 -1
- package/src/qingflow_mcp/cli/commands/common.py +12 -3
- package/src/qingflow_mcp/cli/commands/exports.py +2 -2
- package/src/qingflow_mcp/cli/commands/imports.py +3 -3
- package/src/qingflow_mcp/cli/commands/portal.py +2 -2
- package/src/qingflow_mcp/cli/commands/record.py +101 -27
- package/src/qingflow_mcp/cli/commands/task.py +28 -47
- package/src/qingflow_mcp/cli/commands/view.py +1 -1
- package/src/qingflow_mcp/cli/context.py +0 -3
- package/src/qingflow_mcp/cli/formatters.py +784 -16
- package/src/qingflow_mcp/cli/main.py +117 -33
- package/src/qingflow_mcp/errors.py +43 -2
- package/src/qingflow_mcp/public_surface.py +26 -17
- package/src/qingflow_mcp/response_trim.py +81 -17
- package/src/qingflow_mcp/server.py +14 -12
- package/src/qingflow_mcp/server_app_builder.py +65 -21
- package/src/qingflow_mcp/server_app_user.py +22 -16
- package/src/qingflow_mcp/session_store.py +11 -7
- package/src/qingflow_mcp/solution/compiler/__init__.py +3 -1
- package/src/qingflow_mcp/solution/compiler/workflow_compiler.py +173 -0
- package/src/qingflow_mcp/solution/executor.py +245 -18
- package/src/qingflow_mcp/tools/ai_builder_tools.py +1780 -406
- package/src/qingflow_mcp/tools/app_tools.py +184 -43
- package/src/qingflow_mcp/tools/approval_tools.py +197 -35
- package/src/qingflow_mcp/tools/auth_tools.py +92 -16
- package/src/qingflow_mcp/tools/code_block_tools.py +298 -40
- package/src/qingflow_mcp/tools/custom_button_tools.py +64 -10
- package/src/qingflow_mcp/tools/directory_tools.py +236 -72
- package/src/qingflow_mcp/tools/export_tools.py +244 -34
- package/src/qingflow_mcp/tools/feedback_tools.py +9 -0
- package/src/qingflow_mcp/tools/file_tools.py +9 -3
- package/src/qingflow_mcp/tools/import_tools.py +336 -49
- package/src/qingflow_mcp/tools/navigation_tools.py +91 -12
- package/src/qingflow_mcp/tools/package_tools.py +118 -6
- package/src/qingflow_mcp/tools/portal_tools.py +39 -3
- package/src/qingflow_mcp/tools/qingbi_report_tools.py +116 -7
- package/src/qingflow_mcp/tools/record_tools.py +1141 -356
- package/src/qingflow_mcp/tools/resource_read_tools.py +188 -39
- package/src/qingflow_mcp/tools/role_tools.py +80 -9
- package/src/qingflow_mcp/tools/solution_tools.py +59 -45
- package/src/qingflow_mcp/tools/task_context_tools.py +662 -158
- package/src/qingflow_mcp/tools/task_tools.py +113 -29
- package/src/qingflow_mcp/tools/view_tools.py +106 -3
- package/src/qingflow_mcp/tools/workflow_tools.py +48 -4
- package/src/qingflow_mcp/tools/workspace_tools.py +71 -3
- package/skills/qingflow-app-builder/references/build-complete-system.md +0 -428
- package/skills/qingflow-app-builder/references/build-single-app.md +0 -530
- package/skills/qingflow-mcp-setup/SKILL.md +0 -111
- package/skills/qingflow-mcp-setup/agents/openai.yaml +0 -4
- package/skills/qingflow-mcp-setup/references/claude-desktop.md +0 -34
- package/skills/qingflow-mcp-setup/references/environments.md +0 -61
- package/skills/qingflow-mcp-setup/references/generic-stdio.md +0 -31
- package/skills/qingflow-mcp-setup/scripts/check_local_server.sh +0 -38
- package/skills/qingflow-workflow-builder/SKILL.md +0 -96
- package/skills/qingflow-workflow-builder/manifest.yaml +0 -8
- package/skills/qingflow-workflow-builder/references/01-overview.md +0 -45
- package/skills/qingflow-workflow-builder/references/02-update-mode.md +0 -53
- package/skills/qingflow-workflow-builder/references/03-flow-patterns.md +0 -57
- package/skills/qingflow-workflow-builder/references/04-stage1-business-modeling.md +0 -131
- package/skills/qingflow-workflow-builder/references/05-stage2-members-roles.md +0 -29
- package/skills/qingflow-workflow-builder/references/06-stage3-build-spec.md +0 -165
- package/skills/qingflow-workflow-builder/references/07-stage4-validate-spec.md +0 -33
- package/skills/qingflow-workflow-builder/references/08-stage5-apply-verify.md +0 -51
- package/skills/qingflow-workflow-builder/references/09-stage6-summary.md +0 -88
- package/skills/qingflow-workflow-builder/references/10-node-config-reference.md +0 -93
- package/skills/qingflow-workflow-builder/references/11-troubleshooting.md +0 -15
- package/skills/qingflow-workflow-builder/scripts/diff_flow_spec.py +0 -275
- package/skills/qingflow-workflow-builder/scripts/validate_flow_spec.py +0 -605
|
@@ -28,17 +28,18 @@ Canonical rules before any example:
|
|
|
28
28
|
- Always use `columns`
|
|
29
29
|
- Do not emit `column_names`
|
|
30
30
|
- Treat `fields` only as a legacy alias the MCP may normalize, not as the preferred shape
|
|
31
|
-
- Use `filters` with
|
|
31
|
+
- Use `filters` with the unified fixed-filter DSL: `field_name`, `operator`, `value`/`values`; do not write raw `judgeType` / `judgeValues`
|
|
32
32
|
- Use `query_conditions` for the frontend query panel. Do not put query-panel fields into `filters`.
|
|
33
|
-
-
|
|
33
|
+
- Do not create views named `全部数据`, `我的数据`, `我发起的`, `待办`, `已办`, or `抄送`. These are built-in default/system views. New views must use business-specific names such as `订单台账视图`, `客户跟进视图`, or `逾期任务看板`.
|
|
34
|
+
- To change a built-in default/system view, first read the existing raw `view_key` from `app_get.views` or `app_get_views`, then use `patch_views` or a full `upsert_views` item with that `view_key`.
|
|
34
35
|
- New views created by `app_views_apply` default the frontend associated report/view area to visible with `limit_type="all"`. Existing views preserve their current associated-resource display unless `associated_resources` is explicitly patched.
|
|
35
|
-
- Use `app_associated_resources_apply` for the associated report/view resource pool, selected resources, and match rules. `associated_item_id` is the internal associated-resource id from `app_get.associated_resources`; `view_configs`, remove, and reorder may also pass an existing resource's `chart_id`/`chart_key`/`view_key`, which the tool resolves to the internal id. Do not write backend raw `sourceType`; reports default to BI app reports, and dataset reports use `report_source="dataset"`. Use `match_mappings` for associated view/report filters; read `match-rules.md` if field type compatibility is unclear.
|
|
36
|
+
- Use `app_associated_resources_apply` for the associated report/view resource pool, selected resources, and match rules. Permission is split like the backend: resource pool writes use EditAppAuth, while `view_configs` uses the view config/DataManageAuth path. `associated_item_id` is the internal associated-resource id from `app_get.associated_resources`; `view_configs`, remove, and reorder may also pass an existing resource's `chart_id`/`chart_key`/`view_key`, which the tool resolves to the internal id. Do not write backend raw `sourceType`; reports default to BI app reports, and dataset reports use `report_source="dataset"`. Use `match_mappings` with `target_field + operator + source_field/value` for associated view/report filters; read `match-rules.md` if field type compatibility is unclear.
|
|
36
37
|
- For gantt, use `start_field`, `end_field`, and optionally `title_field`
|
|
37
38
|
- If `app_get.views` or `app_get_views` shows duplicate view names, include `view_key` in `upsert_views[]` and update that exact target
|
|
38
39
|
- Builder view writes always use the raw `view_key` from `app_get.views[].view_key`, such as `emsrao25rs02`. Do not pass `custom:emsrao25rs02`; that prefixed form is only for record-data `view_id`.
|
|
39
40
|
- For an existing view, prefer `patch_views` for parameter replacement. Do not send a partial `upsert_views` object such as only `name/type/query_conditions`; backend view saves require other type-specific fields, and the patch path preserves them for you.
|
|
40
41
|
|
|
41
|
-
Apply a
|
|
42
|
+
Apply a business table view:
|
|
42
43
|
|
|
43
44
|
```json
|
|
44
45
|
{
|
|
@@ -49,16 +50,10 @@ Apply a default table view:
|
|
|
49
50
|
"publish": true,
|
|
50
51
|
"upsert_views": [
|
|
51
52
|
{
|
|
52
|
-
"name": "
|
|
53
|
+
"name": "订单台账视图",
|
|
53
54
|
"view_key": "VIEW_KEY_IF_DUPLICATE_NAMES_EXIST",
|
|
54
55
|
"type": "table",
|
|
55
|
-
"columns": ["订单编号", "客户名称", "订单金额", "状态"
|
|
56
|
-
"query_conditions": {
|
|
57
|
-
"enabled": true,
|
|
58
|
-
"exact": false,
|
|
59
|
-
"hide_before_query": false,
|
|
60
|
-
"rows": [["订单编号", "客户名称"], ["状态", "负责人"], ["创建时间"]]
|
|
61
|
-
}
|
|
56
|
+
"columns": ["订单编号", "客户名称", "订单金额", "状态"]
|
|
62
57
|
}
|
|
63
58
|
],
|
|
64
59
|
"remove_views": []
|
|
@@ -277,7 +272,32 @@ At least one `query_conditions.rows` field does not exist on the app.
|
|
|
277
272
|
|
|
278
273
|
### `INVALID_QUERY_CONDITION_FIELD`
|
|
279
274
|
|
|
280
|
-
The field exists but cannot be used in the frontend query-condition panel
|
|
275
|
+
The field exists but cannot be used in the frontend query-condition panel.
|
|
276
|
+
|
|
277
|
+
Supported `query_conditions.rows` fields are query-panel fields:
|
|
278
|
+
|
|
279
|
+
- text / long text
|
|
280
|
+
- number / amount
|
|
281
|
+
- date / datetime
|
|
282
|
+
- single select / multi select
|
|
283
|
+
- member / department
|
|
284
|
+
- phone / email
|
|
285
|
+
- boolean
|
|
286
|
+
|
|
287
|
+
Do not use these fields in `query_conditions`:
|
|
288
|
+
|
|
289
|
+
- relation
|
|
290
|
+
- attachment
|
|
291
|
+
- subtable or subtable subfield
|
|
292
|
+
- address/location
|
|
293
|
+
- Q-Linker
|
|
294
|
+
- code block
|
|
295
|
+
|
|
296
|
+
Fix path:
|
|
297
|
+
|
|
298
|
+
- If you wanted a saved filter that opens with the view, use `filters`.
|
|
299
|
+
- If you wanted a related report/view to match the current record, use `app_associated_resources_apply.match_mappings`.
|
|
300
|
+
- If you only need frontend search fields, remove unsupported fields from `query_conditions.rows` and keep query-panel supported fields only.
|
|
281
301
|
|
|
282
302
|
## Notes
|
|
283
303
|
|
|
@@ -286,6 +306,6 @@ The field exists but cannot be used in the frontend query-condition panel, such
|
|
|
286
306
|
- `app_get_views` should be treated as canonical readback and now returns `columns`
|
|
287
307
|
- If `app_views_apply` returns `AMBIGUOUS_VIEW`, stop and re-run `app_get_views`; then retry with the exact `view_key`
|
|
288
308
|
- `filters` are ANDed together as one flat condition group
|
|
289
|
-
- `query_conditions.rows` does not mean OR; it controls frontend query-field layout
|
|
309
|
+
- `query_conditions.rows` does not mean OR; it controls frontend query-field layout and should only contain query-panel supported fields
|
|
290
310
|
- `app_views_apply` publishes by default
|
|
291
311
|
- For select-style filters, success means the backend preserved the option value in readback, not just that the view name now exists
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import argparse
|
|
5
|
+
import json
|
|
6
|
+
import sys
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
VALID_PORTAL_STATUSES = {"verified", "unverified", "not_created"}
|
|
12
|
+
VALID_APP_VERIFY_STATUSES = {"verified", "unverified", "failed"}
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def main(argv: list[str] | None = None) -> int:
|
|
16
|
+
parser = argparse.ArgumentParser(description="Validate a Qingflow complete-system delivery summary JSON file.")
|
|
17
|
+
parser.add_argument("summary_file", nargs="?", default="tmp/qingflow_system_build_summary.json")
|
|
18
|
+
args = parser.parse_args(argv)
|
|
19
|
+
path = Path(args.summary_file)
|
|
20
|
+
issues = validate_summary_file(path)
|
|
21
|
+
if issues:
|
|
22
|
+
_emit({"status": "failed", "error_code": "SYSTEM_BUILD_SUMMARY_INVALID", "path": str(path), "issues": issues})
|
|
23
|
+
return 1
|
|
24
|
+
payload = json.loads(path.read_text(encoding="utf-8"))
|
|
25
|
+
_emit(
|
|
26
|
+
{
|
|
27
|
+
"status": "success",
|
|
28
|
+
"path": str(path),
|
|
29
|
+
"summary": {
|
|
30
|
+
"package_id": payload.get("package_id"),
|
|
31
|
+
"package_name": payload.get("package_name"),
|
|
32
|
+
"portal_dash_key": payload.get("portal_dash_key"),
|
|
33
|
+
"portal_live_status": payload.get("portal_live_status"),
|
|
34
|
+
"app_count": len(payload.get("apps") or []),
|
|
35
|
+
"partial_count": len(payload.get("partial_items") or []),
|
|
36
|
+
"needs_followup_count": len(payload.get("needs_followup") or []),
|
|
37
|
+
},
|
|
38
|
+
}
|
|
39
|
+
)
|
|
40
|
+
return 0
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def validate_summary_file(path: Path) -> list[dict[str, Any]]:
|
|
44
|
+
if not path.exists():
|
|
45
|
+
return [_issue("MISSING_FILE", "$", f"summary file does not exist: {path}")]
|
|
46
|
+
try:
|
|
47
|
+
payload = json.loads(path.read_text(encoding="utf-8"))
|
|
48
|
+
except OSError as exc:
|
|
49
|
+
return [_issue("READ_FAILED", "$", str(exc))]
|
|
50
|
+
except json.JSONDecodeError as exc:
|
|
51
|
+
return [_issue("INVALID_JSON", "$", exc.msg)]
|
|
52
|
+
if not isinstance(payload, dict):
|
|
53
|
+
return [_issue("INVALID_ROOT", "$", "summary root must be a JSON object")]
|
|
54
|
+
|
|
55
|
+
issues: list[dict[str, Any]] = []
|
|
56
|
+
_require_positive_int(payload, "package_id", issues)
|
|
57
|
+
_require_nonempty_string(payload, "package_name", issues)
|
|
58
|
+
_require_bool(payload, "front_end_visible", issues)
|
|
59
|
+
_require_string_enum(payload, "portal_live_status", VALID_PORTAL_STATUSES, issues)
|
|
60
|
+
if payload.get("portal_live_status") == "verified":
|
|
61
|
+
_require_nonempty_string(payload, "portal_dash_key", issues)
|
|
62
|
+
elif "portal_dash_key" in payload and payload.get("portal_dash_key") is not None and not isinstance(payload.get("portal_dash_key"), str):
|
|
63
|
+
issues.append(_issue("INVALID_TYPE", "$.portal_dash_key", "portal_dash_key must be a string when present"))
|
|
64
|
+
|
|
65
|
+
apps = payload.get("apps")
|
|
66
|
+
if not isinstance(apps, list) or not apps:
|
|
67
|
+
issues.append(_issue("INVALID_APPS", "$.apps", "apps must be a non-empty array"))
|
|
68
|
+
else:
|
|
69
|
+
for index, app in enumerate(apps):
|
|
70
|
+
prefix = f"$.apps[{index}]"
|
|
71
|
+
if not isinstance(app, dict):
|
|
72
|
+
issues.append(_issue("INVALID_APP_ITEM", prefix, "app item must be an object"))
|
|
73
|
+
continue
|
|
74
|
+
_require_nonempty_string(app, "app_key", issues, prefix)
|
|
75
|
+
_require_nonempty_string(app, "app_name", issues, prefix)
|
|
76
|
+
for key in ("fields_count", "views_count", "flows_count", "charts_count"):
|
|
77
|
+
_require_nonnegative_int(app, key, issues, prefix)
|
|
78
|
+
_require_string_enum(app, "publish_verify_status", VALID_APP_VERIFY_STATUSES, issues, prefix)
|
|
79
|
+
|
|
80
|
+
for key in ("warnings", "partial_items", "needs_followup"):
|
|
81
|
+
if not isinstance(payload.get(key), list):
|
|
82
|
+
issues.append(_issue("INVALID_TYPE", f"$.{key}", f"{key} must be an array"))
|
|
83
|
+
return issues
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _require_positive_int(payload: dict[str, Any], key: str, issues: list[dict[str, Any]], prefix: str = "$") -> None:
|
|
87
|
+
value = payload.get(key)
|
|
88
|
+
if isinstance(value, bool) or not isinstance(value, int) or value <= 0:
|
|
89
|
+
issues.append(_issue("INVALID_TYPE", f"{prefix}.{key}", f"{key} must be a positive integer"))
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _require_nonnegative_int(payload: dict[str, Any], key: str, issues: list[dict[str, Any]], prefix: str = "$") -> None:
|
|
93
|
+
value = payload.get(key)
|
|
94
|
+
if isinstance(value, bool) or not isinstance(value, int) or value < 0:
|
|
95
|
+
issues.append(_issue("INVALID_TYPE", f"{prefix}.{key}", f"{key} must be a non-negative integer"))
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def _require_nonempty_string(payload: dict[str, Any], key: str, issues: list[dict[str, Any]], prefix: str = "$") -> None:
|
|
99
|
+
value = payload.get(key)
|
|
100
|
+
if not isinstance(value, str) or not value.strip():
|
|
101
|
+
issues.append(_issue("INVALID_TYPE", f"{prefix}.{key}", f"{key} must be a non-empty string"))
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def _require_bool(payload: dict[str, Any], key: str, issues: list[dict[str, Any]], prefix: str = "$") -> None:
|
|
105
|
+
if not isinstance(payload.get(key), bool):
|
|
106
|
+
issues.append(_issue("INVALID_TYPE", f"{prefix}.{key}", f"{key} must be a boolean"))
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def _require_string_enum(payload: dict[str, Any], key: str, allowed: set[str], issues: list[dict[str, Any]], prefix: str = "$") -> None:
|
|
110
|
+
value = payload.get(key)
|
|
111
|
+
if value not in allowed:
|
|
112
|
+
issues.append(_issue("INVALID_VALUE", f"{prefix}.{key}", f"{key} must be one of {sorted(allowed)}"))
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def _issue(code: str, path: str, message: str) -> dict[str, Any]:
|
|
116
|
+
return {"code": code, "path": path, "message": message}
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _emit(payload: dict[str, Any]) -> None:
|
|
120
|
+
print(json.dumps(payload, ensure_ascii=False, indent=2))
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
if __name__ == "__main__":
|
|
124
|
+
sys.exit(main())
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: qingflow-app-builder-code-integrations
|
|
3
|
-
description: Configure Qingflow code block and Q-Linker fields through the builder surface when the task involves input field insertion, alias parsing, target field binding, or troubleshooting broken code/q-linker form configurations.
|
|
3
|
+
description: Configure Qingflow code block and Q-Linker fields through the builder surface when the task involves input field insertion, alias parsing, target field binding, or troubleshooting broken code/q-linker form configurations. In Wingent Momo runtime, use the injected MCP session and recover auth/workspace only after a tool error.
|
|
4
4
|
metadata:
|
|
5
5
|
short-description: Configure Qingflow code blocks and Q-Linkers safely
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Qingflow App Builder Code Integrations
|
|
9
9
|
|
|
10
|
+
> **Skill 版本**:`qingflow-skills-2026.06.24.2`(入口文档版本;如需确认 CLI 包版本,使用 `qingflow --version` 或 `qingflow --json version`)。
|
|
11
|
+
|
|
10
12
|
Use this skill when the user wants to build or repair:
|
|
11
13
|
- `code_block` fields
|
|
12
14
|
- `q_linker` fields
|
|
@@ -58,7 +60,7 @@ For code block or Q-Linker work, use this order:
|
|
|
58
60
|
|
|
59
61
|
1. Resolve the app and read fields:
|
|
60
62
|
- `app_resolve`
|
|
61
|
-
- `
|
|
63
|
+
- `app_get_fields`
|
|
62
64
|
2. Confirm the target field set already exists.
|
|
63
65
|
3. Apply schema updates with `app_schema_apply`.
|
|
64
66
|
4. Read fields again and verify:
|
|
@@ -115,7 +117,7 @@ Hard rules:
|
|
|
115
117
|
|
|
116
118
|
After each code block or Q-Linker change, verify all of these:
|
|
117
119
|
|
|
118
|
-
- `
|
|
120
|
+
- `app_get_fields` shows the intended field type
|
|
119
121
|
- the high-level config is readable and stable
|
|
120
122
|
- target fields still have valid types
|
|
121
123
|
- insert schema can be opened
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
"""Entry point for running qingflow_mcp as a module.
|
|
2
|
-
|
|
1
|
+
"""Entry point for running qingflow_mcp as a module.
|
|
2
|
+
|
|
3
|
+
Default to the curated user-facing MCP surface. Split package and console
|
|
4
|
+
entrypoints can still start the builder server explicitly.
|
|
5
|
+
"""
|
|
6
|
+
from qingflow_mcp.server_app_user import main
|
|
3
7
|
|
|
4
8
|
if __name__ == "__main__":
|
|
5
9
|
main()
|