Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions packages/cli/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# @mcp-use/cli

## 2.1.8

### Patch Changes

- Updated dependencies
- @mcp-use/[email protected]
- [email protected]

## 2.1.7

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@mcp-use/cli",
"version": "2.1.7",
"version": "2.1.8",
"description": "Build tool for MCP UI widgets - bundles React components into standalone HTML pages for Model Context Protocol servers",
"author": "mcp-use, Inc.",
"license": "MIT",
Expand Down
8 changes: 8 additions & 0 deletions packages/inspector/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# @mcp-use/inspector

## 0.3.8

### Patch Changes

- fix: support multiple clients per server
- Updated dependencies
- [email protected]

## 0.3.7

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/inspector/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@mcp-use/inspector",
"type": "module",
"version": "0.3.7",
"version": "0.3.8",
"description": "MCP Inspector - A tool for inspecting and debugging MCP servers",
"author": "",
"license": "MIT",
Expand Down
13 changes: 9 additions & 4 deletions packages/inspector/src/client/components/InspectorDashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,13 @@ export function InspectorDashboard() {
}, {} as Record<string, string>),
}

// Map UI transport type to actual transport type
// "SSE" in UI means "Streamable HTTP" which uses 'http' transport
// "WebSocket" in UI means "WebSocket" which uses 'sse' transport
const actualTransportType = transportType === 'SSE' ? 'http' : 'sse'

// For now, use URL as both ID and name - this will need proper implementation
addConnection(url, url, proxyConfig)
addConnection(url, url, proxyConfig, actualTransportType)
}

