Overview
DreamFactory v7.7.1 is a security-and-correctness release with one major component update. The database ?filter= pipeline gets a full sweep — filter values are now bound as query parameters (SQL-injection hardening), bare AND/OR filters parse correctly instead of silently matching nothing, BETWEEN works, and DELETE/PATCH-by-filter on system resources no longer 500s. The MCP Server jumps to 1.4.0 with lazy mode, merged tool styles, Exposed Services scoping, opt-in API-key auth, and a round of OAuth/daemon hardening. The release also adds platform-wide access-usage auditing, outbound OAuth2 for Remote Web Services, fixes an RBAC bypass in the AMQP/MQTT subscribe consumers, brings the single-connector editions onto the Laravel 13 stack they missed in 7.7.0, and open-sources the System API MCP daemon (df-system-mcp-server, Apache-2.0), now included in every full edition.
New Features
MCP Server (df-mcp-server 1.4.0) — OPEN SOURCE
- Lazy mode — a search/describe/call facade with hot tools, result paging, and a token-savings ledger, for clients that can't afford a large
tools/list. Per-servicelazy_modesetting:auto/on/off, defaultauto— the facade engages automatically when the service's full tool catalog would exceed roughly 8k tokens. - Exposed Services scoping —
tools/listis scoped to each MCP service's Exposed Services selection, cutting token cost; existing services are backfilled on upgrade. - Merged tool style — database tools register once behind a service argument instead of once per service (now the default for new services), extended to file tools; existing services keep their configured style.
- Exposure controls — per-service "Require Role Access" switch, a server-wide
allow_writesswitch that returns permission errors on role denials, catalog preview (tools/listfor a chosen role without a session), stateless sessions as the new daemon default, snake_case tool arguments with camelCase aliases and tool annotations, aggregate pushdown with paged grouped results, and an admin daemon health check atGET /_internal/ai/mcp-health. - Opt-in API-key authentication — per-service static
X-DreamFactory-API-Keyauth on the MCP endpoint, for clients that can't do OAuth. - Configurable redirect URIs — supports MCP clients that skip dynamic client registration.
- System API MCP Server (
system_mcp) — a new service type that exposes DreamFactory's own admin/system API over MCP, with a secret-field manifest and daemon launcher. The System API daemon makes its first public release alongside 7.7.1:dreamfactory/df-system-mcp-server0.5.1, open source (Apache-2.0), included in every full edition's 7.7.1 composer build as a vendor sibling. Start it with df-mcp-server'sscripts/start-system-daemon.sh(requires Node.js on the host), or pointMCP_SYSTEM_DAEMON_URLat a daemon running as a sidecar. Until the daemon is started, requests to asystem_mcpservice return a clear 503 with setup instructions.
Access Usage Auditing (df-system, df-admin-interface) — OPEN SOURCE
- Last-used and last-denied timestamps recorded for apps, roles, and users (new
access_usagetable + middleware; tune viaDF_ACCESS_USAGE_ENABLED,DF_ACCESS_USAGE_THROTTLE_SECONDS). - Read-only
GET /api/v2/system/access_usageaudit report withnever_used,stale,disabled_but_attempted, androle_unreferencedflags — find dormant credentials and orphaned roles at a glance. - Admin UI: last-used column and "Not used in" filter on the Apps, Roles, Users, and Admins tables;
get_access_auditadded to the System API MCP tool catalog.
Remote Web Services outbound OAuth2 (df-rws) — OPEN SOURCE
- Client-credentials authentication for proxied backends that require bearer tokens — token acquisition, caching, refresh, and one automatic retry on backend 401 are handled inside the service, no event scripts needed. Six optional
rws_configfields (token URL, client id/secret, grant type, scope, auth method); the client secret is encrypted at rest and masked in API responses. Supports Basic-header (e.g. Oracle OIDS/IDCS) and RFC 6749 post-body client authentication.
SQL whole-set aggregates (df-sqldb) — OPEN SOURCE
- Aggregate fields (
MIN/MAX/COUNT, etc.) are now allowed without aGROUP BY, returning whole-set aggregates from_tablequeries.
Admin UI (df-admin-interface 1.8.0) — OPEN SOURCE
- MCP service editor, redesigned — Connect, Tools, Settings, and Create surfaces with a tool grid; an Access section on the Tools rail to create/add/edit roles and API keys without leaving the MCP page;
allow_writes/ "Require Role Access" wired up; daemon health and server-backed tool/context catalog sizes; a merged database-tool matrix when the tool style is "merged". - System API MCP Server (
system_mcp) service details UI. - API Docs show the full instance URL in Swagger curl examples and Request URL (relative server URLs are absolutized).
Editions & packaging
- Everything new in this release is open source except the df-agents and df-schema-contracts fixes (commercial packages, tier placement unchanged from 7.7.0).
- New package: df-system-mcp-server 0.5.1 — the System API MCP daemon is now open source (Apache-2.0) and ships in every full edition, including OSS, alongside df-mcp-server.
- The eleven single-connector editions, last refreshed at 7.6.0, catch up to the 7.7.0 platform: Laravel 13 root constraints, the symfony 8 conflict guard, and seven package pins aligned to their 7.7.0 tags — plus all applicable 7.7.1 bumps. Single-connector installs now resolve Laravel 13.33 like every other edition.
Security Hardening
- df-sqldb: SQL injection hardening in
_tablefilters. Filter and{"expression"}values are now bound as query parameters instead of interpolated into SQL; a recognized set of no-argument SQL functions (NOW(),CURRENT_TIMESTAMP(), …) remains inline. - df-amqp / df-mqtt: subscribe-consumer RBAC bypass fixed. The subscription callback previously dispatched the triggered service request with permission checks disabled, so any user with pub/sub access on a queue could invoke admin-only endpoints. Callbacks now run permission-checked under the identity captured at subscribe time.
- df-amqp:
unserialize()of queue payloads is constrained to theSubscribejob class (allowed_classes+instanceofguard), blocking PHP gadget-chain attacks via crafted payloads. - df-mqtt: publish topics are validated — non-empty strings up to 64 KiB, no NUL bytes, no subscribe-only wildcards (
+/#). - df-core: curl SSRF/TLS defaults hardened — redirects are no longer followed automatically, each opted-in redirect hop is validated and pinned to its resolved IP, and SSL peer/host verification is on by default. The installed service-type list at the API root now requires authentication.
- df-system: import-URL SSRF validator blocks
0.0.0.0/8, IPv4-mapped/compatible IPv6, and alternate IPv4 encodings (decimal, hex, octal, short-dotted); security-question password-reset attempts are throttled and the reset response envelope is unified to blunt account enumeration. - df-rws: caller-supplied query parameters and pass-from-client header values expand public lookups only — private/secret lookups are expanded solely for admin-configured values; the service no longer follows HTTP redirects from the remote endpoint unless explicitly configured.
- df-mcp-server: the daemon shared secret is required on every
/mcproute; custom function tools are opt-in viaMCP_ALLOW_FUNCTION_TOOLS;/registerno longer persists caller-suppliedredirect_urisandredirect_uriis validated on/login; loopback OAuth redirects follow RFC 8252 §7.3; plus config/OAuth hardening found during 7.7.1 testing.
Fixes
Platform (df-core, df-system)
- DELETE and PATCH with
?filter=on system resources no longer return a 500 (Call to undefined method ...::deleteByFilter()). The filter now resolves to matching ids through the same criteria translation and model scoping as GET, then delegates to the existing by-ids batch paths; an empty match returns an empty resource set. - Filters with unparenthesized
AND/OR(a='x' OR b='y') parse correctly instead of silently matching nothing;BETWEEN/NOT BETWEENare implemented by expansion to range comparisons. (df-core + companion df-sqldb parsing fixes, including bare operators inside parenthesized groups.) _specis listed in the service access list, so roles can be granted it.- Package import resolves service ids without the cached id/name map — role service-access rows for services created in the same import are no longer skipped.
- Validation errors from record updates return 400 instead of 500; a service description may be null;
?model=truebuilds from the caller's_tablelisting. - MCP query templates use snake_case arguments and
aggregate_datafor group counts.
MCP (df-mcp-server)
- The MCP proxy no longer starves the PHP-FPM worker pool; the daemon's DreamFactory request timeout is raised to 60s.
get_data_modelquery templates match the active tool style; global tools read the stateless per-request config;mcp:prune-request-logsruns daily.
Agents (df-agents) — COMMERCIAL
- Approving an access request for a bare-service target now actually grants it — approval previously OR-ed verbs into existing table-scoped rows only, so a role with rows for other tables got nothing and the agent kept being denied.
- The activity ledger is indexed by
(app_id, occurred_at)and(role_id, occurred_at), and gets retention: a dailyagents:prune-ledgercommand (default 90 days,DF_AGENTS_LEDGER_RETENTION_DAYS, 0 disables).
Schema Contracts (df-schema-contracts) — COMMERCIAL
- Fresh installs using SQL Server as the system database no longer fail migrations: the user-audit foreign keys use
NO ACTIONon sqlsrv (error 1785, multiple cascade paths).
API Builder (df-api-builder)
- Generated OpenAPI specs for built APIs emit valid paths — endpoint paths previously rendered without separators (e.g.
/test_buildersample_1) or without a leading slash, breaking spec importers.
Admin UI (df-admin-interface)
- Login page no longer scrolls the auth pane.
- An existing grant's
requestor_maskis preserved when the MCP access editor changes its level;all_list_filesis counted only with two or more file services, matching the daemon.
Platform & Compatibility
- No platform baseline change: Laravel 13 / PHP 8.4+ as in 7.7.0. Shipped lockfiles refresh to Laravel 13.33.
- df-amqp, df-mqtt, and df-rws now declare
php ^8.3explicitly and build against the Laravel 13 stack; df-mqtt widens php-mqtt/client to allow v2 (shipped lockfiles resolve v2; same public surface as used by the service).
Upgrade Notes
- Run database migrations — 7.7.1 adds the
access_usagetable (df-system), agent activity-ledger indexes (df-agents), and MCP schema updates including the Exposed Services backfill andlazy_modecolumn (df-mcp-server).mcp:prune-request-logsandagents:prune-ledgerare scheduled daily once migrated. - Agent activity-ledger retention begins: rows older than 90 days start pruning daily after upgrade. Set
DF_AGENTS_LEDGER_RETENTION_DAYSto widen the window, or0to disable, before upgrading if you keep the ledger as a long-term audit trail. - Outbound HTTP behavior change (intended): requests made through the platform curl wrapper no longer follow redirects automatically and verify SSL peer/host by default. HTTP-backed services that relied on silent redirect-following or unverified/self-signed certificates need their service config updated after upgrade.
- Filter behavior changes (intended): filters that previously returned silently empty results because of bare
AND/ORnow match rows; inline SQL in filter values (beyond the recognized no-argument functions) no longer executes — it is bound as a parameter value. Review any filters that depended on either behavior. - AMQP/MQTT subscribers now run permission-checked under the subscribing identity. Flows that (improperly) relied on the unchecked dispatch will now receive permission errors — grant the subscriber's role the required access.
- MCP defaults: existing MCP services with large tool catalogs will start serving the lazy facade after upgrade (
lazy_modedefaults toauto) — setlazy_modetooffper service to keep the fulltools/list. New MCP services default to the merged database tool style; existing services keep their configured style. The daemon now runs stateless sessions by default on every install — setMCP_STATELESS=falseto restore warm, process-pinned sessions on single-node deployments. Custom function tools are disabled unlessMCP_ALLOW_FUNCTION_TOOLS=true, and the daemon shared secret is now required on every/mcproute. system_mcprequires its daemon to be running:composer install/updateon the 7.7.1 full-edition manifests brings indreamfactory/df-system-mcp-server(single-connector editions carry neither the MCP server norsystem_mcp); start the daemon with df-mcp-server'sscripts/start-system-daemon.sh(Node.js required on the host) or setMCP_SYSTEM_DAEMON_URLto a running sidecar. Service creation succeeds without it, but requests return 503 with setup instructions until the daemon is reachable.- df-rws: remote endpoints that redirect now require explicitly enabling redirect-following in the service config; caller-supplied parameters no longer expand private lookups.
- df-mqtt publishes now reject empty, oversized (>64 KiB), NUL-containing, or wildcard topics.
- The service-type catalog at the API root now requires authentication; unauthenticated integrations reading it must send credentials.
- Password-reset endpoints are rate-limited and return a uniform envelope; automation that parsed the old distinct responses should be updated.
- Security fixes are cumulative — upgrade promptly if you expose
_tablefilters to end users, run AMQP/MQTT subscriptions, or expose the MCP or RWS surfaces.