@mcp-shark/mcp-shark 1.4.0 → 1.4.1
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 +16 -1
- package/bin/mcp-shark.js +179 -53
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -66,11 +66,20 @@ Or if installed locally:
|
|
|
66
66
|
npx @mcp-shark/mcp-shark
|
|
67
67
|
```
|
|
68
68
|
|
|
69
|
+
**Open browser automatically:**
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
mcp-shark --open
|
|
73
|
+
# or
|
|
74
|
+
mcp-shark -o
|
|
75
|
+
```
|
|
76
|
+
|
|
69
77
|
The UI will automatically:
|
|
70
78
|
|
|
71
79
|
- Install dependencies if needed
|
|
72
80
|
- Build the frontend if needed
|
|
73
81
|
- Start the server on `http://localhost:9853`
|
|
82
|
+
- Optionally open your browser automatically (with `--open` flag)
|
|
74
83
|
|
|
75
84
|
Open your browser to `http://localhost:9853` to access the MCP Shark interface.
|
|
76
85
|
|
|
@@ -331,8 +340,14 @@ No manual configuration editing required - MCP Shark handles everything for you.
|
|
|
331
340
|
mcp-shark
|
|
332
341
|
```
|
|
333
342
|
|
|
343
|
+
Or to automatically open your browser:
|
|
344
|
+
|
|
345
|
+
```bash
|
|
346
|
+
mcp-shark --open
|
|
347
|
+
```
|
|
348
|
+
|
|
334
349
|
3. **Open your browser:**
|
|
335
|
-
Navigate to `http://localhost:9853`
|
|
350
|
+
Navigate to `http://localhost:9853` (or it will open automatically with `--open` flag)
|
|
336
351
|
|
|
337
352
|
4. **Interactive Tour**: On first launch, you'll see an interactive tour - follow it to get started
|
|
338
353
|
|
package/bin/mcp-shark.js
CHANGED
|
@@ -3,67 +3,110 @@
|
|
|
3
3
|
import { spawn } from 'node:child_process';
|
|
4
4
|
import { fileURLToPath } from 'node:url';
|
|
5
5
|
import { dirname, join, resolve } from 'node:path';
|
|
6
|
-
import { existsSync } from 'node:fs';
|
|
6
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
7
|
+
import { Command } from 'commander';
|
|
8
|
+
import open from 'open';
|
|
9
|
+
|
|
10
|
+
const SERVER_URL = 'http://localhost:9853';
|
|
11
|
+
const BROWSER_OPEN_DELAY = 1000;
|
|
7
12
|
|
|
8
13
|
const __filename = fileURLToPath(import.meta.url);
|
|
9
14
|
const __dirname = dirname(__filename);
|
|
10
15
|
const rootDir = resolve(__dirname, '..');
|
|
11
|
-
const uiDir = join(rootDir, 'ui');
|
|
12
16
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
/**
|
|
18
|
+
* Display welcome banner
|
|
19
|
+
*/
|
|
20
|
+
function displayWelcomeBanner() {
|
|
21
|
+
const pkgPath = join(rootDir, 'package.json');
|
|
22
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
|
|
23
|
+
const version = pkg.version;
|
|
18
24
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
const banner = `
|
|
26
|
+
███╗ ███╗ ██████╗ ██████╗ ███████╗██╗ ██╗ █████╗ ██████╗ ██╗ ██╗
|
|
27
|
+
████╗ ████║██╔════╝██╔══██╗ ██╔════╝██║ ██║██╔══██╗██╔══██╗██║ ██╔╝
|
|
28
|
+
██╔████╔██║██║ ██████╔╝ ███████╗███████║███████║██████╔╝█████╔╝
|
|
29
|
+
██║╚██╔╝██║██║ ██╔═══╝ ╚════██║██╔══██║██╔══██║██╔══██╗██╔═██╗
|
|
30
|
+
██║ ╚═╝ ██║╚██████╗██║ ███████║██║ ██║██║ ██║██║ ██║██║ ██╗
|
|
31
|
+
╚═╝ ╚═╝ ╚═════╝╚═╝ ╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝
|
|
32
|
+
|
|
33
|
+
Aggregate multiple MCP servers into a unified interface
|
|
34
|
+
Version: ${version} | Homepage: https://mcpshark.sh
|
|
35
|
+
`;
|
|
28
36
|
|
|
29
|
-
|
|
30
|
-
if (code !== 0) {
|
|
31
|
-
console.error('Failed to install dependencies');
|
|
32
|
-
process.exit(1);
|
|
33
|
-
}
|
|
34
|
-
console.log('Dependencies installed successfully!\n');
|
|
35
|
-
startUIServer();
|
|
36
|
-
});
|
|
37
|
-
} else {
|
|
38
|
-
startUIServer();
|
|
37
|
+
console.log(banner);
|
|
39
38
|
}
|
|
40
39
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
40
|
+
const uiDir = join(rootDir, 'ui');
|
|
41
|
+
const distDir = join(uiDir, 'dist');
|
|
42
|
+
const rootNodeModules = join(rootDir, 'node_modules');
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Run a command and return a promise that resolves when it completes
|
|
46
|
+
*/
|
|
47
|
+
function runCommand(command, args, options) {
|
|
48
|
+
return new Promise((resolve, reject) => {
|
|
49
|
+
const process = spawn(command, args, {
|
|
50
|
+
...options,
|
|
48
51
|
stdio: 'inherit',
|
|
49
52
|
shell: true,
|
|
50
53
|
});
|
|
51
54
|
|
|
52
|
-
|
|
55
|
+
process.on('close', (code) => {
|
|
53
56
|
if (code !== 0) {
|
|
54
|
-
|
|
55
|
-
|
|
57
|
+
reject(new Error(`Command failed with exit code ${code}`));
|
|
58
|
+
} else {
|
|
59
|
+
resolve();
|
|
56
60
|
}
|
|
57
|
-
runServer();
|
|
58
61
|
});
|
|
59
|
-
|
|
60
|
-
|
|
62
|
+
|
|
63
|
+
process.on('error', (error) => {
|
|
64
|
+
reject(error);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Install dependencies in the root directory
|
|
71
|
+
*/
|
|
72
|
+
async function installDependencies() {
|
|
73
|
+
console.log('Installing dependencies...');
|
|
74
|
+
try {
|
|
75
|
+
await runCommand('npm', ['install'], { cwd: rootDir });
|
|
76
|
+
console.log('Dependencies installed successfully!\n');
|
|
77
|
+
} catch (error) {
|
|
78
|
+
console.error('Failed to install dependencies:', error.message);
|
|
79
|
+
process.exit(1);
|
|
61
80
|
}
|
|
62
81
|
}
|
|
63
82
|
|
|
64
|
-
|
|
83
|
+
/**
|
|
84
|
+
* Build the UI for production
|
|
85
|
+
*/
|
|
86
|
+
async function buildUI() {
|
|
87
|
+
console.log('Building UI for production...');
|
|
88
|
+
try {
|
|
89
|
+
await runCommand('npm', ['run', 'build'], { cwd: uiDir });
|
|
90
|
+
} catch (error) {
|
|
91
|
+
console.error('Failed to build UI:', error.message);
|
|
92
|
+
process.exit(1);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Open the browser after a short delay
|
|
98
|
+
*/
|
|
99
|
+
async function openBrowser() {
|
|
100
|
+
await new Promise((resolve) => setTimeout(resolve, BROWSER_OPEN_DELAY));
|
|
101
|
+
open(SERVER_URL);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Start the UI server
|
|
106
|
+
*/
|
|
107
|
+
async function startServer(shouldOpenBrowser = false) {
|
|
65
108
|
console.log('Starting MCP Shark UI server...');
|
|
66
|
-
console.log(
|
|
109
|
+
console.log(`Open ${SERVER_URL} in your browser`);
|
|
67
110
|
console.log('Press Ctrl+C to stop\n');
|
|
68
111
|
|
|
69
112
|
const serverProcess = spawn('node', ['server.js'], {
|
|
@@ -72,22 +115,105 @@ function runServer() {
|
|
|
72
115
|
shell: true,
|
|
73
116
|
});
|
|
74
117
|
|
|
118
|
+
if (shouldOpenBrowser) {
|
|
119
|
+
await openBrowser();
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
let isShuttingDown = false;
|
|
123
|
+
|
|
75
124
|
serverProcess.on('close', (code) => {
|
|
76
|
-
if (
|
|
77
|
-
|
|
78
|
-
|
|
125
|
+
if (!isShuttingDown) {
|
|
126
|
+
if (code !== 0 && code !== null) {
|
|
127
|
+
console.error(`Server exited with code ${code}`);
|
|
128
|
+
process.exit(code);
|
|
129
|
+
}
|
|
130
|
+
} else {
|
|
131
|
+
process.exit(0);
|
|
79
132
|
}
|
|
80
133
|
});
|
|
81
134
|
|
|
82
135
|
// Handle process termination
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
process.exit(0);
|
|
87
|
-
});
|
|
136
|
+
const shutdown = async (signal) => {
|
|
137
|
+
if (isShuttingDown) return;
|
|
138
|
+
isShuttingDown = true;
|
|
88
139
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
process
|
|
92
|
-
|
|
140
|
+
console.log('Shutting down...');
|
|
141
|
+
|
|
142
|
+
// Send signal to child process
|
|
143
|
+
serverProcess.kill(signal);
|
|
144
|
+
|
|
145
|
+
// Wait for child process to exit, with timeout
|
|
146
|
+
const timeout = setTimeout(() => {
|
|
147
|
+
console.log('Forcefully terminating server process...');
|
|
148
|
+
serverProcess.kill('SIGKILL');
|
|
149
|
+
process.exit(1);
|
|
150
|
+
}, 5000);
|
|
151
|
+
|
|
152
|
+
serverProcess.once('close', () => {
|
|
153
|
+
clearTimeout(timeout);
|
|
154
|
+
process.exit(0);
|
|
155
|
+
});
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
process.on('SIGINT', () => shutdown('SIGINT'));
|
|
159
|
+
process.on('SIGTERM', () => shutdown('SIGTERM'));
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Validate that required directories exist
|
|
164
|
+
*/
|
|
165
|
+
function validateDirectories() {
|
|
166
|
+
if (!existsSync(uiDir)) {
|
|
167
|
+
console.error('Error: UI directory not found. Please ensure you are in the correct directory.');
|
|
168
|
+
process.exit(1);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Ensure dependencies are installed
|
|
174
|
+
*/
|
|
175
|
+
async function ensureDependencies() {
|
|
176
|
+
if (!existsSync(rootNodeModules)) {
|
|
177
|
+
await installDependencies();
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Ensure UI is built
|
|
183
|
+
*/
|
|
184
|
+
async function ensureUIBuilt() {
|
|
185
|
+
if (!existsSync(distDir)) {
|
|
186
|
+
await buildUI();
|
|
187
|
+
}
|
|
93
188
|
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Main execution function
|
|
192
|
+
*/
|
|
193
|
+
async function main() {
|
|
194
|
+
// Display welcome banner
|
|
195
|
+
displayWelcomeBanner();
|
|
196
|
+
|
|
197
|
+
// Parse command line options
|
|
198
|
+
const program = new Command();
|
|
199
|
+
program.option('-o, --open', 'Open the browser', false).parse(process.argv);
|
|
200
|
+
|
|
201
|
+
const options = program.opts();
|
|
202
|
+
|
|
203
|
+
// Validate environment
|
|
204
|
+
validateDirectories();
|
|
205
|
+
|
|
206
|
+
// Ensure dependencies are installed
|
|
207
|
+
await ensureDependencies();
|
|
208
|
+
|
|
209
|
+
// Ensure UI is built
|
|
210
|
+
await ensureUIBuilt();
|
|
211
|
+
|
|
212
|
+
// Start the server
|
|
213
|
+
await startServer(options.open);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
main().catch((error) => {
|
|
217
|
+
console.error('Unexpected error:', error);
|
|
218
|
+
process.exit(1);
|
|
219
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mcp-shark/mcp-shark",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.1",
|
|
4
4
|
"description": "Aggregate multiple Model Context Protocol (MCP) servers into a single unified interface with a powerful monitoring UI. Prov deep visibility into every request and response.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./bin/mcp-shark.js",
|
|
@@ -85,7 +85,9 @@
|
|
|
85
85
|
"mcp-shark-common": "github:mcp-shark/mcp-shark-common",
|
|
86
86
|
"react": "^18.2.0",
|
|
87
87
|
"react-dom": "^18.2.0",
|
|
88
|
-
"ws": "^8.16.0"
|
|
88
|
+
"ws": "^8.16.0",
|
|
89
|
+
"open": "^11.0.0",
|
|
90
|
+
"commander": "^14.0.2"
|
|
89
91
|
},
|
|
90
92
|
"devDependencies": {
|
|
91
93
|
"@commitlint/cli": "^19.5.0",
|