From d774c8061303a41a857807149a5d80eaa47d1197 Mon Sep 17 00:00:00 2001
From: Rhys Sullivan <39114868+RhysSullivan@users.noreply.github.com>
Date: Sun, 10 May 2026 22:08:01 -0700
Subject: [PATCH 1/2] Split cloud onboarding into create-org and setup-mcp
routes
The cloud app now routes onboarding through /create-org (org creation
plus pending invitations) and /setup-mcp (MCP server URL and install
command). AuthGate redirects an authenticated user without an org to
/create-org and renders these routes without the app shell so they read
as a focused two-step flow. After creating an org the user is taken to
/setup-mcp; "Continue to app" lands at /.
---
apps/cloud/src/routeTree.gen.ts | 42 ++++++++++
apps/cloud/src/routes/__root.tsx | 30 ++++++-
apps/cloud/src/routes/create-org.tsx | 6 ++
apps/cloud/src/routes/setup-mcp.tsx | 6 ++
.../pages/{onboarding.tsx => create-org.tsx} | 11 ++-
apps/cloud/src/web/pages/setup-mcp.tsx | 80 +++++++++++++++++++
6 files changed, 170 insertions(+), 5 deletions(-)
create mode 100644 apps/cloud/src/routes/create-org.tsx
create mode 100644 apps/cloud/src/routes/setup-mcp.tsx
rename apps/cloud/src/web/pages/{onboarding.tsx => create-org.tsx} (96%)
create mode 100644 apps/cloud/src/web/pages/setup-mcp.tsx
diff --git a/apps/cloud/src/routeTree.gen.ts b/apps/cloud/src/routeTree.gen.ts
index bc0ab8b70..ecffa48b2 100644
--- a/apps/cloud/src/routeTree.gen.ts
+++ b/apps/cloud/src/routeTree.gen.ts
@@ -10,9 +10,11 @@
import { Route as rootRouteImport } from './routes/__root'
import { Route as ToolsRouteImport } from './routes/tools'
+import { Route as SetupMcpRouteImport } from './routes/setup-mcp'
import { Route as SecretsRouteImport } from './routes/secrets'
import { Route as PoliciesRouteImport } from './routes/policies'
import { Route as OrgRouteImport } from './routes/org'
+import { Route as CreateOrgRouteImport } from './routes/create-org'
import { Route as ConnectionsRouteImport } from './routes/connections'
import { Route as BillingRouteImport } from './routes/billing'
import { Route as ApiKeysRouteImport } from './routes/api-keys'
@@ -26,6 +28,11 @@ const ToolsRoute = ToolsRouteImport.update({
path: '/tools',
getParentRoute: () => rootRouteImport,
} as any)
+const SetupMcpRoute = SetupMcpRouteImport.update({
+ id: '/setup-mcp',
+ path: '/setup-mcp',
+ getParentRoute: () => rootRouteImport,
+} as any)
const SecretsRoute = SecretsRouteImport.update({
id: '/secrets',
path: '/secrets',
@@ -41,6 +48,11 @@ const OrgRoute = OrgRouteImport.update({
path: '/org',
getParentRoute: () => rootRouteImport,
} as any)
+const CreateOrgRoute = CreateOrgRouteImport.update({
+ id: '/create-org',
+ path: '/create-org',
+ getParentRoute: () => rootRouteImport,
+} as any)
const ConnectionsRoute = ConnectionsRouteImport.update({
id: '/connections',
path: '/connections',
@@ -82,9 +94,11 @@ export interface FileRoutesByFullPath {
'/api-keys': typeof ApiKeysRoute
'/billing': typeof BillingRoute
'/connections': typeof ConnectionsRoute
+ '/create-org': typeof CreateOrgRoute
'/org': typeof OrgRoute
'/policies': typeof PoliciesRoute
'/secrets': typeof SecretsRoute
+ '/setup-mcp': typeof SetupMcpRoute
'/tools': typeof ToolsRoute
'/billing/plans': typeof BillingPlansRoute
'/sources/$namespace': typeof SourcesNamespaceRoute
@@ -95,9 +109,11 @@ export interface FileRoutesByTo {
'/api-keys': typeof ApiKeysRoute
'/billing': typeof BillingRoute
'/connections': typeof ConnectionsRoute
+ '/create-org': typeof CreateOrgRoute
'/org': typeof OrgRoute
'/policies': typeof PoliciesRoute
'/secrets': typeof SecretsRoute
+ '/setup-mcp': typeof SetupMcpRoute
'/tools': typeof ToolsRoute
'/billing/plans': typeof BillingPlansRoute
'/sources/$namespace': typeof SourcesNamespaceRoute
@@ -109,9 +125,11 @@ export interface FileRoutesById {
'/api-keys': typeof ApiKeysRoute
'/billing': typeof BillingRoute
'/connections': typeof ConnectionsRoute
+ '/create-org': typeof CreateOrgRoute
'/org': typeof OrgRoute
'/policies': typeof PoliciesRoute
'/secrets': typeof SecretsRoute
+ '/setup-mcp': typeof SetupMcpRoute
'/tools': typeof ToolsRoute
'/billing_/plans': typeof BillingPlansRoute
'/sources/$namespace': typeof SourcesNamespaceRoute
@@ -124,9 +142,11 @@ export interface FileRouteTypes {
| '/api-keys'
| '/billing'
| '/connections'
+ | '/create-org'
| '/org'
| '/policies'
| '/secrets'
+ | '/setup-mcp'
| '/tools'
| '/billing/plans'
| '/sources/$namespace'
@@ -137,9 +157,11 @@ export interface FileRouteTypes {
| '/api-keys'
| '/billing'
| '/connections'
+ | '/create-org'
| '/org'
| '/policies'
| '/secrets'
+ | '/setup-mcp'
| '/tools'
| '/billing/plans'
| '/sources/$namespace'
@@ -150,9 +172,11 @@ export interface FileRouteTypes {
| '/api-keys'
| '/billing'
| '/connections'
+ | '/create-org'
| '/org'
| '/policies'
| '/secrets'
+ | '/setup-mcp'
| '/tools'
| '/billing_/plans'
| '/sources/$namespace'
@@ -164,9 +188,11 @@ export interface RootRouteChildren {
ApiKeysRoute: typeof ApiKeysRoute
BillingRoute: typeof BillingRoute
ConnectionsRoute: typeof ConnectionsRoute
+ CreateOrgRoute: typeof CreateOrgRoute
OrgRoute: typeof OrgRoute
PoliciesRoute: typeof PoliciesRoute
SecretsRoute: typeof SecretsRoute
+ SetupMcpRoute: typeof SetupMcpRoute
ToolsRoute: typeof ToolsRoute
BillingPlansRoute: typeof BillingPlansRoute
SourcesNamespaceRoute: typeof SourcesNamespaceRoute
@@ -182,6 +208,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof ToolsRouteImport
parentRoute: typeof rootRouteImport
}
+ '/setup-mcp': {
+ id: '/setup-mcp'
+ path: '/setup-mcp'
+ fullPath: '/setup-mcp'
+ preLoaderRoute: typeof SetupMcpRouteImport
+ parentRoute: typeof rootRouteImport
+ }
'/secrets': {
id: '/secrets'
path: '/secrets'
@@ -203,6 +236,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof OrgRouteImport
parentRoute: typeof rootRouteImport
}
+ '/create-org': {
+ id: '/create-org'
+ path: '/create-org'
+ fullPath: '/create-org'
+ preLoaderRoute: typeof CreateOrgRouteImport
+ parentRoute: typeof rootRouteImport
+ }
'/connections': {
id: '/connections'
path: '/connections'
@@ -260,9 +300,11 @@ const rootRouteChildren: RootRouteChildren = {
ApiKeysRoute: ApiKeysRoute,
BillingRoute: BillingRoute,
ConnectionsRoute: ConnectionsRoute,
+ CreateOrgRoute: CreateOrgRoute,
OrgRoute: OrgRoute,
PoliciesRoute: PoliciesRoute,
SecretsRoute: SecretsRoute,
+ SetupMcpRoute: SetupMcpRoute,
ToolsRoute: ToolsRoute,
BillingPlansRoute: BillingPlansRoute,
SourcesNamespaceRoute: SourcesNamespaceRoute,
diff --git a/apps/cloud/src/routes/__root.tsx b/apps/cloud/src/routes/__root.tsx
index 334fbe9ef..787206f06 100644
--- a/apps/cloud/src/routes/__root.tsx
+++ b/apps/cloud/src/routes/__root.tsx
@@ -1,6 +1,13 @@
import React from "react";
import * as Sentry from "@sentry/react";
-import { HeadContent, Scripts, createRootRoute } from "@tanstack/react-router";
+import {
+ HeadContent,
+ Outlet,
+ Scripts,
+ createRootRoute,
+ useLocation,
+ useNavigate,
+} from "@tanstack/react-router";
import { AutumnProvider } from "autumn-js/react";
import posthog from "posthog-js";
import { PostHogProvider } from "posthog-js/react";
@@ -13,10 +20,11 @@ import { plugins as clientPlugins } from "virtual:executor/plugins-client";
import { AuthProvider, useAuth } from "../web/auth";
import { SupportOptions } from "../web/components/support-options";
import { LoginPage } from "../web/pages/login";
-import { OnboardingPage } from "../web/pages/onboarding";
import { Shell } from "../web/shell";
import appCss from "@executor-js/react/globals.css?url";
+const ONBOARDING_PATHS = new Set(["/create-org", "/setup-mcp"]);
+
if (typeof window !== "undefined" && import.meta.env.VITE_PUBLIC_SENTRY_DSN) {
Sentry.init({
dsn: import.meta.env.VITE_PUBLIC_SENTRY_DSN,
@@ -198,6 +206,18 @@ function ShellErrorFallback() {
function AuthGate() {
const auth = useAuth();
+ const location = useLocation();
+ const navigate = useNavigate();
+ const isOnboardingRoute = ONBOARDING_PATHS.has(location.pathname);
+
+ const needsOrgRedirect =
+ auth.status === "authenticated" && auth.organization == null && !isOnboardingRoute;
+
+ React.useEffect(() => {
+ if (needsOrgRedirect) {
+ void navigate({ to: "/create-org", replace: true });
+ }
+ }, [needsOrgRedirect, navigate]);
if (auth.status === "loading") {
return
+ Step 1 of 2 +
+ Step 2 of 2 +
++ Executor exposes your sources, secrets, and tools to any MCP-compatible agent. Copy the + URL into your client, or run the install command. +
++ MCP server URL +
++ Paste this into your MCP client config. +
++ Install command +
+Adds the server to a supported agent.
+- Paste this into your MCP client config. -
+Paste this into your MCP client config.