Skip to main content
Changes on main that are not yet part of a tagged release.

Upgrade notes

  • Automation that changes a connector’s URL, an OAuth client’s client ID or token endpoint, an identity provider’s client ID, issuer or token URL, or the SMTP host or port must now send the secret again in the same request; an update that leaves it blank while a secret is stored is refused with invalid_argument (see Security below).
  • On a deployment with more than one replica, finish rolling out this version before adding or editing an identity provider or OAuth connector: an older replica doesn’t serve the new sign-in, connector callback and connect-page addresses, and sends the shared callback for providers and connectors that have their own. For the same reason, a provider or connector added or changed on this version doesn’t sign in or connect after rolling back to an older one.
  • The oauth_redirect_uri that ListIdentityProviders and ListConnectors return is now only the callback that providers and connectors added before this version are registered with. Register each provider’s redirect_uri or each connector’s oauth_redirect_uri instead.
  • The Conduit CLI’s local-connector endpoints (AuthorizeLocalTool, ReportLocalEvent, ListEnabledLocalConnectors) now refuse every OAuth client other than the Conduit CLI.

Security

  • A workspace’s identity provider could take over accounts that sign in through another provider. Every provider shared one sign-in redirect URI, and the callback trusted the sign-in state to say which provider a response came from. An identity provider run by a workspace admin could start a victim’s sign-in, send them on to an honest provider (Google, or another workspace’s provider), and receive the honest provider’s code for their account — an IdP mix-up — which it could use to sign in as them, instance admins included. Each provider now has a redirect URI of its own (/api/auth/callback/<key>, shown on the provider screen), a response is accepted only on the URI of the provider its sign-in started with, and a response that names its issuer must name that provider.
  • A connector’s authorization server could capture a member’s grant for another connector. Every connector shared one OAuth callback URL, so a connector whose authorization server a workspace admin runs could pass a member’s connect flow on to another connector’s authorization server and receive the resulting code. Each connector now has a callback URL of its own (/upstream/callback/<key>, shown on the connector’s form), a connect response is accepted only on the URL of the connector it was started for, and one that names a different authorization server than the connector’s is refused.
  • Outbound requests could reach internal IPv4 addresses through IPv6 translation. A connector, identity provider or telemetry endpoint whose hostname resolved to a NAT64 or 6to4 address (such as 64:ff9b::a9fe:a9fe) passed the internal-address check, and on a network with NAT64 — common on IPv6 cloud subnets — reached the IPv4 address inside it, including the cloud metadata service. Conduit now checks the IPv4 address such an IPv6 address carries, and refuses the deprecated and local-use IPv4-embedding ranges outright.
  • A workspace identity provider’s discovery document could run script on the Conduit origin. The authorization endpoint a provider’s issuer published was used as the sign-in redirect without being checked, so an issuer run by a workspace admin could answer with a javascript: URL that anyone opening that workspace’s login page would execute (the default content security policy blocked it; CONDUIT_CSP=report-only or off did not). Discovered authorization and token endpoints are now held to the same rule as ones an admin types in — https, not an internal address — and a provider that publishes anything else fails sign-in with “Couldn’t reach the identity provider”.
  • A workspace’s MCP client rules could be bypassed from another workspace. “Who can connect”, per-app rules and client revocations held only at the workspace’s own MCP URL, so a client it refused could still use workspace tools against it through a connection to another workspace, and any MCP client — not just the Conduit CLI — could fetch the member’s local (stdio) connector definitions, environment secrets included. The rules now apply wherever a client acts in the workspace (and such a client shows up on its MCP Clients page), and only the Conduit CLI can call the local-connector endpoints.
  • A connect link could connect your account to a different workspace. The link an assistant gives you to connect an account (an OAuth sign-in, an API token, or a Pipedream app) used whichever workspace your browser was last switched to — which another site could change — rather than the workspace the assistant was using. A member of more than one workspace could have their account land in another workspace’s connector or Pipedream project. Connect links now name their workspace, every connect step acts in that workspace, and the connect page shows which workspace you’re connecting to. A link for a workspace you aren’t a member of connects nothing.
  • An admin could redirect a stored secret they can’t read. Changing where a secret is sent — a connector’s URL, an OAuth client’s client ID or token endpoint, an identity provider’s client ID, issuer or token URL, or the SMTP host or port — kept the stored secret when its field was left blank, so a co-admin or an API client with connectors:write could have Conduit send it to a host they control; these edits now require the secret to be re-entered. An instance telemetry exporter moved to a new endpoint or protocol now drops its stored headers, as a workspace exporter already did. Repointing a connector also discovers an MCP connector’s OAuth provider again for the new URL and cancels connect flows already in progress.

Changed

  • The workspace menu shows Switch Workspace only when you belong to another workspace, and Create Workspace only when you’re allowed to create one.
  • The login, invite and join pages use full-width buttons, and provider buttons read Continue with the provider.
  • On a browser that hasn’t signed in before, the login page says Sign up to continue when it offers a sign-in provider, since a provider’s first sign-in creates the account.

Fixed

  • Dialogs in the web UI are back to a comfortable width, consistent across the app, and a dialog taller than the window scrolls instead of running its buttons off the bottom of the screen.
2026-10-01
The docs move to Mintlify and gain a cloud edition, API client settings are redesigned, and the CONDUIT_DOCS_URL default changes.

Upgrade notes

  • The default CONDUIT_DOCS_URL is now https://pipedream.com/docs/conduit, and in redirect mode /docs/ no longer adds a version to the path. If you relied on the old default, https://conduit.pipedream.com/docs, set CONDUIT_DOCS_URL explicitly.

Added

  • CONDUIT_DOCS_EDITION selects which edition of the embedded docs /docs/ serves: self-hosted (the default, the full docs) or cloud.

