Skip to content
This repository was archived by the owner on May 21, 2026. It is now read-only.

Commit 704cbc1

Browse files
committed
feat(inspector): integrate MCP Inspector with automatic mounting and enhanced server capabilities
- Add automatic mounting of the MCP Inspector at `/inspector` for all MCP servers created with `createMCPServer` - Update README with usage instructions for embedded and standalone inspector modes - Enhance server setup to dynamically import and mount the inspector - Include new dependencies and update package configurations for improved functionality - Refactor inspector server code for better structure and maintainability
1 parent 9b67f70 commit 704cbc1

22 files changed

Lines changed: 860 additions & 152 deletions

File tree

INSPECTOR_INTEGRATION.md

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
# MCP Inspector Integration
2+
3+
## Overview
4+
5+
The MCP Inspector is now automatically mounted at `/inspector` for all MCP servers created with `createMCPServer`, similar to how FastAPI provides automatic Swagger documentation at `/docs`.
6+
7+
## Key Changes
8+
9+
### 1. Inspector Package (`@mcp-use/inspector`)
10+
11+
- **New Middleware Function**: Created `mountInspector()` function that can mount the inspector UI on any Express app
12+
- **Package Configuration**:
13+
- Added `main` and `exports` fields to make it importable
14+
- Added Express as a peer dependency
15+
- Built server components are available in `dist/server/`
16+
17+
### 2. MCP Server (`mcp-use`)
18+
19+
- **Automatic Mounting**: Modified `createMCPServer()` to automatically mount the inspector at `/inspector`
20+
- **Optional Dependency**: Added `@mcp-use/inspector` as an optional peer dependency
21+
- **Graceful Degradation**: Server works fine if inspector package is not installed
22+
23+
### 3. Templates (`create-mcp-use-app`)
24+
25+
- **Automatic Setup**: All new projects created with `create-mcp-use-app` include `@mcp-use/inspector` as a dependency
26+
- **No Manual Configuration**: Developers don't need to manually call `mountInspector()` anymore
27+
- **Console Message**: Server startup logs include the inspector URL
28+
29+
## Usage
30+
31+
### For New Projects
32+
33+
When developers create a new MCP server:
34+
35+
```typescript
36+
import { createMCPServer } from 'mcp-use'
37+
38+
const server = createMCPServer('my-server', {
39+
version: '1.0.0',
40+
description: 'My awesome MCP server'
41+
})
42+
43+
// Define tools, resources, prompts...
44+
45+
server.listen(3000)
46+
// Inspector automatically available at http://localhost:3000/inspector
47+
```
48+
49+
### For Existing Projects
50+
51+
1. Install the inspector package:
52+
```bash
53+
pnpm add @mcp-use/inspector
54+
```
55+
56+
2. Build the inspector:
57+
```bash
58+
cd packages/inspector && pnpm build
59+
```
60+
61+
3. The inspector will automatically be available at `/inspector` when you start your server
62+
63+
### Manual Mounting (Advanced)
64+
65+
If you need custom mounting:
66+
67+
```typescript
68+
import { mountInspector } from '@mcp-use/inspector'
69+
70+
// Mount at custom path
71+
mountInspector(server, '/my-custom-path')
72+
```
73+
74+
## Implementation Details
75+
76+
### How It Works
77+
78+
1. When `createMCPServer()` is called, it attempts to dynamically import `@mcp-use/inspector`
79+
2. If the package is installed, `mountInspector()` is called automatically with the Express app instance
80+
3. The inspector middleware:
81+
- Serves the built React UI from `dist/client/`
82+
- Handles static assets (JS, CSS)
83+
- Serves the HTML for all inspector routes (client-side routing)
84+
85+
### Workspace Setup
86+
87+
For local development in the monorepo:
88+
89+
```json
90+
{
91+
"dependencies": {
92+
"@mcp-use/inspector": "workspace:*"
93+
}
94+
}
95+
```
96+
97+
For published packages:
98+
99+
```json
100+
{
101+
"dependencies": {
102+
"@mcp-use/inspector": "^0.1.0"
103+
}
104+
}
105+
```
106+
107+
## Benefits
108+
109+
1. **Zero Configuration**: Works out of the box, just like FastAPI's `/docs`
110+
2. **Developer Experience**: Instant visual debugging and testing of MCP servers
111+
3. **Optional**: Doesn't break existing servers if inspector is not installed
112+
4. **Consistent**: All MCP servers have the same inspector experience
113+
114+
## Files Modified
115+
116+
- `packages/inspector/src/server/middleware.ts` - New middleware function
117+
- `packages/inspector/src/server/index.ts` - Export mountInspector
118+
- `packages/inspector/package.json` - Added exports and peer dependencies
119+
- `packages/inspector/tsconfig.server.json` - Fixed TypeScript config
120+
- `packages/mcp-use/src/server/mcp-server.ts` - Auto-mount inspector
121+
- `packages/mcp-use/package.json` - Added inspector as optional peer dependency
122+
- `packages/create-mcp-use-app/src/templates/ui/package.json` - Added inspector dependency
123+
- `packages/create-mcp-use-app/src/templates/ui/src/server.ts` - Updated comments
124+
- `test_app/package.json` - Added inspector dependency
125+
- `test_app/src/server.ts` - Updated comments
126+
127+
## Testing
128+
129+
To test the integration:
130+
131+
1. Build all packages:
132+
```bash
133+
cd /Users/e.t./Projects/mcp-use/mcp-use-ts
134+
pnpm install
135+
cd packages/inspector && pnpm build
136+
cd ../mcp-use && pnpm build
137+
```
138+
139+
2. Run the test app:
140+
```bash
141+
cd test_app
142+
pnpm dev
143+
```
144+
145+
3. Open `http://localhost:3000/inspector` in your browser
146+

