FCHubFCHub.co

Changelog

Every version, every fix, every new tool. The full paper trail.

What I changed, when, and why you should care.


July 2026

v2.2.0

npm · Latest release

Connected MCP tools, resources, prompts, clients, and transports orbiting one protocol artefact

MCP TypeScript SDK v2 is here. I upgraded the server, the wire, and every piece of evidence that stops “works on my machine” from becoming a release strategy.

  • SDK v2, properly — I pinned every official TypeScript SDK package to 2.0.0 and added a live registry gate that fails when “latest” moves. Dependency drift has lost its improv licence.
  • Two protocol eras, one server — I give modern clients the 2026 protocol, server/discover, cache hints, and the complete wire contract; I keep a deliberate compatibility path for existing 2025 clients instead of launching them into the sun for dramatic effect.
  • Evidence from real handshakes — I made client certification record the protocol actually negotiated over HTTP and STDIO. I verify the exact candidate through Inspector, Claude Code, Docker, proxy, archive, and soak lanes rather than testing a suspiciously similar cousin.
  • The v1 ghosts are gone — I removed stale helpers and active leftovers, then added a scanner so they cannot wander back in wearing a new filename.

I passed the official conformance suite across both supported protocol versions, then ran a six-minute candidate soak without errors, leaks, or interpretive networking. New protocol. Same store. Considerably less wishful thinking.

v2.1.0

npm · Latest release

I added FluentCart 1.6+ subscription support, minus the traditional rush to wire every shiny endpoint to a chat box and call it innovation.

Renewals are first-class reads

I added fluentcart_renewal_list and fluentcart_renewal_get so an assistant can list renewal records and open one renewal in detail. I also retained the useful FluentCart 1.6 context in the subscription projection, including collection method and pending-skip state when the store returns it.

Subscription detail changes are guarded

I added a narrowly reviewed bill_times update to reversible mode for changing a subscription's total billing-cycle limit. I check fresh bill_times and bill_count as a best-effort preflight, reject an already stale or end-of-term change, and read the record back before reporting success. FluentCart 1.6 has no atomic version precondition, so an ambiguous failure says the mutation may have applied and requires a fresh read instead of a blind retry. I allow this only for store-billed manual or system subscriptions; I fail closed before writing to gateway-billed automatic subscriptions. I also fail closed when a subscription has linked FluentCart Pro licences because the upstream update event can change licence state. I did not build a back door to billing control: charges, renewal creation, skipping, voiding, resending, transaction synchronisation, refunds, and subscription cancellation remain absent.

I left pause, resume, and reactivate absent too. FluentCart 1.6 can change scheduled charges and related renewal state through those lifecycle routes, and I cannot prove a supported restoration. An endpoint existing is not the same thing as an undo button. Remarkable, but useful.

I also removed fluentcart_subscription_fetch. I previously classed it as a read, but FluentCart 1.6 uses it to resynchronise with the payment gateway and can mutate local subscription state. I am leaving that in the admin, not behind a deceptively calm tool description.

I also made the generic store-settings write reject subscription_management_mode and subscription_system_charge. They are store-wide billing controls, so I require a dedicated guard instead of letting them slip through a generic settings form in a fake moustache.

FluentCart 1.6 compatibility refresh

I verified 2.1.0 with WordPress 7.0.2, FluentCart Core 1.6.0, and FluentCart Pro 1.6.0. “FluentCart 1.6+” identifies the compatibility work in this release; I am not claiming that I tested every future FluentCart version. I also removed the legacy tax-country delete operation from route discovery: it was a nonfunctional ghost route, not a missing feature to mourn.


v2.0.1

npm · Latest release

I made this the client-first release. Pick the app you already use, follow its exact recipe, and verify one store read. Revolutionary stuff, assuming one ignores the decade software spent making setup pages start with architecture diagrams.

Eight clear connection paths

