Skip to main content
The MCP Inspector can be integrated directly into your Express or Hono applications, making it available at a custom path alongside your MCP server.

Auto-Mounting with mcp-use

When using mcp-use to create your MCP server, the inspector is automatically available at /inspector.

Example

import { MCPServer } from 'mcp-use/server'

const server = new MCPServer({
  name: 'my-server',
  version: '1.0.0',
})

// Add your tools, resources, prompts...
server.addTool(/* ... */)

// Start the server
server.listen(3000)

// 🎉 Inspector automatically available at http://localhost:3000/inspector
The inspector is automatically mounted when using mcp-use/server. No additional configuration needed.

Manual Integration

Express Integration

Mount the inspector on an Express application:
import express from 'express'
import { mountInspector } from '@mcp-use/inspector'

const app = express()

// Your Express routes
app.get('/api/health', (req, res) => {
  res.json({ status: 'ok' })
})

// Mount inspector at /inspector
mountInspector(app)

app.listen(3000, () => {
  console.log('Server running on http://localhost:3000')
  console.log('Inspector available at http://localhost:3000/inspector')
})

Hono Integration

Mount the inspector on a Hono application:
import { Hono } from 'hono'
import { mountInspector } from '@mcp-use/inspector'

const app = new Hono()

// Your Hono routes
app.get('/api/health', (c) => {
  return c.json({ status: 'ok' })
})

// Mount inspector at /inspector
mountInspector(app)

// Start server with your Hono adapter
export default app

Path Customization

The inspector is mounted at /inspector by default. To use a different path, you can use a path prefix with your framework:

Express with Custom Path

import express from 'express'
import { mountInspector } from '@mcp-use/inspector'

const app = express()

// Mount at custom path using Express router
const inspectorRouter = express.Router()
mountInspector(inspectorRouter)

app.use('/debug', inspectorRouter)
// Inspector now available at http://localhost:3000/debug/inspector

Hono with Custom Path

import { Hono } from 'hono'
import { mountInspector } from '@mcp-use/inspector'

const app = new Hono()

// Create sub-app for inspector
const inspectorApp = new Hono()
mountInspector(inspectorApp)

app.route('/debug', inspectorApp)
// Inspector now available at http://localhost:3000/debug/inspector

Configuration Options

mountInspector Options

The mountInspector function accepts an optional configuration object:
import { mountInspector } from '@mcp-use/inspector'

mountInspector(app, {
  autoConnectUrl: 'http://localhost:3000/mcp',  // Auto-connect to an MCP server
  devMode: true,                                  // Enable development mode
  sandboxOrigin: 'https://sandbox.example.com',   // Custom sandbox origin
})
OptionTypeDefaultDescription
autoConnectUrlstring | nullundefinedMCP server URL to auto-connect on load
devModebooleantrue if not productionEnables same-origin sandbox for MCP Apps widgets (no subdomain required)
sandboxOriginstring | nullundefinedOverride the sandbox origin for MCP Apps widgets

devMode

When devMode is true, the inspector uses same-origin for the MCP Apps widget sandbox instead of requiring a sandbox-{hostname} subdomain. This is essential when running behind reverse proxies (ngrok, E2B, Cloudflare tunnels) where that subdomain does not exist. When using mcp-use/server, devMode is automatically set to true in development and false in production.

sandboxOrigin

Override the sandbox origin used for MCP Apps widget iframes. Use this when you have a specific domain configured for sandboxed content in production.

Embeddable Chat Components

The inspector also exports client-side chat UI components from @mcp-use/inspector/client for embedding into your own React app.

ChatTab Quick Start

Use ChatTab when you want the full chat experience with the smallest integration surface.
import { ChatTab } from '@mcp-use/inspector/client'

<ChatTab
  connection={connection}
  isConnected={isConnected}
  prompts={prompts}
  serverId={serverId}
  callPrompt={callPrompt}
  readResource={readResource}
  hideTitle
  hideModelBadge
  hideServerUrl
  clearButtonLabel="Start over"
  clearButtonHideShortcut
  clearButtonVariant="ghost"
/>

ChatTab Customization Props

PropTypeDescription
hideTitlebooleanHides the chat header title (Chat)
hideModelBadgebooleanHides the selected model badge in the landing state
hideServerUrlbooleanHides the MCP server URL shown in the landing state
clearButtonLabelstringCustom label for the clear/new-chat button
clearButtonHideIconbooleanHides the clear/new-chat button icon
clearButtonHideShortcutbooleanHides the keyboard shortcut hint on the clear/new-chat button
clearButtonVariant"default" | "secondary" | "ghost" | "outline"Visual button variant for the clear/new-chat button

Advanced Composition (MessageList / ChatHeader / ChatLandingForm)

