/ docs · functional specification

The full platform
functional reference.

Every functional area of AI API Mapper documented at implementation depth so architects, security reviewers, and platform engineers can evaluate the product with real technical context.

Changelog · Changelog

Changelog

This page summarises each platform release. Full technical detail is available in the repository.


Version 1.2.7

A toolset is now the thing you manage, and mappings are added to it. An MCP toolset is what an AI client connects to, but until now it could only be created from inside a single mapping and was permanently tied to it. Exposing endpoints from two APIs through one connection meant two toolsets and two client configurations. A toolset now draws its tools from as many mappings as you like, and Tools Management opens on the toolset itself.

Existing toolsets are migrated automatically as part of the standard database upgrade. Every toolset keeps its mapping, every tool keeps its identity, and no access policy, credential binding or client configuration has to be touched.

Changes in this release:

  • Create a toolset, then add mappings to it. Name the toolset, choose which client applications may reach it, then add one or more published mappings. Each added mapping gets its own card where you choose its target system, its authentication profile, its default access policy, and which of its endpoints become tools
  • Downstream settings moved to where the decision actually is. Target system, authentication profile and policy defaults are now set per mapping rather than per toolset, because a toolset spanning two APIs reaches two different systems — which is the reason for spanning them. A toolset with one mapping behaves exactly as it did
  • Two views of the same data, with a toggle. MCP Toolsets lists one row per toolset with the mappings it draws from; Mappings keeps the previous card-per-mapping view for answering "what does this mapping publish?". The toolset view is the default, and your choice is remembered
  • A toolset that spans several mappings is visible as such. In the Mappings view it appears under each mapping it draws from, with a count showing how many mappings that row touches — so it is clear before editing that the change reaches further than the card you opened it from
  • Two mappings cannot publish the same tool name into one toolset. MCP tool names are {toolset}-{endpoint} and a call is resolved by that name, so two endpoints sharing a name would mean one tool silently answering the other's calls. This is refused when you save, naming both mappings, rather than becoming a wrong answer at runtime. Nothing is renamed automatically — that would move a tool underneath clients already calling it
  • A duplicate that slips in anyway is flagged, not hidden. Republishing a mapping can rename an endpoint onto a name another mapping in the same toolset already uses, and that republish is deliberately not blocked — failing a mapping publish because of an unrelated toolset's shape would be worse. Instead the toolset is marked with a warning wherever it is listed, the editor names the affected tool and badges each colliding endpoint, and Security sees it on Tool Oversight. Both tools stay callable until you resolve it, which is the honest state of affairs; deselecting either one clears it
  • A toolset belongs to one tenant, and you choose it first. When your session spans tenants, the toolset editor asks which tenant the toolset is for before any mapping can be added, then offers only that tenant's published mappings and client applications. A toolset is reached through one tenant's runtime URL and governed by that tenant's policies, so a toolset mixing tenants was never something the runtime could serve
  • Client applications and mappings are added and removed, not picked from a wall. Both are chosen from a search box listing what is not yet added, and each added one has a remove button — a tenant with two hundred client applications no longer means two hundred cards to scroll past. Any mapping can now be removed, including a toolset's last one
  • An endpoint opens when you ask it to. Including an endpoint no longer unfolds its settings; an expand icon on the right does. A toolset exposing thirty endpoints stays readable
  • Every warning a toolset carries is visible without editing it. A toolset that publishes a duplicate tool name, or that exposes an endpoint another toolset already exposes to the same client application, is marked with a warning icon in the list and explained in full in the read-only View details — which is what a user without publish rights can open. Previously the second of those was only ever visible to someone already editing the toolset
  • Adding a mapping to a toolset never disturbs the tools already in it. Tool identity does not include the mapping, so existing access policies, credential bindings and audit history stay attached exactly where they were
  • A deprecated mapping no longer silences its neighbours. Each mapping in a toolset is resolved at its own lifecycle point, so one mapping going out of service removes only its own tools
  • Toolset create and update requests are now validated for shape before they reach the domain, and the Tools Management screen's contextual help documents the new workflow

Version 1.2.5

A rebuilt authorization model: roles are permission bundles, and scope belongs to the grant. A role is now a named set of permissions written as area:level, and a user's authority is simply the union of the roles they hold. Levels form a ladder inside a single area — write carries read carries the ability to merely name a thing — and carry nothing across areas. Scope has moved off the role's name and onto the grant: the same Security → Manage role administers one tenant when granted against that tenant, and every tenant when granted against none. The fifteen separate GLOBAL_* roles are gone, and with them the class of mistake where a role and its global twin drifted apart.

Existing grants are migrated automatically as part of the standard database upgrade. No role has to be re-granted, and no user's effective authority changes.

Changes in this release:

  • An area role is finally usable on its own. Every admin screen needs to name things another area owns — a target system, a model profile, a client application, a tenant — and obtaining a name used to cost the full administration role for that other area. A new lookup tier returns identity only (an id and a name, never configuration, never a value), and each area role carries exactly the lookups its own screens need. An ESRA exposure manager no longer needs the Apps & Tools role to pick an audience
  • Six screens that returned an authorization error inside a picker now work, for the same reason
  • Every screen and every gated control declares the permission it needs in one place, and an automated check compares that declaration against the authority the endpoints behind it actually require — so a screen cannot be visible under one rule and reachable under another. Four screens whose declared and enforced authority disagreed have been corrected
  • One gating rule across the whole Portal: no read on the subject and the control is not shown; read but not write and it is shown disabled, with the missing role named; write and it is enabled. Hiding a control from someone who can see the thing it acts on tells them the platform cannot do it, rather than what to ask for
  • The dashboard adapts to the areas you hold rather than to whether you are a platform administrator. Each tile and quick link is offered on the same permission as the screen it leads to, so an area administrator lands on a useful page instead of an empty one
  • Notifications reach whoever administers the thing they are about. The bell is now filtered by the area that owns each notification's subject, so the holder of the API Definitions role is told when their enrichment finishes — previously that was a tenant-administration privilege
  • The Users screen shows the roles a user actually holds. A whole-tenant role is displayed as itself rather than expanded into the area roles it contains, so opening a user and pressing Save no longer rewrites their grant
  • A single role table serves both scopes, with the Global/Tenant selector above it choosing the scope
  • You can only grant roles you hold yourself. Handing out a role is now permitted exactly when the administrator's own permissions already cover everything that role carries. A user administrator who holds Membership delegates Membership; the roles of areas they do not hold appear greyed out in the form, with a note saying why. To let someone grant another area's roles, grant them that area — the same decision, made visible in their own role list rather than only in what they can do to other people's. Editing a user who holds roles you cannot grant still works: those grants pass through untouched, and you may remove them

A tool's security rules now belong to whoever publishes the tool. Access policies and endpoint authentication bindings used to be filed under Security even though an MCP toolset or an ESRA exposure is what creates and destroys them, and ownership was determined by parsing the tool's identifier as text. Every tool the platform serves is now a registered identity with a real reference, and its rules hang off that.

Changes in this release:

  • An ESRA exposure manager or a toolset administrator sets the rules of the tools they publish, using their own area's authority, from the screen that publishes them. There is no separate Security screen to visit and no tool identifier to type
  • A publisher only ever sees its own tools. Both screens previously loaded the tenant's entire set of rules and filtered client-side
  • New Security → Tool Oversight screen. Security governs tools rather than owning them: this screen reads every tool in scope whoever publishes it, with the rules currently attached, and offers exactly two actions — take a tool offline, and clear a leftover row whose publisher no longer exists. It authors nothing
  • Taking a tool offline is immediate and cannot be undone by its owner. The Runtime refuses every call to a quarantined tool whatever that tool's own policies permit, and the reason recorded is shown to the owner and written to the audit trail
  • Deselecting an endpoint deactivates its tool rather than deleting it, so reselecting the endpoint restores the rules that were attached to it
  • Visible change: the tools screen now shows no tools for a mapping whose newest version is deprecated, matching what the Runtime actually serves. The two previously disagreed
  • The database upgrade is one command again. Data backfills run as part of apply, between the schema migrations they belong between, and status reports outstanding backfill work alongside outstanding schema work — so an empty pending list means there is genuinely nothing left to do

Consent now means something on the Runtime. An AI client obtaining access through the OAuth flow is shown what it is asking for, and that approval is enforced on every call.

