All notable changes to mcp-creatio are documented here. The format follows Keep a Changelog, and the project adheres to Semantic Versioning.
Credential flexibility and multi-tenant hardening: gateway/delegated now accept a forwarded
Creatio session cookie (not just a Bearer), and the schema caches are shared, per-tenant, bounded,
and stampede-safe. 608 tests; live-verified on two Creatio instances (both CRUD backends, cookie
passthrough, and dynamic-tool discovery).
- Cookie / multi-shape credential passthrough (
delegated&gateway) — a client or Control-Plane that holds a Creatio Forms-auth session (cookie +BPMCSRF) instead of an OAuth Bearer can now connect by forwarding it inX-Creatio-Cookie(BPMCSRF read from the cookie, or an explicitX-Creatio-Bpmcsrfheader). The per-request credential is a typedInjectedCredential(bearer | cookie); the stateless passthrough provider attachesAuthorization: BearerorCookie+BPMCSRF+ForceUseSession— no cookie jar, no per-credential pool.Authorizationtakes precedence when both are present.
- Shared
VersionedTtlCachefor schema caches — OData$metadata/ entity-sets and DataService runtime schemas now use one version + TTL + LRU cache, keyed per base URL. Fixes a multi-tenant$metadatare-fetch thrash on every interleaved tenant switch (the OData store was single-slot) and bounds the previously unbounded DataService schema cache. - Single-flight schema loads + deduped
legacylogin — concurrent cache misses for the same schema coalesce into one fetch; concurrentlegacyre-logins coalesce into oneAuthServicecall (matching the OAuth2 and broker providers).
Kubernetes readiness: dedicated liveness/readiness HTTP probes and a hardened container image, so the HTTP server can be orchestrated with standard health checks. 586 tests.
- Liveness/readiness endpoints —
GET /healthz(liveness) andGET /readyz(readiness) on the HTTP server, registered ahead of the auth and request-logging middleware so probes are unauthenticated and stay out of the request log./healthzreports the process is up (name, version, uptime);/readyzreturns200once the listener is accepting connections and flips to503at the start of graceful shutdown, so an orchestrator drains the instance before its connections are torn down.
- Dockerfile hardened for orchestration — the runtime image now runs as the unprivileged
nodeuser and declares a containerHEALTHCHECKagainst/healthz.
Per-tenant tool isolation for multi-tenant (gateway) deployments, plus a reusable live-regression
harness. Live-verified across all five auth modes against two real Creatio instances; 583 tests,
94.7% line coverage.
- Per-tenant dynamic-tool isolation (
gatewaymode) — a single MCP deployment serving many Creatio instances now keeps each tenant's tool surface separate, keyed by the effective base URL (X-Creatio-Base-Url, elseCREATIO_BASE_URL). Optional capabilities are probed per tenant and the tools they expose — DataForge, Global Search, and the dynamically discovered per-instance published tools — register only for the tenant they were found on. A newTenantToolRegistry(src/server/mcp/tenant-tool-registry.ts) holds the per-tenant capability verdicts, dynamic tools, and live session servers, with idle-TTL + LRU eviction that never drops a tenant with a live session. Single-tenant modes (everything exceptgatewaywith an override) map to one bucket, so their behavior is unchanged. - Reusable live-regression harness (
scripts/live-regression.mjs) — config-driven end-to-end smoke against a real Creatio over MCP: drives stdio + every HTTP auth mode (incl. broker DCR + PKCE with a local callback catcher), asserts the per-instance tool surface, and runs an opt-in full CRUD lifecycle (create → read-back → update → delete → verify-gone). Local credentials live in a gitignoredscripts/live-regression.local.json;*.example.jsonis the committed schema. Not part ofnpm test.
- Cross-tenant capability bleed — previously the optional-capability probe (DataForge / Global
Search / published tools) ran once per process from the first caller and applied that verdict to
every tenant, so on a heterogeneous
gatewaydeployment one instance's tools ordescribe-entityrouting could surface for another. The probe and tool registration are now per-tenant.
Server.createSessionServer/ensureCapabilitiesProbedtake the request's base-URL override and bind the session + probe to that tenant;_describeEntityresolves DataForge readiness per tenant.
Output-edge secret redaction + a content-validated schema cache that auto-invalidates when the Creatio data model changes (and is multi-tenant-safe). Schema-freshness live-verified vs a real Creatio; 570 tests, 94.6% line coverage.
- Central secret redaction — a single
redactSecretslayer scrubs credential-looking values (Bearer/Basic/Authorization, andclient_secret/password/access_token/refresh_token/BPMCSRF-style params) from both tool results relayed to the client and log lines. This turns the long-standing "never leak secrets/tokens" invariant from a convention into an enforced choke point. Errors thrown from tool handlers are scrubbed too, while preserving theErrortype/stack (no silent swallowing).
- Content-validated schema cache — schema/metadata caches (
describe-entity,list-entities, DataService write-coercion, OData$metadata) now validate against Creatio's own client-cache hash stamp (GET /api/ClientCache/Hashes— theruntime-entity-schemabucket +cacheVersion, the same signal the Freedom UI uses). When the data model changes at runtime (add/alter/remove an entity or column) the cache self-heals within ~60s instead of serving a stale schema for up to 30 minutes — fixing silently-wrong writes after a configuration change. Degrades gracefully to a coarse time-bucketed refresh when the endpoint is unavailable. - Per-tenant schema-cache isolation — schema/metadata caches are keyed by Creatio base URL, so a
gateway-mode deployment serving multiple instances (viaX-Creatio-Base-Url) never serves one tenant's schema or metadata to another.
- Keep-alive reuse — the single-session keep-alive tick (
legacy/client_credentials) now also refreshes the schema-freshness snapshot, so its periodic ping doubles as a cache-freshness check rather than a bare round-trip.
- README: concrete
delegated/gatewaysetup examples showing what to inject and where (theAuthorization: Bearer …header, plusX-Creatio-Base-Urlfor multi-tenant routing), and that the gateway injects a Bearer token only.
- 570 tests, 94.6% line coverage. New suites: secret redaction (+ error scrubbing at the tool boundary and the log line), ClientCache hash client, schema-freshness gate (TTL, per-base-url keying, degraded fallback), schema-freshness integration across both CRUD backends, and the keep-alive warm passthrough. The schema-freshness path was live-verified against a real Creatio.
Security/perf/architecture remediation (from a full re-review) plus broker production-readiness. Live-regressed across all transports vs a real Creatio; 537 tests, 94.5% line coverage.
- Broker access tokens are audience-bound —
aud(the/mcpresource) +iss(origin) are set and verified on every/mcpcall, so a token minted by one deployment is rejected by another sharingCREATIO_MCP_JWT_SECRET(token redirection / confused-deputy).client_idis bound and enforced on refresh. refresh_tokengrant (rotating, single-use, client-bound, gated on the broker still holding the user's Creatio tokens) — replaces a previously non-redeemable refresh token; standalone clients no longer re-consent hourly.CREATIO_MCP_JWT_SECREThardening — minimum 32 chars enforced; required in production (fail-closed); ephemeral-with-warning only outside production.- SSRF guard for the gateway
X-Creatio-Base-Urloverride —CREATIO_MCP_ALLOWED_BASE_URLSallowlist; cloud-metadata link-local addresses always blocked. - OData identifier-injection guard, log redaction of
code/state/tokenquery params, and bounded DCR client store (TTL + cap). - RFC 7009
POST /revoke(logout) — revokes the Creatio token upstream (/connect/revocation, best-effort) and purges server-side + issued-refresh tokens; always200.
brokerauth mode — the MCP acts as its own OAuth 2.1 authorization server for clients (DCR +/authorize+/token) and brokers the user login to Creatio via authorization_code + PKCE, holding the user's Creatio tokens server-side. The "connect → authorize → work as me" UX for standalone direct clients (Claude Desktop / ChatGPT). Selected viaCREATIO_MCP_AUTH_MODE=broker.- Pluggable broker token store —
CREATIO_MCP_TOKEN_STORE=memory(default) |redis. The Redis store (CREATIO_MCP_REDIS_URL) encrypts tokens at rest (AES-256-GCM;CREATIO_MCP_TOKEN_ENC_KEYor derived from the JWT secret) with native TTL → stateless, restart-durable, horizontally-scalable broker. CREATIO_MCP_PUBLIC_URL— pins issuer/audience/redirects/discovery to the external origin behind a TLS-terminating proxy.- Proactive session keep-alive (
CREATIO_MCP_KEEPALIVE_SECONDS, default300s,0disables) forlegacy/client_credentials; reactive reconnect now also recovers from a login-page bounce, not only401.
- Unified env scheme — two prefixes,
CREATIO_*(reach + auth Creatio) andCREATIO_MCP_*(MCP behavior), with a single declarative back-compat alias table (legacy names still work with a one-time deprecation notice). SingleCREATIO_MCP_AUTH_MODEselector (explicit or inferred: legacy → client_credentials → delegated). - Per-session
McpServer— each transport/session gets its ownMcpServer(a shared singleton rejected a second concurrent session'sconnect()with "Already connected to a transport"). - Performance — tuned global undici keep-alive dispatcher for outbound Creatio calls;
single-flight token refresh (no thundering herd); O(1)
describe-entityvia metadata indexes; compact (non-pretty) tool output; capability-probe negative-cache. - Architecture/DRY —
createAuthEdgefactory (auth-strategy out ofHttpServer);httpServer.ts→http-server.ts; shared identifier/probe/expiry helpers; OData read +getCurrentUserInfoonto the sharedrequest()helper; mutation audit now records outcome. - Lint —
@typescript-eslint/member-orderingrule codifies the class-member convention.
- Coverage raised to 94.5% lines (537 tests). Added the broker full-stack API suite (supertest) and an opt-in real-Redis integration test (auto-skips without Redis).
- Auto-create a GitHub Release from the CHANGELOG section on a
v*tag push (+ a manual backfill path), alongside the existing Docker multi-arch publish.
- Docker stdio transport —
MCP_TRANSPORTenv (httpdefault |stdio) selects the run mode in the container (stdio viadocker run -i); both transports read the same env.
- Declare
expressandzodas directdependencies(previously resolved only transitively through the MCP SDK) — required for a correct--omit=devruntime image.
- Docker image rebuilt as a multi-stage build on
node:24-alpine, running the compileddist/(nots-node/devDeps at runtime) viadocker-entrypoint.sh. - CI: GitHub Actions bumped to their Node24 majors (clears the Node20 deprecation); the publish workflow syncs the README to the Docker Hub repository overview.
- AGENTS.md: run modes & deployment, DataService wire-value gotchas (verified vs core/devkit),
engineering-principles section. README: Docker HTTP/stdio examples +
MCP_TRANSPORT/PORT.
- Capability kill-switches —
DISABLE_DATAFORGEandDISABLE_GLOBAL_SEARCHenv flags. When set, the capability is neither probed at startup (no network / no token spend) nor registered as a tool, even on an environment where it is available.describe-entitythen falls back to the active CRUD backend instead of DataForge.
- AGENTS.md: mandatory release checklist (bump → changelog → build/test → commit → tag → push → npm publish), engineering-principles section (SOLID / GRASP / Clean Code / patterns), tests-are-part-of-done rule, and the new disable flags. README env table updated.
- Selectable CRUD backend — OData or DataService (Creatio's native data API, now the
default), chosen per-deployment via
CREATIO_CRUD_BACKEND. Full DataService provider: read/create/update/delete, schema discovery viaRuntimeEntitySchemaRequest, entity listing viaVwSysSchemaInWorkspace, and metadata-driven value coercion. - Neutral query contract (
ReadQuery/FilterNodeAST /ReadResult) with a per-backend translator (Strategy): the MCP layer is dialect-agnostic; each backend owns its translation. - Capability-driven read params — the OData-only
filter(raw$filter) andexpandparameters are registered only when the active backend supports them.
- 10 issues found via live regression across both backends, incl.: OData ISO date/datetime
literals now emitted unquoted (
Edm.Date/Edm.DateTimeOffset);describe-entitysourcereflects the active backend; DataServiceFilterComparisonTypewire values corrected (gt/ge/lt/le/contains/endswith);list-entitiesde-duplication; lookup-FK select/path normalization; primary-column (Photo) projection; count/top:0handling; extended→baseDataValueTypecoercion; lookup-FK write mapping; quoted profile-tz DateTime parameters; and the explicitIsNullflag (fixes invertedisNotNull).
services/restructured into symmetricodata/anddataservice/folders; sharedassertEntityName/lookupIdPathhelpers;odataRootmoved into the OData layer so the shared HTTP client stays transport-only.
- Architecture audit refactor:
ICreatioAuthProvidersplit by capability (ISP/LSP) into core +IRevocable+IInteractive; directory renameproviders → contracts,services → sessions;server.tsGod-method slimmed into a declarative tool table; centralizedCreatioHttpClient.request()helper; idle-TTL eviction of session user tokens.
- DataForge env-gated MCP tools (semantic data-model layer) +
describe-entityrouting. - Global Search tool, plus hardened structured read lookup filters.
- Read pagination (
$skip) and total count ($count) with a default page size. - Published-tools proxy — surfaces tools published in the in-Creatio CrtMCPPublishingApp
(hidden, env-gated via
ENABLE_PUBLISHED_TOOLS). - CRUD backend selection seam + DataService groundwork.
- Engine layer earns its place: cross-cutting readonly guard + audit trail.
- Publish only
dist/to npm (addedfileswhitelist). - Dependency bumps (TypeScript,
@types/node,fast-xml-parser). - Testing made mandatory; coverage raised to 90%+ across statements/functions/lines.
- Baseline: Creatio MCP server (CRUD, schema inspection, process execution, sys settings, admin operations) over OData, with stdio + HTTP run modes and legacy/OAuth2 authentication.