I put ChatGPT Desktop, Codex CLI, Codex IDE extension, Claude Desktop, Cursor, VS Code with GitHub Copilot, Windsurf, and ChatGPT web together in one chooser. I gave each its current configuration surface and a useful verification step.

Claude Desktop supplies Node

I stopped asking Claude Desktop users to install Node.js for the MCPB extension. Claude Desktop supplies the runtime; I package FluentCart MCP's JavaScript and production dependencies, not a secret Node executable wearing a trench coat.

No global npm install

I corrected the local recipes: npx -y fluentcart-mcp downloads the package on demand and reuses the package-manager cache. I do not install FluentCart MCP globally.

OpenAI desktop and web are no longer muddled together

I documented that ChatGPT Desktop shares ~/.codex/config.toml with Codex CLI and the Codex IDE extension, with Settings → MCP servers → Add server as the shortest route. ChatGPT web uses OpenAI Secure MCP Tunnel, separate Platform and Developer mode permissions, and an outbound-only private connection. I no longer pass the FluentCart HTTP bearer key off as ChatGPT authentication.

The public ChatGPT Plugins Directory still requires FluentCart authorisation. A patch release may improve onboarding; I cannot acquire somebody else's trademark permission by sheer optimism.


v2.0.0

npm · Latest release

I made this a breaking release, and unapologetically so. Version 1.x handed an AI assistant the whole store on connection and trusted everyone involved to be careful. I started 2.0.0 from the opposite assumption.

Upgrading from 1.x will change what your AI can do

Writes are off unless you switch them on, the default mode presents three compact read tools instead of the entire catalogue, and refunds, cancellations, deletions and bulk actions are not exposed at all. Enabling reversible writes adds one executor. If your workflow depended on removed actions, it will stop working.

Writes are absent by default

I added FLUENTCART_WRITE_MODE and made it default to disabled. Its values are disabled and reversible.

I filter before registration, not at call time, which is the part that matters: a tool your policy excludes cannot be listed, searched, described or invoked by name. I left no "the model found it anyway" path, because there is nothing to find.

I use disabled to expose reads. I use reversible to add work that can be undone — creating and updating products, variants, coupons, customers, shipping rules, tax rules, attributes, order bumps and upgrade paths.

I make deletion, bulk operations, order status changes, marking an order paid, and dispute handling unavailable in every mode. FluentCart provides no supported way to reverse any of them, so I do not classify any as a reversible write. I made this narrower than 1.x on purpose.

Refunding and cancellation are not available

I did not ship fluentcart_order_refund or fluentcart_subscription_cancel as product tools in 2.0.0. I provide no write mode or environment variable that enables them. Use FluentCart's admin or official operator tooling for those jobs.

Modes: static is gone, dynamic is the default

I renamed what 1.x called static to full. I offer dynamic, curated, code, and full, and I give you dynamic when you say nothing.

  • dynamic — three read tools: fluentcart_search_tools, fluentcart_describe_tools, and fluentcart_execute_read_tool. Reversible mode adds fluentcart_execute_reversible_write.
  • code — two tools over a QuickJS WebAssembly sandbox, fluentcart_search_api and fluentcart_execute_code. Read-only by construction: the sandbox has no route to a write.
  • curated — a shortlist for the workflows people actually run.
  • full — everything exposed, registered up front, exactly as static used to behave.

I now enforce definition-token budgets rather than merely reporting them: 1,500 for dynamic, 1,200 for code, and 12,000 for curated. I measure full mode on every build but never gate it, because gating it would be gating the thing it exists to provide. I generate the figures for each revision with node scripts/measure-tool-context.mjs, serialise them with mcp-tools-list-v1, count them with gpt-tokenizer@3.4.0, and record them in release-contract.json.

HTTP is loopback-first

I bind the HTTP transport to 127.0.0.1 by default. I refuse a non-loopback bind without FLUENTCART_MCP_API_KEY of at least 32 characters, and I run the check before listen() so a misconfigured deployment fails immediately instead of quietly serving a store-administration API to the internet.

