@josephyan/qingflow-app-user-mcp 0.2.0-beta.25 → 0.2.0-beta.27
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 +2 -2
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/skills/qingflow-app-user/SKILL.md +3 -18
- package/skills/qingflow-record-analysis/SKILL.md +30 -64
- package/skills/qingflow-record-analysis/references/dsl-templates.md +93 -0
- package/skills/qingflow-record-crud/SKILL.md +24 -89
- package/skills/qingflow-task-ops/SKILL.md +2 -25
- package/src/qingflow_mcp/__init__.py +1 -1
- package/src/qingflow_mcp/server.py +82 -17
- package/src/qingflow_mcp/server_app_user.py +77 -9
- package/src/qingflow_mcp/tools/directory_tools.py +46 -4
- package/src/qingflow_mcp/tools/record_tools.py +892 -21
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.
|
|
6
|
+
npm install @josephyan/qingflow-app-user-mcp@0.2.0-beta.27
|
|
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.
|
|
12
|
+
npx -y -p @josephyan/qingflow-app-user-mcp@0.2.0-beta.27 qingflow-app-user-mcp
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
Environment:
|
package/package.json
CHANGED
package/pyproject.toml
CHANGED
|
@@ -9,19 +9,8 @@ metadata:
|
|
|
9
9
|
|
|
10
10
|
## Overview
|
|
11
11
|
|
|
12
|
-
This skill is a
|
|
13
|
-
|
|
14
|
-
Use it when the request is operational, but you first need to decide which specialized skill should own it.
|
|
15
|
-
|
|
16
|
-
This skill does **not** try to teach every detailed workflow itself.
|
|
17
|
-
It routes to:
|
|
18
|
-
|
|
19
|
-
- [$qingflow-record-crud](/Users/yanqidong/Documents/qingflow-next/.codex/skills/qingflow-record-crud/SKILL.md) for record browsing, detail lookup, create, update, and delete
|
|
20
|
-
- [$qingflow-task-ops](/Users/yanqidong/Documents/qingflow-next/.codex/skills/qingflow-task-ops/SKILL.md) for task-center usage, comments, approvals, rollback, transfer, urge, and directory lookup
|
|
21
|
-
- [$qingflow-record-analysis](/Users/yanqidong/Documents/qingflow-next/.codex/skills/qingflow-record-analysis/SKILL.md) for grouped analysis, ratios, rankings, trends, and final statistical conclusions
|
|
22
|
-
|
|
23
|
-
Before operating on data, identify whether the task targets `test` or `prod` and read [references/environments.md](references/environments.md).
|
|
24
|
-
If the user did not specify one, default to `prod`.
|
|
12
|
+
This skill is a lightweight router for operational Qingflow work.
|
|
13
|
+
Assumes MCP is connected, authenticated, and on the correct workspace.
|
|
25
14
|
|
|
26
15
|
## Default Paths
|
|
27
16
|
|
|
@@ -42,23 +31,19 @@ Route to exactly one of these specialized paths:
|
|
|
42
31
|
## Routing Rules
|
|
43
32
|
|
|
44
33
|
- If the user does not know the target `app_key`, discover apps first with `app_list` or `app_search`, then route to the specialized skill
|
|
45
|
-
- If the task is about browsing, reading, creating, updating, deleting, attachments, relations,
|
|
34
|
+
- If the task is about browsing, reading, creating, updating, deleting, attachments, relations, subtable writes, or member/department-field candidate lookup, switch to `$qingflow-record-crud`
|
|
46
35
|
- If the task is about inbox, todo, cc, task-center workload, comments, approval, reject, rollback, transfer, urge, or directory lookup, switch to `$qingflow-task-ops`
|
|
47
36
|
- If the task is about grouped distributions, ratios, rankings, trends, insights, or any final statistical conclusion, switch to `$qingflow-record-analysis`
|
|
48
37
|
- If the MCP is not connected, authenticated, or bound to the right workspace, switch to `$qingflow-mcp-setup`
|
|
49
38
|
|
|
50
39
|
## Shared Preconditions
|
|
51
40
|
|
|
52
|
-
- confirm environment first
|
|
53
|
-
- ensure auth exists
|
|
54
|
-
- ensure workspace is selected
|
|
55
41
|
- prefer canonical app ids, record ids, task ids, and workflow node ids over guessed names
|
|
56
42
|
- if a field or target is still ambiguous after schema/task lookup, ask the user to confirm from a short candidate list instead of guessing
|
|
57
43
|
- if the task can stay read-only, do not write or act
|
|
58
44
|
|
|
59
45
|
## Resources
|
|
60
46
|
|
|
61
|
-
- Environment switching: [references/environments.md](references/environments.md)
|
|
62
47
|
- Record CRUD: [$qingflow-record-crud](/Users/yanqidong/Documents/qingflow-next/.codex/skills/qingflow-record-crud/SKILL.md)
|
|
63
48
|
- Task center and workflow usage: [$qingflow-task-ops](/Users/yanqidong/Documents/qingflow-next/.codex/skills/qingflow-task-ops/SKILL.md)
|
|
64
49
|
- Dedicated analysis workflow: [$qingflow-record-analysis](/Users/yanqidong/Documents/qingflow-next/.codex/skills/qingflow-record-analysis/SKILL.md)
|
|
@@ -7,15 +7,15 @@ metadata:
|
|
|
7
7
|
|
|
8
8
|
# Qingflow Record Analysis
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
This skill is for final statistical conclusions only.
|
|
11
|
+
Assumes MCP is connected, authenticated, and on the correct workspace.
|
|
12
|
+
Analysis tasks must start with `record_schema_get`. Use field_id-based DSLs only.
|
|
12
13
|
|
|
13
14
|
## Step 1: `record_schema_get` → Step 2: build DSL → Step 3: `record_analyze`
|
|
14
15
|
|
|
15
16
|
This is the ONLY execution order. Never skip step 1. Never call `record_analyze` without a schema.
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
Comments, approvals, rollback, transfer, urge, and directory lookup stay in [$qingflow-task-ops](/Users/yanqidong/Documents/qingflow-next/.codex/skills/qingflow-task-ops/SKILL.md), not in this analysis skill.
|
|
18
|
+
Core tools: `record_schema_get`, `record_analyze`. Use `record_list`/`record_get` only for post-analysis samples; task/comment work stays in [$qingflow-task-ops](/Users/yanqidong/Documents/qingflow-next/.codex/skills/qingflow-task-ops/SKILL.md).
|
|
19
19
|
|
|
20
20
|
---
|
|
21
21
|
|
|
@@ -74,56 +74,32 @@ Comments, approvals, rollback, transfer, urge, and directory lookup stay in [$qi
|
|
|
74
74
|
|
|
75
75
|
---
|
|
76
76
|
|
|
77
|
-
|
|
77
|
+
See [references/dsl-templates.md](references/dsl-templates.md) for complete copy-paste templates.
|
|
78
78
|
|
|
79
|
+
**Typical summary / distribution:**
|
|
79
80
|
```json
|
|
80
81
|
{
|
|
81
|
-
"
|
|
82
|
-
"
|
|
83
|
-
|
|
84
|
-
],
|
|
85
|
-
"metrics": [
|
|
86
|
-
{ "op": "count", "alias": "记录数" }
|
|
87
|
-
],
|
|
88
|
-
"filters": [
|
|
89
|
-
{ "field_id": TIME_FIELD_ID, "op": "between", "value": ["2024-03-01", "2024-03-31"] }
|
|
90
|
-
],
|
|
91
|
-
"sort": [
|
|
92
|
-
{ "by": "记录数", "order": "desc" }
|
|
93
|
-
],
|
|
82
|
+
"dimensions": [{ "field_id": FIELD_ID_FROM_SCHEMA, "alias": "维度名" }],
|
|
83
|
+
"metrics": [{ "op": "count", "alias": "记录数" }],
|
|
84
|
+
"sort": [{ "by": "记录数", "order": "desc" }],
|
|
94
85
|
"limit": 50,
|
|
95
86
|
"strict_full": true
|
|
96
87
|
}
|
|
97
88
|
```
|
|
98
89
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
**Whole-table count (no grouping):**
|
|
102
|
-
```json
|
|
103
|
-
{ "dimensions": [], "metrics": [{"op":"count","alias":"记录数"}], "strict_full": true }
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
**Monthly trend:**
|
|
107
|
-
```json
|
|
108
|
-
{
|
|
109
|
-
"dimensions": [{"field_id": 3, "alias": "月份", "bucket":"month"}],
|
|
110
|
-
"metrics": [{"op":"count","alias":"记录数"}],
|
|
111
|
-
"sort": [{"by":"月份","order":"asc"}],
|
|
112
|
-
"limit": 24, "strict_full": true
|
|
113
|
-
}
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
**Cross analysis with sum:**
|
|
90
|
+
**Typical time-filter / trend:**
|
|
117
91
|
```json
|
|
118
92
|
{
|
|
119
|
-
"dimensions": [{"field_id":
|
|
120
|
-
"metrics": [{"op":"count","alias":"记录数"
|
|
121
|
-
"
|
|
122
|
-
"
|
|
93
|
+
"dimensions": [{ "field_id": TIME_FIELD_ID, "alias": "月份", "bucket": "month" }],
|
|
94
|
+
"metrics": [{ "op": "count", "alias": "记录数" }],
|
|
95
|
+
"filters": [{ "field_id": TIME_FIELD_ID, "op": "between", "value": ["2024-03-01", "2024-03-31"] }],
|
|
96
|
+
"sort": [{ "by": "月份", "order": "asc" }],
|
|
97
|
+
"limit": 24,
|
|
98
|
+
"strict_full": true
|
|
123
99
|
}
|
|
124
100
|
```
|
|
125
101
|
|
|
126
|
-
|
|
102
|
+
Top-level arguments:
|
|
127
103
|
|
|
128
104
|
- `app_key`: required.
|
|
129
105
|
- `dimensions`: `[]` = whole-table summary; `[{...}]` = grouped.
|
|
@@ -136,12 +112,10 @@ More templates:
|
|
|
136
112
|
|
|
137
113
|
## RULES
|
|
138
114
|
|
|
139
|
-
- Normalize relative time phrases into explicit legal date ranges.
|
|
140
115
|
- 渗透率 / 转化率 / 占比类结论必须先定义分子和分母。
|
|
141
116
|
- Do not claim a metric you did not query.
|
|
142
117
|
- Derived ratios must be computed outside the DSL.
|
|
143
118
|
- Before choosing a DSL shape, first decide whether the question needs `count`, `sum`, `avg`, `distinct_count`, `ratio`, or `ranking`.
|
|
144
|
-
- If a field is still ambiguous after `record_schema_get`, do not guess; ask the user to confirm from a short candidate list.
|
|
145
119
|
- Rankings must come from structured sorted results.
|
|
146
120
|
- For partial answers, explicitly disclose which parts are complete and which parts remain unresolved.
|
|
147
121
|
- Complex answers should default to `先结构、后解读`.
|
|
@@ -150,33 +124,25 @@ More templates:
|
|
|
150
124
|
- Final wording should stay as close as possible to schema titles.
|
|
151
125
|
- Do not pass field titles, aliases, or guessed ids.
|
|
152
126
|
- If `completeness.statement_scope=returned_groups_only` or `completeness.rows_truncated=true`, downgrade wording to returned groups only.
|
|
153
|
-
- All `field_id` MUST come from `record_schema_get`. Never guess or use field titles.
|
|
154
127
|
- One DSL per question. Multiple small DSLs > one overloaded request.
|
|
155
|
-
- Normalize relative dates to concrete ranges BEFORE building DSL. Never send impossible dates (e.g. `2026-02-29`).
|
|
156
|
-
- If schema has ambiguous fields, ask user to pick from a short list. Do not guess.
|
|
157
128
|
- `record_list` is NEVER the basis for final statistics.
|
|
158
|
-
- Derived ratios: run numerator and denominator as separate DSLs, compute ratio in your reasoning.
|
|
159
129
|
- Set `alias` for any metric you will sort by, compare, or quote.
|
|
160
130
|
|
|
161
131
|
---
|
|
162
132
|
|
|
163
|
-
## OUTPUT
|
|
164
|
-
|
|
165
|
-
### 必须逐行列出数据(硬性要求)
|
|
166
|
-
|
|
167
|
-
final_answer MUST include a table with every row from `result.rows`:
|
|
168
|
-
|
|
169
|
-
| {维度别名} | {指标别名} | 占比 |
|
|
170
|
-
|------------|-----------|------|
|
|
171
|
-
| {row.dimensions.X} | {row.metrics.Y} | {Y / total * 100}% |
|
|
172
|
-
|
|
173
|
-
- 占比 = 行指标值 / `result.totals.metric_totals` 总值, 保留一位小数
|
|
174
|
-
- 如 `metric_totals` 不存在, 用各行之和作分母
|
|
175
|
-
- 超过 20 行展示 Top 20 并注明
|
|
176
|
-
- 不得只写"共 N 种类型"而省略明细
|
|
177
|
-
|
|
178
|
-
### 结论分级
|
|
133
|
+
## OUTPUT
|
|
179
134
|
|
|
135
|
+
- Final answer must show concrete numbers.
|
|
136
|
+
- If `result.rows` exists, list each returned row; if there are more than 20 rows, show Top 20 and say so.
|
|
137
|
+
- 占比 = 行指标值 / `result.totals.metric_totals` 总值;如 `metric_totals` 缺失,用各行之和作分母。
|
|
138
|
+
- Prefer the structured `ranking` block when it exists.
|
|
180
139
|
- `safe_for_final_conclusion=true` → `全量可信结论`
|
|
181
|
-
-
|
|
140
|
+
- Otherwise → `初步观察`
|
|
182
141
|
- `rows_truncated=true` → 用 `前 N 个分组`, 不用 `全部`/`所有`
|
|
142
|
+
|
|
143
|
+
## Resources
|
|
144
|
+
|
|
145
|
+
- DSL templates: [references/dsl-templates.md](references/dsl-templates.md)
|
|
146
|
+
- Analysis patterns: [references/analysis-patterns.md](references/analysis-patterns.md)
|
|
147
|
+
- Confidence reporting: [references/confidence-reporting.md](references/confidence-reporting.md)
|
|
148
|
+
- Analysis gotchas: [references/analysis-gotchas.md](references/analysis-gotchas.md)
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# DSL Templates
|
|
2
|
+
|
|
3
|
+
Use these copy-paste templates after `record_schema_get`.
|
|
4
|
+
|
|
5
|
+
## Whole-table summary
|
|
6
|
+
|
|
7
|
+
```json
|
|
8
|
+
{
|
|
9
|
+
"dimensions": [],
|
|
10
|
+
"metrics": [
|
|
11
|
+
{ "op": "count", "alias": "记录数" }
|
|
12
|
+
],
|
|
13
|
+
"strict_full": true
|
|
14
|
+
}
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Distribution / ranking
|
|
18
|
+
|
|
19
|
+
```json
|
|
20
|
+
{
|
|
21
|
+
"dimensions": [
|
|
22
|
+
{ "field_id": 9500572, "alias": "报价类型" }
|
|
23
|
+
],
|
|
24
|
+
"metrics": [
|
|
25
|
+
{ "op": "count", "alias": "记录数" }
|
|
26
|
+
],
|
|
27
|
+
"sort": [
|
|
28
|
+
{ "by": "记录数", "order": "desc" }
|
|
29
|
+
],
|
|
30
|
+
"limit": 50,
|
|
31
|
+
"strict_full": true
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Time-filtered distribution
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"app_key": "YOUR_APP_KEY",
|
|
40
|
+
"dimensions": [
|
|
41
|
+
{ "field_id": 9500572, "alias": "维度名" }
|
|
42
|
+
],
|
|
43
|
+
"metrics": [
|
|
44
|
+
{ "op": "count", "alias": "记录数" }
|
|
45
|
+
],
|
|
46
|
+
"filters": [
|
|
47
|
+
{ "field_id": 3, "op": "between", "value": ["2024-03-01", "2024-03-31"] }
|
|
48
|
+
],
|
|
49
|
+
"sort": [
|
|
50
|
+
{ "by": "记录数", "order": "desc" }
|
|
51
|
+
],
|
|
52
|
+
"limit": 50,
|
|
53
|
+
"strict_full": true
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Monthly trend
|
|
58
|
+
|
|
59
|
+
```json
|
|
60
|
+
{
|
|
61
|
+
"dimensions": [
|
|
62
|
+
{ "field_id": 3, "alias": "月份", "bucket": "month" }
|
|
63
|
+
],
|
|
64
|
+
"metrics": [
|
|
65
|
+
{ "op": "count", "alias": "记录数" }
|
|
66
|
+
],
|
|
67
|
+
"sort": [
|
|
68
|
+
{ "by": "月份", "order": "asc" }
|
|
69
|
+
],
|
|
70
|
+
"limit": 24,
|
|
71
|
+
"strict_full": true
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Cross analysis with sum
|
|
76
|
+
|
|
77
|
+
```json
|
|
78
|
+
{
|
|
79
|
+
"dimensions": [
|
|
80
|
+
{ "field_id": 2, "alias": "状态" },
|
|
81
|
+
{ "field_id": 5, "alias": "负责人" }
|
|
82
|
+
],
|
|
83
|
+
"metrics": [
|
|
84
|
+
{ "op": "count", "alias": "记录数" },
|
|
85
|
+
{ "op": "sum", "field_id": 7, "alias": "总金额" }
|
|
86
|
+
],
|
|
87
|
+
"sort": [
|
|
88
|
+
{ "by": "记录数", "order": "desc" }
|
|
89
|
+
],
|
|
90
|
+
"limit": 100,
|
|
91
|
+
"strict_full": true
|
|
92
|
+
}
|
|
93
|
+
```
|
|
@@ -9,44 +9,16 @@ metadata:
|
|
|
9
9
|
|
|
10
10
|
## Overview
|
|
11
11
|
|
|
12
|
-
This skill is for
|
|
13
|
-
|
|
14
|
-
Use it for:
|
|
15
|
-
|
|
16
|
-
- record browsing
|
|
17
|
-
- record detail lookup
|
|
18
|
-
- record create / update / delete
|
|
19
|
-
- attachment preflight before a write
|
|
20
|
-
- relation/member/department lookup that directly supports a write
|
|
21
|
-
|
|
22
|
-
Do **not** use this skill for:
|
|
23
|
-
|
|
24
|
-
- grouped analysis, ratios, rankings, trends, or final statistical conclusions
|
|
25
|
-
Switch to [$qingflow-record-analysis](/Users/yanqidong/Documents/qingflow-next/.codex/skills/qingflow-record-analysis/SKILL.md)
|
|
26
|
-
- task-center workflow actions, comments, or directory-driven operational workflows
|
|
27
|
-
Switch to [$qingflow-task-ops](/Users/yanqidong/Documents/qingflow-next/.codex/skills/qingflow-task-ops/SKILL.md)
|
|
28
|
-
|
|
29
|
-
This skill assumes the MCP is already connected, authenticated, and bound to the correct workspace.
|
|
30
|
-
If not, switch to [$qingflow-mcp-setup](/Users/yanqidong/.codex/skills/qingflow-mcp-setup/SKILL.md) first.
|
|
31
|
-
|
|
32
|
-
Before operating on data, identify whether the task targets `test` or `prod` and read [references/environments.md](references/environments.md).
|
|
33
|
-
If the user did not specify one, default to `prod`.
|
|
12
|
+
This skill is for record CRUD only inside existing Qingflow apps.
|
|
13
|
+
Assumes MCP is connected, authenticated, and on the correct workspace.
|
|
34
14
|
|
|
35
15
|
## Default Paths
|
|
36
16
|
|
|
37
17
|
Use exactly one of these default paths:
|
|
38
18
|
|
|
39
|
-
1. Browse records
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
2. Read one record
|
|
43
|
-
`record_schema_get -> record_get`
|
|
44
|
-
|
|
45
|
-
3. Write records
|
|
46
|
-
`record_schema_get -> record_write`
|
|
47
|
-
|
|
48
|
-
4. Analysis
|
|
49
|
-
Switch to [$qingflow-record-analysis](/Users/yanqidong/Documents/qingflow-next/.codex/skills/qingflow-record-analysis/SKILL.md)
|
|
19
|
+
1. Browse records: `record_schema_get -> record_list`
|
|
20
|
+
2. Read one record: `record_schema_get -> record_get`
|
|
21
|
+
3. Write records: `record_schema_get -> record_write`
|
|
50
22
|
|
|
51
23
|
## Core Tools
|
|
52
24
|
|
|
@@ -55,16 +27,14 @@ Use exactly one of these default paths:
|
|
|
55
27
|
- `record_get`
|
|
56
28
|
- `record_write`
|
|
57
29
|
|
|
58
|
-
`record_schema_get`
|
|
59
|
-
|
|
60
|
-
- only fields visible to the current user at the applicant node are returned
|
|
61
|
-
- hidden fields are omitted entirely
|
|
62
|
-
- missing fields should be treated as `当前用户在申请人节点下不可见/不可用`, not as a reason to guess a different field
|
|
30
|
+
`record_schema_get` only exposes the current user's applicant-node visible fields; if a field is missing, treat it as unavailable in the current permission scope.
|
|
63
31
|
|
|
64
32
|
## Supporting Tools
|
|
65
33
|
|
|
66
34
|
- `app_list`
|
|
67
35
|
- `app_search`
|
|
36
|
+
- `record_member_candidates`
|
|
37
|
+
- `record_department_candidates`
|
|
68
38
|
- `directory_search`
|
|
69
39
|
- `directory_list_internal_users`
|
|
70
40
|
- `directory_list_internal_departments`
|
|
@@ -90,15 +60,7 @@ Use exactly one of these default paths:
|
|
|
90
60
|
- Use `record_list` for browse/export/sample inspection only
|
|
91
61
|
- Use `record_get` when `record_id` is known
|
|
92
62
|
- `record_get` without explicit `columns` still returns only applicant-node visible fields; do not assume it exposes the full builder-side record
|
|
93
|
-
- `record_list` accepts:
|
|
94
|
-
- `columns`
|
|
95
|
-
- `where`
|
|
96
|
-
- `order_by`
|
|
97
|
-
- `limit`
|
|
98
|
-
- `page`
|
|
99
63
|
- `record_list` and `record_get` may reject hidden-field `field_id`s because record tools now validate against the applicant-node visible schema only
|
|
100
|
-
- `record_list` is **not** an analysis tool
|
|
101
|
-
- If a request turns into grouped distributions, ratios, rankings, trends, or final statistical conclusions, switch to [$qingflow-record-analysis](/Users/yanqidong/Documents/qingflow-next/.codex/skills/qingflow-record-analysis/SKILL.md)
|
|
102
64
|
|
|
103
65
|
## Record Write Rules
|
|
104
66
|
|
|
@@ -108,51 +70,24 @@ Use `record_write` as the only default write tool.
|
|
|
108
70
|
|
|
109
71
|
1. Run `record_schema_get`
|
|
110
72
|
2. Decide whether the task is `insert`, `update`, or `delete`
|
|
111
|
-
3.
|
|
112
|
-
4.
|
|
113
|
-
5.
|
|
114
|
-
6.
|
|
115
|
-
7.
|
|
73
|
+
3. For relation fields, read `target_app_key / target_app_name` from schema first
|
|
74
|
+
4. For member fields with unknown ids, run `record_member_candidates`
|
|
75
|
+
5. For department fields with unknown ids, run `record_department_candidates`
|
|
76
|
+
6. Build SQL-like JSON clauses
|
|
77
|
+
7. Run `record_write`
|
|
78
|
+
8. If `ok=false`, explain `field_errors` first, then summarize blockers; do not report a write as executed
|
|
79
|
+
9. If `ok=true`, report the affected `record_id` or created resource
|
|
80
|
+
10. For important writes, keep `verify_write=true`
|
|
116
81
|
|
|
117
82
|
### SQL-like JSON DSL
|
|
118
83
|
|
|
119
84
|
The DSL is clause-shaped like SQL, but it is **not raw SQL text**.
|
|
120
85
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
{
|
|
125
|
-
|
|
126
|
-
"values": [
|
|
127
|
-
{ "field_id": 12, "value": "测试客户" },
|
|
128
|
-
{ "field_id": 18, "value": 1000 }
|
|
129
|
-
],
|
|
130
|
-
"submit_type": "submit",
|
|
131
|
-
"verify_write": true
|
|
132
|
-
}
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
#### Update
|
|
136
|
-
|
|
137
|
-
```json
|
|
138
|
-
{
|
|
139
|
-
"operation": "update",
|
|
140
|
-
"record_id": 123,
|
|
141
|
-
"set": [
|
|
142
|
-
{ "field_id": 18, "value": 2000 }
|
|
143
|
-
],
|
|
144
|
-
"verify_write": true
|
|
145
|
-
}
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
#### Delete
|
|
149
|
-
|
|
150
|
-
```json
|
|
151
|
-
{
|
|
152
|
-
"operation": "delete",
|
|
153
|
-
"record_ids": [123, 124]
|
|
154
|
-
}
|
|
155
|
-
```
|
|
86
|
+
| operation | required shape | compact example |
|
|
87
|
+
|-----------|----------------|-----------------|
|
|
88
|
+
| `insert` | `values` | `{"operation":"insert","values":[{"field_id":12,"value":"测试客户"}]}` |
|
|
89
|
+
| `update` | `record_id + set` | `{"operation":"update","record_id":123,"set":[{"field_id":18,"value":2000}]}` |
|
|
90
|
+
| `delete` | `record_id` or `record_ids` | `{"operation":"delete","record_ids":[123,124]}` |
|
|
156
91
|
|
|
157
92
|
### Write discipline
|
|
158
93
|
|
|
@@ -164,7 +99,9 @@ The DSL is clause-shaped like SQL, but it is **not raw SQL text**.
|
|
|
164
99
|
- Do not use free-form `WHERE` updates or deletes
|
|
165
100
|
- Do not auto-fill missing fields
|
|
166
101
|
- Do not auto-resolve relation targets without first querying them
|
|
167
|
-
- Do not assume
|
|
102
|
+
- Do not assume member display names resolve automatically; `record_member_candidates` returns ids, but direct name-to-id write is not automatic
|
|
103
|
+
- Do not assume department names resolve automatically; `record_department_candidates` returns ids, but direct name-to-id write is not automatic
|
|
104
|
+
- Do not assume `record_schema_get` is a builder/full-field schema.
|
|
168
105
|
|
|
169
106
|
## Response Interpretation
|
|
170
107
|
|
|
@@ -173,12 +110,10 @@ The DSL is clause-shaped like SQL, but it is **not raw SQL text**.
|
|
|
173
110
|
- If `record_write` returns `ok=false`, the write was blocked and not executed
|
|
174
111
|
- Prefer explaining `field_errors` before summarizing top-level blockers
|
|
175
112
|
- If `record_write` returns `ok=true`, still check `verification` and `warnings` before claiming success
|
|
176
|
-
- Treat `request_route` as the source of truth for live route debugging
|
|
177
113
|
- Prefer canonical schema titles and aliases in your final wording
|
|
178
114
|
- If only part of the requested work is completed, explicitly disclose which parts are done and which are not
|
|
179
115
|
|
|
180
116
|
## Resources
|
|
181
117
|
|
|
182
|
-
- Environment switching: [references/environments.md](references/environments.md)
|
|
183
118
|
- Record operation patterns: [references/record-patterns.md](references/record-patterns.md)
|
|
184
119
|
- Data gotchas: [references/data-gotchas.md](references/data-gotchas.md)
|
|
@@ -9,29 +9,8 @@ metadata:
|
|
|
9
9
|
|
|
10
10
|
## Overview
|
|
11
11
|
|
|
12
|
-
This skill is for
|
|
13
|
-
|
|
14
|
-
Use it for:
|
|
15
|
-
|
|
16
|
-
- task-center browsing
|
|
17
|
-
- headline task counts
|
|
18
|
-
- grouped worksheet or workflow-node workload views
|
|
19
|
-
- approve / reject / rollback / transfer / urge
|
|
20
|
-
- record comments
|
|
21
|
-
- directory lookup that supports task or comment actions
|
|
22
|
-
|
|
23
|
-
Do **not** use this skill for:
|
|
24
|
-
|
|
25
|
-
- record create / update / delete
|
|
26
|
-
Switch to [$qingflow-record-crud](/Users/yanqidong/Documents/qingflow-next/.codex/skills/qingflow-record-crud/SKILL.md)
|
|
27
|
-
- grouped analysis, ratios, rankings, trends, or final statistical conclusions
|
|
28
|
-
Switch to [$qingflow-record-analysis](/Users/yanqidong/Documents/qingflow-next/.codex/skills/qingflow-record-analysis/SKILL.md)
|
|
29
|
-
|
|
30
|
-
This skill assumes the MCP is already connected, authenticated, and bound to the correct workspace.
|
|
31
|
-
If not, switch to [$qingflow-mcp-setup](/Users/yanqidong/.codex/skills/qingflow-mcp-setup/SKILL.md) first.
|
|
32
|
-
|
|
33
|
-
Before operating on live work, identify whether the task targets `test` or `prod` and read [references/environments.md](references/environments.md).
|
|
34
|
-
If the user did not specify one, default to `prod`.
|
|
12
|
+
This skill is for task-center and workflow usage operations only.
|
|
13
|
+
Assumes MCP is connected, authenticated, and on the correct workspace.
|
|
35
14
|
|
|
36
15
|
## Default Paths
|
|
37
16
|
|
|
@@ -143,6 +122,4 @@ Use exactly one of these default paths:
|
|
|
143
122
|
|
|
144
123
|
## Resources
|
|
145
124
|
|
|
146
|
-
- Environment switching: [references/environments.md](references/environments.md)
|
|
147
125
|
- Workflow and task usage actions: [references/workflow-usage.md](references/workflow-usage.md)
|
|
148
|
-
|
|
@@ -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,88 @@ 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
|
+
|
|
57
|
+
## Analytics Path
|
|
58
|
+
|
|
59
|
+
`record_schema_get -> record_analyze`
|
|
60
|
+
|
|
61
|
+
Use this DSL shape:
|
|
62
|
+
|
|
63
|
+
- `dimensions`: `{{field_id, alias, bucket}}`
|
|
64
|
+
- `metrics`: `{{op, field_id, alias}}`
|
|
65
|
+
- `filters`: `{{field_id, op, value}}`
|
|
66
|
+
- `sort`: `{{by, order}}`
|
|
67
|
+
|
|
68
|
+
Important key rules:
|
|
69
|
+
|
|
70
|
+
- Use `op`
|
|
71
|
+
- Do **not** use `type`
|
|
72
|
+
- Do **not** use `agg`
|
|
73
|
+
- Do **not** use `aggregation`
|
|
74
|
+
- Do **not** use `operator`
|
|
75
|
+
|
|
76
|
+
Analysis answers must include concrete numbers. When applicable, include percentages based on the returned totals.
|
|
77
|
+
|
|
78
|
+
## Record CRUD Path
|
|
79
|
+
|
|
80
|
+
`record_schema_get -> record_list / record_get / record_write`
|
|
81
|
+
|
|
82
|
+
`record_write` uses SQL-like JSON clauses:
|
|
83
|
+
|
|
84
|
+
- `insert` -> `values`
|
|
85
|
+
- `update` -> `record_id + set`
|
|
86
|
+
- `delete` -> `record_id` or `record_ids`
|
|
87
|
+
|
|
88
|
+
- Read relation targets from `record_schema_get.target_app_key` / `target_app_name` before preparing relation writes.
|
|
89
|
+
- 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`.
|
|
90
|
+
|
|
91
|
+
## Task Center Path
|
|
92
|
+
|
|
93
|
+
`task_summary -> task_list / task_facets -> task action`
|
|
94
|
+
|
|
95
|
+
## Time Handling
|
|
96
|
+
|
|
97
|
+
Normalize relative dates before building DSL.
|
|
98
|
+
|
|
99
|
+
- If the user says `3月` without a year, use the current year: `{current_year}`
|
|
100
|
+
- Convert month-only phrases into explicit legal date ranges
|
|
101
|
+
- Never send impossible dates such as `2026-02-29`
|
|
102
|
+
|
|
103
|
+
## Environment
|
|
104
|
+
|
|
105
|
+
Default to `prod` unless the user explicitly specifies `test`.
|
|
106
|
+
|
|
107
|
+
## Constraints
|
|
108
|
+
|
|
109
|
+
Avoid builder-side app or schema changes here.""",
|
|
45
110
|
)
|
|
46
111
|
sessions = SessionStore()
|
|
47
112
|
backend = BackendClient()
|