For custom layouts, compose lower-level exports from @mcp-use/inspector/client. When using MessageList, pass serverBaseUrl from your MCP connection URL so widget resource rendering uses the correct server origin:
import { MessageList } from '@mcp-use/inspector/client'

<MessageList
  messages={messages}
  isLoading={isLoading}
  serverId={connection.url}
  serverBaseUrl={connection.url}
  tools={connection.tools}
  readResource={readResource}
  sendMessage={(text) => sendMessage(text, [])}
/>

Environment Detection

The inspector automatically detects the framework:
  • Express: Detects Express app instance
  • Hono: Detects Hono app instance
  • Auto-detection: Works with both frameworks

Client Files

The inspector includes built client files. If files are missing, you’ll see a warning:
⚠️  MCP Inspector client files not found at /path/to/files
   Run 'yarn build' in the inspector package to build the UI
Solution: Ensure the inspector package is properly built before mounting.

Best Practices

Development vs Production

Development:
  • Mount inspector directly in development
  • Use default /inspector path
  • Enable hot reload for inspector UI
Production:
  • Consider mounting only in staging environments
  • Use custom paths for security
  • Restrict access with authentication middleware

Security Considerations

The inspector provides full access to your MCP server. In production, consider:
  • Adding authentication middleware
  • Restricting to internal networks
  • Using custom paths
  • Disabling in production entirely

Example with Authentication

import express from 'express'
import { mountInspector } from '@mcp-use/inspector'

const app = express()

// Authentication middleware
const requireAuth = (req, res, next) => {
  // Your auth logic
  if (!req.user) {
    return res.status(401).json({ error: 'Unauthorized' })
  }
  next()
}

// Mount inspector behind authentication
app.use('/inspector', requireAuth)
mountInspector(app)

Multiple MCP Servers

When mounting the inspector, it can connect to multiple MCP servers:
  1. Mount inspector once on your main application
  2. Connect to different MCP servers from the inspector UI
  3. Each server appears as a separate connection

CORS Configuration

If your MCP server is on a different origin, configure CORS:
import express from 'express'
import cors from 'cors'
import { mountInspector } from '@mcp-use/inspector'

const app = express()

// Configure CORS for inspector
app.use(cors({
  origin: ['http://localhost:3000', 'https://your-domain.com'],
  credentials: true
}))

mountInspector(app)

Reverse Proxy Support

The inspector and MCP Apps widgets work behind reverse proxies such as ngrok, E2B sandboxes, and Cloudflare tunnels. To set this up:
  1. Set MCP_URL to the public-facing URL of your server. This ensures widget asset URLs and Vite HMR WebSocket connections route correctly through the proxy.
MCP_URL=https://abc123.ngrok.io npx @mcp-use/cli dev
  1. devMode is enabled automatically in development, so MCP Apps widgets use same-origin sandboxing (no sandbox-{hostname} subdomain required).
  2. Vite HMR works through the proxy — a WebSocket proxy forwards HMR connections from the main HTTP server to Vite’s internal port automatically.
See the CLI Environment Variables documentation for more details on MCP_URL.

Widget Server URL

Widgets rendered via MCP Apps have access to a window.__mcpServerUrl global variable containing the server’s origin URL. Use this to construct API URLs dynamically instead of hardcoding localhost:
// Inside a widget
const data = await fetch(`${window.__mcpServerUrl}/api/data`)
This global is injected automatically and works correctly behind reverse proxies.

Embedding Widget Iframes

If you need to embed inspector widgets in iframes from your own application (e.g., embedding widgets in your dashboard or admin panel), you can configure allowed origins using the MCP_INSPECTOR_FRAME_ANCESTORS environment variable.
# Allow embedding from specific domains
MCP_INSPECTOR_FRAME_ANCESTORS="https://app.example.com https://admin.example.com" node server.js

# Or in development, allow all origins
MCP_INSPECTOR_FRAME_ANCESTORS="*" npm run dev
Security Note:
By default, the inspector uses:
  • Development mode (when devServerBaseUrl is detected): frame-ancestors * (allows all origins)
  • Production mode: frame-ancestors 'self' (same-origin only)
This prevents unauthorized sites from embedding your inspector widgets while making development easier.
For more details, see the CLI Environment Variables documentation.

Troubleshooting

Inspector Not Loading

Issue: Inspector page shows blank or errors. Solutions:
  1. Check that client files are built: yarn build in inspector package
  2. Verify the mount path is correct
  3. Check browser console for errors
  4. Ensure no route conflicts with /inspector

Route Conflicts

Issue: Your routes conflict with inspector paths. Solution: Use a custom path or ensure your routes don’t overlap with /inspector/*.

Build Errors

Issue: Inspector fails to mount with build errors. Solutions:
  1. Ensure @mcp-use/inspector is properly installed
  2. Check Node.js version compatibility
  3. Verify all dependencies are installed
  4. Rebuild the inspector package