embark-cli 1.1.7
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/.claude/CLAUDE.md +33 -0
- package/.claude/settings.local.json +32 -0
- package/.github/WORKFLOWS.md +147 -0
- package/.github/workflows/ci.yml +49 -0
- package/.github/workflows/publish.yml +109 -0
- package/.idea/embark-remote-mcp.iml +9 -0
- package/.idea/encodings.xml +4 -0
- package/.idea/indexLayout.xml +8 -0
- package/.idea/vcs.xml +6 -0
- package/.mcp.json +14 -0
- package/GIT_DISCOVERY.md +231 -0
- package/INTEGRATION_TESTING.md +243 -0
- package/MULTI_REPOSITORY_SEARCH.md +242 -0
- package/README.md +434 -0
- package/dist/auth/auth-helper.d.ts +3 -0
- package/dist/auth/auth-helper.d.ts.map +1 -0
- package/dist/auth/auth-helper.js +171 -0
- package/dist/auth/auth-helper.js.map +1 -0
- package/dist/auth/index.d.ts +4 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +24 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/jba-login.d.ts +17 -0
- package/dist/auth/jba-login.d.ts.map +1 -0
- package/dist/auth/jba-login.js +345 -0
- package/dist/auth/jba-login.js.map +1 -0
- package/dist/auth/types.d.ts +16 -0
- package/dist/auth/types.d.ts.map +1 -0
- package/dist/auth/types.js +3 -0
- package/dist/auth/types.js.map +1 -0
- package/dist/config.d.ts +26 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +54 -0
- package/dist/config.js.map +1 -0
- package/dist/embark-client.d.ts +56 -0
- package/dist/embark-client.d.ts.map +1 -0
- package/dist/embark-client.js +543 -0
- package/dist/embark-client.js.map +1 -0
- package/dist/git-utils.d.ts +47 -0
- package/dist/git-utils.d.ts.map +1 -0
- package/dist/git-utils.js +232 -0
- package/dist/git-utils.js.map +1 -0
- package/dist/handlers.d.ts +80 -0
- package/dist/handlers.d.ts.map +1 -0
- package/dist/handlers.js +301 -0
- package/dist/handlers.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +165 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +4 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +92 -0
- package/dist/logger.js.map +1 -0
- package/dist/stats-server.d.ts +3 -0
- package/dist/stats-server.d.ts.map +1 -0
- package/dist/stats-server.js +623 -0
- package/dist/stats-server.js.map +1 -0
- package/dist/stats.d.ts +118 -0
- package/dist/stats.d.ts.map +1 -0
- package/dist/stats.js +206 -0
- package/dist/stats.js.map +1 -0
- package/dist/tools.d.ts +9 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +62 -0
- package/dist/tools.js.map +1 -0
- package/package.json +47 -0
- package/test-git-discovery.mjs +322 -0
- package/test-multi-repo-filters.mjs +151 -0
- package/test-multiple-roots.mjs +436 -0
- package/test-roots.mjs +306 -0
- package/test-snippet-extraction.mjs +136 -0
- package/watch-logs.sh +78 -0
package/test-roots.mjs
ADDED
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Test script for MCP roots/list functionality
|
|
5
|
+
*
|
|
6
|
+
* This script spawns the MCP server and tests the roots/list endpoint
|
|
7
|
+
* by sending JSON-RPC requests via stdio.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { spawn } from 'child_process';
|
|
11
|
+
import { fileURLToPath } from 'url';
|
|
12
|
+
import { dirname, join } from 'path';
|
|
13
|
+
|
|
14
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
15
|
+
const __dirname = dirname(__filename);
|
|
16
|
+
|
|
17
|
+
// Configuration
|
|
18
|
+
const SERVER_PATH = join(__dirname, 'dist', 'index.js');
|
|
19
|
+
const REPOSITORY_URL = process.env.REPOSITORY_GIT_REMOTE_URL || 'https://github.com/jetbrains/embark-mcp.git';
|
|
20
|
+
|
|
21
|
+
// Colors for terminal output
|
|
22
|
+
const colors = {
|
|
23
|
+
reset: '\x1b[0m',
|
|
24
|
+
green: '\x1b[32m',
|
|
25
|
+
red: '\x1b[31m',
|
|
26
|
+
yellow: '\x1b[33m',
|
|
27
|
+
blue: '\x1b[34m',
|
|
28
|
+
gray: '\x1b[90m',
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
function log(message, color = colors.reset) {
|
|
32
|
+
console.log(`${color}${message}${colors.reset}`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function logSuccess(message) {
|
|
36
|
+
log(`✓ ${message}`, colors.green);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function logError(message) {
|
|
40
|
+
log(`✗ ${message}`, colors.red);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function logInfo(message) {
|
|
44
|
+
log(`ℹ ${message}`, colors.blue);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function logDebug(message) {
|
|
48
|
+
log(` ${message}`, colors.gray);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Send a JSON-RPC request to the server
|
|
53
|
+
*/
|
|
54
|
+
function sendRequest(server, request) {
|
|
55
|
+
return new Promise((resolve, reject) => {
|
|
56
|
+
const requestStr = JSON.stringify(request) + '\n';
|
|
57
|
+
logDebug(`→ ${requestStr.trim()}`);
|
|
58
|
+
|
|
59
|
+
let responseBuffer = '';
|
|
60
|
+
let resolved = false;
|
|
61
|
+
|
|
62
|
+
const onData = (data) => {
|
|
63
|
+
responseBuffer += data.toString();
|
|
64
|
+
|
|
65
|
+
// Try to parse complete JSON objects
|
|
66
|
+
const lines = responseBuffer.split('\n');
|
|
67
|
+
responseBuffer = lines.pop(); // Keep incomplete line in buffer
|
|
68
|
+
|
|
69
|
+
for (const line of lines) {
|
|
70
|
+
if (line.trim()) {
|
|
71
|
+
try {
|
|
72
|
+
const response = JSON.parse(line);
|
|
73
|
+
logDebug(`← ${line}`);
|
|
74
|
+
|
|
75
|
+
// Check if this is the response to our request
|
|
76
|
+
if (response.id === request.id) {
|
|
77
|
+
resolved = true;
|
|
78
|
+
server.stdout.off('data', onData);
|
|
79
|
+
resolve(response);
|
|
80
|
+
}
|
|
81
|
+
} catch (e) {
|
|
82
|
+
// Not valid JSON, continue accumulating
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
server.stdout.on('data', onData);
|
|
89
|
+
|
|
90
|
+
// Timeout after 5 seconds
|
|
91
|
+
setTimeout(() => {
|
|
92
|
+
if (!resolved) {
|
|
93
|
+
server.stdout.off('data', onData);
|
|
94
|
+
reject(new Error('Request timeout'));
|
|
95
|
+
}
|
|
96
|
+
}, 5000);
|
|
97
|
+
|
|
98
|
+
server.stdin.write(requestStr);
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Test the roots/list endpoint
|
|
104
|
+
*/
|
|
105
|
+
async function testRootsList(server) {
|
|
106
|
+
log('\n--- Testing roots/list ---', colors.yellow);
|
|
107
|
+
|
|
108
|
+
const request = {
|
|
109
|
+
jsonrpc: '2.0',
|
|
110
|
+
id: 2,
|
|
111
|
+
method: 'roots/list',
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
try {
|
|
115
|
+
const response = await sendRequest(server, request);
|
|
116
|
+
|
|
117
|
+
if (response.error) {
|
|
118
|
+
logError(`Server returned error: ${JSON.stringify(response.error)}`);
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (!response.result) {
|
|
123
|
+
logError('Response missing result field');
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const { roots } = response.result;
|
|
128
|
+
|
|
129
|
+
if (!Array.isArray(roots)) {
|
|
130
|
+
logError('roots field is not an array');
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
logSuccess('roots/list returned valid response');
|
|
135
|
+
logInfo(`Found ${roots.length} root(s)`);
|
|
136
|
+
|
|
137
|
+
if (roots.length === 0) {
|
|
138
|
+
log(' No roots configured (this is valid if REPOSITORY_GIT_REMOTE_URL is not set)', colors.yellow);
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Validate each root
|
|
143
|
+
let allValid = true;
|
|
144
|
+
for (const [index, root] of roots.entries()) {
|
|
145
|
+
logInfo(`Root ${index + 1}:`);
|
|
146
|
+
|
|
147
|
+
if (!root.uri) {
|
|
148
|
+
logError(` Missing uri field`);
|
|
149
|
+
allValid = false;
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
logSuccess(` uri: ${root.uri}`);
|
|
154
|
+
|
|
155
|
+
if (root.name) {
|
|
156
|
+
logInfo(` name: ${root.name}`);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Validate URI format (should start with embark:// for this server)
|
|
160
|
+
if (!root.uri.startsWith('embark://')) {
|
|
161
|
+
log(` Warning: URI doesn't start with embark:// (got: ${root.uri})`, colors.yellow);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return allValid;
|
|
166
|
+
} catch (error) {
|
|
167
|
+
logError(`Failed to test roots/list: ${error.message}`);
|
|
168
|
+
return false;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Test server initialization
|
|
174
|
+
*/
|
|
175
|
+
async function testInitialize(server) {
|
|
176
|
+
log('\n--- Testing initialization ---', colors.yellow);
|
|
177
|
+
|
|
178
|
+
const request = {
|
|
179
|
+
jsonrpc: '2.0',
|
|
180
|
+
id: 1,
|
|
181
|
+
method: 'initialize',
|
|
182
|
+
params: {
|
|
183
|
+
protocolVersion: '2024-11-05',
|
|
184
|
+
capabilities: {
|
|
185
|
+
roots: {
|
|
186
|
+
listChanged: true,
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
clientInfo: {
|
|
190
|
+
name: 'test-client',
|
|
191
|
+
version: '1.0.0',
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
try {
|
|
197
|
+
const response = await sendRequest(server, request);
|
|
198
|
+
|
|
199
|
+
if (response.error) {
|
|
200
|
+
logError(`Initialization error: ${JSON.stringify(response.error)}`);
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (!response.result) {
|
|
205
|
+
logError('Initialization response missing result');
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
logSuccess('Server initialized successfully');
|
|
210
|
+
|
|
211
|
+
// Check if server advertises roots capability
|
|
212
|
+
if (response.result.capabilities?.roots) {
|
|
213
|
+
logSuccess('Server advertises roots capability');
|
|
214
|
+
logDebug(` ${JSON.stringify(response.result.capabilities.roots)}`);
|
|
215
|
+
} else {
|
|
216
|
+
logError('Server does not advertise roots capability');
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return true;
|
|
221
|
+
} catch (error) {
|
|
222
|
+
logError(`Failed to initialize: ${error.message}`);
|
|
223
|
+
return false;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Main test runner
|
|
229
|
+
*/
|
|
230
|
+
async function runTests() {
|
|
231
|
+
log('='.repeat(60), colors.blue);
|
|
232
|
+
log('MCP Server Roots Testing', colors.blue);
|
|
233
|
+
log('='.repeat(60), colors.blue);
|
|
234
|
+
|
|
235
|
+
logInfo(`Server path: ${SERVER_PATH}`);
|
|
236
|
+
logInfo(`Test repository: ${REPOSITORY_URL}`);
|
|
237
|
+
|
|
238
|
+
// Spawn the server
|
|
239
|
+
log('\n--- Starting MCP server ---', colors.yellow);
|
|
240
|
+
const server = spawn('node', [SERVER_PATH], {
|
|
241
|
+
env: {
|
|
242
|
+
...process.env,
|
|
243
|
+
REPOSITORY_GIT_REMOTE_URL: REPOSITORY_URL,
|
|
244
|
+
},
|
|
245
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
// Log stderr for debugging
|
|
249
|
+
server.stderr.on('data', (data) => {
|
|
250
|
+
logDebug(`[stderr] ${data.toString().trim()}`);
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
server.on('error', (error) => {
|
|
254
|
+
logError(`Failed to start server: ${error.message}`);
|
|
255
|
+
process.exit(1);
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
// Wait a bit for server to start
|
|
259
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
260
|
+
|
|
261
|
+
let allTestsPassed = true;
|
|
262
|
+
|
|
263
|
+
try {
|
|
264
|
+
// Test 1: Initialize
|
|
265
|
+
const initSuccess = await testInitialize(server);
|
|
266
|
+
if (!initSuccess) {
|
|
267
|
+
allTestsPassed = false;
|
|
268
|
+
log('\n❌ Initialization test failed', colors.red);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Test 2: Roots list
|
|
272
|
+
if (initSuccess) {
|
|
273
|
+
const rootsSuccess = await testRootsList(server);
|
|
274
|
+
if (!rootsSuccess) {
|
|
275
|
+
allTestsPassed = false;
|
|
276
|
+
log('\n❌ Roots test failed', colors.red);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// Summary
|
|
281
|
+
log('\n' + '='.repeat(60), colors.blue);
|
|
282
|
+
if (allTestsPassed) {
|
|
283
|
+
log('✓ All tests passed!', colors.green);
|
|
284
|
+
log('='.repeat(60), colors.blue);
|
|
285
|
+
server.kill();
|
|
286
|
+
process.exit(0);
|
|
287
|
+
} else {
|
|
288
|
+
log('✗ Some tests failed', colors.red);
|
|
289
|
+
log('='.repeat(60), colors.blue);
|
|
290
|
+
server.kill();
|
|
291
|
+
process.exit(1);
|
|
292
|
+
}
|
|
293
|
+
} catch (error) {
|
|
294
|
+
logError(`Test execution failed: ${error.message}`);
|
|
295
|
+
console.error(error);
|
|
296
|
+
server.kill();
|
|
297
|
+
process.exit(1);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// Run tests
|
|
302
|
+
runTests().catch((error) => {
|
|
303
|
+
logError(`Fatal error: ${error.message}`);
|
|
304
|
+
console.error(error);
|
|
305
|
+
process.exit(1);
|
|
306
|
+
});
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Test script for snippet extraction functionality
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { fileURLToPath } from 'url';
|
|
8
|
+
import { dirname, join } from 'path';
|
|
9
|
+
import { extractSnippetFromGit } from './dist/git-utils.js';
|
|
10
|
+
|
|
11
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
12
|
+
const __dirname = dirname(__filename);
|
|
13
|
+
|
|
14
|
+
// Colors for terminal output
|
|
15
|
+
const colors = {
|
|
16
|
+
reset: '\x1b[0m',
|
|
17
|
+
green: '\x1b[32m',
|
|
18
|
+
red: '\x1b[31m',
|
|
19
|
+
yellow: '\x1b[33m',
|
|
20
|
+
blue: '\x1b[34m',
|
|
21
|
+
gray: '\x1b[90m',
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
function log(message, color = colors.reset) {
|
|
25
|
+
console.log(`${color}${message}${colors.reset}`);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function logSuccess(message) {
|
|
29
|
+
log(`✓ ${message}`, colors.green);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function logError(message) {
|
|
33
|
+
log(`✗ ${message}`, colors.red);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function logInfo(message) {
|
|
37
|
+
log(`ℹ ${message}`, colors.blue);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Test snippet extraction from this repository
|
|
42
|
+
*/
|
|
43
|
+
async function testSnippetExtraction() {
|
|
44
|
+
log('='.repeat(60), colors.blue);
|
|
45
|
+
log('Testing Snippet Extraction', colors.blue);
|
|
46
|
+
log('='.repeat(60), colors.blue);
|
|
47
|
+
|
|
48
|
+
const repoPath = __dirname;
|
|
49
|
+
const testCases = [
|
|
50
|
+
{
|
|
51
|
+
name: 'Extract from git-utils.ts',
|
|
52
|
+
relativePath: 'src/git-utils.ts',
|
|
53
|
+
revision: 'HEAD',
|
|
54
|
+
// Extract a reasonable portion from the middle of the file
|
|
55
|
+
startOffset: 1500,
|
|
56
|
+
endOffset: 1700,
|
|
57
|
+
description: 'Extract 200 bytes from git-utils.ts'
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
name: 'Extract from package.json',
|
|
61
|
+
relativePath: 'package.json',
|
|
62
|
+
revision: null, // Will use HEAD
|
|
63
|
+
startOffset: 0,
|
|
64
|
+
endOffset: 100,
|
|
65
|
+
description: 'Extract first 100 bytes of package.json'
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
name: 'Extract beginning of git-utils.ts',
|
|
69
|
+
relativePath: 'src/git-utils.ts',
|
|
70
|
+
revision: 'HEAD',
|
|
71
|
+
startOffset: 0,
|
|
72
|
+
endOffset: 150,
|
|
73
|
+
description: 'Extract file header'
|
|
74
|
+
}
|
|
75
|
+
];
|
|
76
|
+
|
|
77
|
+
let allTestsPassed = true;
|
|
78
|
+
|
|
79
|
+
for (const testCase of testCases) {
|
|
80
|
+
log(`\n--- ${testCase.name} ---`, colors.yellow);
|
|
81
|
+
logInfo(testCase.description);
|
|
82
|
+
logInfo(`File: ${testCase.relativePath}`);
|
|
83
|
+
logInfo(`Offsets: ${testCase.startOffset}-${testCase.endOffset}`);
|
|
84
|
+
logInfo(`Revision: ${testCase.revision || 'HEAD'}`);
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
const snippet = extractSnippetFromGit(
|
|
88
|
+
repoPath,
|
|
89
|
+
testCase.relativePath,
|
|
90
|
+
testCase.revision,
|
|
91
|
+
testCase.startOffset,
|
|
92
|
+
testCase.endOffset
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
if (snippet === null) {
|
|
96
|
+
logError('Failed to extract snippet (returned null)');
|
|
97
|
+
allTestsPassed = false;
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (snippet.length === 0) {
|
|
102
|
+
logError('Extracted snippet is empty');
|
|
103
|
+
allTestsPassed = false;
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
logSuccess(`Successfully extracted ${snippet.length} bytes`);
|
|
108
|
+
log('\nSnippet preview:', colors.gray);
|
|
109
|
+
log('---', colors.gray);
|
|
110
|
+
log(snippet.slice(0, 200) + (snippet.length > 200 ? '...' : ''), colors.gray);
|
|
111
|
+
log('---', colors.gray);
|
|
112
|
+
} catch (error) {
|
|
113
|
+
logError(`Test failed with error: ${error.message}`);
|
|
114
|
+
allTestsPassed = false;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Summary
|
|
119
|
+
log('\n' + '='.repeat(60), colors.blue);
|
|
120
|
+
if (allTestsPassed) {
|
|
121
|
+
log('✓ All tests passed!', colors.green);
|
|
122
|
+
log('='.repeat(60), colors.blue);
|
|
123
|
+
process.exit(0);
|
|
124
|
+
} else {
|
|
125
|
+
log('✗ Some tests failed', colors.red);
|
|
126
|
+
log('='.repeat(60), colors.blue);
|
|
127
|
+
process.exit(1);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Run tests
|
|
132
|
+
testSnippetExtraction().catch((error) => {
|
|
133
|
+
logError(`Fatal error: ${error.message}`);
|
|
134
|
+
console.error(error);
|
|
135
|
+
process.exit(1);
|
|
136
|
+
});
|
package/watch-logs.sh
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# Watch logs script for Embark MCP Server
|
|
4
|
+
# This script helps you monitor the server logs in real-time during Claude Code integration testing
|
|
5
|
+
|
|
6
|
+
LOG_FILE="$HOME/.embark/debug.log"
|
|
7
|
+
|
|
8
|
+
# Colors
|
|
9
|
+
GREEN='\033[0;32m'
|
|
10
|
+
BLUE='\033[0;34m'
|
|
11
|
+
YELLOW='\033[1;33m'
|
|
12
|
+
RED='\033[0;31m'
|
|
13
|
+
NC='\033[0m' # No Color
|
|
14
|
+
|
|
15
|
+
echo -e "${BLUE}============================================================${NC}"
|
|
16
|
+
echo -e "${BLUE}Embark MCP Server Log Watcher${NC}"
|
|
17
|
+
echo -e "${BLUE}============================================================${NC}"
|
|
18
|
+
echo ""
|
|
19
|
+
echo -e "${YELLOW}Log file:${NC} $LOG_FILE"
|
|
20
|
+
echo ""
|
|
21
|
+
|
|
22
|
+
# Check if log file exists
|
|
23
|
+
if [ ! -f "$LOG_FILE" ]; then
|
|
24
|
+
echo -e "${RED}⚠ Log file does not exist yet.${NC}"
|
|
25
|
+
echo -e "${YELLOW}ℹ Make sure ENABLE_LOCAL_LOGS=true is set in your .mcp.json${NC}"
|
|
26
|
+
echo ""
|
|
27
|
+
echo -e "Example .mcp.json configuration:"
|
|
28
|
+
echo -e "${BLUE}"
|
|
29
|
+
cat << 'EOF'
|
|
30
|
+
{
|
|
31
|
+
"mcpServers": {
|
|
32
|
+
"embark-mcp": {
|
|
33
|
+
"command": "node",
|
|
34
|
+
"args": ["/path/to/embark-remote-mcp/dist/index.js"],
|
|
35
|
+
"env": {
|
|
36
|
+
"REPOSITORY_GIT_REMOTE_URL": "https://github.com/your-org/your-repo.git",
|
|
37
|
+
"ENABLE_LOCAL_LOGS": "true"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
EOF
|
|
43
|
+
echo -e "${NC}"
|
|
44
|
+
echo ""
|
|
45
|
+
echo -e "Waiting for log file to be created..."
|
|
46
|
+
echo -e "${YELLOW}(Restart Claude Code to create the log file)${NC}"
|
|
47
|
+
echo ""
|
|
48
|
+
|
|
49
|
+
# Wait for file to be created
|
|
50
|
+
while [ ! -f "$LOG_FILE" ]; do
|
|
51
|
+
sleep 1
|
|
52
|
+
done
|
|
53
|
+
|
|
54
|
+
echo -e "${GREEN}✓ Log file created!${NC}"
|
|
55
|
+
echo ""
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
echo -e "${GREEN}✓ Watching logs...${NC}"
|
|
59
|
+
echo -e "${YELLOW}ℹ Press Ctrl+C to stop${NC}"
|
|
60
|
+
echo ""
|
|
61
|
+
echo -e "${BLUE}------------------------------------------------------------${NC}"
|
|
62
|
+
echo ""
|
|
63
|
+
|
|
64
|
+
# Filter and colorize logs
|
|
65
|
+
tail -f "$LOG_FILE" | while IFS= read -r line; do
|
|
66
|
+
# Check for specific patterns and colorize
|
|
67
|
+
if echo "$line" | grep -q "ListRoots"; then
|
|
68
|
+
echo -e "${GREEN}$line${NC}"
|
|
69
|
+
elif echo "$line" | grep -q '"level": "error"'; then
|
|
70
|
+
echo -e "${RED}$line${NC}"
|
|
71
|
+
elif echo "$line" | grep -q '"level": "warn"'; then
|
|
72
|
+
echo -e "${YELLOW}$line${NC}"
|
|
73
|
+
elif echo "$line" | grep -q "root"; then
|
|
74
|
+
echo -e "${BLUE}$line${NC}"
|
|
75
|
+
else
|
|
76
|
+
echo "$line"
|
|
77
|
+
fi
|
|
78
|
+
done
|