@josephyan/qingflow-app-builder-mcp 0.2.0-beta.26 → 0.2.0-beta.28
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-builder-mcp@0.2.0-beta.
|
|
6
|
+
npm install @josephyan/qingflow-app-builder-mcp@0.2.0-beta.28
|
|
7
7
|
```
|
|
8
8
|
|
|
9
9
|
Run:
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
|
-
npx -y -p @josephyan/qingflow-app-builder-mcp@0.2.0-beta.
|
|
12
|
+
npx -y -p @josephyan/qingflow-app-builder-mcp@0.2.0-beta.28 qingflow-app-builder-mcp
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
Environment:
|
package/package.json
CHANGED
package/pyproject.toml
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from datetime import date
|
|
4
|
+
|
|
3
5
|
from mcp.server.fastmcp import FastMCP
|
|
4
6
|
|
|
5
7
|
from .backend_client import BackendClient
|
|
@@ -23,25 +25,91 @@ from .tools.workspace_tools import WorkspaceTools
|
|
|
23
25
|
|
|
24
26
|
|
|
25
27
|
def build_server() -> FastMCP:
|
|
28
|
+
today = date.today()
|
|
29
|
+
current_year = today.year
|
|
26
30
|
server = FastMCP(
|
|
27
31
|
"Qingflow MCP",
|
|
28
|
-
instructions=(
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
32
|
+
instructions=f"""Use this server for Qingflow operational workflows. Current date: `{today.isoformat()}`.
|
|
33
|
+
|
|
34
|
+
## Authentication
|
|
35
|
+
|
|
36
|
+
Use `auth_login` first, then `workspace_list` and `workspace_select`.
|
|
37
|
+
All resource tools operate with the logged-in user's Qingflow permissions.
|
|
38
|
+
|
|
39
|
+
## App Discovery
|
|
40
|
+
|
|
41
|
+
If `app_key` is unknown, use `app_list` or `app_search` first.
|
|
42
|
+
|
|
43
|
+
## Schema-First Rule
|
|
44
|
+
|
|
45
|
+
Always call `record_schema_get` before `record_list`, `record_get`, `record_write`, or `record_analyze`.
|
|
46
|
+
|
|
47
|
+
- All `field_id` values must come from the schema response.
|
|
48
|
+
- Never guess field names or ids.
|
|
49
|
+
|
|
50
|
+
## Schema Scope
|
|
51
|
+
|
|
52
|
+
`record_schema_get` returns the current user's applicant-node visible fields only.
|
|
53
|
+
|
|
54
|
+
- Hidden fields are omitted.
|
|
55
|
+
- Missing fields mean the field is not visible in the current permission scope.
|
|
56
|
+
- Read `fields` and `suggested_*` from the top level of the schema response.
|
|
57
|
+
|
|
58
|
+
## Analytics Path
|
|
59
|
+
|
|
60
|
+
`record_schema_get -> record_analyze`
|
|
61
|
+
|
|
62
|
+
Use this DSL shape:
|
|
63
|
+
|
|
64
|
+
- `dimensions`: `{{field_id, alias, bucket}}`
|
|
65
|
+
- `metrics`: `{{op, field_id, alias}}`
|
|
66
|
+
- `filters`: `{{field_id, op, value}}`
|
|
67
|
+
- `sort`: `{{by, order}}`
|
|
68
|
+
|
|
69
|
+
Important key rules:
|
|
70
|
+
|
|
71
|
+
- Use `op`
|
|
72
|
+
- Do **not** use `type`
|
|
73
|
+
- Do **not** use `agg`
|
|
74
|
+
- Do **not** use `aggregation`
|
|
75
|
+
- Do **not** use `operator`
|
|
76
|
+
|
|
77
|
+
Analysis answers must include concrete numbers. When applicable, include percentages based on the returned totals.
|
|
78
|
+
|
|
79
|
+
## Record CRUD Path
|
|
80
|
+
|
|
81
|
+
`record_schema_get -> record_list / record_get / record_write`
|
|
82
|
+
|
|
83
|
+
- For `columns`, prefer `[{{field_id}}]`; bare integer field ids remain supported for compatibility.
|
|
84
|
+
|
|
85
|
+
`record_write` uses SQL-like JSON clauses:
|
|
86
|
+
|
|
87
|
+
- `insert` -> `values`
|
|
88
|
+
- `update` -> `record_id + set`
|
|
89
|
+
- `delete` -> `record_id` or `record_ids`
|
|
90
|
+
|
|
91
|
+
- Read relation targets from `record_schema_get.target_app_key` / `target_app_name` before preparing relation writes.
|
|
92
|
+
- If a member or department field id is known but candidate ids are not, use `record_member_candidates` or `record_department_candidates` before `record_write`.
|
|
93
|
+
|
|
94
|
+
## Task Center Path
|
|
95
|
+
|
|
96
|
+
`task_summary -> task_list / task_facets -> task action`
|
|
97
|
+
|
|
98
|
+
## Time Handling
|
|
99
|
+
|
|
100
|
+
Normalize relative dates before building DSL.
|
|
101
|
+
|
|
102
|
+
- If the user says `3月` without a year, use the current year: `{current_year}`
|
|
103
|
+
- Convert month-only phrases into explicit legal date ranges
|
|
104
|
+
- Never send impossible dates such as `2026-02-29`
|
|
105
|
+
|
|
106
|
+
## Environment
|
|
107
|
+
|
|
108
|
+
Default to `prod` unless the user explicitly specifies `test`.
|
|
109
|
+
|
|
110
|
+
## Constraints
|
|
111
|
+
|
|
112
|
+
Avoid builder-side app or schema changes here.""",
|
|
45
113
|
)
|
|
46
114
|
sessions = SessionStore()
|
|
47
115
|
backend = BackendClient()
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from datetime import date
|
|
4
|
+
|
|
3
5
|
from mcp.server.fastmcp import FastMCP
|
|
4
6
|
|
|
5
7
|
from .backend_client import BackendClient
|
|
@@ -16,17 +18,86 @@ from .tools.workspace_tools import WorkspaceTools
|
|
|
16
18
|
|
|
17
19
|
|
|
18
20
|
def build_user_server() -> FastMCP:
|
|
21
|
+
today = date.today()
|
|
22
|
+
current_year = today.year
|
|
19
23
|
server = FastMCP(
|
|
20
24
|
"Qingflow App User MCP",
|
|
21
|
-
instructions=(
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
instructions=f"""Use this server for Qingflow operational workflows. Current date: `{today.isoformat()}`.
|
|
26
|
+
|
|
27
|
+
## App Discovery
|
|
28
|
+
|
|
29
|
+
If `app_key` is unknown, use `app_list` or `app_search` first.
|
|
30
|
+
|
|
31
|
+
## Schema-First Rule
|
|
32
|
+
|
|
33
|
+
Always call `record_schema_get` before `record_list`, `record_get`, `record_write`, or `record_analyze`.
|
|
34
|
+
|
|
35
|
+
- All `field_id` values must come from the schema response.
|
|
36
|
+
- Never guess field names or ids.
|
|
37
|
+
|
|
38
|
+
## Schema Scope
|
|
39
|
+
|
|
40
|
+
`record_schema_get` returns the current user's applicant-node visible fields only.
|
|
41
|
+
|
|
42
|
+
- Hidden fields are omitted.
|
|
43
|
+
- Missing fields mean the field is not visible in the current permission scope.
|
|
44
|
+
- Read `fields` and `suggested_*` from the top level of the schema response.
|
|
45
|
+
|
|
46
|
+
## Analytics Path
|
|
47
|
+
|
|
48
|
+
`record_schema_get -> record_analyze`
|
|
49
|
+
|
|
50
|
+
Use this DSL shape:
|
|
51
|
+
|
|
52
|
+
- `dimensions`: `{{field_id, alias, bucket}}`
|
|
53
|
+
- `metrics`: `{{op, field_id, alias}}`
|
|
54
|
+
- `filters`: `{{field_id, op, value}}`
|
|
55
|
+
- `sort`: `{{by, order}}`
|
|
56
|
+
|
|
57
|
+
Important key rules:
|
|
58
|
+
|
|
59
|
+
- Use `op`
|
|
60
|
+
- Do **not** use `type`
|
|
61
|
+
- Do **not** use `agg`
|
|
62
|
+
- Do **not** use `aggregation`
|
|
63
|
+
- Do **not** use `operator`
|
|
64
|
+
|
|
65
|
+
Analysis answers must include concrete numbers. When applicable, include percentages based on the returned totals.
|
|
66
|
+
|
|
67
|
+
## Record CRUD Path
|
|
68
|
+
|
|
69
|
+
`record_schema_get -> record_list / record_get / record_write`
|
|
70
|
+
|
|
71
|
+
- For `columns`, prefer `[{{field_id}}]`; bare integer field ids remain supported for compatibility.
|
|
72
|
+
|
|
73
|
+
`record_write` uses SQL-like JSON clauses:
|
|
74
|
+
|
|
75
|
+
- `insert` -> `values`
|
|
76
|
+
- `update` -> `record_id + set`
|
|
77
|
+
- `delete` -> `record_id` or `record_ids`
|
|
78
|
+
|
|
79
|
+
- Read relation targets from `record_schema_get.target_app_key` / `target_app_name` before preparing relation writes.
|
|
80
|
+
- If a member or department field id is known but candidate ids are not, use `record_member_candidates` or `record_department_candidates` before `record_write`.
|
|
81
|
+
|
|
82
|
+
## Task Center Path
|
|
83
|
+
|
|
84
|
+
`task_summary -> task_list / task_facets -> task action`
|
|
85
|
+
|
|
86
|
+
## Time Handling
|
|
87
|
+
|
|
88
|
+
Normalize relative dates before building DSL.
|
|
89
|
+
|
|
90
|
+
- If the user says `3月` without a year, use the current year: `{current_year}`
|
|
91
|
+
- Convert month-only phrases into explicit legal date ranges
|
|
92
|
+
- Never send impossible dates such as `2026-02-29`
|
|
93
|
+
|
|
94
|
+
## Environment
|
|
95
|
+
|
|
96
|
+
Default to `prod` unless the user explicitly specifies `test`.
|
|
97
|
+
|
|
98
|
+
## Constraints
|
|
99
|
+
|
|
100
|
+
Avoid builder-side app or schema changes here.""",
|
|
30
101
|
)
|
|
31
102
|
sessions = SessionStore()
|
|
32
103
|
backend = BackendClient()
|