Changes in this release:

  • Four scopes — see which tools exist, call them, see which agents exist, message them — deliberately few enough that a person can reason about them at a consent screen
  • Discovery and invocation are each gated on their own scope, checked before any per-tool policy runs. Consent is a ceiling, not a policy dimension an operator can forget to configure
  • The scopes granted are the intersection of what the user approved and what the client registered, never the union, and the approval is recorded at the moment it is given — so re-registering a client later cannot widen an approval already made
  • The platform now advertises the scopes a client may ask for, which is what lets a client request less than the default
  • A client that asks for nothing receives the platform's default set, listed in full on the consent screen before the user approves it
  • A client can manage its own registration: it receives a management credential once, at registration, and can read, update, revoke or delete itself through the standard protocol endpoints. It cannot reach any other client's registration, and the platform answers identically whether a client is unknown or the credential is wrong
  • A client may only use the grant types it registered for
  • Registrations that never complete a sign-in are swept away, so abandoned registration attempts do not accumulate
  • Fixed: a client using http://localhost for its callback, or binding a different local port on each run, was refused. Both are what native and MCP clients conventionally do, and both are now accepted, with the exception kept as narrow as the specification allows

Platform hardening and operational correctness. This release closes out two full review cycles.

Changes in this release:

  • Portal access tokens are signed with a private key the Portal alone holds, and validated everywhere else against the matching public key, published at a standard JWKS endpoint. A second, retiring key can be configured during a rotation, so a key can be replaced without invalidating every session in flight
  • A resilience policy — retries, per-attempt timeouts and a circuit breaker — now applies to every outbound call the platform makes on a tenant's behalf. Retries are deliberately not applied to unsafe HTTP methods: the platform cannot know whether a downstream write that timed out was applied, and cannot compensate if it was
  • The MCP surface has a working kill switch (Runtime:Transport:ExposeMcp) and a configurable request body ceiling (Runtime:Transport:MaxRequestBodyBytes, 1 MB by default)
  • The admin Portal is served with a full browser security policy — Content-Security-Policy, framing and content-type protections, referrer and permissions policy, and HSTS — derived per deployment from the configured gateway origin
  • Password hashing raised to the current OWASP-recommended work factor, with existing accounts upgraded transparently at their next successful sign-in and without resetting anyone's password-rotation schedule
  • Session revocation now survives a restart and reaches a newly scaled-out instance
  • Secrets are bound by identity rather than by label, so renaming a secret does not silently repoint the configuration that used it, and a removed secret fails loudly at the point of use instead of falling back
  • A secret resolves inside the tenant that owns it; asking for a name your tenant does not hold is indistinguishable from asking for a name that does not exist
  • Adding a private or loopback address to the outbound allowlist requires platform scope, and can be turned off deployment-wide
  • Every write is checked against the area that owns the data before it is applied, and an authorization refusal now returns a clear "forbidden" response rather than surfacing as an unexpected error. Behaviour change: creating or rotating an inline LLM credential is a Security operation — the AI Settings form keeps its secret picker, and shows the inline option disabled with the reason
  • Fixed: the "Run enrichment" switch was silently off when creating a new mapping version, for every tenant that had model profiles configured
  • Fixed: the Agent Card's signature could not be verified over its path-based URL, because the key document it points at was not reachable without a credential. Remote parties could not check a signature the platform was publishing
  • Supply-chain hardening across the release pipeline: image signing is now mandatory rather than advisory, datastore ports and the broker management console are no longer published to the host in production, containers drop all capabilities, dependency versions are locked, and a production dependency advisory fails the build
  • Consistent modal behaviour across the Portal, page actions aligned consistently, and inline help updated across every screen

Upgrade note. A production deployment must now supply an RSA signing key pair for Portal tokens (Authentication:SigningKeyPem). Portal API refuses to start in Production without it, unless Authentication:RequireAsymmetricSigningInProduction is explicitly set to false as a temporary migration measure. See the Configuration Reference for generation and rotation.


Version 1.2.2

A2A Hosted Agent mode — LLM-backed agent skills, built on Microsoft Agent Framework. A registered agent can now be a Hosted Agent instead of a proxy to a remote peer: an LLM-backed reasoning agent that runs admin-defined Skills over a curated subset of your Mapping tools. A skill's LLM turn recognizes an incomplete request and asks a clarifying question instead of failing outright, then resumes the exact same conversation on the caller's follow-up message — every tool it calls still goes through the platform's existing authorization, credential brokering, and audit pipeline unchanged, with the LLM never given a bypass path to a downstream API.

Changes in this release:

  • New HostedAgent kind for registered agents, alongside the existing concentrator (RemoteAgent) kind — set once at registration, never changed afterward
  • Admins define one or more Skills on a Hosted Agent: a name, a prompt, and an explicit subset of individual tools drawn from the tenant's MCP toolsets and ESRA exposures — never the whole catalog, and never a whole Mapping when only some of its tools should be agent-reachable
  • MCP toolsets and ESRA exposures can each be marked "Hosted Agents only" or "MCP clients + Hosted Agents" (in addition to the existing "MCP clients only") — an agent-only toolset needs no MCP client application assigned to it
  • A skill's LLM turn recognizes an incomplete request and pauses the task instead of failing it, asking a clarifying question the caller can answer to resume the same conversation
  • A skill's LLM turn also recognizes a credential-rejected downstream call and pauses the task the same way, distinguishing a wrong request from one blocked on credentials
  • Every tool the LLM invokes goes through the exact same governed invocation pipeline — authorization, credential brokering, downstream call, audit — a deterministic skill invocation uses
  • Structural prompt-injection defense: a skill's LLM turn can only ever see and call the tools explicitly assigned to it, and the caller's message can never rewrite the admin-authored system prompt
  • Every LLM turn is audited with its actual decision content — which tool it chose, the clarifying question it asked, and the turn's token spend — not just success or failure
  • LLM connectivity reuses the platform's existing LLM connection management, the same one already used for semantic enrichment
  • New functional documentation: A2A Hosted Agent Mode

ESRA — the Enterprise Semantic Retrieval Agent. An AI client can now ask a question in plain language and receive governed evidence from your own enterprise databases, published as an ordinary MCP tool through the existing Runtime. There is no vector database, no embedding pipeline, and no copy of your data unless you ask for one: retrieval runs on the native full-text search engine of the database itself. Because it is an ordinary tool, everything that already governs a tool call governs a retrieval call unchanged: authentication, access policy, audit, rate limits and tenant isolation.

The design principle throughout is that the AI model proposes possible search strategies, and the platform's own deterministic logic decides what actually runs. A service model chooses among the sources a caller is already authorized to reach — seeing business descriptions only, never a schema, a host, or a credential — and proposes several search strategies per source; it never writes or sees SQL. Every proposed plan is validated by the platform before it can run, so a plan that fails validation can never reach a database. If the model is slow or unavailable, retrieval still works: every model-assisted stage has a deterministic fallback, and the response is marked degraded rather than failing outright.

