@mcp-use/inspector 0.3.10 → 0.3.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -25,29 +25,29 @@
25
25
 
26
26
  ## 📦 Related Packages
27
27
 
28
- | Package | Description | Version |
29
- |---------|-------------|---------|
30
- | [mcp-use](https://github.com/mcp-use/mcp-use-ts/tree/main/packages/mcp-use) | Core MCP framework | [![npm](https://img.shields.io/npm/v/mcp-use.svg)](https://www.npmjs.com/package/mcp-use) |
31
- | [@mcp-use/cli](https://github.com/mcp-use/mcp-use-ts/tree/main/packages/cli) | Build tool for MCP apps | [![npm](https://img.shields.io/npm/v/@mcp-use/cli.svg)](https://www.npmjs.com/package/@mcp-use/cli) |
32
- | [create-mcp-use-app](https://github.com/mcp-use/mcp-use-ts/tree/main/packages/create-mcp-use-app) | Create MCP apps | [![npm](https://img.shields.io/npm/v/create-mcp-use-app.svg)](https://www.npmjs.com/package/create-mcp-use-app) |
28
+ | Package | Description | Version |
29
+ | ------------------------------------------------------------------------------------------------- | ----------------------- | --------------------------------------------------------------------------------------------------------------- |
30
+ | [mcp-use](https://github.com/mcp-use/mcp-use-ts/tree/main/packages/mcp-use) | Core MCP framework | [![npm](https://img.shields.io/npm/v/mcp-use.svg)](https://www.npmjs.com/package/mcp-use) |
31
+ | [@mcp-use/cli](https://github.com/mcp-use/mcp-use-ts/tree/main/packages/cli) | Build tool for MCP apps | [![npm](https://img.shields.io/npm/v/@mcp-use/cli.svg)](https://www.npmjs.com/package/@mcp-use/cli) |
32
+ | [create-mcp-use-app](https://github.com/mcp-use/mcp-use-ts/tree/main/packages/create-mcp-use-app) | Create MCP apps | [![npm](https://img.shields.io/npm/v/create-mcp-use-app.svg)](https://www.npmjs.com/package/create-mcp-use-app) |
33
33
 
34
34
  ---
35
35
 
36
36
  ## ✨ Key Features
37
37
 
38
- | Feature | Description |
39
- |---------|-------------|
40
- | **🚀 Auto-Mount** | Automatically available at `/inspector` for all MCP-Use servers |
41
- | **🔌 Multi-Connection** | Connect to and manage multiple MCP servers simultaneously |
42
- | **🎯 Interactive Testing** | Test tools with live execution and real-time results |
43
- | **📊 Real-time Status** | Monitor connection states, errors, and server health |
44
- | **🔐 OAuth Support** | Built-in OAuth flow handling with popup authentication |
45
- | **💾 Persistent Sessions** | Connections saved to localStorage and auto-reconnect |
46
- | **🎨 Beautiful UI** | Modern, responsive interface built with React and Tailwind |
47
- | **🔍 Tool Explorer** | Browse and execute all available tools with schema validation |
48
- | **📁 Resource Browser** | View and copy resource URIs with syntax highlighting |
49
- | **💬 Prompt Manager** | Test and manage prompts with argument templates |
50
- | **🌐 Universal Support** | Works with HTTP/SSE and WebSocket connections |
38
+ | Feature | Description |
39
+ | -------------------------- | --------------------------------------------------------------- |
40
+ | **🚀 Auto-Mount** | Automatically available at `/inspector` for all MCP-Use servers |
41
+ | **🔌 Multi-Connection** | Connect to and manage multiple MCP servers simultaneously |
42
+ | **🎯 Interactive Testing** | Test tools with live execution and real-time results |
43
+ | **📊 Real-time Status** | Monitor connection states, errors, and server health |
44
+ | **🔐 OAuth Support** | Built-in OAuth flow handling with popup authentication |
45
+ | **💾 Persistent Sessions** | Connections saved to localStorage and auto-reconnect |
46
+ | **🎨 Beautiful UI** | Modern, responsive interface built with React and Tailwind |
47
+ | **🔍 Tool Explorer** | Browse and execute all available tools with schema validation |
48
+ | **📁 Resource Browser** | View and copy resource URIs with syntax highlighting |
49
+ | **💬 Prompt Manager** | Test and manage prompts with argument templates |
50
+ | **🌐 Universal Support** | Works with HTTP/SSE and WebSocket connections |
51
51
 
52
52
  ---
53
53
 
@@ -61,7 +61,7 @@ When you create an MCP server with `mcp-use`, the inspector is automatically ava
61
61
  import { createMCPServer } from 'mcp-use/server'
62
62
 
63
63
  const server = createMCPServer('my-server', {
64
- version: '1.0.0'
64
+ version: '1.0.0',
65
65
  })
66
66
 
67
67
  // Add your tools, resources, prompts...
@@ -72,6 +72,7 @@ server.listen(3000)
72
72
  ```
73
73
 
74
74
  **That's it!** No additional configuration needed. The inspector:
75
+
75
76
  - Automatically mounts at `/inspector`
76
77
  - Auto-connects to your local MCP server
77
78
  - Provides instant debugging capabilities
@@ -83,13 +84,13 @@ Use the inspector with any MCP server (local or remote):
83
84
 
84
85
  ```bash
85
86
  # Inspect a remote server
86
- npx mcp-inspect --url https://mcp.linear.app/sse
87
+ npx @mcp-use/inspector --url https://mcp.linear.app/sse
87
88
 
88
89
  # Custom port
89
- npx mcp-inspect --url http://localhost:3000/mcp --port 8080
90
+ npx @mcp-use/inspector --url http://localhost:3000/mcp --port 8080
90
91
 
91
92
  # Open inspector without auto-connect
92
- npx mcp-inspect
93
+ npx @mcp-use/inspector
93
94
  ```
94
95
 
95
96
  ### Method 3: Custom Integration
@@ -116,6 +117,7 @@ app.listen(3000)
116
117
  ### Dashboard Overview
117
118
 
118
119
  The main dashboard shows:
120
+
119
121
  - **Connection Overview**: Total servers, active connections, available tools
120
122
  - **Server List**: All configured servers with their current status
121
123
  - **Quick Actions**: Add new server, refresh all, clear sessions
@@ -123,10 +125,12 @@ The main dashboard shows:
123
125
  ### Adding Servers
124
126
 
125
127
  Click "Add New MCP Server" and provide:
128
+
126
129
  - **Server Name** (optional): Friendly name for identification
127
130
  - **Server URL**: The MCP endpoint URL
128
131
 
129
132
  Example URLs:
133
+
130
134
  - Local: `http://localhost:3000/mcp`
131
135
  - Linear: `https://mcp.linear.app/sse`
132
136
  - WebSocket: `ws://localhost:8080`
@@ -135,15 +139,15 @@ Example URLs:
135
139
 
136
140
  The inspector displays real-time connection states:
137
141
 
138
- | State | Description | Action |
139
- |-------|-------------|---------|
140
- | 🔍 **discovering** | Finding the server | Wait |
141
- | 🔄 **connecting** | Establishing connection | Wait |
142
- | 🔐 **authenticating** | OAuth flow in progress | Complete auth |
143
- | 📥 **loading** | Loading tools & resources | Wait |
144
- | ✅ **ready** | Connected and operational | Use tools |
145
- | ❌ **failed** | Connection failed | Retry |
146
- | ⏳ **pending_auth** | Waiting for authentication | Click Authenticate |
142
+ | State | Description | Action |
143
+ | --------------------- | -------------------------- | ------------------ |
144
+ | 🔍 **discovering** | Finding the server | Wait |
145
+ | 🔄 **connecting** | Establishing connection | Wait |
146
+ | 🔐 **authenticating** | OAuth flow in progress | Complete auth |
147
+ | 📥 **loading** | Loading tools & resources | Wait |
148
+ | ✅ **ready** | Connected and operational | Use tools |
149
+ | ❌ **failed** | Connection failed | Retry |
150
+ | ⏳ **pending_auth** | Waiting for authentication | Click Authenticate |
147
151
 
148
152
  ### Testing Tools
149
153
 
@@ -183,6 +187,7 @@ For servers requiring OAuth (like Linear):
183
187
  4. Connection automatically completes
184
188
 
185
189
  If popup is blocked:
190
+
186
191
  - Click "open auth page" link
187
192
  - Complete authentication manually
188
193
  - Return to inspector
@@ -190,6 +195,7 @@ If popup is blocked:
190
195
  ### Resource Management
191
196
 
192
197
  Browse available resources:
198
+
193
199
  - View resource descriptions
194
200
  - Copy resource URIs
195
201
  - Check MIME types
@@ -198,6 +204,7 @@ Browse available resources:
198
204
  ### Prompt Testing
199
205
 
200
206
  Test prompts with the inspector:
207
+
201
208
  1. Navigate to **Prompts** tab
202
209
  2. Select a prompt
203
210
  3. Fill in required arguments
@@ -211,6 +218,7 @@ Test prompts with the inspector:
211
218
  ### Server Card
212
219
 
213
220
  Each server displays:
221
+
214
222
  - Connection status indicator
215
223
  - Server name and URL
216
224
  - Available tools count
@@ -220,6 +228,7 @@ Each server displays:
220
228
  ### Tool Explorer
221
229
 
222
230
  The tool explorer shows:
231
+
223
232
  - Tool name and description
224
233
  - Input schema with types
225
234
  - Output schema
@@ -229,6 +238,7 @@ The tool explorer shows:
229
238
  ### Chat Interface
230
239
 
231
240
  Interactive chat for testing conversational flows:
241
+
232
242
  - Send messages to test prompts
233
243
  - View tool calls in real-time
234
244
  - See formatted responses
@@ -251,6 +261,7 @@ Manage multiple servers efficiently:
251
261
  ### Session Management
252
262
 
253
263
  Sessions are automatically saved to localStorage:
264
+
254
265
  - Preserves server configurations
255
266
  - Maintains connection preferences
256
267
  - Restores on page reload
@@ -259,18 +270,19 @@ Sessions are automatically saved to localStorage:
259
270
  ### Custom Themes
260
271
 
261
272
  The inspector respects system theme preferences:
273
+
262
274
  - Light mode for better readability
263
275
  - Dark mode for reduced eye strain
264
276
  - Automatic switching based on OS settings
265
277
 
266
278
  ### Keyboard Shortcuts
267
279
 
268
- | Shortcut | Action |
269
- |----------|--------|
270
- | `Cmd/Ctrl + K` | Quick server search |
271
- | `Cmd/Ctrl + N` | Add new server |
280
+ | Shortcut | Action |
281
+ | -------------- | ----------------------- |
282
+ | `Cmd/Ctrl + K` | Quick server search |
283
+ | `Cmd/Ctrl + N` | Add new server |
272
284
  | `Cmd/Ctrl + R` | Refresh all connections |
273
- | `Esc` | Close modals |
285
+ | `Esc` | Close modals |
274
286
 
275
287
  ---
276
288
 
@@ -284,18 +296,18 @@ import { createMCPServer } from 'mcp-use/server'
284
296
 
285
297
  const server = createMCPServer('dev-server', {
286
298
  version: '1.0.0',
287
- description: 'Development MCP Server'
299
+ description: 'Development MCP Server',
288
300
  })
289
301
 
290
302
  server.tool('debug_tool', {
291
303
  description: 'Debug tool for testing',
292
304
  parameters: z.object({
293
- message: z.string()
305
+ message: z.string(),
294
306
  }),
295
307
  execute: async ({ message }) => {
296
308
  console.log('Debug:', message)
297
309
  return { received: message, timestamp: Date.now() }
298
- }
310
+ },
299
311
  })
300
312
 
301
313
  server.listen(3000)
@@ -311,8 +323,8 @@ const server = createMCPServer('production-server', {
311
323
  clientId: process.env.OAUTH_CLIENT_ID,
312
324
  clientSecret: process.env.OAUTH_CLIENT_SECRET,
313
325
  authorizationUrl: 'https://api.example.com/oauth/authorize',
314
- tokenUrl: 'https://api.example.com/oauth/token'
315
- }
326
+ tokenUrl: 'https://api.example.com/oauth/token',
327
+ },
316
328
  })
317
329
 
318
330
  // Inspector handles OAuth flow automatically
@@ -341,6 +353,7 @@ URL: https://api.example.com/mcp
341
353
  The inspector is built with modern web technologies:
342
354
 
343
355
  ### Frontend Stack
356
+
344
357
  - **React 19**: UI framework
345
358
  - **React Router**: Navigation
346
359
  - **Tailwind CSS**: Styling
@@ -368,6 +381,7 @@ src/client/
368
381
  ### Connection Management
369
382
 
370
383
  The `useMcp` hook handles:
384
+
371
385
  - WebSocket/SSE connections
372
386
  - Automatic reconnection
373
387
  - OAuth flow management
@@ -381,6 +395,7 @@ The `useMcp` hook handles:
381
395
  ### Common Issues and Solutions
382
396
 
383
397
  **Inspector not loading:**
398
+
384
399
  ```bash
385
400
  # Check server is running
386
401
  curl http://localhost:3000/inspector
@@ -390,23 +405,27 @@ curl http://localhost:3000/inspector
390
405
  ```
391
406
 
392
407
  **Connection fails immediately:**
408
+
393
409
  - Check CORS configuration
394
410
  - Verify server URL is correct
395
411
  - Ensure server supports SSE/WebSocket
396
412
  - Check network/firewall settings
397
413
 
398
414
  **OAuth popup blocked:**
415
+
399
416
  - Allow popups for the inspector domain
400
417
  - Use the manual auth link provided
401
418
  - Check browser console for errors
402
419
 
403
420
  **Tools not executing:**
421
+
404
422
  - Verify tool schemas are valid
405
423
  - Check server logs for errors
406
424
  - Ensure proper authentication
407
425
  - Validate input parameters
408
426
 
409
427
  **Session not persisting:**
428
+
410
429
  - Check localStorage is enabled
411
430
  - Clear browser cache
412
431
  - Try incognito/private mode
@@ -422,7 +441,7 @@ curl http://localhost:3000/inspector
422
441
  // Use pagination for many tools
423
442
  server.configurePagination({
424
443
  toolsPerPage: 50,
425
- enableSearch: true
444
+ enableSearch: true,
426
445
  })
427
446
  ```
428
447
 
@@ -433,7 +452,7 @@ server.configurePagination({
433
452
  const inspector = {
434
453
  maxConnections: 5,
435
454
  connectionTimeout: 30000,
436
- keepAlive: true
455
+ keepAlive: true,
437
456
  }
438
457
  ```
439
458
 
@@ -443,7 +462,7 @@ const inspector = {
443
462
  // Cache tool results
444
463
  server.enableCache({
445
464
  ttl: 300, // 5 minutes
446
- maxSize: 100 // MB
465
+ maxSize: 100, // MB
447
466
  })
448
467
  ```
449
468
 
@@ -457,7 +476,7 @@ server.enableCache({
457
476
  // Configure CORS for inspector access
458
477
  server.configureCORS({
459
478
  origin: ['http://localhost:3000'],
460
- credentials: true
479
+ credentials: true,
461
480
  })
462
481
  ```
463
482
 
@@ -474,7 +493,7 @@ server.use(authMiddleware)
474
493
  // Prevent abuse
475
494
  server.configureRateLimit({
476
495
  windowMs: 60000, // 1 minute
477
- max: 100 // requests
496
+ max: 100, // requests
478
497
  })
479
498
  ```
480
499
 
@@ -499,9 +518,9 @@ configureInspector(options: InspectorOptions): void
499
518
 
500
519
  ```typescript
501
520
  interface InspectorOptions {
502
- autoConnect?: boolean // Auto-connect to local server
521
+ autoConnect?: boolean // Auto-connect to local server
503
522
  theme?: 'light' | 'dark' | 'auto'
504
- persistence?: boolean // Save sessions
523
+ persistence?: boolean // Save sessions
505
524
  maxConnections?: number
506
525
  connectionTimeout?: number
507
526
  }
@@ -512,6 +531,7 @@ interface InspectorOptions {
512
531
  ## 🤝 Contributing
513
532
 
514
533
  We welcome contributions! Areas for improvement:
534
+
515
535
  - Additional UI themes
516
536
  - More keyboard shortcuts
517
537
  - Enhanced tool testing features
@@ -534,4 +554,4 @@ See our [contributing guide](https://github.com/mcp-use/mcp-use-ts/blob/main/CON
534
554
 
535
555
  ## 📜 License
536
556
 
537
- MIT © [MCP-Use](https://github.com/mcp-use)
557
+ MIT © [MCP-Use](https://github.com/mcp-use)
@@ -0,0 +1,262 @@
1
+ #!/usr/bin/env node
2
+ import { serve } from '@hono/node-server';
3
+ import { Hono } from 'hono';
4
+ import { cors } from 'hono/cors';
5
+ import { logger } from 'hono/logger';
6
+ import { existsSync } from 'node:fs';
7
+ import { join, dirname } from 'node:path';
8
+ import { fileURLToPath } from 'node:url';
9
+ import { exec } from 'node:child_process';
10
+ import { promisify } from 'node:util';
11
+ import { MCPInspector } from '../server/mcp-inspector.js';
12
+ const __filename = fileURLToPath(import.meta.url);
13
+ const __dirname = dirname(__filename);
14
+ const execAsync = promisify(exec);
15
+ // Find available port starting from 8080
16
+ async function findAvailablePort(startPort = 8080) {
17
+ const net = await import('node:net');
18
+ for (let port = startPort; port < startPort + 100; port++) {
19
+ try {
20
+ await new Promise((resolve, reject) => {
21
+ const server = net.createServer();
22
+ server.listen(port, () => {
23
+ server.close(() => resolve());
24
+ });
25
+ server.on('error', () => reject(new Error(`Port ${port} is in use`)));
26
+ });
27
+ return port;
28
+ }
29
+ catch {
30
+ continue;
31
+ }
32
+ }
33
+ throw new Error(`No available port found starting from ${startPort}`);
34
+ }
35
+ // Parse command line arguments
36
+ const args = process.argv.slice(2);
37
+ let mcpUrl;
38
+ let startPort = 8080;
39
+ for (let i = 0; i < args.length; i++) {
40
+ if (args[i] === '--url' && i + 1 < args.length) {
41
+ mcpUrl = args[i + 1];
42
+ i++;
43
+ }
44
+ else if (args[i] === '--port' && i + 1 < args.length) {
45
+ startPort = parseInt(args[i + 1], 10);
46
+ i++;
47
+ }
48
+ else if (args[i] === '--help' || args[i] === '-h') {
49
+ console.log(`
50
+ MCP Inspector - Inspect and debug MCP servers
51
+
52
+ Usage:
53
+ npx @mcp-use/inspect [options]
54
+
55
+ Options:
56
+ --url <url> MCP server URL to auto-connect to (e.g., http://localhost:3000/mcp)
57
+ --port <port> Starting port to try (default: 8080, will find next available)
58
+ --help, -h Show this help message
59
+
60
+ Examples:
61
+ # Run inspector with auto-connect
62
+ npx @mcp-use/inspect --url http://localhost:3000/mcp
63
+
64
+ # Run starting from custom port
65
+ npx @mcp-use/inspect --url http://localhost:3000/mcp --port 9000
66
+
67
+ # Run without auto-connect
68
+ npx @mcp-use/inspect
69
+ `);
70
+ process.exit(0);
71
+ }
72
+ }
73
+ const app = new Hono();
74
+ // Middleware
75
+ app.use('*', cors());
76
+ app.use('*', logger());
77
+ // Health check
78
+ app.get('/health', (c) => {
79
+ return c.json({ status: 'ok', timestamp: new Date().toISOString() });
80
+ });
81
+ // MCP Inspector routes
82
+ const mcpInspector = new MCPInspector();
83
+ // List available MCP servers
84
+ app.get('/api/servers', async (c) => {
85
+ try {
86
+ const servers = await mcpInspector.listServers();
87
+ return c.json({ servers });
88
+ }
89
+ catch {
90
+ return c.json({ error: 'Failed to list servers' }, 500);
91
+ }
92
+ });
93
+ // Connect to an MCP server
94
+ app.post('/api/servers/connect', async (c) => {
95
+ try {
96
+ const { url, command } = await c.req.json();
97
+ const server = await mcpInspector.connectToServer(url, command);
98
+ return c.json({ server });
99
+ }
100
+ catch {
101
+ return c.json({ error: 'Failed to connect to server' }, 500);
102
+ }
103
+ });
104
+ // Get server details
105
+ app.get('/api/servers/:id', async (c) => {
106
+ try {
107
+ const id = c.req.param('id');
108
+ const server = await mcpInspector.getServer(id);
109
+ if (!server) {
110
+ return c.json({ error: 'Server not found' }, 404);
111
+ }
112
+ return c.json({ server });
113
+ }
114
+ catch {
115
+ return c.json({ error: 'Failed to get server details' }, 500);
116
+ }
117
+ });
118
+ // Execute a tool on a server
119
+ app.post('/api/servers/:id/tools/:toolName/execute', async (c) => {
120
+ try {
121
+ const id = c.req.param('id');
122
+ const toolName = c.req.param('toolName');
123
+ const input = await c.req.json();
124
+ const result = await mcpInspector.executeTool(id, toolName, input);
125
+ return c.json({ result });
126
+ }
127
+ catch {
128
+ return c.json({ error: 'Failed to execute tool' }, 500);
129
+ }
130
+ });
131
+ // Get server tools
132
+ app.get('/api/servers/:id/tools', async (c) => {
133
+ try {
134
+ const id = c.req.param('id');
135
+ const tools = await mcpInspector.getServerTools(id);
136
+ return c.json({ tools });
137
+ }
138
+ catch {
139
+ return c.json({ error: 'Failed to get server tools' }, 500);
140
+ }
141
+ });
142
+ // Get server resources
143
+ app.get('/api/servers/:id/resources', async (c) => {
144
+ try {
145
+ const id = c.req.param('id');
146
+ const resources = await mcpInspector.getServerResources(id);
147
+ return c.json({ resources });
148
+ }
149
+ catch {
150
+ return c.json({ error: 'Failed to get server resources' }, 500);
151
+ }
152
+ });
153
+ // Disconnect from a server
154
+ app.delete('/api/servers/:id', async (c) => {
155
+ try {
156
+ const id = c.req.param('id');
157
+ await mcpInspector.disconnectServer(id);
158
+ return c.json({ success: true });
159
+ }
160
+ catch {
161
+ return c.json({ error: 'Failed to disconnect server' }, 500);
162
+ }
163
+ });
164
+ // Serve static assets from the built client
165
+ const clientDistPath = join(__dirname, '../../dist/client');
166
+ if (existsSync(clientDistPath)) {
167
+ // Serve static assets from /inspector/assets/* (matching Vite's base path)
168
+ app.get('/inspector/assets/*', async (c) => {
169
+ const path = c.req.path.replace('/inspector/assets/', 'assets/');
170
+ const fullPath = join(clientDistPath, path);
171
+ if (existsSync(fullPath)) {
172
+ const content = await import('node:fs').then(fs => fs.readFileSync(fullPath));
173
+ // Set appropriate content type based on file extension
174
+ if (path.endsWith('.js')) {
175
+ c.header('Content-Type', 'application/javascript');
176
+ }
177
+ else if (path.endsWith('.css')) {
178
+ c.header('Content-Type', 'text/css');
179
+ }
180
+ else if (path.endsWith('.svg')) {
181
+ c.header('Content-Type', 'image/svg+xml');
182
+ }
183
+ return c.body(content);
184
+ }
185
+ return c.notFound();
186
+ });
187
+ // Redirect root path to /inspector
188
+ app.get('/', (c) => {
189
+ return c.redirect('/inspector');
190
+ });
191
+ // Serve the main HTML file for /inspector and all other routes (SPA routing)
192
+ app.get('*', (c) => {
193
+ const indexPath = join(clientDistPath, 'index.html');
194
+ if (existsSync(indexPath)) {
195
+ const content = import('node:fs').then(fs => fs.readFileSync(indexPath, 'utf-8'));
196
+ return c.html(content);
197
+ }
198
+ return c.html(`
199
+ <!DOCTYPE html>
200
+ <html>
201
+ <head>
202
+ <title>MCP Inspector</title>
203
+ </head>
204
+ <body>
205
+ <h1>MCP Inspector</h1>
206
+ <p>Client files not found. Please run 'yarn build' to build the UI.</p>
207
+ <p>API is available at <a href="/api/servers">/api/servers</a></p>
208
+ </body>
209
+ </html>
210
+ `);
211
+ });
212
+ }
213
+ else {
214
+ console.warn(`⚠️ MCP Inspector client files not found at ${clientDistPath}`);
215
+ console.warn(` Run 'yarn build' in the inspector package to build the UI`);
216
+ // Fallback for when client is not built
217
+ app.get('*', (c) => {
218
+ return c.html(`
219
+ <!DOCTYPE html>
220
+ <html>
221
+ <head>
222
+ <title>MCP Inspector</title>
223
+ </head>
224
+ <body>
225
+ <h1>MCP Inspector</h1>
226
+ <p>Client files not found. Please run 'yarn build' to build the UI.</p>
227
+ <p>API is available at <a href="/api/servers">/api/servers</a></p>
228
+ </body>
229
+ </html>
230
+ `);
231
+ });
232
+ }
233
+ // Start the server with automatic port selection
234
+ async function startServer() {
235
+ try {
236
+ const port = await findAvailablePort(startPort);
237
+ serve({
238
+ fetch: app.fetch,
239
+ port,
240
+ });
241
+ console.log(`🚀 MCP Inspector running on http://localhost:${port}`);
242
+ if (mcpUrl) {
243
+ console.log(`📡 Auto-connecting to: ${mcpUrl}`);
244
+ }
245
+ // Auto-open browser
246
+ try {
247
+ const command = process.platform === 'win32' ? 'start' : process.platform === 'darwin' ? 'open' : 'xdg-open';
248
+ await execAsync(`${command} http://localhost:${port}`);
249
+ console.log(`🌐 Browser opened automatically`);
250
+ }
251
+ catch (error) {
252
+ console.log(`🌐 Please open http://localhost:${port} in your browser`);
253
+ }
254
+ return { port, fetch: app.fetch };
255
+ }
256
+ catch (error) {
257
+ console.error('Failed to start server:', error);
258
+ process.exit(1);
259
+ }
260
+ }
261
+ // Start the server
262
+ startServer();
@@ -0,0 +1,382 @@
1
+ #!/usr/bin/env node
2
+ var __defProp = Object.defineProperty;
3
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
5
+
6
+ // src/cli/inspect.ts
7
+ import { serve } from "@hono/node-server";
8
+ import { Hono } from "hono";
9
+ import { cors } from "hono/cors";
10
+ import { logger } from "hono/logger";
11
+ import { existsSync, readFileSync } from "fs";
12
+ import { dirname, join } from "path";
13
+ import { fileURLToPath } from "url";
14
+ import open from "open";
15
+
16
+ // src/server/mcp-inspector.ts
17
+ import { MCPClient } from "mcp-use";
18
+ var MCPInspector = class {
19
+ constructor() {
20
+ __publicField(this, "servers", /* @__PURE__ */ new Map());
21
+ __publicField(this, "client");
22
+ this.client = new MCPClient();
23
+ }
24
+ async listServers() {
25
+ return Array.from(this.servers.values());
26
+ }
27
+ async connectToServer(url, command) {
28
+ const id = Date.now().toString();
29
+ const name = url || command || "Unknown Server";
30
+ try {
31
+ const serverName = `server_${id}`;
32
+ const serverConfig = url ? { url } : { command };
33
+ this.client.addServer(serverName, serverConfig);
34
+ const session = await this.client.createSession(serverName, true);
35
+ const tools = [
36
+ {
37
+ name: "get_weather",
38
+ description: "Get current weather for a location",
39
+ inputSchema: {
40
+ type: "object",
41
+ properties: {
42
+ location: { type: "string", description: "City name" }
43
+ },
44
+ required: ["location"]
45
+ }
46
+ }
47
+ ];
48
+ const resources = [
49
+ {
50
+ uri: "file:///home/user/documents",
51
+ name: "Documents",
52
+ description: "User documents directory",
53
+ mimeType: "application/x-directory"
54
+ }
55
+ ];
56
+ const server = {
57
+ id,
58
+ name,
59
+ url,
60
+ command,
61
+ status: "connected",
62
+ session,
63
+ tools,
64
+ resources,
65
+ lastActivity: /* @__PURE__ */ new Date()
66
+ };
67
+ this.servers.set(id, server);
68
+ return server;
69
+ } catch (error) {
70
+ const server = {
71
+ id,
72
+ name,
73
+ url,
74
+ command,
75
+ status: "error",
76
+ tools: [],
77
+ resources: [],
78
+ lastActivity: /* @__PURE__ */ new Date()
79
+ };
80
+ this.servers.set(id, server);
81
+ throw error;
82
+ }
83
+ }
84
+ async getServer(id) {
85
+ return this.servers.get(id) || null;
86
+ }
87
+ async executeTool(serverId, toolName, input) {
88
+ const server = this.servers.get(serverId);
89
+ if (!server || !server.session) {
90
+ throw new Error("Server not found or not connected");
91
+ }
92
+ try {
93
+ const result = {
94
+ tool: toolName,
95
+ input,
96
+ result: `Mock result for ${toolName} with input: ${JSON.stringify(input)}`,
97
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
98
+ };
99
+ server.lastActivity = /* @__PURE__ */ new Date();
100
+ return result;
101
+ } catch (error) {
102
+ server.status = "error";
103
+ throw error;
104
+ }
105
+ }
106
+ async getServerTools(serverId) {
107
+ const server = this.servers.get(serverId);
108
+ if (!server) {
109
+ throw new Error("Server not found");
110
+ }
111
+ return server.tools;
112
+ }
113
+ async getServerResources(serverId) {
114
+ const server = this.servers.get(serverId);
115
+ if (!server) {
116
+ throw new Error("Server not found");
117
+ }
118
+ return server.resources;
119
+ }
120
+ async disconnectServer(serverId) {
121
+ const server = this.servers.get(serverId);
122
+ if (server && server.session) {
123
+ try {
124
+ await server.session.disconnect();
125
+ } catch (error) {
126
+ console.error("Error disconnecting from server:", error);
127
+ }
128
+ }
129
+ this.servers.delete(serverId);
130
+ }
131
+ };
132
+
133
+ // src/cli/inspect.ts
134
+ var __filename = fileURLToPath(import.meta.url);
135
+ var __dirname = dirname(__filename);
136
+ function isValidUrl(urlString) {
137
+ try {
138
+ const url = new URL(urlString);
139
+ return url.protocol === "http:" || url.protocol === "https:" || url.protocol === "ws:" || url.protocol === "wss:";
140
+ } catch {
141
+ return false;
142
+ }
143
+ }
144
+ async function findAvailablePort(startPort2 = 8080, maxAttempts = 100) {
145
+ const net = await import("net");
146
+ for (let port = startPort2; port < startPort2 + maxAttempts; port++) {
147
+ try {
148
+ await new Promise((resolve, reject) => {
149
+ const server = net.createServer();
150
+ server.listen(port, () => {
151
+ server.close(() => resolve());
152
+ });
153
+ server.on("error", (err) => reject(err));
154
+ });
155
+ return port;
156
+ } catch (error) {
157
+ continue;
158
+ }
159
+ }
160
+ throw new Error(`No available port found after trying ${maxAttempts} ports starting from ${startPort2}`);
161
+ }
162
+ var args = process.argv.slice(2);
163
+ var mcpUrl;
164
+ var startPort = 8080;
165
+ for (let i = 0; i < args.length; i++) {
166
+ if (args[i] === "--url" && i + 1 < args.length) {
167
+ const url = args[i + 1];
168
+ if (!isValidUrl(url)) {
169
+ console.error(`Error: Invalid URL format: ${url}`);
170
+ console.error("URL must start with http://, https://, ws://, or wss://");
171
+ process.exit(1);
172
+ }
173
+ mcpUrl = url;
174
+ i++;
175
+ } else if (args[i] === "--port" && i + 1 < args.length) {
176
+ const parsedPort = Number.parseInt(args[i + 1], 10);
177
+ if (Number.isNaN(parsedPort) || parsedPort < 1 || parsedPort > 65535) {
178
+ console.error(`Error: Port must be a number between 1 and 65535, got: ${args[i + 1]}`);
179
+ process.exit(1);
180
+ }
181
+ startPort = parsedPort;
182
+ i++;
183
+ } else if (args[i] === "--help" || args[i] === "-h") {
184
+ console.log(`
185
+ MCP Inspector - Inspect and debug MCP servers
186
+
187
+ Usage:
188
+ npx @mcp-use/inspector [options]
189
+
190
+ Options:
191
+ --url <url> MCP server URL to auto-connect to (e.g., http://localhost:3000/mcp)
192
+ --port <port> Starting port to try (default: 8080, will find next available)
193
+ --help, -h Show this help message
194
+
195
+ Examples:
196
+ # Run inspector with auto-connect
197
+ npx @mcp-use/inspector --url http://localhost:3000/mcp
198
+
199
+ # Run starting from custom port
200
+ npx @mcp-use/inspector --url http://localhost:3000/mcp --port 9000
201
+
202
+ # Run without auto-connect
203
+ npx @mcp-use/inspector
204
+ `);
205
+ process.exit(0);
206
+ }
207
+ }
208
+ var app = new Hono();
209
+ app.use("*", cors());
210
+ app.use("*", logger());
211
+ app.get("/health", (c) => {
212
+ return c.json({ status: "ok", timestamp: (/* @__PURE__ */ new Date()).toISOString() });
213
+ });
214
+ var mcpInspector = new MCPInspector();
215
+ app.get("/api/servers", async (c) => {
216
+ try {
217
+ const servers = await mcpInspector.listServers();
218
+ return c.json({ servers });
219
+ } catch (error) {
220
+ const message = error instanceof Error ? error.message : "Unknown error";
221
+ console.error("Failed to list servers:", message, error);
222
+ return c.json({ error: "Failed to list servers", details: message }, 500);
223
+ }
224
+ });
225
+ app.post("/api/servers/connect", async (c) => {
226
+ try {
227
+ const { url, command } = await c.req.json();
228
+ if (url && !isValidUrl(url)) {
229
+ return c.json({ error: "Invalid URL format. Must start with http://, https://, ws://, or wss://" }, 400);
230
+ }
231
+ const server = await mcpInspector.connectToServer(url, command);
232
+ return c.json({ server });
233
+ } catch (error) {
234
+ const message = error instanceof Error ? error.message : "Unknown error";
235
+ console.error("Failed to connect to server:", message, error);
236
+ return c.json({ error: "Failed to connect to server", details: message }, 500);
237
+ }
238
+ });
239
+ app.get("/api/servers/:id", async (c) => {
240
+ try {
241
+ const id = c.req.param("id");
242
+ const server = await mcpInspector.getServer(id);
243
+ if (!server) {
244
+ return c.json({ error: "Server not found" }, 404);
245
+ }
246
+ return c.json({ server });
247
+ } catch (error) {
248
+ const message = error instanceof Error ? error.message : "Unknown error";
249
+ console.error("Failed to get server details:", message, error);
250
+ return c.json({ error: "Failed to get server details", details: message }, 500);
251
+ }
252
+ });
253
+ app.post("/api/servers/:id/tools/:toolName/execute", async (c) => {
254
+ try {
255
+ const id = c.req.param("id");
256
+ const toolName = c.req.param("toolName");
257
+ const input = await c.req.json();
258
+ const result = await mcpInspector.executeTool(id, toolName, input);
259
+ return c.json({ result });
260
+ } catch (error) {
261
+ const message = error instanceof Error ? error.message : "Unknown error";
262
+ console.error("Failed to execute tool:", message, error);
263
+ return c.json({ error: "Failed to execute tool", details: message }, 500);
264
+ }
265
+ });
266
+ app.get("/api/servers/:id/tools", async (c) => {
267
+ try {
268
+ const id = c.req.param("id");
269
+ const tools = await mcpInspector.getServerTools(id);
270
+ return c.json({ tools });
271
+ } catch (error) {
272
+ const message = error instanceof Error ? error.message : "Unknown error";
273
+ console.error("Failed to get server tools:", message, error);
274
+ return c.json({ error: "Failed to get server tools", details: message }, 500);
275
+ }
276
+ });
277
+ app.get("/api/servers/:id/resources", async (c) => {
278
+ try {
279
+ const id = c.req.param("id");
280
+ const resources = await mcpInspector.getServerResources(id);
281
+ return c.json({ resources });
282
+ } catch (error) {
283
+ const message = error instanceof Error ? error.message : "Unknown error";
284
+ console.error("Failed to get server resources:", message, error);
285
+ return c.json({ error: "Failed to get server resources", details: message }, 500);
286
+ }
287
+ });
288
+ app.delete("/api/servers/:id", async (c) => {
289
+ try {
290
+ const id = c.req.param("id");
291
+ await mcpInspector.disconnectServer(id);
292
+ return c.json({ success: true });
293
+ } catch (error) {
294
+ const message = error instanceof Error ? error.message : "Unknown error";
295
+ console.error("Failed to disconnect server:", message, error);
296
+ return c.json({ error: "Failed to disconnect server", details: message }, 500);
297
+ }
298
+ });
299
+ var clientDistPath = join(__dirname, "../../dist/client");
300
+ if (existsSync(clientDistPath)) {
301
+ app.get("/inspector/assets/*", (c) => {
302
+ const path = c.req.path.replace("/inspector/assets/", "assets/");
303
+ const fullPath = join(clientDistPath, path);
304
+ if (existsSync(fullPath)) {
305
+ const content = readFileSync(fullPath);
306
+ if (path.endsWith(".js")) {
307
+ c.header("Content-Type", "application/javascript");
308
+ } else if (path.endsWith(".css")) {
309
+ c.header("Content-Type", "text/css");
310
+ } else if (path.endsWith(".svg")) {
311
+ c.header("Content-Type", "image/svg+xml");
312
+ }
313
+ return c.body(content);
314
+ }
315
+ return c.notFound();
316
+ });
317
+ app.get("/", (c) => {
318
+ return c.redirect("/inspector");
319
+ });
320
+ app.get("*", (c) => {
321
+ const indexPath = join(clientDistPath, "index.html");
322
+ if (existsSync(indexPath)) {
323
+ const content = readFileSync(indexPath, "utf-8");
324
+ return c.html(content);
325
+ }
326
+ return c.html(`
327
+ <!DOCTYPE html>
328
+ <html>
329
+ <head>
330
+ <title>MCP Inspector</title>
331
+ </head>
332
+ <body>
333
+ <h1>MCP Inspector</h1>
334
+ <p>Client files not found. Please run 'yarn build' to build the UI.</p>
335
+ <p>API is available at <a href="/api/servers">/api/servers</a></p>
336
+ </body>
337
+ </html>
338
+ `);
339
+ });
340
+ } else {
341
+ console.warn(`\u26A0\uFE0F MCP Inspector client files not found at ${clientDistPath}`);
342
+ console.warn(` Run 'yarn build' in the inspector package to build the UI`);
343
+ app.get("*", (c) => {
344
+ return c.html(`
345
+ <!DOCTYPE html>
346
+ <html>
347
+ <head>
348
+ <title>MCP Inspector</title>
349
+ </head>
350
+ <body>
351
+ <h1>MCP Inspector</h1>
352
+ <p>Client files not found. Please run 'yarn build' to build the UI.</p>
353
+ <p>API is available at <a href="/api/servers">/api/servers</a></p>
354
+ </body>
355
+ </html>
356
+ `);
357
+ });
358
+ }
359
+ async function startServer() {
360
+ try {
361
+ const port = await findAvailablePort(startPort);
362
+ serve({
363
+ fetch: app.fetch,
364
+ port
365
+ });
366
+ console.log(`\u{1F680} MCP Inspector running on http://localhost:${port}`);
367
+ if (mcpUrl) {
368
+ console.log(`\u{1F4E1} Auto-connecting to: ${mcpUrl}`);
369
+ }
370
+ try {
371
+ await open(`http://localhost:${port}`);
372
+ console.log(`\u{1F310} Browser opened automatically`);
373
+ } catch {
374
+ console.log(`\u{1F310} Please open http://localhost:${port} in your browser`);
375
+ }
376
+ return { port, fetch: app.fetch };
377
+ } catch (error) {
378
+ console.error("Failed to start server:", error);
379
+ process.exit(1);
380
+ }
381
+ }
382
+ startServer();
@@ -0,0 +1,121 @@
1
+ import { MCPClient } from 'mcp-use';
2
+ export class MCPInspector {
3
+ constructor() {
4
+ this.servers = new Map();
5
+ this.client = new MCPClient();
6
+ }
7
+ async listServers() {
8
+ return Array.from(this.servers.values());
9
+ }
10
+ async connectToServer(url, command) {
11
+ const id = Date.now().toString();
12
+ const name = url || command || 'Unknown Server';
13
+ try {
14
+ // Configure server in MCP client
15
+ const serverName = `server_${id}`;
16
+ const serverConfig = url ? { url } : { command };
17
+ this.client.addServer(serverName, serverConfig);
18
+ // Create session
19
+ const session = await this.client.createSession(serverName, true);
20
+ // Mock tools and resources for now
21
+ const tools = [
22
+ {
23
+ name: 'get_weather',
24
+ description: 'Get current weather for a location',
25
+ inputSchema: {
26
+ type: 'object',
27
+ properties: {
28
+ location: { type: 'string', description: 'City name' },
29
+ },
30
+ required: ['location'],
31
+ },
32
+ },
33
+ ];
34
+ const resources = [
35
+ {
36
+ uri: 'file:///home/user/documents',
37
+ name: 'Documents',
38
+ description: 'User documents directory',
39
+ mimeType: 'application/x-directory',
40
+ },
41
+ ];
42
+ const server = {
43
+ id,
44
+ name,
45
+ url,
46
+ command,
47
+ status: 'connected',
48
+ session,
49
+ tools,
50
+ resources,
51
+ lastActivity: new Date(),
52
+ };
53
+ this.servers.set(id, server);
54
+ return server;
55
+ }
56
+ catch (error) {
57
+ const server = {
58
+ id,
59
+ name,
60
+ url,
61
+ command,
62
+ status: 'error',
63
+ tools: [],
64
+ resources: [],
65
+ lastActivity: new Date(),
66
+ };
67
+ this.servers.set(id, server);
68
+ throw error;
69
+ }
70
+ }
71
+ async getServer(id) {
72
+ return this.servers.get(id) || null;
73
+ }
74
+ async executeTool(serverId, toolName, input) {
75
+ const server = this.servers.get(serverId);
76
+ if (!server || !server.session) {
77
+ throw new Error('Server not found or not connected');
78
+ }
79
+ try {
80
+ // Mock tool execution for now
81
+ const result = {
82
+ tool: toolName,
83
+ input,
84
+ result: `Mock result for ${toolName} with input: ${JSON.stringify(input)}`,
85
+ timestamp: new Date().toISOString(),
86
+ };
87
+ server.lastActivity = new Date();
88
+ return result;
89
+ }
90
+ catch (error) {
91
+ server.status = 'error';
92
+ throw error;
93
+ }
94
+ }
95
+ async getServerTools(serverId) {
96
+ const server = this.servers.get(serverId);
97
+ if (!server) {
98
+ throw new Error('Server not found');
99
+ }
100
+ return server.tools;
101
+ }
102
+ async getServerResources(serverId) {
103
+ const server = this.servers.get(serverId);
104
+ if (!server) {
105
+ throw new Error('Server not found');
106
+ }
107
+ return server.resources;
108
+ }
109
+ async disconnectServer(serverId) {
110
+ const server = this.servers.get(serverId);
111
+ if (server && server.session) {
112
+ try {
113
+ await server.session.disconnect();
114
+ }
115
+ catch (error) {
116
+ console.error('Error disconnecting from server:', error);
117
+ }
118
+ }
119
+ this.servers.delete(serverId);
120
+ }
121
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mcp-use/inspector",
3
3
  "type": "module",
4
- "version": "0.3.10",
4
+ "version": "0.3.11",
5
5
  "description": "MCP Inspector - A tool for inspecting and debugging MCP servers",
6
6
  "author": "",
7
7
  "license": "MIT",
@@ -53,6 +53,7 @@
53
53
  "lucide-react": "^0.545.0",
54
54
  "motion": "^12.23.22",
55
55
  "next-themes": "^0.4.6",
56
+ "open": "^10.0.0",
56
57
  "react": "^19.2.0",
57
58
  "react-dom": "^19.2.0",
58
59
  "react-resizable-panels": "^3.0.6",
@@ -61,7 +62,7 @@
61
62
  "sonner": "^2.0.7",
62
63
  "tailwind-merge": "^3.3.1",
63
64
  "vite-express": "^0.21.1",
64
- "mcp-use": "1.0.6"
65
+ "mcp-use": "1.0.7"
65
66
  },
66
67
  "publishConfig": {
67
68
  "access": "public"
@@ -98,7 +99,7 @@
98
99
  "build": "npm run build:client && npm run build:server && npm run build:cli",
99
100
  "build:client": "vite build",
100
101
  "build:server": "tsup src/server/*.ts --format esm --out-dir dist/server && tsc -p tsconfig.server.json --emitDeclarationOnly --declaration",
101
- "build:cli": "tsup src/cli/inspect.ts --format cjs --out-dir dist/cli",
102
+ "build:cli": "tsup src/cli/inspect.ts --format esm --out-dir dist/cli",
102
103
  "start": "node dist/server/server.js",
103
104
  "preview": "vite preview",
104
105
  "type-check": "tsc --noEmit",