I return exactly {"error":"Unauthorized"} for every authentication rejection and use a constant-time comparison behind it. I make a wrong key indistinguishable from a missing one.

The 1.x documentation warned that without a key "anyone who discovers your endpoint can query your store". I made that untrue and removed the warning instead of leaving it there to look prudent.

Oversized responses fail loudly

I now return a RESPONSE_TOO_LARGE error when a response exceeds the budget and name the remedies: narrow the page size, date range, or field list. I previously returned a truncated payload marked _truncated, which is a polite way of describing data that looks complete and isn't.

Least-privilege roles are supported

I make the server do what the configured WordPress user can do, and nothing more. I corrected the old advice to hand over a full admin login: I support a narrow FluentCart role, and I recommend pairing one with the default read-only write mode.

Support profile

I verified this release against WordPress 7.0.2 with FluentCart 1.5.5 and FluentCart Pro 1.5.4.

I also captured the route surface of an older 1.3.9 install from a real runtime, but support is not claimed by that route evidence. It records which endpoints the build serves; I do not claim that these tools work against it, and I do not claim support until a tool-level compatibility check passes. I treat a smaller tool list on an older store as evidence that route pruning works, not that I exercised the surviving tools there.

Also

  • I no longer expose subscription pause, resume, or reactivate as tools.
  • I no longer include the customer address dropdown helper or the duplicate address-add tool.
  • I make MCP Resources read through to your store on every read; I keep no resource-layer cache, and I no longer imply otherwise in the documentation.
  • I generate published counts from the release contract instead of retyping one number across six files, which is how I let them drift in the first place.

March 2026

v1.1.0

Released 4 March 2026npm · GitHub Release

I made this the "full audit" release. I tested every tool against live FluentCart 1.3.13, read the backend PHP source line by line, and hunted down every schema, response shape, and undocumented quirk. I shipped 41 bug fixes and 30 quality improvements, and filed 14 new upstream issues. I dropped the tool count from 279 to 274 because five backend endpoints are genuinely broken with no workaround.

274 total tools (was 279).

What changed

Response transforms — I made list endpoints return trimmed payloads. I added product_type and fulfillment_type to product_list, and purchase_value, ltv, and purchase_count to customer_list. I strip subscription bloat with transformSubscription() and trim variants to essential fields with trimVariant().

Fetch-merge pattern — I made write tools fetch current state, merge your changes, and send the complete object instead of silently nuking unspecified fields. I applied the pattern to coupon_update, customer_update, variant_update, product_update_detail, and settings_save_store.

Cache invalidation — I made write tools declare which cache keys to invalidate through invalidates in the factory. I wired 17 write tools across tax classes, tax settings, shipping zones, shipping classes, and roles. No more stale cached data after mutations.

Schema corrections from PHP source — I changed bundle_save from the wrong bundle_items to bundle_child_ids. I corrected the invalid pricing_update enum values to simple_variations and advanced_variations. I also added the missing action: 'euCrossBorderSettings' discriminator and eu_vat_settings wrapper to tax_eu_vat_save.

Timing-safe auth — I replaced HTTP Bearer token string equality with crypto.timingSafeEqual.

Bug fixes (41)