const handleClearAllConnections = () => {
Expand Down Expand Up @@ -222,7 +227,7 @@ export function InspectorDashboard() {
>
<Badge variant="secondary" className="text-xs cursor-pointer hover:bg-secondary/80 transition-colors">
v
{typeof window !== 'undefined' && (window as any).__INSPECTOR_VERSION__ || '1.0.0'}
{(typeof window !== 'undefined' && (window as any).__INSPECTOR_VERSION__) || '1.0.0'}
</Badge>
</a>
</TooltipTrigger>
Expand Down Expand Up @@ -268,7 +273,7 @@ export function InspectorDashboard() {
<div className="flex items-center gap-3">
<h4 className="font-semibold text-sm">{connection.name}</h4>
<div className="flex items-center gap-2">
{connection.error
{connection.error && connection.state !== 'ready'
? (
<Tooltip>
<TooltipTrigger asChild>
Expand Down Expand Up @@ -399,7 +404,7 @@ export function InspectorDashboard() {
</SelectTrigger>
<SelectContent>
<SelectItem value="SSE">Streamable HTTP</SelectItem>
<SelectItem value="WebSocket">WebSocket</SelectItem>
<SelectItem value="WebSocket">Server-Sent Events (SSE)</SelectItem>
</SelectContent>
</Select>
</div>
Expand Down
6 changes: 3 additions & 3 deletions packages/inspector/src/client/components/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ export function Layout({ children }: LayoutProps) {
const existing = connections.find(c => c.url === autoConnectUrl)
if (!existing) {
setIsAutoConnecting(true)
addConnection(autoConnectUrl, 'Local MCP Server')
addConnection(autoConnectUrl, 'Local MCP Server', undefined, 'http')
// Navigate immediately but keep loading screen visible a bit longer to avoid flash
navigate(`/servers/${encodeURIComponent(autoConnectUrl)}`)
setTimeout(() => {
Expand All @@ -254,7 +254,7 @@ export function Layout({ children }: LayoutProps) {
const existing = connections.find(c => c.url === config.autoConnectUrl)
if (!existing) {
// Auto-connect to the local server
addConnection(config.autoConnectUrl, 'Local MCP Server')
addConnection(config.autoConnectUrl, 'Local MCP Server', undefined, 'http')
}
}
})
Expand Down Expand Up @@ -383,7 +383,7 @@ export function Layout({ children }: LayoutProps) {
</span>
{selectedServer && (
<div className="flex items-center gap-2">
{selectedServer.error
{selectedServer.error && selectedServer.state !== 'ready'
? (
<Tooltip>
<TooltipTrigger asChild>
Expand Down
26 changes: 20 additions & 6 deletions packages/inspector/src/client/context/McpContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ interface MCPConnection {

interface McpContextType {
connections: MCPConnection[]
addConnection: (url: string, name?: string, proxyConfig?: { proxyAddress?: string, proxyToken?: string, customHeaders?: Record<string, string> }) => void
addConnection: (url: string, name?: string, proxyConfig?: { proxyAddress?: string, proxyToken?: string, customHeaders?: Record<string, string> }, transportType?: 'http' | 'sse') => void
removeConnection: (id: string) => void
getConnection: (id: string) => MCPConnection | undefined
}
Expand All @@ -33,12 +33,14 @@ interface SavedConnection {
url: string
name: string
proxyConfig?: { proxyAddress?: string, proxyToken?: string, customHeaders?: Record<string, string> }
transportType?: 'http' | 'sse'
}

function McpConnectionWrapper({ url, name, proxyConfig, onUpdate, onRemove: _onRemove }: {
function McpConnectionWrapper({ url, name, proxyConfig, transportType, onUpdate, onRemove: _onRemove }: {
url: string
name: string
proxyConfig?: { proxyAddress?: string, proxyToken?: string, customHeaders?: Record<string, string> }
transportType?: 'http' | 'sse'
onUpdate: (connection: MCPConnection) => void
onRemove: () => void
}) {
Expand Down Expand Up @@ -79,6 +81,7 @@ function McpConnectionWrapper({ url, name, proxyConfig, onUpdate, onRemove: _onR
url: finalUrl,
callbackUrl,
customHeaders: Object.keys(customHeaders).length > 0 ? customHeaders : undefined,
transportType: transportType || 'http', // Default to 'http' for Streamable HTTP
})
const onUpdateRef = useRef(onUpdate)
const prevConnectionRef = useRef<MCPConnection | null>(null)
Expand Down Expand Up @@ -194,12 +197,21 @@ export function McpProvider({ children }: { children: ReactNode }) {
&& typeof conn.id === 'string'
&& typeof conn.url === 'string'
&& typeof conn.name === 'string'
}).map((conn: any) => {
// Migrate existing connections to include transportType
if (!conn.transportType) {
conn.transportType = 'http' // Default to 'http' for Streamable HTTP
}
return conn
})
: []

// If we filtered out any invalid connections, update localStorage
if (validConnections.length !== parsed.length) {
console.warn('Cleaned up invalid connections from localStorage')
// If we filtered out any invalid connections or migrated transport types, update localStorage
const hasChanges = validConnections.length !== parsed.length
|| validConnections.some((conn: any) => conn.transportType === 'http' && !parsed.find((p: any) => p.id === conn.id && p.transportType))

if (hasChanges) {
console.warn('Updated connections in localStorage with transport type migration')
localStorage.setItem('mcp-inspector-connections', JSON.stringify(validConnections))
}

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

const addConnection = useCallback((url: string, name?: string, proxyConfig?: { proxyAddress?: string, proxyToken?: string, customHeaders?: Record<string, string> }) => {
const addConnection = useCallback((url: string, name?: string, proxyConfig?: { proxyAddress?: string, proxyToken?: string, customHeaders?: Record<string, string> }, transportType?: 'http' | 'sse') => {
const connectionName = name || url
const newConnection: SavedConnection = {
id: url,
url,
name: connectionName,
proxyConfig,
transportType: transportType || 'http', // Default to 'http' for Streamable HTTP
}

setSavedConnections((prev) => {
Expand Down Expand Up @@ -289,6 +302,7 @@ export function McpProvider({ children }: { children: ReactNode }) {
url={saved.url}
name={saved.name}
proxyConfig={saved.proxyConfig}
transportType={saved.transportType}
onUpdate={updateConnection}
onRemove={() => removeConnection(saved.id)}
/>
Expand Down
8 changes: 8 additions & 0 deletions packages/mcp-use/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# mcp-use

## 1.0.4

### Patch Changes

- fix: support multiple clients per server
- Updated dependencies
- @mcp-use/[email protected]

## 1.0.3

### Patch Changes
Expand Down
4 changes: 2 additions & 2 deletions packages/mcp-use/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "mcp-use",
"type": "module",
"version": "1.0.3",
"version": "1.0.4",
"packageManager": "[email protected]",
"description": "Opinionated MCP Framework for TypeScript (@modelcontextprotocol/sdk compatible) - Build MCP Agents and Clients + MCP Servers with support for MCP-UI.",
"author": "mcp-use, Inc.",
Expand Down Expand Up @@ -88,7 +88,7 @@
"example:observability": "tsx examples/client/observability.ts"
},
"peerDependencies": {
"@mcp-use/inspector": "^0.3.7",
"@mcp-use/inspector": "^0.3.8",
"cors": "^2.8.5",
"express": "^4.18.2",
"langfuse": "^3.32.0",
Expand Down
56 changes: 40 additions & 16 deletions packages/mcp-use/src/server/mcp-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export class McpServer {
this.app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*')
res.header('Access-Control-Allow-Methods', 'GET, POST, DELETE, OPTIONS')
res.header('Access-Control-Allow-Headers', 'Content-Type')
res.header('Access-Control-Allow-Headers', 'Content-Type, Accept, Authorization, mcp-protocol-version, mcp-session-id, X-Proxy-Token, X-Target-URL')
next()
})

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

const { StreamableHTTPServerTransport } = await import('@modelcontextprotocol/sdk/server/streamableHttp.js')

// Create StreamableHTTPServerTransport in stateless mode
const httpTransport = new StreamableHTTPServerTransport({
sessionIdGenerator: undefined // Stateless mode
})

// Connect the MCP server to the transport
await this.server.connect(httpTransport)

const endpoint = '/mcp'

// POST endpoint for messages
// Create a new transport for each request to support multiple concurrent clients
this.app.post(endpoint, express.json(), async (req, res) => {
const transport = new StreamableHTTPServerTransport({
sessionIdGenerator: undefined,
enableJsonResponse: true
})

res.on('close', () => {
transport.close()
})

await this.server.connect(transport)
await transport.handleRequest(req, res, req.body)
})

// GET endpoint for SSE streaming
this.app.get(endpoint, async (req, res) => {
await httpTransport.handleRequest(req, res)
})
const transport = new StreamableHTTPServerTransport({
sessionIdGenerator: undefined,
enableJsonResponse: true
})

// POST endpoint for messages
this.app.post(endpoint, express.json(), async (req, res) => {
await httpTransport.handleRequest(req, res, req.body)
res.on('close', () => {
transport.close()
})

await this.server.connect(transport)
await transport.handleRequest(req, res)
})

// DELETE endpoint for session cleanup
this.app.delete(endpoint, async (req, res) => {
await httpTransport.handleRequest(req, res)
const transport = new StreamableHTTPServerTransport({
sessionIdGenerator: undefined,
enableJsonResponse: true
})

res.on('close', () => {
transport.close()
})

await this.server.connect(transport)
await transport.handleRequest(req, res)
})

this.mcpMounted = true
Expand Down
6 changes: 6 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading