@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.
@@ -2,12 +2,12 @@
2
2
  * GraphQL Query Execution Tools
3
3
  *
4
4
  * Four query/mutation execution tools:
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
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 graphql.listRoots/buildQuery/validate/generateFull.
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: "graphql.query",
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: "graphql.queryAll",
73
- description: "Auto-paginated GraphQL query. Follows cursors, merges edges, deduplicates. Use instead of graphql.query when you need all records.",
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: "graphql.batchMutate",
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: "graphql.introspect",
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 config.validate and fix auth/base URL.");
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 graphql.query tool call.
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 graphql.queryAll tool call.
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 graphql.batchMutate tool call.
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 graphql.introspect tool call.
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
- * 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
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: "graphql.listRoots",
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: "graphql.planOperation",
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: "graphql.buildQuery",
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: "graphql.validate",
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: "graphql.generateFull",
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 graphql.listRoots to discover available fields.`);
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
- ? "graphql.queryAll"
470
- : "graphql.query",
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 graphql.listRoots to discover available fields.`);
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 graphql.introspect's force param.
551
+ * Exposed for use by graphql_introspect's force param.
552
552
  */
553
553
  export function clearSchemaCache(ctx) {
554
554
  if (!ctx.client)
@@ -1,6 +1,6 @@
1
1
  /**
2
- * Metrics tools: metrics.query, metrics.topEvents, metrics.healthCheck,
3
- * metrics.sloReport, metrics.labelCatalog, metrics.catalog
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: "metrics.query",
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: "metrics.topEvents",
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: "metrics.healthCheck",
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: "metrics.sloReport",
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: "metrics.labelCatalog",
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: "metrics.metricCatalog",
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: "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.",
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: "metrics.snapshot",
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: "metrics.compare",
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: "metrics.mutationAudit",
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
- "graphql.query": [
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
- "graphql.query": {
537
- family: "graphql.query",
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["graphql.query"],
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 metrics.topEvents and the
974
- * metrics.healthCheck Event API fallback path.
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 config.validate and fix auth/base URL.");
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 metrics.query tool call.
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 metrics.healthCheck tool call.
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 event.list({ eventStatus: \"FAILED\", from: \"<recent>\", count: 50 }) to identify failing events");
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 metrics.sloReport tool call.
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 metrics.topEvents with eventStatus=FAILED and investigate top failures via /fluent-trace.");
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 metrics.sloReport over shorter windows (e.g., 15m).");
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 metrics.query to break down latency by event_name/entity_type and isolate slow workflows.");
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 metrics.labelCatalog tool call.
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 metrics.metricCatalog with includeLiveMetrics=true to inspect exported metric names first.");
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 metrics.metricCatalog tool call.
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 metrics.planQuery tool call.
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 metrics.metricCatalog with includeLiveMetrics=true to inspect live metric names before building PromQL.",
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: "metrics.query",
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: "metrics.query",
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: "metrics.query",
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: "metrics.query",
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 metrics.topEvents tool call.
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
- // metrics.snapshot — compound dashboard in one call
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
- // metrics.compare — compare two adjacent time windows
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 metrics.metricCatalog to discover available metrics." },
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;
@@ -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
- * (connection.add/remove/list/switch), and per-tool-call profile resolution
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 connection.add tool
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";
@@ -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., plugin.list with 597 rule keys)
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
  }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Settings management tools: setting.upsert, setting.bulkUpsert
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: "setting.get",
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: "setting.upsert",
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: "setting.bulkUpsert",
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 config.validate and fix auth/base URL.");
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
- "setting:get",
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 setting.get tool call.
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 setting.upsert tool call.
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 setting.bulkUpsert tool call.
681
+ * Handle setting_bulkUpsert tool call.
682
682
  */
683
683
  export async function handleSettingBulkUpsert(args, ctx) {
684
684
  const parsed = SettingBulkUpsertInputSchema.parse(args);
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Test tools: test.assert
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: "test.assert",
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 config.validate and fix auth/base URL.");
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 test.assert tool call.
256
+ * Handle test_assert tool call.
257
257
  */
258
258
  export async function handleTestAssert(args, ctx) {
259
259
  const parsed = TestAssertInputSchema.parse(args);