MCPToggleModal - Add button to open config (#2743)

* make ServerRow not optionally not expandable

* changeset

* factor out servers toggle list

* changeset

* add servers modal

* changest

* Reduce padding in modal

* separate fetch useEffect for more efficient rendering

* add button to open installed servers config

* changeset

* add mcptab type

* change codicon

* modify button display

---------

Co-authored-by: Saoud Rizwan <7799382+saoudrizwan@users.noreply.github.com>
This commit is contained in:
Evan 2025-04-10 16:25:08 -07:00 committed by GitHub
parent fb037a05c1
commit 47aecdfc75
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 38 additions and 9 deletions

View File

@ -0,0 +1,5 @@
---
"claude-dev": minor
---
Add button to open config to MCP toggle modal

View File

@ -575,7 +575,7 @@ export class Controller {
break
}
case "showMcpView": {
await this.postMessageToWebview({ type: "action", action: "mcpButtonClicked" })
await this.postMessageToWebview({ type: "action", action: "mcpButtonClicked", tab: message.tab || undefined })
break
}
case "openMcpSettings": {

View File

@ -6,7 +6,7 @@ import { AutoApprovalSettings } from "./AutoApprovalSettings"
import { BrowserSettings } from "./BrowserSettings"
import { ChatSettings } from "./ChatSettings"
import { HistoryItem } from "./HistoryItem"
import { McpServer, McpMarketplaceCatalog, McpMarketplaceItem, McpDownloadResponse } from "./mcp"
import { McpServer, McpMarketplaceCatalog, McpMarketplaceItem, McpDownloadResponse, McpViewTab } from "./mcp"
import { TelemetrySetting } from "./TelemetrySetting"
import type { BalanceResponse, UsageTransaction, PaymentTransaction } from "../shared/ClineAccount"
@ -106,6 +106,7 @@ export interface ExtensionMessage {
serverName: string
error?: string
}
tab?: McpViewTab
}
export type Invoke = "sendMessage" | "primaryButtonClick" | "secondaryButtonClick"

View File

@ -5,6 +5,7 @@ import { ChatSettings } from "./ChatSettings"
import { UserInfo } from "./UserInfo"
import { ChatContent } from "./ChatContent"
import { TelemetrySetting } from "./TelemetrySetting"
import { McpViewTab } from "./mcp"
export interface WebviewMessage {
type:
@ -93,6 +94,7 @@ export interface WebviewMessage {
chatContent?: ChatContent
mcpId?: string
timeout?: number
tab?: McpViewTab
// For toggleToolAutoApprove
serverName?: string
serverUrl?: string

View File

@ -105,3 +105,5 @@ export interface McpDownloadResponse {
llmsInstallationContent: string
requiresApiKey: boolean
}
export type McpViewTab = "marketplace" | "addRemote" | "installed"

View File

@ -10,6 +10,7 @@ import { ExtensionStateContextProvider, useExtensionState } from "./context/Exte
import { FirebaseAuthProvider } from "./context/FirebaseAuthContext"
import { vscode } from "./utils/vscode"
import McpView from "./components/mcp/configuration/McpConfigurationView"
import { McpViewTab } from "@shared/mcp"
const AppContent = () => {
const { didHydrateState, showWelcome, shouldShowAnnouncement, telemetrySetting, vscMachineId } = useExtensionState()
@ -18,6 +19,7 @@ const AppContent = () => {
const [showMcp, setShowMcp] = useState(false)
const [showAccount, setShowAccount] = useState(false)
const [showAnnouncement, setShowAnnouncement] = useState(false)
const [mcpTab, setMcpTab] = useState<McpViewTab | undefined>(undefined)
const handleMessage = useCallback((e: MessageEvent) => {
const message: ExtensionMessage = e.data
@ -39,6 +41,9 @@ const AppContent = () => {
case "mcpButtonClicked":
setShowSettings(false)
setShowHistory(false)
if (message.tab) {
setMcpTab(message.tab)
}
setShowMcp(true)
setShowAccount(false)
break
@ -89,7 +94,7 @@ const AppContent = () => {
<>
{showSettings && <SettingsView onDone={() => setShowSettings(false)} />}
{showHistory && <HistoryView onDone={() => setShowHistory(false)} />}
{showMcp && <McpView onDone={() => setShowMcp(false)} />}
{showMcp && <McpView initialTab={mcpTab} onDone={() => setShowMcp(false)} />}
{showAccount && <AccountView onDone={() => setShowAccount(false)} />}
{/* Do not conditionally load ChatView, it's expensive and there's state we don't want to lose (user input, disableInput, askResponse promise, etc.) */}
<ChatView

View File

@ -73,10 +73,22 @@ const ServersToggleModal: React.FC = () => {
}}
/>
<div className="m-0 mb-2.5">MCP Servers</div>
<div style={{ marginBottom: "-10px" }}>
<ServersToggleList servers={mcpServers} isExpandable={false} hasTrashIcon={false} listGap="small" />
<div className="flex justify-between items-center mb-2.5">
<h3 className="m-0">MCP Servers</h3>
<VSCodeButton
appearance="icon"
onClick={() => {
vscode.postMessage({
type: "showMcpView",
tab: "installed",
})
setIsVisible(false)
}}>
<span className="codicon codicon-gear text-[10px]"></span>
</VSCodeButton>
</div>
<ServersToggleList servers={mcpServers} isExpandable={false} hasTrashIcon={false} listGap="small" />
</div>
)}
</div>

View File

@ -6,16 +6,18 @@ import { vscode } from "@/utils/vscode"
import AddRemoteServerForm from "./tabs/add-server/AddRemoteServerForm"
import McpMarketplaceView from "./tabs/marketplace/McpMarketplaceView"
import InstalledServersView from "./tabs/installed/InstalledServersView"
import { McpViewTab } from "@shared/mcp"
type McpViewProps = {
onDone: () => void
initialTab?: McpViewTab
}
const McpConfigurationView = ({ onDone }: McpViewProps) => {
const McpConfigurationView = ({ onDone, initialTab }: McpViewProps) => {
const { mcpMarketplaceEnabled } = useExtensionState()
const [activeTab, setActiveTab] = useState(mcpMarketplaceEnabled ? "marketplace" : "installed")
const [activeTab, setActiveTab] = useState<McpViewTab>(initialTab || (mcpMarketplaceEnabled ? "marketplace" : "installed"))
const handleTabChange = (tab: string) => {
const handleTabChange = (tab: McpViewTab) => {
setActiveTab(tab)
}