@fluentcommerce/fluent-mcp-extn 0.7.2 → 0.7.3
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/event-tools.js +19 -2
- package/dist/graphql-query-tools.js +58 -2
- package/dist/metrics-tools.js +47 -0
- package/dist/settings-tools.js +53 -17
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -988,7 +988,7 @@ With `outputDir`, each workflow is saved as `{TYPE}-{SUBTYPE}.json` (e.g., `ORDE
|
|
|
988
988
|
|
|
989
989
|
| Tool | Description |
|
|
990
990
|
|---|---|
|
|
991
|
-
| `setting_get` | Fetch settings by name (`%` wildcards supported)
|
|
991
|
+
| `setting_get` | Fetch settings by name (`%` wildcards supported). Auto-paginates wildcard queries via edge cursors (up to 500 records). Warns when results are truncated. Optionally save to local file to keep large JSON out of LLM context. |
|
|
992
992
|
| `setting_upsert` | Create or update a setting with upsert semantics — queries existing by name + context + contextId first |
|
|
993
993
|
| `setting_bulkUpsert` | Batch create/update up to 50 settings with per-setting error handling |
|
|
994
994
|
|
package/dist/event-tools.js
CHANGED
|
@@ -473,7 +473,15 @@ export async function handleEventList(args, ctx) {
|
|
|
473
473
|
const analysis = analyzeEvents(events.results, events.hasMore ?? false);
|
|
474
474
|
return { ok: true, analyze: true, ...analysis };
|
|
475
475
|
}
|
|
476
|
-
|
|
476
|
+
const hasMore = events.hasMore ?? false;
|
|
477
|
+
return {
|
|
478
|
+
ok: true,
|
|
479
|
+
events,
|
|
480
|
+
...(hasMore ? {
|
|
481
|
+
_truncated: true,
|
|
482
|
+
_truncationWarning: `More events exist beyond this page. Use 'start' parameter to fetch the next page, or narrow filters (entityType, from/to, eventStatus) to reduce results.`,
|
|
483
|
+
} : {}),
|
|
484
|
+
};
|
|
477
485
|
}
|
|
478
486
|
/**
|
|
479
487
|
* Handle event_flowInspect tool call.
|
|
@@ -493,6 +501,7 @@ export async function handleEventFlowInspect(args, ctx) {
|
|
|
493
501
|
if (parsed.rootEntityId !== undefined) {
|
|
494
502
|
baseParams["context.rootEntityId"] = parsed.rootEntityId;
|
|
495
503
|
}
|
|
504
|
+
let _paginationTruncated = false;
|
|
496
505
|
const fetchPaged = async (extraParams) => {
|
|
497
506
|
const all = [];
|
|
498
507
|
let page = 1;
|
|
@@ -505,8 +514,10 @@ export async function handleEventFlowInspect(args, ctx) {
|
|
|
505
514
|
};
|
|
506
515
|
const result = await client.getEvents(reqParams);
|
|
507
516
|
const rows = Array.isArray(result?.results) ? result.results : [];
|
|
508
|
-
if (rows.length === 0)
|
|
517
|
+
if (rows.length === 0) {
|
|
518
|
+
hasMore = false;
|
|
509
519
|
break;
|
|
520
|
+
}
|
|
510
521
|
for (const row of rows) {
|
|
511
522
|
const rec = asRecord(row);
|
|
512
523
|
if (rec)
|
|
@@ -515,6 +526,8 @@ export async function handleEventFlowInspect(args, ctx) {
|
|
|
515
526
|
hasMore = result.hasMore ?? rows.length >= 500;
|
|
516
527
|
page += 1;
|
|
517
528
|
}
|
|
529
|
+
if (hasMore)
|
|
530
|
+
_paginationTruncated = true;
|
|
518
531
|
return all;
|
|
519
532
|
};
|
|
520
533
|
const orchestrationEvents = await fetchPaged({
|
|
@@ -920,6 +933,10 @@ export async function handleEventFlowInspect(args, ctx) {
|
|
|
920
933
|
window: { from: parsed.from ?? null, to: parsed.to ?? null },
|
|
921
934
|
paging: { maxPages: parsed.maxPages, pageSize: 500 },
|
|
922
935
|
compact: parsed.compact,
|
|
936
|
+
...(_paginationTruncated ? {
|
|
937
|
+
_truncated: true,
|
|
938
|
+
_truncationWarning: `Results truncated at ${parsed.maxPages} pages (${parsed.maxPages * 500} events max). Increase maxPages to fetch more, or narrow the time window.`,
|
|
939
|
+
} : {}),
|
|
923
940
|
};
|
|
924
941
|
// ========= COMPACT MODE =========
|
|
925
942
|
if (parsed.compact) {
|
|
@@ -147,6 +147,34 @@ function requireClient(ctx) {
|
|
|
147
147
|
}
|
|
148
148
|
return ctx.client;
|
|
149
149
|
}
|
|
150
|
+
function analyzePaginationLimits(pagination, limits) {
|
|
151
|
+
if (!pagination)
|
|
152
|
+
return { truncated: false };
|
|
153
|
+
const totalPages = typeof pagination.totalPages === "number" ? pagination.totalPages : null;
|
|
154
|
+
const totalRecords = typeof pagination.totalRecords === "number" ? pagination.totalRecords : null;
|
|
155
|
+
const pagesReached = typeof pagination.pagesFetched === "number"
|
|
156
|
+
? pagination.pagesFetched >= limits.maxPages
|
|
157
|
+
: totalPages !== null
|
|
158
|
+
? totalPages >= limits.maxPages
|
|
159
|
+
: false;
|
|
160
|
+
const recordsReached = typeof pagination.recordsFetched === "number"
|
|
161
|
+
? pagination.recordsFetched >= limits.maxRecords
|
|
162
|
+
: totalRecords !== null
|
|
163
|
+
? totalRecords >= limits.maxRecords
|
|
164
|
+
: false;
|
|
165
|
+
if (!pagesReached && !recordsReached) {
|
|
166
|
+
return { truncated: false };
|
|
167
|
+
}
|
|
168
|
+
const reasons = [];
|
|
169
|
+
if (pagesReached)
|
|
170
|
+
reasons.push(`page cap ${limits.maxPages}`);
|
|
171
|
+
if (recordsReached)
|
|
172
|
+
reasons.push(`record cap ${limits.maxRecords}`);
|
|
173
|
+
return {
|
|
174
|
+
truncated: true,
|
|
175
|
+
warning: `Auto-pagination may be truncated by the ${reasons.join(" and ")}. Narrow the query or raise the limit if you need a complete result.`,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
150
178
|
// ---------------------------------------------------------------------------
|
|
151
179
|
// Handlers
|
|
152
180
|
// ---------------------------------------------------------------------------
|
|
@@ -190,13 +218,41 @@ export async function handleGraphQLQueryAll(args, ctx) {
|
|
|
190
218
|
};
|
|
191
219
|
const result = await client.graphqlPaginated(payload);
|
|
192
220
|
const pagination = result.extensions?.autoPagination ?? null;
|
|
221
|
+
const paginationInfo = pagination && typeof pagination === "object"
|
|
222
|
+
? pagination
|
|
223
|
+
: null;
|
|
224
|
+
const paginationAnalysis = analyzePaginationLimits(paginationInfo, {
|
|
225
|
+
maxPages: parsed.maxPages,
|
|
226
|
+
maxRecords: parsed.maxRecords,
|
|
227
|
+
});
|
|
193
228
|
if (parsed.summarize) {
|
|
194
229
|
const summary = summarizeConnection(result);
|
|
195
230
|
if (summary) {
|
|
196
|
-
return {
|
|
231
|
+
return {
|
|
232
|
+
ok: true,
|
|
233
|
+
summarized: true,
|
|
234
|
+
...summary,
|
|
235
|
+
pagination,
|
|
236
|
+
...(paginationAnalysis.truncated
|
|
237
|
+
? {
|
|
238
|
+
_truncated: true,
|
|
239
|
+
_truncationWarning: paginationAnalysis.warning,
|
|
240
|
+
}
|
|
241
|
+
: {}),
|
|
242
|
+
};
|
|
197
243
|
}
|
|
198
244
|
}
|
|
199
|
-
return {
|
|
245
|
+
return {
|
|
246
|
+
ok: true,
|
|
247
|
+
response: result,
|
|
248
|
+
pagination,
|
|
249
|
+
...(paginationAnalysis.truncated
|
|
250
|
+
? {
|
|
251
|
+
_truncated: true,
|
|
252
|
+
_truncationWarning: paginationAnalysis.warning,
|
|
253
|
+
}
|
|
254
|
+
: {}),
|
|
255
|
+
};
|
|
200
256
|
}
|
|
201
257
|
/**
|
|
202
258
|
* Handle graphql_batchMutate tool call.
|
package/dist/metrics-tools.js
CHANGED
|
@@ -10,6 +10,7 @@ import { GraphQLIntrospectionService, } from "@fluentcommerce/fc-connect-sdk";
|
|
|
10
10
|
import { ToolError } from "./errors.js";
|
|
11
11
|
import { classifyMutationOperations, listMutationCatalog, } from "./mutation-taxonomy.js";
|
|
12
12
|
import { parseWindowMs, recommendStep } from "./time-window.js";
|
|
13
|
+
const MAX_METRICS_RANGE_POINTS = 5_000;
|
|
13
14
|
// ---------------------------------------------------------------------------
|
|
14
15
|
// Input schemas
|
|
15
16
|
// ---------------------------------------------------------------------------
|
|
@@ -204,6 +205,13 @@ export const METRICS_TOOL_DEFINITIONS = [
|
|
|
204
205
|
// ---------------------------------------------------------------------------
|
|
205
206
|
// Math helpers
|
|
206
207
|
// ---------------------------------------------------------------------------
|
|
208
|
+
function parseIsoTimestamp(value, field) {
|
|
209
|
+
const parsed = new Date(value);
|
|
210
|
+
if (Number.isNaN(parsed.getTime())) {
|
|
211
|
+
throw new ToolError("VALIDATION_ERROR", `metrics_query range ${field} must be a valid ISO-8601 timestamp.`);
|
|
212
|
+
}
|
|
213
|
+
return parsed;
|
|
214
|
+
}
|
|
207
215
|
function round1(value) {
|
|
208
216
|
return Math.round(value * 10) / 10;
|
|
209
217
|
}
|
|
@@ -1022,6 +1030,7 @@ async function aggregateEventsFromApi(client, params) {
|
|
|
1022
1030
|
return {
|
|
1023
1031
|
totalEvents: allEvents.length,
|
|
1024
1032
|
totalPages: page - 1,
|
|
1033
|
+
truncated: hasMore,
|
|
1025
1034
|
statusBreakdown: Object.fromEntries(statusCounts),
|
|
1026
1035
|
groups,
|
|
1027
1036
|
uniqueNames: new Set(allEvents.map((e) => e.name)),
|
|
@@ -1064,6 +1073,28 @@ export async function handleMetricsQuery(args, ctx) {
|
|
|
1064
1073
|
if (parsed.type === "range" && (!parsed.start || !parsed.end || !parsed.step)) {
|
|
1065
1074
|
throw new ToolError("VALIDATION_ERROR", "Range queries require start, end, and step.");
|
|
1066
1075
|
}
|
|
1076
|
+
if (parsed.type === "range") {
|
|
1077
|
+
const start = parseIsoTimestamp(parsed.start, "start");
|
|
1078
|
+
const end = parseIsoTimestamp(parsed.end, "end");
|
|
1079
|
+
const durationMs = end.getTime() - start.getTime();
|
|
1080
|
+
if (durationMs <= 0) {
|
|
1081
|
+
throw new ToolError("VALIDATION_ERROR", "metrics_query range end must be after start.");
|
|
1082
|
+
}
|
|
1083
|
+
const stepMs = parseWindowMs(parsed.step);
|
|
1084
|
+
const estimatedPoints = Math.ceil(durationMs / stepMs);
|
|
1085
|
+
if (estimatedPoints > MAX_METRICS_RANGE_POINTS) {
|
|
1086
|
+
const hint = recommendStep(durationMs, Math.min(500, MAX_METRICS_RANGE_POINTS));
|
|
1087
|
+
throw new ToolError("VALIDATION_ERROR", `Range query would request about ${estimatedPoints} points, which exceeds the safety limit of ${MAX_METRICS_RANGE_POINTS}. Increase step to at least ${hint.step}.`, {
|
|
1088
|
+
details: {
|
|
1089
|
+
estimatedPoints,
|
|
1090
|
+
maxPoints: MAX_METRICS_RANGE_POINTS,
|
|
1091
|
+
recommendedStep: hint.step,
|
|
1092
|
+
recommendedStepMs: hint.stepMs,
|
|
1093
|
+
recommendedEstimatedPoints: hint.estimatedPoints,
|
|
1094
|
+
},
|
|
1095
|
+
});
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1067
1098
|
const client = requireClient(ctx);
|
|
1068
1099
|
const response = await client.queryPrometheus(parsed);
|
|
1069
1100
|
const vectors = extractPrometheusVectors(response);
|
|
@@ -1092,6 +1123,7 @@ export async function handleMetricsHealthCheck(args, ctx) {
|
|
|
1092
1123
|
let statusBreakdown = {};
|
|
1093
1124
|
let totalEvents = 0;
|
|
1094
1125
|
let topEvents = [];
|
|
1126
|
+
let eventApiTruncated = false;
|
|
1095
1127
|
try {
|
|
1096
1128
|
// Query 1: status breakdown
|
|
1097
1129
|
const statusResponse = await client.queryPrometheus({
|
|
@@ -1154,6 +1186,7 @@ export async function handleMetricsHealthCheck(args, ctx) {
|
|
|
1154
1186
|
});
|
|
1155
1187
|
totalEvents = agg.totalEvents;
|
|
1156
1188
|
statusBreakdown = agg.statusBreakdown;
|
|
1189
|
+
eventApiTruncated = agg.truncated;
|
|
1157
1190
|
if (parsed.includeTopEvents) {
|
|
1158
1191
|
topEvents = rankTopEvents(agg.groups, agg.totalEvents, parsed.topN);
|
|
1159
1192
|
}
|
|
@@ -1230,6 +1263,10 @@ export async function handleMetricsHealthCheck(args, ctx) {
|
|
|
1230
1263
|
ok: true,
|
|
1231
1264
|
healthy,
|
|
1232
1265
|
source,
|
|
1266
|
+
...(eventApiTruncated ? {
|
|
1267
|
+
_truncated: true,
|
|
1268
|
+
_truncationWarning: "Event API results truncated — counts may be approximate. Narrow the time window for accuracy.",
|
|
1269
|
+
} : {}),
|
|
1233
1270
|
summary: {
|
|
1234
1271
|
window,
|
|
1235
1272
|
totalEvents,
|
|
@@ -1268,6 +1305,7 @@ export async function handleMetricsSloReport(args, ctx) {
|
|
|
1268
1305
|
let pendingEvents = 0;
|
|
1269
1306
|
let runtimeP95Seconds = null;
|
|
1270
1307
|
let inflightP95Seconds = null;
|
|
1308
|
+
let eventApiTruncated = false;
|
|
1271
1309
|
try {
|
|
1272
1310
|
const [totalResponse, failedResponse, noMatchResponse, pendingResponse, runtimeP95Response, inflightP95Response,] = await Promise.all([
|
|
1273
1311
|
client.queryPrometheus({
|
|
@@ -1316,6 +1354,7 @@ export async function handleMetricsSloReport(args, ctx) {
|
|
|
1316
1354
|
pendingEvents = agg.statusBreakdown["PENDING"] ?? 0;
|
|
1317
1355
|
runtimeP95Seconds = null;
|
|
1318
1356
|
inflightP95Seconds = null;
|
|
1357
|
+
eventApiTruncated = agg.truncated;
|
|
1319
1358
|
}
|
|
1320
1359
|
let topFailingEvents;
|
|
1321
1360
|
if (parsed.includeTopFailingEvents) {
|
|
@@ -1401,6 +1440,10 @@ export async function handleMetricsSloReport(args, ctx) {
|
|
|
1401
1440
|
ok: true,
|
|
1402
1441
|
source,
|
|
1403
1442
|
healthy: findings.length === 0,
|
|
1443
|
+
...(eventApiTruncated ? {
|
|
1444
|
+
_truncated: true,
|
|
1445
|
+
_truncationWarning: "Event API results truncated — counts may be approximate. Narrow the time window or increase maxPages for accuracy.",
|
|
1446
|
+
} : {}),
|
|
1404
1447
|
summary: {
|
|
1405
1448
|
window,
|
|
1406
1449
|
timeWindow: { from, to },
|
|
@@ -1837,6 +1880,10 @@ export async function handleMetricsTopEvents(args, ctx) {
|
|
|
1837
1880
|
const failedCount = agg.statusBreakdown["FAILED"] ?? 0;
|
|
1838
1881
|
return {
|
|
1839
1882
|
ok: true,
|
|
1883
|
+
...(agg.truncated ? {
|
|
1884
|
+
_truncated: true,
|
|
1885
|
+
_truncationWarning: `Event API results truncated at ${agg.totalPages} pages (${agg.totalEvents} events fetched). Counts may be approximate. Narrow the time window or increase maxPages for accuracy.`,
|
|
1886
|
+
} : {}),
|
|
1840
1887
|
analytics: {
|
|
1841
1888
|
timeWindow: { from: parsed.from, to: toTime },
|
|
1842
1889
|
totalEvents: agg.totalEvents,
|
package/dist/settings-tools.js
CHANGED
|
@@ -63,9 +63,9 @@ export const SettingGetInputSchema = z.object({
|
|
|
63
63
|
.number()
|
|
64
64
|
.int()
|
|
65
65
|
.min(1)
|
|
66
|
-
.max(
|
|
67
|
-
.default(
|
|
68
|
-
.describe("Max results (default:
|
|
66
|
+
.max(500)
|
|
67
|
+
.default(25)
|
|
68
|
+
.describe("Max results per page (default: 25, max: 500). Auto-paginates wildcard queries using edge cursors."),
|
|
69
69
|
digest: z
|
|
70
70
|
.boolean()
|
|
71
71
|
.default(false)
|
|
@@ -320,7 +320,10 @@ function digestSetting(setting) {
|
|
|
320
320
|
digest,
|
|
321
321
|
};
|
|
322
322
|
}
|
|
323
|
-
function buildSettingGetResponse(parsed, settings, cacheMeta) {
|
|
323
|
+
function buildSettingGetResponse(parsed, settings, cacheMeta, truncated = false) {
|
|
324
|
+
const truncationWarning = truncated
|
|
325
|
+
? `Results truncated at ${settings.length} settings. More exist on the server. Use graphql_queryAll with a settings query to fetch all, or narrow your filter.`
|
|
326
|
+
: undefined;
|
|
324
327
|
if (settings.length === 0) {
|
|
325
328
|
return {
|
|
326
329
|
ok: true,
|
|
@@ -370,6 +373,7 @@ function buildSettingGetResponse(parsed, settings, cacheMeta) {
|
|
|
370
373
|
count: settings.length,
|
|
371
374
|
savedTo: outputDir,
|
|
372
375
|
files: savedFiles,
|
|
376
|
+
...(truncationWarning ? { warning: truncationWarning } : {}),
|
|
373
377
|
...(cacheMeta ? { _cache: cacheMeta } : {}),
|
|
374
378
|
settings: settings.map((s) => ({
|
|
375
379
|
id: s.id,
|
|
@@ -387,6 +391,7 @@ function buildSettingGetResponse(parsed, settings, cacheMeta) {
|
|
|
387
391
|
ok: true,
|
|
388
392
|
count: settings.length,
|
|
389
393
|
digested: true,
|
|
394
|
+
...(truncationWarning ? { warning: truncationWarning } : {}),
|
|
390
395
|
...(cacheMeta ? { _cache: cacheMeta } : {}),
|
|
391
396
|
settings: settings.map((s) => digestSetting(s)),
|
|
392
397
|
};
|
|
@@ -394,6 +399,7 @@ function buildSettingGetResponse(parsed, settings, cacheMeta) {
|
|
|
394
399
|
return {
|
|
395
400
|
ok: true,
|
|
396
401
|
count: settings.length,
|
|
402
|
+
...(truncationWarning ? { warning: truncationWarning } : {}),
|
|
397
403
|
...(cacheMeta ? { _cache: cacheMeta } : {}),
|
|
398
404
|
settings: settings.map((s) => ({
|
|
399
405
|
id: s.id,
|
|
@@ -565,7 +571,7 @@ export async function handleSettingGet(args, ctx) {
|
|
|
565
571
|
if (cacheable && ctx.cache) {
|
|
566
572
|
const cached = await ctx.cache.get(cacheKey);
|
|
567
573
|
if (cached.hit && Array.isArray(cached.data)) {
|
|
568
|
-
return buildSettingGetResponse(parsed, cached.data, { hit: true, ageMs: cached.ageMs ?? 0 });
|
|
574
|
+
return buildSettingGetResponse(parsed, cached.data, { hit: true, ageMs: cached.ageMs ?? 0 }, false);
|
|
569
575
|
}
|
|
570
576
|
}
|
|
571
577
|
// Build variables — only include context/contextId if provided
|
|
@@ -585,10 +591,11 @@ export async function handleSettingGet(args, ctx) {
|
|
|
585
591
|
else if (parsed.context === "ACCOUNT") {
|
|
586
592
|
variables.contextId = [0];
|
|
587
593
|
}
|
|
588
|
-
// Build query —
|
|
589
|
-
const query = `query GetSettings($name: [String!], $context: [String!], $contextId: [Int!], $first: Int) {
|
|
590
|
-
settings(name: $name, context: $context, contextId: $contextId, first: $first) {
|
|
594
|
+
// Build query — edge cursors for Fluent-style pagination
|
|
595
|
+
const query = `query GetSettings($name: [String!], $context: [String!], $contextId: [Int!], $first: Int, $after: String) {
|
|
596
|
+
settings(name: $name, context: $context, contextId: $contextId, first: $first, after: $after) {
|
|
591
597
|
edges {
|
|
598
|
+
cursor
|
|
592
599
|
node {
|
|
593
600
|
id
|
|
594
601
|
name
|
|
@@ -599,20 +606,49 @@ export async function handleSettingGet(args, ctx) {
|
|
|
599
606
|
valueType
|
|
600
607
|
}
|
|
601
608
|
}
|
|
609
|
+
pageInfo {
|
|
610
|
+
hasNextPage
|
|
611
|
+
}
|
|
602
612
|
}
|
|
603
613
|
}`;
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
614
|
+
// Auto-paginate wildcard queries using edge cursors; single-page for exact names
|
|
615
|
+
const MAX_TOTAL = 500;
|
|
616
|
+
const isWildcard = isWildcardSettingName(parsed.name);
|
|
617
|
+
const allSettings = [];
|
|
618
|
+
let cursor = null;
|
|
619
|
+
let hasNextPage = true;
|
|
620
|
+
while (hasNextPage && allSettings.length < MAX_TOTAL) {
|
|
621
|
+
const pageVars = { ...variables };
|
|
622
|
+
if (cursor)
|
|
623
|
+
pageVars.after = cursor;
|
|
624
|
+
const response = await client.graphql({
|
|
625
|
+
query,
|
|
626
|
+
variables: pageVars,
|
|
627
|
+
});
|
|
628
|
+
const data = response?.data;
|
|
629
|
+
const connection = data?.settings;
|
|
630
|
+
const edges = (connection?.edges ?? []);
|
|
631
|
+
const pageInfo = connection?.pageInfo;
|
|
632
|
+
for (const edge of edges) {
|
|
633
|
+
if (allSettings.length >= MAX_TOTAL)
|
|
634
|
+
break;
|
|
635
|
+
allSettings.push(edge.node);
|
|
636
|
+
}
|
|
637
|
+
hasNextPage = Boolean(pageInfo?.hasNextPage) && edges.length > 0;
|
|
638
|
+
// Fluent pagination: cursor lives on the edge, not in pageInfo
|
|
639
|
+
if (hasNextPage && edges.length > 0) {
|
|
640
|
+
cursor = edges[edges.length - 1].cursor ?? null;
|
|
641
|
+
}
|
|
642
|
+
// Non-wildcard: one page is enough
|
|
643
|
+
if (!isWildcard)
|
|
644
|
+
break;
|
|
645
|
+
}
|
|
646
|
+
const settings = allSettings;
|
|
647
|
+
const truncated = hasNextPage && allSettings.length >= MAX_TOTAL;
|
|
612
648
|
if (cacheable && ctx.cache) {
|
|
613
649
|
await ctx.cache.set(cacheKey, "setting", settings);
|
|
614
650
|
}
|
|
615
|
-
return buildSettingGetResponse(parsed, settings, cacheable && ctx.cache ? { hit: false, stored: true } : undefined);
|
|
651
|
+
return buildSettingGetResponse(parsed, settings, cacheable && ctx.cache ? { hit: false, stored: true } : undefined, truncated);
|
|
616
652
|
}
|
|
617
653
|
/**
|
|
618
654
|
* Handle setting_upsert tool call.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluentcommerce/fluent-mcp-extn",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.3",
|
|
4
4
|
"description": "[Experimental] MCP (Model Context Protocol) extension server for Fluent Commerce. Exposes event dispatch, transition actions, GraphQL execution, Prometheus metrics, batch ingestion, and webhook validation as MCP tools.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|