@fluentcommerce/fluent-mcp-extn 0.7.0 → 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 +176 -174
- package/dist/batch-tools.js +21 -21
- package/dist/cache-tools.js +5 -5
- package/dist/config.js +1 -1
- package/dist/entity-tools.js +16 -16
- package/dist/environment-tools.js +10 -10
- package/dist/event-tools.js +45 -28
- package/dist/fluent-client.js +20 -0
- package/dist/graphql-query-tools.js +73 -17
- package/dist/graphql-schema-tools.js +14 -14
- package/dist/metrics-tools.js +87 -40
- package/dist/profile-registry.js +2 -2
- package/dist/response-shaper.js +1 -1
- package/dist/settings-tools.js +62 -26
- package/dist/test-tools.js +4 -4
- package/dist/tools.js +153 -148
- package/dist/workflow-tools.js +34 -44
- package/docs/E2E_TESTING.md +59 -59
- package/docs/HANDOVER_GITHUB_COPILOT.md +9 -9
- package/docs/HANDOVER_GITHUB_REPO_MCP_CONFIG.example.json +12 -12
- package/docs/RUNBOOK.md +38 -38
- package/docs/TOOL_REFERENCE.md +296 -296
- package/package.json +1 -1
package/dist/profile-registry.js
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
* Multi-profile registry for simultaneous Fluent Commerce environment access.
|
|
3
3
|
*
|
|
4
4
|
* Supports lazy client initialization, runtime profile management
|
|
5
|
-
* (
|
|
5
|
+
* (connection_add/remove/list/switch), and per-tool-call profile resolution
|
|
6
6
|
* via the optional `profile` parameter on every tool.
|
|
7
7
|
*
|
|
8
8
|
* Profiles can be:
|
|
9
9
|
* - Pre-loaded at startup via FLUENT_ADDITIONAL_PROFILES env var (comma-separated names)
|
|
10
|
-
* - Added at runtime via the
|
|
10
|
+
* - Added at runtime via the connection_add tool
|
|
11
11
|
*/
|
|
12
12
|
import { detectAuthStrategy, loadConfigForProfile, buildExplicitConfig, } from "./config.js";
|
|
13
13
|
import { initSDKClient } from "./sdk-client.js";
|
package/dist/response-shaper.js
CHANGED
|
@@ -143,7 +143,7 @@ function deepShape(value, budget, stats) {
|
|
|
143
143
|
// Object
|
|
144
144
|
const obj = value;
|
|
145
145
|
const keys = Object.keys(obj);
|
|
146
|
-
// Summarize large objects (e.g.,
|
|
146
|
+
// Summarize large objects (e.g., plugin_list with 597 rule keys)
|
|
147
147
|
if (keys.length > budget.maxArrayElements && !hasProtectedStructure(obj)) {
|
|
148
148
|
return summarizeObject(obj, keys, budget.sampleSize, stats);
|
|
149
149
|
}
|
package/dist/settings-tools.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Settings management tools:
|
|
2
|
+
* Settings management tools: setting_upsert, setting_bulkUpsert
|
|
3
3
|
*
|
|
4
4
|
* Closes the configuration loop — agents can create and update
|
|
5
5
|
* settings that workflows depend on (webhook URLs, feature flags, thresholds).
|
|
@@ -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)
|
|
@@ -84,7 +84,7 @@ export const SettingBulkUpsertInputSchema = z.object({
|
|
|
84
84
|
// ---------------------------------------------------------------------------
|
|
85
85
|
export const SETTING_TOOL_DEFINITIONS = [
|
|
86
86
|
{
|
|
87
|
-
name: "
|
|
87
|
+
name: "setting_get",
|
|
88
88
|
description: [
|
|
89
89
|
"Fetch settings by name (% wildcards supported). Use outputFile to save large values to disk.",
|
|
90
90
|
"Use digest=true for structural summary instead of raw content (Mystique-aware).",
|
|
@@ -98,7 +98,7 @@ export const SETTING_TOOL_DEFINITIONS = [
|
|
|
98
98
|
},
|
|
99
99
|
},
|
|
100
100
|
{
|
|
101
|
-
name: "
|
|
101
|
+
name: "setting_upsert",
|
|
102
102
|
description: "Create or update a setting. Use lobValue for large JSON. For fc.mystique.* settings, set valueType: \"JSON\".",
|
|
103
103
|
annotations: {
|
|
104
104
|
title: "Upsert Setting",
|
|
@@ -109,7 +109,7 @@ export const SETTING_TOOL_DEFINITIONS = [
|
|
|
109
109
|
},
|
|
110
110
|
},
|
|
111
111
|
{
|
|
112
|
-
name: "
|
|
112
|
+
name: "setting_bulkUpsert",
|
|
113
113
|
description: "Batch upsert up to 50 settings in one call. Returns per-setting results.",
|
|
114
114
|
annotations: {
|
|
115
115
|
title: "Bulk Upsert Settings",
|
|
@@ -122,7 +122,7 @@ export const SETTING_TOOL_DEFINITIONS = [
|
|
|
122
122
|
];
|
|
123
123
|
function requireSettingClient(ctx) {
|
|
124
124
|
if (!ctx.client) {
|
|
125
|
-
throw new ToolError("CONFIG_ERROR", "SDK client is not available. Run
|
|
125
|
+
throw new ToolError("CONFIG_ERROR", "SDK client is not available. Run config_validate and fix auth/base URL.");
|
|
126
126
|
}
|
|
127
127
|
return ctx.client;
|
|
128
128
|
}
|
|
@@ -168,7 +168,7 @@ function isWildcardSettingName(name) {
|
|
|
168
168
|
}
|
|
169
169
|
function buildSettingGetCacheKey(input) {
|
|
170
170
|
return [
|
|
171
|
-
"
|
|
171
|
+
"setting_get",
|
|
172
172
|
input.name,
|
|
173
173
|
input.context ?? "_all",
|
|
174
174
|
input.contextId !== undefined ? String(input.contextId) : "_all",
|
|
@@ -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,
|
|
@@ -554,7 +560,7 @@ async function updateSetting(client, input) {
|
|
|
554
560
|
return setting;
|
|
555
561
|
}
|
|
556
562
|
/**
|
|
557
|
-
* Handle
|
|
563
|
+
* Handle setting_get tool call.
|
|
558
564
|
* Fetches settings by name (with wildcard support) and optionally writes to file.
|
|
559
565
|
*/
|
|
560
566
|
export async function handleSettingGet(args, ctx) {
|
|
@@ -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,23 +606,52 @@ 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
|
-
* Handle
|
|
654
|
+
* Handle setting_upsert tool call.
|
|
619
655
|
*/
|
|
620
656
|
export async function handleSettingUpsert(args, ctx) {
|
|
621
657
|
const parsed = SettingUpsertInputSchema.parse(args);
|
|
@@ -678,7 +714,7 @@ export async function handleSettingUpsert(args, ctx) {
|
|
|
678
714
|
return result;
|
|
679
715
|
}
|
|
680
716
|
/**
|
|
681
|
-
* Handle
|
|
717
|
+
* Handle setting_bulkUpsert tool call.
|
|
682
718
|
*/
|
|
683
719
|
export async function handleSettingBulkUpsert(args, ctx) {
|
|
684
720
|
const parsed = SettingBulkUpsertInputSchema.parse(args);
|
package/dist/test-tools.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Test tools:
|
|
2
|
+
* Test tools: test_assert
|
|
3
3
|
*
|
|
4
4
|
* Entity state assertion with optional polling for agentic verify loops.
|
|
5
5
|
*/
|
|
@@ -67,7 +67,7 @@ export const TestAssertInputSchema = z.object({
|
|
|
67
67
|
// ---------------------------------------------------------------------------
|
|
68
68
|
export const TEST_TOOL_DEFINITIONS = [
|
|
69
69
|
{
|
|
70
|
-
name: "
|
|
70
|
+
name: "test_assert",
|
|
71
71
|
description: "Assert entity state (status, type, attributes, edge counts). Set poll=true to retry until pass or timeout (for async state changes).",
|
|
72
72
|
annotations: {
|
|
73
73
|
title: "Assert Entity State",
|
|
@@ -224,7 +224,7 @@ function evaluateAssertions(entity, assertions) {
|
|
|
224
224
|
}
|
|
225
225
|
function requireTestClient(ctx) {
|
|
226
226
|
if (!ctx.client) {
|
|
227
|
-
throw new ToolError("CONFIG_ERROR", "SDK client is not available. Run
|
|
227
|
+
throw new ToolError("CONFIG_ERROR", "SDK client is not available. Run config_validate and fix auth/base URL.");
|
|
228
228
|
}
|
|
229
229
|
return ctx.client;
|
|
230
230
|
}
|
|
@@ -253,7 +253,7 @@ function sleep(ms) {
|
|
|
253
253
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
254
254
|
}
|
|
255
255
|
/**
|
|
256
|
-
* Handle
|
|
256
|
+
* Handle test_assert tool call.
|
|
257
257
|
*/
|
|
258
258
|
export async function handleTestAssert(args, ctx) {
|
|
259
259
|
const parsed = TestAssertInputSchema.parse(args);
|