AreaFix
Couponscoupon_update rewritten with fetch-merge pattern
Couponscoupon_list response transform added (trim to essential fields)
Couponscoupon_apply/coupon_cancel converted to createTool with correct field names
Couponscoupon_settings_save specific field schema added
Customerscustomer_list transform includes purchase analytics fields
Customerscustomer_update rewritten with fetch-merge pattern
Customerscustomer_bulk_action enum restricted to delete_customers
Customerscustomer_update_additional_info now handles label sync correctly
Subscriptionssubscription_list now supports active_view filter
SubscriptionsResponse transforms strip bloat from subscription data
Productsproduct_list transform includes product_type and fulfillment_type
Productsproduct_bulk_action enum restricted to valid actions
Productsproduct_update_detail rewritten with fetch-merge pattern
Productsproduct_fetch_by_ids array serialisation fixed
Productsvariant_create title marked as required
Productsvariant_update warning added about subscription field re-specification
ProductsbuildVariantFromExisting now spreads other_info instead of mutating input
Productsbundle_save field name corrected to bundle_child_ids
Productspricing_update enum values corrected to match backend constants
ProductsUpgrade path schemas corrected
Productsintegration_save integration field schema added
Productsfeed_status field renamed to notification_id
Productsterms_by_parent annotations corrected (readOnly + idempotent)
Taxtax_eu_vat_save rewritten as createTool with correct payload structure
TaxCache invalidation wired to tax write tools
Integrationsintegration_change_feed_status enum added
Integrationsintegration_get_feed_settings required fields added
Integrationsintegration_save_feed_settings required fields + integration field added
Settingssettings_save_store rewritten to flat key-value structure
ShippingCache invalidation wired to all shipping write tools
RolesCapability guards and FluentCart Pro requirement notes added
Rolesrole_get WARNING (empty backend), role_update WARNING (no-op)
Filesfile_upload WARNING (multipart-only, JSON not supported)
Filesfile_bucket_list driver field marked required with warning
Emailemail_template_preview param renamed to match backend
Emailemail_list format note added
Ordersorder_sync_statuses warning added
Ordersorder_transaction_update_status warning added
OrdersOrder bump tools get capability guards
ReportsDuplicate report clarifications added
Publicpublic_user_login HTTPS security warning added

Infrastructure improvements (30 P2 fixes)

  • I refactored truncateResponse with a sliceToFit helper and a while-loop safety cap for high-variance arrays.
  • I made server.ts import DYNAMIC_TOOL_COUNT instead of hardcoding 3.
  • I extracted parseSuccessBody from request() to reduce cognitive complexity.
  • I extracted executeStatusOperations from the order status handler.
  • I updated the Biome config to exclude test utility scripts from linting.
  • I removed 22 stale debug and scenario test files: 6,813 lines of archaeology.

Upstream FluentCart bugs filed

