@mcp-use/inspector 0.3.2 → 0.3.5

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/dist/index.js DELETED
@@ -1,107 +0,0 @@
1
- // src/server/middleware.ts
2
- import { Buffer } from "buffer";
3
- import { existsSync } from "fs";
4
- import { dirname, join } from "path";
5
- import { fileURLToPath } from "url";
6
- var __filename = fileURLToPath(import.meta.url);
7
- var __dirname = dirname(__filename);
8
- function mountInspector(app, path = "/inspector", mcpServerUrl) {
9
- const basePath = path.startsWith("/") ? path : `/${path}`;
10
- const clientDistPath = join(__dirname, "../../dist/client");
11
- if (!existsSync(clientDistPath)) {
12
- console.warn(`\u26A0\uFE0F MCP Inspector client files not found at ${clientDistPath}`);
13
- console.warn(` Run 'yarn build' in the inspector package to build the UI`);
14
- return;
15
- }
16
- app.get(`${basePath}/config.json`, (_req, res) => {
17
- res.json({
18
- autoConnectUrl: mcpServerUrl || null
19
- });
20
- });
21
- app.get(`${basePath}/api/favicon/:url`, async (req, res) => {
22
- const url = req.params.url;
23
- if (!url) {
24
- res.status(400).json({ error: "URL parameter is required" });
25
- return;
26
- }
27
- try {
28
- const decodedUrl = decodeURIComponent(url);
29
- let fullUrl = decodedUrl;
30
- if (!decodedUrl.startsWith("http://") && !decodedUrl.startsWith("https://")) {
31
- fullUrl = `https://${decodedUrl}`;
32
- }
33
- const urlObj = new URL(fullUrl);
34
- const faviconUrls = [
35
- `${urlObj.origin}/favicon.ico`,
36
- `${urlObj.origin}/favicon.png`,
37
- `${urlObj.origin}/apple-touch-icon.png`
38
- ];
39
- for (const faviconUrl of faviconUrls) {
40
- try {
41
- const response = await fetch(faviconUrl, {
42
- headers: {
43
- "User-Agent": "Mozilla/5.0 (compatible; MCP-Inspector/1.0)"
44
- }
45
- });
46
- if (response.ok) {
47
- const contentType = response.headers.get("content-type") || "image/x-icon";
48
- const buffer = await response.arrayBuffer();
49
- res.setHeader("Content-Type", contentType);
50
- res.setHeader("Cache-Control", "public, max-age=86400");
51
- res.setHeader("Access-Control-Allow-Origin", "*");
52
- res.send(Buffer.from(buffer));
53
- return;
54
- }
55
- } catch {
56
- continue;
57
- }
58
- }
59
- res.status(404).json({ error: "No favicon found" });
60
- } catch (error) {
61
- console.error("Favicon proxy error:", error);
62
- res.status(400).json({ error: "Invalid URL or fetch failed" });
63
- }
64
- });
65
- app.use(`${basePath}/assets`, (_req, res) => {
66
- const assetPath = join(clientDistPath, "assets", _req.path);
67
- if (existsSync(assetPath)) {
68
- if (assetPath.endsWith(".js")) {
69
- res.setHeader("Content-Type", "application/javascript");
70
- } else if (assetPath.endsWith(".css")) {
71
- res.setHeader("Content-Type", "text/css");
72
- }
73
- res.sendFile(assetPath);
74
- } else {
75
- res.status(404).send("Asset not found");
76
- }
77
- });
78
- if (basePath !== "") {
79
- app.get("/oauth/callback", (req, res) => {
80
- const queryString = req.url.split("?")[1] || "";
81
- const redirectUrl = queryString ? `${basePath}/oauth/callback?${queryString}` : `${basePath}/oauth/callback`;
82
- res.redirect(302, redirectUrl);
83
- });
84
- }
85
- app.get(basePath, (_req, res) => {
86
- const indexPath = join(clientDistPath, "index.html");
87
- if (!existsSync(indexPath)) {
88
- res.status(500).send("Inspector UI not found. Please build the inspector package.");
89
- return;
90
- }
91
- res.sendFile(indexPath);
92
- });
93
- app.get(`${basePath}/`, (_req, res) => {
94
- res.redirect(301, basePath);
95
- });
96
- app.get(`${basePath}/*`, (_req, res) => {
97
- const indexPath = join(clientDistPath, "index.html");
98
- if (!existsSync(indexPath)) {
99
- res.status(500).send("Inspector UI not found. Please build the inspector package.");
100
- return;
101
- }
102
- res.sendFile(indexPath);
103
- });
104
- }
105
- export {
106
- mountInspector
107
- };
@@ -1,4 +0,0 @@
1
- import { Hono } from 'hono';
2
- declare const app: Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
3
- export default app;
4
- //# sourceMappingURL=favicon-proxy.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"favicon-proxy.d.ts","sourceRoot":"","sources":["../../src/server/favicon-proxy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAG3B,QAAA,MAAM,GAAG,4EAAa,CAAA;AAqJtB,eAAe,GAAG,CAAA"}
@@ -1,123 +0,0 @@
1
- import { Hono } from 'hono';
2
- import { cors } from 'hono/cors';
3
- const app = new Hono();
4
- // Enable CORS for all routes
5
- app.use('*', cors());
6
- const faviconCache = new Map();
7
- const CACHE_TTL = 24 * 60 * 60 * 1000; // 24 hours in milliseconds
8
- const MAX_CACHE_SIZE = 1000; // Maximum number of cached favicons
9
- // Clean up expired cache entries
10
- function cleanupCache() {
11
- const now = Date.now();
12
- for (const [key, entry] of faviconCache.entries()) {
13
- if (now - entry.timestamp > entry.ttl) {
14
- faviconCache.delete(key);
15
- }
16
- }
17
- }
18
- // Run cleanup every hour
19
- setInterval(cleanupCache, 60 * 60 * 1000);
20
- // Get cache key for a URL
21
- function getCacheKey(url) {
22
- try {
23
- const urlObj = new URL(url);
24
- return urlObj.hostname.toLowerCase();
25
- }
26
- catch {
27
- return url.toLowerCase();
28
- }
29
- }
30
- // Favicon proxy endpoint
31
- app.get('/:url', async (c) => {
32
- const url = c.req.param('url');
33
- if (!url) {
34
- return c.json({ error: 'URL parameter is required' }, 400);
35
- }
36
- try {
37
- // Decode the URL
38
- const decodedUrl = decodeURIComponent(url);
39
- // Add protocol if missing
40
- let fullUrl = decodedUrl;
41
- if (!decodedUrl.startsWith('http://') && !decodedUrl.startsWith('https://')) {
42
- fullUrl = `https://${decodedUrl}`;
43
- }
44
- // Validate URL
45
- const urlObj = new URL(fullUrl);
46
- const cacheKey = getCacheKey(fullUrl);
47
- // Check cache first
48
- const cachedEntry = faviconCache.get(cacheKey);
49
- if (cachedEntry && (Date.now() - cachedEntry.timestamp) < cachedEntry.ttl) {
50
- return new Response(cachedEntry.data, {
51
- headers: {
52
- 'Content-Type': cachedEntry.contentType,
53
- 'Cache-Control': 'public, max-age=86400, immutable', // Cache for 24 hours
54
- 'Access-Control-Allow-Origin': '*',
55
- 'X-Cache': 'HIT',
56
- },
57
- });
58
- }
59
- const protocol = urlObj.protocol;
60
- const baseDomain = `${protocol}//${urlObj.origin.split('.').slice(-2).join('.')}`;
61
- // Try to fetch favicon from common locations
62
- const faviconUrls = [
63
- `${urlObj.origin}/favicon.ico`,
64
- `${urlObj.origin}/favicon.png`,
65
- `${urlObj.origin}/apple-touch-icon.png`,
66
- `${urlObj.origin}/icon.png`,
67
- `${baseDomain}/favicon.ico`,
68
- `${baseDomain}/favicon.png`,
69
- `${baseDomain}/apple-touch-icon.png`,
70
- `${baseDomain}/icon.png`,
71
- ];
72
- for (const faviconUrl of faviconUrls) {
73
- try {
74
- const response = await fetch(faviconUrl, {
75
- headers: {
76
- 'User-Agent': 'Mozilla/5.0 (compatible; MCP-Inspector/1.0)',
77
- },
78
- });
79
- if (response.ok) {
80
- const contentType = response.headers.get('content-type') || 'image/x-icon';
81
- const buffer = await response.arrayBuffer();
82
- // Cache the result
83
- if (faviconCache.size >= MAX_CACHE_SIZE) {
84
- // Remove oldest entries if cache is full
85
- const entries = Array.from(faviconCache.entries());
86
- entries.sort((a, b) => a[1].timestamp - b[1].timestamp);
87
- const toRemove = entries.slice(0, Math.floor(MAX_CACHE_SIZE / 4));
88
- toRemove.forEach(([key]) => faviconCache.delete(key));
89
- }
90
- faviconCache.set(cacheKey, {
91
- data: buffer,
92
- contentType,
93
- timestamp: Date.now(),
94
- ttl: CACHE_TTL,
95
- });
96
- return new Response(buffer, {
97
- headers: {
98
- 'Content-Type': contentType,
99
- 'Cache-Control': 'public, max-age=86400, immutable', // Cache for 24 hours
100
- 'Access-Control-Allow-Origin': '*',
101
- 'X-Cache': 'MISS',
102
- },
103
- });
104
- }
105
- }
106
- catch {
107
- // Continue to next URL
108
- continue;
109
- }
110
- }
111
- // If no favicon found, return a default icon
112
- return c.json({ error: 'No favicon found' }, 404);
113
- }
114
- catch (error) {
115
- console.error('Favicon proxy error:', error);
116
- return c.json({ error: 'Invalid URL or fetch failed' }, 400);
117
- }
118
- });
119
- // Health check endpoint
120
- app.get('/health', (c) => {
121
- return c.json({ status: 'ok', service: 'favicon-proxy' });
122
- });
123
- export default app;
@@ -1,9 +0,0 @@
1
- declare function startServer(): Promise<{
2
- port: number;
3
- fetch: (request: Request, Env?: unknown, executionCtx?: import("hono").ExecutionContext) => Response | Promise<Response>;
4
- }>;
5
- declare const _default: {
6
- startServer: typeof startServer;
7
- };
8
- export default _default;
9
- //# sourceMappingURL=standalone.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"standalone.d.ts","sourceRoot":"","sources":["../../src/server/standalone.ts"],"names":[],"mappings":"AA+NA,iBAAe,WAAW;;;GA6BzB;;;;AAOD,wBAA8B"}
@@ -1,228 +0,0 @@
1
- import { exec } from 'node:child_process';
2
- import { existsSync } from 'node:fs';
3
- import { dirname, join } from 'node:path';
4
- import { fileURLToPath } from 'node:url';
5
- import { promisify } from 'node:util';
6
- import { serve } from '@hono/node-server';
7
- import { Hono } from 'hono';
8
- import { cors } from 'hono/cors';
9
- import { logger } from 'hono/logger';
10
- import faviconProxy from './favicon-proxy.js';
11
- import { MCPInspector } from './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
- const app = new Hono();
36
- // Middleware
37
- app.use('*', cors());
38
- app.use('*', logger());
39
- // Mount favicon proxy
40
- app.route('/api/favicon', faviconProxy);
41
- // Health check
42
- app.get('/health', (c) => {
43
- return c.json({ status: 'ok', timestamp: new Date().toISOString() });
44
- });
45
- // MCP Inspector routes
46
- const mcpInspector = new MCPInspector();
47
- // List available MCP servers
48
- app.get('/api/servers', async (c) => {
49
- try {
50
- const servers = await mcpInspector.listServers();
51
- return c.json({ servers });
52
- }
53
- catch {
54
- return c.json({ error: 'Failed to list servers' }, 500);
55
- }
56
- });
57
- // Connect to an MCP server
58
- app.post('/api/servers/connect', async (c) => {
59
- try {
60
- const { url, command } = await c.req.json();
61
- const server = await mcpInspector.connectToServer(url, command);
62
- return c.json({ server });
63
- }
64
- catch {
65
- return c.json({ error: 'Failed to connect to server' }, 500);
66
- }
67
- });
68
- // Get server details
69
- app.get('/api/servers/:id', async (c) => {
70
- try {
71
- const id = c.req.param('id');
72
- const server = await mcpInspector.getServer(id);
73
- if (!server) {
74
- return c.json({ error: 'Server not found' }, 404);
75
- }
76
- return c.json({ server });
77
- }
78
- catch {
79
- return c.json({ error: 'Failed to get server details' }, 500);
80
- }
81
- });
82
- // Execute a tool on a server
83
- app.post('/api/servers/:id/tools/:toolName/execute', async (c) => {
84
- try {
85
- const id = c.req.param('id');
86
- const toolName = c.req.param('toolName');
87
- const input = await c.req.json();
88
- const result = await mcpInspector.executeTool(id, toolName, input);
89
- return c.json({ result });
90
- }
91
- catch {
92
- return c.json({ error: 'Failed to execute tool' }, 500);
93
- }
94
- });
95
- // Get server tools
96
- app.get('/api/servers/:id/tools', async (c) => {
97
- try {
98
- const id = c.req.param('id');
99
- const tools = await mcpInspector.getServerTools(id);
100
- return c.json({ tools });
101
- }
102
- catch {
103
- return c.json({ error: 'Failed to get server tools' }, 500);
104
- }
105
- });
106
- // Get server resources
107
- app.get('/api/servers/:id/resources', async (c) => {
108
- try {
109
- const id = c.req.param('id');
110
- const resources = await mcpInspector.getServerResources(id);
111
- return c.json({ resources });
112
- }
113
- catch {
114
- return c.json({ error: 'Failed to get server resources' }, 500);
115
- }
116
- });
117
- // Disconnect from a server
118
- app.delete('/api/servers/:id', async (c) => {
119
- try {
120
- const id = c.req.param('id');
121
- await mcpInspector.disconnectServer(id);
122
- return c.json({ success: true });
123
- }
124
- catch {
125
- return c.json({ error: 'Failed to disconnect server' }, 500);
126
- }
127
- });
128
- // Serve static assets from the built client
129
- const clientDistPath = join(__dirname, '../../dist/client');
130
- if (existsSync(clientDistPath)) {
131
- // Serve static assets from /inspector/assets/* (matching Vite's base path)
132
- app.get('/inspector/assets/*', async (c) => {
133
- const path = c.req.path.replace('/inspector/assets/', 'assets/');
134
- const fullPath = join(clientDistPath, path);
135
- if (existsSync(fullPath)) {
136
- const content = await import('node:fs').then(fs => fs.readFileSync(fullPath));
137
- // Set appropriate content type based on file extension
138
- if (path.endsWith('.js')) {
139
- c.header('Content-Type', 'application/javascript');
140
- }
141
- else if (path.endsWith('.css')) {
142
- c.header('Content-Type', 'text/css');
143
- }
144
- else if (path.endsWith('.svg')) {
145
- c.header('Content-Type', 'image/svg+xml');
146
- }
147
- return c.body(content);
148
- }
149
- return c.notFound();
150
- });
151
- // Redirect root path to /inspector
152
- app.get('/', (c) => {
153
- return c.redirect('/inspector');
154
- });
155
- // Serve the main HTML file for /inspector and all other routes (SPA routing)
156
- app.get('*', (c) => {
157
- const indexPath = join(clientDistPath, 'index.html');
158
- if (existsSync(indexPath)) {
159
- const content = import('node:fs').then(fs => fs.readFileSync(indexPath, 'utf-8'));
160
- return c.html(content);
161
- }
162
- return c.html(`
163
- <!DOCTYPE html>
164
- <html>
165
- <head>
166
- <title>MCP Inspector</title>
167
- </head>
168
- <body>
169
- <h1>MCP Inspector</h1>
170
- <p>Client files not found. Please run 'yarn build' to build the UI.</p>
171
- <p>API is available at <a href="/api/servers">/api/servers</a></p>
172
- </body>
173
- </html>
174
- `);
175
- });
176
- }
177
- else {
178
- console.warn(`⚠️ MCP Inspector client files not found at ${clientDistPath}`);
179
- console.warn(` Run 'yarn build' in the inspector package to build the UI`);
180
- // Fallback for when client is not built
181
- app.get('*', (c) => {
182
- return c.html(`
183
- <!DOCTYPE html>
184
- <html>
185
- <head>
186
- <title>MCP Inspector</title>
187
- </head>
188
- <body>
189
- <h1>MCP Inspector</h1>
190
- <p>Client files not found. Please run 'yarn build' to build the UI.</p>
191
- <p>API is available at <a href="/api/servers">/api/servers</a></p>
192
- </body>
193
- </html>
194
- `);
195
- });
196
- }
197
- // Start the server with automatic port selection
198
- async function startServer() {
199
- try {
200
- const port = await findAvailablePort();
201
- serve({
202
- fetch: app.fetch,
203
- port,
204
- });
205
- console.log(`🚀 MCP Inspector running on http://localhost:${port}`);
206
- // Auto-open browser in development
207
- if (process.env.NODE_ENV !== 'production') {
208
- try {
209
- const command = process.platform === 'win32' ? 'start' : process.platform === 'darwin' ? 'open' : 'xdg-open';
210
- await execAsync(`${command} http://localhost:${port}`);
211
- console.log(`🌐 Browser opened automatically`);
212
- }
213
- catch (error) {
214
- console.log(`🌐 Please open http://localhost:${port} in your browser`);
215
- }
216
- }
217
- return { port, fetch: app.fetch };
218
- }
219
- catch (error) {
220
- console.error('Failed to start server:', error);
221
- process.exit(1);
222
- }
223
- }
224
- // Start the server if this file is run directly
225
- if (import.meta.url === `file://${process.argv[1]}`) {
226
- startServer();
227
- }
228
- export default { startServer };
@@ -1,9 +0,0 @@
1
- declare function startServer(): Promise<{
2
- port: number;
3
- fetch: (request: Request, Env?: unknown, executionCtx?: import("hono").ExecutionContext) => Response | Promise<Response>;
4
- }>;
5
- declare const _default: {
6
- startServer: typeof startServer;
7
- };
8
- export default _default;
9
- //# sourceMappingURL=unified.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"unified.d.ts","sourceRoot":"","sources":["../../src/server/unified.ts"],"names":[],"mappings":"AA2QA,iBAAe,WAAW;;;GA8DzB;;;;AAOD,wBAA8B"}