@fluentcommerce/fluent-mcp-extn
v0.3.6
Published
[Experimental] MCP (Model Context Protocol) extension server for Fluent Commerce. Exposes event dispatch, transition actions, GraphQL execution, Prometheus metrics, batch ingestion, and webhook validation as MCP tools.
Downloads
1,014
Maintainers
Readme
@fluentcommerce/fluent-mcp-extn
[!CAUTION]
🧪 EXPERIMENTAL — LABS PROJECT
This package is NOT production-ready. It is an internal labs experiment under active development.
- No stability guarantees — APIs, tool names, schemas, and config may change or break between any release
- No support — this is not an officially supported Fluent Commerce product
- No warranty — provided as-is for experimentation and internal evaluation only
- Do NOT use in production without thorough review
Pin to an exact version (
@0.3.4) if you depend on current behavior.
MCP (Model Context Protocol) extension server for Fluent Commerce.
Exposes event dispatch, transition actions, GraphQL operations, Prometheus metrics queries, batch ingestion, webhook validation, entity lifecycle management, workflow management, settings management, environment discovery, and test automation as MCP tools — powered by @fluentcommerce/fc-connect-sdk.
What this does: This server runs as a background process inside your AI coding assistant (Claude Code, Cursor, VS Code Copilot, Windsurf, etc.). It gives the AI direct, authenticated access to Fluent Commerce APIs — so the AI can query orders, send events, inspect workflows, check metrics, and run diagnostics on your behalf, using natural language.
Already using
@fluentcommerce/ai-skills? You're already set up —ai-skills install --profileauto-configures this server in your.mcp.json. Skip to Verify connection or Tools (45) to see what's available.
Table of Contents
- Quick Start
- Why This Extension
- Tools (45)
- Configuration
- Error Handling
- Support Scripts
- Troubleshooting
- Development (Contributors)
- Companion Packages
- License
Why This Extension
The official fluent mcp server (bundled with Fluent CLI) covers core GraphQL and workflow operations. This extension adds capabilities typically needed for implementation and diagnostics:
| Capability | Official MCP | This Extension |
|---|:---:|:---:|
| Event dispatch (event.build / event.send / event.list / event.get) | | Yes |
| Event runtime forensics (event.flowInspect) | | Yes |
| Workflow transitions (workflow.transitions) | | Yes |
| Auto-paginated GraphQL (graphql.queryAll) | | Yes |
| Batch mutations (graphql.batchMutate) | | Yes |
| Batch ingestion (batch.*) | | Yes |
| Prometheus metrics (metrics.query) | | Yes |
| Metrics health assessment (metrics.healthCheck) | | Yes |
| Managed SLO snapshot (metrics.sloReport) | | Yes |
| Metric label discovery (metrics.labelCatalog) | | Yes |
| Event analytics rankings (metrics.topEvents) | | Yes |
| Webhook signature validation | | Yes |
| Schema introspection (graphql.introspect) | | Yes |
| Multi-strategy auth (profile, OAuth, token command, static token) | | Yes |
| Entity CRUD (entity.create / entity.update / entity.get) | | Yes |
| Workflow management (workflow.get / workflow.list / workflow.upload / workflow.diff / workflow.simulate) | | Yes |
| Settings management (setting.get / setting.upsert / setting.bulkUpsert) | | Yes |
| Environment snapshot (environment.discover / environment.validate) | | Yes |
| Test assertions with polling (test.assert) | | Yes |
Best practice: run both the official MCP server and this extension together.
Quick Start
Automated setup (recommended)
If you use @fluentcommerce/ai-skills, a single command installs skills AND configures this MCP server:
npx @fluentcommerce/ai-skills install --profile YOUR_PROFILE --profile-retailer YOUR_RETAILER_REFThis creates .mcp.json with fluent-mcp-extn pre-configured. Skip to Verify connection.
Manual setup
If you're using this server standalone (without ai-skills), add it to your project's .mcp.json.
| IDE | MCP config file |
|---|---|
| Claude Code | .mcp.json (workspace root) |
| Cursor | .mcp.json (workspace root) or .cursor/mcp.json |
| VS Code Copilot | .vscode/mcp.json |
| Windsurf | Workspace/app MCP settings |
1. Add MCP server entry
Pick one of the auth options below.
Option A: Fluent CLI Profile (recommended)
Reuses your existing Fluent CLI profile — no credentials in .mcp.json:
{
"mcpServers": {
"fluent-mcp-extn": {
"type": "stdio",
"command": "npx",
"args": ["@fluentcommerce/fluent-mcp-extn"],
"env": {
"FLUENT_PROFILE": "YOUR_PROFILE",
"FLUENT_PROFILE_RETAILER": "YOUR_RETAILER_REF"
}
}
}
}Use retailer ref in FLUENT_PROFILE_RETAILER (for example RETAILER_REF), not retailer ID.
Reads base URL, client ID/secret, username/password, and retailer ID from ~/.fluentcommerce/YOUR_PROFILE/. Requires Fluent CLI to be installed with at least one profile configured (fluent profile list).
Option B: Explicit OAuth credentials
Set credentials as shell environment variables (never in .mcp.json):
export FLUENT_CLIENT_ID=your-client-id
export FLUENT_CLIENT_SECRET=your-client-secret
export FLUENT_USERNAME=your-username
export FLUENT_PASSWORD=your-passwordThen in .mcp.json, only the non-sensitive connection details:
{
"mcpServers": {
"fluent-mcp-extn": {
"type": "stdio",
"command": "npx",
"args": ["@fluentcommerce/fluent-mcp-extn"],
"env": {
"FLUENT_BASE_URL": "https://YOUR_ACCOUNT.sandbox.api.fluentretail.com",
"FLUENT_RETAILER_ID": "YOUR_RETAILER_ID"
}
}
}
}The MCP server inherits all parent shell environment variables automatically.
Option C: Profile + overrides (hybrid)
Use a profile as the base, override specific values via env vars:
{
"mcpServers": {
"fluent-mcp-extn": {
"type": "stdio",
"command": "npx",
"args": ["@fluentcommerce/fluent-mcp-extn"],
"env": {
"FLUENT_PROFILE": "YOUR_PROFILE",
"FLUENT_PROFILE_RETAILER": "YOUR_RETAILER_REF",
"FLUENT_RETAILER_ID": "YOUR_RETAILER_ID"
}
}
}
}Any explicit FLUENT_* env var overrides the value from the profile. Setting FLUENT_BASE_URL or OAuth env vars disables createClientFromProfile and falls back to standard OAuth (profile values still used as defaults for unset vars).
Option D: Token command (vault / CI integration)
For CI pipelines or environments where credentials come from a vault or external process:
{
"mcpServers": {
"fluent-mcp-extn": {
"type": "stdio",
"command": "npx",
"args": ["@fluentcommerce/fluent-mcp-extn"],
"env": {
"FLUENT_BASE_URL": "https://YOUR_ACCOUNT.sandbox.api.fluentretail.com",
"FLUENT_RETAILER_ID": "YOUR_RETAILER_ID",
"TOKEN_COMMAND": "vault read -field=token secret/fluent/api",
"TOKEN_COMMAND_TIMEOUT_MS": "10000"
}
}
}
}The command must print a valid bearer token to stdout. Token is cached for 55 minutes before re-executing the command.
Option E: Static bearer token
For quick testing with a pre-obtained token:
{
"mcpServers": {
"fluent-mcp-extn": {
"type": "stdio",
"command": "npx",
"args": ["@fluentcommerce/fluent-mcp-extn"],
"env": {
"FLUENT_BASE_URL": "https://YOUR_ACCOUNT.sandbox.api.fluentretail.com",
"FLUENT_RETAILER_ID": "YOUR_RETAILER_ID",
"FLUENT_ACCESS_TOKEN": "YOUR_BEARER_TOKEN"
}
}
}
}No automatic refresh — the token will expire according to its original grant TTL.
Auth priority order
When multiple auth methods are configured, the first valid method wins:
- Profile —
FLUENT_PROFILEset → uses SDKcreateClientFromProfile - OAuth —
FLUENT_CLIENT_ID+FLUENT_CLIENT_SECRET→ SDK-native OAuth with automatic refresh - Token command —
TOKEN_COMMAND→ executes shell command, caches token for 55 min - Static token —
FLUENT_ACCESS_TOKEN→ no refresh, dev fallback only
2. Restart your IDE
Restart so the MCP client picks up the new server.
3. Verify connection
Run these tools in order to confirm everything works:
config.validate— should returnok: truehealth.ping— should returnok: trueconnection.test— should returnok: truewith your user/account details
If any returns ok: false, see Troubleshooting.
4. Try a real call
event.build → build a payload (no API call)
event.send with dryRun: true → validate without sending
event.send with dryRun: false → send for realRequirements
- Node.js 20+
- Fluent CLI installed when using profile auth (
FLUENT_PROFILE) - Fluent Commerce API credentials (see Configuration)
Install
From npm (recommended)
No install needed — npx runs it directly from the npm registry:
npx @fluentcommerce/fluent-mcp-extnThis starts the MCP stdio server process. In a plain terminal it appears idle because it is waiting for MCP JSON-RPC input from your IDE/agent.
Or install as a project dependency:
npm install @fluentcommerce/fluent-mcp-extnFrom source
git clone https://bitbucket.org/fluentcommerce/fluent-mcp-extn.git
cd fluent-mcp-extn
npm install && npm run buildThen use in .mcp.json:
{
"command": "node",
"args": ["path/to/fluent-mcp-extn/dist/index.js"]
}Configuration
All configuration is via environment variables in your .mcp.json env block. Never commit credentials to git.
Required
| Variable | Description |
|---|---|
| FLUENT_BASE_URL | Fluent Commerce API base URL |
Plus at least one auth method below.
Authentication (first valid method wins)
1. Fluent CLI profile (recommended for local development)
| Variable | Required | Description |
|---|---|---|
| FLUENT_PROFILE | Yes | Fluent CLI profile name (~/.fluentcommerce/<profile>) |
| FLUENT_PROFILE_RETAILER | No | Retailer ref (matches retailer.<ref>.json) |
| FLUENT_PROFILE_DIR | No | Override profile base directory (defaults to ~/.fluentcommerce) |
FLUENT_PROFILE_RETAILER allows retailer-scoped user credential overrides from profile files.
2. OAuth
| Variable | Required | Description |
|---|---|---|
| FLUENT_CLIENT_ID | Yes | OAuth client ID |
| FLUENT_CLIENT_SECRET | Yes | OAuth client secret |
| FLUENT_USERNAME | No | Username (for password grant) |
| FLUENT_PASSWORD | No | Password (for password grant) |
Security: These credentials must be set as shell environment variables, never in
.mcp.json. MCP server processes inherit all parent shell env vars automatically. Themcp-setupcommand strips any secrets found in.mcp.jsonduring re-runs.
3. Token command
| Variable | Default | Description |
|---|---|---|
| TOKEN_COMMAND | — | Shell command that prints a bearer token to stdout |
| TOKEN_COMMAND_TIMEOUT_MS | 10000 | Timeout for the command |
4. Static token
| Variable | Description |
|---|---|
| FLUENT_ACCESS_TOKEN | Pre-obtained bearer token |
Optional
| Variable | Default | Description |
|---|---|---|
| FLUENT_RETAILER_ID | — | Default retailer for events and batch operations |
| FLUENT_ACCOUNT_ID | — | Default account for events |
Resilience Tuning
| Variable | Default | Description |
|---|---|---|
| FLUENT_REQUEST_TIMEOUT_MS | 30000 | Request timeout |
| FLUENT_RETRY_ATTEMPTS | 3 | Retry attempts for read operations |
| FLUENT_RETRY_INITIAL_DELAY_MS | 300 | Initial backoff delay |
| FLUENT_RETRY_MAX_DELAY_MS | 5000 | Max backoff delay |
| FLUENT_RETRY_FACTOR | 2 | Backoff multiplier |
Response Shaping
Controls how large responses are handled before returning to the AI. When a response exceeds the budget, arrays are auto-summarized (not truncated) with record counts, field inventory, value distributions, and sample records — giving the AI a complete analytical picture instead of cut-off data.
| Variable | Default | Description |
|---|---|---|
| FLUENT_RESPONSE_BUDGET_CHARS | 50000 | Max serialized response size (~12.5k tokens). 0 disables (unlimited). |
| FLUENT_RESPONSE_MAX_ARRAY | 50 | Arrays exceeding this size are auto-summarized. Only active when budget > 0. |
| FLUENT_RESPONSE_SAMPLE_SIZE | 3 | Number of sample records included in array summaries. |
Cache
Filesystem-based cache for near-static read responses (schema introspection, workflows, settings, plugins). Enabled automatically when FLUENT_PROFILE is set.
| Variable | Default | Description |
|---|---|---|
| FLUENT_CACHE_ENABLED | true | Set to "false" to disable the disk cache entirely |
| FLUENT_CACHE_DIR | accounts/<PROFILE>/.cache | Override the cache directory |
| FLUENT_CACHE_TTL_WORKFLOW | 3600000 (1h) | Workflow cache TTL in ms |
| FLUENT_CACHE_TTL_SETTING | 3600000 (1h) | Setting cache TTL in ms |
| FLUENT_CACHE_TTL_INTROSPECT | 86400000 (24h) | Schema introspection cache TTL in ms |
| FLUENT_CACHE_TTL_PLUGIN | 3600000 (1h) | Plugin list cache TTL in ms |
Behavior:
- Per-profile isolation — each profile gets its own cache directory under
accounts/<PROFILE>/.cache - Cached tools:
graphql.introspect,plugin.list,workflow.get,workflow.list,setting.get - Write-through invalidation — write operations auto-invalidate related cache entries:
workflow.uploadclearsworkflow:*,setting.upsert/setting.bulkUpsertclears matchingsetting:get:*entries,graphql.introspectwithforce: trueclearsintrospect:* _cachemetadata — all cached tool responses include a_cachefield ({ hit, ageMs }on cache hit,{ hit: false, stored: true }on cache miss) so the AI can reason about data freshness- baseUrl fingerprint — cache auto-clears if the profile is re-pointed to a different environment, preventing cross-environment contamination
- Fail-open — cache errors (corrupt files, permission issues) become cache misses; the tool continues with a live API call
- Requires
FLUENT_PROFILE— no profile means no safe namespace, so caching is disabled
Tools (45)
Diagnostics
| Tool | Description |
|---|---|
| config.validate | Validate auth and base URL configuration |
| health.ping | Quick connectivity check |
| connection.test | Full auth + GraphQL end-to-end test (returns user/account context) |
Events
| Tool | Description |
|---|---|
| event.build | Build event payload without sending (validation only) |
| event.send | Build and send event (supports dryRun: true) |
| event.get | Fetch a single event by ID |
| event.list | List/filter events with pagination |
| event.flowInspect | One-call root-entity flow forensics — works for ORDER/FULFILMENT/LOCATION/WAVE/PRODUCT and more |
event.flowInspect supports any entity type. Pass rootEntityType when you want strict filtering; omit it to inspect by root ref only. Use rootEntityId when refs are reused and you need exact disambiguation.
Compact mode (default compact: true): Returns a pre-analyzed summary (~2-3k tokens) with an analysis section containing anomaly findings, status flow, failed webhook endpoints, and slowest rulesets. Set compact: false for full raw data (~24k tokens).
Default-on flags: compact, includeAudit, includeExceptions, includeNoMatchDetails, includeEventDetails, includeScheduled
Opt-in flags (default false):
includeRuleDetails— per-rule execution trace with class name, props, and timingincludeCustomLogs— custom plugin log messages (LogCollection)includeSnapshots— entity state snapshots at each processing pointincludeCrossEntity— child entity events (FULFILMENT_CHOICE, FULFILMENT)
Example — compact forensics (recommended first call):
{
"rootEntityRef": "ORD-001",
"rootEntityType": "ORDER"
}Example — full data with all sections:
{
"rootEntityRef": "ORD-001",
"rootEntityType": "ORDER",
"compact": false,
"includeRuleDetails": true,
"includeCustomLogs": true,
"includeSnapshots": true,
"includeCrossEntity": true
}Example — lightweight (minimal output):
{
"rootEntityRef": "ORD-001",
"rootEntityType": "ORDER",
"includeAudit": false,
"includeEventDetails": false,
"includeExceptions": false,
"includeNoMatchDetails": false,
"maxDrilldowns": 0
}Local-First LLM Reduction (flowInspect)
If event.flowInspect returns large JSON, run local analysis first and only send compact artifacts to an LLM:
npx tsx scripts/run-flow-inspect.ts <ROOT_ENTITY_REF> --profile <PROFILE>This writes:
EVENT_FLOW_INSPECT_<ref>.json(raw)EVENT_FLOW_INSPECT_<ref>.summary.json(local anomaly + metrics summary)EVENT_FLOW_INSPECT_<ref>.drilldown.json(focusedevent.getextraction for top evidence IDs)EVENT_FLOW_INSPECT_<ref>.llm-packet.md(small LLM handoff packet)
Useful flags:
--lightuses compact fetch mode for faster runs--root-type ...and--root-id ...tighten entity matching--drilldown/--no-drilldowntoggle focusedevent.getenrichment--drilldown-limitcontrols how many top evidence IDs get enriched--drilldown-classes webhook,mutation,sendEvent,mismatch,exception,scheduled,slow,statuslimits enrichment to selected evidence classes--top-n,--evidence-limit,--truncatecontrol summary/packet compactness--no-llm-packskips markdown packet output
Metrics
| Tool | Description |
|---|---|
| metrics.query | Query Prometheus metrics using instant or range mode |
| metrics.healthCheck | One-call anomaly check with Prometheus-first + Event API fallback |
| metrics.sloReport | Managed-services SLO snapshot (rates + p95 latency + findings) |
| metrics.labelCatalog | Discover supported metric labels from live series + known Fluent hints |
| metrics.topEvents | Aggregate and rank top events by name/entity/status in a time window |
Orchestration
| Tool | Description |
|---|---|
| workflow.transitions | Query available user actions/transitions for provided triggers (POST /api/v4.1/transition) |
| plugin.list | List all registered rules with metadata (GET /orchestration/rest/v1/plugin). Supports optional name filter. |
flexType auto-derive: When type and subtype are provided but flexType is omitted, it is auto-derived as TYPE::SUBTYPE. All three params (module, flexType, flexVersion) are required by the Transition API — omitting any one silently returns empty results.
Example — get actions for a ServicePoint manifest trigger:
{
"triggers": [
{
"type": "MANIFEST",
"subtype": "DEFAULT",
"status": "PENDING",
"module": "servicepoint",
"flexType": "CARRIER::DEFAULT",
"retailerId": "2"
}
]
}Example — auto-derive flexType from type + subtype:
{
"triggers": [
{
"type": "CREDIT_MEMO",
"subtype": "APPEASEMENT",
"status": "CREATED",
"module": "adminconsole",
"flexVersion": "1.0",
"retailerId": "2"
}
]
}Example — list all rules matching "SendEvent":
{
"name": "SendEvent"
}GraphQL
| Tool | Description |
|---|---|
| graphql.query | Execute any query or mutation |
| graphql.queryAll | Auto-paginated query — follows cursors across all pages |
| graphql.batchMutate | Execute up to 50 mutations in one request |
| graphql.introspect | Inspect schema types, mutations, and input fields |
Example — query orders:
{
"query": "{ orders(first: 5) { edges { cursor node { id ref status } } pageInfo { hasNextPage } } }"
}Example — auto-paginate all active orders:
{
"query": "{ orders(first: 100, after: $cursor) { edges { cursor node { id ref status } } pageInfo { hasNextPage } } }",
"variables": { "cursor": null },
"maxRecords": 5000
}Example — batch update 3 orders:
{
"mutation": "updateOrder",
"inputs": [
{ "id": "1", "status": "SHIPPED" },
{ "id": "2", "status": "SHIPPED" },
{ "id": "3", "status": "SHIPPED" }
],
"returnFields": ["id", "ref", "status"]
}Example — dry-run batch mutation (validates query without executing):
{
"mutation": "updateOrder",
"inputs": [{ "id": "1", "status": "SHIPPED" }],
"returnFields": ["id", "ref", "status"],
"dryRun": true
}With dryRun: true, returns the generated aliased mutation query and variables for review without making any API call. Use this to preview what will be sent before executing bulk operations.
Batch Ingestion
| Tool | Description |
|---|---|
| batch.create | Create an ingestion job |
| batch.send | Send records to a job |
| batch.status | Check job status |
| batch.batchStatus | Check a specific batch within a job |
| batch.results | Get per-record outcomes |
Typical flow: batch.create → batch.send → batch.status (poll) → batch.results
Webhook
| Tool | Description |
|---|---|
| webhook.validate | Validate payload fields and optionally verify cryptographic signature |
Entity Lifecycle
| Tool | Description |
|---|---|
| entity.create | Type-safe entity creation with field validation, compound key encoding, and retailer auto-injection. Supports 12 entity types. |
| entity.update | Status-aware entity updates with optional transition validation via workflow.transitions |
| entity.get | Unified entity lookup by ID or ref with optional edge inclusion |
Supported types: ORDER, FULFILMENT, LOCATION, NETWORK, CUSTOMER, PRODUCT, INVENTORY_POSITION, VIRTUAL_CATALOGUE, VIRTUAL_POSITION, CATEGORY, CARRIER, SETTING
Example — create a location:
{
"entityType": "LOCATION",
"data": {
"ref": "LOC_WH_01",
"type": "WAREHOUSE",
"name": "Main Warehouse",
"openingSchedule": { "allHours": true }
},
"dryRun": true
}Workflow Management
| Tool | Description |
|---|---|
| workflow.get | Fetch a specific workflow by entity type and subtype via REST API. Works even when the list endpoint returns 401. |
| workflow.list | List all workflows for a retailer. Deduplicates to latest version per workflow name. |
| workflow.upload | Deploy workflow JSON via REST API with structure validation. For production, prefer fluent module install via CLI. |
| workflow.diff | Compare two workflow definitions — returns added/removed/modified rulesets with risk assessment. Supports summary, detailed, and mermaid formats. |
| workflow.simulate | Static analysis prediction of which rulesets would fire for a given status + event name. Does NOT execute Java rules or check runtime state — use workflow.transitions for authoritative live validation. |
Example — fetch a workflow and save to file:
{
"entityType": "ORDER",
"entitySubtype": "HD",
"retailerId": "2",
"outputFile": "accounts/MYPROFILE/workflows/MyRetailer/ORDER-HD.json"
}When outputFile is set, the full workflow JSON is saved to disk and only a summary is returned (status count, ruleset count, total rules). This reads from the live server via REST API — not the CLI workflowlog cache.
Example — list all workflows and download to directory:
{
"retailerId": "2",
"outputDir": "accounts/MYPROFILE/workflows/MyRetailer/"
}With outputDir, each workflow is saved as {TYPE}-{SUBTYPE}.json (e.g., ORDER-HD.json). The response lists saved files with paths and sizes. Without outputDir, returns metadata only (name, version, status count per workflow).
Settings Management
| Tool | Description |
|---|---|
| setting.get | Fetch settings by name (% wildcards supported), optionally save to local file to keep large JSON out of LLM context |
| setting.upsert | Create or update a setting with upsert semantics — queries existing by name + context + contextId first |
| setting.bulkUpsert | Batch create/update up to 50 settings with per-setting error handling |
Contexts: RETAILER, ACCOUNT, LOCATION, NETWORK, AGENT, CUSTOMER
Example — fetch a manifest setting and save to file (keeps large JSON out of LLM context):
{
"name": "fc.mystique.manifest.oms",
"context": "ACCOUNT",
"contextId": 0,
"outputFile": "accounts/MYPROFILE/manifests/backups/fc.mystique.manifest.oms.json"
}When outputFile is set, the response returns metadata only (name, context, valueType, sizeBytes, savedTo path) — the full JSON goes to disk. For multiple matches (e.g., name: "fc.mystique.manifest.%"), each setting is saved as a separate file in the outputFile directory.
Example — create/update a manifest setting with explicit valueType:
{
"name": "fc.mystique.manifest.oms.fragment.custom",
"context": "ACCOUNT",
"contextId": 0,
"valueType": "JSON",
"lobValue": "{\"manifestVersion\":\"2.0\",\"routes\":[]}"
}Provide either value (for small strings ≤255 chars) or lobValue (for large JSON payloads, as a JSON string). The valueType parameter accepts "STRING", "LOB", or "JSON". For Mystique manifest settings, always use valueType: "JSON" — the default LOB breaks manifest parsing. A warning is emitted if a fc.mystique.manifest.* setting is created without valueType: "JSON".
Environment
| Tool | Description |
|---|---|
| environment.discover | Full environment snapshot — retailer, locations, networks, catalogues, workflows, settings, modules, users. Each section is opt-in via include array. |
| environment.validate | Pre-flight validation checks: auth, retailer, locations, inventory, workflows, settings, modules |
Test Automation
| Tool | Description |
|---|---|
| test.assert | Assert entity state matches expectations. Supports status, type, attribute, and edge assertions. Optional polling mode retries until pass or timeout. |
Example — assert an order reached BOOKED with at least 1 fulfilment:
{
"entityType": "ORDER",
"ref": "HD-001",
"assertions": {
"status": "BOOKED",
"edges": { "fulfilments": { "minCount": 1 } }
},
"poll": true,
"timeoutMs": 60000
}Cache
| Tool | Description |
|---|---|
| cache.status | Show local cache statistics — entry count, size, hit/miss rate, per-category breakdown. No API call. |
| cache.clear | Clear cached entries by pattern (e.g. workflow:*) or all. No API call, operates on local filesystem only. |
See Cache configuration for env vars, TTLs, and behavior details. Write operations auto-invalidate related cache entries, so manual clearing is only needed after out-of-band changes (CLI deployments, REST API calls, admin console edits).
| Pattern | Clears |
|---|---|
| workflow:* | All cached workflow list/get responses |
| setting:get:fc.mystique.* | Cached manifest and setting lookups |
| introspect:* | GraphQL schema introspection cache |
| plugin:list | Cached plugin metadata |
| (omit pattern) | Everything |
Example — check cache health:
{}Returns enabled, directory, entries, totalBytes, per-categories breakdown, and session hits/misses.
Example — clear workflow cache after a CLI deploy:
{
"pattern": "workflow:*"
}Error Handling
All tools return a consistent envelope:
Success:
{
"ok": true,
"response": { }
}Failure:
{
"ok": false,
"error": {
"code": "AUTH_ERROR",
"message": "OAuth token request failed.",
"retryable": false,
"details": {}
}
}| Error Code | Meaning | Retryable |
|---|---|---|
| CONFIG_ERROR | Missing or invalid environment variables | No |
| AUTH_ERROR | Authentication failed | No |
| VALIDATION_ERROR | Invalid tool arguments | No |
| TIMEOUT_ERROR | Request timed out | Yes |
| RATE_LIMIT | API rate limit hit | Yes |
| UPSTREAM_UNAVAILABLE | Fluent API unreachable | Yes |
| NETWORK_ERROR | Network connectivity issue | Yes |
| SDK_ERROR | Unexpected SDK error | Varies |
| UNKNOWN_ERROR | Unclassified error | No |
Retry Behavior
Read operations (queries, list, get) use execute() which retries on transient failures (timeout, rate limit, network errors) with exponential backoff up to FLUENT_RETRY_ATTEMPTS times. Write operations (create, update, send, upload, upsert) use executeOnce() with no automatic retry to prevent duplicate side effects. Tune retry parameters via the Resilience Tuning env vars above.
Support Scripts (Debugging and Validation)
These scripts are useful during tenant validation, support, and failure triage:
# Positive smoke test
npm run e2e:smoke -- --profile YOUR_PROFILE --retailer YOUR_RETAILER_REF_OR_ID
# Interactive smoke setup
npm run e2e:smoke -- --wizard
# Negative-path validation (bad payloads, schema failures, error envelopes)
npx tsx scripts/e2e-negative.ts --profile YOUR_PROFILE --retailer YOUR_RETAILER_REF_OR_ID
# Check status of specific events and filtered event lists
npx tsx scripts/check-event-status.ts --profile YOUR_PROFILE --retailer YOUR_RETAILER_REF_OR_ID --event-id <EVENT_ID>Recommended operator flow:
- Run positive smoke (
e2e:smoke). - Run negative validation (
e2e-negative.ts) to verify expected error handling. - Use
check-event-status.tsto trace real event outcomes when diagnosing failures.
Troubleshooting
| Symptom | Likely Cause | Fix |
|---|---|---|
| config.validate fails | Missing or invalid env vars | Check FLUENT_BASE_URL and at least one complete auth method |
| FLUENT_PROFILE auth fails | Profile/retailer ref mismatch or missing files | Verify fluent profile list, profile name, and FLUENT_PROFILE_RETAILER ref |
| AUTH_ERROR on any tool | Bad credentials or expired token | Verify OAuth values or regenerate token |
| connection.test fails | Network or URL mismatch | Verify API URL, check VPN/proxy, confirm tenant is reachable |
| event.send succeeds but workflow doesn't trigger | Event name not mapped in workflow | Check workflow event handlers and ruleset conditions |
| Server doesn't appear in MCP client | Config not reloaded | Restart IDE/client after editing .mcp.json |
| Events sent to wrong tenant | Wrong FLUENT_BASE_URL | Confirm the API URL and retailer ID |
| RATE_LIMIT errors | Too many requests | Reduce request frequency; retryable errors auto-retry up to FLUENT_RETRY_ATTEMPTS |
Development (Contributors)
Using these tools in a development workflow
For a step-by-step guide on using MCP tools to scaffold rules, build modules, fire events, assert state transitions, and debug failures, see docs/DEV_WORKFLOW.md in the @fluentcommerce/ai-skills package.
Workspace layout
When used alongside @fluentcommerce/ai-skills, this server integrates with a workspace convention for managing source code, workflows, and analysis artifacts:
accounts/
<PROFILE>/
SOURCE/ # custom source code (account-level, shared across retailers)
backend/ # Java Maven plugin repos and JAR files
frontend/ # Mystique SDK component projects
workflows/ # downloaded workflow JSONs (scoped by retailer)
analysis/ # generated analysis artifactsSkills use this server's tools (plugin.list, graphql.query, connection.test, etc.) to:
- Build a deployed rule inventory by cross-referencing live registered rules with local source
- Validate connectivity during guided onboarding (
/fluent-connect) - Run entity count discovery queries during workspace setup
- Power end-to-end test flows with event dispatch and state assertions
See the Getting Started section in @fluentcommerce/ai-skills for the full directory layout and guided onboarding.
Contributing to this package
git clone https://bitbucket.org/fluentcommerce/fluent-mcp-extn.git
cd fluent-mcp-extn
npm install && npm run build && npm test # ~378 unit tests
npm run dev # hot-reload via tsxPublish checklist:
- Bump version in
package.json npm run build && npm testnpm run e2e:smoke -- --profile <PROFILE> --retailer <RETAILER>(requires live API)npm pack— inspect contentsnpm publish --access public- Post-publish: start via MCP client, run
config.validate,health.ping,connection.test
prepublishOnlyenforcesbuild && testautomatically. Keep credentials out of.mcp.jsonand docs.
Companion Packages
| Package | Purpose |
|---|---|
| @fluentcommerce/ai-skills | Install Fluent domain skills across AI coding assistants |
| Fluent CLI (@fluentcommerce/cli) | Official CLI and built-in MCP server |
