Skip to content

Commit 1bbe767

Browse files
authored
fix: inspector connector status and transport improvements (#75)
* fix status dot * fix: 1 transport per request * chore: version packages and update changelogs
1 parent 78539be commit 1bbe767

File tree

11 files changed

+106
-33
lines changed

11 files changed

+106
-33
lines changed

packages/cli/CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# @mcp-use/cli
22

3+
## 2.1.8
4+
5+
### Patch Changes
6+
7+
- Updated dependencies
8+
- @mcp-use/inspector@0.3.8
9+
10+
311
## 2.1.7
412

513
### Patch Changes

packages/cli/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@mcp-use/cli",
3-
"version": "2.1.7",
3+
"version": "2.1.8",
44
"description": "Build tool for MCP UI widgets - bundles React components into standalone HTML pages for Model Context Protocol servers",
55
"author": "mcp-use, Inc.",
66
"license": "MIT",

packages/inspector/CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# @mcp-use/inspector
22

3+
## 0.3.8
4+
5+
### Patch Changes
6+
7+
- fix: support multiple clients per server
8+
- Updated dependencies
9+
10+
311
## 0.3.7
412

513
### Patch Changes

packages/inspector/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@mcp-use/inspector",
33
"type": "module",
4-
"version": "0.3.7",
4+
"version": "0.3.8",
55
"description": "MCP Inspector - A tool for inspecting and debugging MCP servers",
66
"author": "",
77
"license": "MIT",

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

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,13 @@ export function InspectorDashboard() {
124124
}, {} as Record<string, string>),
125125
}
126126

127+
// Map UI transport type to actual transport type
128+
// "SSE" in UI means "Streamable HTTP" which uses 'http' transport
129+
// "WebSocket" in UI means "WebSocket" which uses 'sse' transport
130+
const actualTransportType = transportType === 'SSE' ? 'http' : 'sse'
131+
127132
// For now, use URL as both ID and name - this will need proper implementation
128-
addConnection(url, url, proxyConfig)
133+
addConnection(url, url, proxyConfig, actualTransportType)
129134
}
130135

