qingflow-mcp 0.3.19 → 0.3.20
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 +1 -1
- package/dist/server.js +85 -24
- package/package.json +1 -1
package/README.md
CHANGED
package/dist/server.js
CHANGED
|
@@ -65,7 +65,7 @@ const REQUEST_TIMEOUT_MS = toPositiveInt(process.env.QINGFLOW_REQUEST_TIMEOUT_MS
|
|
|
65
65
|
const EXECUTION_BUDGET_MS = toPositiveInt(process.env.QINGFLOW_EXECUTION_BUDGET_MS) ?? 20000;
|
|
66
66
|
const WAIT_RESULT_DEFAULT_TIMEOUT_MS = toPositiveInt(process.env.QINGFLOW_WAIT_RESULT_TIMEOUT_MS) ?? 5000;
|
|
67
67
|
const WAIT_RESULT_POLL_INTERVAL_MS = toPositiveInt(process.env.QINGFLOW_WAIT_RESULT_POLL_INTERVAL_MS) ?? 500;
|
|
68
|
-
const SERVER_VERSION = "0.3.
|
|
68
|
+
const SERVER_VERSION = "0.3.20";
|
|
69
69
|
const accessToken = process.env.QINGFLOW_ACCESS_TOKEN;
|
|
70
70
|
const baseUrl = process.env.QINGFLOW_BASE_URL;
|
|
71
71
|
if (!accessToken) {
|
|
@@ -745,12 +745,14 @@ const listOutputSchema = listSuccessOutputSchema;
|
|
|
745
745
|
const recordGetInputPublicSchema = z
|
|
746
746
|
.object({
|
|
747
747
|
apply_id: publicFieldSelectorSchema,
|
|
748
|
+
app_key: publicStringSchema.optional(),
|
|
748
749
|
max_columns: z.number().int().positive().max(MAX_COLUMN_LIMIT).optional(),
|
|
749
750
|
select_columns: z.array(publicFieldSelectorSchema).min(1).max(MAX_COLUMN_LIMIT),
|
|
750
751
|
output_profile: outputProfileSchema.optional()
|
|
751
752
|
});
|
|
752
753
|
const recordGetInputSchema = z.preprocess(normalizeRecordGetInput, z.object({
|
|
753
754
|
apply_id: z.union([z.string().min(1), z.number().int()]),
|
|
755
|
+
app_key: z.string().min(1).optional(),
|
|
754
756
|
max_columns: z.number().int().positive().max(MAX_COLUMN_LIMIT).optional(),
|
|
755
757
|
select_columns: z
|
|
756
758
|
.array(z.union([z.string().min(1), z.number().int()]))
|
|
@@ -2832,6 +2834,17 @@ function buildMeta(response) {
|
|
|
2832
2834
|
base_url: baseUrl
|
|
2833
2835
|
};
|
|
2834
2836
|
}
|
|
2837
|
+
async function fetchRecordsByApplyIds(params) {
|
|
2838
|
+
const response = await client.listRecords(params.appKey, buildListPayload({
|
|
2839
|
+
pageNum: 1,
|
|
2840
|
+
pageSize: Math.min(Math.max(params.applyIds.length, 1), 200),
|
|
2841
|
+
applyIds: params.applyIds
|
|
2842
|
+
}), { userId: params.userId });
|
|
2843
|
+
const records = asArray(asObject(response.result)?.result)
|
|
2844
|
+
.map((item) => asObject(item))
|
|
2845
|
+
.filter((item) => Boolean(item));
|
|
2846
|
+
return { response, records };
|
|
2847
|
+
}
|
|
2835
2848
|
function normalizeStringArray(value) {
|
|
2836
2849
|
return uniqueStringList(asArray(value)
|
|
2837
2850
|
.map((item) => asNullableString(item)?.trim() ?? "")
|
|
@@ -3783,6 +3796,7 @@ function normalizeRecordGetInput(raw) {
|
|
|
3783
3796
|
return {
|
|
3784
3797
|
...normalizedObj,
|
|
3785
3798
|
apply_id: coerceNumberLike(normalizedObj.apply_id),
|
|
3799
|
+
app_key: coerceStringLike(normalizedObj.app_key),
|
|
3786
3800
|
max_columns: coerceNumberLike(normalizedObj.max_columns),
|
|
3787
3801
|
select_columns: normalizeSelectorListInput(selectColumns),
|
|
3788
3802
|
output_profile: normalizeOutputProfileInput(normalizedObj.output_profile)
|
|
@@ -3903,6 +3917,7 @@ function normalizeBatchGetInput(raw) {
|
|
|
3903
3917
|
const selectColumns = normalizedObj.select_columns ?? normalizedObj.keep_columns;
|
|
3904
3918
|
return {
|
|
3905
3919
|
...normalizedObj,
|
|
3920
|
+
app_key: coerceStringLike(normalizedObj.app_key),
|
|
3906
3921
|
apply_ids: normalizeIdArrayInput(normalizedObj.apply_ids),
|
|
3907
3922
|
max_columns: coerceNumberLike(normalizedObj.max_columns),
|
|
3908
3923
|
select_columns: normalizeSelectorListInput(selectColumns),
|
|
@@ -5503,6 +5518,7 @@ function buildRecordGetArgsFromQuery(args) {
|
|
|
5503
5518
|
}
|
|
5504
5519
|
return recordGetInputSchema.parse({
|
|
5505
5520
|
apply_id: args.apply_id,
|
|
5521
|
+
app_key: args.app_key,
|
|
5506
5522
|
max_columns: args.max_columns,
|
|
5507
5523
|
select_columns: args.select_columns,
|
|
5508
5524
|
output_profile: args.output_profile
|
|
@@ -5588,6 +5604,13 @@ async function executeQueryPlan(args) {
|
|
|
5588
5604
|
};
|
|
5589
5605
|
}
|
|
5590
5606
|
async function executeRecordsBatchGet(args) {
|
|
5607
|
+
if (!args.app_key) {
|
|
5608
|
+
throw missingRequiredFieldError({
|
|
5609
|
+
field: "app_key",
|
|
5610
|
+
tool: "qf_records_batch_get",
|
|
5611
|
+
fixHint: "Provide app_key, for example: {\"app_key\":\"21b3d559\",\"apply_ids\":[\"...\"],\"select_columns\":[0]}."
|
|
5612
|
+
});
|
|
5613
|
+
}
|
|
5591
5614
|
if (!args.select_columns?.length) {
|
|
5592
5615
|
throw missingRequiredFieldError({
|
|
5593
5616
|
field: "select_columns",
|
|
@@ -5605,25 +5628,23 @@ async function executeRecordsBatchGet(args) {
|
|
|
5605
5628
|
const rows = [];
|
|
5606
5629
|
const missingApplyIds = [];
|
|
5607
5630
|
let metaResponse = null;
|
|
5631
|
+
const { response, records } = await fetchRecordsByApplyIds({
|
|
5632
|
+
appKey: args.app_key,
|
|
5633
|
+
applyIds: requestedApplyIds
|
|
5634
|
+
});
|
|
5635
|
+
metaResponse = buildMeta(response);
|
|
5636
|
+
const byApplyId = new Map(records.map((record) => [String(record.applyId ?? ""), record]));
|
|
5608
5637
|
for (const applyId of requestedApplyIds) {
|
|
5609
|
-
|
|
5610
|
-
|
|
5611
|
-
|
|
5612
|
-
|
|
5613
|
-
rows.push(buildFlatRowFromAnswers({
|
|
5614
|
-
applyId: record.applyId ?? applyId,
|
|
5615
|
-
answers: asArray(record.answers),
|
|
5616
|
-
selectedColumns: selectedColumnsForRow
|
|
5617
|
-
}));
|
|
5618
|
-
}
|
|
5619
|
-
catch (error) {
|
|
5620
|
-
if (error instanceof QingflowApiError &&
|
|
5621
|
-
(error.httpStatus === 404 || error.errCode === 404)) {
|
|
5622
|
-
missingApplyIds.push(applyId);
|
|
5623
|
-
continue;
|
|
5624
|
-
}
|
|
5625
|
-
throw error;
|
|
5638
|
+
const record = byApplyId.get(String(applyId));
|
|
5639
|
+
if (!record) {
|
|
5640
|
+
missingApplyIds.push(applyId);
|
|
5641
|
+
continue;
|
|
5626
5642
|
}
|
|
5643
|
+
rows.push(buildFlatRowFromAnswers({
|
|
5644
|
+
applyId: record.applyId ?? applyId,
|
|
5645
|
+
answers: asArray(record.answers),
|
|
5646
|
+
selectedColumns: selectedColumnsForRow
|
|
5647
|
+
}));
|
|
5627
5648
|
}
|
|
5628
5649
|
const completeness = {
|
|
5629
5650
|
result_amount: requestedApplyIds.length,
|
|
@@ -6186,10 +6207,50 @@ async function executeRecordGet(args) {
|
|
|
6186
6207
|
}
|
|
6187
6208
|
const outputProfile = resolveOutputProfile(args.output_profile);
|
|
6188
6209
|
const queryId = randomUUID();
|
|
6189
|
-
|
|
6190
|
-
|
|
6210
|
+
let response;
|
|
6211
|
+
let record = null;
|
|
6212
|
+
try {
|
|
6213
|
+
response = await client.getRecord(String(args.apply_id));
|
|
6214
|
+
record = asObject(response.result) ?? {};
|
|
6215
|
+
}
|
|
6216
|
+
catch (error) {
|
|
6217
|
+
const providerError = error instanceof QingflowApiError ? error : null;
|
|
6218
|
+
const shouldFallback = providerError && (providerError.httpStatus === 404 || providerError.errCode === 404 || providerError.errCode === 49304);
|
|
6219
|
+
if (!shouldFallback) {
|
|
6220
|
+
throw error;
|
|
6221
|
+
}
|
|
6222
|
+
if (!args.app_key) {
|
|
6223
|
+
throw new InputValidationError({
|
|
6224
|
+
message: `qf_record_get could not read apply_id \"${String(args.apply_id)}\" through the direct record endpoint`,
|
|
6225
|
+
errorCode: "APP_KEY_REQUIRED_FOR_RECORD_GET",
|
|
6226
|
+
fixHint: "Retry qf_record_get with app_key, or use qf_query/qf_records_batch_get with explicit app_key for this record.",
|
|
6227
|
+
details: {
|
|
6228
|
+
apply_id: String(args.apply_id),
|
|
6229
|
+
provider_err_code: providerError?.errCode ?? null,
|
|
6230
|
+
provider_err_msg: providerError?.errMsg ?? null
|
|
6231
|
+
}
|
|
6232
|
+
});
|
|
6233
|
+
}
|
|
6234
|
+
const fallback = await fetchRecordsByApplyIds({
|
|
6235
|
+
appKey: args.app_key,
|
|
6236
|
+
applyIds: [String(args.apply_id)]
|
|
6237
|
+
});
|
|
6238
|
+
response = fallback.response;
|
|
6239
|
+
record = fallback.records.find((item) => String(item.applyId ?? "") === String(args.apply_id)) ?? null;
|
|
6240
|
+
if (!record) {
|
|
6241
|
+
throw new InputValidationError({
|
|
6242
|
+
message: `Record \"${String(args.apply_id)}\" not found in app \"${args.app_key}\"`,
|
|
6243
|
+
errorCode: "RECORD_NOT_FOUND",
|
|
6244
|
+
fixHint: "Confirm apply_id and app_key, or fetch the row via qf_records_list/qf_query first.",
|
|
6245
|
+
details: {
|
|
6246
|
+
apply_id: String(args.apply_id),
|
|
6247
|
+
app_key: args.app_key
|
|
6248
|
+
}
|
|
6249
|
+
});
|
|
6250
|
+
}
|
|
6251
|
+
}
|
|
6191
6252
|
const projection = projectAnswersForOutput({
|
|
6192
|
-
answers: asArray(record
|
|
6253
|
+
answers: asArray(record?.answers),
|
|
6193
6254
|
maxColumns: args.max_columns,
|
|
6194
6255
|
selectColumns: args.select_columns
|
|
6195
6256
|
});
|
|
@@ -6197,8 +6258,8 @@ async function executeRecordGet(args) {
|
|
|
6197
6258
|
? (projection.selectedColumns ?? []).slice(0, args.max_columns)
|
|
6198
6259
|
: projection.selectedColumns ?? [];
|
|
6199
6260
|
const row = buildFlatRowFromAnswers({
|
|
6200
|
-
applyId: record
|
|
6201
|
-
answers: asArray(record
|
|
6261
|
+
applyId: record?.applyId ?? null,
|
|
6262
|
+
answers: asArray(record?.answers),
|
|
6202
6263
|
selectedColumns: selectedColumnsForRow
|
|
6203
6264
|
});
|
|
6204
6265
|
const completeness = {
|
|
@@ -6223,7 +6284,7 @@ async function executeRecordGet(args) {
|
|
|
6223
6284
|
payload: {
|
|
6224
6285
|
ok: true,
|
|
6225
6286
|
data: {
|
|
6226
|
-
apply_id: record
|
|
6287
|
+
apply_id: record?.applyId ?? null,
|
|
6227
6288
|
row,
|
|
6228
6289
|
applied_limits: {
|
|
6229
6290
|
column_cap: args.max_columns ?? null,
|