Changed

  • The docs are rendered with Mintlify and published at pipedream.com/docs/conduit.
  • The image is about 70 MB larger.
  • Docs URLs no longer end in a slash. An old URL with a trailing slash redirects to the new one.
  • The changelog is one page, with an anchor for each release (for example, /docs/changelog#v0-13-4). Old per-release changelog URLs, /docs/deploy/load-tests and the old API operation pages redirect to their new location.
  • Settings → API Clients lists clients in a table and manages each client’s scopes and credentials from its row menu. A client’s credentials dialog shows its client ID and token endpoint together, and revoking a credential asks for confirmation first.
  • A newly created client secret or SCIM token is hidden until you choose to show it, and can be copied without revealing it.
  • The Admin API is now called the API in the web app and the docs, and its pages moved to /docs/use/api and /docs/use/api-reference. The old addresses redirect to the new ones.
Compare v0.13.4…v0.14.0
2026-09-30
Instance-wide help instructions, display names from your identity provider and editable by members and admins, workspace slugs removed, and OAuth endpoint error fixes.

Upgrade notes

  • Workspaces no longer have a slug. The slug fields are gone from the Admin API (UpdateWorkspace) and from every workspace in RPC and MCP tool responses. An RPC client that still sends one has it ignored; an MCP tool call that passes one is refused as an unknown argument. No migration runs, so upgrading and rolling back are unaffected.
  • Help instructions are now set once for the whole instance, not per workspace. A database migration, run automatically on boot, keeps the existing text when the instance has exactly one workspace (every single-workspace instance). An instance with more than one workspace starts with none, even if only one workspace had instructions, so one workspace’s text is never shown to everyone: an instance admin sets them again from ? → Edit. Help edited while an upgrade is rolling out, or before a rollback, may be lost. GetSession reports helpSet in place of activeWorkspaceHelpSet, in RPC and MCP tool responses.

Changed

  • Only instance admins can edit the help instructions (? → Edit), and every signed-in user sees the same instructions, in every workspace or none. Workspace owners and admins who aren’t instance admins can no longer edit them.
  • A new account’s display name comes from the identity provider’s name claim, or its given_name and family_name claims when name is absent. With none of them, or when accepting an invite without a name, the name is the part of the email address before the @, as before, and a later SSO sign-in that asserts a name replaces it. Names set in Conduit are never replaced. A database migration, run automatically on boot, records where each name came from; existing names are treated as set in Conduit.
  • Anyone can change their own name from the account menu (Edit profile), or with the UpdateMyProfile RPC, except someone SCIM provisions: their directory owns their name.
  • Workspace admins can rename members in Settings → Members, or with the UpdateWorkspaceMemberName RPC and its builtin MCP tool, when the member signs in through one of the workspace’s own identity providers, isn’t provisioned by SCIM, and doesn’t outrank them. The members list shows why a rename isn’t available, and ListWorkspaceMembers reports it per member (name_edit; unset for API clients, which can’t rename). The member actions now sit in a menu next to Review access.
  • A personal workspace, created for a new account at its first SSO sign-in in multi-workspace mode, is now named “Personal”.
  • Workspaces are identified by name alone in the web app: the slug field is gone from workspace settings, Create Workspace and the instance admin’s workspace editor. Settings → Workspaces (instance admin) shows each workspace’s owner under its name, and its search matches owner emails as well as names.
  • The unauthenticated GetSetupStatus RPC is gone; GetAuthMethods reports whether first-run setup is still needed (needsSetup).
  • Refreshed the web UI’s components: confirmation dialogs can’t be dismissed by a backdrop click or while their action is running and open as a bottom sheet on small screens, the audit log’s filters form a single toolbar, and IDs in an audit event’s details copy with a click.

Fixed

  • OAuth error responses from the token, device authorization and client registration endpoints carry Cache-Control: no-store, as client-credentials errors already did. An internal failure at these endpoints is a 500 server_error rather than a 400; a database failure while looking up a device code or the user behind a grant was reported as invalid_grant. A client registration refused because the instance has reached its registered-client limit is a 503 temporarily_unavailable rather than a 400 invalid_client_metadata.
Compare v0.13.3…v0.13.4
2026-09-29
Tidier traces: API and SQL spans are renamed for easier monitoring, background jobs and auth checks nest inside the requests that cause them, and first-run setup is atomic.

Upgrade notes

  • API request spans are named for the RPC — conduit.v1.ConduitService/GetUserUsage rather than GET /conduit.v1.ConduitService/GetUserUsage — with the bare method (GetUserUsage) as their resource.name. APM monitors, dashboards or saved views that match the old span or resource names need updating; http.route and the http_server_request_duration_seconds metric’s http_route label are unchanged.
  • Database statement spans from generated queries are named with a sql. prefix — sql.GetUser rather than GetUser — so they are easy to tell apart from API request spans. Monitors or dashboards matching the old names need updating.

Changed

  • API request spans carry rpc.system (connect_rpc), rpc.service and rpc.method on every call, not only on failures.
  • The instance liveness heartbeat, written every 30 seconds, no longer exports a trace for each of its database statements to instance telemetry exporters.
  • The session check that runs on every signed-in request now appears inside that request’s trace, instead of exporting as a separate one-span trace per request.
  • Opening a new Postgres connection, including building an RDS IAM token, is its own postgresql.connect span in the trace of the request that needed it, instead of counting toward that request’s first query.
  • With Postgres, an unused database connection now stays open for 30 minutes (previously 5) before Conduit closes it, so the first page load after a quiet stretch no longer waits on new connections.
  • Issuing an OAuth access token (authorization code, refresh, device and client-credentials grants) records its database work inside the token request’s trace, instead of as several separate one-span traces per token.
  • With Postgres, counting a failed sign-in, MCP, SCIM or API-client authentication attempt toward its cluster-wide throttle is recorded inside that request’s trace, and the counters’ periodic cleanup no longer exports a trace each time it runs.
  • When an access or connector change notifies connected MCP clients, each recheck of their access is one mcp.notify.access_changed or mcp.notify.lists_changed trace, linked to the change that caused it, instead of separate one-span traces for every connected member’s database reads. Log-level lookups for forwarded connector log messages, and recording which MCP clients reach a workspace, are traced inside the request that caused them.
  • The hourly sweep of expired OAuth codes, tokens and sessions is exported as one oauth.cleanup trace with its database statements beneath it, instead of a separate trace for each statement.
  • With several replicas on Postgres, what each other replica does in response to a change (clearing caches, notifying its connected MCP clients) appears in the trace of the request that made the change, under a cluster.dispatch span. The cache rebuild after a replica’s event listener reconnects is one cluster.resync trace.
  • Completing first-run setup creates the admin account, its password and the default workspace in one transaction, so an interrupted setup leaves nothing behind and can be retried. Setup, password rotation and break-glass sign-in record their database work inside the request’s trace.
Compare v0.13.2…v0.13.3
2026-09-28
Email sender settings save on their own, gRPC exporters with https endpoints use TLS for logs and metrics, and signing in returns you to the page you opened.

Upgrade notes

In a multi-replica deployment, saving only the email sender through a replica still on the previous version turns email off. After the rollout, check Settings → Instance → Email and save the provider again if it’s off.

Changed

  • The email settings page shows the from address and name once, above the providers, instead of in every provider’s section, and they can be saved on their own with Save sender.
  • Updating email settings through the UpdateEmailConfig RPC or its builtin MCP tool keeps the active provider when a request omits provider, so a request can change just the sender or a provider’s settings; enabled: false turns email off, and a request that names a provider alongside it, sets enabled: true with no provider, names an unknown provider, or gives a from address that isn’t one bare address (with email off too) is refused. The enabled a response reports always agrees with its provider.
  • Instance telemetry settings refuse an exporter endpoint that isn’t an http:// or https:// URL with a host, since the scheme is what picks plaintext or TLS.

Fixed

  • Logs and metrics sent to an instance gRPC exporter with an https endpoint now use TLS instead of plaintext, which the collector refused.
  • Opening a Conduit page while signed out, such as a connect link from an MCP client, returns to that page after signing in instead of the home page.
Compare v0.13.1…v0.13.2
2026-09-28
Email settings are validated so they can’t be saved in a state that fails to send, multi-replica deployments deliver config changes, cancellations and prompt answers reliably, and concurrent first SSO sign-ins no longer fail.

Upgrade notes

None.

Changed

  • Email settings have their own entry in the admin sidebar and a docs page.
  • Each email provider’s settings are shown inline in their own section, with the active one outlined and marked Active, so another provider can be checked or filled in while the active one keeps sending, and saving that provider’s form switches all email to it.
  • Turning email off asks for confirmation and keeps every provider’s saved settings, so switching back doesn’t mean entering them again.
  • The Amazon SES region is chosen from a list of SES regions, or typed in as a region code under Other region….
  • Recording usage no longer sends your telemetry backend a separate one-span trace for each statement it writes (at least one per MCP tool call, prompt or resource read), and each usage rollup or retention pass is now one trace with its statements beneath it instead of a trace per statement. A rollup check that finds nothing new sends no trace, and a failed rollup or retention pass is reported to error tracking as a conduit.usage.maintenance_failed issue.
  • MCP tool listings and Pipedream tool calls no longer read and decrypt the workspace’s Pipedream settings on every request, including in workspaces that never set Pipedream up.

Fixed

  • Email settings that can’t send are now refused instead of saving and then failing every send (invites included), including an edit to saved settings that already can’t send: a from address that isn’t one bare address, SMTP without a host or a port from 1 to 65535, Resend without an API key, or SES without a valid region code or access key.
  • The email settings page now warns when the active provider’s saved settings are missing something they need to send, such as the SES region whose absence made sends fail with a DNS error for email..amazonaws.com.
  • Saving email settings while the stored settings can’t be read now fails with an error instead of clearing every field the save didn’t include, saved SMTP, Resend and SES credentials among them.
  • Two first sign-ins through the same identity provider at the same moment (for example, in two tabs) now both land on one account, instead of the second failing with an error and leaving a stray, unusable user behind.
  • In multi-replica deployments, a change saved just as its client disconnected is no longer dropped before reaching the other replicas, which then kept serving stale connector lists and telemetry exporters until the next change, and stale access for up to 30 seconds.
  • In multi-replica deployments, an MCP cancellation now reaches the replica running the request, and a prompt answer reaches it at once rather than up to 15 seconds late, even when the client exits right after sending it.
  • In multi-replica deployments, saves no longer stall when a replica’s event connection to Postgres hangs; each waits at most 5 seconds for it.
  • Finishing a connector sign-in now completes the MCP client’s pending prompt even when the browser leaves the page right away.
  • On Postgres, the audit log lists events recorded in the same second newest first, in one fixed order, so paging through a log that isn’t changing no longer shows them out of order or repeats or skips them.
  • The MCP endpoint and the API now accept a bearer token whose scheme is written in any case (the token endpoints answer token_type: "bearer", which some clients echo into their Authorization header) or that has extra spaces before it, as SCIM already did, instead of refusing it as unauthenticated.
  • A member’s Pipedream connection no longer keeps using a workspace’s old Pipedream settings after they change while the member’s request is in flight, and in multi-replica deployments a replica that missed the change picks it up within 30 seconds.
  • Log records from background work that isn’t traced no longer carry a trace id that no trace in your backend matches.
Compare v0.13.0…v0.13.1
2026-09-27
The first big release in preparation for Conduit Cloud: workspaces own their email domains, sign-in methods and login pages, invites replace the join policy, and telemetry keeps member content and identity out — read the upgrade notes before pulling.

Upgrade notes

Creating or updating a workspace through the Admin API or the MCP workspace tools refuses a slug that isn’t lowercase letters, numbers, and single hyphens; existing slugs are kept until changed.A connector tool with invalid x-mcp-header annotations stops being listed after the upgrade (it was previously offered with the annotations removed). The server log names each such tool and why; the connector’s provider needs to fix the tool definition for it to return.Email domains move from each workspace identity provider to the workspace. The migration carries every domain over with its verification and the provider it signs in through. While a rolling upgrade runs, a domain change made through a replica still on the previous version is lost, and replicas still on the previous version keep routing domains as they were before the upgrade. Rolling back to the previous version shows domains as they were before the upgrade until you upgrade again.In a multi-workspace deployment, the login page sends an email at a domain a workspace has verified to that workspace’s provider, and offers the password field for it only when that provider can’t be reached. If CONDUIT_ADMIN_EMAIL (the break-glass login) is at such a domain, change it to an address no workspace verifies, such as the default admin@localhost, so break-glass sign-in doesn’t depend on that provider being down. The same holds for any password account at a verified domain.The workspace join policy is removed. People become members of a workspace through its own identity provider at its domains, an invite, or SCIM, so a workspace set to let anyone signed in join, to admit a join link, or to admit people at an email domain no longer does. Members are unaffected. An invite reaches only a domain the workspace has verified or the inviting admin’s own, and needs email set up; people elsewhere, such as contractors at another company or at a public email service, join through SCIM. A domain the workspace held only to admit joins (unverified, signing in with no provider) is removed from its Domains. While a rolling upgrade runs, replicas still on the previous version keep admitting joins by the join policy; rolling back restores it, though not settings:read on API clients.A session signed in through an identity provider stops working when the provider is disabled or deleted, and one signed in by password stops working when password sign-in is turned off (an instance admin’s excepted), in the web app and in MCP clients. Every workspace otherwise accepts every sign-in method until an admin changes that. Sessions and MCP tokens from before the upgrade recorded no sign-in method, so turning off a provider or password sign-in doesn’t end them: they last until they expire (an MCP client’s refresh token renews for up to 90 days at a time). To end them sooner, for instance when turning off a compromised provider, set a re-authentication age on each workspace (Settings → Sign-in → Sign-in methods), which asks every holder of such a session to sign in again; so does a workspace narrowing its methods. Instance admins aren’t subject to a workspace’s sign-in methods.Admin API clients: some identity provider and workspace fields change incompatibly. IdentityProvider.domain_status is removed; read a domain’s verification from ListWorkspaceDomains (sso:read). VerifyIdentityProviderDomain and its verify_workspace_idp_domain tool are removed in favor of VerifyWorkspaceDomain. CreateIdentityProvider refuses a workspace provider with no domains. GetAuthPolicy answers only instance admins; anonymous callers read the login page’s methods from GetAuthMethods. SetActiveWorkspace takes workspace_id in place of organization_id; a caller still sending organization_id sends no workspace and is refused. GetWorkspaceJoinPolicy is removed, and with it the settings:read scope, which is taken off every API client that held it; a token request that still names it is refused with invalid_scope.Building from source needs Go 1.27.1 or later. If you set GOLANG_IMAGE for the Docker build, point it at a golang:1.27.1 image or later.Signing in through a workspace’s own identity provider now makes someone a member only with an email the provider confirms at one of its domains. A workspace provider with no domains lets no one new join after the upgrade; members who have signed in through it before, or that SCIM provisioned, still sign in. Add the domains your members’ emails are at in the provider’s dialog, under Domains; they don’t need to be verified for this, unless the provider doesn’t send email_verified (Microsoft Entra ID doesn’t): then verify them. Contractors at domains you don’t list join through SCIM.If your workspace verified an email domain and later removed its conduit-domain-verification TXT record, publish it again: another workspace that publishes its own record on the domain can now take the verification over while yours is missing.Telemetry no longer carries tool content or upstream error text from member calls. Tool-call, prompt-fetch and resource-read events report failures as error.type (with audit.reason set to the same value) instead of the error message, resource reads carry mcp.resource.scheme instead of mcp.resource.uri, and the mcp.upstream.request_body, mcp.upstream.response_body and mcp.upstream.error_message span attributes and the entry span’s url.path are gone (http.route remains). Dashboards or alerts built on those attributes need updating.Spans and events no longer carry user.email (or email under enduser.id). Use user.id; the audit log keeps the emails, and its entries now carry actor_user_id to join them (see Added). A SIEM that keyed on user.email should key on user.id. The names of a workspace’s own settings (policy.name, group.name, idp.name, scim_token.label, api_client.name, rule.name, scim.idp_name) are no longer sent to instance exporters, which get the ids already on each event; the workspace’s own exporters still receive them.

Added

  • Workspace invites. Workspace admins invite people by email from Settings → Members (Invite), where pending invites are listed to resend or cancel; the API is CreateWorkspaceInvite, ListWorkspaceInvites (with the domains the caller may invite at, invitable_domains), ResendWorkspaceInvite and CancelWorkspaceInvite. An invite goes to an address at the admin’s own verified domain or one the workspace verified, with a role up to admin and the admin’s own. Its link goes only into the email, so invites need email configured. The link opens the workspace’s login page, and the invitee joins with the invite’s role by signing in with that address (JoinWorkspace takes an invite_token); someone with no account, invited to a workspace that accepts email and password, creates a password account from the invite (GetWorkspaceInvite, AcceptWorkspaceInvite). An invite grants no more than the admin who last sent it could grant when it’s accepted. While password sign-in is on (the default), this means password accounts can now be created by anyone a workspace admin invites, with the invitee’s consent through the emailed link, not only by first-run setup; turn password sign-in off to prevent it. A migration adds the workspace_invites table. See Access control.
  • Workspaces own their email domains. The workspace Settings → SSO page is now Settings → Sign-in, with the workspace’s identity providers and a Domains list below them: add a domain and verify it with a DNS TXT record; each provider’s dialog sets which domains sign in with it. The API has ListWorkspaceDomains, AddWorkspaceDomain, DeleteWorkspaceDomain and VerifyWorkspaceDomain, with matching built-in admin tools; API clients with sso:read can list domains, without their DNS challenge. See SSO.
  • The multi-workspace login page asks for your email first, sending an address at a workspace’s verified domain straight to that workspace’s provider, and leads with the method the browser last signed in with. See SSO.
  • A workspace chooses which sign-in methods it accepts under Settings → Sign-in → Sign-in methods: its own providers (accepted while enabled), each of the instance’s providers, and password. Its login page offers exactly the methods it accepts. It can:
    • admit an instance provider, such as Google, only for accounts at its own domains, and send those domains’ sign-ins straight to it;
    • ask members to sign in again after a day, a week or a month.
    A session the workspace doesn’t accept is asked to sign in again, and an MCP client is sent to authorize again, where the consent screen says which workspace needs a fresh sign-in. Disabling or deleting a provider signs out everyone who signed in through it, and turning password sign-in off for the instance signs out everyone who signed in by password, except instance admins. Conduit refuses a change that would leave a workspace with no sign-in method, or lock out the admin making it. The API has GetWorkspaceSignInPolicy, UpdateWorkspaceSignInPolicy and UpdateWorkspaceInstanceProvider. See SSO.
  • Every workspace has a login page at /login/<workspace-id> (the id in its MCP URL), offering its sign-in methods and starting members’ sessions in that workspace. See SSO.
  • Conduit speaks the stateless MCP protocol revision 2026-07-28 alongside the handshake revisions 2025-03-26, 2025-06-18, and 2025-11-25, selected per request. server/discover now lists 2026-07-28, so clients on that revision use it directly instead of falling back to the initialize handshake. On it, clients learn about tool, prompt, and resource list changes over a subscriptions/listen stream; per-resource update subscriptions are not offered. Clients on the handshake revisions are unaffected. See the MCP client reference.
  • The load-testing harness measures either protocol revision. conduit-bench -era stateless (or ERA=stateless for k6) drives every scenario over MCP 2026-07-28, holding subscriptions/listen streams. See Load Tests for the comparison with the handshake revisions.
  • Connector progress reaches your client. When a client connected over HTTP asks for progress on a tool call (a progressToken) and accepts a streamed response, the connector’s progress notifications are relayed to it as the call runs, on every protocol revision. Connectors that don’t report progress are unaffected.
  • Audit log entries carry actor_user_id, trace_id and span_id, so an audited action joins to telemetry by user id and trace. Returned by ListAuditLog, ListOrgAuditLog and the audit:read API. Existing rows leave them empty. The migration runs automatically on boot.
  • ListRecentToolCalls and ListOrgRecentToolCalls accept a trace_id filter: from a span in your telemetry backend to the call’s stored error text. A usage-store migration adds the index automatically on boot.

Changed

  • Workspace slugs are lowercase letters, numbers, and single hyphens, at most 63 characters, and a workspace created without one gets a short random suffix instead of failing when another workspace holds the slug its name derives.
  • The settings sidebar groups pages the same way in multi-workspace deployments as in single-workspace ones: Access Control, Authentication & API, and Observability, with an Instance Admin section below for instance admins. A workspace’s name is edited from Workspace Settings in the workspace menu.
  • SetActiveWorkspace takes workspace_id in place of organization_id. Switching into a workspace that doesn’t accept how you signed in now succeeds, and the web app then asks you to sign in to it again.
  • A verified domain can move to the workspace that now controls its DNS: one that publishes its own TXT record while the current holder’s is gone takes the verification over. Keep your record published to keep the domain. See SSO.
  • Joining a workspace is through its own provider, an invite, or SCIM. The join policy (anyone signed in may join, listing, the join link, and join domains) is removed, along with GetWorkspaceJoinPolicy, UpdateWorkspaceJoinPolicy, GetWorkspaceJoinLink and their built-in tools, JoinWorkspace’s link_token, and the settings:read API-client scope. DiscoverWorkspaces lists the workspaces a sign-in offered you. See Access control.
  • Single-workspace deployments get a workspace’s sign-in settings on Settings → Sign-in: each provider’s Domains action, which can limit it to accounts from your domains, the Domains list, and Ask members to sign in again. See SSO.
  • A connector tool whose x-mcp-header annotations are invalid (empty, not a header name, duplicated, on a parameter that isn’t a string, integer or boolean, or placed outside the schema’s properties) is no longer offered, matching how MCP 2026-07-28 clients treat such a tool. The connector’s other tools are unaffected, and a warning names the tool and the reason.
  • OAuth connectors also request any scope an MCP upstream’s 401 challenge names, alongside the scopes it advertises.
  • The auth policy is readable only by instance admins. GetAuthPolicy no longer answers anonymous callers. The login page gets its identity providers from GetAuthMethods, and whether the caller may create a workspace is can_create_workspace on GetSession. Instance admins can read the policy with the new get_auth_policy built-in admin tool.
  • The auth policy’s signup and idp_required fields are removed. Neither was ever enforced: setting them changed nothing about who could sign in. Clients that send them have them ignored.
  • Only your domains’ people join through a workspace provider. Signing in through a workspace’s own provider makes someone a member only when the provider confirms their email at one of its domains, verified or not (a provider that doesn’t send email_verified, such as Microsoft Entra ID, only at a verified one); anyone else it authenticates needs an account it already signs in, and the rest are refused before an account is created. At a verified domain they join as they sign in; at one the workspace hasn’t verified, the sign-in ends on a Join Acme? page and they join only if they choose to (JoinWorkspace, which DiscoverWorkspaces now lists as joinable). A workspace provider needs at least one domain (domains on CreateIdentityProvider and UpdateIdentityProvider). The provider dialog reads the provider’s published claims (GetIssuerClaims) to warn when it doesn’t confirm email addresses, which joining relies on. See SSO.
  • A provider’s domains are workspace domains. An identity provider’s domains (on create, update, and read) are the workspace domains that sign in with it; one named on the provider that the workspace doesn’t hold yet is added, unverified. domain_status is removed in favor of ListWorkspaceDomains. VerifyWorkspaceDomain replaces VerifyIdentityProviderDomain (and the verify_workspace_idp_domain tool). A verified domain belongs to one workspace, signs in with at most one of its providers, and stays verified when that provider is removed. Public email services such as gmail.com can no longer be added as a domain.
  • Sessions record how the person signed in. Browser sessions and MCP access tokens now store the sign-in method, the identity provider, and the time of the sign-in behind them; a refreshed token keeps the original sign-in’s time; a workspace’s sign-in methods judge a session by them. A migration adds the columns to the sessions table and the OAuth code, refresh-token and device-code tables; existing rows record an unknown sign-in.
  • Tool, prompt and resource change notifications cost Conduit no upstream calls. A policy, group or role change notifies only the MCP clients whose access it moved, and a connector change notifies the clients that may use that connector, without Conduit listing any connector to check. Each notification now covers tools, prompts and resources together, so a client may re-list a list that didn’t change. A tool a connector adds on its own side shows up the next time the client re-lists.
  • Conduit is built with Go 1.27.1. The standard library’s faster JSON implementation cuts the gateway’s per-request encoding cost, most for large tool results.
  • Telemetry is stricter about what it contains: no tool arguments, results or upstream bodies, no recipient addresses in email delivery errors, connector URLs reduced to scheme://host (with a new connector.id attribute), and capped, valid-UTF-8 text everywhere. A failed MCP call’s event carries an error.type in place of the error text. Names of a workspace’s policies, groups, identity providers, SCIM tokens and API clients reach only that workspace’s exporters; instance exporters get their ids. Connector names still reach every exporter. See What telemetry contains.
  • Failed sign-in audit rows record the actor as anonymous and keep the typed identifier only when it is shaped like an email address; sign-in audit rows now include the (capped) user agent.
  • Connector URLs in audit log details no longer include credentials or query strings.
  • Reading a connector’s answer costs less. Conduit parses each tool result, listing, prompt, and resource a connector returns once instead of three times: a 1 MiB tool result takes about a third of the CPU and 40% of the memory it did, and a large tool listing 30–40% less of each.
  • One member’s connector token refresh no longer holds up everyone else’s calls. Conduit gets connector tokens for each member (and for a workspace-wide grant) independently, so a slow or unreachable token endpoint delays only the calls waiting on that token, and a call whose token is already cached never waits.

Fixed

  • Email sent over SMTP carries a plain-text part alongside its HTML, and a subject or sender name with non-ASCII characters (such as a workspace name) is encoded, so mail servers that require it no longer reject or garble the message.
  • Signing in through an identity provider from a page that sent you to the login page, such as the device authorization page for the Conduit CLI, returns you to that page instead of the home page.
  • The home page’s tool-calls card and top connectors and tools cover the active workspace, like the cards beside them, and the tool-calls headline counts the last 30 days its label names. It counted every workspace’s calls of all time.
  • Someone signing in for the first time gets a personal workspace even when another person with the same name already has one.
  • Instance admins can create a workspace from the workspace switcher while workspace creation is limited to instance admins. The option was disabled for everyone in that mode.
  • A JSON-RPC message without an id that names a request method (anything but a notifications/… method) is refused with HTTP 400 instead of being run with its result discarded, and a notification that carries an id is refused as an invalid request, as is a request whose id isn’t a number or a string of at most 256 bytes. The Conduit CLI’s local server applies the same rule to id-less requests, dropping one instead of running it.
  • A connector’s result metadata (_meta) on a rendered prompt now reaches the client, as it already did for tool results.
  • A single malformed byte in a logged value — reachable without signing in — could make an OpenTelemetry collector reject a whole batch of logs and events. Every exported string is now valid UTF-8 and bounded.
  • Upstream response bodies, including one-time Pipedream connect links, were recorded on spans; they no longer are.
  • The docs claimed tool calls are recorded in the audit log without error text. Tool calls are recorded in usage (denied calls also in the audit log), and the access-control, connector and Pipedream pages now say so.
  • Large integers in a URL connector’s structuredContent, result _meta, and content-block fields reach an MCP client connected to Conduit directly exactly as the connector sent them. They were rounded to about 16 significant digits.
  • Connecting your own account or token for an instance-wide connector now refreshes your MCP clients’ tool lists, as it already did for a workspace’s connectors.

Security

  • The login page looks up where an email signs in (ResolveSignIn) with a POST, not a GET, so the address someone types no longer lands in the query string that proxies and access logs record.
  • A SCIM rename decides afresh whether the account’s new email counts as verified, as account creation does: for a workspace’s own identity provider, only at a domain the workspace verified and bound to it. The address kept the old one’s verification before, so a workspace could rename an account into another organization’s domain and have it count as verified there.
  • A sign-in through an identity provider Conduit can’t reach no longer shows the signed-out visitor the provider’s address and the network error.
  • Responses from identity providers during sign-in (OIDC discovery, signing keys, user info) are capped at 1 MiB, like the other control-plane responses Conduit reads, so a hostile or compromised provider can’t stream an unbounded body into server memory.
  • Creating an MCP OAuth connector now fails, with “metadata at … names issuer …, not …”, when the authorization server’s metadata names a different issuer than the server the upstream points to (RFC 8414 §3.3), which is how an authorization-server mix-up is staged. Existing connectors are unaffected; an upstream that serves mismatched metadata needs its provider to fix it.
Compare v0.12.0…v0.13.0
2026-09-23
Workspaces decide which MCP clients may connect and which connect tabs their home page offers, replacing CONDUIT_CIMD_ALLOWED_DOMAINS — read the upgrade notes before pulling.

Upgrade notes

CONDUIT_CIMD_ALLOWED_DOMAINS is removed, and an instance that still sets it refuses to boot until it is unset. Which clients may connect is now each workspace’s decision, and every workspace starts open to any client: before upgrading an instance that relied on the variable, plan the equivalent in Settings → MCP Clients for each workspace — set Who can connect to Only allowed clients (the clients Conduit recognizes connect when they prove who they are, and anything self-registered needs an explicit Allow), block any recognized vendor you do not accept, and Add a client for a vendor Conduit does not know, by the URL of its client ID metadata document. See Governing connected clients.The instance-level MCP Clients page is removed. Every client decision — who may connect, per-client allow and block, revocation — is made on each workspace’s MCP Clients page (instance admins can act in any workspace), and the Dynamic Client Registration switch now lives in Settings → Sign-in. The instance-wide client list and its wholesale revocation have no replacement: to stop a client everywhere, block it in each workspace, which refuses every member’s use of it at once.A database migration creates the workspace client tables and seeds each single-workspace member’s clients into that workspace’s list; it runs automatically on boot, and the list fills further as clients make their next request.The new provider setting is added by a database migration on startup. Existing Okta, Microsoft, and Custom OIDC providers continue to request fresh sign-in until an admin changes the setting. Google and GitHub presets omit prompt after the upgrade regardless of the stored setting; no configuration change is needed.

Added

  • Workspace MCP Clients. Workspace administrators get an MCP Clients page (Settings → MCP Clients, in both deployment shapes) that decides which clients may connect to the workspace and lists every client it knows or has seen; see Governing connected clients.
  • Who can connect is one choice among three — any client, verified clients only (URL-based client IDs and the Conduit CLI), or only allowed clients (the clients Conduit recognizes when they prove who they are, plus whatever the workspace allows) — with the workspace’s own message to blocked members, shown in the client’s error, on the consent screen, and on the home page.
  • The consent screen lists the workspaces that will refuse the client before the member approves it.
  • The Clients table is one row per client the workspace knows or has seen — the ones Conduit recognizes (Claude Code, Claude Desktop, Cursor, Codex, ChatGPT, VS Code, MCP Inspector, the Conduit CLI), the ones the workspace adds, and anything that has connected, admitted or refused — each with its access and the reason, its home page tab, how many members use it, their live sessions, and when it was last active there; facets select what is allowed, blocked or connected.
  • A recognized client’s installs that prove they are it and the installs that only claim to be it are separate rows, each allowed or blocked on its own.
  • Any client can be allowed or blocked from its row, a block with its own message.
  • Add a client names a client Conduit does not know by the URL of its client ID metadata document, which only its vendor can host; the workspace decides about that client on its own, even when the document sits under a vendor Conduit recognizes (one connector among ChatGPT’s, say).
  • A workspace can revoke a member’s client for that workspace alone: the member’s token keeps working at their other workspaces, its next refresh is refused so the client returns to the consent screen, and access returns once they approve it again.
  • The client list starts with the clients already authorized by members who belong to just that workspace (every member on a single-workspace instance); a member of several workspaces appears as their clients connect after the upgrade.
  • Conduit recognizes the shipped clients from the client ID metadata documents their vendors publish (verified when they connect with one) or, for clients that register themselves (Cursor, MCP Inspector), from what they present, which any client can imitate, so those stay unverified; repeat registrations of one client are grouped by an identity the server computes from the client’s software_id, else its redirect URIs, else its client id.
  • Rejected MCP requests are counted under the new client_revoked and client_not_allowed reasons.
  • The home page’s connect tabs are the workspace’s. The tabs under How to use Conduit are the clients the workspace offers — the ones Conduit has setup steps for, now including VS Code, and any client the workspace added — in the workspace’s order, the first shown, allowed tab opening by default.
  • Edit home page tab gives a client its own icon and Markdown steps with a live preview; {{server_url}} and {{client_name}} are filled in when shown, fenced code becomes copyable commands, the steps can’t be saved blank, and a menu action restores Conduit’s.
  • The workspace arranges the tabs by dragging rows in the Clients table and hides a tab with its house toggle without changing whether the client may connect; a blocked client has no tab, and when the posture itself blocks, Home says so above the tabs in the workspace’s words.
  • Okta, Microsoft, and Custom OIDC providers have a Request fresh sign-in setting. Turn it off to allow the provider to reuse an existing session when signing in to Conduit.

Changed

  • MCP client governance is the workspace’s alone. The instance-level MCP Clients page — the roll-up of every authorization across workspaces, with wholesale revocation — is removed, and its two RPCs (AdminListOAuthClients, AdminRevokeOAuthClient) with it. Which clients may connect, per-client decisions and revocation are made on each workspace’s MCP Clients page; the Dynamic Client Registration switch moves to Settings → Sign-in, since accepting registrations is the authorization server’s setting, not a workspace’s. What crosses workspaces — registrations, consents, use — stays visible in the instance audit log and usage pages.

Fixed

  • server/discover declaring an unsupported protocol version is refused per the MCP spec. A probe that names a stateless-era revision Conduit does not serve (such as 2026-07-28) now gets HTTP 400 with UnsupportedProtocolVersionError, whose supported list names the revisions Conduit does serve, like every other request declaring that version. Clients retry with a listed version; a probe that declares no version is still answered with the list.
  • Google and GitHub presets now omit prompt, since neither provider documents support for prompt=login.
  • An upstream that keeps rejecting freshly issued credentials no longer costs a token mint or refresh per request. A credential obtained in the last 30 seconds that the upstream rejects is kept rather than replaced, so such an upstream costs at most one mint or refresh per half minute per credential however many requests arrive; the requests fail with the same reconnect prompt as before. A per-user OAuth token an upstream rejects before its stated expiry is now refreshed and the call repeated with the new token, instead of being presented again. A connector with a fixed token, or none, no longer re-handshakes and repeats a call the upstream answered 401: the call fails as an authentication failure and the next one opens a fresh session.
Compare v0.11.1…v0.12.0
2026-09-18
Traces group by operation and no longer report abandoned requests, oversized results or stalled upstreams as separate issues, repeated exporter errors are logged once a minute, membership and client listings are faster, and a token an upstream rejects is replaced at once.

Upgrade notes

None.

Changed

  • Membership lookups by user are indexed (a migration runs on upgrade), so listing a user’s workspaces and resolving which workspace an MCP session belongs to no longer scan the membership table.
  • Spans are grouped by operation in your tracing backend: database spans carry the key APM backends read to name them sqlite.query or postgresql.query, internal spans name their domain as the operation instead of collapsing into one “Internal” bucket, and upstream MCP calls and outbound HTTP calls list the connector and method, or the peer, as their resource.
  • A tool result over the gateway’s response size cap is no longer a tracked issue: the call still fails and tells the caller to request less, and the failed span stays visible in traces.
  • A request the caller abandons is no longer a server error. When a browser reload or a closed MCP stream cancels a request mid-flight, Conduit answers Canceled (HTTP 499) instead of a 5xx, so the failure it interrupted records no tracked exception in your tracing backend, writes no error-level log line, does not count against request error metrics, and sends no in-band MCP log message about it to the caller’s other sessions.
  • A dependency’s failure now records its cause. When Pipedream or an upstream connector refuses or fails a request — a rejected credential, a 5xx, a timeout — the tracked exception in your tracing backend and the warning in the log carry what the dependency said, under an issue type of its own (conduit.rpc.dependency_failed) kept apart from Conduit’s own faults, instead of only the status code and route.
  • A failing telemetry exporter no longer floods the console log. An export error that recurs on every batch — a collector that is unreachable, or one that does not accept a signal Conduit sends — is logged once, then once a minute with the number of repeats, instead of on every attempt.
  • A collector that does not serve a signal is no longer sent it batch after batch. When a gRPC collector answers Unimplemented for traces, logs, or metrics — a traces-only backend given Conduit’s logs, say — Conduit reports it once, naming the exporter and the signal, stops sending that signal to that exporter, and probes with one batch every five minutes until the collector serves it, then reports that it is resuming. The exporter’s other signals continue unaffected.

Fixed

  • Open MCP streams no longer flood the tracing backend with single-span traces: a request’s session check now appears inside that request’s trace, and the periodic keepalive check on each open stream records none.
  • The admin list of OAuth and MCP clients no longer slows down as clients accumulate: it issued two database queries per registered client, over a second with a few hundred of them.
  • A workspace’s Pipedream access token is minted once and shared by every member’s MCP session, instead of once per member, removing a slow step from each member’s first request.
  • A Pipedream access token that Pipedream rejects is replaced at once. When Pipedream answers a member’s MCP request or a Connect API call with 401 for a token Conduit still held as valid, Conduit drops that token, mints a fresh one and retries the request, instead of presenting the rejected token until its stated expiry and showing members a reconnect prompt for a credential that was never theirs.
  • GraphQL and OpenAPI connectors recover from a rejected token the way MCP connectors do. When such a connector’s upstream answers 401 for a client-credentials or per-user OAuth token Conduit still held as valid, the token is dropped and the call repeated once with a fresh one, instead of failing with a reconnect prompt until the token’s stated expiry.
  • Tool calls by connector-qualified name from MCP Apps-capable clients no longer fan a tool listing out to every connector first, which slowed those calls and put listing load on every upstream.
  • An upstream that stalls past Conduit’s request timeout now appears as one issue in your tracing backend, instead of two to four issues for the same failure under differing messages.
  • A credential Conduit cannot obtain is no longer reported as your session having expired. When Conduit itself failed to get the token it uses for an upstream — the Pipedream token mint refused or unreachable, a connector’s client-credentials grant failing, a token endpoint down — MCP clients were told their session had expired and re-authenticated for nothing, tool calls failed with “session expired”, and the failure left no tracked issue. It is now reported as an unavailable upstream credential: the tool call says so and that reconnecting will not help, the connector catalog shows the connector as unavailable rather than as needing a credential, and the failure is tracked under its own issue type. A grant the upstream itself refuses, because it was revoked or expired, still asks the caller to reconnect.
  • Non-ASCII text in a tool result or upstream error no longer makes the collector reject traces and events. Text Conduit shortens before putting it on a span, an event, or a stored record — an upstream response body, an error message, a client name — was cut at a fixed byte count, which could split a multi-byte character and leave invalid UTF-8; the collector then refused the whole batch it arrived in. Shortened text now ends on a character boundary and is marked with an ellipsis, and text an upstream sends that is not UTF-8 is repaired before export.
Compare v0.11.0…v0.11.1
2026-09-14
Workspace RPCs and MCP admin tools now name the workspace they act on, identity providers are one surface for instance and workspace scopes, and workspace admins can publish help instructions.

Upgrade notes

The database migration for workspace help runs automatically at startup.Admin API: ListWorkspaceIdentityProviders is replaced by ListIdentityProviders. The identity-provider RPCs now serve both scopes from one family, so the workspace-only method is gone. API clients holding sso:read call ListIdentityProviders instead; as on every workspace method, organizationId is optional for an API client and means its own workspace. In responses, the provider’s owner_scope field is now organization_id (empty for an instance provider). This breaks the scoped-method freeze deliberately, while the Admin API is days old and the project is pre-1.0; the OpenAPI reference is regenerated.MCP builtin workspace-admin tools take an organizationId argument. Omit it and the tool acts on the workspace the MCP session is bound to; name another workspace you administer to act there instead.

Added

  • Workspace admins can write Markdown help instructions from the question-mark icon in the header (? → Edit). Members see the icon once instructions are saved.
  • GetSession returns activeWorkspaceHelpSet: whether the active workspace has help instructions.

Changed

  • Admin API: every workspace method takes organizationId. The 20 workspace methods that had no such field — policies, groups, access inspection, workspace connectors, Pipedream, SCIM tokens and provisioning — gain it. For an API client the field is optional on every workspace method and means the client’s own workspace; naming any other workspace is refused. Nothing an existing client sends stops working; the OpenAPI reference is regenerated.
  • Workspace RPCs act on the workspace the request names. Every workspace-level RPC requires organization_id, and a signed-in user’s active workspace is never substituted for it — not by the authorization gate, the handler, the audit row, or the telemetry scope. A settings page left open after switching workspaces in another tab now changes the workspace it shows, not the one switched to. A refused call is audited in the workspace the request named; a member’s refused instance-admin call, which names none, now lands in the instance audit log rather than the member’s active workspace’s. A workspace call that names no workspace is refused as malformed (invalid_argument) before any role check, and is not audited as a denial. An instance admin naming a workspace that does not exist gets not_found. In the app, the workspace settings pages need a workspace to address, so an instance admin who belongs to no workspace no longer sees them in the navigation.
  • One identity-provider surface for instance and workspace. The login-page providers (instance admins, Settings → Sign-in) and each workspace’s SSO providers (workspace admins, Settings → SSO) were two RPC families and two settings pages over one table. They are now one family — ListIdentityProviders, CreateIdentityProvider, UpdateIdentityProvider, DeleteIdentityProvider, VerifyIdentityProviderDomain — addressed by scope: organization_id names a workspace, and leaving it unset names the instance, which only instance admins may do. Both settings pages render the same provider list, so the workspace SSO page gains the standard row-actions menu and the copyable redirect URI field the instance page already had. Over MCP the two scopes stay two sets of tools, named as in the previous release: list_idps, create_idp, update_idp and delete_idp in the instance-admin connector take no workspace, and list_workspace_idps, create_workspace_idp, update_workspace_idp, delete_workspace_idp and verify_workspace_idp_domain in the workspace-admin connector default to the session’s workspace like every other workspace tool. A workspace admin’s tool list never advertises the instance’s providers.
  • Identity-provider changes made in a workspace now appear in that workspace’s audit log. Creating, updating, deleting, or verifying a domain of a workspace SSO provider is recorded against the workspace; instance provider changes stay instance-level. Domain verification also joins the audit event catalog, so the filter can select it.
  • Workspace telemetry exporters receive an instance admin’s workspace-filtered usage reads. On the instance usage dashboard, a read filtered to one workspace is now scoped to that workspace, so the workspace’s exporter receives it, as it already does an instance admin’s read of the workspace’s audit log. Unfiltered, instance-wide reads still reach instance exporters only.
  • The instance usage dashboard’s workspace filter must name an existing workspace. A usage read filtered to a workspace that has since been deleted is refused as not found, like every request that names a missing workspace. The filter menu offers live workspaces only, so this reaches only a saved URL.
  • User docs start with short setup and connector guides, link directly to Conduit pages, and include a short explanation of MCP.
  • User guides cover remote setup without the feature-flagged Conduit CLI and direct help and connector requests to Conduit admins.
  • The Connectors page links to the connector-request guide beside its description.
  • The book icon moved from the sidebar footer to the header and opens Start here. The GitHub links in the app and docs are gone.
  • Home’s Claude and ChatGPT setup steps follow the providers’ current menus.

Fixed

  • Editing an instance identity provider now reports what went wrong. A rejected issuer or token URL (plain http, a special-use address) or a scope list without openid returns an invalid-argument error with the reason, where the instance path previously answered “identity provider not found”.
Compare v0.10.3…v0.11.0
2026-09-10
Adds two repository-built images for load-testing a throwaway Conduit deployment on your own infrastructure, and stops a connection’s menu from offering Replace token when there is nothing to type.

Upgrade notes

None.

Added

  • Load tests on your own infrastructure. Two new images built from the repository — loadtest-conduit, the Conduit image with a load-test seeder that runs at boot, and loadtest-mcp-server, the mock upstream the seeded connectors call — let you load-test a throwaway deployment wherever you run Conduit and its upstreams, with every result recording the pod shape it was measured on; see Load Tests.

Fixed

  • A connection’s menu no longer offers Replace token when there is nothing the member could type. A connector whose stored auth method is outside the none / token / oauth vocabulary now reads as unauthenticated everywhere (which is how the gateway already ran it), so a stale per-user token for it no longer lists it on Accounts as a live connection; and a member whose own token has been displaced by a workspace credential they may not override sees only Disconnect. Before, either case opened an update dialog with no inputs and a disabled Save.
Compare v0.10.2…v0.10.3
2026-09-07
Workspace administrators can send their workspace’s traces and events to their own OpenTelemetry collectors, MCP clients that support MCP Apps can render connector UI templates through the gateway, and each non-admin user may own one workspace.

Upgrade notes

None.

Added

  • Workspace telemetry exporters. Workspace administrators can send their workspace’s traces and events to their own OpenTelemetry collectors from Settings → Telemetry. A workspace exporter receives only activity within that workspace — its members’ MCP traffic, its settings changes, its SCIM provisioning — never other workspaces or instance administration, and never metrics. Endpoints must be https and use an HTTP protocol; they are reached through the same hardened outbound client as connectors. Signals sent to a workspace’s exporters carry the resource attributes the workspace configures (service.name defaults to conduit); the deployment’s OTEL_RESOURCE_ATTRIBUTES reach instance exporters only. Instance exporters continue to receive everything. A workspace may configure one exporter. See Telemetry Export.
  • Every workspace-scoped span and event now carries a conduit.workspace.id attribute, so an instance backend can be filtered by workspace.

Changed

  • The MCP gateway now preserves standard tool output schemas, structured tool results, and tool, result, and resource metadata from upstream connectors.
  • MCP clients that support MCP Apps can now discover and render UI templates from remote connectors. Conduit preserves the required ui:// scheme while namespacing template URIs, forwards the Apps declaration through the local CLI, keeps app-only tools out of clients that cannot render them, and lets app views call uniquely named tools and load uniquely declared templates by the local names and URIs they were authored with. Undeclared secondary UI resources are resolved across every accessible connector currently advertising an app template, without a fixed connector limit and with explicit errors for ambiguous or incomplete results.
  • Telemetry exporter settings now reject an exporter with a missing name or endpoint, or an unknown protocol, instead of saving it and silently exporting nothing.
  • Workspace telemetry pipelines are now created on first use, with each replica retaining the 64 most recently used pipelines and recycling older ones. This bounds exporter queues and background workers without limiting how many workspaces may configure telemetry.
  • Each user may own one workspace. Membership in other users’ workspaces is unaffected, and instance administrators are not limited.

Fixed

  • Changing a workspace telemetry exporter’s protocol or endpoint now clears its write-only headers instead of forwarding the stored credentials to the new collector.
  • An OTLP/HTTP telemetry exporter whose endpoint was entered with a trailing slash or with a signal path (such as /v1/logs) now sends traces to /v1/traces; before, they went to the path as entered.
  • The usage dashboards no longer drop the current hour’s calls and auth failures (and, at midnight UTC, the current day’s active users) when read during the first second of the hour.
Compare v0.10.1…v0.10.2
2026-09-03
Active-active replicas no longer need session-sticky load balancing, so any L7 balancer works with its defaults; the Admin API can inspect a group’s combined access, and MCP resource-read errors name the failing URI.

Upgrade notes

  • Sticky-session rules configured on a load balancer for Conduit’s active-active tier can stay or go; neither choice affects correctness.

Added

  • The Admin API can inspect the combined connector and tool access granted through a group, its parent-group hierarchy, and workspace-wide policies.
  • The MCP gateway’s stateless-era (2026-07-28) surface now relays mid-call client interactions — form elicitation, sampling, and roots requests — as SEP-2322 input_required retries: round one returns the requests plus a sealed requestState, and a retry echoing the state with the matching inputResponses completes the original call. Multi-round chains work without re-sending earlier answers (they replay from the sealed state), and a call needing a capability the request’s _meta didn’t declare is refused with the spec’s -32021 MissingRequiredClientCapabilityError naming the capability. The era remains served only when explicitly enabled, until its full semantics land.

Changed

  • Active-active deployments no longer need session-sticky load balancing. A client’s answer to an in-band MCP prompt (elicitation or sampling), and a request cancellation (notifications/cancelled), may reach any replica: the receiving replica hands it to the one holding the call, through the database and the cluster notification channel. Any load balancer that round-robins across replicas — an AWS ALB included — works with no affinity configuration, and the startup warning about sticky routing is gone. A client’s answer to an in-band prompt is now capped at 1 MiB on every replica (a larger answer is refused and the prompt times out). Includes a database migration (runs automatically on boot).
  • The Admin API reference now presents read-only operations as HTTP GET without duplicate POST entries for the same methods.
  • MCP resources/read errors now echo the requested URI in error.data.uri (SEP-2164), in both protocol eras, so clients can attribute a failed read without parsing the error message.
  • The load-test documentation is one sizing-focused page (headline capacity, deployment sizing guidance, and a history table) instead of a page per test pass, and the published numbers are re-measured under a workload model calibrated to real production traffic: bursty agent calls, a small always-on bot cohort, heavy-tailed upstream latency, routine tool errors, and mixed response sizes.
Compare v0.10.0…v0.10.1
2026-08-27
Adds a workspace Admin API with machine-to-machine API clients, modernizes MCP protocol support, and hardens upstream connector OAuth against token mix-up and confused-deputy attacks.

Upgrade notes

A new database migration adds the API-client tables and a kind column to users; it applies automatically on boot (SQLite and Postgres). Optional: set CONDUIT_DISABLE_API_CLIENTS=true and restart Conduit to stop API-client token minting and reject existing machine tokens instance-wide (a break-glass kill switch; per-client controls are in workspace settings).

Added

  • Admin API with machine-to-machine auth. Workspace admins can create API clients — machine principals that call Conduit’s workspace-admin operations (connectors, policies, groups, audit-log reads) from scripts and CI with no user in the flow. Clients authenticate via OAuth 2.0 client credentials (client_secret_basic or, stronger, private_key_jwt) at /oauth/token, receive a short-lived bearer token, and call the same Connect RPC API the UI uses. Access is governed by area read/write scopes. API clients are RPC-only: they are not workspace members, hold no connector policies, and cannot connect to /mcp (headless MCP access is a planned follow-up). Managed in Settings → API Clients. See Admin API.
  • Admin API reference — a generated, always-current reference for the public admin API (every method, its request/response fields, and an example), covering exactly the scoped surface an API client can reach. See Admin API Reference.
  • Connector lookup in the Admin API. Connector list responses now include their canonical IDs, which automation can pass to GetConnector to retrieve one connector’s non-secret configuration with connectors:read.
  • Admin inventory and access-debugging APIs. API clients can retrieve live connector tool catalogs with explicit resolution status, summarize configured policy grants, and inspect allow, enable, and effective access for one or many members. Sanitized SSO and provisioning inventory is available through the new sso:read and provisioning:read scopes; identity-changing operations remain machine-unreachable.
  • Upstream OAuth clients now authenticate at token endpoints with HTTP Basic (client_secret_basic, RFC 6749 §2.3.1) when that is the method the authorization server’s metadata advertises for presenting a secret; the body shape (client_secret_post) remains the choice whenever it is advertised or the metadata is silent. The method is recorded when the connector’s OAuth client is provisioned, so both the code exchange and token refreshes use it; connectors provisioned earlier keep the body shape until their next edit re-provisions the client.

Changed

  • API-client create and manage dialogs now keep a stable size while scope details expand, continue directly into credential setup after creation, and show the client ID as a copyable value in the credentials panel — previously it was only visible when creating a client secret, leaving key-only (private_key_jwt) clients no way to see the ID their assertions must name.
  • The gateway’s client to upstream MCP connectors now requests protocol revision 2025-11-25 at initialize (previously 2025-03-26), accepts whichever supported revision the upstream negotiates, and echoes the negotiated revision on every later request’s MCP-Protocol-Version header, as the spec requires of clients from 2025-06-18. An upstream that negotiates a revision Conduit doesn’t speak keeps working exactly as before: no header is sent, which the spec reads as 2025-03-26.
  • Dynamic client registration for an upstream MCP connector’s OAuth flow now declares the RFC 7591 application_type (web — or native when the instance’s callback URL is a loopback address, the local-development shape), which authorization servers implementing MCP’s SEP-837 require.
  • The MCP initialize response now assigns an Mcp-Session-Id, which stateful-transport clients echo on their later requests per the MCP spec. The id is advisory: Conduit authenticates every request by its bearer token and keeps MCP session state in the database, so requests are served identically with or without it — but clients that treat a missing assignment as “no session” (some strict SSE consumers) now get one.
  • MCP listings (tools/list, prompts/list, resources/list, resources/templates/list) are served in a deterministic sorted order, so an unchanged set always serializes identically — letting clients cache listings and improving LLM prompt-cache hit rates, per the MCP spec recommendation.
  • An MCP request that declares a stateless protocol revision (2026-07-28 or later, via the MCP-Protocol-Version header or request _meta) is now answered with the spec’s UnsupportedProtocolVersionError listing the supported versions — instead of a handshake-era-shaped response a modern client could misread. server/discover keeps answering for any declared version, so version discovery stays one round trip. Dual-era clients (the official MCP SDKs) fall back to the initialize handshake automatically.
  • MCP SSE responses now carry X-Accel-Buffering: no, telling buffering reverse proxies (such as nginx) to deliver event frames immediately.
  • x-mcp-header annotations in a connector’s advertised tool schemas are stripped before the tools reach clients: Conduit does not support the custom-header feature (MCP 2026-07-28), so advertising the annotation would solicit Mcp-Param-* headers nothing consumes — and a malformed annotation would make conforming clients reject the whole tool. Everything else in the schema passes through untouched.

Fixed

  • Resource references in a connector’s prompt and tool results — resource_link blocks, embedded resources, and mentions of those same URIs in the result’s text — are now rewritten to the gateway’s conduit://<connector>/<uri> form, matching the resource listing. Previously they relayed the connector’s own raw URIs, which a resources/read through Conduit could not resolve (so a prompt telling the model to load a resource pointed at a URI the gateway answered as not found). A read of a URI outside the wrapped form also now returns an error spelling out that form, so a model holding a raw URI quoted in prose alone can construct the routable form and retry.

Security

  • The workspace join policy no longer returns the invite-link token. Reading the policy (GetWorkspaceJoinPolicy, including the settings:read API scope and the workspace-admin MCP tool) now reports only whether a link exists (link_token_set); the token itself — a live credential that admits any signed-in user to the workspace while link joining is enabled — moves to a new GetWorkspaceJoinLink call gated at settings:write, the same authority that can mint the link. Automation that read link_token from the policy must call GetWorkspaceJoinLink instead.
  • Upstream OAuth discovery now validates the resource identifier a connector’s protected-resource metadata advertises (RFC 9728 §3.3): it must name the MCP server itself — the same origin, at the endpoint’s path or a parent of it. Metadata naming a foreign resource fails the connect flow with a clear error instead of requesting tokens audienced for that other resource (a confused-deputy defense). Connectors whose metadata advertises a mismatched identifier will fail to connect until the upstream fixes it.
  • The MCP endpoint now validates the Origin header (DNS-rebinding defense, an MCP transport requirement): a browser-sent http(s) origin that isn’t the instance’s own external origin (CONDUIT_BASE_URL) is refused with 403. Requests without an Origin header — every non-browser MCP client — are unaffected.
  • The connector OAuth callback now validates the RFC 9207 iss parameter on authorization responses (mix-up defense): a present iss must match the issuer recorded when the connector’s authorization server was discovered, and an authorization server whose metadata advertises authorization_response_iss_parameter_supported must send it. Authorization servers that predate RFC 9207 are unaffected, as are manually-configured OAuth clients (no discovered issuer to compare against). Includes a migration (runs automatically on boot); connectors configured before this release record their issuer on the next connector edit.
Compare v0.9.6…v0.10.0
2026-08-26
Enforces the Content Security Policy by default, requires consented OAuth capability scopes, adds a per-workspace usage dashboard, and hardens sessions, CSRF, and request throttling.

Upgrade notes

The new Content Security Policy is enforced by default. Deployments diagnosing a custom browser integration can temporarily set CONDUIT_CSP=report-only.OAuth scope storage is added automatically on startup. Existing client grants retain connector and personal tools only; users must reconnect and explicitly approve an administrative scope before an OAuth client can use admin tools.

Added

  • The MCP endpoint and the conduit CLI’s stdio server answer server/discover, the pre-negotiation probe clients on MCP protocol revision 2026-07-28 and later send before anything else. The response lists the supported protocol versions (the initialize-handshake revisions — Conduit does not yet implement the stateless 2026-07-28 semantics), capabilities, and server identity in one round trip, so a probing client selects a supported version and proceeds with the initialize handshake instead of inferring the fallback from a method-not-found error.
  • Workspace usage dashboard: workspace admins get Settings → Usage, showing their workspace’s tool-call volume, active members, top users/tools/clients, and recent calls — the dashboard instance admins already had, scoped to one workspace. Backed by new workspace-admin RPCs (GetOrgUsageOverview, ListOrgUsageBreakdown, ListOrgRecentToolCalls) that never read outside the workspace: the per-member drill-down shows only calls made in that workspace, never a member’s activity elsewhere. In single-workspace mode the instance and workspace dashboards fold into one page, as the audit log already does.

Changed

  • CSP violation reports that say nothing about the deployment are no longer logged or emitted as telemetry events: content a browser extension injected into the page (which no policy can govern, and which browsers report anyway) and reports naming a page outside CONDUIT_BASE_URL, which anyone could submit to the unauthenticated report endpoint. A report that survives the filter is a real policy regression.
  • The Groups & Policies dialogs edit as a draft: the grant editor and the group-members dialog collect changes behind Cancel/Save and write them in one atomic call on Save, instead of persisting every toggle immediately — so an accidental click is discardable and a half-finished edit is never live policy. The grant editor’s Allow all connectors switch still applies immediately. Saving membership sends only the explicit adds and removals, so a member added while the dialog was open — by a SCIM sync, a provisioning rule, or another admin — is never evicted by a save that didn’t touch them. Backing this, the update_group admin tool (UpdateGroup) accepts a batch of membership changes alongside its now-optional rename, and the single-member add_group_member / remove_group_member tools (AddGroupMember / RemoveGroupMember) are removed — update_group covers both, and workspace-admin clients get a shorter tool list.
  • The usage dashboards’ per-user drill-down is headed by who it is about — the user’s avatar, name, and email — instead of a generic “User usage” title. On the workspace dashboard the identity comes from the member roster (ListWorkspaceMembers gains an exact user_id filter), so an ex-member’s remaining history falls back to the generic heading.

Fixed

  • The built-in docs site prefetches pages again. Its Content-Security-Policy blocked every link prefetch, so in-site navigation lost the head start the docs are built to have.

Security

  • OAuth clients now receive explicit, consented capability scopes enforced on listings and direct calls in addition to the caller’s live role and workspace policy; ordinary connector and personal-tool scopes are required, while admin scopes are opt-in and hidden from ineligible users.
  • Stateful MCP upstream sessions are isolated per member even when a connector uses shared or no authentication, preventing one member from receiving another member’s upstream session state.
  • OpenAPI connector path parameters can no longer traverse outside the operation declared in the connector’s specification.
  • Compressed Connect RPC requests are rejected before decompression and the RPC surface is throttled per client IP, preventing unauthenticated gzip bombs from exhausting server CPU.
  • The web UI now enforces its Content Security Policy by default, denies all framing even when CSP is disabled, and briefly holds OAuth approval input to prevent clickjacking.
  • MCP tool calls now reject nonsensically oversized names before tracing, routing, or recording them. High-volume call activity remains in bounded usage data and OpenTelemetry; policy denials remain in the audit log.
  • HTTPS deployments now use a __Host- browser-session cookie (with automatic migration of existing sessions) and send a one-year, host-only HSTS policy.
  • Cookie-authenticated Connect GETs now require the exact application origin; sibling subdomains and CORS-allowed origins no longer satisfy CSRF checks.
  • PostgreSQL deployments now atomically consume shared password-attempt counters across replicas, keyed separately by account and IP, so concurrent requests cannot race past the shared limit.
  • Connector create and update requests with a missing connector payload now return InvalidArgument instead of panicking.
  • MCP tool-list change detection now hashes complete advertised definitions, including behavior hints, plus a non-secret connector-source fingerprint, so clients are notified when a trusted name’s definition or destination changes.
Compare v0.9.5…v0.9.6
2026-08-24
The MCP gateway gains prompts, upstream resources, argument completion, client logging, and request cancellation, and reports connector failures as spec-compliant tool results.

Upgrade notes

None.

Added

  • MCP prompts: the gateway now aggregates prompts from connectors that serve them (prompts/list / prompts/get), named <connector>__<prompt> and gated by the same connector access policies as tools; connected clients get notifications/prompts/list_changed when their prompt set changes. The Conduit CLI proxies prompts through. Prompt fetches and resource reads are recorded in the usage store and metrics (conduit_mcp_prompt_gets_total, conduit_mcp_resource_reads_total), and denied fetches are audited like denied tool calls. Includes a usage-store migration (runs automatically on boot).
  • MCP resources from remote connectors: resources/list, resources/read, and resources/templates/list now aggregate what upstream MCP servers expose, under the same connector access policies as tools. An upstream resource is advertised as conduit://<connector>/<original-uri> so reads route to the owning connector by name; resource templates expand inside that form and round-trip. The Conduit CLI proxies resources through. New connector names are restricted to letters, digits, and . _ ~ - (they are the routing segment of resource URIs); a pre-existing name outside that set keeps working but serves no resources until renamed.
  • MCP argument completion: completion/complete for a prompt or resource template routes to the connector that owns it, under the referent’s own access policy; connectors that offer no completion answer an empty suggestion list.
  • MCP logging: clients can opt into gateway log messages with logging/setLevel (persisted per session, honored by every replica). Conduit sends a warning when one of the caller’s connectors fails during a listing — previously visible only in server logs — and forwards the log messages a connector itself emits while answering the caller’s requests (connector:<name> logger prefix), which were previously dropped. Includes a database migration (runs automatically on boot).
  • MCP request cancellation: the standard notifications/cancelled notification now aborts the in-flight request it names, including the upstream connector call behind it. Behind multiple replicas this relies on the same sticky routing already required for in-band prompts.

Changed

  • Published binaries (the server in the Docker image and the conduit CLI downloads it serves) are built stripped of debug info and without build-machine paths, making each roughly a third smaller. Panic stack traces and runtime profiling are unaffected.
  • The MCP endpoint reports the instance’s real build version (and a display title) in the initialize response instead of a fixed placeholder, and identifies itself with that version to upstream connectors.
  • MCP list requests that carry a pagination cursor are rejected with an invalid-params error. Conduit returns every list in one page and never issues cursors, so a cursor can only be one this server did not mint; re-serving the full list would masquerade as pagination.

Fixed

  • The workspace member roster no longer discloses each member’s instance-level role to workspace admins who are not instance admins — who holds instance admin is instance-scoped information. Instance admins still see and manage it as before; the Members page shows the instance-role column only to them.
  • The login page now shows the email and password fields whenever the server would accept a password sign-in — including break-glass recovery (CONDUIT_ADMIN_EMAIL + CONDUIT_ADMIN_PASSWORD) on instances that have disabled password sign-in by policy. Previously the fields were hidden with password sign-in disabled, leaving the accepted break-glass credential with no form to be entered into. In that state the instance Sign-in settings now also show a warning that break-glass is keeping password sign-in active, recommending a restart without the variables as soon as possible.
  • Upstream MCP servers that answer a request over SSE with notification frames ahead of the result (progress or log messages) are now parsed correctly — the response frame is selected instead of the first frame.
  • Tool calls that fail in the connector behind them (an unreachable server, an HTTP error, a response over the gateway’s 8 MiB cap, a timeout) are now reported as tool results with isError: true, as the MCP spec requires, instead of JSON-RPC protocol errors. The failure text reaches the model, and when one of the gateway’s own limits stopped the call it now explains how to adjust (request less data, or less work per call) — previously these failures looked transient to clients, inviting identical retries that could never succeed.
Compare v0.9.4…v0.9.5
2026-08-20
Reconnecting an app account now updates it in place, and each user keeps a single connected account per app — accumulated duplicates clean themselves up on the next connect.

Upgrade notes

None.

Fixed

  • Reconnecting an app account no longer creates a duplicate, and each app now keeps a single connected account per user. Reconnect updates the existing account’s credentials in place, and completing a connect flow removes any other accounts you had for that app, keeping the one just connected — tool calls don’t yet offer a way to choose between multiple accounts for the same app, so keeping one removes the ambiguity about which account a call uses. Duplicates that accumulated earlier are cleaned up the next time the affected user connects or reconnects that app; each removal is recorded in the audit log.
Compare v0.9.3…v0.9.4
2026-08-19
A personal Usage page for every user, plus a security fix preventing cross-tenant workspace joins via a workspace-scoped identity provider.

Upgrade notes

No action required. A usage-database migration builds three new tool_calls indexes on first boot; on an instance with a long call history that adds a one-time startup delay.

Added

  • A personal Usage page. Every user now has a Usage page (/usage) showing their own tool-call activity — time range, workspace filter, daily chart, top connectors/tools, connected clients, and recent calls. The home-page summary cards link to it.
  • New documentation: Single Sign-On, Access Control (roles, groups, and policies), Connectors, the Pipedream Connector, How MCP Authorization Works, and Security Hardening — plus a deployment validation checklist on the Kubernetes page.

Fixed

  • Recreating a group, or re-inviting a removed member, with the same name could fail with “policy already exists.” Deleting a group or removing a member left its connector-access policy behind with no effect, and that leftover permanently squatted on the name; it’s now cleaned up along with the group or membership, and any such leftovers from earlier deletions are cleaned up automatically on upgrade.

Security

  • A workspace’s own identity provider could open the door to another workspace. On a multi-workspace instance, an email address asserted by a workspace-scoped IdP was treated as verified for any domain — so a tenant’s IdP could mint a verified address in a domain another tenant owns and join that workspace through its allowed-domain join policy. An address from a workspace-scoped IdP now counts as verified only for a domain the IdP has proven via the DNS TXT challenge (instance-scoped IdPs are unaffected), and a migration on first boot clears the verified flag on accounts whose only basis was an unproven workspace IdP.
Compare v0.9.2…v0.9.3
2026-08-14
Identity provider sign-in scopes are now editable, sign-in audit events record provisioning-rule results, and workspace provisioning rules now apply on a user’s first SSO sign-in in single-workspace mode.

Upgrade notes

None.

Added

  • Editable scopes on identity providers. The scopes requested from an identity provider at sign-in are now editable in both the instance sign-in settings and workspace SSO settings, prefilled with the defaults (previously they were fixed at openid email profile). Add whatever scope your IdP requires to include extra claims in the ID token — for example Okta requires the groups scope for a groups claim, which user provisioning rules can then match on.
  • Sign-in events now record provisioning-rule results. Each successful sign-in’s audit event lists which user provisioning rules matched and, for SSO sign-ins, the names of the claims the identity provider asserted (names only, never values). When a rule doesn’t fire, the audit log now shows whether the claim it depends on ever arrived. For deeper troubleshooting, running the server at debug log level also logs each SSO sign-in’s full verified ID-token claims.

Fixed

  • Workspace provisioning rules now apply on the first sign-in in single-workspace mode. A workspace-scoped user provisioning rule (for example “SSO claim groups contains X → add to group Y”) used to be skipped on a user’s very first SSO sign-in when the instance runs in single-workspace mode with a deployment-wide identity provider — the rule only took effect from their second sign-in. The user’s imminent membership in the sole workspace now counts during rule evaluation, matching how password sign-in already behaved.
Compare v0.9.1…v0.9.2
2026-08-13
Connectors backed by stateful MCP servers — including servers hosted on AWS Bedrock AgentCore — now work: the gateway keeps the server’s MCP session across requests instead of being rejected after the handshake.

Upgrade notes

None.

Fixed

  • Stateful MCP servers now work as connectors. The gateway keeps the session a connector’s MCP server establishes during the initialize handshake (its Mcp-Session-Id) and presents it on every subsequent request, starting a fresh session automatically if the server expires it. Servers that require this — including those built on the official MCP TypeScript SDK’s default stateful mode, and MCP servers hosted on AWS Bedrock AgentCore, which uses the session id to route requests — previously rejected every request after the handshake with a “session not found” error. Servers that don’t use sessions are unaffected. For connectors authenticated per user, each user gets their own upstream session.
Compare v0.9.0…v0.9.1
2026-08-13
Every instance now distributes the conduit CLI — device-code login, auto-configured AI clients, and local MCP connectors governed by your workspace policies — plus IAM authentication to AWS RDS; stop the old container before starting this version.

Upgrade notes

Stop the old container before starting the new one. This release’s migrations rename a connector column and drop another, so a replica running the previous version against the same database will fail its connector reads and writes until it is replaced. A normal stop/start (or a Kubernetes Recreate rollout) is unaffected; a rolling upgrade that runs both versions at once is not supported for this release. No multi-replica deployment configuration is affected today, since Postgres multi-replica mode is not yet in use.Otherwise no operator action: the migrations run automatically on boot, and the Docker image now also carries the conduit CLI binaries it serves.

Added

  • The conduit CLI: your instance’s tools, from a laptop. Every Conduit instance now distributes its own command-line client at /cli/ — users install it with one curl | sh from the home page, sign in with conduit login (a device code approved in the browser, no copy-pasting credentials), and are done. The install script, the binaries, and their checksums all come from your instance, so air-gapped deployments need nothing external and the client always matches the server it talks to.
  • conduit setup: your AI clients wired up for you. The install script ends by detecting the AI clients on the machine — Claude Code, Claude Desktop, Cursor, Windsurf, VS Code, Codex CLI, and Gemini CLI — and offering to register Conduit’s MCP server with each one: a picker with everything preselected, and idempotent config edits that leave other servers and unrelated settings untouched (one caveat: an edit to Codex’s config.toml re-encodes it, so comments there don’t survive — a file that’s already current is never rewritten). A client already pointing at the remote /mcp URL under the conduit name is switched to the CLI — it proxies the same remote tools, so keeping both entries would duplicate them. Run conduit setup again any time (say, after installing a new client), or conduit setup --all where there is no terminal to ask on.
  • Local connectors: MCP servers that run on the user’s own machine, under your policies. Admins can define a connector by launch command (Add connector → MCP Server by command) instead of by URL. Users enable it on their Connectors page like any other, and the CLI runs it locally: every tool call is authorized by your instance first, counts in usage, and lands in the audit trail exactly like a remote call — but a successful tool’s results stay on the user’s machine and never transit the server (only the outcome, and a failed call’s error message, are reported back). Access is governed by the same allow/enable policies as everything else, including as a class (local:*). Launch commands are found using the PATH the user’s login shell sets up, so a runtime installed with Homebrew or nvm works even when the MCP client wasn’t started from a terminal.
  • Environment variables for local connectors, secret-safe. A local connector’s env vars are declared the same way a remote connector’s custom headers are — the field editor labels the key as an environment variable or a header depending on the connector. A value can be a shared workspace secret or one each member supplies on their connect page; either way it is encrypted at rest and never shown back to you in the UI or API after you save it. One thing to know when choosing the scope: a local connector runs on the member’s own machine, so its environment has to be sent there. A workspace value is therefore readable by every member who can use that connector — treat it as shared with them — while a per-member value stays that member’s own and is never handed to anyone else’s machine. The field editor says so where you enter the value. This applies only to local connectors; a remote connector’s workspace values are used server-side and never leave the instance.
  • conduit mcp: one local endpoint for everything. Pointing an MCP client (Claude Code, Claude Desktop, Cursor, Codex) at conduit mcp gives it the instance’s remote tools and the machine’s local connectors in a single tool list. The home page’s connect card now leads with this path, with per-client setup instructions and an npx quick-add.
  • Live updates reach CLI sessions. When an admin changes a policy or a connector — or a user changes their own enabled set — connected conduit mcp sessions pick it up immediately: the tool list refreshes in the client, and local connectors start or stop mid-session to match. That includes editing a local connector’s launch command, arguments or environment variables: running sessions retire the old process and use the new definition on the next call, so a fix reaches every machine without asking anyone to restart their MCP client. No restarts.
  • conduit upgrade: the fleet converges on your server’s version. The CLI compares its own binary against what the server distributes (by content digest, so a rebuilt image with the same tag still converges — and a server rollback rolls the fleet back the same way), verifies the download’s checksum, and swaps itself atomically. conduit login and conduit mcp print a notice when out of sync; conduit upgrade --check exits non-zero for scripts. A running conduit mcp session adopts the new binary in place — same process, same client connection, no restart of the MCP client — and a failed upgrade can never take a session down.
  • Fleet visibility for the CLI, in the audit log and telemetry. New audit events record each CLI connection (with the user, workspace, and CLI version) and every local connector that fails to start or crashes — with a machine-readable error class (for example, “the runtime isn’t installed”) and the failing process’s own error output, so you can see whether a rollout works on real machines without asking anyone. Denied local tool calls are audited exactly like denied remote ones, successful starts and binary downloads flow to telemetry, and every CLI request carries its version, so stale clients are identifiable. When a failure has a known fix, the server’s guidance is shown to the user in their MCP client, and the connector fails fast until the definition changes — no retry storms, no repeated log spam.
  • conduit --version and conduit --help (with -v/-h shorthands) report the build and usage; conduit login -h and friends exit cleanly.
  • IAM authentication to AWS RDS and Aurora. Set CONDUIT_DATABASE_AUTH=rds-iam and Conduit authenticates to its PostgreSQL with short-lived IAM tokens minted from the AWS identity it runs as (an EKS service-account role, Pod Identity, or an instance profile) instead of a password in CONDUIT_DATABASE_URL — no database credential stored anywhere, nothing to rotate. Setup steps are on the Deployment Tiers page; the Kubernetes page shows the EKS wiring. To support mounting the RDS CA bundle (IAM auth requires TLS), the Helm chart gained extraVolumes / extraVolumeMounts.

Changed

  • Connectors can no longer be created or edited through the builtin MCP tools. The create_connector and update_connector tools are gone from the conduit_workspace_admin builtin connector: their inputs carry upstream credentials (tokens, auth headers, client secrets), which don’t belong in tool-call transcripts. Use the Connectors settings page instead; listing and deleting connectors remain available as builtin tools.
  • The home page’s “How to use Conduit” card offers two paths. “All tools” (recommended) walks through installing the CLI and pointing clients at it; “Remote tools only” keeps the zero-install hosted URL flow for clients that can’t run local processes (like ChatGPT).
  • Connector “header fields” are “config fields” in the API. The declared field list on a connector covers two transports — an HTTP header on a remote connector, an environment variable on a local one — so the API now names it for the concept: header_fields on connector reads/writes is config_fields (message ConnectorConfigField), and the connect page’s user_header_fields / user_header_keys_set are user_config_fields / user_config_keys_set. Scripts that call the connectors API with the old field names need updating; stored declarations and values are preserved (the database migrates automatically on boot) and the UI is unchanged.
  • stdio.env is gone from the connector API. A local connector’s environment is declared as config fields now, so the values are encrypted at rest and write-only instead of stored in the clear. A script still sending stdio.env has it ignored rather than rejected — move those entries to config_fields (scope workspace or user) and supply the values the same way you would a custom header’s.
  • A CLI login is only issued to the Conduit CLI. The device-authorization endpoint now accepts only the first-party conduit-cli client. The approval screen names the client asking for access, and that name is what tells you whether a login is one you started — so it has to be a name the server vouches for rather than whatever a caller sent.
  • The CLI requires HTTPS. conduit login, conduit upgrade, and conduit mcp refuse a plain-http instance URL unless it is localhost. conduit upgrade replaces the running binary with one downloaded from your instance and checks it against a checksum from that same instance, so the TLS connection is what makes the check meaningful.
Compare v0.8.1…v0.9.0
2026-08-10
Custom MCP servers gain the OAuth client-credentials grant, and OAuth discovery now follows the metadata URL a server advertises in its 401 challenge.

Upgrade notes

None.

Added

  • Custom MCP servers can now authenticate upstream with the OAuth client credentials grant, matching OpenAPI and GraphQL connectors. Pick “Client credentials” as the grant type when adding or editing an MCP connector and supply the provider’s client ID, client secret, and token endpoint (plus optional scopes and audience) — Conduit mints a workspace-wide token itself and refreshes it before expiry, so members never connect their own accounts. Switching an existing MCP connector between grants revokes credentials issued by the client being replaced, and the editor warns before saving.

Changed

  • Adding an OAuth MCP connector now discovers the server’s OAuth configuration from the metadata URL the server itself advertises when it rejects an unauthenticated request, so servers that don’t publish metadata at the standard well-known paths — such as agents hosted on Amazon Bedrock AgentCore — can now be added.
Compare v0.8.0…v0.8.1
2026-08-06
Connectors are now opt-in per member, workspace deletion removes everything it owned, and the container runs as a non-root user — read the upgrade notes before pulling.

Upgrade notes

  • The container now runs as a non-root user (UID 65532). Kubernetes installs using the Helm chart need no action — the chart’s new default security context re-owns the data volume on mount. Raw-manifest installs should add the securityContext blocks now shown on the Kubernetes page. Docker installs upgrading an existing data volume must re-own it once before starting the new version (a fresh install needs nothing):
  • The database is migrated automatically on boot, on both SQLite and Postgres. Rows stranded by deletions made under earlier versions — access policies, groups, provisioning rules, connectors and their stored credentials belonging to workspaces or users that no longer exist — are removed by the migration. They were unreachable, but if you want a record of them, take your usual pre-upgrade backup first.
  • Sign-ins already in progress complete normally when you restart into this version. Rolling back afterwards is the case to know about: a sign-in started by this version and finished by the previous one is rejected by your identity provider, because the challenge it was started with can no longer be proved. Nothing to do — the pending records expire within five minutes, and a retry succeeds.
  • If you had switched off any built-in Conduit tool connector with the update_builtin_tools admin tool, that switch no longer exists: after this upgrade, built-in tools follow workspace access policies. Withhold them in each workspace’s policies to keep them off.
  • Members who never chose their connectors now start with built-in tools only. Previously a member who had never touched the Connectors page was served everything their workspace allowed them — every connector that authenticates at the workspace level, and every Pipedream app named in their policies. After this upgrade those are switched off until the member switches them on, one connector at a time, on the Connectors page. Members who have already made a selection are unaffected, and nothing changes about what a policy allows: this is only the starting point of a member’s own selection. Tell affected members to visit Connectors after the upgrade — or let their agent do it, since Conduit’s own get_my_connectors and set_connector_enabled tools stay available and can enable a connector from the client.

Changed

  • A connector is off until the person using it turns it on. A member’s selection on the Connectors page starts as Conduit’s built-in tools and nothing else; every other connector their workspace allows them — an MCP server, an OpenAPI or GraphQL connector, a Pipedream app — waits there for them to switch on. Allowing a connector in a policy is what makes it available to a member, not what puts it in their client, so a workspace-wide grant no longer lands dozens of tools in everyone’s client on its own. See the Upgrade notes for what this means for existing members.
  • A connection blocked by outbound network protection now explains the fix. Saving Pipedream credentials, saving an OAuth connector, or opening a connector’s tools when the upstream’s hostname resolves to a private address — reached through a private endpoint or gateway such as AWS PrivateLink, or on your own network — used to fail with only blocked: connection to special-use address …. The error now says to list the hostname in CONDUIT_SAFEHTTP_ALLOWED_PRIVATE_HOSTS and points to the Network Access page, which gains worked examples for Pipedream behind a private endpoint and for MCP servers on a private network.
  • Deleting a workspace now deletes everything it owns. Its groups, access policies, provisioning rules, identity providers and their SCIM tokens, its connectors — including stored credentials and connected accounts — and its Pipedream and telemetry settings are all removed with it. Previously these were left behind: invisible and unusable, but present, which for connector credentials meant secrets outliving the workspace they belonged to. Deleting a user account likewise now removes their remaining group memberships and OAuth consent records along with their sessions and connected accounts. These relationships are now enforced by the database itself, so nothing can strand them again.
  • Built-in tool availability is decided by roles and access policies alone. The instance-wide switches that could hide the built-in Conduit tool connectors — reachable only through the update_builtin_tools admin tool, never the UI — are removed, along with that tool. A built-in connector you want to withhold from a workspace comes out of its access policies, like any other connector. The stored switch state is dropped by a migration that runs automatically on boot.
  • The Connectors page opens on an overview. Bare /connectors no longer auto-selects a connector; the pane summarizes what you have enabled — tool counts (“4 of 27 tools”), connected state, and an inline Connect button for Pipedream apps. Clicking the page background (or pressing Escape) returns to it.
  • The Connectors overview costs one request, not one per connector. It used to fetch each enabled connector’s tool list separately, so opening the page with 30 connectors enabled meant 30 concurrent upstream tools/list handshakes. Conduit now gathers them in a single call, fans out to the upstreams itself a few at a time, and skips connectors it knows you haven’t connected yet — so a connector that can’t be reached costs its own row rather than the whole summary, and the header total says what it covers (“120 tools enabled across 4 of 5 connectors”) instead of disappearing. A connector that never answers costs the summary a few seconds rather than the request: the page comes back with that row uncounted.
  • Connectors page polish. The rail’s sections collapse (Built-in starts folded; searching reveals everything), the connect-account control leads the tools panel header, and the search and tool-filter boxes carry an inline ✕ to clear them.
  • Connector setup shows the redirect URI to register with your OAuth provider. Adding or editing a connector that authenticates with an OAuth client you supply yourself — an MCP server that doesn’t support dynamic client registration, or a GraphQL/OpenAPI connector — now displays Conduit’s callback URL next to the client ID and secret, with a copy button. Previously admins had to assemble it from the instance’s host and found out they had it wrong when a member’s connection attempt came back as a redirect_uri_mismatch.
  • Connector auth setup no longer offers “let members use their own credential instead” for OAuth. OAuth members already connect their own accounts, so the setting was misleading. Existing connector behavior is unchanged, and API updates that omit allow_user_override preserve its stored value.
  • Connector wizard polish. The name is editable when importing a server.json (prefill, not a lock), and the details step’s name field explains what the name is for (it prefixes the connector’s tools). Correcting the pasted source re-derives what the later steps prefilled from it (anything you edited sticks), a step that outgrows the screen scrolls instead of pushing the buttons off it, and a header field’s example label now comes from its header name.
  • Single-workspace deployments no longer show a workspace filter on the Usage page.
  • 1Password’s inline suggestions stay out of non-credential fields. Search boxes, filters, and config/secret fields no longer get the overlay; sign-in and setup keep it — those hold a user’s own credential.

Security

  • The server runs as a non-root user. The container image now runs as a fixed unprivileged user (UID 65532), and the Helm chart’s default security contexts pin that for admission policies to verify: runAsNonRoot, the runtime’s default seccomp profile, no privilege escalation, and every Linux capability dropped. The server never needed any of them. See the upgrade note above for existing Docker data volumes.
  • Dependency security updates. The server now builds with Go 1.26.5 and gRPC v1.82.1, picking up upstream fixes for a standard-library symlink-following issue and a vulnerability reachable through telemetry export (GO-2026-6061). The docs-site build tooling moves past vulnerable sharp, postcss and nanoid releases. Nothing to configure.
  • Sign-in through an identity provider uses PKCE. The authorization request now carries a one-time challenge that Conduit proves when it redeems the code, so a sign-in code captured on its way back — from browser history, a proxy log, a referrer — can no longer be redeemed at all. Conduit already rejected a sign-in built on an injected code, by checking the nonce in the identity token against the one it issued, so nobody could take over an account this way before. What changes is where the injected code dies: at your provider, instead of at Conduit after the exchange has already happened. That matters because the exchange is the step that hands Conduit the victim’s tokens from your provider — today they are discarded, and this removes the possibility of ever obtaining them. It also brings the sign-in leg in line with OAuth 2.1 and with connecting a connector, which has always used PKCE. Nothing to configure, and no compatibility risk either way. A provider that does not implement PKCE ignores the extra parameters, as the OAuth spec requires. A provider that implements it and says so, but supports only the older plain transformation, is detected during discovery and is sent no challenge at all — sending one would make it refuse the sign-in. A provider whose app registration requires PKCE now works where it previously could not.

Fixed

  • Copy buttons draw their icon at full size. The copy control beside a copyable value — the SCIM base URL, a new SCIM token, a connector’s redirect URI — rendered at two-thirds scale inside its button.
  • Connector tool counts refresh after access and connection changes. The Connectors overview and individual tool panels could keep their previous results for up to five minutes after an access-policy edit, a Pipedream configuration change, or disconnecting a personal MCP credential.
  • The workspace Provisioning page requires an active workspace. An instance admin whose session had no active workspace saw every workspace’s provisioning rules there, and a rule created in that state was reachable from no workspace at all afterwards. Both are now refused with an error naming the problem.
  • Opening a connector that isn’t serving tools says so. Selecting one in a policy’s connector list — which shows every connector in the workspace, including disabled ones, because a policy can grant any of them — reported a generic server error. It now explains that the connector is disabled or its configuration didn’t load, and points to connector settings.
  • A failed request logs what went wrong. An operation that fails with an internal error now records the failure — which operation, and the error itself — in the server log and in the trace it exports. That covers both an API request and one of Conduit’s own tools called over MCP, whose failures were previously reported only to the calling client. Nothing to configure; this changes what is recorded when a request fails, not when one fails.
  • A server error now says which operation failed. Where the UI used to show a bare “internal” on a failed save or list, it names the operation — “create connector failed”, “list groups failed”. The underlying cause goes to the server log and the trace, where an operator can see it, and stays out of the response: error text from the database or an upstream describes Conduit’s internals, not anything the person clicking can act on.
  • A momentary database failure no longer empties a workspace’s connectors. If the read that loads a workspace’s connectors failed, the empty result was cached: for as long as the cache held, that workspace’s tools were missing from tools/list and its connector pages showed errors. The failure is now logged and the next request retries.
Compare v0.7.0…v0.8.0
2026-08-03
Connectors can require custom HTTP headers, with each value supplied once for the workspace or by each member on their own connect page.

Upgrade notes

  • search and fetch are no longer offered to every client. They are now served only to the clients that require them — ChatGPT connectors — and are hidden from everything else. If you were using them from another client to find a tool without reading the whole list, use the client’s own tool list instead: it already contains every tool search could return.
  • A spec whose server is plain http on a non-loopback host is now refused when saving an OpenAPI connector that has no URL of its own — the same rule a typed URL has always followed. Existing connectors keep working until someone edits them; re-saving one records its destination and restores the two protections named under Fixed. http://localhost still works for local development with CONDUIT_SAFEHTTP_ALLOW_LOCALHOST=1.

Added

  • Custom header fields on connectors. A custom MCP, GraphQL, or OpenAPI connector can now declare the extra HTTP headers its upstream requires — each with a human-friendly label, a description, and a required/secret flag — alongside whatever authentication it already uses. Every field is either workspace-scoped (the admin enters one shared value in the connector editor) or member-scoped (each member enters their own on the connector’s connect page, exactly where per-user API tokens are entered today). This covers internal MCP servers that expect a per-user credential in a non-standard header (say X-Jira-Token) instead of Authorization: Bearer. Adding a connector from a pasted config picks the headers up for you. The wizard now accepts both the registry server.json (whose remotes[].headers carry a description and required/secret flags) and a client mcpServers entry — the shape an internal server’s setup instructions usually show — and turns declared headers into fields, preselecting the Custom authentication method. Each field’s value source stays unset until you pick it, since nothing in a config file says whether a value is shared or personal, and pasted values are never imported: a manifest’s is a placeholder, and a real token belongs to the member who owns it. The none authentication method is now labelled Custom rather than “No authentication” — a server reached with admin-declared headers is authenticated, by those headers. A member-facing field description accepts a restricted subset of markdown — emphasis, inline code, lists and line breaks — so setup steps read as instructions rather than one long line, and the connector editor previews exactly what members will see. Links are allowed but can never hide where they go: the target host is displayed beside the link text, and only absolute https links are linked at all. Images are not rendered, and headings, quotes and tables are flattened to plain text, so admin-authored copy on a credential page cannot impersonate Conduit’s own interface. Values are write-only in the API and encrypted at rest, responses only ever name the stored keys, and the connect page shows the exact host a value is sent to before the member types it. Changing a connector’s URL revokes stored header values in both scopes — like every other stored upstream credential, a value is bound to the destination it was supplied for. A tool call that lacks a required member value answers with the connector’s connect link, the same flow OAuth and token connectors use.

Changed

  • search and fetch are scoped to the clients that need them. The two tools exist because a ChatGPT connector outside developer mode accepts nothing else: a server that exposes them is declaring itself a searchable document corpus, and Conduit answered with its own tool catalog. Advertised to every client, that misled the capable ones. A model reads a tool named search as a knowledge source to ground an answer in, so it would spend a turn searching — and get back tool schemas rather than an answer — then treat the returned schemas as an instruction to start calling those tools. It also read as evidence of tools the client could not see, when there were none: every tool search can return is already in the client’s tool list. Conduit now identifies the client from the name it reports when it connects and offers the pair only to ChatGPT, which needs it. Every other client gets the plain tool list. ChatGPT connectors are unaffected.

Fixed

  • An OpenAPI connector’s destination is now recorded where the rest of Conduit looks for it. Such a connector can be registered with a spec and no URL, in which case requests went to the base URL declared inside the spec. Two protections read the URL field instead: the host shown to a member before they enter a credential, and the rule that revokes stored credentials when a connector is pointed somewhere new. For those connectors the first showed nothing and the second never fired, so editing only the spec could redirect every member’s stored credential to another host silently. The base declared by a spec is now resolved into the connector’s URL when it is saved, which also means it passes the same https and address checks a URL you type has always passed. A connector that asks each member for a value is refused without a URL, since there would be no destination to show them.
Compare v0.6.1…v0.7.0
2026-07-31
Tool search finds a tool from a plain phrase again, and the identity-provider sign-in state token is stored hashed.

Upgrade notes

  • A sign-in already in progress when you restart into this version fails once and succeeds on retry: the pending flow was recorded in the previous format and cannot be completed by the new one. Nothing to do — the stale records expire within five minutes and are cleaned up on their own.

Security

  • The sign-in state token is stored hashed. The short-lived token that ties an identity-provider redirect to its callback was the last opaque credential Conduit wrote to the database in readable form. It is now hashed like every other one — sessions, refresh tokens, authorization codes — so a copy of the database cannot be used to claim a sign-in that is still in flight.

Fixed

  • Tool search understands a phrase. The search tool that ChatGPT connectors use — and that any client can use to find a tool without reading the whole list — required every word of the query to appear in a tool’s text, so a natural request like “list my google calendar events” returned nothing at all because no tool’s text contains “my”. It now ranks tools by how much of the query they match and answers with the closest first, so a word that matches nothing is ignored instead of excluding everything. Searching by app or connector name works again too: the shorter tool names introduced in v0.6.0 left search matching only the abbreviated form, so google_sheets found nothing where the wire name says pd__gsheets-. google_sheets, google calendar and google-calendar all find their tools now.
Compare v0.6.0…v0.6.1
2026-07-31
Prometheus metrics, traces for every outbound call and SQL statement, shorter MCP tool names, and a Helm chart for Kubernetes.

Upgrade notes

  • Built-in and Pipedream tools are advertised under new, shorter names. A client that reads the tool list each session picks them up on its own, and the previous longer names are still accepted on a tool call — so a saved agent configuration keeps working.
  • The exception is the nine identity-provider tools, which were also renamed (create_workspace_identity_provider → create_workspace_idp, and likewise for create/update/delete/list at both the instance and workspace level, plus verify_workspace_identity_provider_domain → verify_workspace_idp_domain). A configuration naming one of those by hand needs updating.
  • Access policies need no change — they are written against the stored name, which has not moved.

Added

  • Prometheus metrics. Set CONDUIT_METRICS_ADDR (Helm: metrics.enabled) to expose a /metrics endpoint on a dedicated port — tool-call rates and latencies per connector, MCP auth failures, connected SSE sessions, HTTP request durations, database pool health, and Go runtime metrics. The same metrics are pushed over OTLP to the OpenTelemetry exporters configured in Settings → Telemetry, next to the existing traces and events. See Monitoring.
  • Telemetry for over-long tool names. A new OTel event, conduit.mcp.tool_name.over_budget, tells you when Conduit advertised a tool name long enough that a client may reject or truncate it. It fires once per tools/list carrying a name of 50 bytes or more — 64 (the limit the strictest AI clients enforce) minus the 14 a client spends prefixing the name itself as mcp__conduit__ — and reports how many names were over, how many tools were listed, and the longest one, which identifies the connector responsible. Look for it in your OTLP backend, alongside the other conduit.mcp.* events. The most effective fix is usually on the client side: registering this endpoint under a short name (conduit) leaves far more room for the tool name than a long one does.
  • Helm chart. Conduit now ships a Helm chart for Kubernetes: helm install conduit oci://ghcr.io/pipedreamhq/charts/conduit --version X.Y.Z. One chart covers both deployment tiers — configuring PostgreSQL (database.secretKey) switches from embedded SQLite on a persistent volume to stateless rolling updates with replicas > 1 — and the chart enforces the tier rules (single replica on the embedded tier, an existing Secret for the encryption key, baseURL derived from the ingress host). Each chart release pins its matching image. See Deploy on Kubernetes.
  • Private registries and source builds. The Kubernetes guide covers mirroring the image and chart into your own registry, and the Docker build now accepts build args (GOPROXY, NPM_CONFIG_REGISTRY, ALPINE_MIRROR, and base-image overrides) so the image can be built entirely against a private package registry — see Build from Source.

Changed

  • Traces now cover every outbound call, and an unreachable service raises an alert. Conduit traced the requests it makes to your MCP connectors, but calls to other services showed up as an unexplained gap in the trace — the token exchange with your identity provider during a sign-in, requests to the Pipedream API, sending an email. Each of those is now its own timed span in your OTLP backend (POST api.pipedream.com, and so on), recording the method, the host it called, and the response status. So a slow sign-in or a connector list that won’t load can be traced to the service responsible instead of inferred. A service Conduit cannot reach — DNS failure, connection refused, TLS failure, a timeout — is now also reported as an error to your tracing backend, grouped by what failed (conduit.pipedream.api_failed, conduit.auth.idp_request_failed, conduit.email.send_failed, and so on), so it can raise an alert rather than sitting unnoticed in a trace nobody opens. Requests that Conduit’s own SSRF hardening refused are deliberately excluded: that is the guard working as intended, not an outage. Request paths and query strings are deliberately not recorded, because for an OpenAPI connector they carry the arguments of the tool call — the same reason Conduit already redacts tool call parameters from traces.
  • Database queries appear in traces. Every SQL statement Conduit runs is now a span inside the operation that ran it, named after the query (GetAuthPolicySettings, InsertAuditLog), so you can see whether a slow request is waiting on the database or on something else — previously that time was an unexplained gap. Query values are never recorded, only the statement itself: the parameters are what hold email addresses, tokens and tool arguments. This adds one span per statement, so traces are more detailed and larger. If the volume is more than you want, reduce it with trace sampling in your collector rather than expecting a per-signal switch — a trace missing some of its spans is harder to read than a trace you kept fewer of. Conduit also now sends trace context (the standard W3C traceparent header) with every outbound request. If you run Conduit alongside your own connectors, internal APIs or identity provider and they report to the same tracing backend, their spans join Conduit’s trace automatically — one trace from the AI client’s tool call through to your service, with nothing to configure. The header carries only randomly generated trace and span ids: no hostnames, user or workspace identifiers, or anything about your deployment. Application-level tracing “baggage” is deliberately never sent.
  • Shorter tool names. AI clients prefix every tool name with a namespace of their own, and the strictest reject anything past 64 characters — so a Conduit tool could arrive at the model truncated or dropped. Conduit’s built-in tools are now advertised with no connector prefix (conduit_workspace_admin__update_workspace → update_workspace), Pipedream tools use pd__, with a shorter slug for a curated set of well-known apps (pipedream__google_sheets-add-single-row → pd__gsheets-add-single-row) — an app outside that set keeps its full slug rather than being abbreviated into something unreadable. The identity-provider tools drop their redundant wording (verify_workspace_identity_provider_domain → verify_workspace_idp_domain), and tools from your own MCP connectors are unchanged. Access policies, usage and audit records are unaffected — they record the full name either way — and a new connector’s name is now capped at 24 characters, since it is spent from every one of that connector’s tool names.
  • Faster tool and resource listings. When a client asks what tools are available, Conduit now queries your connectors at the same time instead of one after another, so a listing takes about as long as your slowest connector rather than the sum of all of them — the more connectors a workspace has, the larger the difference. A slow or unreachable connector no longer holds up the healthy ones, and nothing else changes: the same tools are listed, in the same order, and a connector that can’t be reached still either contributes nothing or offers its authenticate tool so the user can reconnect it.
  • Outbound connections are pooled and reused. Conduit kept a separate connection pool per user and per connector, so the first tool call each person made to a given upstream paid a fresh TCP and TLS handshake even though hundreds of other calls to that same host were already in flight. All callers now share one pool per upstream, and connections stay warm across configuration changes instead of being dropped whenever a policy or connector is edited. Tool calls and connector listings lose a round trip or two of setup latency, and a busy instance holds far fewer outbound connections — which is the number your firewall’s per-source connection limits and your upstreams’ rate limits actually see. Nothing changes about which hosts Conduit reaches or the SSRF protections applied to them: hosts you exempt with CONDUIT_SAFEHTTP_ALLOWED_PRIVATE_HOSTS are still pooled separately from hosts you don’t, so an exemption is never shared with a request that wasn’t granted it.
Compare v0.5.1…v0.6.0
2026-07-27
One tracked issue per real failure in error tracking, migrations that apply out of order, connector credentials retired with their user, and a faster web UI after upgrades.

Upgrade notes

None.

Changed

  • Telemetry reports cleaner error signals. A tool call the client abandons mid-flight no longer records a tracked exception in your tracing backend (the span still shows as errored), and a failure that crosses several spans on its way up records one exception instead of a matched pair — so error tracking counts one issue per real failure.
  • Database migrations now apply even when an earlier-numbered migration arrives after a later one has already run (e.g. upgrading across a hotfix), instead of refusing to start.
  • The web UI loads faster after an upgrade. Shared library code is cached across releases now, so only the app’s own code re-downloads when you pull a new version.

Fixed

  • MCP clients that probe resources/templates/list now receive an empty list instead of a JSON-RPC method-not-found error.
  • Deleting a user now also removes their stored connector credentials; grants orphaned by earlier deletions are cleaned up automatically on upgrade.
Compare v0.5.0…v0.5.1
2026-07-26
Stored credentials are encrypted at rest, auth tables are named after the product, and workspace and account management reach MCP clients. Read the upgrade notes before pulling.

Upgrade notes

  • If you run Conduit on PostgreSQL, check who is allowed to create workspaces. A fresh PostgreSQL instance set that policy to “anyone” while a fresh instance on the embedded database set it to “instance admins only” — the two backends disagreed, and PostgreSQL got the permissive one. New instances now start restricted on both. An instance created before this release keeps whatever value it has, which for PostgreSQL may be “anyone” through no choice of yours, so it is worth confirming: Settings → Access → workspace creation. We deliberately do not change it for you, because we cannot tell a value you chose from one you inherited.
  • Take a database backup before upgrading, and make sure your encryption key is backed up too. This release encrypts several kinds of stored credential that were previously kept as readable text, converting existing rows on the first start. That step is automatic and needs nothing from you. What it does mean is that downgrading to an earlier version afterwards will not work on the same database. The values stay encrypted, while an older build expects to read them directly — so identity-provider sign-in, email sending, and upstream connectors would fail on the older version. If you need to go back, restore the backup you took before upgrading. Your encryption key also covers more than it did before — see the entries below for what, and CONDUIT_ENCRYPTION_KEY for where it lives. The same backup covers a second change with the same shape: several database tables were renamed, so an older build would not find them either. Nothing reads those tables but Conduit itself, so this is invisible unless you query the database directly or have built reporting on top of it — see below.

Added

  • Workspace settings and members can be managed from an MCP client. Workspace admins get built-in tools to rename a workspace, change its URL slug or logo, set a member’s role, and remove a member — the same actions the workspace settings pages offer, under the same rules: you cannot grant a role above your own, change your own role, or leave a workspace without an administrator.
  • You can see who you are signed in as, and which workspaces you belong to, from an MCP client. Any user gets built-in tools to read their own account and the workspace they are working in, to list the workspaces they are a member of, and to create one — the last subject to the same rules as the web app, so it is refused if your instance runs in single-workspace mode or reserves workspace creation for instance administrators. Only your own memberships are listed: being an instance administrator does not put every workspace in that list.

Changed

  • Connectors can no longer be saved with the unimplemented token-exchange auth type. It was accepted at save time and could never work: exchanging a token on a member’s behalf needs the token their identity provider issued, and Conduit does not retain one, so such a connector looked configured and served no tools. It was never offered in the connector UI or by any catalog entry, so reaching it required calling the API directly. That call now returns an explanatory error instead of appearing to succeed.
  • Database tables are named after what the product calls them. The tables behind users, workspaces and provisioning carried a ba_ prefix, left over from the library this instance’s auth layer was first ported from. It described where the code came from rather than what the data is, so anyone reading the database had to know a piece of Conduit’s history to find the users table. ba_user is now users, ba_organization is workspaces, ba_member is workspace_members, ba_assignment_rule is provisioning_rules, and so on through sixteen tables. This is internal plumbing: no API, RPC, or UI field changes, and the upgrade renames existing tables in place without touching a row of data. It matters only if you query the database directly — a reporting tool or a support script pointed at ba_* needs the new names.

Fixed

  • Revoking a user’s sessions now tells you if it didn’t work — and always takes their refresh tokens too. Revoking sessions from the admin pages reported success whatever happened, so a failed revoke looked identical to a successful one and was recorded in the audit log as having happened. For a control you reach for when you believe an account is compromised, that is the worst possible failure: you move on believing access is cut. The two halves of the revoke — the sessions themselves and the OAuth refresh tokens that can mint new ones — now also succeed or fail together, so a partial failure can no longer leave a token behind that quietly restores access.
  • Deleting an identity provider now reports failure, and never leaves its claimed domains behind. A failed delete answered with success, so an administrator could believe a sign-in route was closed while it still worked. The provider and the domains it claims for sign-in routing are now removed together; previously a failure between the two could leave a domain pointing at a provider that no longer existed.
  • Saving instance sign-in settings now reports failure instead of showing you your old values as if they saved. The page answered from a fresh read, so a write that didn’t land came back looking successful with the previous settings displayed — and the audit log recorded a change that never happened. These settings are also now saved together: a partial failure could previously leave the instance in a combination of sign-in options nobody chose, such as requiring SSO while re-permitting passwords.
  • A GraphQL or OpenAPI connector whose credential stopped working now offers you a reconnect link. When an upstream rejected a saved credential — an account disconnected on their side, a token revoked or expired — an MCP connector answered with the prompt to reconnect, but a GraphQL or OpenAPI one answered with the raw rejection text, which reads as a broken tool rather than as something you can fix. All three now offer the same prompt. As before, this applies only where you are the one who connected the credential: an upstream rejecting a workspace-wide credential set by an admin still reports the upstream’s own explanation, since reconnecting is not yours to do.
  • An upstream credential is no longer used so close to its expiry that it can lapse mid-request. Conduit refreshes a cached upstream token shortly before it expires. For connectors using SSO token exchange, and for connected accounts, that safety window was shorter than the time a single upstream call is allowed to take — so a token could pass the check, then expire while the request carrying it was still in flight, and the call came back rejected even though the credential had been valid when it was chosen. The window is now wider than the longest a call can run, for every kind of connector. Also fixed in the same place: a token exchange whose result was valid for under thirty seconds was cached as though it had already expired, so a fresh exchange ran on every request instead of once.
  • A Pipedream access token is no longer re-fetched on every single request. Conduit caches the token it mints for Pipedream until shortly before it expires. When Pipedream’s reply omitted how long the token was good for — which the OAuth specification permits — Conduit read that as “already expired” and minted a fresh one for every upstream call, adding a round trip to each and burning through token requests. A reply with no stated lifetime is now treated as good for an hour.
  • A stalled token endpoint no longer holds up the requests behind it. When Conduit fetched a credential from an identity provider, a connector’s token endpoint, or Pipedream, the fetch ignored the fact that the request that needed it had been abandoned — so a slow endpoint was waited out in full even though nobody was left to receive the answer, and in Pipedream’s case every other caller queued behind it. These fetches now stop as soon as the work is no longer wanted.
  • A failing token endpoint now says what went wrong. If a token endpoint answered with something other than the expected JSON — typically a proxy’s HTML error page during an outage — the error recorded was a complaint about invalid JSON syntax, with no mention of the status code that would have identified it as an outage. The status is now included. Relatedly, a reply too large to accept is reported as such rather than as malformed.
  • Renaming a workspace to a slug that is already taken no longer changes its name anyway. The name, URL slug and logo were saved one after another. If you edited more than one and the slug collided with another workspace, the earlier fields had already been written by the time the collision was reported — so the error said the slug was taken while the workspace had quietly been renamed. All three are now saved together, and a rejected slug leaves the workspace exactly as it was.
  • Switching workspace now tells you if it failed. The write that records which workspace you are working in was made with its error discarded: a failed switch was logged on the server and answered as a success, so the app showed you the workspace you had picked while the next page load put you back in the old one. It now surfaces the failure.
  • A new workspace and its owner are created together. The workspace row and the membership that makes you its owner were written one after the other. If the second failed, the workspace existed with no members at all — invisible in your workspace list, and removable only by an instance administrator. Both now land in one step, so a failure leaves nothing behind.
  • A workspace can no longer be created with a blank name. A name of only spaces was accepted, producing a workspace with no readable name and a URL slug of dashes.
  • An SSO sign-in’s state token is now spent exactly once. The identity provider’s callback carries a one-time state value that Conduit checks and then discards. It was checked and discarded in two steps, so two callbacks arriving together with the same value could both pass the check before either cleared it. The exchange that follows would still fail for the second one, since the provider only honours its authorization code once, but the guard that is supposed to be single-use was not. It is now consumed in a single step. Relatedly, if Conduit cannot store that state at the start of a sign-in, the sign-in now fails at that point rather than sending you to your provider for a round trip that could only come back rejected.
  • Editing a user or a workspace from the admin pages now reports a failure instead of claiming success. Both saves wrote their fields with the error discarded, so a write that did not land still answered with a success. Renaming a workspace additionally hid every failure except a duplicate slug, which is the one it did report. Both now surface what went wrong.
  • Saving a workspace’s join settings now tells you if it failed. A failed write was logged on the server and otherwise ignored: the page answered with the settings as they were re-read afterwards, so an admin saw a success and their old values, with no indication the change had not been stored. It was also recorded in the audit log as a change that happened. Discovering workspaces to join had the same shape, reporting a failed lookup as “no workspaces available”. Both now surface the error.
  • A database hiccup no longer crashes the workspace, members and access pages, and no list can quietly come back short. Several screens loaded their rows in a way that mishandled a failed query: instead of reporting the failure, the request crashed outright. Others could return a partially-read list — a members roster missing members, a workspace’s identity providers missing providers — with nothing to indicate anything was missing, which is worse than an error, because an admin reasonably reads the page as the truth. Reads now either return the complete result or report a failure you can see and retry.
  • Identity-provider tokens are now encrypted at rest. When a member signs in through SSO, Conduit keeps the tokens the identity provider issued so it can exchange them for upstream access on that member’s behalf. Those were stored as readable text: anyone with a copy of the database or a backup could read them and act as your members against the identity provider. They are now encrypted with the same instance key as every other stored credential, and existing rows are encrypted in place on the first start after upgrading.
  • Connected-account credentials and workspace join links are now encrypted at rest. The access and refresh tokens Conduit holds on your behalf for an upstream connector — the ones minted when a member connects their account, or when an admin connects one credential for the whole workspace — were stored in the database as readable text, as were per-member API tokens and the secret in a workspace’s join link. Anyone holding a copy of the database file or a backup could read them and call those upstream services as your members. They are now encrypted with the same instance key that already protected identity-provider and email credentials, and existing rows are encrypted in place the first time the upgraded instance starts, so there is nothing to run by hand. This makes the encryption key load-bearing for connected accounts: if <data-dir>/conduit.key (or CONDUIT_ENCRYPTION_KEY) is lost, members have to reconnect their accounts and admins have to regenerate join links. Back the key up.
  • Changing a member’s workspace role now reaches their connected AI clients. A role change updated the workspace immediately, but announced nothing: a user already connected over MCP kept being offered the admin tools of the role they no longer held, and someone newly promoted saw none of their new tools, until they reconnected. Calling a tool they had lost was always refused — permission is re-checked on every call, so this was never a way to keep access — but the list an assistant chooses from could be out of date for as long as the connection stayed open. Role changes made through provisioning rules, and the automatic owner promotion that follows demoting the last one, were affected the same way and are fixed too. Connections now resolve who you are each time they recompute your tools rather than remembering it from when you connected, so a change made anywhere — by another instance in a multi-replica deployment, or directly in the database — is picked up as well.
Compare v0.4.1…v0.5.0
2026-07-25
Failures now surface as issues in APM error tracking, with service-entry spans for every request and W3C trace propagation from MCP clients.

Upgrade notes

None.

Changed

  • Errors in traces now surface in APM error tracking. Every HTTP request (RPCs, MCP calls, OAuth, SCIM) gets a service-entry span named after its route, and failures the operator should act on — upstream transport errors, credential refresh/exchange failures, handler panics, unhandled 500s — carry a full exception (stable exception.type, message, stack trace), which is what backends like Datadog require to open an issue. Expected failures (a tool result reporting an error, a credential the user hasn’t connected yet) stay visible in traces but deliberately never become issues, and exception types/messages are kept stable so one failure mode groups into one issue. Conduit also honors an inbound W3C traceparent, so a client that traces its own agent loop sees Conduit’s spans in the same trace; health probes, static assets, and idle MCP event streams are not traced.
Compare v0.4.0…v0.4.1
2026-07-25
Refused requests and upstream-credential writes in the audit log, server-wide request body caps, SSRF hardening on every outbound call, forwarded client IPs trusted only from proxies you declare, and connector repointing that revokes stale credentials.

Upgrade notes

  • If a reverse proxy fronts your instance, set CONDUIT_TRUSTED_PROXIES to its address range. Conduit no longer trusts forwarded client-IP headers from private-range addresses by default; it now trusts loopback only. This affects any deployment whose proxy reaches Conduit over the network rather than over loopback — a Kubernetes ingress controller (CONDUIT_TRUSTED_PROXIES=10.42.0.0/16, your pod CIDR), or docker run -p, where traffic arrives from the bridge gateway (172.17.0.0/16). Sidecar proxies talking to Conduit over loopback need no change. Left unset, such an instance still works, but every audit entry and per-IP rate limit resolves to the proxy’s own address, and Conduit logs a warning once per process naming the peer it saw — that address is the one to trust. See client IP attribution.
  • If your instance reaches the Pipedream API, Resend, or Amazon SES through an egress proxy on a private address, list that proxy’s hostname in CONDUIT_SAFEHTTP_ALLOWED_PRIVATE_HOSTS. Those three calls now go through the same SSRF-hardened client as every other outbound request, which refuses to connect to private addresses. Instances that reach the internet directly need no change. A blocked call fails with blocked connection to special-use address naming the host. See Network Access.
  • Database migrations apply automatically on boot; nothing else to do.

Changed

  • Repointing a connector revokes the credentials members stored for it. Editing a connector’s URL, or its OAuth client id, authorization endpoint, or token endpoint, now drops every credential held for the old destination — each member’s connected account and the shared workspace credential — and members reconnect to re-consent. A credential is only valid for the upstream it is sent to and the authorization server that issued it, so carrying it to a new destination would have handed those tokens (and, on the next refresh, the connector’s client secret) to whoever now sits behind the new address. Every such edit is recorded in the audit log as config.connector.repointed, with the field that changed, its previous value, and how many credentials were dropped.

Security

  • Every request body and every upstream response is bounded. Conduit capped bodies at each endpoint that read one, which meant the cap was something a new endpoint had to remember. Request bodies are now capped for the whole server before any route sees them — 1 MiB on pre-auth surfaces, 10 MiB where a large payload is legitimate (the API, /mcp, SCIM) — so a route cannot be added without one. In the other direction, replies from services Conduit calls out to are now capped as well: an identity provider’s token or discovery response, an upstream’s OAuth metadata, or a vendor API’s JSON was read without limit, so a compromised or hostile peer answering with an endless body could exhaust the gateway’s memory. Oversized replies are refused rather than truncated, so a short read can never be mistaken for a complete one.
  • All outbound requests go through the SSRF-hardened client. Identity providers, upstream MCP servers, connectors, and OAuth metadata documents already did. The Pipedream API and the Resend and Amazon SES email providers now do too, so the protection is what a newly added outbound call inherits rather than something each one opts into. The new Network Access page is now the single list of every host Conduit connects to, what each is for, and when it is contacted.
  • Forwarded client-IP headers are only trusted from proxies you declare. Conduit attributes audit entries and keys its per-IP rate limits (sign-in, sign-up, OAuth, failed MCP auth) on the client IP. It previously accepted X-Forwarded-For from any private-range peer, so on a shared network — a Kubernetes cluster without NetworkPolicies, a Docker bridge, or the LAN of an on-prem install — a caller could choose the value. That let them give every request a fresh rate-limit bucket, which defeats the per-IP throttles for password spraying across many accounts, and write an arbitrary string into the audit log, which breaks attribution and could implicate a real address. The default trusted set is now loopback only — every other proxy is listed explicitly as an IP or CIDR in CONDUIT_TRUSTED_PROXIES — and a forwarded value must parse as an IP address to be used at all.
  • Refused requests are recorded in the audit log. Permission checks used to be silent: an authenticated member could call every instance-admin and workspace-admin RPC, and name every builtin MCP tool, collecting hundreds of refusals without producing a single audit entry — so the reconnaissance that precedes an attack left no trace, and only the operations that succeeded were ever visible to an admin reviewing the log afterward. Refusals now appear as authz.role.denied (the caller’s role doesn’t reach that method or builtin tool) and authz.policy.denied (their access policy doesn’t grant that connector tool), each naming the actor, the target, and the workspace, and each recording whether the call arrived over HTTP or MCP. The two are separate events because they call for different responses — the first says someone is reaching above their role, the second may just mean a policy needs widening — and filtering the authz group shows both. They are deliberately not sampled: a burst of denials from one account is the signal, and dropping its tail would drop the evidence. Denied tool calls also count in the Usage dashboards, where they previously went uncounted.
  • Upstream connector credentials are recorded when set or cleared. Storing a static token, completing an OAuth connect flow, and disconnecting all now write connect.upstream_credential.set / .cleared, naming the connector, whether the credential is the caller’s own or the shared workspace one, and — for a workspace credential, which every member uses — the admin who connected it. The credential plane was the one place a write left no record, which made it the cheapest place to establish persistence. This adds a database migration that runs automatically on boot; no operator action is needed. Connect flows already in progress across the upgrade are unaffected.
  • A removed member’s open MCP stream stops receiving a workspace’s change signals. On the bare /mcp endpoint, where the client names no workspace, a stream held open across a membership change kept delivering that workspace’s list_changed notifications — which connectors and tools changed there, and when — to someone who had since been removed from it. Such a stream now closes as soon as its token resolves to a different workspace, and the client reconnects against its current access.
  • Failed MCP authentication is reported even while the throttle is active. Repeated bad-token requests to /mcp are rate-limited per IP; the throttled attempts were previously dropped before their telemetry was recorded, so a brute-force burst registered as a trickle. Every attempt is now counted and reported.
  • Every pre-auth request body is size-capped. The OAuth consent callback decoded its JSON body, and the token endpoint parsed its form, before either checked the caller’s session — so an unauthenticated client could stream oversized bodies into memory in parallel, degrading the instance for all workspaces. Both now reject anything past the 1 MiB pre-auth cap that the rest of the unauthenticated surface already enforced. The install guide now states which abuse Conduit handles itself and which it expects a fronting proxy to absorb.
  • A failed audit-log write is no longer silent. If the audit insert itself fails, Conduit logs an error and emits conduit.audit.write_failed to your OTLP backend, rather than discarding the failure — a broken audit pipeline used to be indistinguishable from a quiet system.
Compare v0.3.0…v0.4.0
2026-07-24
SCIM 2.0 provisioning, a guarantee that every signed-into workspace keeps an owner and an admin, canonical emails and unique memberships, and a linkable Connectors page.

Upgrade notes

Migrations apply automatically on boot. Three of them rewrite existing rows, and one wants a follow-up from an admin:
  • Group names that collide only by case are made unique. Collisions already in the database are kept rather than merged: the later group gains a [<group id>] suffix, visible in Settings → Policies for an admin to rename to whatever it should be.
  • Stored email addresses are normalized (lowercased, trimmed), and duplicate workspace and group memberships left by earlier races are collapsed, keeping the highest-privilege one. Nothing to do.
  • Pending MCP authorization codes are cleared. A client that was mid-flow at the moment of the upgrade re-authorizes on its own.

Added

  • SCIM 2.0 provisioning. An identity provider (Okta, Microsoft Entra, or any SCIM 2.0 IdP) can push users, groups, and group memberships into a workspace, so joiners, movers, and leavers in your directory reach Conduit without anyone signing in first. Workspace admins generate bearer tokens in Settings → SCIM, each bound to one of the workspace’s SSO providers so provisioned users and sign-ins resolve to the same person. Deprovisioning removes the user from the workspace, revokes their sessions, and ends the group memberships and policy grants they held there; reactivating them restores the memberships the IdP still asserts, since an IdP pushes group changes as deltas and never re-sends one its own directory didn’t change. Grants that came from anywhere else are not resurrected — a membership an admin added by hand stays that admin’s to re-make. Pushed groups become Conduit groups usable in access policies, marked SCIM in Settings → Policies because their name and their IdP-pushed members are reconciled to the directory on every sync; memberships added by an admin or an assignment rule are never touched by a sync. See SCIM Provisioning for connecting an IdP. A token carries the authority of the workspace admin who generated it and no more. It cannot deprovision the workspace’s owner, change the name or email of someone a different identity provider established, or rename or deprovision an instance administrator — each of those reaches past the workspace the token belongs to. Two provisioned people in one workspace also cannot share a userName: an address can legitimately belong to several federated identities, while SCIM requires userName to identify exactly one user, so the second push is refused rather than leaving an IdP’s match-before-provision lookup with two answers. Every provisioning change is recorded in the workspace audit log, attributed to the connection’s SSO provider — and so is every push Conduit refuses, with the reason, since a refusal repeats on every sync until a human resolves it and belongs where the workspace’s admins will see it rather than only in the IdP’s own logs. Conduit refuses rather than guesses: a membership push it cannot interpret exactly, or a remove of an attribute it cannot unset, is answered with an error instead of a 200 the IdP would read as applied, because the nearest guess at “which members?” is an empty group.

Changed

  • A workspace people can sign into always keeps at least one administrator — and an owner. Removing or demoting a member is refused — on every path: the members UI, the instance admin API, SCIM deprovisioning, and deleting the user’s account outright — when it would leave the workspace’s remaining members with no owner or admin. Removing the only member is allowed (nobody is left to be locked out), which is what keeps a user’s own workspace from making their account undeletable; the workspace stays in place for an operator to keep or delete. An owner can be removed or demoted while another admin remains, and when that leaves the workspace owner-less the longest-standing admin is promoted to owner automatically, so owner-only actions (like deleting the workspace) stay reachable. Removals honor the same rank ceiling as role changes — you cannot remove a member who outranks you, so an admin cannot evict the owner and inherit ownership — and an instance administrator can only be removed or renamed by another instance admin, never by anything scoped to a single workspace. Deleting a member revokes the group memberships and policy grants they held in one step with the removal, so a partial failure cannot leave grants behind.
  • Memberships are enforced unique in the database. A person’s workspace membership and a group’s member entries are backed by unique indexes, so concurrent joins (invite acceptance, sign-in auto-join, SCIM sync, assignment rules) can no longer create duplicate rows on Postgres. Group membership rows are also foreign-keyed to their group, so deleting a group removes them in the database itself and a membership can never outlive its group. Group member counts include only people who still have an account, so a deleted user can no longer show up in a group an admin cannot remove them from.
  • Group names are unique per workspace without regard to case. They were already compared that way, so “Engineering” and “engineering” could both exist while a lookup for either matched both — which left an identity provider’s group sync picking one arbitrarily.
  • Emails are stored in one canonical form. Addresses are normalized (lowercased, trimmed) on the way in, so sign-in, SSO, and provisioning always resolve the same person regardless of the casing an identity provider or a sign-up form sent.
  • OAuth clients receive sessions for exactly the user who authorized them. Authorization codes carry the user’s id rather than their email address. An address can legitimately belong to more than one identity, so resolving by email could mint a session for the wrong account.
  • Unchecking a connector’s last tool disables the connector. On the Connectors page, tool checkboxes and the enable switch now follow each other in both directions: checking a tool enables the connector (as before), and unchecking the last one turns it off instead of leaving it enabled with nothing selected.
  • The Connectors page is linkable. Selecting a connector navigates to /connectors/<id> (e.g. /connectors/app:linear), and the two search boxes persist as ?q= (connector search) and ?tools= (tool filter) — so a specific connector’s tool view can be bookmarked or shared, and reloading or navigating back restores what you were looking at. Opening /connectors bare lands on the first connector’s URL, and a link to a connector that no longer exists falls back there too.

Fixed

  • Searching connectors no longer drops keyboard focus. In the policy grant editor and on the Connectors page, the search box could lose focus mid-word whenever a search crossed between “no matches” and “matches”; typing now stays uninterrupted, and the no-matches message appears in place of the connector list.
  • The Connectors page no longer flashes a built-in connector while loading. The detail pane (on the Connectors page and in the policy grant editor) now shows a loading placeholder until the real connector list arrives, instead of briefly showing a built-in connector and then switching.
  • The home dashboard’s Top connectors and Top tools lists now show the Conduit logo for built-in Conduit tools instead of a generic plug icon.
Compare v0.2.7…v0.3.0
2026-07-23
Search-engine exclusion, instant hover-preloaded navigation, a real error page, and resilience fixes for crashes and upgrades.

Upgrade notes

None.

Added

  • Search engines are told to stay out. Every response carries an X-Robots-Tag: noindex header and the instance serves a disallow-all robots.txt, so a Conduit dashboard reachable from the internet is neither crawled nor indexed.

Changed

  • Navigation feels faster. Hovering a link preloads the destination page’s code and data, so most navigations render instantly.
  • Unexpected page errors get a real error page. If a page fails to load or render, the app shows a styled “Something went wrong” page with the error and a retry button, instead of an unstyled developer message.

Fixed

  • Deploying no longer breaks already-open tabs. A tab opened before an upgrade could fail on its next page navigation (the old page code it asks for is gone); the app now reloads itself once to pick up the new version.
  • A crashing request is a logged 500, not a vanished connection. If a request handler hits an unexpected internal error, the client now gets a clean HTTP 500 and the crash is recorded in the server log and as a conduit.server.panic telemetry event, instead of the connection simply dropping with nothing written anywhere.
Compare v0.2.6…v0.2.7
2026-07-23
Per-page browser tab titles, instant app connect links, and big database-efficiency gains for session validation and connection pooling.

Upgrade notes

None.

Changed

  • Browser tabs show the page name. Every page in the dashboard sets its own tab title (Members, Usage, Connect Slack, …) instead of every tab reading “Conduit”, so multiple open tabs are distinguishable.
  • App connect links go straight into the connect flow. Opening /connectors/app:<slug>/connect (the link Conduit hands to MCP clients) launches the account-connect flow immediately instead of showing a page with a Connect button — and shows a “connected” confirmation right away when the account already exists. The page also warms the connection to the connect service while loading, so the flow appears sooner.
  • Session validation costs one database query instead of three. Every API request, MCP request, and SSE keepalive validates its session with a single joined lookup (session + user + membership) rather than three sequential round-trips. Not a cache — revocation still takes effect immediately. PostgreSQL tool-call throughput +11%, dashboard API +30% at the standard pod shape; idle SSE streams cost a third of the database reads. See the load tests.

Fixed

  • Database connection pools no longer churn under load. The pools kept only Go’s default 2 idle connections, so heavy traffic closed and re-dialed connections constantly — on PostgreSQL this could exhaust the pod’s ephemeral ports and fail requests (measured at ~1,000 concurrent tool calls). Idle capacity now matches pool capacity, with a 5-minute idle shed so a quiet instance releases its connections back to a shared database server. PostgreSQL tool-call throughput at the standard pod shape rose from 850/s (with errors) to 3,600/s (clean) — see the load tests.
Compare v0.2.5…v0.2.6
2026-07-22
Full-screen split view with mobile fixes, faster SSE connects, container-aware memory limits, load-test docs, and an optional debug endpoint.

Upgrade notes

None.

Added

  • Published capacity test results. A new Load tests docs section records dated capacity passes — sustained per-pod ceilings per deployment tier, with full environment provenance so numbers stay comparable across versions. The measuring harness ships in the repo (loadtest/).
  • Debug endpoint for profiling and load analysis. Setting CONDUIT_DEBUG_ADDR (e.g. localhost:6060) starts a second listener serving Go pprof profiles and runtime/DB-pool statistics. Off by default; bind it to localhost or a private interface only. See the configuration reference.

Changed

  • The runtime respects the container memory limit. Conduit derives the Go garbage collector’s soft memory limit (GOMEMLIMIT) from the container’s cgroup ceiling automatically (90% of it; setting GOMEMLIMIT yourself still wins). Memory-dense workloads — many held SSE streams — now degrade gracefully under GC pressure instead of being OOM-killed, and fit ~50% more connected users per pod. See the load tests.

Fixed

  • SSE connections are no longer serialized at connect. Registering an MCP SSE stream previously performed upstream work while holding a global lock, so a reconnect burst (for example after a deploy) could delay — or under a slow upstream, freeze — all new SSE connections on the instance. Connecting is now instant regardless of upstream latency or burst size; clients may receive one extra list_changed notification after connecting (they re-list, which is always safe). See the load tests for measurements.
  • Split-view polish on the Connectors page and the policy grant editor: the Connectors page no longer scrolls as a whole — the connector list and tool pane fill the screen and scroll independently — headers and the checkbox column align, and connector descriptions truncate to one line with a “more” toggle.
  • Expanding a tool row no longer shifts its description text, and documentation links inside a row open without collapsing the row.
  • On phones, tool rows stack the name above the description instead of squeezing the description into a sliver, and the tool filter box spans the full width.
  • On cramped screens — phones in either orientation, or any short window — the workspace-admin “Manage connectors” banner on the Connectors page collapses to a one-line link, so the connector list keeps the screen space (the page header is pinned and no longer scrolls away).
  • The Groups & Policies page fits phone screens: its dialogs no longer overflow the viewport, and the connector icon strip shows fewer icons (with a higher +N count) instead of running off the edge.
  • The policy grant dialog makes better use of cramped screens: on narrow phones and short windows it hides its helper sentences and goes full-height, so the connector list keeps several rows visible instead of two. When “Allow all connectors” is on, the dialog now shrinks to fit the summary instead of showing a mostly-empty full-height box.
  • On a fresh load of the Connectors page (and the policy grant editor), the split view no longer defaults its selection to a built-in connector while the app catalog is still loading — the selection lands on the first real connector once the list fills in.
Compare v0.2.4…v0.2.5
2026-07-22
Split-view browsing and configuration for connectors and tools, plus a wider audit log layout.

Upgrade notes

None.

Changed

  • The audit log pages use a wider layout on large screens, giving the event table and the detail panel more room.
  • Browsing and configuring connectors and tools — on the Connectors page and in the policy grant editor — now uses a split view: the connector list sits on the left and the selected connector’s tools on the right. Each tool shows as a compact one-line row that expands for its full description, and connectors with many tools gain a filter box to narrow the list. The connector list loads more automatically as you scroll — no more Previous/Next paging through the Pipedream app catalog. Tool checkboxes work even while a connector is toggled off — checking a tool enables the connector with just that tool selected. In the policy grant editor, workspace admins now see a connector’s full tool catalog, including connectors that haven’t been granted to anyone yet.
Compare v0.2.3…v0.2.4
2026-07-21
Fixes the Connectors page showing no apps in workspaces whose allow policies name specific apps.

Upgrade notes

None.

Fixed

  • The Connectors page again lists apps in workspaces whose allow policies name specific apps (rather than granting all apps): the Pipedream lookup that resolves those app slugs sent a query the API rejected, and the page rendered no apps at all — leaving members nothing to enable. Failures of that lookup now surface as an error instead of an empty app list.
Compare v0.2.2…v0.2.3
2026-07-21
In-client connector auth — connect prompts, URL elicitation, a focused connect page — plus the client-credentials grant and a unified reconnect UX.

Upgrade notes

  • All schema migrations in this release apply automatically on boot; no manual steps.
  • Active-active deployments: configure session-sticky load balancing (by bearer token or Mcp-Session-Id) so in-band MCP prompts work — see the entry under Changed and Deployment Tiers.

Added

  • OpenAPI and GraphQL connectors can now authenticate upstream with the OAuth client credentials grant. Pick “Client credentials” as the grant type in the connector’s authentication settings and supply the client ID, client secret, and token endpoint (plus optional scopes and audience) — no authorization URL is needed. Conduit exchanges the credentials for a workspace-wide token itself and refreshes it before expiry, so members never connect their own accounts.
  • Tool lists now show the HTTP method and path under each OpenAPI-derived tool (e.g. GET /v1/apps), on the connectors page and in policy grant editing — specs can declare several operations with identical summaries, and the operation is what tells them apart.
  • The connector wizard now reads the security schemes an OpenAPI spec declares and preselects the matching authentication method — prefilling the authorization and token endpoints for OAuth authorization-code flows, the token endpoint for client-credentials flows, and choosing the API token method for API-key and bearer schemes. Detection is a prefill only: everything stays editable, and specs without a recognizable scheme leave the wizard unchanged.
  • Identity providers can now carry an access denied help message, shown to users when the provider refuses a sign-in with access_denied — for example, when a user isn’t assigned to the app in Okta or Microsoft Entra. Admins configure it per provider (instance sign-in providers and workspace SSO providers both), as plain text where pasted URLs and [label](https://url) spans render as links — useful for pointing users at a docs portal or an access-request form. The message also appears on the login page as an info popover next to that provider’s sign-in button. The error page now names the provider in its fixed copy (“Sign in failed for Okta. Reach out to your admin for assistance.”) when the sign-in flow is known. The backing schema migration runs automatically on upgrade.
  • Connectors that need a personal credential are now discoverable from MCP clients: instead of silently hiding an unconnected connector’s tools, the gateway lists a <connector>__authenticate tool that returns a link to connect your account, and calls to a not-yet-connected connector’s tools return the same link instead of a raw authentication error. Once you connect, tool lists refresh automatically.
  • A focused connect page (/connectors/<id>/connect) is the landing target of those links: one connector, one action — authorize (OAuth), paste a key (token), or connect an app account (Pipedream) — then return to your assistant.
  • App tool calls (via Pipedream) for an app without a connected account get the same connect prompt as every other connector, instead of passing Pipedream’s raw connect-link text through.
  • In-client connect prompts via URL elicitation. When your MCP client supports URL-mode elicitation (MCP 2025-11-25), connecting an account is offered natively in the client: the <connector>__authenticate tool asks for consent to open Conduit’s connect page, and calling a tool whose credential is missing or no longer works returns the standard URLElicitationRequiredError so capable clients can open the page and retry automatically once you’ve connected. Credentials are always entered on Conduit’s session-gated connect page — never in the MCP client — per the MCP spec’s requirement that sensitive values not pass through clients. Clients without URL elicitation get the connect link as text, as before.
  • The MCP protocol version is now negotiated per session: Conduit echoes the client’s requested version when supported (2025-03-26 through 2025-11-25) instead of always answering 2025-03-26.

Changed

  • The built-in conduit__get_connectors tool is now conduit__get_my_connectors — the name now says whose connectors it lists (the caller’s own, filtered by their access policies). MCP clients calling it by the old name must switch to the new one.
  • The built-in get_workspace_connectors tool moved from the everyone-visible conduit connector to conduit_workspace_admin, and the RPC behind it is now workspace-admin only. It returns the workspace’s full connector catalog for policy management — every connector including disabled ones, with an enabled field carrying the real state — rather than the caller’s view of what is currently live. Members keep get_my_connectors for that.
  • The Connectors and Accounts pages now manage every connection the same way, first-time or not: a connected connector shows its credential type with an inline Reconnect / Disconnect menu instead of a bare “Connected” label. Applies to OAuth, per-user token, and Pipedream app connectors alike.
  • Active-active deployments now need session-sticky load balancing for in-band MCP prompts (elicitation/sampling): the gateway holds such a tool call open on one replica and waits for the client’s answer on a separate request, which must return to the same replica. Route each MCP connection to a consistent replica (by bearer token or Mcp-Session-Id) — everything else remains replica-independent. Conduit warns at startup in this mode. See Deployment Tiers.

Fixed

  • Connecting, reconnecting, or disconnecting a connector now refreshes its tool list right away — in the web UI (the connector’s tools re-fetch, so a reconnect clears a stale error instead of leaving it cached) and for connected MCP clients (connect/disconnect now emits notifications/tools/list_changed).
  • A connector whose saved credential the upstream rejects (expired or revoked) no longer disappears silently from the tool list: it surfaces the same <connector>__authenticate tool worded as a reconnect, and calling any of its tools returns a reconnect link — so a stale credential is recoverable from the client.
  • The Groups & Policies page now shows the correct name and icon for grants on disabled connectors and on admin built-in tools, and the grant editor lists them, so a grant no longer becomes anonymous or uneditable when its connector is switched off or the viewing admin lacks the instance-admin role.
Compare v0.2.1…v0.2.2
2026-07-20
Pipedream connector tools fix, MCP tool metadata, faster restarts.

Upgrade notes

None.

Changed

  • Built-in Conduit tools now declare MCP behavior-hint annotations (readOnlyHint, destructiveHint, idempotentHint), so clients can auto-approve read-only calls like list_connectors and warn before destructive ones like admin_delete_workspace. Annotations from upstream MCP servers pass through to clients unchanged.
  • Built-in Conduit tools now carry a human-readable display title (e.g. “Join Workspace”), which MCP clients that support tool titles show in place of the wire name. Tool titles from upstream MCP servers are now passed through to clients as well.
  • Shutdown now ends open MCP SSE streams immediately instead of waiting out the 10-second drain timeout on connections that never finish on their own, so a stop or redeploy completes in under a second once in-flight requests drain. MCP clients reconnect automatically.

Fixed

  • Pipedream app tools now appear on /mcp in workspaces whose access policy grants all connectors with a wildcard (including the default policy every workspace starts with). The gateway told Pipedream which apps to serve only when the policy listed them explicitly, so a wildcard grant surfaced no app tools at all — enabling an app on the Connectors page had no visible effect. It now always names the user’s enabled apps to Pipedream.
  • MCP clients that sat idle long enough for all their tokens to expire no longer lose their OAuth client registration to the cleanup sweep — a returning client (e.g. Claude Code reusing its cached client_id) failed every authorization with “invalid client_id” and had to be manually re-registered. Only abandoned registrations that never completed an authorization are reclaimed now.
  • Failed /oauth/authorize requests (unknown client_id, unregistered redirect_uri) are now logged server-side; previously the only signal was the error page in the end user’s browser.
  • On the embedded database, restarting or redeploying an instance no longer trips the single-instance guard. The guard treated the previous process’s last heartbeat (up to 90 seconds old) as a live second instance, so a normal stop-then-start deploy crash-looped for a few minutes before coming up. It now flags only instances that write a heartbeat after the current process started — a real concurrent writer is still detected within one 30-second beat.
Compare v0.2.0…v0.2.1
2026-07-19
PostgreSQL support and active-active high availability.

Upgrade notes

None — database migrations apply automatically on boot. The new PostgreSQL/high-availability features are opt-in via CONDUIT_DATABASE_URL; embedded deployments are unchanged.

Added

  • PostgreSQL support: set CONDUIT_DATABASE_URL to run Conduit on an operator-supplied PostgreSQL (14+) instead of the embedded database. The embedded zero-dependency default is unchanged. Requires CONDUIT_ENCRYPTION_KEY (and CONDUIT_ADMIN_PASSWORD until setup completes); usage metrics live in the same database.
  • High availability: on PostgreSQL, Conduit runs active-active with any number of replicas behind a load balancer — zero-downtime rolling upgrades, live cache invalidation between replicas, cluster-wide authentication-failure throttling, and a /healthz/ready readiness endpoint that checks database connectivity. See the High Availability deployment guide.
  • Conduit now refuses to start when another live instance is using the same embedded database file — a misconfigured multi-instance deployment fails loudly instead of corrupting data.
  • Deployment guides for Kubernetes, high availability and backups, and other platforms (Compose, VMs, Fly.io).

Fixed

  • The first-run setup wizard survives a server restart between signing in with the bootstrap credential and completing setup.
  • Connecting a connector account via OAuth survives a server restart mid-flow (between opening the provider’s consent page and returning).
Compare v0.1.0…v0.2.0
2026-07-19
The first tagged release of Conduit.

Upgrade notes

None — this is the first release.

Added

  • MCP gateway: tools from MCP servers, GraphQL and OpenAPI connectors, and the Pipedream connector catalog, aggregated behind a single governed MCP endpoint with OAuth 2.1 and dynamic client registration.
  • Access policies: allow policies and groups decide who can use which connectors and tools, enforced on every tool listing and call; users refine their own enabled set. Connected clients refresh live when access changes.
  • Workspaces: single-workspace self-host mode and multi-workspace (tenant) mode, with per-workspace connector configuration, join policies, and provisioning rules.
  • Authentication: email + password and identity providers (social presets and custom OIDC), workspace SSO, and an instance auth policy.
  • Observability: audit log of admin changes and sign-ins, OpenTelemetry traces and events, and usage dashboards.
  • Built-in documentation: this docs site ships inside the Conduit image, served at /docs/ and always matching the running version; the app sidebar links to the docs and to the running version’s changelog.
Full commit history