131136
const handleClearAllConnections = () => {
@@ -222,7 +227,7 @@ export function InspectorDashboard() {
222227
>
223228
<Badge variant="secondary" className="text-xs cursor-pointer hover:bg-secondary/80 transition-colors">
224229
v
225-
{typeof window !== 'undefined' && (window as any).__INSPECTOR_VERSION__ || '1.0.0'}
230+
{(typeof window !== 'undefined' && (window as any).__INSPECTOR_VERSION__) || '1.0.0'}
226231
</Badge>
227232
</a>
228233
</TooltipTrigger>
@@ -268,7 +273,7 @@ export function InspectorDashboard() {
268273
<div className="flex items-center gap-3">
269274
<h4 className="font-semibold text-sm">{connection.name}</h4>
270275
<div className="flex items-center gap-2">
271-
{connection.error
276+
{connection.error && connection.state !== 'ready'
272277
? (
273278
<Tooltip>
274279
<TooltipTrigger asChild>
@@ -399,7 +404,7 @@ export function InspectorDashboard() {
399404
</SelectTrigger>
400405
<SelectContent>
401406
<SelectItem value="SSE">Streamable HTTP</SelectItem>
402-
<SelectItem value="WebSocket">WebSocket</SelectItem>
407+
<SelectItem value="WebSocket">Server-Sent Events (SSE)</SelectItem>
403408
</SelectContent>
404409
</Select>
405410
</div>

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ export function Layout({ children }: LayoutProps) {
233233
const existing = connections.find(c => c.url === autoConnectUrl)
234234
if (!existing) {
235235
setIsAutoConnecting(true)
236-
addConnection(autoConnectUrl, 'Local MCP Server')
236+
addConnection(autoConnectUrl, 'Local MCP Server', undefined, 'http')
237237
// Navigate immediately but keep loading screen visible a bit longer to avoid flash
238238
navigate(`/servers/${encodeURIComponent(autoConnectUrl)}`)
239239
setTimeout(() => {
@@ -254,7 +254,7 @@ export function Layout({ children }: LayoutProps) {
254254
const existing = connections.find(c => c.url === config.autoConnectUrl)
255255
if (!existing) {
256256
// Auto-connect to the local server
257-
addConnection(config.autoConnectUrl, 'Local MCP Server')
257+
addConnection(config.autoConnectUrl, 'Local MCP Server', undefined, 'http')
258258
}
259259
}
260260
})
@@ -383,7 +383,7 @@ export function Layout({ children }: LayoutProps) {
383383
</span>
384384
{selectedServer && (
385385
<div className="flex items-center gap-2">
386-
{selectedServer.error
386+
{selectedServer.error && selectedServer.state !== 'ready'
387387
? (
388388
<Tooltip>
389389
<TooltipTrigger asChild>

packages/inspector/src/client/context/McpContext.tsx

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ interface MCPConnection {
2121

2222
interface McpContextType {
2323
connections: MCPConnection[]
24-
addConnection: (url: string, name?: string, proxyConfig?: { proxyAddress?: string, proxyToken?: string, customHeaders?: Record<string, string> }) => void
24+
addConnection: (url: string, name?: string, proxyConfig?: { proxyAddress?: string, proxyToken?: string, customHeaders?: Record<string, string> }, transportType?: 'http' | 'sse') => void
2525
removeConnection: (id: string) => void
2626
getConnection: (id: string) => MCPConnection | undefined
2727
}
@@ -33,12 +33,14 @@ interface SavedConnection {
3333
url: string
3434
name: string
3535
proxyConfig?: { proxyAddress?: string, proxyToken?: string, customHeaders?: Record<string, string> }
36+
transportType?: 'http' | 'sse'
3637
}
3738

38-
function McpConnectionWrapper({ url, name, proxyConfig, onUpdate, onRemove: _onRemove }: {
39+
function McpConnectionWrapper({ url, name, proxyConfig, transportType, onUpdate, onRemove: _onRemove }: {
3940
url: string
4041
name: string
4142
proxyConfig?: { proxyAddress?: string, proxyToken?: string, customHeaders?: Record<string, string> }
43+
transportType?: 'http' | 'sse'
4244
onUpdate: (connection: MCPConnection) => void
4345
onRemove: () => void
4446
}) {
@@ -79,6 +81,7 @@ function McpConnectionWrapper({ url, name, proxyConfig, onUpdate, onRemove: _onR
7981
url: finalUrl,
8082
callbackUrl,
8183
customHeaders: Object.keys(customHeaders).length > 0 ? customHeaders : undefined,
84+
transportType: transportType || 'http', // Default to 'http' for Streamable HTTP
8285
})
8386
const onUpdateRef = useRef(onUpdate)
8487
const prevConnectionRef = useRef<MCPConnection | null>(null)
@@ -194,12 +197,21 @@ export function McpProvider({ children }: { children: ReactNode }) {
194197
&& typeof conn.id === 'string'
195198
&& typeof conn.url === 'string'
196199
&& typeof conn.name === 'string'
200+
}).map((conn: any) => {
201+
// Migrate existing connections to include transportType
202+
if (!conn.transportType) {
203+
conn.transportType = 'http' // Default to 'http' for Streamable HTTP
204+
}
205+
return conn
197206
})
198207
: []
199208

200-
// If we filtered out any invalid connections, update localStorage
201-
if (validConnections.length !== parsed.length) {
202-
console.warn('Cleaned up invalid connections from localStorage')
209+
// If we filtered out any invalid connections or migrated transport types, update localStorage
210+
const hasChanges = validConnections.length !== parsed.length
211+
|| validConnections.some((conn: any) => conn.transportType === 'http' && !parsed.find((p: any) => p.id === conn.id && p.transportType))
212+
213+
if (hasChanges) {
214+
console.warn('Updated connections in localStorage with transport type migration')
203215
localStorage.setItem('mcp-inspector-connections', JSON.stringify(validConnections))
204216
}
205217

@@ -218,13 +230,14 @@ export function McpProvider({ children }: { children: ReactNode }) {
218230
setConnectionVersion(v => v + 1)
219231
}, [])
220232

221-
const addConnection = useCallback((url: string, name?: string, proxyConfig?: { proxyAddress?: string, proxyToken?: string, customHeaders?: Record<string, string> }) => {
233+
const addConnection = useCallback((url: string, name?: string, proxyConfig?: { proxyAddress?: string, proxyToken?: string, customHeaders?: Record<string, string> }, transportType?: 'http' | 'sse') => {
222234
const connectionName = name || url
223235
const newConnection: SavedConnection = {
224236
id: url,
225237
url,
226238
name: connectionName,
227239
proxyConfig,
240+
transportType: transportType || 'http', // Default to 'http' for Streamable HTTP
228241
}
229242

230243
setSavedConnections((prev) => {
@@ -289,6 +302,7 @@ export function McpProvider({ children }: { children: ReactNode }) {
289302
url={saved.url}
290303
name={saved.name}
291304
proxyConfig={saved.proxyConfig}
305+
transportType={saved.transportType}
292306
onUpdate={updateConnection}
293307
onRemove={() => removeConnection(saved.id)}
294308
/>

packages/mcp-use/CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# mcp-use
22

3+
## 1.0.4
4+
5+
### Patch Changes
6+
7+
- fix: support multiple clients per server
8+
- Updated dependencies
9+
- @mcp-use/inspector@0.3.8
10+
311
## 1.0.3
412

513
### Patch Changes

packages/mcp-use/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "mcp-use",
33
"type": "module",
4-
"version": "1.0.3",
4+
"version": "1.0.4",
55
"packageManager": "[email protected]",
66
"description": "Opinionated MCP Framework for TypeScript (@modelcontextprotocol/sdk compatible) - Build MCP Agents and Clients + MCP Servers with support for MCP-UI.",
77
"author": "mcp-use, Inc.",
@@ -88,7 +88,7 @@
8888
"example:observability": "tsx examples/client/observability.ts"
8989
},
9090
"peerDependencies": {
91-
"@mcp-use/inspector": "^0.3.7",
91+
"@mcp-use/inspector": "^0.3.8",
9292
"cors": "^2.8.5",
9393
"express": "^4.18.2",
9494
"langfuse": "^3.32.0",

packages/mcp-use/src/server/mcp-server.ts

Lines changed: 40 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export class McpServer {
4646
this.app.use((req, res, next) => {
4747
res.header('Access-Control-Allow-Origin', '*')
4848
res.header('Access-Control-Allow-Methods', 'GET, POST, DELETE, OPTIONS')
49-
res.header('Access-Control-Allow-Headers', 'Content-Type')
49+
res.header('Access-Control-Allow-Headers', 'Content-Type, Accept, Authorization, mcp-protocol-version, mcp-session-id, X-Proxy-Token, X-Target-URL')
5050
next()
5151
})
5252

@@ -296,7 +296,8 @@ export class McpServer {
296296
*
297297
* Sets up the HTTP transport layer for the MCP server, creating endpoints for
298298
* Server-Sent Events (SSE) streaming, POST message handling, and DELETE session cleanup.
299-
* Uses stateless mode for session management, making it suitable for stateless deployments.
299+
* Each request gets its own transport instance to prevent state conflicts between
300+
* concurrent client connections.
300301
*
301302
* This method is called automatically when the server starts listening and ensures
302303
* that MCP clients can communicate with the server over HTTP.
@@ -314,30 +315,53 @@ export class McpServer {
314315
if (this.mcpMounted) return
315316

316317
const { StreamableHTTPServerTransport } = await import('@modelcontextprotocol/sdk/server/streamableHttp.js')
317-
318-
// Create StreamableHTTPServerTransport in stateless mode
319-
const httpTransport = new StreamableHTTPServerTransport({
320-
sessionIdGenerator: undefined // Stateless mode
321-
})
322-
323-
// Connect the MCP server to the transport
324-
await this.server.connect(httpTransport)
325318

326319
const endpoint = '/mcp'
327320

321+
// POST endpoint for messages
322+
// Create a new transport for each request to support multiple concurrent clients
323+
this.app.post(endpoint, express.json(), async (req, res) => {
324+
const transport = new StreamableHTTPServerTransport({
325+
sessionIdGenerator: undefined,
326+
enableJsonResponse: true
327+
})
328+
329+
res.on('close', () => {
330+
transport.close()
331+
})
332+
333+
await this.server.connect(transport)
334+
await transport.handleRequest(req, res, req.body)
335+
})
336+
328337
// GET endpoint for SSE streaming
329338
this.app.get(endpoint, async (req, res) => {
330-
await httpTransport.handleRequest(req, res)
331-
})
339+
const transport = new StreamableHTTPServerTransport({
340+
sessionIdGenerator: undefined,
341+
enableJsonResponse: true
342+
})
332343

333-
// POST endpoint for messages
334-
this.app.post(endpoint, express.json(), async (req, res) => {
335-
await httpTransport.handleRequest(req, res, req.body)
344+
res.on('close', () => {
345+
transport.close()
346+
})
347+
348+
await this.server.connect(transport)
349+
await transport.handleRequest(req, res)
336350
})
337351

338352
// DELETE endpoint for session cleanup
339353
this.app.delete(endpoint, async (req, res) => {
340-
await httpTransport.handleRequest(req, res)
354+
const transport = new StreamableHTTPServerTransport({
355+
sessionIdGenerator: undefined,
356+
enableJsonResponse: true
357+
})
358+
359+
res.on('close', () => {
360+
transport.close()
361+
})
362+
363+
await this.server.connect(transport)
364+
await transport.handleRequest(req, res)
341365
})
342366

343367
this.mcpMounted = true

0 commit comments

Comments
 (0)