@fluentcommerce/fluent-mcp-extn 0.7.0 → 0.7.2
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 +26 -26
- package/dist/fluent-client.js +20 -0
- package/dist/graphql-query-tools.js +15 -15
- package/dist/graphql-schema-tools.js +14 -14
- package/dist/metrics-tools.js +40 -40
- package/dist/profile-registry.js +2 -2
- package/dist/response-shaper.js +1 -1
- package/dist/settings-tools.js +9 -9
- 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
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
* GraphQL Query Execution Tools
|
|
3
3
|
*
|
|
4
4
|
* Four query/mutation execution tools:
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
5
|
+
* graphql_query — execute a single GraphQL query or mutation
|
|
6
|
+
* graphql_queryAll — execute with SDK auto-pagination
|
|
7
|
+
* graphql_batchMutate — execute multiple mutations in a single aliased request
|
|
8
|
+
* graphql_introspect — inspect the schema via introspection service
|
|
9
9
|
*
|
|
10
|
-
* NOTE: graphql-schema-tools.ts handles
|
|
10
|
+
* NOTE: graphql-schema-tools.ts handles graphql_listRoots/buildQuery/validate/generateFull.
|
|
11
11
|
* This file handles the query execution tools.
|
|
12
12
|
*/
|
|
13
13
|
import { z } from "zod";
|
|
@@ -58,7 +58,7 @@ export const GraphQLIntrospectInputSchema = z.object({
|
|
|
58
58
|
// ---------------------------------------------------------------------------
|
|
59
59
|
export const GRAPHQL_QUERY_TOOL_DEFINITIONS = [
|
|
60
60
|
{
|
|
61
|
-
name: "
|
|
61
|
+
name: "graphql_query",
|
|
62
62
|
description: "Execute a GraphQL query or mutation. Relay pagination: first/after with cursors on edges.",
|
|
63
63
|
annotations: {
|
|
64
64
|
title: "GraphQL Query",
|
|
@@ -69,8 +69,8 @@ export const GRAPHQL_QUERY_TOOL_DEFINITIONS = [
|
|
|
69
69
|
},
|
|
70
70
|
},
|
|
71
71
|
{
|
|
72
|
-
name: "
|
|
73
|
-
description: "Auto-paginated GraphQL query. Follows cursors, merges edges, deduplicates. Use instead of
|
|
72
|
+
name: "graphql_queryAll",
|
|
73
|
+
description: "Auto-paginated GraphQL query. Follows cursors, merges edges, deduplicates. Use instead of graphql_query when you need all records.",
|
|
74
74
|
annotations: {
|
|
75
75
|
title: "GraphQL Query All",
|
|
76
76
|
readOnlyHint: true,
|
|
@@ -80,7 +80,7 @@ export const GRAPHQL_QUERY_TOOL_DEFINITIONS = [
|
|
|
80
80
|
},
|
|
81
81
|
},
|
|
82
82
|
{
|
|
83
|
-
name: "
|
|
83
|
+
name: "graphql_batchMutate",
|
|
84
84
|
description: "Execute up to 50 mutations in one aliased request. Provide mutation name, inputs array, and returnFields.",
|
|
85
85
|
annotations: {
|
|
86
86
|
title: "GraphQL Batch Mutate",
|
|
@@ -91,7 +91,7 @@ export const GRAPHQL_QUERY_TOOL_DEFINITIONS = [
|
|
|
91
91
|
},
|
|
92
92
|
},
|
|
93
93
|
{
|
|
94
|
-
name: "
|
|
94
|
+
name: "graphql_introspect",
|
|
95
95
|
description: "Inspect GraphQL schema. Modes: type, mutation, listMutations, listQueries. Cached 24h, force=true to refresh.",
|
|
96
96
|
annotations: {
|
|
97
97
|
title: "Introspect Schema",
|
|
@@ -143,7 +143,7 @@ function introspectCacheKey(input) {
|
|
|
143
143
|
}
|
|
144
144
|
function requireClient(ctx) {
|
|
145
145
|
if (!ctx.client) {
|
|
146
|
-
throw new ToolError("CONFIG_ERROR", "SDK client is not available. Run
|
|
146
|
+
throw new ToolError("CONFIG_ERROR", "SDK client is not available. Run config_validate and fix auth/base URL.");
|
|
147
147
|
}
|
|
148
148
|
return ctx.client;
|
|
149
149
|
}
|
|
@@ -151,7 +151,7 @@ function requireClient(ctx) {
|
|
|
151
151
|
// Handlers
|
|
152
152
|
// ---------------------------------------------------------------------------
|
|
153
153
|
/**
|
|
154
|
-
* Handle
|
|
154
|
+
* Handle graphql_query tool call.
|
|
155
155
|
*/
|
|
156
156
|
export async function handleGraphQLQuery(args, ctx) {
|
|
157
157
|
const client = requireClient(ctx);
|
|
@@ -171,7 +171,7 @@ export async function handleGraphQLQuery(args, ctx) {
|
|
|
171
171
|
return { ok: true, response: result };
|
|
172
172
|
}
|
|
173
173
|
/**
|
|
174
|
-
* Handle
|
|
174
|
+
* Handle graphql_queryAll tool call.
|
|
175
175
|
*/
|
|
176
176
|
export async function handleGraphQLQueryAll(args, ctx) {
|
|
177
177
|
const client = requireClient(ctx);
|
|
@@ -199,7 +199,7 @@ export async function handleGraphQLQueryAll(args, ctx) {
|
|
|
199
199
|
return { ok: true, response: result, pagination };
|
|
200
200
|
}
|
|
201
201
|
/**
|
|
202
|
-
* Handle
|
|
202
|
+
* Handle graphql_batchMutate tool call.
|
|
203
203
|
*/
|
|
204
204
|
export async function handleGraphQLBatchMutate(args, ctx) {
|
|
205
205
|
const client = requireClient(ctx);
|
|
@@ -249,7 +249,7 @@ export async function handleGraphQLBatchMutate(args, ctx) {
|
|
|
249
249
|
};
|
|
250
250
|
}
|
|
251
251
|
/**
|
|
252
|
-
* Handle
|
|
252
|
+
* Handle graphql_introspect tool call.
|
|
253
253
|
*/
|
|
254
254
|
export async function handleGraphQLIntrospect(args, ctx) {
|
|
255
255
|
const client = requireClient(ctx);
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
* GraphQL Schema Tools
|
|
3
3
|
*
|
|
4
4
|
* Four schema-aware tools that close the gap with the official MCP server:
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
5
|
+
* graphql_listRoots — list query & mutation root fields
|
|
6
|
+
* graphql_buildQuery — generate a query/mutation string from structured inputs
|
|
7
|
+
* graphql_validate — validate a GraphQL document against the live schema
|
|
8
|
+
* graphql_generateFull — generate a maximal-selection query for a root field
|
|
9
9
|
*
|
|
10
10
|
* All tools share a single SchemaService instance (cached, with force-refresh).
|
|
11
11
|
*/
|
|
@@ -346,7 +346,7 @@ function getSchemaService(ctx) {
|
|
|
346
346
|
// ---------------------------------------------------------------------------
|
|
347
347
|
export const GRAPHQL_SCHEMA_TOOL_DEFINITIONS = [
|
|
348
348
|
{
|
|
349
|
-
name: "
|
|
349
|
+
name: "graphql_listRoots",
|
|
350
350
|
description: "List all query and mutation root fields from the live schema.",
|
|
351
351
|
annotations: {
|
|
352
352
|
title: "List Schema Roots",
|
|
@@ -357,7 +357,7 @@ export const GRAPHQL_SCHEMA_TOOL_DEFINITIONS = [
|
|
|
357
357
|
},
|
|
358
358
|
},
|
|
359
359
|
{
|
|
360
|
-
name: "
|
|
360
|
+
name: "graphql_planOperation",
|
|
361
361
|
description: "Inspect a query/mutation root field and return required args, nested input shape, variables template, and a ready-to-run document scaffold. Use when the model is unsure which inputs are mandatory.",
|
|
362
362
|
annotations: {
|
|
363
363
|
title: "Plan GraphQL Operation",
|
|
@@ -368,7 +368,7 @@ export const GRAPHQL_SCHEMA_TOOL_DEFINITIONS = [
|
|
|
368
368
|
},
|
|
369
369
|
},
|
|
370
370
|
{
|
|
371
|
-
name: "
|
|
371
|
+
name: "graphql_buildQuery",
|
|
372
372
|
description: "Generate a GraphQL query/mutation from { rootField, fields, args }. Auto-validates against live schema.",
|
|
373
373
|
annotations: {
|
|
374
374
|
title: "Build GraphQL Query",
|
|
@@ -379,7 +379,7 @@ export const GRAPHQL_SCHEMA_TOOL_DEFINITIONS = [
|
|
|
379
379
|
},
|
|
380
380
|
},
|
|
381
381
|
{
|
|
382
|
-
name: "
|
|
382
|
+
name: "graphql_validate",
|
|
383
383
|
description: "Validate a GraphQL document against the live schema. Returns OK or validation errors.",
|
|
384
384
|
annotations: {
|
|
385
385
|
title: "Validate GraphQL",
|
|
@@ -390,7 +390,7 @@ export const GRAPHQL_SCHEMA_TOOL_DEFINITIONS = [
|
|
|
390
390
|
},
|
|
391
391
|
},
|
|
392
392
|
{
|
|
393
|
-
name: "
|
|
393
|
+
name: "graphql_generateFull",
|
|
394
394
|
description: "Generate a maximal-field query for a root field with recursive introspection (depth 1-5, default 2).",
|
|
395
395
|
annotations: {
|
|
396
396
|
title: "Generate Full Query",
|
|
@@ -434,7 +434,7 @@ export async function handlePlanOperation(args, ctx) {
|
|
|
434
434
|
}
|
|
435
435
|
const field = rootType.getFields()[parsed.rootField];
|
|
436
436
|
if (!field) {
|
|
437
|
-
throw new ToolError("VALIDATION_ERROR", `Root field '${parsed.rootField}' not found. Use
|
|
437
|
+
throw new ToolError("VALIDATION_ERROR", `Root field '${parsed.rootField}' not found. Use graphql_listRoots to discover available fields.`);
|
|
438
438
|
}
|
|
439
439
|
const argPlans = (field.args ?? []).map((arg) => {
|
|
440
440
|
const described = describeInputField(schema, arg.type, arg.name);
|
|
@@ -466,8 +466,8 @@ export async function handlePlanOperation(args, ctx) {
|
|
|
466
466
|
variablesTemplate,
|
|
467
467
|
selectionTemplate: includeSelectionSet ? selectionLines : [],
|
|
468
468
|
recommendedExecutionTool: parsed.kind === "query" && selectionLines.some((line) => line.startsWith("edges {"))
|
|
469
|
-
? "
|
|
470
|
-
: "
|
|
469
|
+
? "graphql_queryAll"
|
|
470
|
+
: "graphql_query",
|
|
471
471
|
document,
|
|
472
472
|
};
|
|
473
473
|
}
|
|
@@ -538,7 +538,7 @@ export async function handleGenerateFull(args, ctx) {
|
|
|
538
538
|
}
|
|
539
539
|
const field = rootType.getFields()[parsed.rootField];
|
|
540
540
|
if (!field) {
|
|
541
|
-
throw new ToolError("VALIDATION_ERROR", `Root field '${parsed.rootField}' not found. Use
|
|
541
|
+
throw new ToolError("VALIDATION_ERROR", `Root field '${parsed.rootField}' not found. Use graphql_listRoots to discover available fields.`);
|
|
542
542
|
}
|
|
543
543
|
const returnTypeName = unwrapNamed(field.type).name;
|
|
544
544
|
const selection = buildMaxSelection(schema, returnTypeName, parsed.depth);
|
|
@@ -548,7 +548,7 @@ export async function handleGenerateFull(args, ctx) {
|
|
|
548
548
|
}
|
|
549
549
|
/**
|
|
550
550
|
* Force-clear the schema cache for the current client.
|
|
551
|
-
* Exposed for use by
|
|
551
|
+
* Exposed for use by graphql_introspect's force param.
|
|
552
552
|
*/
|
|
553
553
|
export function clearSchemaCache(ctx) {
|
|
554
554
|
if (!ctx.client)
|
package/dist/metrics-tools.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Metrics tools:
|
|
3
|
-
*
|
|
2
|
+
* Metrics tools: metrics_query, metrics_topEvents, metrics_healthCheck,
|
|
3
|
+
* metrics_sloReport, metrics_labelCatalog, metrics.catalog
|
|
4
4
|
*
|
|
5
5
|
* Prometheus-backed observability plus Event API fallback for
|
|
6
6
|
* health assessment, SLO reporting, label discovery, and metric planning.
|
|
@@ -151,52 +151,52 @@ export const MetricsMutationAuditInputSchema = z.object({
|
|
|
151
151
|
// ---------------------------------------------------------------------------
|
|
152
152
|
export const METRICS_TOOL_DEFINITIONS = [
|
|
153
153
|
{
|
|
154
|
-
name: "
|
|
154
|
+
name: "metrics_query",
|
|
155
155
|
description: "Query Prometheus metrics via GraphQL (instant or range). Requires METRICS_VIEW permission.",
|
|
156
156
|
annotations: { title: "Query Metrics", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
157
157
|
},
|
|
158
158
|
{
|
|
159
|
-
name: "
|
|
159
|
+
name: "metrics_topEvents",
|
|
160
160
|
description: "Aggregate events by name+entityType+status in a time window. Returns top-N rankings.",
|
|
161
161
|
annotations: { title: "Top Events", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
162
162
|
},
|
|
163
163
|
{
|
|
164
|
-
name: "
|
|
164
|
+
name: "metrics_healthCheck",
|
|
165
165
|
description: "Single-call health assessment via Prometheus. Checks failure rate, NO_MATCH, PENDING, dominance. Falls back to Event API.",
|
|
166
166
|
annotations: { title: "Health Check", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
167
167
|
},
|
|
168
168
|
{
|
|
169
|
-
name: "
|
|
169
|
+
name: "metrics_sloReport",
|
|
170
170
|
description: "SLO snapshot: event volume, failure/no-match/pending rates, p95 latency. Prometheus with Event API fallback.",
|
|
171
171
|
annotations: { title: "SLO Report", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
172
172
|
},
|
|
173
173
|
{
|
|
174
|
-
name: "
|
|
174
|
+
name: "metrics_labelCatalog",
|
|
175
175
|
description: "Discover labels for a Prometheus metric with live sampling and known Fluent hints.",
|
|
176
176
|
annotations: { title: "Label Catalog", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
177
177
|
},
|
|
178
178
|
{
|
|
179
|
-
name: "
|
|
179
|
+
name: "metrics_metricCatalog",
|
|
180
180
|
description: "List known Fluent metric families with labels, variants, and example PromQL. Can optionally probe live metric names and labels.",
|
|
181
181
|
annotations: { title: "Metric Catalog", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
182
182
|
},
|
|
183
183
|
{
|
|
184
|
-
name: "
|
|
185
|
-
description: "Plan PromQL for a metric family: validates labels, picks the right histogram variant, and returns a ready-to-run
|
|
184
|
+
name: "metrics_planQuery",
|
|
185
|
+
description: "Plan PromQL for a metric family: validates labels, picks the right histogram variant, and returns a ready-to-run metrics_query payload.",
|
|
186
186
|
annotations: { title: "Plan Metric Query", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
187
187
|
},
|
|
188
188
|
{
|
|
189
|
-
name: "
|
|
189
|
+
name: "metrics_snapshot",
|
|
190
190
|
description: "Dashboard snapshot: runs parallel queries to show event volume, failure rates, breakdowns by entity type, avg latency, and p95 in one call. Uses delta pattern for accurate window counts.",
|
|
191
191
|
annotations: { title: "Metrics Snapshot", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
192
192
|
},
|
|
193
193
|
{
|
|
194
|
-
name: "
|
|
194
|
+
name: "metrics_compare",
|
|
195
195
|
description: "Compare a metric across two adjacent time windows (e.g. last 30m vs preceding 30m). Returns current/previous values, absolute delta, and percentage change per group.",
|
|
196
196
|
annotations: { title: "Compare Windows", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
197
197
|
},
|
|
198
198
|
{
|
|
199
|
-
name: "
|
|
199
|
+
name: "metrics_mutationAudit",
|
|
200
200
|
description: "Audit GraphQL create/update mutation traffic by domain and subdomain. Discovers mutations locally, counts each operation over a fixed window, and aggregates results.",
|
|
201
201
|
annotations: { title: "Mutation Audit", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
202
202
|
},
|
|
@@ -363,7 +363,7 @@ const KNOWN_METRIC_LABELS = {
|
|
|
363
363
|
"env_tag",
|
|
364
364
|
"environment",
|
|
365
365
|
],
|
|
366
|
-
"
|
|
366
|
+
"graphql_query": [
|
|
367
367
|
"account.name",
|
|
368
368
|
"query.type",
|
|
369
369
|
"field.name",
|
|
@@ -533,12 +533,12 @@ const KNOWN_METRIC_FAMILIES = {
|
|
|
533
533
|
],
|
|
534
534
|
examples: [],
|
|
535
535
|
},
|
|
536
|
-
"
|
|
537
|
-
family: "
|
|
536
|
+
"graphql_query": {
|
|
537
|
+
family: "graphql_query",
|
|
538
538
|
category: "graphql_micrometer",
|
|
539
539
|
kind: "timer",
|
|
540
540
|
description: "Micrometer timer for GraphQL field-level execution.",
|
|
541
|
-
labels: KNOWN_METRIC_LABELS["
|
|
541
|
+
labels: KNOWN_METRIC_LABELS["graphql_query"],
|
|
542
542
|
safeGroupBy: ["query.type", "field.name", "account.name"],
|
|
543
543
|
queryable: false,
|
|
544
544
|
notes: [
|
|
@@ -970,8 +970,8 @@ function summarizeKnownMetricFamily(family, includeExamples) {
|
|
|
970
970
|
// parseWindowMs imported from ./time-window.js (single source of truth)
|
|
971
971
|
/**
|
|
972
972
|
* Fetch events from the Event API with pagination, then aggregate by
|
|
973
|
-
* (name|entityType|status). Shared by
|
|
974
|
-
*
|
|
973
|
+
* (name|entityType|status). Shared by metrics_topEvents and the
|
|
974
|
+
* metrics_healthCheck Event API fallback path.
|
|
975
975
|
*/
|
|
976
976
|
async function aggregateEventsFromApi(client, params) {
|
|
977
977
|
const baseParams = {
|
|
@@ -1049,7 +1049,7 @@ function rankTopEvents(groups, totalEvents, topN) {
|
|
|
1049
1049
|
// ---------------------------------------------------------------------------
|
|
1050
1050
|
function requireClient(ctx) {
|
|
1051
1051
|
if (!ctx.client) {
|
|
1052
|
-
throw new ToolError("CONFIG_ERROR", "SDK client is not available. Run
|
|
1052
|
+
throw new ToolError("CONFIG_ERROR", "SDK client is not available. Run config_validate and fix auth/base URL.");
|
|
1053
1053
|
}
|
|
1054
1054
|
return ctx.client;
|
|
1055
1055
|
}
|
|
@@ -1057,7 +1057,7 @@ function requireClient(ctx) {
|
|
|
1057
1057
|
// Handlers
|
|
1058
1058
|
// ---------------------------------------------------------------------------
|
|
1059
1059
|
/**
|
|
1060
|
-
* Handle
|
|
1060
|
+
* Handle metrics_query tool call.
|
|
1061
1061
|
*/
|
|
1062
1062
|
export async function handleMetricsQuery(args, ctx) {
|
|
1063
1063
|
const parsed = MetricsQueryInputSchema.parse(args);
|
|
@@ -1081,7 +1081,7 @@ export async function handleMetricsQuery(args, ctx) {
|
|
|
1081
1081
|
};
|
|
1082
1082
|
}
|
|
1083
1083
|
/**
|
|
1084
|
-
* Handle
|
|
1084
|
+
* Handle metrics_healthCheck tool call.
|
|
1085
1085
|
*/
|
|
1086
1086
|
export async function handleMetricsHealthCheck(args, ctx) {
|
|
1087
1087
|
const parsed = MetricsHealthCheckInputSchema.parse(args);
|
|
@@ -1212,7 +1212,7 @@ export async function handleMetricsHealthCheck(args, ctx) {
|
|
|
1212
1212
|
// Build recommendations
|
|
1213
1213
|
const recommendations = [];
|
|
1214
1214
|
if (findings.some((f) => f.type === "HIGH_FAILURE_RATE")) {
|
|
1215
|
-
recommendations.push("Run
|
|
1215
|
+
recommendations.push("Run event_list({ eventStatus: \"FAILED\", from: \"<recent>\", count: 50 }) to identify failing events");
|
|
1216
1216
|
recommendations.push("Hand off to /fluent-trace for root cause analysis");
|
|
1217
1217
|
}
|
|
1218
1218
|
if (findings.some((f) => f.type === "NO_MATCH_PRESENT")) {
|
|
@@ -1243,7 +1243,7 @@ export async function handleMetricsHealthCheck(args, ctx) {
|
|
|
1243
1243
|
};
|
|
1244
1244
|
}
|
|
1245
1245
|
/**
|
|
1246
|
-
* Handle
|
|
1246
|
+
* Handle metrics_sloReport tool call.
|
|
1247
1247
|
*/
|
|
1248
1248
|
export async function handleMetricsSloReport(args, ctx) {
|
|
1249
1249
|
const parsed = MetricsSloReportInputSchema.parse(args);
|
|
@@ -1386,16 +1386,16 @@ export async function handleMetricsSloReport(args, ctx) {
|
|
|
1386
1386
|
}
|
|
1387
1387
|
const recommendations = [];
|
|
1388
1388
|
if (findings.some((f) => f.type === "HIGH_FAILURE_RATE")) {
|
|
1389
|
-
recommendations.push("Run
|
|
1389
|
+
recommendations.push("Run metrics_topEvents with eventStatus=FAILED and investigate top failures via /fluent-trace.");
|
|
1390
1390
|
}
|
|
1391
1391
|
if (findings.some((f) => f.type === "HIGH_NO_MATCH_RATE")) {
|
|
1392
1392
|
recommendations.push("Validate event names against workflow rulesets using /fluent-workflow-analyzer.");
|
|
1393
1393
|
}
|
|
1394
1394
|
if (findings.some((f) => f.type === "HIGH_PENDING_RATE")) {
|
|
1395
|
-
recommendations.push("Check orchestration backlog and re-run
|
|
1395
|
+
recommendations.push("Check orchestration backlog and re-run metrics_sloReport over shorter windows (e.g., 15m).");
|
|
1396
1396
|
}
|
|
1397
1397
|
if (findings.some((f) => f.type === "HIGH_RUNTIME_P95" || f.type === "HIGH_INFLIGHT_P95")) {
|
|
1398
|
-
recommendations.push("Use
|
|
1398
|
+
recommendations.push("Use metrics_query to break down latency by event_name/entity_type and isolate slow workflows.");
|
|
1399
1399
|
}
|
|
1400
1400
|
return {
|
|
1401
1401
|
ok: true,
|
|
@@ -1433,7 +1433,7 @@ export async function handleMetricsSloReport(args, ctx) {
|
|
|
1433
1433
|
};
|
|
1434
1434
|
}
|
|
1435
1435
|
/**
|
|
1436
|
-
* Handle
|
|
1436
|
+
* Handle metrics_labelCatalog tool call.
|
|
1437
1437
|
*/
|
|
1438
1438
|
export async function handleMetricsLabelCatalog(args, ctx) {
|
|
1439
1439
|
const parsed = MetricsLabelCatalogInputSchema.parse(args);
|
|
@@ -1449,7 +1449,7 @@ export async function handleMetricsLabelCatalog(args, ctx) {
|
|
|
1449
1449
|
let sampled = null;
|
|
1450
1450
|
const warnings = [];
|
|
1451
1451
|
if (!sampling.queryable) {
|
|
1452
|
-
warnings.push("This documented metric is a Micrometer meter name, not a guaranteed Prometheus family. Use
|
|
1452
|
+
warnings.push("This documented metric is a Micrometer meter name, not a guaranteed Prometheus family. Use metrics_metricCatalog with includeLiveMetrics=true to inspect exported metric names first.");
|
|
1453
1453
|
}
|
|
1454
1454
|
else {
|
|
1455
1455
|
sampled = await sampleMetricLabels(client, sampling.metrics, parsed.window, parsed.maxValuesPerLabel, knownLabels);
|
|
@@ -1478,7 +1478,7 @@ export async function handleMetricsLabelCatalog(args, ctx) {
|
|
|
1478
1478
|
};
|
|
1479
1479
|
}
|
|
1480
1480
|
/**
|
|
1481
|
-
* Handle
|
|
1481
|
+
* Handle metrics_metricCatalog tool call.
|
|
1482
1482
|
*/
|
|
1483
1483
|
export async function handleMetricsMetricCatalog(args, ctx) {
|
|
1484
1484
|
const parsed = MetricsMetricCatalogInputSchema.parse(args);
|
|
@@ -1572,7 +1572,7 @@ export async function handleMetricsMetricCatalog(args, ctx) {
|
|
|
1572
1572
|
};
|
|
1573
1573
|
}
|
|
1574
1574
|
/**
|
|
1575
|
-
* Handle
|
|
1575
|
+
* Handle metrics_planQuery tool call.
|
|
1576
1576
|
*/
|
|
1577
1577
|
export async function handleMetricsPlanQuery(args) {
|
|
1578
1578
|
const parsed = MetricsPlanQueryInputSchema.parse(args);
|
|
@@ -1585,7 +1585,7 @@ export async function handleMetricsPlanQuery(args) {
|
|
|
1585
1585
|
metric: parsed.metric,
|
|
1586
1586
|
warnings: [
|
|
1587
1587
|
"Metric is not in the built-in catalog.",
|
|
1588
|
-
"Use
|
|
1588
|
+
"Use metrics_metricCatalog with includeLiveMetrics=true to inspect live metric names before building PromQL.",
|
|
1589
1589
|
],
|
|
1590
1590
|
};
|
|
1591
1591
|
}
|
|
@@ -1761,7 +1761,7 @@ export async function handleMetricsPlanQuery(args) {
|
|
|
1761
1761
|
query,
|
|
1762
1762
|
recommendedQueryType: parsed.goal === "delta" || parsed.goal === "recency" || parsed.goal === "raw" ? "instant" : "instant",
|
|
1763
1763
|
executeWith: {
|
|
1764
|
-
tool: "
|
|
1764
|
+
tool: "metrics_query",
|
|
1765
1765
|
arguments: {
|
|
1766
1766
|
query,
|
|
1767
1767
|
type: "instant",
|
|
@@ -1772,7 +1772,7 @@ export async function handleMetricsPlanQuery(args) {
|
|
|
1772
1772
|
recommendedStep: recommendStep(parseWindowMs(parsed.window)).step,
|
|
1773
1773
|
estimatedPoints: recommendStep(parseWindowMs(parsed.window)).estimatedPoints,
|
|
1774
1774
|
executeWith: {
|
|
1775
|
-
tool: "
|
|
1775
|
+
tool: "metrics_query",
|
|
1776
1776
|
arguments: {
|
|
1777
1777
|
query,
|
|
1778
1778
|
type: "range",
|
|
@@ -1785,14 +1785,14 @@ export async function handleMetricsPlanQuery(args) {
|
|
|
1785
1785
|
countAudit: {
|
|
1786
1786
|
...countAudit,
|
|
1787
1787
|
resetAuditExecuteWith: {
|
|
1788
|
-
tool: "
|
|
1788
|
+
tool: "metrics_query",
|
|
1789
1789
|
arguments: {
|
|
1790
1790
|
query: countAudit.resetAuditQuery,
|
|
1791
1791
|
type: "instant",
|
|
1792
1792
|
},
|
|
1793
1793
|
},
|
|
1794
1794
|
comparisonExecuteWith: {
|
|
1795
|
-
tool: "
|
|
1795
|
+
tool: "metrics_query",
|
|
1796
1796
|
arguments: {
|
|
1797
1797
|
query: countAudit.comparisonQuery,
|
|
1798
1798
|
type: "instant",
|
|
@@ -1819,7 +1819,7 @@ export async function handleMetricsPlanQuery(args) {
|
|
|
1819
1819
|
};
|
|
1820
1820
|
}
|
|
1821
1821
|
/**
|
|
1822
|
-
* Handle
|
|
1822
|
+
* Handle metrics_topEvents tool call.
|
|
1823
1823
|
*/
|
|
1824
1824
|
export async function handleMetricsTopEvents(args, ctx) {
|
|
1825
1825
|
const parsed = MetricsTopEventsInputSchema.parse(args);
|
|
@@ -1852,7 +1852,7 @@ export async function handleMetricsTopEvents(args, ctx) {
|
|
|
1852
1852
|
};
|
|
1853
1853
|
}
|
|
1854
1854
|
// ---------------------------------------------------------------------------
|
|
1855
|
-
//
|
|
1855
|
+
// metrics_snapshot — compound dashboard in one call
|
|
1856
1856
|
// ---------------------------------------------------------------------------
|
|
1857
1857
|
export async function handleMetricsSnapshot(args, ctx) {
|
|
1858
1858
|
const parsed = MetricsSnapshotInputSchema.parse(args);
|
|
@@ -1981,7 +1981,7 @@ export async function handleMetricsSnapshot(args, ctx) {
|
|
|
1981
1981
|
};
|
|
1982
1982
|
}
|
|
1983
1983
|
// ---------------------------------------------------------------------------
|
|
1984
|
-
//
|
|
1984
|
+
// metrics_compare — compare two adjacent time windows
|
|
1985
1985
|
// ---------------------------------------------------------------------------
|
|
1986
1986
|
export async function handleMetricsCompare(args, ctx) {
|
|
1987
1987
|
const parsed = MetricsCompareInputSchema.parse(args);
|
|
@@ -1993,7 +1993,7 @@ export async function handleMetricsCompare(args, ctx) {
|
|
|
1993
1993
|
ok: true,
|
|
1994
1994
|
valid: false,
|
|
1995
1995
|
metric: parsed.metric,
|
|
1996
|
-
error: { code: "UNKNOWN_METRIC", message: "Metric not in catalog or not queryable. Use
|
|
1996
|
+
error: { code: "UNKNOWN_METRIC", message: "Metric not in catalog or not queryable. Use metrics_metricCatalog to discover available metrics." },
|
|
1997
1997
|
};
|
|
1998
1998
|
}
|
|
1999
1999
|
const family = resolved.family;
|
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).
|
|
@@ -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",
|
|
@@ -554,7 +554,7 @@ async function updateSetting(client, input) {
|
|
|
554
554
|
return setting;
|
|
555
555
|
}
|
|
556
556
|
/**
|
|
557
|
-
* Handle
|
|
557
|
+
* Handle setting_get tool call.
|
|
558
558
|
* Fetches settings by name (with wildcard support) and optionally writes to file.
|
|
559
559
|
*/
|
|
560
560
|
export async function handleSettingGet(args, ctx) {
|
|
@@ -615,7 +615,7 @@ export async function handleSettingGet(args, ctx) {
|
|
|
615
615
|
return buildSettingGetResponse(parsed, settings, cacheable && ctx.cache ? { hit: false, stored: true } : undefined);
|
|
616
616
|
}
|
|
617
617
|
/**
|
|
618
|
-
* Handle
|
|
618
|
+
* Handle setting_upsert tool call.
|
|
619
619
|
*/
|
|
620
620
|
export async function handleSettingUpsert(args, ctx) {
|
|
621
621
|
const parsed = SettingUpsertInputSchema.parse(args);
|
|
@@ -678,7 +678,7 @@ export async function handleSettingUpsert(args, ctx) {
|
|
|
678
678
|
return result;
|
|
679
679
|
}
|
|
680
680
|
/**
|
|
681
|
-
* Handle
|
|
681
|
+
* Handle setting_bulkUpsert tool call.
|
|
682
682
|
*/
|
|
683
683
|
export async function handleSettingBulkUpsert(args, ctx) {
|
|
684
684
|
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);
|