Changes in this release:

  • New ESRA capability, integrated across the Runtime, Portal, and background job processing, with an initial PostgreSQL retrieval provider and an internal document store
  • Three-level configuration — sources, capabilities, exposures — with a narrowing-only invariant: an exposure may lower a limit, remove a source, or drop a response mode, never the reverse; a widening override is a publication error with a named reason, never a silent clamp
  • Each exposure gets its own independent access policy, using the platform's existing governance model unchanged — so one capability can be published to two audiences over different source subsets under different policies
  • ESRA tools compose into the existing tool catalog additively, alongside ordinary mapping-based tools — a tenant with no ESRA configuration sees exactly the catalog it saw before
  • The PostgreSQL provider builds every query from validated configuration rather than untrusted input, applies row limits and ordering server-side, and runs every query in a read-only transaction with a statement timeout — so a query can never modify data or run away indefinitely
  • Record-level access filters, derived from the caller's claims, are applied as part of every query and fail closed: if a caller lacks a required claim, that source is skipped entirely rather than queried without its access restriction
  • The internal retrieval model's tasks are isolated from caller and document content, and its output is validated against an allow-list: an identifier the model was never given is dropped and logged, and a fabricated citation invalidates the whole answer
  • Internal document store: administrators upload .txt, .md, .csv, .pdf and .docx files that become searchable content in their own right, segmented per format so ranking is not diluted by document length
  • Upload protections guard against disguised file types, compressed-file bombs, and XML-based exploits; legacy and macro-enabled Office formats are rejected with an actionable message, and content flagged for possible prompt injection is quarantined for operator review rather than silently indexed or bluntly refused
  • A new ESRA & Data role area with dedicated roles for viewing data source configuration, managing what exists and what is searchable, and managing who is allowed to see it. The two management roles are independent, so publishing enterprise data to an AI client requires sign-off from multiple distinct role holders in sequence
  • Portal gains an ESRA & Data section — data sources, capabilities, exposures and the document store — with per-control gating: a holder who can read but not manage sees the configuration with its controls disabled and the missing role named, rather than a screen that silently omits functionality
  • The exposures screen shows the computed effective scope before publication: which sources survive all three configuration levels, which were narrowed away and at which level, and exactly what blocks publishing
  • Every stage of a retrieval call is captured in the governance audit trail and can flow to external immutable audit targets, with payload capture conditional and processed asynchronously so retrieval never incurs added latency from audit logging
  • Guided source onboarding: a seven-step wizard reads the database's own catalog — relations, columns, keys, full-text indexes — and proposes the mapping, replacing a create dialog plus a separate entities tab. It never guesses which columns are filterable or restricted: those are governance decisions, and a security control set by heuristic is worse than one left unset
  • Every ESRA editor now stages its changes and saves once. Five screens previously applied a sub-entity edit immediately and carried a disclaimer saying so
  • A new ESRA overview screen shows the pipeline as a pipeline — sources feed capabilities, capabilities are published by exposures — and names everything blocking the next step on one page
  • Source readiness has one shared implementation, used by both the Portal's health column and the publication guard, so the screen and the guard cannot disagree about whether a source is usable
  • Grounded answers now compose from the retrieved evidence, and never fail an invocation: retrieval has already done its work, so every failure returns the evidence with a warning rather than discarding a usable result set
  • Document fetch ships: encrypted, expiring references bound to tenant and exposure, re-authorized on every fetch because a reference is a pointer and never a grant, and bounded by a distributed hourly character quota — the control that stops fetch becoming a corpus-download API
  • SQL Server joins PostgreSQL as a first-class source engine, using SQL Server's native full-text search with the search condition passed as a parameter
  • The internal document store works end to end: uploads are accepted, and a background job extracts, scans and segments each file, recovering automatically if the worker processing it fails. Uploads report per file, because a batch verdict cannot say which of ten files was the password-protected PDF
  • The document store gains a review screen showing every processing state — including the ones retrieval can never return — and a quarantine queue that shows what the injection scanner matched before an operator releases anything
  • Scheduled health probes: a source whose database went away now drops out of retrieval scope on its own, rather than being selected and failing every invocation until an operator probes it by hand
  • Try a query runs the real pipeline against a published exposure as one of its own client applications, and shows every stage of it. It writes one operator-action audit record and no invocation records — an administrator testing a query must never appear in the trail as a caller having retrieved data
  • Invocation traces reassemble the stage records ESRA already writes into the run they belonged to, which is the only way to tell "the corpus has no answer" from "the plan was rejected" from "a provider query timed out"
  • SQL Server transaction isolation is now a per-source setting — read committed by default, with an opt-in for databases configured to allow a stricter level. Choosing an isolation level the database does not support fails with a named reason rather than falling back silently
  • Connection failures that happen before a source is reached — an unapproved host, an unresolvable secret, a misconfigured connection — now carry their own descriptive classification, and the connection test states what to change rather than reporting a generic failure
  • A data source that is actively serving traffic can no longer be edited in place. A published, enabled source is what the runtime is actively searching, so changes now require an explicit unpublish step first — this prevents a live audience's search results from changing silently mid-flight, with no record that a change happened. Unpublishing is itself blocked while any published exposure still depends on the source. Disabling a source removes it from live traffic immediately, which is what allows a correction to be made even when unpublishing is blocked; the change takes effect again once the source is re-enabled
  • Database entities can now be read directly from the database when editing an existing source, not only during initial onboarding — removing the need to type relation and column names from memory when adding an entity later, which had been a source of empty result sets discovered only after the fact. The screens also now state plainly that a missing table is far more often a missing database permission than an empty database
  • Document fetch now works against the internal store and SQL Server, alongside the source types that already supported it — previously, every fetch reference minted by these two source types was refused as invalid or expired, even immediately after being issued. A source type that has no fetch capability at all is now reported as such, rather than being described as a bad reference
  • ESRA returns results far more often. Time budgets for each retrieval stage were increased to better match real-world AI model response times, and output limits are now sized for models that reason before answering. Search plans no longer treat every search term as strictly required — a pattern that had caused many searches to match nothing on a real dataset — terms are now weighted so that precision comes from result ranking rather than from an all-or-nothing match. An empty response from the retrieval model is now reported accurately as "no results," rather than as a parsing error
  • The Call Flow trace can now fully explain a retrieval call. A new step captures the caller's prompt and the response they received, after masking, exactly as the caller saw it. Retrieval steps name the data sources considered, which were selected, and which were passed over, along with the specific source and entity each underlying query ran against. The search terms used are shown as planned intent — what had to match, what could match, and what was excluded — following the same payload-capture setting as the rest of the call, since they are the caller's own words. The underlying database query text is never recorded, and neither is an entity's underlying table name
  • Retrieval stage outcomes are now described in plain terms — OK, Partial, Failed, and Not run — each explaining what it means for the answer, replacing an internal status label whose commonest cause (no AI model configured, so the platform's built-in deterministic fallback ran) was easy to mistake for an alarm. The audit trail keeps its own, more precise vocabulary
  • A partially healthy source now names the specific entity responsible, instead of only reporting that at least one entity has a problem — a distinction that matters on a source with many entities, where the previous message left an operator to check each one by hand. The connection test names the affected entities, and the Searchable entities tab shows what's wrong, and whose responsibility it is to fix, down to the individual column where the engine can tell. Findings come from the scheduled health sweep, so they are available without the operator running anything, and each new probe refreshes them. The PostgreSQL health check also now specifically looks for a genuine full-text search index, rather than treating the presence of any index as sufficient
  • A full-text index that is still being built is no longer reported as an ongoing health problem. Under continuous data ingestion, an index catching up is the normal state rather than an exception, so the previous warning was effectively permanent — and a warning that never clears is one nobody reads. The catch-up state is now shown as an informational note instead, since results may simply be incomplete until it catches up; an index whose build status can't be determined at all still shows as degraded, since that genuinely isn't known to be fine. This status is informational only and never blocks a source from being queried
  • SQL Server sources can now have their schema read directly from the database too, matching how PostgreSQL sources already work — previously every SQL Server source required relations and columns to be typed in by hand in both the onboarding wizard and the source editor. A relation with no full-text index is now reported accurately for each engine: usable but slower on PostgreSQL, not usable at all on SQL Server, which requires one
  • ESRA tools now carry their own system prompt guidance, the same way mapping-based toolsets already do. A tool description alone doesn't tell a connected AI application when to use the tool, when not to, or that it must cite the retrieved record rather than paraphrase it — this guidance is now published alongside the tool and merged into the context a client attaches automatically. If this guidance can't be loaded for one tool, that tool is simply omitted from the guidance rather than breaking the listing for every tool
  • An exposure's published tool name must now be unique across the tenant's entire tool catalog, not just among other ESRA exposures — closing a gap where a mapping-based toolset could share a name with an ESRA exposure, leaving a connected AI client with two barely distinguishable entries
  • The Call Flow trace now shows the complete retrieval pipeline. Every stage is named, individually iconed, and timed — including each individual data-source query — instead of a retrieval call rendering as a single, unexplained governance check
  • Opening an invocation's trace now works reliably, and opens in place within its own row in the list, rather than in a separate panel that didn't make clear which run it belonged to. A tenant-resolution inconsistency that could prevent a trace from loading has been fixed, and the panel now explains why a listing or trace could not be read, instead of showing a misleading "never called" empty state
  • A failed invocation now says what failed. The listing previously reported only how many stages failed; it now names the first failing stage, its error classification, and the recorded reason, and correctly reports a run that completed via fallback as degraded rather than as a plain success or failure
  • Stage-outcome badges in Try & trace now use colour combinations that stay legible in both light and dark Portal themes
  • ESRA now reports what AI model usage has cost. Each capability tracks a running total of tokens used — input, output, and combined — shown on its list row and in its detail view; the overview page totals spend across every capability, including retired ones, since a retired capability's historical spend still counts. Input and output tokens are shown separately, since output is priced higher than input by most providers. Failed and retried calls are counted, since they are billed like any other call; where a provider doesn't report usage directly, the count is estimated and clearly labelled as an estimate. Cost tracking runs off the request path, so it adds no latency to a retrieval call, and briefly falls behind rather than delaying an answer if the platform is under heavy load
  • Every ESRA screen now has a Refresh button — sources, capabilities, exposures, documents, and recent invocations — consistent with the rest of the Portal. The overview's capabilities card also gets its own quick-refresh control for the model-usage total specifically, since that figure updates continuously as retrieval calls happen
  • The raw, free-form policy rule editor is removed from the ESRA access-policy screen, since it corresponded to no ESRA-specific concept and was routinely left empty. A policy rule authored elsewhere is now carried through and displayed in context wherever it applies
  • Circuit breakers replace the previous per-query retry behaviour: a struggling data source now fails fast for concurrent queries after the first couple of failures, rather than every concurrent query independently retrying and timing out on its own. Failure thresholds are configurable per source, and circuit status is shown on the source grid on the same schedule as the health sweep
  • An opt-in, access-scoped result cache can now collapse a burst of near-identical queries against a slow-changing data source. The cache is scoped so that two callers whose access permissions narrow a source's visible rows differently can never share a cached result, and content masking always re-applies fresh on every read regardless of caching. The cache is off by default per source, applies only to raw result retrieval (not generated answers), and uses the platform's existing shared caching infrastructure rather than a separate one
  • Retrieval performance improvements: planning across multiple sources now happens concurrently instead of one source at a time; per-source query latency is now tracked with tenant-level detail suitable for monitoring dashboards; and both supported database drivers' connection pools are pre-warmed at startup to the platform's typical concurrency level instead of starting cold
  • Admin-facing index and schema advisories: health probes now also flag a search index that exists but cannot serve the configured retrieval query, an index built against outdated search configuration, and an access-filter column with no supporting index. All three are advisory only — never a blocker, and never affecting a source's health or scope — surfaced as a separate, distinct count on the source grid alongside the health badge
  • ESRA is included on every plan at no additional cost
  • Grounded answer generation can now be published for real use. The two response modes that produce a synthesized answer instead of raw results have existed since ESRA's initial release but could not be published until now; a capability or exposure may enable them, subject to a per-source opt-in that a capability alone cannot override. The Portal's response-mode picker now shows the cost implication of each choice up front — plain result and context modes add no cost beyond ordinary retrieval, while either answer-generation mode adds a further model call with real added latency and token spend — rather than leaving an operator to discover it later on the token-usage screen. The default stage-timing values shown when creating a new capability have also been corrected to match what the platform actually uses
  • An exposure can now optionally warn the calling AI application about prompt injection risk in retrieved content, through two independent, off-by-default settings: one adds a defensive notice to the exposure's system prompt, read once at discovery time by clients that fold tool guidance into their own context; the other attaches the same notice to every individual result, for clients that don't read discovery-time guidance. ESRA's own internal model is always protected against instructions embedded in retrieved content, regardless of these settings — both settings exist to warn the calling application, which ESRA does not control
  • MySQL and MariaDB join PostgreSQL and SQL Server as source engines, using each database's native full-text search. Natural-language search needs no special handling; boolean-mode search (required or excluded terms, exact phrases) is fully protected against search-syntax injection. A relation with no full-text index is reported as unusable on these engines rather than merely slow, since a search without one fails outright on MySQL and MariaDB. Verified against real MySQL and MariaDB instances independently, since full-text search behaviour differs between the two despite their shared heritage
  • Elasticsearch and OpenSearch join the source engine list, the first providers reached over their native HTTP query API rather than a database driver. Every search term is treated strictly as a value to match, never as query syntax — verified by tests confirming that a wide range of adversarial inputs, including characters with special meaning to the underlying query language, always produce structurally identical, safe requests. Native relevance ranking and highlighting are used as-is. A searchable field that isn't configured for full-text search is flagged as degraded, and a result-key field that can't be used for sorting is flagged as unhealthy, since queries would otherwise fail outright rather than merely rank worse
  • MongoDB joins the source engine list, connected over its own native protocol rather than a SQL-style or REST connection. Both MongoDB's built-in text index and its richer Atlas Search capability (where available) are supported as search modes per data source; the platform's declared capabilities for a MongoDB source stay conservative regardless of which mode is in use, so retrieval planning is never told the source can do more than the safe baseline guarantees. Every search value is passed through MongoDB's typed query-building interface rather than ever being built from raw text, closing off MongoDB's specific injection risk — a search term shaped like a query operator. This is also the first source type where the platform distinguishes a genuine collection from a database view, since MongoDB has both
  • Fixed: newly added MongoDB sources could not actually be used. A wiring gap prevented the platform from resolving MongoDB's search, schema-reading, and document-fetch capabilities at runtime, even though the underlying support had shipped correctly. A new automated check now verifies, for every supported source engine, that all three capabilities resolve correctly at startup, catching this class of gap going forward
  • Oracle joins the source engine list, using Oracle Text search and a managed, cross-platform Oracle database driver. Read-only enforcement is applied at the database transaction level. Oracle Text is a separately licensed Oracle feature that isn't universally installed; the health probe distinguishes a working index, a database confirmed not to have Oracle Text licensed, and a genuinely inconclusive case, rather than collapsing the last two together — so an administrator can tell "not enabled" apart from "can't check." Because Oracle Text indexes one column at a time rather than computing a combined document across columns the way some other engines do, this provider searches the single highest-weighted configured column and generates result snippets itself. Verified against a real Oracle test database for connectivity, read-only enforcement, row limits, and document fetch; ranking quality and native snippet behaviour specifically require a licensed Oracle Text installation and are outside the scope of this release's automated verification
  • Fixed: the Portal's data source screens had fallen behind the source engines above. The "Add a data source" wizard's provider list only offered PostgreSQL and SQL Server, so a source of any of the four newer engine types (MySQL/MariaDB, Elasticsearch/OpenSearch, MongoDB, or Oracle) could not be created through the wizard at all; the source editor was separately missing Oracle from its own list. Both screens now offer every supported source engine, with dedicated connection steps for engines that don't use a traditional database connection (Elasticsearch, MongoDB). The "missing full-text index" warning shown when picking searchable entities is also corrected: it previously understated the impact of a missing index on MySQL, Oracle, and MongoDB, all of which — like SQL Server — fail outright without one, rather than merely running more slowly
  • Listing mappings is now substantially faster on tenants with many mapping versions. The mapping list now loads only the summary information it displays — the latest version number and the published version's endpoint details — instead of loading and tracking every version of every mapping. API response fields, ordering, filtering, total counts, and pagination are unchanged
  • Database migrations are now automatically verified against both supported database engines (SQL Server and PostgreSQL) as part of the release process, closing several PostgreSQL-specific migration issues that had gone undetected
  • Semantic enrichment progress updates are now throttled to a reasonable rate — at most every few seconds, or on meaningful progress milestones — instead of being published on every individual field, reducing load from very large enrichment runs without changing the progress information shown in the Portal
  • The Public Site's documentation pages now sanitize rendered content and carry the same browser security headers used elsewhere across the platform, reducing exposure to malicious content in documentation

Version 1.2.0

MCP Server-Sent Events support, external correlation ID tracking, and delegated On-Behalf-Of downstream authentication. AI clients that expect a persistent server-to-client stream — rather than a JSON reply to each POST — can now connect to the Runtime, invoke tools, and receive responses over SSE. The Runtime implements the Streamable HTTP transport of MCP specification 2025-11-25 in full, and keeps serving the deprecated 2024-11-05 HTTP+SSE transport for older clients. A client may also send its own correlation identifier and later retrieve the full platform trace of the work it triggered, and each toolset now decides which correlation identifier its downstream APIs receive and under which header name. Downstream authentication gained delegated token exchange: an AI client presents a token the Runtime can validate, and the Runtime exchanges it for a downstream token so tools act on the target system as the signed-in user — Microsoft Graph via Entra On-Behalf-Of being the first supported provider. Credential caching was reworked alongside it, so whether a cached credential is shared between callers follows from the authentication strategy instead of from a setting that could contradict it.

Changes in this release:

  • The MCP endpoint /runtime/{tenantId}/{clientId}/mcp now serves POST, GET, and DELETE
  • POST answers a request with a JSON body or, when the client accepts text/event-stream, an SSE stream that opens with a priming event, delivers the response, and terminates
  • GET opens the standalone server-to-client stream, answering 406 without Accept: text/event-stream, 409 for a second concurrent stream on one session, and 405 when the SSE transport is switched off
  • DELETE terminates a session and closes its streams
  • Sessions are established at initialize and carried in Mcp-Session-Id; a session the server does not recognise is always answered with 404 so the client re-initializes
  • Streams are resumable: every frame carries an event id, and a client reconnecting with Last-Event-ID is resumed on the stream that issued it and receives only what followed — never messages that belonged to another stream
  • The Origin header is validated on every MCP request, refusing unknown origins with 403, which is the DNS-rebinding defence the specification mandates
  • MCP-Protocol-Version is validated, refusing unsupported revisions with 400 and assuming 2025-03-26 when the header is absent
  • Malformed input is now refused with an HTTP error status carrying a JSON-RPC error with no id, replacing the previous 200-with-error-body behaviour
  • The deprecated HTTP+SSE transport is retained: GET .../sse advertises the message URL in an endpoint frame and POST .../messages?sessionId=… returns 202 with the response arriving on the stream
  • All transports feed the same request dispatcher, so the tool catalog, governance decisions, and audit records do not depend on how a client connected
  • Session ids are cryptographically random, and a request is accepted against a session only when its tenant, client application, and authenticated caller all match the identity that opened it
  • Idle streams receive a keep-alive signal every 15 seconds so proxies do not reap the connection
  • Sessions left idle beyond the configured timeout are reclaimed, and a per-tenant concurrent-session cap plus a dedicated rate limit bound stream growth
  • New configuration controls stream enablement, keep-alive cadence, idle timeout, session cap, queue depth, replay retention, SSE response preference, and whether sessions are mandatory, validated at startup
  • Explicit Gateway routes for the stream and message endpoints, both requiring a bearer token or API key
  • Session state and message routing are shared across all running instances, so a multi-instance deployment needs no sticky sessions at the ingress; state falls back to a single-instance-only mode when no shared cache is configured, and the Runtime warns at startup when this is the case
  • The per-tenant session cap is enforced consistently across instances, and a crashed instance's sessions cannot permanently consume a tenant's budget
  • Terminating a session on one instance closes the stream held by another, and each keep-alive doubles as a heartbeat that refreshes the shared session expiry
  • Regression coverage includes SSE framing, protocol version and origin guards, session ownership, expiry and termination, stream multiplexing rules, event ids and replay, keep-alives, disconnect handling, and full end-to-end handshakes for both transports
  • An MCP client may send an optional X-Correlation-Id; the Runtime stores it as the external correlation ID against the execution ID it generated, and echoes it back on X-External-Correlation-Id
  • The Runtime now always generates the execution ID itself instead of adopting the inbound header, so no caller can merge its audit records into another caller's execution trace
  • Every governance audit record written for a call carries the caller's correlation ID, and both the governance explorer and Call Flow explorer can filter on it and display it beside the execution ID
  • The header is accepted only as a short opaque identifier — at most 128 characters, letters, digits and - _ . : / + = @ # — with anything else discarded, so it cannot carry free-form text; no prompt content is stored or processed
  • All four client SDKs — .NET, TypeScript, Python, and Java — can send the calling application's correlation ID, either through an ambient provider callback invoked per request or as a per-call argument, and warn when the Runtime rejects the value rather than dropping it silently
  • Each toolset now chooses which correlation identifier the Runtime sends downstream — the execution ID, the caller's, the caller's falling back to the execution ID, both on separate headers, or none — replacing the previous fixed behaviour
  • Both downstream correlation header names are configurable per toolset, defaulting to X-Correlation-Id and X-External-Correlation-Id
  • A configured header name is validated when the toolset is saved and refused with a 400 if it is not a valid HTTP header field name, so a malformed name can never reach an outbound request
  • The propagation policy applies identically to REST and SOAP tools, and existing toolsets are backfilled with the previous behaviour so nothing changes on upgrade
  • Downstream authentication profiles can now select a grant profile — standard token exchange, Microsoft Entra ID On-Behalf-Of, or JWT bearer assertion — so the Runtime can obtain a downstream token in whichever shape the identity provider expects
  • Entra On-Behalf-Of lets an AI client reach Microsoft Graph, or any other Entra-protected API, as the signed-in user, with the downstream token never transiting the client
  • Existing token exchange profiles are unaffected: a profile without a grant profile behaves exactly as before
  • For assertion-based grants the Runtime checks the caller's token audience before contacting the identity provider, and reports a mismatch naming both the audience it saw and the audience it expected
  • A caller that authenticates as an application rather than a user is refused with an explanatory message, or may be routed to the application's own credentials when the profile opts in
  • Identity provider rejections now surface the returned error with an actionable hint — missing consent, wrong audience, expired assertion, invalid client secret — with the caller's token redacted out of the message
  • Whether a cached credential is shared between callers is now decided by the authentication strategy rather than by the caching configuration, so the two can never disagree
  • A credential that belongs to the signed-in user is always cached per caller, closing a gap where one caller's exchanged token could previously be served to another caller on the same tenant and profile
  • A credential that is the same for every caller is never fragmented per caller, so an application with 2000 users acquires one credential rather than 2000 identical ones
  • Credential workflows are classified individually by whether they read the caller's token or identity, closing the same cross-user caching gap for workflow-based profiles
  • Passthrough bearer authentication is no longer cached: it forwards the caller's own token and acquires nothing new, so caching it stored a live user credential for no benefit
  • The cache scope selector now offers only the scopes compatible with the selected strategy, explains the resulting isolation in words, and realigns itself when the strategy changes
  • The caching policy's time-to-live is now actually applied, as a ceiling on the credential's own expiry rather than an extension of it
  • The Portal and the API now share one consistent set of cache scope values; stored profiles are migrated to it automatically
  • Governance audit records now attribute a downstream call to the caller or to the application from the same decision that drives caching, correcting cases where cached application credentials were recorded as delegated and credential workflows were always recorded as application even when they acted on behalf of a user
  • The auth profile form gained the grant profile selector, the application-caller fallback, and the audience preflight toggle, hiding fields the selected grant profile does not use
  • Executable hosts, Portal Web, Public Site, and Runtime MCP server metadata are versioned 1.2.0-dev

Version 1.1.12 — 2026 Q3

OData and Microsoft Graph correctness release. A tool built on an OData collection endpoint returned an empty object to the AI client even though the downstream call had succeeded and returned data. Collection responses are now modelled as the envelope OData actually sends, the paging link is exposed for the first time, and tools built on nested Graph paths such as a channel's messages can be invoked at all.

Changes in this release:

  • A tool built on a nested Microsoft Graph path — a team's channels, a channel's messages, a message's replies — now asks for every identifier its path needs. Previously the parent identifier was never offered as an input, so the tool could not be called at all; the failure appeared only when an AI client first tried to use it
  • Each identifier in such a path is now named for what it identifies — a team's channel messages ask for a team id and a channel id, not two fields both called id. Every Graph entity names its identifier id, so where a path did offer one, that single value was being used for every level and the call quietly fetched something other than what was asked for
  • Paths with a single identifier — a team by id, a user by id — are unchanged and need no attention
  • Action required: a Graph or OData API whose nested navigation endpoints were imported before this release must be re-imported; the affected tools cannot be invoked as they stand
  • A tool built on an OData or Microsoft Graph collection endpoint — listing users, groups, or any entity set — now returns the entities instead of an empty object; the call had been succeeding all along, but every response field was being read from the wrong place
  • Collection responses are modelled as the envelope the protocol actually sends, with the entities under value, rather than as a bare array; this covers entity set lists, navigation collections such as a user's direct reports, and functions and actions that return a collection
  • @odata.nextLink is now available as a mappable field, so an AI client can page a result the service truncated — previously there was no way to reach the continuation link, and a large result set silently ended at the first page
  • @odata.count is likewise available for endpoints called with $count=true
  • Single-entity reads are unaffected and were never subject to this defect
  • A field path can now address a property whose own name contains a dot, which is what makes the OData annotations above mappable; paths written before this release are unchanged and keep working
  • Action required: an OData or Graph API onboarded before this release must be re-imported and its mapping re-seeded to pick up the corrected response fields and the new paging fields. Existing mappings are not rewritten automatically, because the field paths in a published mapping belong to whoever authored it
  • This release carries no database schema change
  • Executable hosts, Portal Web, Public Site, and Runtime MCP server metadata are versioned 1.1.12-stable

Version 1.1.11 — 2026 Q3

Credential workflow release. A workflow-based authentication profile can now call a standards-compliant OAuth 2.0 token endpoint, which requires a form-encoded request that its HTTP step could not previously send, and can post and read the XML envelopes that legacy enterprise token services expect.

Changes in this release:

  • An HTTP request step in a credential workflow can now send its body as JSON (as before), as form data, or as raw content under a content type the author declares
  • Form bodies unblock the OAuth 2.0 token endpoint, so client_credentials, password, refresh_token, and token-exchange flows can be expressed as a workflow for the first time
  • Raw bodies cover SOAP and WS-Trust envelopes, plain text, and other vendor-specific formats; file uploads remain unsupported, as no credential flow needs them
  • A form body is edited as a list of named fields that can be added and removed individually, each bound to a static value, a variable from an earlier step, or a secret
  • Binding a field to a secret adds a visible Read secret step to the workflow and links the field to it, so every secret a workflow touches is read by an explicit step; selecting the same secret for a second field reuses that step instead of duplicating it
  • Values are substituted into a request body before it is encoded, and values placed into an XML body are XML-escaped, so a secret is always carried as a value rather than as request structure
  • The encoded form of a secret is now redacted from audit records and logs, not only its original form
  • A JSON body containing a value with a quote or backslash no longer produces a malformed request that fails the whole credential resolution
  • A parse-response step can now read XML using an XPath expression with declared namespace prefixes, and can extract either an element's text or the whole element for tokens that must be forwarded unchanged
  • XML responses are parsed with external content and definition loading disabled, so a downstream system cannot use its response to read local files, trigger outbound requests, or exhaust memory
  • Behaviour change: a JSON request body that is not an object or array is now rejected when a workflow is saved, and the Portal reports an invalid body under the field instead of accepting it. Such a body was previously saved and sent as a bare JSON value, which no token endpoint accepts. Existing workflows continue to run, but one carrying an invalid body must be corrected before it can be saved again
  • XPath expressions and namespace declarations are validated when a workflow is saved rather than failing at the first tool call
  • Request bodies and XML responses are capped per deployment (defaulting to 64 KB), and this limit can be raised where signed assertions are large
  • This release carries no database schema change
  • Executable hosts, Portal Web, Public Site, and Runtime MCP server metadata are versioned 1.1.11-stable

Version 1.1.10 — 2026 Q3

Enrichment attachment security release. The prompt-injection scan that screens reference documents now decides what to do by how dangerous a match is, instead of rejecting an entire upload on any single match — and the model's own output is screened before it can reach a published tool description.

Changes in this release:

  • Reference documents are no longer rejected wholesale over a single pattern match: the most dangerous categories of match (instruction overrides, system-prompt reveal attempts, jailbreak phrasing, credential exfiltration attempts, and unsafe control characters) still block the upload, while lower-risk phrasing is redacted and the document is kept
  • A rejected upload now names the file and the categories of content that matched, instead of reporting only that the content "failed security scan"
  • The credential-exfiltration check now requires an external destination, so an API specification describing how a bearer token is forwarded to a downstream service can be attached; sending a credential to an outside URL or host is still blocked
  • Role-hijack style phrasing detection is more precise, so ordinary text like "you are a client developer integrating with this API" or "these fields act as filters" no longer triggers it
  • The prompt-injection scanner is more accurate at distinguishing genuine jailbreak attempts from incidental text, reducing false positives on ordinary documents
  • Redaction is applied before the extracted text is stored, so no unredacted copy is retained
  • Redactions are reported on the upload response, in the governance audit event, and as a warning on the enrichment run
  • Suggestions returned by the enrichment model are now scanned before they are saved, and any carrying an injection are dropped with a warning naming what was removed — enriched descriptions are published to AI clients that, unlike the enrichment model, can act on instructions they read
  • Pattern severity thresholds for the prompt-injection scanner are configurable per deployment; an unrecognised pattern name now fails startup rather than being silently ignored
  • Severity alone decides the outcome for every prompt-injection match; a per-document match-count override that could relax that decision has been removed
  • The database migration for this release carries no schema change; attachment records written before it remain readable
  • The prompt-injection scan now has a bounded per-pattern timeout and fails closed if it is exceeded, so text crafted to exhaust the scanner cannot stall a request or pass as clean
  • The two attachment upload endpoints now reject an oversized body at the transport layer instead of buffering a large upload before failing the 1 MB attachment check
  • The per-file extraction limit is raised from 50,000 to 500,000 characters, so a full interface specification is no longer cut mid-document with its appendices never reaching the model
  • A document exactly at the extraction limit is no longer mislabelled "Truncated" in the enrichment run detail, and the truncation warning now reports how much text was actually dropped instead of repeating the limit back
  • Executable hosts, Portal Web, Public Site, and Runtime MCP server metadata are versioned 1.1.10-stable

Version 1.1.9 — 2026 Q3

Audit delivery and governance observability release. External audit delivery gets the corrections its retry model needed — terminal failure on the last configured attempt, a bounded critical health state, and a way to put failed deliveries back on the queue — and the Portal sharpens what an operator sees on the governance dashboards.

Changes in this release:

  • An external audit delivery is now marked failed on the last attempt its target allows, instead of being scheduled for one more attempt beyond the configured budget
  • A configured attempt budget larger than the built-in retry schedule is now honoured in full rather than silently cut short
  • A permanently failed delivery raises its target to Critical for 24 hours from its last attempt, then decays to Warning until the delivery leaves audit retention, instead of holding Critical for a year
  • The critical-health window is configurable per deployment
  • Audit target health is derived in one place, so the Audit Delivery Settings page and the Monitoring Dashboard can no longer disagree about the same target
  • A permanently failed delivery can be put back on the delivery queue from the Portal: one row at a time, all failed deliveries of a target, or only those matching the filters currently applied to the target's audit events
  • Requeueing needs the Governance Manage role, is recorded as a governance audit event, and never re-sends a delivery that succeeded or one that is still being worked on
  • A requeued delivery becomes due immediately with a fresh attempt budget, and clears its target's Critical state once no failed delivery remains
  • A retrying delivery now shows when its next attempt is due, which was recorded but never displayed
  • A deployment whose compliance audit target is syslog, SQL Server, or PostgreSQL no longer records a false configuration error on every host start; the check previously looked only at REST-based targets
  • A disabled audit target now shows a single Disabled tag in its own colour instead of an amber Warning health badge beside an amber Disabled badge; being switched off is deliberate, not a fault
  • The Monitoring Dashboard's activity trend now plots Allowed and Error alongside Total and Denied, in the same colours the outcome badges use, with a hover tooltip giving each day's exact counts
  • Trend series are also distinguished by dash pattern and marker shape, so the chart stays readable for red-green colour blindness, and the chart now has its own validated colours for the dark theme instead of light-mode-only values
  • Auth profiles ask for each strategy's secret once: the duplicate "secret override" pickers for API key, Basic, SOAP UsernameToken, client credentials, and token exchange are gone, since they named the same logical secret as the profile's own secret reference
  • Client certificate (mTLS) profiles keep two secret fields, because the certificate file and its private key password are genuinely different secrets
  • Before re-saving an existing profile in the Portal, check whether its override and its secret reference pointed at different secrets — the runtime uses the override today, and saving drops it
  • The audit delivery health card reports Critical when any enabled compliance target is critical; previously every target had to be critical before the card showed it
  • Executable hosts, Portal Web, Public Site, and Runtime MCP server metadata are versioned 1.1.9-stable
  • No database changes; no migration is required

Version 1.1.8 — 2026 Q3

OpenAPI path-item parameter import fix. Contracts that declare entity keys once for a whole path — the idiomatic shape for generated specifications — imported without those keys, producing tools that failed on every call because the path value could not be supplied.

Changes in this release:

  • Parameters declared once for a whole API path are now merged into every operation of that path, with an operation's own declaration winning when it declares the same parameter itself, as the OpenAPI specification requires
  • Referenced path-item parameters now resolve correctly; only OpenAPI imports were affected, since OData derives paths and keys from a different source and SOAP operations have no equivalent placeholders
  • A significant share of paths in one real vendor contract (SAP Convergent Invoicing) were affected; their tools previously failed with a downstream error reporting a missing path parameter
  • Every import, whatever the protocol, now reports operations whose path placeholder the contract never declares as a parameter
  • Publishing a mapping whose endpoint has an unfillable path placeholder logs a warning identifying the mapping, endpoint, and missing parameters
  • The imported API's Import review panel now displays recorded import warnings, which were previously visible only during the import preview
  • The imported APIs list flags contracts that recorded import warnings with a count, so they can be spotted without opening each API
  • Mappings created before this release keep their incomplete parameter sets — re-import the API definition and regenerate the mapping to pick the parameters up
  • No database changes; no migration is required
  • Executable hosts, Portal Web, Public Site, and Runtime MCP server metadata are versioned 1.1.8-stable

Version 1.1.7 — 2026 Q3

OIDC metadata discovery and Runtime downstream-response hardening. External identity-provider probes now use the platform's centralized outbound-security boundary, and Runtime HTTP/SOAP invocations reject oversized responses before they can be fully buffered.

Changes in this release:

  • OIDC metadata requests are validated against the effective tenant/global outbound host allowlist before the request is sent
  • Every redirect destination is revalidated against the same allowlist as the original request
  • Discovery accepts only HTTPS authorities without embedded credentials, query strings, or fragments
  • Metadata responses must use a JSON content type, complete within 10 seconds, and remain within a 256 KiB streaming limit
  • Discovery and connection-test failures return a stable error code and a safe message; detailed network and parsing information remains in server-side logs only
  • Metadata discovery and connection testing require the Security Manage role
  • Response-size limits for outbound requests can now be enforced before a response body is fully buffered, rather than only after
  • Runtime HTTP and SOAP responses have an independent, configurable 16 MiB default size limit (Runtime:Downstream:MaxResponseBodyBytes)
  • Oversized declared responses are rejected based on their declared length; responses of unknown or streamed length are stopped as soon as they exceed the limit
  • Runtime callers receive a stable "response too large" error, and a corresponding metric records rejected downstream responses by protocol and cause
  • Authentication protection (failed-login tracking) is now applied asynchronously across Portal login, MFA, administrator unlock, Portal bearer, and Runtime bearer/API-key failure paths, so it adds no latency to those requests
  • Login-protection counters are updated atomically, so the lockout threshold stays accurate under concurrent attempts
  • Login and MFA enforcement fails closed if the protection store is unavailable, while alert notifications fail open only after the authentication request has already been denied
  • Account and IP identifiers used for failed-login tracking are stored as one-way fingerprints rather than in directly identifiable form
  • Persistence now separates global read-only visibility from cross-tenant write authority: a global read-only role can still view data across tenants but cannot save tenant-scoped changes, while the ability to write across tenant boundaries remains limited to the platform's highest administrative role
  • Vendor OpenAPI contracts with templated OAuth flow URLs (for example, a host and port left as placeholders) now import instead of failing with a URL parsing error
  • Unparsable URL fields are removed before reading and reported as import warnings; a remaining failure returns an actionable, stable error code
  • Non-structural import warnings no longer cause a whole contract to be rejected over minor quirks, such as server variables declared with empty defaults
  • Schemas that declare more than one possible shape for a field now resolve to a concrete type, so previously untyped fields (for example, a numeric field also allowed to be a string) now import with a proper type
  • Server-variable defaults are substituted into the stored server URL, and a still-templated URL is flagged as needing a configured downstream base URL
  • Generated tool names that exceed the length limit are shortened using a suffix derived from the full name, so entity-oriented contracts no longer fail to save over duplicate normalized names
  • Endpoint names already within the limit are unchanged, so existing mappings keep their tool names
  • Semantic enrichment no longer omits fields: payloads larger than one prompt are split across multiple prompts instead of being truncated, so a large contract cannot arrive with only its first fields named
  • Fields of a shared type (an OpenAPI component, OData type, or SOAP/XSD type) are enriched once and applied to every operation that uses it, cutting repeated work and preventing the same field being named differently in different operations
  • SOAP header and fault fields are now enriched; they previously became field mappings without ever being shown to the enrichment model
  • Field descriptions carry their owning type's identity, so the schema name the model is asked to return is grounded in real schema information instead of guessed
  • Suggestions from every prompt covering an operation are combined rather than replaced, and any field left without a suggestion is reported as a warning
  • New "Enrichment advanced settings" panel on the create-mapping and request-enrichment dialogs exposes prompt budget, fields per prompt, operations per prompt, and shared-schema enrichment, with platform defaults when left blank and validated bounds
  • Per-run enrichment settings are stored with the run, so an interrupted run resumes with the sizing it started with
  • Endpoint names proposed by the model are made unique automatically, so a proposal that names two similar operations identically no longer fails the whole enrichment run
  • A proposal that violates a business rule now fails the run with the reason recorded, instead of being retried indefinitely while the run sits at 100%
  • Executable hosts, Portal Web, Public Site, and Runtime MCP server metadata are versioned 1.1.7-stable

Version 1.1.6 — 2026 Q2

Downstream client certificate (mTLS) authentication. Administrators can now bind a downstream target authentication profile to a client certificate, so the Runtime authenticates to the downstream API via mutual TLS instead of a bearer token or header.

This release also makes semantic enrichment resilient to interruption. An enrichment run that stops partway — a worker crash, or a run outliving the message broker's delivery window — is now detected, re-queued, and resumed from the last completed chunk, instead of leaving the mapping locked with a frozen progress bar and no error.

Changes in this release:

  • New client certificate downstream authentication strategy, alongside the existing API key, Basic, bearer, OAuth, workflow, and SOAP strategies
  • Auth profile form: upload a certificate file directly, select the secret holding its private key password, and optionally enter an expected certificate thumbprint
  • Uploading a certificate creates a new secret in the existing secret store and selects it automatically — no separate binary-secret workflow to learn
  • Client certificates are presented on the TLS handshake for both REST/OpenAPI/OData tools and SOAP tools
  • Governance audit captures for client-certificate-authenticated invocations never contain the certificate or password material
  • Mapping editor: editing is now strictly limited to Draft/Proposed mappings (no more silent auto-clone-to-draft on Approved/Published), and "Cancel draft" is now "Cancel version," available from Draft through Approved
  • Mapping editor: semantic enrichment warnings are shown as their own alert instead of being folded into the change-summary text, and reference attachments can now be attached when creating a mapping proposal, not just when re-requesting enrichment
  • Trusted Identity Providers page redesign: a sectioned provider details view, a searchable claim mapping profile picker, a combined name-or-issuer search box, and refresh/loading indicators matching the rest of the portal
  • The built-in platform identity provider (used for device flow and web session sign-in) is now flagged as a system provider and shown with a "System" badge; it can no longer be edited or deleted from the admin UI
  • Claim Mapping Profiles page redesign to match: a sectioned profile details view (claims shown as badges instead of raw JSON), a redesigned enabled/disabled toggle, a debounced server-side name search, and the same refresh/loading indicators
  • The built-in "default" global claim mapping profile is now flagged as a system profile and shown with a "System" badge; it can no longer be edited or deleted from the admin UI
  • Credential Workflows page refresh: debounced name search, a searchable tenant filter, and refresh/loading indicators matching the rest of the portal
  • Credential Workflows step editor: bigger, easier-to-hit move-up/move-down/delete buttons; the final "build credential set" step's collapsed summary now shows extra headers/query parameters/cookies when no auth scheme is selected, and this step must now be the workflow's last step, enforced automatically by the editor
  • Fixed a shared searchable-dropdown bug where an open menu pushed surrounding layout taller and could render behind other panels, affecting every page using the searchable tenant/entity picker
  • Secret Store page refresh: debounced name search, refresh/loading indicators, and an "Add connection" button matching the other primary create actions
  • Secret Store grid: Store info, Created at, and Updated at are now combined into a single Details column placed after Tenant, matching the more compact activity-column layout used elsewhere
  • Secret details modal redesign: a sectioned view (store type and tenant scope badges, then a details grid) instead of a flat key/value list with raw JSON
  • Key Vault connection modal: the Enabled checkbox is now a labeled toggle card consistent with the enabled/disabled switches used on other pages
  • Outbound Allowlist page refresh: debounced host/name search and refresh/loading indicators matching the rest of the portal
  • Outbound Allowlist grid: the Description column was dropped in favor of showing the description beneath the entry name, and Subdomains/Status are now badges instead of plain text
  • Allowlist entry details modal redesign: a sectioned view (active/scope/subdomains badges, then a details grid, then the description) instead of a flat key/value list with raw JSON
  • Create/Edit allowlist entry modal: the Allow subdomains and Entry active checkboxes are now labeled toggle cards consistent with the enabled/disabled switches used on other pages
  • LLM Connections page refresh: connection name/status/provider filtering moved server-side with a debounced name search, plus refresh/loading indicators matching the rest of the portal
  • LLM Connections: new connection details view — a sectioned, read-only summary (scope/status badges, provider, credential handling, model profiles, tenant assignments, timestamps) opened from a new "View details" row action
  • LLM Connections: the tenant assignments "Remove" action is now a proper button instead of a link-styled button, and the connection/model profile Enabled checkboxes are now labeled toggle cards consistent with other pages
  • Client Applications page refresh: debounced name/client ID search and refresh/loading indicators matching the rest of the portal
  • Client application details modal redesign: a sectioned view (status badge, tenant, timestamps, then dedicated description and system prompt sections) instead of a flat key/value list with raw JSON
  • Create/Edit client application modal: the Active checkbox is now a labeled toggle card consistent with the enabled/disabled switches used on other pages
  • API Key management page refresh: debounced name/description search and refresh/loading indicators matching the rest of the portal
  • API key details modal redesign: a sectioned view (overview with status badge and timestamps, description, and claims shown as badges) instead of a flat key/value list
  • Edit API key modal: the Active checkbox is now a labeled toggle card consistent with the enabled/disabled switches used on other pages
  • Target Systems page refresh: debounced name search and refresh/loading indicators on both the target systems grid and the auth profiles grid, matching the rest of the portal
  • Target system and auth profile details modals redesign: sectioned views with status/strategy/tenant badges instead of a flat key/value list, and the auth profile modal now shows the strategy's additional configuration and credential caching settings as structured fields instead of raw JSON
  • Create/Edit target system and auth profile modals: the Active checkbox is now a labeled toggle card consistent with the enabled/disabled switches used on other pages, and the auth profile form's raw-JSON "Preview generated configuration" section has been removed
  • Tools Management page refresh: debounced mapping/toolset name search and refresh/loading indicators matching the rest of the portal
  • Tools Management: new read-only toolset details view — a sectioned summary (identity, default downstream settings and policy, client assignments, per-endpoint effective routing and access policy) opened from a new "View details" row action, available to every user regardless of manage access
  • Updated inline help content for the Client Applications, API Key management, Target Systems, and Tools Management pages to describe the new search, refresh, details, and toggle behavior
  • Monitoring Dashboard: the Reset filters and Search buttons now show icons, the audit table groups Category and Action into a single column, and the audit event detail view is now organized into sections (Overview, Actor, Request context) with status/category/action shown as badges instead of a flat field list
  • Monitoring Dashboard: audit event dimensions that contain JSON-encoded values are now pretty-printed instead of showing as a raw string
  • Monitoring Dashboard: CSV/JSON export now asks for confirmation before running when the matching result set is larger than the 200-row export limit, stating the total match count so a truncated export is never triggered by mistake
  • Updated inline help content for the Monitoring Dashboard to describe the new column layout, detail view, and export truncation confirmation
  • Enrichment Dashboard: the Reset filters and Search buttons now show icons, matching the Monitoring Dashboard
  • Enrichment Dashboard: added a Tenant column using the shared tenant display, and combined the Status and Progress columns into a single "Status & Progress" column
  • Enrichment Dashboard: added a selectable auto refresh interval (off, 3, 5, 10, 30, or 60 seconds); each refresh is now scheduled after the previous request finishes instead of on a fixed clock, so a slow request can no longer overlap the next poll
  • Updated inline help content for the Enrichment Dashboard to describe the new Tenant and Status & Progress columns and the auto refresh control
  • Call Flow page: the Reset filters and Search buttons now show icons, matching the Monitoring and Enrichment dashboards
  • Call Flow page: added a Tenant column using the shared tenant display, and combined the Type and Tool/Mapping columns into a single column
  • Updated inline help content for the Call Flow page to describe the new Type/Tool/Mapping and Tenant columns
  • Semantic enrichment now survives interruption: a run that stops because its worker crashed, or because the message broker withdrew the job for running longer than its maximum unacknowledged time, is automatically re-queued and resumes from the last completed chunk instead of restarting from the beginning
  • Enrichment runs report liveness on a timer while they are being processed, so a run that is merely slow is no longer mistaken for one that has stopped
  • A run whose worker is still running but stops making progress — stuck waiting on an LLM call that never returns — is now detected as hung and recovered, instead of appearing healthy indefinitely
  • Recovery signals the stuck attempt to stop before re-queueing the run, so an abandoned run stops consuming its LLM budget
  • Every completed enrichment pass is now recorded, so a resumed run only pays for the chunks it never finished — a 29-chunk run interrupted after 7 chunks resumes at chunk 8
  • A scheduled sweep releases enrichment runs that cannot be recovered, marking them failed with the number of chunks completed and unlocking the mapping, so a wedged run no longer needs manual database intervention
  • The sweep also reports how many enrichment runs are in progress and how recently each reported liveness, making a slow run distinguishable from a stuck one in the logs
  • The message broker's maximum unacknowledged-delivery time was raised from 30 minutes to 3 hours, so a long enrichment run against a slow LLM is no longer withdrawn mid-run

Version 1.1.5 — 2026 Q2

OData/CSDL + Microsoft Graph API onboarding. Administrators can now onboard OData v4 services — including Microsoft Graph — as first-class imported APIs alongside OpenAPI and SOAP/WSDL, with a shared preview/curation workflow that also now protects OpenAPI and WSDL imports from metadata explosion.

Changes in this release:

  • New OData contract protocol with Generic and Microsoft Graph import styles; CSDL metadata can be imported from uploaded content or a remote metadata URL
  • OData metadata is parsed into a full semantic model (entity types, complex types, enums, entity sets, singletons, navigation, actions/functions) before translation, so OData semantics survive rather than being flattened directly into the import model
  • Entity sets and singletons generate constrained create/read/update/delete operations that respect the service's own declared capability restrictions — read-only entity sets no longer get mutating tools generated for them
  • Bound and unbound actions and functions become first-class operations; single-hop navigation properties can be optionally included
  • The Microsoft Graph import style applies Graph-aware naming, permission hints, and conservative v1.0-only defaults
  • New standardized curation stage shared by OpenAPI, WSDL, and OData imports: an operation deny-list, an allow-list/explicit-selection mode, a tag/group allow-list, a path-prefix allow-list, a maximum-persisted-operation-count guardrail, and a mandatory explicit-selection step for oversized contracts, enforced before anything is persisted
  • New Portal import UX: an import-style selector, a "Preview operations" action showing the full candidate catalog with inclusion/exclusion reasons, and a selection checklist for committing only the chosen operations
  • Enum members, entity keys, and optimistic-concurrency tokens are now preserved on the imported schema instead of being flattened to plain strings
  • Endpoint identifiers remain stable across re-imports, so mapping version upgrades correctly preserve endpoint identity when a contract is re-imported
  • Structured logs, import metrics, and governance audit entries for every import mode, including the two new-version import endpoints, which previously had no audit coverage
  • Hardened CSDL metadata parsing against XML external-entity attacks; remote metadata fetches continue to go through the platform's outbound security checks

Version 1.1.4 — 2026 Q2

Device Authorization Grant (RFC 8628) plus browser-based runtime OAuth authorization hardening. AI agents and CLI tools can now authenticate and receive portal-equivalent credentials through operator-approved browser flows, and the browser authorization path now supports external-provider sign-in, MFA, and explicit consent.

Changes in this release:

  • Agents call a new initiation endpoint and receive a short user code (XXXX-YYYY) to display to the operator alongside a verification URL
  • A new /device page in Portal.Web lets operators look up the active session, sign in if not already authenticated, and approve or deny the request with a single action
  • The agent polls a dedicated token endpoint and receives an access token and refresh token once the operator approves
  • Runtime OAuth browser authorization now reuses the full Portal login experience instead of a separate minimal login page
  • OAuth authorization requests survive external-provider redirects, MFA verification, and tenant/context handoff so the flow can complete for accounts that require those steps
  • Already-authenticated operators must explicitly confirm runtime access before the authorization callback is completed
  • All device flow events — initiated, approved, denied, and token issued — are written to the governance audit trail with a shared session identifier for lifecycle correlation
  • Stale sessions (pending past expiry) are expired nightly; terminal sessions are purged after a configurable retention window by the existing data lifecycle job
  • Revoking a session — from the Portal UI, an administrator action, or an automatic response to detected refresh-token theft — now takes effect immediately against the Runtime, not just against future token refreshes. A revoked session's access token is rejected on its next use, on every host, rather than remaining valid until its own natural expiry

Version 1.1.3 — 2026 Q2

Semantic Enrichment Attachments. Administrators can now attach reference documents to an enrichment request to give the LLM additional context beyond the imported API definition.

Changes in this release:

  • Attach up to 5 reference files (.txt, .md, .pdf) per enrichment request with a combined size limit of 1 MB
  • Uploaded content is automatically scanned for prompt injection before the enrichment job is submitted; suspicious content is rejected before any processing begins
  • Reference documents are distilled once into a compact glossary, and only the entries relevant to each operation are injected into that operation's LLM pass — keeping large documents within the prompt budget instead of re-sending them on every chunk (configurable; falls back to verbatim injection)
  • File names, sizes, and content fingerprints are recorded on the enrichment run and visible in the run detail view
  • Attachment controls are available in both the standalone enrichment request modal and the new-version enrichment flow in the mapping editor
  • Files can be added across multiple picks and removed individually before submitting

Version 1.1.2 — 2026 Q2

Mapping annotation hint management. Administrators can now set MCP behavioral annotation hints per endpoint directly in the mapping editor, receive LLM-inferred hints through the semantic enrichment pipeline, and review proposed hints in the enrichment proposal panel before applying them to the draft.

Changes in this release:

  • Four per-endpoint annotation hints: Read-only, Destructive, Idempotent, and Open-world — each tri-state (Yes / No / Not set)
  • New "Endpoint annotation hints" enrichment target in the semantic enrichment request modal
  • LLM prompt and response schema updated to generate and receive annotation hints
  • Annotation diffs shown in the enrichment proposal panel alongside name and description changes
  • Inline help updated with annotation hint field documentation

Version 1.1.1 — 2026 Q2

MCP 2025-11-25 protocol compliance. The Runtime now advertises and implements the full MCP 2025-11-25 specification, including prompts, cursor-based pagination, and tool annotation hints on the wire.

Changes in this release:

  • Protocol version bumped to 2025-11-25 on the MCP initialize response
  • New ping handler returning an empty object as required by the specification
  • prompts/list and prompts/get expose toolset system prompts as user-controlled prompts (slash-command / menu items) alongside the existing resources surface
  • Tool annotation hints (readOnlyHint, destructiveHint, idempotentHint, openWorldHint) emitted on the MCP wire for each tool; per-toolset annotation overrides configurable from the Portal
  • Cursor-based pagination on tools/list, resources/list, and prompts/list with configurable page sizes

Version 1.1.0 — 2026 Q2

API Onboarding Versioning release. Introduces API definition families that group multiple imported versions of the same downstream API, per-revision version labels and current-version designation, version compatibility reports, version-aware mapping draft creation that preserves endpoint IDs where operations match across API versions, and durable external governance audit delivery.

Changes in this release:

  • API definition families with multi-revision tracking and current-version promotion
  • Import new API version flow (URL and content) with version label and set-as-current options
  • Family Versions panel on API cards listing all revisions
  • Version compatibility view comparing two revisions with breaking-change classification
  • Delete protection for imported API definitions referenced by mapping versions
  • API-version-targeted mapping draft creation with endpoint identifier stability
  • External audit delivery fan-out with REST, syslog, SQL Server, and PostgreSQL compliance targets plus operational target monitoring/management in the Portal

Version 1.0.0 — 2026 Q1

First stable release. Full foundational platform including Portal, Portal API, Runtime, Jobs Worker, Gateway, and Database Migrator. Multi-tenant architecture, OpenAPI and SOAP/WSDL import, mapping proposal workflow, LLM-powered semantic enrichment, MCP toolset authoring, downstream authentication strategies, governance audit trail, area-based role model, and external identity provider federation.