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 CHANGED
@@ -117,7 +117,7 @@ npm i -g git+https://github.com/853046310/qingflow-mcp.git
117
117
  Install from npm (pinned version):
118
118
 
119
119
  ```bash
120
- npm i -g qingflow-mcp@0.3.19
120
+ npm i -g qingflow-mcp@0.3.20
121
121
  ```
122
122
 
123
123
  Or one-click installer:
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.19";
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
- try {
5610
- const response = await client.getRecord(applyId);
5611
- metaResponse = metaResponse ?? buildMeta(response);
5612
- const record = asObject(response.result) ?? {};
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
- const response = await client.getRecord(String(args.apply_id));
6190
- const record = asObject(response.result) ?? {};
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.answers),
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.applyId ?? null,
6201
- answers: asArray(record.answers),
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.applyId ?? null,
6287
+ apply_id: record?.applyId ?? null,
6227
6288
  row,
6228
6289
  applied_limits: {
6229
6290
  column_cap: args.max_columns ?? null,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qingflow-mcp",
3
- "version": "0.3.19",
3
+ "version": "0.3.20",
4
4
  "private": false,
5
5
  "license": "MIT",
6
6
  "type": "module",