nitrostack 1.0.19 → 1.0.21
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/cli/mcp-dev-wrapper.js +60 -14
- package/dist/cli/mcp-dev-wrapper.js.map +1 -1
- package/dist/core/events/log-emitter.d.ts +8 -0
- package/dist/core/events/log-emitter.d.ts.map +1 -0
- package/dist/core/events/log-emitter.js +20 -0
- package/dist/core/events/log-emitter.js.map +1 -0
- package/dist/core/logger.d.ts.map +1 -1
- package/dist/core/logger.js +3 -1
- package/dist/core/logger.js.map +1 -1
- package/package.json +1 -1
- package/src/studio/app/settings/page.tsx +8 -79
- package/src/studio/components/Sidebar.tsx +1 -1
|
@@ -3,6 +3,7 @@ import { spawn } from 'child_process';
|
|
|
3
3
|
import chokidar from 'chokidar';
|
|
4
4
|
import path from 'path';
|
|
5
5
|
import { fileURLToPath } from 'url';
|
|
6
|
+
import http from 'http';
|
|
6
7
|
const __filename = fileURLToPath(import.meta.url);
|
|
7
8
|
const __dirname = path.dirname(__filename);
|
|
8
9
|
/**
|
|
@@ -13,6 +14,7 @@ const __dirname = path.dirname(__filename);
|
|
|
13
14
|
* 2. Watches for changes in the dist/ directory
|
|
14
15
|
* 3. Restarts the server when changes are detected
|
|
15
16
|
* 4. Maintains stdio connection for Studio
|
|
17
|
+
* 5. Captures stderr from the MCP server and streams it over an SSE endpoint
|
|
16
18
|
*
|
|
17
19
|
* IMPORTANT: All logs go to stderr to avoid corrupting MCP JSON-RPC on stdout
|
|
18
20
|
*/
|
|
@@ -28,21 +30,68 @@ let isRestarting = false;
|
|
|
28
30
|
let consecutiveFailures = 0;
|
|
29
31
|
const maxConsecutiveFailures = 3;
|
|
30
32
|
let restartTimeout = null;
|
|
33
|
+
let sseClient = null;
|
|
34
|
+
const logCache = [];
|
|
35
|
+
// Create an HTTP server for SSE log streaming
|
|
36
|
+
const logServer = http.createServer((req, res) => {
|
|
37
|
+
if (req.url === '/mcp-logs') {
|
|
38
|
+
res.writeHead(200, {
|
|
39
|
+
'Content-Type': 'text/event-stream',
|
|
40
|
+
'Cache-Control': 'no-cache',
|
|
41
|
+
'Connection': 'keep-alive',
|
|
42
|
+
'Access-Control-Allow-Origin': '*', // Allow all origins
|
|
43
|
+
});
|
|
44
|
+
sseClient = res;
|
|
45
|
+
// Send cached logs
|
|
46
|
+
logCache.forEach(log => {
|
|
47
|
+
sseClient?.write(`data: ${log}\n\n`);
|
|
48
|
+
});
|
|
49
|
+
req.on('close', () => {
|
|
50
|
+
sseClient = null;
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
res.writeHead(404);
|
|
55
|
+
res.end();
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
const logServerPort = parseInt(process.env.MCP_LOG_PORT || '3004');
|
|
59
|
+
logServer.listen(logServerPort, () => {
|
|
60
|
+
console.error(`[NitroStack Hot Reload] Log streaming server running at http://localhost:${logServerPort}/mcp-logs`);
|
|
61
|
+
});
|
|
31
62
|
function startMCPServer() {
|
|
32
63
|
if (isRestarting)
|
|
33
64
|
return;
|
|
34
|
-
// Start the MCP server - inherit stdin/stdout for MCP protocol
|
|
35
|
-
// Set NODE_ENV=development to use STDIO transport only
|
|
36
|
-
// Set PORT from MCP_SERVER_PORT to avoid conflicts with Studio (port 3000)
|
|
37
65
|
const mcpEnv = {
|
|
38
66
|
...process.env,
|
|
39
|
-
NODE_ENV: 'development',
|
|
40
|
-
PORT: process.env.MCP_SERVER_PORT || '3002',
|
|
67
|
+
NODE_ENV: 'development',
|
|
68
|
+
PORT: process.env.MCP_SERVER_PORT || '3002',
|
|
41
69
|
};
|
|
42
70
|
mcpProcess = spawn('node', [distPath], {
|
|
43
|
-
stdio: ['inherit', 'inherit', '
|
|
71
|
+
stdio: ['inherit', 'inherit', 'pipe'], // Pipe stderr to capture logs
|
|
44
72
|
env: mcpEnv,
|
|
45
73
|
});
|
|
74
|
+
let buffer = '';
|
|
75
|
+
if (mcpProcess.stderr) {
|
|
76
|
+
mcpProcess.stderr.on('data', (data) => {
|
|
77
|
+
buffer += data.toString();
|
|
78
|
+
let boundary = buffer.indexOf('\n');
|
|
79
|
+
while (boundary !== -1) {
|
|
80
|
+
const line = buffer.substring(0, boundary);
|
|
81
|
+
buffer = buffer.substring(boundary + 1);
|
|
82
|
+
// Forward to the console for local debugging
|
|
83
|
+
process.stderr.write(line + '\n');
|
|
84
|
+
if (line.startsWith('NITRO_LOG::')) {
|
|
85
|
+
const logJson = line.substring('NITRO_LOG::'.length);
|
|
86
|
+
logCache.push(logJson);
|
|
87
|
+
if (sseClient) {
|
|
88
|
+
sseClient.write(`data: ${logJson}\n\n`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
boundary = buffer.indexOf('\n');
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
}
|
|
46
95
|
mcpProcess.on('exit', (code) => {
|
|
47
96
|
if (!isRestarting) {
|
|
48
97
|
if (code !== 0) {
|
|
@@ -55,7 +104,7 @@ function startMCPServer() {
|
|
|
55
104
|
console.error(`[NitroStack Hot Reload] Server exited with code ${code} (attempt ${consecutiveFailures}/${maxConsecutiveFailures}), restarting...`);
|
|
56
105
|
}
|
|
57
106
|
else {
|
|
58
|
-
consecutiveFailures = 0;
|
|
107
|
+
consecutiveFailures = 0;
|
|
59
108
|
console.error(`[NitroStack Hot Reload] Server exited with code ${code}, restarting...`);
|
|
60
109
|
}
|
|
61
110
|
mcpProcess = null;
|
|
@@ -67,11 +116,9 @@ function startMCPServer() {
|
|
|
67
116
|
});
|
|
68
117
|
}
|
|
69
118
|
function restartMCPServer() {
|
|
70
|
-
// Clear any pending restart
|
|
71
119
|
if (restartTimeout) {
|
|
72
120
|
clearTimeout(restartTimeout);
|
|
73
121
|
}
|
|
74
|
-
// Debounce restarts - wait for all file changes to settle
|
|
75
122
|
restartTimeout = setTimeout(() => {
|
|
76
123
|
if (isRestarting)
|
|
77
124
|
return;
|
|
@@ -79,23 +126,21 @@ function restartMCPServer() {
|
|
|
79
126
|
if (mcpProcess) {
|
|
80
127
|
console.error('[NitroStack Hot Reload] Changes detected, restarting server...');
|
|
81
128
|
mcpProcess.kill('SIGTERM');
|
|
82
|
-
// Wait for the process to exit and ports to be released (especially for HTTP transport)
|
|
83
129
|
setTimeout(() => {
|
|
84
130
|
mcpProcess = null;
|
|
85
131
|
isRestarting = false;
|
|
86
132
|
startMCPServer();
|
|
87
133
|
console.error('[NitroStack Hot Reload] Server restarted successfully');
|
|
88
|
-
}, 1500);
|
|
134
|
+
}, 1500);
|
|
89
135
|
}
|
|
90
136
|
else {
|
|
91
137
|
isRestarting = false;
|
|
92
138
|
startMCPServer();
|
|
93
139
|
}
|
|
94
|
-
}, 1000);
|
|
140
|
+
}, 1000);
|
|
95
141
|
}
|
|
96
142
|
// Start the server initially
|
|
97
143
|
startMCPServer();
|
|
98
|
-
// Watch for changes in dist directory
|
|
99
144
|
const watcher = chokidar.watch(watchPath, {
|
|
100
145
|
ignoreInitial: true,
|
|
101
146
|
persistent: true,
|
|
@@ -112,13 +157,13 @@ watcher.on('add', (filepath) => {
|
|
|
112
157
|
console.error(`[NitroStack Hot Reload] File added: ${path.relative(projectRoot, filepath)}`);
|
|
113
158
|
restartMCPServer();
|
|
114
159
|
});
|
|
115
|
-
// Handle graceful shutdown
|
|
116
160
|
process.on('SIGINT', () => {
|
|
117
161
|
console.error('[NitroStack Hot Reload] Shutting down...');
|
|
118
162
|
watcher.close();
|
|
119
163
|
if (mcpProcess) {
|
|
120
164
|
mcpProcess.kill('SIGTERM');
|
|
121
165
|
}
|
|
166
|
+
logServer.close();
|
|
122
167
|
process.exit(0);
|
|
123
168
|
});
|
|
124
169
|
process.on('SIGTERM', () => {
|
|
@@ -126,6 +171,7 @@ process.on('SIGTERM', () => {
|
|
|
126
171
|
if (mcpProcess) {
|
|
127
172
|
mcpProcess.kill('SIGTERM');
|
|
128
173
|
}
|
|
174
|
+
logServer.close();
|
|
129
175
|
process.exit(0);
|
|
130
176
|
});
|
|
131
177
|
//# sourceMappingURL=mcp-dev-wrapper.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-dev-wrapper.js","sourceRoot":"","sources":["../../src/cli/mcp-dev-wrapper.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,KAAK,EAAgB,MAAM,eAAe,CAAC;AACpD,OAAO,QAAQ,MAAM,UAAU,CAAC;AAChC,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"mcp-dev-wrapper.js","sourceRoot":"","sources":["../../src/cli/mcp-dev-wrapper.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
import Transport from 'winston-transport';
|
|
3
|
+
export declare const logEmitter: EventEmitter<[never]>;
|
|
4
|
+
export declare class EventEmitterTransport extends Transport {
|
|
5
|
+
constructor(opts?: Transport.TransportStreamOptions);
|
|
6
|
+
log(info: any, callback: () => void): void;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=log-emitter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log-emitter.d.ts","sourceRoot":"","sources":["../../../src/core/events/log-emitter.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,SAAS,MAAM,mBAAmB,CAAC;AAG1C,eAAO,MAAM,UAAU,uBAAqB,CAAC;AAG7C,qBAAa,qBAAsB,SAAQ,SAAS;gBACtC,IAAI,CAAC,EAAE,SAAS,CAAC,sBAAsB;IAInD,GAAG,CAAC,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,IAAI;CAUpC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
import Transport from 'winston-transport';
|
|
3
|
+
// Create a new event emitter
|
|
4
|
+
export const logEmitter = new EventEmitter();
|
|
5
|
+
// Define a custom winston transport
|
|
6
|
+
export class EventEmitterTransport extends Transport {
|
|
7
|
+
constructor(opts) {
|
|
8
|
+
super(opts);
|
|
9
|
+
}
|
|
10
|
+
log(info, callback) {
|
|
11
|
+
setImmediate(() => {
|
|
12
|
+
logEmitter.emit('log', info);
|
|
13
|
+
// Also write to stderr for the dev wrapper to capture
|
|
14
|
+
process.stderr.write(`NITRO_LOG::${JSON.stringify(info)}\n`);
|
|
15
|
+
});
|
|
16
|
+
// Perform the callback
|
|
17
|
+
callback();
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=log-emitter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log-emitter.js","sourceRoot":"","sources":["../../../src/core/events/log-emitter.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,SAAS,MAAM,mBAAmB,CAAC;AAE1C,6BAA6B;AAC7B,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,YAAY,EAAE,CAAC;AAE7C,oCAAoC;AACpC,MAAM,OAAO,qBAAsB,SAAQ,SAAS;IAClD,YAAY,IAAuC;QACjD,KAAK,CAAC,IAAI,CAAC,CAAC;IACd,CAAC;IAED,GAAG,CAAC,IAAS,EAAE,QAAoB;QACjC,YAAY,CAAC,GAAG,EAAE;YAChB,UAAU,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;YAC7B,sDAAsD;YACtD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,cAAc,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/D,CAAC,CAAC,CAAC;QAEH,uBAAuB;QACvB,QAAQ,EAAE,CAAC;IACb,CAAC;CACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/core/logger.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/core/logger.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAGpC;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,GAAG,MAAM,CA6DT;AAED;;GAEG;AACH,eAAO,MAAM,aAAa,QAAkC,CAAC"}
|
package/dist/core/logger.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import winston from 'winston';
|
|
2
|
+
import { EventEmitterTransport } from './events/log-emitter.js';
|
|
2
3
|
/**
|
|
3
4
|
* Create a logger instance with custom configuration
|
|
4
5
|
*
|
|
@@ -7,7 +8,7 @@ import winston from 'winston';
|
|
|
7
8
|
*/
|
|
8
9
|
export function createLogger(options) {
|
|
9
10
|
const { level = 'info', file, serviceName = 'nitrostack', enableConsole = false } = options;
|
|
10
|
-
const transports = [];
|
|
11
|
+
const transports = [new EventEmitterTransport()];
|
|
11
12
|
// CRITICAL: Console logging disabled by default for MCP compatibility
|
|
12
13
|
// MCP uses stdio for JSON-RPC communication, console output breaks it
|
|
13
14
|
if (enableConsole) {
|
|
@@ -35,6 +36,7 @@ export function createLogger(options) {
|
|
|
35
36
|
}
|
|
36
37
|
const winstonLogger = winston.createLogger({
|
|
37
38
|
level,
|
|
39
|
+
format: winston.format.combine(winston.format.timestamp(), winston.format.json()),
|
|
38
40
|
transports,
|
|
39
41
|
});
|
|
40
42
|
return {
|
package/dist/core/logger.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/core/logger.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/core/logger.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -5,8 +5,6 @@ import { Settings as SettingsIcon, Wifi, CheckCircle, AlertCircle } from 'lucide
|
|
|
5
5
|
|
|
6
6
|
export default function SettingsPage() {
|
|
7
7
|
const [transport, setTransport] = useState<'stdio' | 'http'>('stdio');
|
|
8
|
-
const [httpUrl, setHttpUrl] = useState('http://localhost:3002');
|
|
9
|
-
const [httpBasePath, setHttpBasePath] = useState('/mcp');
|
|
10
8
|
const [connecting, setConnecting] = useState(false);
|
|
11
9
|
const [connectionStatus, setConnectionStatus] = useState<'idle' | 'success' | 'error'>('idle');
|
|
12
10
|
const [errorMessage, setErrorMessage] = useState('');
|
|
@@ -14,12 +12,8 @@ export default function SettingsPage() {
|
|
|
14
12
|
useEffect(() => {
|
|
15
13
|
// Load saved settings from localStorage
|
|
16
14
|
const savedTransport = localStorage.getItem('mcp_transport');
|
|
17
|
-
const savedHttpUrl = localStorage.getItem('mcp_http_url');
|
|
18
|
-
const savedHttpBasePath = localStorage.getItem('mcp_http_base_path');
|
|
19
15
|
|
|
20
16
|
if (savedTransport) setTransport(savedTransport as 'stdio' | 'http');
|
|
21
|
-
if (savedHttpUrl) setHttpUrl(savedHttpUrl);
|
|
22
|
-
if (savedHttpBasePath) setHttpBasePath(savedHttpBasePath);
|
|
23
17
|
}, []);
|
|
24
18
|
|
|
25
19
|
const handleSaveSettings = async () => {
|
|
@@ -30,10 +24,6 @@ export default function SettingsPage() {
|
|
|
30
24
|
try {
|
|
31
25
|
// Save settings to localStorage
|
|
32
26
|
localStorage.setItem('mcp_transport', transport);
|
|
33
|
-
if (transport === 'http') {
|
|
34
|
-
localStorage.setItem('mcp_http_url', httpUrl);
|
|
35
|
-
localStorage.setItem('mcp_http_base_path', httpBasePath);
|
|
36
|
-
}
|
|
37
27
|
|
|
38
28
|
// Try to reconnect with new settings
|
|
39
29
|
const response = await fetch('/api/init', {
|
|
@@ -41,8 +31,6 @@ export default function SettingsPage() {
|
|
|
41
31
|
headers: { 'Content-Type': 'application/json' },
|
|
42
32
|
body: JSON.stringify({
|
|
43
33
|
transport,
|
|
44
|
-
baseUrl: httpUrl,
|
|
45
|
-
basePath: httpBasePath,
|
|
46
34
|
}),
|
|
47
35
|
});
|
|
48
36
|
|
|
@@ -93,15 +81,11 @@ export default function SettingsPage() {
|
|
|
93
81
|
</label>
|
|
94
82
|
<div className="grid grid-cols-2 gap-4">
|
|
95
83
|
<button
|
|
96
|
-
|
|
97
|
-
className={`p-4 rounded-lg border-2 transition-all text-left
|
|
98
|
-
transport === 'stdio'
|
|
99
|
-
? 'border-primary bg-primary/10'
|
|
100
|
-
: 'border-border hover:border-primary/50'
|
|
101
|
-
}`}
|
|
84
|
+
disabled
|
|
85
|
+
className={`p-4 rounded-lg border-2 transition-all text-left border-primary bg-primary/10`}
|
|
102
86
|
>
|
|
103
87
|
<div className="flex items-center gap-3 mb-2">
|
|
104
|
-
<div className={`w-3 h-3 rounded-full
|
|
88
|
+
<div className={`w-3 h-3 rounded-full bg-primary`} />
|
|
105
89
|
<h3 className="font-semibold text-foreground">STDIO</h3>
|
|
106
90
|
</div>
|
|
107
91
|
<p className="text-sm text-muted-foreground">
|
|
@@ -110,15 +94,11 @@ export default function SettingsPage() {
|
|
|
110
94
|
</button>
|
|
111
95
|
|
|
112
96
|
<button
|
|
113
|
-
|
|
114
|
-
className={`p-4 rounded-lg border-2 transition-all text-left
|
|
115
|
-
transport === 'http'
|
|
116
|
-
? 'border-primary bg-primary/10'
|
|
117
|
-
: 'border-border hover:border-primary/50'
|
|
118
|
-
}`}
|
|
97
|
+
disabled
|
|
98
|
+
className={`p-4 rounded-lg border-2 transition-all text-left border-border hover:border-primary/50`}
|
|
119
99
|
>
|
|
120
100
|
<div className="flex items-center gap-3 mb-2">
|
|
121
|
-
<div className={`w-3 h-3 rounded-full
|
|
101
|
+
<div className={`w-3 h-3 rounded-full bg-muted`} />
|
|
122
102
|
<h3 className="font-semibold text-foreground">HTTP</h3>
|
|
123
103
|
</div>
|
|
124
104
|
<p className="text-sm text-muted-foreground">
|
|
@@ -128,43 +108,6 @@ export default function SettingsPage() {
|
|
|
128
108
|
</div>
|
|
129
109
|
</div>
|
|
130
110
|
|
|
131
|
-
{/* HTTP Configuration (shown only when HTTP is selected) */}
|
|
132
|
-
{transport === 'http' && (
|
|
133
|
-
<div className="space-y-4 mb-6 p-4 bg-muted/30 rounded-lg border border-border">
|
|
134
|
-
<div>
|
|
135
|
-
<label className="block text-sm font-medium text-foreground mb-2">
|
|
136
|
-
Server URL
|
|
137
|
-
</label>
|
|
138
|
-
<input
|
|
139
|
-
type="text"
|
|
140
|
-
value={httpUrl}
|
|
141
|
-
onChange={(e) => setHttpUrl(e.target.value)}
|
|
142
|
-
placeholder="http://localhost:3002"
|
|
143
|
-
className="input"
|
|
144
|
-
/>
|
|
145
|
-
<p className="text-xs text-muted-foreground mt-1">
|
|
146
|
-
The base URL of your MCP HTTP server (default: port 3002)
|
|
147
|
-
</p>
|
|
148
|
-
</div>
|
|
149
|
-
|
|
150
|
-
<div>
|
|
151
|
-
<label className="block text-sm font-medium text-foreground mb-2">
|
|
152
|
-
Base Path
|
|
153
|
-
</label>
|
|
154
|
-
<input
|
|
155
|
-
type="text"
|
|
156
|
-
value={httpBasePath}
|
|
157
|
-
onChange={(e) => setHttpBasePath(e.target.value)}
|
|
158
|
-
placeholder="/mcp"
|
|
159
|
-
className="input"
|
|
160
|
-
/>
|
|
161
|
-
<p className="text-xs text-muted-foreground mt-1">
|
|
162
|
-
The base path for MCP endpoints
|
|
163
|
-
</p>
|
|
164
|
-
</div>
|
|
165
|
-
</div>
|
|
166
|
-
)}
|
|
167
|
-
|
|
168
111
|
{/* Port Allocation Info */}
|
|
169
112
|
<div className="mb-6 p-4 bg-blue-500/10 rounded-lg border border-blue-500/20">
|
|
170
113
|
<h4 className="font-semibold text-foreground mb-2">Port Allocation</h4>
|
|
@@ -191,23 +134,9 @@ export default function SettingsPage() {
|
|
|
191
134
|
<div>
|
|
192
135
|
<h4 className="font-semibold text-foreground mb-1">Transport Information</h4>
|
|
193
136
|
<p className="text-sm text-muted-foreground mb-2">
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
<strong>STDIO</strong> (Default): Studio spawns the MCP server as a child process and communicates
|
|
197
|
-
via standard input/output. The MCP server still runs dual transport (STDIO + HTTP on port 3002).
|
|
198
|
-
</>
|
|
199
|
-
) : (
|
|
200
|
-
<>
|
|
201
|
-
<strong>HTTP</strong>: Studio connects to the running MCP HTTP server on port 3002.
|
|
202
|
-
Use this when you want to inspect an already-running server or connect remotely.
|
|
203
|
-
</>
|
|
204
|
-
)}
|
|
137
|
+
<strong>STDIO</strong> (Default): Studio spawns the MCP server as a child process and communicates
|
|
138
|
+
via standard input/output. The MCP server still runs dual transport (STDIO + HTTP on port 3002).
|
|
205
139
|
</p>
|
|
206
|
-
{transport === 'http' && (
|
|
207
|
-
<p className="text-xs text-amber-600 dark:text-amber-500">
|
|
208
|
-
⚠️ Make sure your MCP server is running with <code>npm run dev</code> or <code>npm start</code>
|
|
209
|
-
</p>
|
|
210
|
-
)}
|
|
211
140
|
</div>
|
|
212
141
|
</div>
|
|
213
142
|
</div>
|
|
@@ -167,7 +167,7 @@ export function Sidebar() {
|
|
|
167
167
|
<div className="flex items-center justify-between text-[10px]">
|
|
168
168
|
<span className="font-medium text-muted-foreground">Transport:</span>
|
|
169
169
|
<span className="font-bold text-primary uppercase">
|
|
170
|
-
|
|
170
|
+
STDIO
|
|
171
171
|
</span>
|
|
172
172
|
</div>
|
|
173
173
|
</div>
|