Skip to content

Commit cec4ed2

Browse files
committed
feat(inspector): implement auto-connect feature for MCP server in Layout component
- Update inspector URL to include autoConnect query parameter for seamless connection - Add state management for auto-connection and loading spinner in Layout component - Enhance user experience by navigating to the server page while displaying a loading state
1 parent dc06590 commit cec4ed2

File tree

2 files changed

+62
-6
lines changed

2 files changed

+62
-6
lines changed

packages/cli/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,8 +175,8 @@ program
175175
const startTime = Date.now();
176176
const ready = await waitForServer(port);
177177
if (ready) {
178-
const inspectorUrl = `http://localhost:${port}/inspector`;
179178
const mcpUrl = `http://localhost:${port}/mcp`;
179+
const inspectorUrl = `http://localhost:${port}/inspector?autoConnect=${encodeURIComponent(mcpUrl)}`;
180180
const readyTime = Date.now() - startTime;
181181
console.log(`\n\x1b[32m✓\x1b[0m Ready in ${readyTime}ms`);
182182
console.log(`Local: http://localhost:${port}`);

packages/inspector/src/client/components/Layout.tsx

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { useLocation, useNavigate } from 'react-router-dom'
55
import { toast } from 'sonner'
66
import LogoAnimated from '@/components/LogoAnimated'
77
import { ShimmerButton } from '@/components/ui/shimmer-button'
8+
import { Spinner } from '@/components/ui/spinner'
89
import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs'
910
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'
1011
import { cn } from '@/lib/utils'
@@ -94,6 +95,7 @@ export function Layout({ children }: LayoutProps) {
9495
const [selectedServerId, setSelectedServerId] = useState<string | null>(null)
9596
const [configLoaded, setConfigLoaded] = useState(false)
9697
const [isCommandPaletteOpen, setIsCommandPaletteOpen] = useState(false)
98+
const [isAutoConnecting, setIsAutoConnecting] = useState(false)
9799

98100
const tabs = [
99101
{ id: 'tools', label: 'Tools', icon: Wrench },
@@ -153,6 +155,27 @@ export function Layout({ children }: LayoutProps) {
153155
if (configLoaded)
154156
return
155157

158+
// Check for autoConnect query parameter first
159+
const urlParams = new URLSearchParams(window.location.search)
160+
const autoConnectUrl = urlParams.get('autoConnect')
161+
162+
if (autoConnectUrl) {
163+
// Auto-connect to the URL from query parameter
164+
const existing = connections.find(c => c.url === autoConnectUrl)
165+
if (!existing) {
166+
setIsAutoConnecting(true)
167+
addConnection(autoConnectUrl, 'Local MCP Server')
168+
// Navigate immediately but keep loading screen visible a bit longer to avoid flash
169+
navigate(`/servers/${encodeURIComponent(autoConnectUrl)}`)
170+
setTimeout(() => {
171+
setIsAutoConnecting(false)
172+
}, 1000)
173+
}
174+
setConfigLoaded(true)
175+
return
176+
}
177+
178+
// Fallback to config.json
156179
fetch('/inspector/config.json')
157180
.then(res => res.json())
158181
.then((config: { autoConnectUrl: string | null }) => {
@@ -247,6 +270,18 @@ export function Layout({ children }: LayoutProps) {
247270
return () => document.removeEventListener('keydown', handleKeyDown)
248271
}, [])
249272

273+
// Show loading spinner during auto-connection
274+
if (isAutoConnecting) {
275+
return (
276+
<div className="h-screen bg-white dark:bg-zinc-900 flex items-center justify-center">
277+
<div className="flex flex-col items-center gap-4">
278+
<Spinner className="h-8 w-8 text-zinc-600 dark:text-zinc-400" />
279+
<p className="text-sm text-zinc-600 dark:text-zinc-400">Connecting to MCP server...</p>
280+
</div>
281+
</div>
282+
)
283+
}
284+
250285
return (
251286
<TooltipProvider>
252287
<div className="h-screen bg-[#f3f3f3] dark:bg-zinc-900 flex flex-col px-4 py-4 gap-4">
@@ -316,11 +351,32 @@ export function Layout({ children }: LayoutProps) {
316351
{selectedServer && (
317352
<Tabs value={activeTab} onValueChange={setActiveTab}>
318353
<TabsList>
319-
{tabs.map(tab => (
320-
<TabsTrigger key={tab.id} value={tab.id} icon={tab.icon}>
321-
{tab.label}
322-
</TabsTrigger>
323-
))}
354+
{tabs.map((tab) => {
355+
// Get count for the current tab
356+
let count = 0
357+
if (tab.id === 'tools') {
358+
count = selectedServer.tools.length
359+
}
360+
else if (tab.id === 'prompts') {
361+
count = selectedServer.prompts.length
362+
}
363+
else if (tab.id === 'resources') {
364+
count = selectedServer.resources.length
365+
}
366+
367+
return (
368+
<TabsTrigger key={tab.id} value={tab.id} icon={tab.icon}>
369+
<div className="flex items-center gap-2">
370+
{tab.label}
371+
{count > 0 && (
372+
<span className="bg-zinc-200 dark:bg-zinc-700 text-zinc-700 dark:text-zinc-300 text-xs px-2 py-0.5 rounded-full font-medium">
373+
{count}
374+
</span>
375+
)}
376+
</div>
377+
</TabsTrigger>
378+
)
379+
})}
324380
</TabsList>
325381
</Tabs>
326382
)}

0 commit comments

Comments
 (0)