From 06b4b71fb9b8a0a6d5fb04c3ca896b48711ab949 Mon Sep 17 00:00:00 2001 From: Justin Bradfield Date: Fri, 8 May 2026 13:21:32 -0500 Subject: [PATCH 1/4] console: clean up connect modal MCP instructions - Move MCP token generation into the MCP tab with a "Generate MCP token" button instead of showing it stacked below with the app password - Restructure MCP instructions into clear steps: (1) get your token (generate or base64-encode existing), (2) connect your client - Simplify client instructions to show `claude mcp add` command and link to docs for other clients instead of tabs for each client - Add `wrap` prop to CopyableBox for multiline command display - Hide the "Create app password" section when on the MCP tab - Use tabs for App password / MCP token on the App Passwords page Co-Authored-By: Claude Opus 4.6 (1M context) --- console/src/access/AppPasswordsPage.tsx | 60 +++--- .../src/components/ConnectInstructions.tsx | 8 + console/src/components/ConnectModal.tsx | 41 ++-- .../src/components/McpConnectInstructions.tsx | 185 +++++++++--------- console/src/components/copyableComponents.tsx | 6 +- console/src/mz-doc-urls.json | 1 + 6 files changed, 147 insertions(+), 154 deletions(-) diff --git a/console/src/access/AppPasswordsPage.tsx b/console/src/access/AppPasswordsPage.tsx index 8be5d53f55600..3ad93817fba39 100644 --- a/console/src/access/AppPasswordsPage.tsx +++ b/console/src/access/AppPasswordsPage.tsx @@ -28,7 +28,12 @@ import { Radio, RadioGroup, Stack, + Tab, Table, + TabList, + TabPanel, + TabPanels, + Tabs, Tbody, Td, Text, @@ -495,34 +500,33 @@ const SecretBox = ({ > - - - - New password {`"${name}"`}: - - - - - - MCP Token - - - - Base64-encoded {userEmail}:<password> for MCP - configuration. - - - + + New password {`"${name}"`} + + + + App password + MCP token + + + + + + + + + + Write this down; you will not be able to see your credentials again after you reload! diff --git a/console/src/components/ConnectInstructions.tsx b/console/src/components/ConnectInstructions.tsx index 139a38a0df067..fef8482b6686c 100644 --- a/console/src/components/ConnectInstructions.tsx +++ b/console/src/components/ConnectInstructions.tsx @@ -35,12 +35,18 @@ export interface ConnectInstructionsProps extends BoxProps { mcpBase64Token?: string; /** Called when the active tab changes. */ onTabChange?: (title: string) => void; + /** Callback to generate a new MCP token (creates an app password). */ + onGenerateToken?: () => void; + /** Whether token generation is in progress. */ + isGeneratingToken?: boolean; } const ConnectInstructions = ({ user, onTabChange, mcpBase64Token, + onGenerateToken, + isGeneratingToken, ...props }: ConnectInstructionsProps): JSX.Element => { const [currentEnvironment] = useAtom(currentEnvironmentState); @@ -129,6 +135,8 @@ const ConnectInstructions = ({ ), icon: , diff --git a/console/src/components/ConnectModal.tsx b/console/src/components/ConnectModal.tsx index 3a99ea3400283..ca2ee13bd31e4 100644 --- a/console/src/components/ConnectModal.tsx +++ b/console/src/components/ConnectModal.tsx @@ -31,7 +31,7 @@ import docUrls from "~/mz-doc-urls.json"; import { useCreateApiToken } from "~/queries/frontegg"; import { useListApiTokens } from "~/queries/frontegg"; import { MaterializeTheme } from "~/theme"; -import { obfuscateSecret, toBase64 } from "~/utils/format"; +import { toBase64 } from "~/utils/format"; import { SecretCopyableBox } from "./copyableComponents"; import SupportLink from "./SupportLink"; @@ -69,6 +69,8 @@ const ConnectModal = ({ ? toBase64(`${mcpUser}:${newPassword.password}`) : undefined; + const isMcpTab = activeTab === "MCP Server"; + return ( @@ -97,17 +99,22 @@ const ConnectModal = ({ userStr={forAppPassword?.user} mcpBase64Token={mcpBase64Token} onTabChange={setActiveTab} + onGenerateToken={() => + createAppPassword({ + type: "personal", + description: "MCP token", + }) + } + isGeneratingToken={createInProgress} mt="4" /> - {showCreateAppPassword && ( + {showCreateAppPassword && !isMcpTab && ( )} @@ -122,8 +129,6 @@ interface CreateAppPasswordProps { createAppPassword: ReturnType["mutate"]; createInProgress: boolean; newPassword: ReturnType["data"]; - mcpBase64Token?: string; - showMcpToken: boolean; } const CreateAppPassword = (props: CreateAppPasswordProps) => { @@ -147,8 +152,6 @@ const CreateAppPasswordInner = ({ createAppPassword, createInProgress, newPassword, - mcpBase64Token, - showMcpToken, }: CreateAppPasswordProps) => { const { data: appPasswords } = useListApiTokens({ user }); const { colors } = useTheme(); @@ -165,26 +168,6 @@ const CreateAppPasswordInner = ({ if (newPassword?.password) { return ( <> - {showMcpToken && mcpBase64Token && ( - - - MCP token - - - - )} - Create a new app password if you don’t have one accessible. + Create a new app password if you don't have one accessible. + )} + )} + + + {isCloud && ( + + Or Base64-encode an existing app password: + + )} + {!isCloud && ( + + Base64-encode your username and password: + + )} + + - - Step 2. Connect your client + + 2. Connect your client + + See the{" "} + + documentation + {" "} + for connecting clients like Claude Desktop, Cursor, Windsurf, etc. + - Replace <base64-token> with the output from Step 1. + Or connect to Claude Code now: - - - Run this command in your terminal: - - - - Or save to .mcp.json in your project directory: - - - - ), - }, - { - title: "Claude Desktop", - children: ( - - - Save to claude_desktop_config.json: - - - - ), - }, - { - title: "Cursor", - children: ( - - - Save to .cursor/mcp.json in your project - directory: - - - - ), - }, - ]} - /> + ); diff --git a/console/src/components/copyableComponents.tsx b/console/src/components/copyableComponents.tsx index 26b8790d45f6f..326f6fabefda2 100644 --- a/console/src/components/copyableComponents.tsx +++ b/console/src/components/copyableComponents.tsx @@ -99,6 +99,7 @@ export interface CopyableBoxProps extends BoxProps { contents: string; variant?: "default" | "compact"; maxHeight?: string; + wrap?: boolean; onCopy?: () => void; } /** Copyable component with a bg box but no line breaks */ @@ -106,6 +107,7 @@ export const CopyableBox: React.FC = ({ contents, variant = "default", maxHeight, + wrap, onCopy, ...props }) => { @@ -127,9 +129,9 @@ export const CopyableBox: React.FC = ({ py={2} flex={1} lineHeight="4" - whiteSpace="nowrap" + whiteSpace={wrap ? "pre" : "nowrap"} overflow="hidden" - textOverflow="ellipsis" + textOverflow={wrap ? undefined : "ellipsis"} minWidth={0} {...(maxHeight && { maxHeight, diff --git a/console/src/mz-doc-urls.json b/console/src/mz-doc-urls.json index 90e47b980392e..56b01b1919e34 100644 --- a/console/src/mz-doc-urls.json +++ b/console/src/mz-doc-urls.json @@ -290,6 +290,7 @@ "/docs/serve-results/sink/kafka/": "https://materialize.com/docs/serve-results/sink/kafka/", "/docs/transform-data/idiomatic-materialize-sql/lag/": "https://materialize.com/docs/transform-data/idiomatic-materialize-sql/lag/", "/docs/integrations/llm/": "https://materialize.com/docs/integrations/llm/", + "/docs/integrations/mcp-server/": "https://materialize.com/docs/integrations/mcp-server/", "/docs/transform-data/idiomatic-materialize-sql/last-value/": "https://materialize.com/docs/transform-data/idiomatic-materialize-sql/last-value/", "/docs/transform-data/idiomatic-materialize-sql/lead/": "https://materialize.com/docs/transform-data/idiomatic-materialize-sql/lead/", "/docs/sql/functions/length/": "https://materialize.com/docs/sql/functions/length/", From ad6a6965805038c11dbff3b144504a3c8121ffd2 Mon Sep 17 00:00:00 2001 From: Justin Bradfield Date: Sat, 9 May 2026 00:42:59 -0500 Subject: [PATCH 2/4] Update console/src/components/McpConnectInstructions.tsx Co-authored-by: Qindeel Ishtiaq --- console/src/components/McpConnectInstructions.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/console/src/components/McpConnectInstructions.tsx b/console/src/components/McpConnectInstructions.tsx index 7a34e53549ec6..f4ebab41bc8bc 100644 --- a/console/src/components/McpConnectInstructions.tsx +++ b/console/src/components/McpConnectInstructions.tsx @@ -85,7 +85,14 @@ const McpConnectInstructions = ({ built-in MCP server. - + 1. Get your MCP token {isCloud && onGenerateToken && ( From a70be203e21dfa28fa61dbebbc3a3b1b108d7e86 Mon Sep 17 00:00:00 2001 From: Justin Bradfield Date: Sat, 9 May 2026 00:43:12 -0500 Subject: [PATCH 3/4] Update console/src/components/McpConnectInstructions.tsx Co-authored-by: Qindeel Ishtiaq --- console/src/components/McpConnectInstructions.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/console/src/components/McpConnectInstructions.tsx b/console/src/components/McpConnectInstructions.tsx index f4ebab41bc8bc..056f1a5d5a074 100644 --- a/console/src/components/McpConnectInstructions.tsx +++ b/console/src/components/McpConnectInstructions.tsx @@ -96,7 +96,7 @@ const McpConnectInstructions = ({ 1. Get your MCP token {isCloud && onGenerateToken && ( - + Generate a new token: From c471887b7d51a7bc607867f49a4bd264ea9c4b1a Mon Sep 17 00:00:00 2001 From: Justin Bradfield Date: Sat, 9 May 2026 00:44:06 -0500 Subject: [PATCH 4/4] Apply suggestions from code review Co-authored-by: Qindeel Ishtiaq --- .../src/components/McpConnectInstructions.tsx | 47 +++++++++---------- console/src/components/copyableComponents.tsx | 10 ++-- 2 files changed, 27 insertions(+), 30 deletions(-) diff --git a/console/src/components/McpConnectInstructions.tsx b/console/src/components/McpConnectInstructions.tsx index 056f1a5d5a074..838033203dc69 100644 --- a/console/src/components/McpConnectInstructions.tsx +++ b/console/src/components/McpConnectInstructions.tsx @@ -72,31 +72,17 @@ const McpConnectInstructions = ({ const claudeCodeCliCommand = `claude mcp add --transport http materialize-${endpoint} \\\n ${endpointUrl} \\\n --header "Authorization: Basic "`; return ( - + Connect your AI agent or coding assistant to Materialize using the built-in MCP server. - + 1. Get your MCP token {isCloud && onGenerateToken && ( - + Generate a new token: @@ -124,14 +110,23 @@ const McpConnectInstructions = ({ ) : ( - + <> + + + For service accounts, create a{" "} + + service app password + {" "} + and Base64-encode it below. + + )} )} @@ -151,7 +146,7 @@ const McpConnectInstructions = ({ - + 2. Connect your client See the{" "} diff --git a/console/src/components/copyableComponents.tsx b/console/src/components/copyableComponents.tsx index 326f6fabefda2..c4df1b9ef7540 100644 --- a/console/src/components/copyableComponents.tsx +++ b/console/src/components/copyableComponents.tsx @@ -126,11 +126,13 @@ export const CopyableBox: React.FC = ({ as="pre" fontFamily="mono" pl={4} - py={2} + pr={wrap ? 2 : 0} + py={wrap ? 3 : 2} flex={1} - lineHeight="4" - whiteSpace={wrap ? "pre" : "nowrap"} - overflow="hidden" + lineHeight={wrap ? "tall" : "4"} + whiteSpace={wrap ? "pre-wrap" : "nowrap"} + overflow={wrap ? "auto" : "hidden"} + overflowWrap={wrap ? "anywhere" : undefined} textOverflow={wrap ? undefined : "ellipsis"} minWidth={0} {...(maxHeight && {