packages/cli/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,9 @@
4141
"@mcp-use/inspector": "workspace:*",
4242
"commander": "^11.0.0",
4343
"esbuild": "^0.19.0",
44-
"globby": "^14.0.0"
44+
"globby": "^14.0.0",
45+
"open": "^10.0.0",
46+
"tsx": "^4.0.0"
4547
},
4648
"devDependencies": {
4749
"@types/node": "^20.0.0",

packages/cli/src/index.ts

Lines changed: 183 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
#!/usr/bin/env node
22
import { Command } from 'commander';
33
import { buildWidgets } from './build';
4+
import { spawn } from 'node:child_process';
5+
import { promises as fs } from 'node:fs';
6+
import path from 'node:path';
7+
import open from 'open';
48

59
const program = new Command();
610

@@ -9,18 +13,194 @@ program
913
.description('MCP CLI tool')
1014
.version('0.1.0');
1115

16+
// Helper to check if server is ready
17+
async function waitForServer(port: number, maxAttempts = 30): Promise<boolean> {
18+
for (let i = 0; i < maxAttempts; i++) {
19+
try {
20+
const response = await fetch(`http://localhost:${port}/inspector`);
21+
if (response.ok) {
22+
return true;
23+
}
24+
} catch {
25+
// Server not ready yet
26+
}
27+
await new Promise(resolve => setTimeout(resolve, 1000));
28+
}
29+
return false;
30+
}
31+
32+
// Helper to run a command
33+
function runCommand(command: string, args: string[], cwd: string): Promise<void> {
34+
return new Promise((resolve, reject) => {
35+
const proc = spawn(command, args, {
36+
cwd,
37+
stdio: 'inherit',
38+
shell: true,
39+
});
40+
41+
proc.on('error', reject);
42+
proc.on('exit', (code) => {
43+
if (code === 0) {
44+
resolve();
45+
} else {
46+
reject(new Error(`Command failed with exit code ${code}`));
47+
}
48+
});
49+
});
50+
}
51+
1252
program
1353
.command('build')
14-
.description('Build MCP UI widgets')
54+
.description('Build TypeScript and MCP UI widgets')
1555
.option('-p, --path <path>', 'Path to project directory', process.cwd())
16-
.option('-w, --watch', 'Watch for changes and rebuild')
1756
.action(async (options) => {
1857
try {
19-
await buildWidgets(options.path, options.watch);
58+
const projectPath = path.resolve(options.path);
59+
60+
// Run tsc first
61+
console.log('🔨 Building TypeScript...');
62+
await runCommand('npx', ['tsc'], projectPath);
63+
console.log('✅ TypeScript build complete!');
64+
65+
// Then build widgets
66+
await buildWidgets(projectPath, false);
2067
} catch (error) {
2168
console.error('Build failed:', error);
2269
process.exit(1);
2370
}
2471
});
2572

73+
program
74+
.command('dev')
75+
.description('Run development server with auto-reload and inspector')
76+
.option('-p, --path <path>', 'Path to project directory', process.cwd())
77+
.option('--port <port>', 'Server port', '3000')
78+
.option('--no-open', 'Do not auto-open inspector')
79+
.action(async (options) => {
80+
try {
81+
const projectPath = path.resolve(options.path);
82+
const port = parseInt(options.port, 10);
83+
84+
console.log('🚀 Starting development mode...\n');
85+
86+
// Find the main source file
87+
let serverFile = 'src/server.ts';
88+
try {
89+
await fs.access(path.join(projectPath, serverFile));
90+
} catch {
91+
serverFile = 'src/index.ts';
92+
}
93+
94+
// Start all processes concurrently
95+
const processes: any[] = [];
96+
97+
// 1. TypeScript watch
98+
console.log('📦 Starting TypeScript compiler in watch mode...');
99+
const tscProc = spawn('npx', ['tsc', '--watch'], {
100+
cwd: projectPath,
101+
stdio: 'pipe',
102+
shell: true,
103+
});
104+
tscProc.stdout?.on('data', (data) => {
105+
const output = data.toString();
106+
if (output.includes('Watching for file changes')) {
107+
console.log('✅ TypeScript compiler watching...');
108+
}
109+
});
110+
processes.push(tscProc);
111+
112+
// 2. Widget builder watch - run in background
113+
console.log('🎨 Starting widget builder in watch mode...');
114+
buildWidgets(projectPath, true).catch((error) => {
115+
console.error('Widget builder failed:', error);
116+
});
117+
118+
// Wait a bit for initial builds
119+
await new Promise(resolve => setTimeout(resolve, 2000));
120+
121+
// 3. Server with tsx
122+
console.log(`🌐 Starting server at http://localhost:${port}...`);
123+
const serverProc = spawn('npx', ['tsx', 'watch', serverFile], {
124+
cwd: projectPath,
125+
stdio: 'inherit',
126+
shell: true,
127+
env: { ...process.env, PORT: String(port) },
128+
});
129+
processes.push(serverProc);
130+
131+
// Auto-open inspector if enabled
132+
if (options.open) {
133+
console.log('⏳ Waiting for server to be ready...');
134+
const ready = await waitForServer(port);
135+
if (ready) {
136+
const inspectorUrl = `http://localhost:${port}/inspector`;
137+
console.log(`\n🔍 Opening inspector at ${inspectorUrl}...\n`);
138+
await open(inspectorUrl);
139+
} else {
140+
console.log('\n⚠️ Server did not start in time, skipping auto-open');
141+
}
142+
}
143+
144+
// Handle cleanup
145+
const cleanup = () => {
146+
console.log('\n\n🛑 Shutting down...');
147+
processes.forEach(proc => proc.kill());
148+
process.exit(0);
149+
};
150+
151+
process.on('SIGINT', cleanup);
152+
process.on('SIGTERM', cleanup);
153+
154+
// Keep the process running
155+
await new Promise(() => {});
156+
} catch (error) {
157+
console.error('Dev mode failed:', error);
158+
process.exit(1);
159+
}
160+
});
161+
162+
program
163+
.command('start')
164+
.description('Start production server')
165+
.option('-p, --path <path>', 'Path to project directory', process.cwd())
166+
.option('--port <port>', 'Server port', '3000')
167+
.action(async (options) => {
168+
try {
169+
const projectPath = path.resolve(options.path);
170+
const port = parseInt(options.port, 10);
171+
172+
// Find the built server file
173+
let serverFile = 'dist/server.js';
174+
try {
175+
await fs.access(path.join(projectPath, serverFile));
176+
} catch {
177+
serverFile = 'dist/index.js';
178+
}
179+
180+
console.log('🚀 Starting production server...');
181+
const serverProc = spawn('node', [serverFile], {
182+
cwd: projectPath,
183+
stdio: 'inherit',
184+
env: { ...process.env, PORT: String(port) },
185+
});
186+
187+
// Handle cleanup
188+
const cleanup = () => {
189+
console.log('\n\n🛑 Shutting down...');
190+
serverProc.kill();
191+
process.exit(0);
192+
};
193+
194+
process.on('SIGINT', cleanup);
195+
process.on('SIGTERM', cleanup);
196+
197+
serverProc.on('exit', (code) => {
198+
process.exit(code || 0);
199+
});
200+
} catch (error) {
201+
console.error('Start failed:', error);
202+
process.exit(1);
203+
}
204+
});
205+
26206
program.parse();

packages/create-mcp-use-app/src/templates/ui/package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,13 @@
1616
],
1717
"main": "dist/server.js",
1818
"scripts": {
19-
"build": "tsc && mcp-use build",
20-
"dev": "concurrently \"tsx src/server.ts\" \"mcp-use build --watch\"",
21-
"start": "node dist/server.js"
19+
"build": "mcp-use build",
20+
"dev": "mcp-use dev",
21+
"start": "mcp-use start"
2222
},
2323
"dependencies": {
2424
"@mcp-ui/server": "^5.11.0",
25+
"@mcp-use/inspector": "workspace:*",
2526
"cors": "^2.8.5",
2627
"express": "^4.18.0",
2728
"mcp-use": "workspace:*"

0 commit comments

Comments
 (0)