@fluentcommerce/fluent-mcp-extn 0.2.0 → 0.2.1

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.
@@ -149,19 +149,19 @@ export class FluentClientAdapter {
149
149
  async queryPrometheus(payload) {
150
150
  const isRange = payload.type === "range";
151
151
  const query = isRange
152
- ? `query MetricRange($query: String!, $start: DateTime!, $end: DateTime!, $step: String!) {
153
- metricRange(query: $query, start: $start, end: $end, step: $step) {
154
- status
155
- data { resultType result { metric values } }
156
- errorType error warnings
157
- }
152
+ ? `query MetricRange($query: String!, $start: DateTime!, $end: DateTime!, $step: String!) {
153
+ metricRange(query: $query, start: $start, end: $end, step: $step) {
154
+ status
155
+ data { resultType result { metric values } }
156
+ errorType error warnings
157
+ }
158
158
  }`
159
- : `query MetricInstant($query: String!${payload.time ? ", $time: DateTime" : ""}) {
160
- metricInstant(query: $query${payload.time ? ", time: $time" : ""}) {
161
- status
162
- data { resultType result { metric value } }
163
- errorType error warnings
164
- }
159
+ : `query MetricInstant($query: String!${payload.time ? ", $time: DateTime" : ""}) {
160
+ metricInstant(query: $query${payload.time ? ", time: $time" : ""}) {
161
+ status
162
+ data { resultType result { metric value } }
163
+ errorType error warnings
164
+ }
165
165
  }`;
166
166
  const variables = { query: payload.query };
167
167
  if (isRange) {
package/dist/tools.js CHANGED
@@ -193,6 +193,7 @@ const GraphQLBatchMutateInputSchema = z.object({
193
193
  inputs: z.array(z.record(z.string(), z.unknown())).min(1).max(50),
194
194
  returnFields: z.array(z.string()).optional(),
195
195
  operationName: z.string().optional(),
196
+ dryRun: z.boolean().default(false),
196
197
  });
197
198
  const GraphQLIntrospectInputSchema = z.object({
198
199
  type: z.string().optional(),
@@ -888,6 +889,10 @@ const TOOL_DEFINITIONS = [
888
889
  type: "string",
889
890
  description: "Custom GraphQL operation name (default: Batch<MutationName>s).",
890
891
  },
892
+ dryRun: {
893
+ type: "boolean",
894
+ description: "If true, builds and validates the mutation query without executing it. Returns the query, variables, and input count for review. Default: false.",
895
+ },
891
896
  },
892
897
  required: ["mutation", "inputs"],
893
898
  additionalProperties: false,
@@ -2540,6 +2545,18 @@ export function registerToolHandlers(server, ctx) {
2540
2545
  for (let i = 0; i < batchSize; i++) {
2541
2546
  variables[`input${i + 1}`] = parsed.inputs[i];
2542
2547
  }
2548
+ // Dry-run: return query + variables without executing
2549
+ if (parsed.dryRun) {
2550
+ return json({
2551
+ ok: true,
2552
+ dryRun: true,
2553
+ mutation: parsed.mutation,
2554
+ inputCount: batchSize,
2555
+ query,
2556
+ variables,
2557
+ note: "No API call made. Set dryRun=false to execute.",
2558
+ });
2559
+ }
2543
2560
  const gqlPayload = {
2544
2561
  query,
2545
2562
  variables: toSdkVariables(variables),
@@ -1,100 +1,100 @@
1
- # Contributing Guide
2
-
3
- This guide defines how to safely change `fluent-mcp-extn` while keeping
4
- behavior predictable for all clients.
5
-
6
- ## 1) Core principles
7
-
8
- - Keep the extension **client-agnostic** (no client-specific names in code/docs).
9
- - Prefer **typed boundaries** and avoid unscoped `any`.
10
- - Keep tool responses consistent:
11
- - success: `{ "ok": true, ... }`
12
- - failure: `{ "ok": false, "error": { ... } }`
13
- - Route Fluent API calls through `FluentClientAdapter` only.
14
-
15
- ## 2) Local setup
16
-
17
- ```bash
18
- npm install
19
- npm run build
20
- npm test
21
- ```
22
-
23
- ## 3) Change workflow
24
-
25
- 1. Make focused changes.
26
- 2. Add or update tests.
27
- 3. Run `npm run build`.
28
- 4. Run `npm test`.
29
- 5. Run `npm run e2e:smoke -- --skip-real-send` when touching tool runtime (requires `FLUENT_BASE_URL` + auth env, or `--profile`).
30
- 6. Update docs if tool behavior/config changed.
31
-
32
- ## 4) Adding a new tool (required checklist)
33
-
34
- When adding a tool, update all of the following:
35
-
36
- 1. `src/tools.ts`
37
- - add zod schema
38
- - add `TOOL_DEFINITIONS` entry
39
- - add handler branch
40
- 2. `src/index.ts`
41
- - add tool name to startup log list
42
- 3. tests
43
- - add/adjust unit tests in `test/`
44
- 4. docs
45
- - update `docs/TOOL_REFERENCE.md`
46
- - update `docs/E2E_TESTING.md` if smoke flow changes
47
-
48
- ## 5) Error handling standards
49
-
50
- - Throw `ToolError` for domain/runtime failures.
51
- - Do not return raw thrown errors directly.
52
- - Let `toToolFailure()` convert unknown errors into normalized error payloads.
53
- - Use specific error codes where possible (`AUTH_ERROR`, `VALIDATION_ERROR`, etc.).
54
-
55
- ## 6) Resilience standards
56
-
57
- - Keep retry/timeout policy centralized via:
58
- - `withTimeout()`
59
- - `withRetry()`
60
- - Avoid per-tool custom retry loops.
61
- - Use config-driven values (`FLUENT_REQUEST_TIMEOUT_MS`, retry env vars).
62
- - Preserve idempotency boundaries:
63
- - read operations can use retry/backoff
64
- - non-idempotent write operations must not auto-retry
65
- - Keep SDK retry disabled and adapter retry as the single control plane.
66
-
67
- ## 7) Security and secrets
68
-
69
- - Never log secrets or token values.
70
- - Use redacted summaries via `toSafeConfigSummary()`.
71
- - Prefer profile, `TOKEN_COMMAND`, or OAuth over static tokens in shared environments.
72
-
73
- ## 8) Documentation standards
74
-
75
- - Keep docs concise and task-oriented.
76
- - Include at least one valid request example when changing tool inputs.
77
- - Update all cross-links in `README.md` when adding new docs.
78
- - For behavior changes, update all affected docs end-to-end:
79
- - `README.md`
80
- - `docs/TOOL_REFERENCE.md`
81
- - `docs/RUNBOOK.md`
82
- - `docs/E2E_TESTING.md`
83
-
84
- ## 9) Pull request quality bar
85
-
86
- A change is ready only if:
87
-
88
- - build passes
89
- - tests pass
90
- - smoke runner passes (or is intentionally skipped with rationale)
91
- - no lint errors introduced
92
- - docs updated for behavior/interface changes
93
- - no client-specific wording added
94
-
95
- ## 10) CI expectations
96
-
97
- - CI workflow file: `.github/workflows/ci.yml`
98
- - `build-and-test` must pass for every PR.
99
- - `e2e-smoke` is manual (`workflow_dispatch`) and requires repository secrets.
100
-
1
+ # Contributing Guide
2
+
3
+ This guide defines how to safely change `fluent-mcp-extn` while keeping
4
+ behavior predictable for all clients.
5
+
6
+ ## 1) Core principles
7
+
8
+ - Keep the extension **client-agnostic** (no client-specific names in code/docs).
9
+ - Prefer **typed boundaries** and avoid unscoped `any`.
10
+ - Keep tool responses consistent:
11
+ - success: `{ "ok": true, ... }`
12
+ - failure: `{ "ok": false, "error": { ... } }`
13
+ - Route Fluent API calls through `FluentClientAdapter` only.
14
+
15
+ ## 2) Local setup
16
+
17
+ ```bash
18
+ npm install
19
+ npm run build
20
+ npm test
21
+ ```
22
+
23
+ ## 3) Change workflow
24
+
25
+ 1. Make focused changes.
26
+ 2. Add or update tests.
27
+ 3. Run `npm run build`.
28
+ 4. Run `npm test`.
29
+ 5. Run `npm run e2e:smoke -- --skip-real-send` when touching tool runtime (requires `FLUENT_BASE_URL` + auth env, or `--profile`).
30
+ 6. Update docs if tool behavior/config changed.
31
+
32
+ ## 4) Adding a new tool (required checklist)
33
+
34
+ When adding a tool, update all of the following:
35
+
36
+ 1. `src/tools.ts`
37
+ - add zod schema
38
+ - add `TOOL_DEFINITIONS` entry
39
+ - add handler branch
40
+ 2. `src/index.ts`
41
+ - add tool name to startup log list
42
+ 3. tests
43
+ - add/adjust unit tests in `test/`
44
+ 4. docs
45
+ - update `docs/TOOL_REFERENCE.md`
46
+ - update `docs/E2E_TESTING.md` if smoke flow changes
47
+
48
+ ## 5) Error handling standards
49
+
50
+ - Throw `ToolError` for domain/runtime failures.
51
+ - Do not return raw thrown errors directly.
52
+ - Let `toToolFailure()` convert unknown errors into normalized error payloads.
53
+ - Use specific error codes where possible (`AUTH_ERROR`, `VALIDATION_ERROR`, etc.).
54
+
55
+ ## 6) Resilience standards
56
+
57
+ - Keep retry/timeout policy centralized via:
58
+ - `withTimeout()`
59
+ - `withRetry()`
60
+ - Avoid per-tool custom retry loops.
61
+ - Use config-driven values (`FLUENT_REQUEST_TIMEOUT_MS`, retry env vars).
62
+ - Preserve idempotency boundaries:
63
+ - read operations can use retry/backoff
64
+ - non-idempotent write operations must not auto-retry
65
+ - Keep SDK retry disabled and adapter retry as the single control plane.
66
+
67
+ ## 7) Security and secrets
68
+
69
+ - Never log secrets or token values.
70
+ - Use redacted summaries via `toSafeConfigSummary()`.
71
+ - Prefer profile, `TOKEN_COMMAND`, or OAuth over static tokens in shared environments.
72
+
73
+ ## 8) Documentation standards
74
+
75
+ - Keep docs concise and task-oriented.
76
+ - Include at least one valid request example when changing tool inputs.
77
+ - Update all cross-links in `README.md` when adding new docs.
78
+ - For behavior changes, update all affected docs end-to-end:
79
+ - `README.md`
80
+ - `docs/TOOL_REFERENCE.md`
81
+ - `docs/RUNBOOK.md`
82
+ - `docs/E2E_TESTING.md`
83
+
84
+ ## 9) Pull request quality bar
85
+
86
+ A change is ready only if:
87
+
88
+ - build passes
89
+ - tests pass
90
+ - smoke runner passes (or is intentionally skipped with rationale)
91
+ - no lint errors introduced
92
+ - docs updated for behavior/interface changes
93
+ - no client-specific wording added
94
+
95
+ ## 10) CI expectations
96
+
97
+ - CI workflow file: `.github/workflows/ci.yml`
98
+ - `build-and-test` must pass for every PR.
99
+ - `e2e-smoke` is manual (`workflow_dispatch`) and requires repository secrets.
100
+