qingflow-mcp 0.3.20 → 0.3.21
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 +76 -6
- package/package.json +1 -1
package/README.md
CHANGED
package/dist/server.js
CHANGED
|
@@ -46,6 +46,9 @@ class InputValidationError extends Error {
|
|
|
46
46
|
}
|
|
47
47
|
const FORM_CACHE_TTL_MS = Number(process.env.QINGFLOW_FORM_CACHE_TTL_MS ?? "300000");
|
|
48
48
|
const formCache = new Map();
|
|
49
|
+
const APPLY_APP_KEY_CACHE_TTL_MS = Number(process.env.QINGFLOW_APPLY_APP_KEY_CACHE_TTL_MS ?? "1800000");
|
|
50
|
+
const applyAppKeyCache = new Map();
|
|
51
|
+
const requestAppKeyCache = new Map();
|
|
49
52
|
const CONTINUATION_CACHE_TTL_MS = Number(process.env.QINGFLOW_CONTINUATION_CACHE_TTL_MS ?? "900000");
|
|
50
53
|
const continuationCache = new Map();
|
|
51
54
|
const DEFAULT_PAGE_SIZE = 50;
|
|
@@ -65,7 +68,7 @@ const REQUEST_TIMEOUT_MS = toPositiveInt(process.env.QINGFLOW_REQUEST_TIMEOUT_MS
|
|
|
65
68
|
const EXECUTION_BUDGET_MS = toPositiveInt(process.env.QINGFLOW_EXECUTION_BUDGET_MS) ?? 20000;
|
|
66
69
|
const WAIT_RESULT_DEFAULT_TIMEOUT_MS = toPositiveInt(process.env.QINGFLOW_WAIT_RESULT_TIMEOUT_MS) ?? 5000;
|
|
67
70
|
const WAIT_RESULT_POLL_INTERVAL_MS = toPositiveInt(process.env.QINGFLOW_WAIT_RESULT_POLL_INTERVAL_MS) ?? 500;
|
|
68
|
-
const SERVER_VERSION = "0.3.
|
|
71
|
+
const SERVER_VERSION = "0.3.21";
|
|
69
72
|
const accessToken = process.env.QINGFLOW_ACCESS_TOKEN;
|
|
70
73
|
const baseUrl = process.env.QINGFLOW_BASE_URL;
|
|
71
74
|
if (!accessToken) {
|
|
@@ -2406,6 +2409,8 @@ server.registerTool("qf_record_create", {
|
|
|
2406
2409
|
const result = asObject(response.result);
|
|
2407
2410
|
const requestId = asNullableString(result?.requestId);
|
|
2408
2411
|
const immediateApplyId = result?.applyId ?? null;
|
|
2412
|
+
rememberRequestAppKey(requestId, parsedArgs.app_key);
|
|
2413
|
+
rememberApplyAppKey(immediateApplyId, parsedArgs.app_key);
|
|
2409
2414
|
const shouldWaitForResult = (parsedArgs.wait_result ?? false) && requestId !== null && immediateApplyId === null;
|
|
2410
2415
|
let finalApplyId = immediateApplyId;
|
|
2411
2416
|
let waitStatus = immediateApplyId !== null ? "completed" : "pending";
|
|
@@ -2418,6 +2423,7 @@ server.registerTool("qf_record_create", {
|
|
|
2418
2423
|
waitStatus = waited.status;
|
|
2419
2424
|
rawOperationResult = waited.operationResult;
|
|
2420
2425
|
finalApplyId = waited.applyId;
|
|
2426
|
+
rememberApplyAppKey(waited.applyId, parsedArgs.app_key);
|
|
2421
2427
|
}
|
|
2422
2428
|
const createResource = finalApplyId !== null ? { type: "record", apply_id: finalApplyId } : null;
|
|
2423
2429
|
const createNextAction = waitStatus === "pending" || waitStatus === "timeout"
|
|
@@ -2478,6 +2484,8 @@ server.registerTool("qf_record_update", {
|
|
|
2478
2484
|
const response = await client.updateRecord(String(parsedArgs.apply_id), { answers: normalizedAnswers }, { userId: parsedArgs.user_id });
|
|
2479
2485
|
const result = asObject(response.result);
|
|
2480
2486
|
const updateRequestId = asNullableString(result?.requestId);
|
|
2487
|
+
rememberRequestAppKey(updateRequestId, parsedArgs.app_key ?? null);
|
|
2488
|
+
rememberApplyAppKey(parsedArgs.apply_id, parsedArgs.app_key ?? null);
|
|
2481
2489
|
const shouldWaitForUpdate = (parsedArgs.wait_result ?? false) && updateRequestId !== null;
|
|
2482
2490
|
let updateStatus = "pending";
|
|
2483
2491
|
let updateRawOperationResult = null;
|
|
@@ -2493,6 +2501,7 @@ server.registerTool("qf_record_update", {
|
|
|
2493
2501
|
if (waited.applyId !== null) {
|
|
2494
2502
|
updateApplyId = waited.applyId;
|
|
2495
2503
|
}
|
|
2504
|
+
rememberApplyAppKey(waited.applyId, parsedArgs.app_key ?? null);
|
|
2496
2505
|
}
|
|
2497
2506
|
else if (updateRequestId === null) {
|
|
2498
2507
|
// No async operation — synchronous completion
|
|
@@ -2538,6 +2547,8 @@ server.registerTool("qf_operation_get", {
|
|
|
2538
2547
|
}, async (args) => {
|
|
2539
2548
|
try {
|
|
2540
2549
|
const response = await client.getOperation(args.request_id);
|
|
2550
|
+
const cachedAppKey = getCachedRequestAppKey(args.request_id);
|
|
2551
|
+
rememberApplyAppKey(extractOperationApplyId(response.result), cachedAppKey);
|
|
2541
2552
|
return okResult({
|
|
2542
2553
|
ok: true,
|
|
2543
2554
|
data: {
|
|
@@ -2834,6 +2845,58 @@ function buildMeta(response) {
|
|
|
2834
2845
|
base_url: baseUrl
|
|
2835
2846
|
};
|
|
2836
2847
|
}
|
|
2848
|
+
function rememberApplyAppKey(applyId, appKey) {
|
|
2849
|
+
const normalizedApplyId = asNullableString(applyId)?.trim();
|
|
2850
|
+
const normalizedAppKey = asNullableString(appKey)?.trim();
|
|
2851
|
+
if (!normalizedApplyId || !normalizedAppKey) {
|
|
2852
|
+
return;
|
|
2853
|
+
}
|
|
2854
|
+
applyAppKeyCache.set(normalizedApplyId, {
|
|
2855
|
+
appKey: normalizedAppKey,
|
|
2856
|
+
expiresAt: Date.now() + APPLY_APP_KEY_CACHE_TTL_MS
|
|
2857
|
+
});
|
|
2858
|
+
}
|
|
2859
|
+
function rememberRequestAppKey(requestId, appKey) {
|
|
2860
|
+
const normalizedRequestId = asNullableString(requestId)?.trim();
|
|
2861
|
+
const normalizedAppKey = asNullableString(appKey)?.trim();
|
|
2862
|
+
if (!normalizedRequestId || !normalizedAppKey) {
|
|
2863
|
+
return;
|
|
2864
|
+
}
|
|
2865
|
+
requestAppKeyCache.set(normalizedRequestId, {
|
|
2866
|
+
appKey: normalizedAppKey,
|
|
2867
|
+
expiresAt: Date.now() + APPLY_APP_KEY_CACHE_TTL_MS
|
|
2868
|
+
});
|
|
2869
|
+
}
|
|
2870
|
+
function getCachedApplyAppKey(applyId) {
|
|
2871
|
+
const normalizedApplyId = asNullableString(applyId)?.trim();
|
|
2872
|
+
if (!normalizedApplyId) {
|
|
2873
|
+
return null;
|
|
2874
|
+
}
|
|
2875
|
+
const hit = applyAppKeyCache.get(normalizedApplyId);
|
|
2876
|
+
if (!hit) {
|
|
2877
|
+
return null;
|
|
2878
|
+
}
|
|
2879
|
+
if (hit.expiresAt <= Date.now()) {
|
|
2880
|
+
applyAppKeyCache.delete(normalizedApplyId);
|
|
2881
|
+
return null;
|
|
2882
|
+
}
|
|
2883
|
+
return hit.appKey;
|
|
2884
|
+
}
|
|
2885
|
+
function getCachedRequestAppKey(requestId) {
|
|
2886
|
+
const normalizedRequestId = asNullableString(requestId)?.trim();
|
|
2887
|
+
if (!normalizedRequestId) {
|
|
2888
|
+
return null;
|
|
2889
|
+
}
|
|
2890
|
+
const hit = requestAppKeyCache.get(normalizedRequestId);
|
|
2891
|
+
if (!hit) {
|
|
2892
|
+
return null;
|
|
2893
|
+
}
|
|
2894
|
+
if (hit.expiresAt <= Date.now()) {
|
|
2895
|
+
requestAppKeyCache.delete(normalizedRequestId);
|
|
2896
|
+
return null;
|
|
2897
|
+
}
|
|
2898
|
+
return hit.appKey;
|
|
2899
|
+
}
|
|
2837
2900
|
async function fetchRecordsByApplyIds(params) {
|
|
2838
2901
|
const response = await client.listRecords(params.appKey, buildListPayload({
|
|
2839
2902
|
pageNum: 1,
|
|
@@ -5640,6 +5703,7 @@ async function executeRecordsBatchGet(args) {
|
|
|
5640
5703
|
missingApplyIds.push(applyId);
|
|
5641
5704
|
continue;
|
|
5642
5705
|
}
|
|
5706
|
+
rememberApplyAppKey(record.applyId ?? applyId, args.app_key);
|
|
5643
5707
|
rows.push(buildFlatRowFromAnswers({
|
|
5644
5708
|
applyId: record.applyId ?? applyId,
|
|
5645
5709
|
answers: asArray(record.answers),
|
|
@@ -6063,6 +6127,9 @@ async function executeRecordsList(args) {
|
|
|
6063
6127
|
const items = collectedRawItems
|
|
6064
6128
|
.slice(0, listLimit.limit)
|
|
6065
6129
|
.map((raw) => normalizeRecordItem(raw, includeAnswers));
|
|
6130
|
+
for (const item of items) {
|
|
6131
|
+
rememberApplyAppKey(item.apply_id, args.app_key);
|
|
6132
|
+
}
|
|
6066
6133
|
const sourceItemsForRows = items.slice();
|
|
6067
6134
|
const requestedSelectColumns = selectResolution.columns.map((item) => item.requested);
|
|
6068
6135
|
const columnProjection = projectRecordItemsColumns({
|
|
@@ -6219,11 +6286,12 @@ async function executeRecordGet(args) {
|
|
|
6219
6286
|
if (!shouldFallback) {
|
|
6220
6287
|
throw error;
|
|
6221
6288
|
}
|
|
6222
|
-
|
|
6289
|
+
const fallbackAppKey = args.app_key ?? getCachedApplyAppKey(args.apply_id);
|
|
6290
|
+
if (!fallbackAppKey) {
|
|
6223
6291
|
throw new InputValidationError({
|
|
6224
6292
|
message: `qf_record_get could not read apply_id \"${String(args.apply_id)}\" through the direct record endpoint`,
|
|
6225
6293
|
errorCode: "APP_KEY_REQUIRED_FOR_RECORD_GET",
|
|
6226
|
-
fixHint: "Retry qf_record_get with app_key, or
|
|
6294
|
+
fixHint: "Retry qf_record_get with app_key, or call qf_records_batch_get/qf_records_list/qf_record_update first so MCP can infer the app_key for this apply_id.",
|
|
6227
6295
|
details: {
|
|
6228
6296
|
apply_id: String(args.apply_id),
|
|
6229
6297
|
provider_err_code: providerError?.errCode ?? null,
|
|
@@ -6232,22 +6300,23 @@ async function executeRecordGet(args) {
|
|
|
6232
6300
|
});
|
|
6233
6301
|
}
|
|
6234
6302
|
const fallback = await fetchRecordsByApplyIds({
|
|
6235
|
-
appKey:
|
|
6303
|
+
appKey: fallbackAppKey,
|
|
6236
6304
|
applyIds: [String(args.apply_id)]
|
|
6237
6305
|
});
|
|
6238
6306
|
response = fallback.response;
|
|
6239
6307
|
record = fallback.records.find((item) => String(item.applyId ?? "") === String(args.apply_id)) ?? null;
|
|
6240
6308
|
if (!record) {
|
|
6241
6309
|
throw new InputValidationError({
|
|
6242
|
-
message: `Record \"${String(args.apply_id)}\" not found in app \"${
|
|
6310
|
+
message: `Record \"${String(args.apply_id)}\" not found in app \"${fallbackAppKey}\"`,
|
|
6243
6311
|
errorCode: "RECORD_NOT_FOUND",
|
|
6244
6312
|
fixHint: "Confirm apply_id and app_key, or fetch the row via qf_records_list/qf_query first.",
|
|
6245
6313
|
details: {
|
|
6246
6314
|
apply_id: String(args.apply_id),
|
|
6247
|
-
app_key:
|
|
6315
|
+
app_key: fallbackAppKey
|
|
6248
6316
|
}
|
|
6249
6317
|
});
|
|
6250
6318
|
}
|
|
6319
|
+
rememberApplyAppKey(record.applyId ?? args.apply_id, fallbackAppKey);
|
|
6251
6320
|
}
|
|
6252
6321
|
const projection = projectAnswersForOutput({
|
|
6253
6322
|
answers: asArray(record?.answers),
|
|
@@ -6280,6 +6349,7 @@ async function executeRecordGet(args) {
|
|
|
6280
6349
|
apply_id: String(args.apply_id),
|
|
6281
6350
|
selected_columns: selectedColumnsForRow
|
|
6282
6351
|
};
|
|
6352
|
+
rememberApplyAppKey(record?.applyId ?? args.apply_id, args.app_key ?? getCachedApplyAppKey(args.apply_id));
|
|
6283
6353
|
return {
|
|
6284
6354
|
payload: {
|
|
6285
6355
|
ok: true,
|