@fluentcommerce/fluent-mcp-extn 0.2.0 → 0.3.0

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/docs/RUNBOOK.md CHANGED
@@ -1,233 +1,315 @@
1
- # Operations Runbook
2
-
3
- This runbook explains how to configure, verify, and troubleshoot
4
- `fluent-mcp-extn` in day-to-day usage.
5
-
6
- ## 1) Prerequisites
7
-
8
- - Node.js 20+
9
- - npm available
10
- - valid Fluent credentials (profile, OAuth, token command, or static token)
11
-
12
- ## 2) Local setup
13
-
14
- ```bash
15
- npm install
16
- npm run build
17
- npm test
18
- npm run e2e:smoke
19
- ```
20
-
21
- Profile-based shortcuts:
22
-
23
- ```bash
24
- npm run e2e:smoke -- --wizard
25
- npm run e2e:smoke -- --profile CLIENT_PROFILE
26
- npm run e2e:smoke -- --profile CLIENT_PROFILE --retailer RETAILER_REF_OR_ID
27
- npm run e2e:smoke -- --profile CLIENT_PROFILE --all-retailers
28
- ```
29
-
30
- Notes:
31
- - `--wizard` is interactive (TTY required).
32
- - For CI/non-interactive runs, use explicit flags (`--profile <name> --retailer <id|ref>` or `--profile <name> --all-retailers`).
33
- - `--profile` only mode may fall back to a retailer that has candidate orders for real-send validation; use `--retailer` for strict retailer scope.
34
-
35
- ## 3) MCP registration
36
-
37
- Add server in your workspace `.mcp.json`:
38
-
39
- ```json
40
- {
41
- "mcpServers": {
42
- "fluent-mcp-extn": {
43
- "type": "stdio",
44
- "command": "node",
45
- "args": ["fluent-mcp-extn/dist/index.js"],
46
- "env": {
47
- "FLUENT_BASE_URL": "https://YOUR_ACCOUNT.sandbox.api.fluentretail.com",
48
- "FLUENT_RETAILER_ID": "YOUR_RETAILER_ID",
49
- "TOKEN_COMMAND": "vault read -field=token secret/fluent/client-dev"
50
- }
51
- }
52
- }
53
- }
54
- ```
55
-
56
- Reload Cursor after editing `.mcp.json`.
57
-
58
- ## 4) Startup verification checklist
59
-
60
- Run tools in this order:
61
-
62
- 1. `config.validate`
63
- 2. `health.ping`
64
- 3. `connection.test`
65
- 4. `event.build`
66
- 5. `event.send` with `dryRun: true`
67
- 6. `event.send` with `dryRun: false`
68
- 7. `event.get` using ID returned by send
69
- 8. `graphql.query` simple read
70
- 9. `workflow.transitions` (optional) — verify User Action API access for a known trigger
71
- 10. `graphql.queryAll` — verify auto-pagination and run-level timeout
72
- 11. `graphql.introspect` with `listMutations: true` — verify schema access
73
- 12. (optional) `graphql.query` synchronous fulfilment options call
74
- (`createFulfilmentOption` with `executionMode: AWAIT_ORCHESTRATION`)
75
- for live checkout readiness checks
76
-
77
- If all steps pass, runtime wiring is healthy.
78
-
79
- Write-safety note:
80
- - non-idempotent write tools do not auto-retry
81
- - callers should confirm failures before manual re-submission
82
-
83
- ## 5) Troubleshooting by symptom
84
-
85
- ### `sdk adapter: not configured`
86
-
87
- Likely causes:
88
-
89
- - `FLUENT_BASE_URL` missing
90
- - auth vars missing or invalid
91
- - `TOKEN_COMMAND` failing
92
-
93
- Actions:
94
-
95
- 1. call `config.validate`
96
- 2. inspect `errors` and `warnings`
97
- 3. verify env vars in `.mcp.json`
98
- 4. reload Cursor MCP process
99
-
100
- ### `AUTH_ERROR`
101
-
102
- Likely causes:
103
-
104
- - invalid client credentials
105
- - expired static token
106
- - vault command returning stale/empty token
107
-
108
- Actions:
109
-
110
- 1. test auth source directly (OAuth or command output)
111
- 2. ensure token command output is either raw token or JSON with
112
- `access_token`/`token`
113
- 3. confirm account permissions for target APIs
114
- 4. for static token mode, rotate token at source (API still enforces true expiry)
115
-
116
- ### `FLUENT_PROFILE` could not be loaded
117
-
118
- Likely causes:
119
-
120
- - profile name is wrong
121
- - retailer ref in `FLUENT_PROFILE_RETAILER` does not match `retailer.<ref>.json`
122
- - profile files are missing in `~/.fluentcommerce/<profile>/`
123
-
124
- Actions:
125
-
126
- 1. run `fluent profile list`
127
- 2. verify `FLUENT_PROFILE` value and active profile files
128
- 3. if using `FLUENT_PROFILE_RETAILER`, confirm it matches retailer **ref** (not ID)
129
- 4. set `FLUENT_PROFILE_DIR` only if profiles are stored outside default path
130
-
131
- ### `TIMEOUT_ERROR` / `NETWORK_ERROR`
132
-
133
- Likely causes:
134
-
135
- - temporary upstream instability
136
- - strict timeout/retry values
137
- - DNS/proxy/firewall constraints
138
-
139
- Actions:
140
-
141
- 1. increase `FLUENT_REQUEST_TIMEOUT_MS`
142
- 2. increase `FLUENT_RETRY_ATTEMPTS`
143
- 3. verify base URL and outbound connectivity
144
- 4. for `graphql.queryAll`, increase tool-level `timeoutMs` (controls whole pagination run)
145
-
146
- ### `VALIDATION_ERROR`
147
-
148
- Likely causes:
149
-
150
- - missing required tool fields
151
- - wrong payload shape
152
-
153
- Actions:
154
-
155
- 1. follow examples in `docs/TOOL_REFERENCE.md`
156
- 2. check `error.details.issues` path/message pairs
157
-
158
- ### Webhook signature validation mismatches
159
-
160
- Likely causes:
161
-
162
- - validating a re-serialized JSON object rather than original webhook body bytes
163
- - incorrect or incomplete public key
164
-
165
- Actions:
166
-
167
- 1. pass exact raw HTTP body via `rawBody` in `webhook.validate`
168
- 2. verify signature header value is unchanged
169
- 3. confirm algorithm (`SHA512withRSA` default)
170
-
171
- ### `SDK_ERROR` with `Request failed: 400` on `event.send`
172
-
173
- Likely causes:
174
-
175
- - event payload `retailerId` does not match the target entity's retailer
176
- - sending with only `entityRef` when workflow expects ID-aware routing
177
-
178
- Actions:
179
-
180
- 1. query the target entity via `graphql.query` and capture `id`, `ref`, and retailer
181
- 2. send event with matching `retailerId`
182
- 3. include `entityId` and `rootEntityId` when available
183
-
184
- ### `SDK_ERROR` with `Workflow [FULFILMENT_OPTIONS::<type>] not found`
185
-
186
- Likely causes:
187
-
188
- - fulfilment options workflow not deployed for this retailer
189
- - `type` / `orderType` does not map to a deployed workflow subtype
190
- - mutation is sent to the wrong retailer ID/environment
191
-
192
- Actions:
193
-
194
- 1. list workflows for target context and confirm `FULFILMENT_OPTIONS::<type>`
195
- exists
196
- 2. deploy/merge the required fulfilment options workflow for checkout
197
- 3. re-run mutation with matching `retailerId`, `type`, and `orderType`
198
- 4. verify synchronous response includes `plans`/`fulfilments`
199
-
200
- ## 6) Reliability tuning guidance
201
-
202
- Start with defaults and adjust only when needed.
203
-
204
- - low latency APIs: keep defaults
205
- - slower integrations: increase timeout to 45-60s
206
- - intermittent networks: increase retries to 4-5
207
- - write operations are timeout-only; retries apply to read paths only
208
- - SDK internal retries are disabled; adapter policy is the single retry control
209
-
210
- Example:
211
-
212
- ```json
213
- {
214
- "FLUENT_REQUEST_TIMEOUT_MS": "45000",
215
- "FLUENT_RETRY_ATTEMPTS": "4",
216
- "FLUENT_RETRY_INITIAL_DELAY_MS": "400",
217
- "FLUENT_RETRY_MAX_DELAY_MS": "6000",
218
- "FLUENT_RETRY_FACTOR": "2"
219
- }
220
- ```
221
-
222
- ## 7) Safe extension workflow
223
-
224
- When adding or changing a tool:
225
-
226
- 1. update schema in `src/tools.ts`
227
- 2. keep response envelopes consistent
228
- 3. route API calls via `FluentClientAdapter`
229
- 4. add unit tests
230
- 5. run:
231
- - `npm run build`
232
- - `npm test`
233
-
1
+ # Operations Runbook
2
+
3
+ This runbook explains how to configure, verify, and troubleshoot
4
+ `fluent-mcp-extn` in day-to-day usage.
5
+
6
+ ## 1) Prerequisites
7
+
8
+ - Node.js 20+
9
+ - npm available
10
+ - valid Fluent credentials (profile, OAuth, token command, or static token)
11
+
12
+ ## 2) Local setup
13
+
14
+ ```bash
15
+ npm install
16
+ npm run build
17
+ npm test
18
+ npm run e2e:smoke
19
+ ```
20
+
21
+ Profile-based shortcuts:
22
+
23
+ ```bash
24
+ npm run e2e:smoke -- --wizard
25
+ npm run e2e:smoke -- --profile CLIENT_PROFILE
26
+ npm run e2e:smoke -- --profile CLIENT_PROFILE --retailer RETAILER_REF_OR_ID
27
+ npm run e2e:smoke -- --profile CLIENT_PROFILE --all-retailers
28
+ ```
29
+
30
+ Notes:
31
+ - `--wizard` is interactive (TTY required).
32
+ - For CI/non-interactive runs, use explicit flags (`--profile <name> --retailer <id|ref>` or `--profile <name> --all-retailers`).
33
+ - `--profile` only mode may fall back to a retailer that has candidate orders for real-send validation; use `--retailer` for strict retailer scope.
34
+
35
+ ## 3) MCP registration
36
+
37
+ Add server in your workspace `.mcp.json`.
38
+
39
+ ### OAuth / Token Command mode
40
+
41
+ ```json
42
+ {
43
+ "mcpServers": {
44
+ "fluent-mcp-extn": {
45
+ "type": "stdio",
46
+ "command": "node",
47
+ "args": ["fluent-mcp-extn/dist/index.js"],
48
+ "env": {
49
+ "FLUENT_BASE_URL": "https://YOUR_ACCOUNT.sandbox.api.fluentretail.com",
50
+ "FLUENT_RETAILER_ID": "YOUR_RETAILER_ID",
51
+ "TOKEN_COMMAND": "vault read -field=token secret/fluent/client-dev"
52
+ }
53
+ }
54
+ }
55
+ }
56
+ ```
57
+
58
+ ### Profile mode (recommended)
59
+
60
+ ```json
61
+ {
62
+ "mcpServers": {
63
+ "fluent-mcp-extn": {
64
+ "type": "stdio",
65
+ "command": "node",
66
+ "args": ["fluent-mcp-extn/dist/index.js"],
67
+ "env": {
68
+ "FLUENT_PROFILE": "HMDEV",
69
+ "FLUENT_PROFILE_RETAILER": "HM_TEST"
70
+ }
71
+ }
72
+ }
73
+ }
74
+ ```
75
+
76
+ Profile mode reads credentials from `~/.fluentcommerce/<profile>/` and
77
+ auto-resolves the retailer ID from the retailer ref. No base URL, client ID,
78
+ or secrets are needed in `.mcp.json`.
79
+
80
+ Reload your IDE after editing `.mcp.json`.
81
+
82
+ ## 4) Startup verification checklist
83
+
84
+ Run tools in this order:
85
+
86
+ 1. `config.validate`
87
+ 2. `health.ping`
88
+ 3. `connection.test`
89
+ 4. `event.build`
90
+ 5. `event.send` with `dryRun: true`
91
+ 6. `event.send` with `dryRun: false`
92
+ 7. `event.get` using ID returned by send
93
+ 8. `graphql.query` simple read
94
+ 9. `entity.get` — verify entity lookup works (e.g., look up a known order by ref)
95
+ 10. `setting.get` with `name: "fc.mystique.manifest.%"` — verify settings read access and wildcard support
96
+ 11. `workflow.list` verify REST workflow API access (list all workflows for a retailer)
97
+ 12. `workflow.get` with `entityType: "ORDER", entitySubtype: "HD"` — verify specific workflow fetch
98
+ 13. `workflow.transitions` (optional) verify User Action API access for a known trigger
99
+ 14. `graphql.queryAll` — verify auto-pagination and run-level timeout
100
+ 12. `graphql.introspect` with `listMutations: true` — verify schema access
101
+ 13. `environment.discover` with `include: ["retailer", "locations"]` — verify environment snapshot
102
+ 14. `environment.validate` with `checks: ["auth", "retailer", "locations"]` — verify pre-flight checks
103
+ 15. (optional) `graphql.query` synchronous fulfilment options call
104
+ (`createFulfilmentOption` with `executionMode: AWAIT_ORCHESTRATION`)
105
+ for live checkout readiness checks
106
+
107
+ If all steps pass, runtime wiring is healthy.
108
+
109
+ Write-safety note:
110
+ - non-idempotent write tools do not auto-retry
111
+ - callers should confirm failures before manual re-submission
112
+
113
+ ## 5) Response shaping configuration
114
+
115
+ Response shaping controls how large API responses are processed before being
116
+ returned to the LLM. When a response exceeds the budget, arrays are
117
+ auto-summarized (not truncated) with record counts, field inventories, value
118
+ distributions, and sample records.
119
+
120
+ | Env var | Default | Description |
121
+ |---------|---------|-------------|
122
+ | `FLUENT_RESPONSE_BUDGET_CHARS` | `50000` (~12.5k tokens) | Max serialized response size. Set to `0` to disable (unlimited). |
123
+ | `FLUENT_RESPONSE_MAX_ARRAY` | `50` | Arrays exceeding this size are auto-summarized. Only active when budget > 0. |
124
+ | `FLUENT_RESPONSE_SAMPLE_SIZE` | `3` | Number of sample records included in array summaries. |
125
+
126
+ Set these in the `env` block of your `.mcp.json`:
127
+
128
+ ```json
129
+ {
130
+ "mcpServers": {
131
+ "fluent-mcp-extn": {
132
+ "type": "stdio",
133
+ "command": "node",
134
+ "args": ["fluent-mcp-extn/dist/index.js"],
135
+ "env": {
136
+ "FLUENT_PROFILE": "HMDEV",
137
+ "FLUENT_RESPONSE_BUDGET_CHARS": "80000",
138
+ "FLUENT_RESPONSE_MAX_ARRAY": "100",
139
+ "FLUENT_RESPONSE_SAMPLE_SIZE": "5"
140
+ }
141
+ }
142
+ }
143
+ }
144
+ ```
145
+
146
+ When shaping is active, responses include a `_responseMeta` object with
147
+ `originalChars`, `shapedChars`, `reductionPercent`, and `summarizedArrays`.
148
+
149
+ ## 6) Troubleshooting by symptom
150
+
151
+ ### `sdk adapter: not configured`
152
+
153
+ Likely causes:
154
+
155
+ - `FLUENT_BASE_URL` missing
156
+ - auth vars missing or invalid
157
+ - `TOKEN_COMMAND` failing
158
+
159
+ Actions:
160
+
161
+ 1. call `config.validate`
162
+ 2. inspect `errors` and `warnings`
163
+ 3. verify env vars in `.mcp.json`
164
+ 4. reload your IDE's MCP process
165
+
166
+ ### `AUTH_ERROR`
167
+
168
+ Likely causes:
169
+
170
+ - invalid client credentials
171
+ - expired static token
172
+ - vault command returning stale/empty token
173
+
174
+ Actions:
175
+
176
+ 1. test auth source directly (OAuth or command output)
177
+ 2. ensure token command output is either raw token or JSON with
178
+ `access_token`/`token`
179
+ 3. confirm account permissions for target APIs
180
+ 4. for static token mode, rotate token at source (API still enforces true expiry)
181
+
182
+ ### `FLUENT_PROFILE` could not be loaded
183
+
184
+ Likely causes:
185
+
186
+ - profile name is wrong
187
+ - retailer ref in `FLUENT_PROFILE_RETAILER` does not match `retailer.<ref>.json`
188
+ - profile files are missing in `~/.fluentcommerce/<profile>/`
189
+
190
+ Actions:
191
+
192
+ 1. run `fluent profile list`
193
+ 2. verify `FLUENT_PROFILE` value and active profile files
194
+ 3. if using `FLUENT_PROFILE_RETAILER`, confirm it matches retailer **ref** (not ID)
195
+ 4. set `FLUENT_PROFILE_DIR` only if profiles are stored outside default path
196
+
197
+ ### `TIMEOUT_ERROR` / `NETWORK_ERROR`
198
+
199
+ Likely causes:
200
+
201
+ - temporary upstream instability
202
+ - strict timeout/retry values
203
+ - DNS/proxy/firewall constraints
204
+
205
+ Actions:
206
+
207
+ 1. increase `FLUENT_REQUEST_TIMEOUT_MS`
208
+ 2. increase `FLUENT_RETRY_ATTEMPTS`
209
+ 3. verify base URL and outbound connectivity
210
+ 4. for `graphql.queryAll`, increase tool-level `timeoutMs` (controls whole pagination run)
211
+
212
+ ### `VALIDATION_ERROR`
213
+
214
+ Likely causes:
215
+
216
+ - missing required tool fields
217
+ - wrong payload shape
218
+
219
+ Actions:
220
+
221
+ 1. follow examples in `docs/TOOL_REFERENCE.md`
222
+ 2. check `error.details.issues` path/message pairs
223
+
224
+ ### Webhook signature validation mismatches
225
+
226
+ Likely causes:
227
+
228
+ - validating a re-serialized JSON object rather than original webhook body bytes
229
+ - incorrect or incomplete public key
230
+
231
+ Actions:
232
+
233
+ 1. pass exact raw HTTP body via `rawBody` in `webhook.validate`
234
+ 2. verify signature header value is unchanged
235
+ 3. confirm algorithm (`SHA512withRSA` default)
236
+
237
+ ### `SDK_ERROR` with `Request failed: 400` on `event.send`
238
+
239
+ Likely causes:
240
+
241
+ - event payload `retailerId` does not match the target entity's retailer
242
+ - sending with only `entityRef` when workflow expects ID-aware routing
243
+
244
+ Actions:
245
+
246
+ 1. query the target entity via `graphql.query` and capture `id`, `ref`, and retailer
247
+ 2. send event with matching `retailerId`
248
+ 3. include `entityId` and `rootEntityId` when available
249
+
250
+ ### `SDK_ERROR` with `Workflow [FULFILMENT_OPTIONS::<type>] not found`
251
+
252
+ Likely causes:
253
+
254
+ - fulfilment options workflow not deployed for this retailer
255
+ - `type` / `orderType` does not map to a deployed workflow subtype
256
+ - mutation is sent to the wrong retailer ID/environment
257
+
258
+ Actions:
259
+
260
+ 1. list workflows for target context and confirm `FULFILMENT_OPTIONS::<type>`
261
+ exists
262
+ 2. deploy/merge the required fulfilment options workflow for checkout
263
+ 3. re-run mutation with matching `retailerId`, `type`, and `orderType`
264
+ 4. verify synchronous response includes `plans`/`fulfilments`
265
+
266
+ ### Response appears truncated or incomplete
267
+
268
+ Likely causes:
269
+
270
+ - `FLUENT_RESPONSE_BUDGET_CHARS` is set too low for the query
271
+ - large arrays are being auto-summarized (check for `_responseMeta` in response)
272
+
273
+ Actions:
274
+
275
+ 1. check the `_responseMeta` object — if `reductionPercent` is high, the budget
276
+ is actively shaping the response
277
+ 2. increase `FLUENT_RESPONSE_BUDGET_CHARS` (e.g., `80000` or `100000`)
278
+ 3. increase `FLUENT_RESPONSE_MAX_ARRAY` if specific arrays are being summarized
279
+ 4. set `FLUENT_RESPONSE_BUDGET_CHARS=0` to disable shaping entirely
280
+ 5. for `event.flowInspect`, use `compact: true` (default) to get a pre-analyzed
281
+ summary instead of raw arrays
282
+
283
+ ## 7) Reliability tuning guidance
284
+
285
+ Start with defaults and adjust only when needed.
286
+
287
+ - low latency APIs: keep defaults
288
+ - slower integrations: increase timeout to 45-60s
289
+ - intermittent networks: increase retries to 4-5
290
+ - write operations are timeout-only; retries apply to read paths only
291
+ - SDK internal retries are disabled; adapter policy is the single retry control
292
+
293
+ Example:
294
+
295
+ ```json
296
+ {
297
+ "FLUENT_REQUEST_TIMEOUT_MS": "45000",
298
+ "FLUENT_RETRY_ATTEMPTS": "4",
299
+ "FLUENT_RETRY_INITIAL_DELAY_MS": "400",
300
+ "FLUENT_RETRY_MAX_DELAY_MS": "6000",
301
+ "FLUENT_RETRY_FACTOR": "2"
302
+ }
303
+ ```
304
+
305
+ ## 8) Safe extension workflow
306
+
307
+ When adding or changing a tool:
308
+
309
+ 1. update schema in `src/tools.ts`
310
+ 2. keep response envelopes consistent
311
+ 3. route API calls via `FluentClientAdapter`
312
+ 4. add unit tests
313
+ 5. run:
314
+ - `npm run build`
315
+ - `npm test`