14 new issues filed on fluent-cart/fluent-cart (issues #22–#35):

IssueBug
#22revenue-by-group and fetch-order-by-group crash with SQL syntax error for all groupKey values
#23POST /coupons returns full WordPress HTML page instead of JSON
#24Customer address API — three endpoint inconsistencies
#25Subscription pause, resume, and reactivate return 'Not available yet'
#26Role get and update methods have empty bodies — endpoints are no-ops
#27Coupon apply expects 'coupon_code' — inconsistent with every other coupon endpoint
#28File upload endpoint requires multipart only — no JSON-based upload option
#29Customer bulk action only supports delete — no status updates
#30Email template preview crashes — undocumented 'template' parameter required
#31Transaction status update accepts any value — no server-side validation
#32Coupon cancel crashes with null dereference when no coupons applied
#33EU VAT settings endpoint requires undocumented action discriminator
#34File bucket-list throws 'Invalid driver' — unclear which driver values are accepted
#35Coupon re-apply and checkProductEligibility are checkout-only but registered as admin REST routes

Previously filed (v1.0.1): #9#15, #17#21

v1.0.1

Released 3 March 2026npm · GitHub Release

I made this the "I actually tested it against a real store" release. I fixed everything v1.0.0 got wrong with product tools. I tested every tool live against FluentCart 1.3.13, hunted down the ones that failed, found their root causes, and either fixed them or filed upstream bugs.

New tools (3)

ToolWhat it does
fluentcart_product_editor_mode_updateSwitch product long description between wp-editor and block-editor
fluentcart_product_create_dummyGenerate test products for development
fluentcart_product_variant_option_updateConfigure attribute combinations for advanced_variations products

279 total tools (was 276).

Subscription pricing support

I closed the big feature gap in v1.0.0: you could read subscription data but could not write it. I added the full subscription billing schema to product_pricing_update, variant_create, and variant_update:

  • payment_typeonetime or subscription
  • repeat_intervaldaily, weekly, monthly, quarterly, half_yearly, yearly
  • times — billing cycle count (0 = unlimited)
  • trial_days — trial period before first charge
  • manage_setup_fee / signup_fee / signup_fee_name — one-time setup fees
  • compare_price — strike-through price
  • item_statusactive / inactive per variant
  • variation_typesimple / variable / subscription on pricing update

Bug fixes

Price corruption — The centrepiece disaster of v1.0.0. I sent values that were already in cents to an API that expects currency units and multiplies by 100 internally. A 400 PLN product became 40,000 PLN. I now send currency units from every write tool and document cents on every read tool.

Cascading variant corruption — I made product_pricing_update fetch the full product state, convert existing variant prices from cents back to currency units, and merge your changes before sending. It no longer silently nukes every variant because you changed a product title.

product_create nested schema — I flattened detail: { fulfillment_type } to fulfillment_type at schema level and moved the nesting into the handler, because MCP hosts turned the original shape into unusable parameters.

variant_list always 500 — I now send explicit page and per_page values because FluentCart's ProductVariationController::index() crashes when query parameters are null.

variant_create and variant_update broken — I rewrote both with proper createTool handlers after MCP flattening exposed schema and handler mismatches. I also made variant_update fetch-then-merge so it does not destroy fields you did not touch.

variant_fetch_by_ids empty results — I fixed incorrect array-parameter serialisation.

product_fetch_by_ids empty results — I fixed the same issue there too. Variety is overrated.

product_taxonomy_sync wrong param name — I changed term_ids to FluentCart's expected terms. One letter away from working.

product_taxonomy_delete wrong param type — I replaced the term_ids array with the single term integer expected by FluentCart's deleteTaxonomyTermFromProduct().

attribute_group_update fails without slug — I now fetch the current group to retain its slug when you do not provide one, because FluentCart requires slug even for title-only changes.

product_list filter_type param removed — I removed the misleading filter_type parameter; it controls FluentCart's internal filter mode, not product type. I documented all valid active_view values instead: publish, draft, subscribable, not_subscribable, physical, digital, bundle, and non_bundle.

post_content stripped from product GET — I stopped removing long descriptions. I now strip only integrations and pricing_table.

Upstream FluentCart bugs filed

Confirmed against FluentCart 1.3.13, filed on fluent-cart/fluent-cart:

IssueBug
#14Product duplication fails when variant SKU is empty string (unique constraint violation)
#15AttrTermResource::create() validates group_id against wrong table (fct_atts_terms instead of fct_atts_groups)

Previously filed (v1.0.0): #9 pricing-table only updates description, #10 fetchVariationsByIds crashes, #11 GET /products/variants null params, #12 no lightweight product update endpoint, #13 price unit asymmetry

v1.0.0

Released 3 March 2026npm · GitHub Release

I made this the stable release and took the surface from 200 tools to 276. I added Docker support, HTTP transport, a Claude Desktop extension, caching, prompts, resources, dynamic mode—the works.

New tool modules (5)

ModuleToolsWhat
Shipping15Zones, methods, classes — full CRUD with zone reordering
Tax22Classes, rates, EU VAT, country tax IDs, shipping overrides, records
Email Notifications8Templates, shortcodes, previews, global settings
Roles7Role CRUD, user lists, permission management
Files4Upload, list, delete, bucket management

New tools in existing modules

ModuleNew toolsHighlights
Reports (core)+10Country heatmap, cart analysis, order value distribution, day/hour patterns, completion time, weeks-between-refund
Reports (insights)+7License charts, retention analysis, subscription cohorts, retention snapshots
Settings+7Module management, confirmation pages, payment method ordering, print templates

Features

Docker support — I added a multi-stage Node 22 Alpine build and published it to Docker Hub (vcodesh/fluentcart-mcp) and GHCR, with a one-line deployment for remote servers and ChatGPT integration.

HTTP transport — I made --transport http start an Express server with /mcp (SSE) and /health endpoints, plus optional Bearer token authentication through FLUENTCART_MCP_API_KEY. I kept it stateless, so session affinity can remain somebody else's hobby.

Dynamic toolset mode — I made --mode dynamic register 3 meta-tools instead of 276. The AI searches, discovers, and executes tools on demand, dropping the initial tool list from roughly 30K tokens to 1.5K for MCP hosts with tool-count limits.

In-memory TTL cache — I added three tiers: SHORT (2 minutes), MEDIUM (10 minutes), and LONG (1 hour). I apply them to stable reference data so the AI does not repeat API calls when it asks the same question twice in one conversation.

MCP Prompts — I added 5 workflow prompts that structure common tasks: analyze-store-performance, investigate-order, customer-overview, catalog-summary, subscription-health

MCP Resources — I added 4 read-only resources for store config, countries, payment methods, and filter options through resource:// URIs.

Claude Desktop Extension — I attached an .mcpb bundle to every GitHub Release. Download, double-click, enter credentials. No Node.js, terminal, or JSON.

Interactive setup wizard — I made npx fluentcart-mcp setup walk through URL, username, and Application Password with live connection testing and automatic retry.

Response size limits — I capped responses at 80,000 characters with intelligent array slicing. No more MCP protocol overflows on large product catalogues.

Request tracing — I added an X-Request-Id UUID header to every API call.

Structured logging — I added MCP-native logging with debug, info, warn, and error levels.

Bug fixes and schema corrections

FixModule
Report date range params used bracket notation (params[startDate]) — changed to flat startDateReports
Coupon create used wrong field names (nametitle, valueamount, usage_limitconditions.max_uses)Coupons
Customer address had first_name/last_name — changed to name (full name, required)Customers
Customer and order sort params used order_by/order_type — changed to sort_by/sort_typeCustomers, Orders
Label create used value — changed to titleLabels
Generic Error thrown for all API failures — now typed FluentCartApiError with machine-readable codesClient

Response transforms

I made list and detail endpoints return slimmer responses to stay within context windows:

  • product_list — ID, title, status, slug, date only
  • product_get — strips integrations and variant pricing_table
  • order_get — strips activities, post_content, transaction meta
  • customer_list — core fields only (id, name, email, status, spend)
  • customer_get — replaces full address array with address_count
  • app_init — strips trans (translation strings)

Breaking changes from v0.9.0

If you built anything against v0.9.0 (you probably didn't — it was out for 12 hours):

  • Coupon, customer address, label, and report tool schemas changed significantly
  • fluentcart_variant_update now requires product_id alongside variant_id
  • Sort parameters standardised to sort_by/sort_type across all listing tools
  • structuredContent removed from tool response type

v0.9.0

Released 2 March 2026 — Feature-complete pre-release.

I shipped 200 tools across 22 modules: the first version that actually did things. I covered everything from orders and subscriptions to product management and reports. I supported STDIO only, with no Docker, caching, resources, or prompts.

I included orders, order transactions, customers, coupons, subscriptions, products, product options, integrations, reports, settings, order bumps, activity, application, dashboard, labels, notes, miscellaneous, and public modules.

I wired the CI pipeline for typecheck, lint, test, build, smoke test, npm publishing, and GitHub Release.

v0.1.0

Released 2 March 2026 — I shipped the initial package structure, CLI skeleton, API client, and tool factory with zero functional tools. I left it on npm for approximately two hours before v0.9.0 replaced it. A distinguished career.

On this page