@deriv-com/fe-mcp-servers 0.0.8 ā 0.0.10
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 +60 -56
- package/bin/fe-mcp.js +424 -0
- package/dist/shift-ai/README.md +124 -77
- package/dist/shift-ai/mcp-server.js +16185 -3065
- package/package.json +7 -3
package/README.md
CHANGED
|
@@ -4,6 +4,7 @@ A collection of Front-End Model Context Protocol (MCP) servers for reusability a
|
|
|
4
4
|
|
|
5
5
|
## šļø Project Structure
|
|
6
6
|
|
|
7
|
+
### Source Structure (Development)
|
|
7
8
|
```
|
|
8
9
|
mcps/
|
|
9
10
|
āāā shift-ai/ # Individual MCP server
|
|
@@ -30,14 +31,43 @@ mcps/
|
|
|
30
31
|
npm install -g @deriv-com/fe-mcp-servers
|
|
31
32
|
```
|
|
32
33
|
|
|
33
|
-
###
|
|
34
|
-
|
|
34
|
+
### CLI Commands
|
|
35
|
+
|
|
36
|
+
After installation, use the `fe-mcp` CLI to manage MCP servers:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
# List all available MCP servers
|
|
40
|
+
fe-mcp list
|
|
41
|
+
|
|
42
|
+
# Interactive config generator - creates file & opens it for copy-paste
|
|
43
|
+
fe-mcp code
|
|
44
|
+
|
|
45
|
+
# Show detailed info about a specific server
|
|
46
|
+
fe-mcp info shift-ai
|
|
47
|
+
|
|
48
|
+
# Output MCP client configuration JSON
|
|
49
|
+
fe-mcp config shift-ai
|
|
50
|
+
|
|
51
|
+
# Show help
|
|
52
|
+
fe-mcp help
|
|
53
|
+
|
|
54
|
+
# Show version
|
|
55
|
+
fe-mcp --version
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Quick Setup (Recommended)
|
|
59
|
+
|
|
60
|
+
The easiest way to get your MCP config:
|
|
35
61
|
|
|
36
62
|
```bash
|
|
37
|
-
|
|
63
|
+
fe-mcp code
|
|
38
64
|
```
|
|
39
65
|
|
|
40
|
-
|
|
66
|
+
This will:
|
|
67
|
+
1. Show you a list of available MCP servers
|
|
68
|
+
2. Ask you to select one
|
|
69
|
+
3. Generate the configuration JSON with the correct path
|
|
70
|
+
4. Save it to a file and auto-open it for easy copy-paste
|
|
41
71
|
|
|
42
72
|
### MCP Configuration Template
|
|
43
73
|
```json
|
|
@@ -45,7 +75,7 @@ Replace `SERVER_NAME` with the specific server you want (e.g., `shift-ai`).
|
|
|
45
75
|
"mcpServers": {
|
|
46
76
|
"server-name": {
|
|
47
77
|
"command": "node",
|
|
48
|
-
"args": ["<
|
|
78
|
+
"args": ["<PATH_FROM_FE-MCP>"]
|
|
49
79
|
}
|
|
50
80
|
}
|
|
51
81
|
}
|
|
@@ -66,11 +96,14 @@ Replace `SERVER_NAME` with the specific server you want (e.g., `shift-ai`).
|
|
|
66
96
|
## š ļø Development
|
|
67
97
|
|
|
68
98
|
### Building the Package
|
|
99
|
+
The build process bundles all dependencies into standalone executables:
|
|
69
100
|
```bash
|
|
70
101
|
cd mcps
|
|
71
102
|
npm run build
|
|
72
103
|
```
|
|
73
104
|
|
|
105
|
+
This creates bundled files in `dist/` with all dependencies included.
|
|
106
|
+
|
|
74
107
|
### Running Tests
|
|
75
108
|
```bash
|
|
76
109
|
npm run test
|
|
@@ -79,64 +112,35 @@ npm run test
|
|
|
79
112
|
### Adding New MCP Servers
|
|
80
113
|
|
|
81
114
|
1. Create a new directory in `mcps/`
|
|
82
|
-
2. Add the required structure
|
|
115
|
+
2. Add the required **source structure**:
|
|
83
116
|
```
|
|
84
117
|
your-server/
|
|
85
118
|
āāā src/
|
|
86
|
-
ā āāā mcp-server.js
|
|
87
|
-
ā
|
|
88
|
-
|
|
89
|
-
āāā README.md # Required: Documentation
|
|
119
|
+
ā āāā mcp-server.js # Main server implementation (entry point)
|
|
120
|
+
ā āāā mcp.js # Core functionality
|
|
121
|
+
āāā README.md # Server documentation
|
|
90
122
|
```
|
|
91
|
-
3.
|
|
92
|
-
4. The build
|
|
123
|
+
3. Implement your MCP server logic in the `src/` files
|
|
124
|
+
4. The build process will automatically bundle everything into `dist/your-server/mcp-server.js`
|
|
125
|
+
5. Users will reference the **bundled file** (not the source) in their MCP configuration
|
|
93
126
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
### š shift-ai
|
|
97
|
-
AI code generation and analysis server that provides intelligent code suggestions, analysis, and automated code generation capabilities.
|
|
98
|
-
|
|
99
|
-
**Status**: ā
Active
|
|
100
|
-
**Location**: `shift-ai/`
|
|
101
|
-
|
|
102
|
-
### š github-mcp
|
|
103
|
-
GitHub integration server for repository management, issue tracking, and pull request automation.
|
|
104
|
-
|
|
105
|
-
**Status**: š§ Planned
|
|
106
|
-
**Location**: `github-mcp/`
|
|
107
|
-
|
|
108
|
-
### š¬ slack-mcp
|
|
109
|
-
Slack workspace automation server for communication workflows and bot integrations.
|
|
110
|
-
|
|
111
|
-
**Status**: š§ Planned
|
|
112
|
-
**Location**: `slack-mcp/`
|
|
113
|
-
|
|
114
|
-
### šļø database-mcp
|
|
115
|
-
Database query and schema management server supporting multiple database systems.
|
|
116
|
-
|
|
117
|
-
**Status**: š§ Planned
|
|
118
|
-
**Location**: `database-mcp/`
|
|
119
|
-
|
|
120
|
-
## š¦ Distribution
|
|
121
|
-
|
|
122
|
-
This package is published to npm as part of the @deriv/ai-tools collection with all dependencies bundled for easy installation and usage.
|
|
123
|
-
|
|
124
|
-
## š§ Standards
|
|
127
|
+
### Requirements for New Servers
|
|
125
128
|
|
|
126
129
|
Each MCP server must:
|
|
127
|
-
- Have `src/mcp-server.js` as the main entry point
|
|
128
|
-
-
|
|
129
|
-
- Include comprehensive
|
|
130
|
-
-
|
|
131
|
-
- Include test coverage where applicable
|
|
130
|
+
- Have `src/mcp-server.js` as the main entry point (source file)
|
|
131
|
+
- Follow the MCP protocol specification
|
|
132
|
+
- Include comprehensive documentation in README.md
|
|
133
|
+
- The build process will bundle everything into a single executable `dist/server-name/mcp-server.js` file
|
|
132
134
|
|
|
133
135
|
## šļø Architecture
|
|
134
136
|
|
|
135
|
-
|
|
136
|
-
- **
|
|
137
|
-
- **
|
|
138
|
-
- **
|
|
139
|
-
- **
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
-
|
|
137
|
+
### Build Process
|
|
138
|
+
- **Input**: Source files in `src/` directories
|
|
139
|
+
- **Process**: esbuild bundles all dependencies
|
|
140
|
+
- **Output**: Single executable files in `dist/` directories
|
|
141
|
+
- **Distribution**: npm package contains only the `dist/` directory
|
|
142
|
+
|
|
143
|
+
### Dependency Management
|
|
144
|
+
- All dependencies are bundled into the final executable
|
|
145
|
+
- No external dependency resolution required at runtime
|
|
146
|
+
- Standalone files that work in any Node.js environment
|
package/bin/fe-mcp.js
ADDED
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
import { execSync, spawn } from 'child_process';
|
|
7
|
+
import readline from 'readline';
|
|
8
|
+
import os from 'os';
|
|
9
|
+
|
|
10
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
const packageRoot = path.join(__dirname, '..');
|
|
12
|
+
const distDir = path.join(packageRoot, 'dist');
|
|
13
|
+
const srcDir = packageRoot;
|
|
14
|
+
|
|
15
|
+
// Read package.json for version
|
|
16
|
+
const packageJson = JSON.parse(fs.readFileSync(path.join(packageRoot, 'package.json'), 'utf-8'));
|
|
17
|
+
|
|
18
|
+
// ANSI colors
|
|
19
|
+
const colors = {
|
|
20
|
+
reset: '\x1b[0m',
|
|
21
|
+
bright: '\x1b[1m',
|
|
22
|
+
dim: '\x1b[2m',
|
|
23
|
+
cyan: '\x1b[36m',
|
|
24
|
+
green: '\x1b[32m',
|
|
25
|
+
yellow: '\x1b[33m',
|
|
26
|
+
blue: '\x1b[34m',
|
|
27
|
+
magenta: '\x1b[35m',
|
|
28
|
+
red: '\x1b[31m',
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const c = (color, text) => `${colors[color]}${text}${colors.reset}`;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Get all available MCP servers
|
|
35
|
+
*/
|
|
36
|
+
function getMcpServers() {
|
|
37
|
+
const servers = [];
|
|
38
|
+
|
|
39
|
+
// Check dist directory for built servers
|
|
40
|
+
if (fs.existsSync(distDir)) {
|
|
41
|
+
const entries = fs.readdirSync(distDir, { withFileTypes: true });
|
|
42
|
+
for (const entry of entries) {
|
|
43
|
+
if (entry.isDirectory()) {
|
|
44
|
+
const mcpServerPath = path.join(distDir, entry.name, 'mcp-server.js');
|
|
45
|
+
const readmePath = path.join(distDir, entry.name, 'README.md');
|
|
46
|
+
|
|
47
|
+
if (fs.existsSync(mcpServerPath)) {
|
|
48
|
+
const server = {
|
|
49
|
+
name: entry.name,
|
|
50
|
+
path: mcpServerPath,
|
|
51
|
+
hasReadme: fs.existsSync(readmePath),
|
|
52
|
+
readmePath: readmePath,
|
|
53
|
+
built: true,
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// Try to extract description from README
|
|
57
|
+
if (server.hasReadme) {
|
|
58
|
+
const readme = fs.readFileSync(readmePath, 'utf-8');
|
|
59
|
+
const descMatch = readme.match(/^#[^\n]+\n+([^\n#]+)/);
|
|
60
|
+
if (descMatch) {
|
|
61
|
+
server.description = descMatch[1].trim();
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
servers.push(server);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Also check source directories for unbuilt servers
|
|
72
|
+
const srcEntries = fs.readdirSync(srcDir, { withFileTypes: true });
|
|
73
|
+
for (const entry of srcEntries) {
|
|
74
|
+
if (entry.isDirectory() &&
|
|
75
|
+
!['dist', 'bin', 'node_modules', 'scripts'].includes(entry.name) &&
|
|
76
|
+
!entry.name.startsWith('.')) {
|
|
77
|
+
const srcMcpPath = path.join(srcDir, entry.name, 'src', 'mcp-server.js');
|
|
78
|
+
|
|
79
|
+
if (fs.existsSync(srcMcpPath)) {
|
|
80
|
+
// Check if already in servers list (built version)
|
|
81
|
+
const existing = servers.find(s => s.name === entry.name);
|
|
82
|
+
if (!existing) {
|
|
83
|
+
const readmePath = path.join(srcDir, entry.name, 'README.md');
|
|
84
|
+
const server = {
|
|
85
|
+
name: entry.name,
|
|
86
|
+
path: srcMcpPath,
|
|
87
|
+
hasReadme: fs.existsSync(readmePath),
|
|
88
|
+
readmePath: readmePath,
|
|
89
|
+
built: false,
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
if (server.hasReadme) {
|
|
93
|
+
const readme = fs.readFileSync(readmePath, 'utf-8');
|
|
94
|
+
const descMatch = readme.match(/^#[^\n]+\n+([^\n#]+)/);
|
|
95
|
+
if (descMatch) {
|
|
96
|
+
server.description = descMatch[1].trim();
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
servers.push(server);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return servers;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* List all available MCP servers
|
|
111
|
+
*/
|
|
112
|
+
function listServers() {
|
|
113
|
+
const servers = getMcpServers();
|
|
114
|
+
|
|
115
|
+
if (servers.length === 0) {
|
|
116
|
+
console.log(c('yellow', '\nā ļø No MCP servers found.'));
|
|
117
|
+
console.log(c('dim', ' Run "npm run build" to build the servers first.\n'));
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
console.log(c('bright', '\nš¦ Available MCP Servers\n'));
|
|
122
|
+
console.log(c('dim', 'ā'.repeat(60)));
|
|
123
|
+
|
|
124
|
+
for (const server of servers) {
|
|
125
|
+
const status = server.built
|
|
126
|
+
? c('green', 'ā built')
|
|
127
|
+
: c('yellow', 'ā source only');
|
|
128
|
+
|
|
129
|
+
console.log(`\n ${c('cyan', server.name)} ${c('dim', `(${status})`)}`);
|
|
130
|
+
|
|
131
|
+
if (server.description) {
|
|
132
|
+
console.log(` ${c('dim', server.description)}`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
console.log(c('dim', '\nā'.repeat(60)));
|
|
137
|
+
console.log(c('dim', `\nTotal: ${servers.length} server(s)`));
|
|
138
|
+
console.log(c('dim', `\nUse "${c('cyan', 'fe-mcp info <name>')}" for details`));
|
|
139
|
+
console.log(c('dim', `Use "${c('cyan', 'fe-mcp path <name>')}" to get the executable path\n`));
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Show detailed info about a specific MCP server
|
|
144
|
+
*/
|
|
145
|
+
function showInfo(serverName) {
|
|
146
|
+
const servers = getMcpServers();
|
|
147
|
+
const server = servers.find(s => s.name === serverName);
|
|
148
|
+
|
|
149
|
+
if (!server) {
|
|
150
|
+
console.log(c('red', `\nā MCP server "${serverName}" not found.\n`));
|
|
151
|
+
console.log(c('dim', 'Available servers:'));
|
|
152
|
+
servers.forEach(s => console.log(c('dim', ` - ${s.name}`)));
|
|
153
|
+
console.log();
|
|
154
|
+
process.exit(1);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
console.log(c('bright', `\nš¦ ${server.name}\n`));
|
|
158
|
+
console.log(c('dim', 'ā'.repeat(60)));
|
|
159
|
+
|
|
160
|
+
if (server.description) {
|
|
161
|
+
console.log(`\n${c('bright', 'Description:')}`);
|
|
162
|
+
console.log(` ${server.description}`);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
console.log(`\n${c('bright', 'Status:')} ${server.built ? c('green', 'Built ā') : c('yellow', 'Not built')}`);
|
|
166
|
+
console.log(`${c('bright', 'Path:')} ${server.path}`);
|
|
167
|
+
|
|
168
|
+
if (server.built) {
|
|
169
|
+
console.log(`\n${c('bright', 'MCP Configuration:')}`);
|
|
170
|
+
console.log(c('dim', ' Add this to your MCP client config:\n'));
|
|
171
|
+
|
|
172
|
+
const config = {
|
|
173
|
+
[server.name]: {
|
|
174
|
+
command: 'node',
|
|
175
|
+
args: [server.path]
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
console.log(c('cyan', JSON.stringify({ mcpServers: config }, null, 2)));
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (server.hasReadme) {
|
|
183
|
+
console.log(`\n${c('bright', 'Documentation:')} ${server.readmePath}`);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
console.log(c('dim', '\nā'.repeat(60) + '\n'));
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Show help
|
|
191
|
+
*/
|
|
192
|
+
function showHelp() {
|
|
193
|
+
console.log(`
|
|
194
|
+
${c('bright', '@deriv-com/fe-mcp-servers CLI')}
|
|
195
|
+
|
|
196
|
+
${c('bright', 'Usage:')}
|
|
197
|
+
fe-mcp <command> [options]
|
|
198
|
+
|
|
199
|
+
${c('bright', 'Commands:')}
|
|
200
|
+
${c('cyan', 'list')} List all available MCP servers
|
|
201
|
+
${c('cyan', 'code')} Interactive config generator (creates file & opens it)
|
|
202
|
+
${c('cyan', 'info <name>')} Show detailed info about a specific server
|
|
203
|
+
${c('cyan', 'config <name>')} Output MCP client configuration JSON
|
|
204
|
+
${c('cyan', 'help')} Show this help message
|
|
205
|
+
${c('cyan', '-v, --version')} Show version number
|
|
206
|
+
|
|
207
|
+
${c('bright', 'Examples:')}
|
|
208
|
+
fe-mcp list
|
|
209
|
+
fe-mcp code
|
|
210
|
+
fe-mcp info shift-ai
|
|
211
|
+
fe-mcp config shift-ai
|
|
212
|
+
|
|
213
|
+
${c('bright', 'Global Installation:')}
|
|
214
|
+
npm install -g @deriv-com/fe-mcp-servers
|
|
215
|
+
fe-mcp list
|
|
216
|
+
`);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Output MCP config JSON for a server
|
|
221
|
+
*/
|
|
222
|
+
function outputConfig(serverName) {
|
|
223
|
+
const servers = getMcpServers();
|
|
224
|
+
const server = servers.find(s => s.name === serverName);
|
|
225
|
+
|
|
226
|
+
if (!server) {
|
|
227
|
+
console.error(c('red', `MCP server "${serverName}" not found.`));
|
|
228
|
+
process.exit(1);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (!server.built) {
|
|
232
|
+
console.error(c('red', `MCP server "${serverName}" is not built yet.`));
|
|
233
|
+
console.error(c('dim', 'Run "npm run build" first.'));
|
|
234
|
+
process.exit(1);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const config = {
|
|
238
|
+
[server.name]: {
|
|
239
|
+
command: 'node',
|
|
240
|
+
args: [server.path]
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
console.log(JSON.stringify(config, null, 2));
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Get global npm root path
|
|
249
|
+
*/
|
|
250
|
+
function getGlobalNpmRoot() {
|
|
251
|
+
try {
|
|
252
|
+
return execSync('npm root -g', { encoding: 'utf-8' }).trim();
|
|
253
|
+
} catch (error) {
|
|
254
|
+
return null;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Open a file with the default application
|
|
260
|
+
*/
|
|
261
|
+
function openFile(filePath) {
|
|
262
|
+
const platform = os.platform();
|
|
263
|
+
let command;
|
|
264
|
+
|
|
265
|
+
if (platform === 'darwin') {
|
|
266
|
+
command = 'open';
|
|
267
|
+
} else if (platform === 'win32') {
|
|
268
|
+
command = 'start';
|
|
269
|
+
} else {
|
|
270
|
+
command = 'xdg-open';
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
try {
|
|
274
|
+
spawn(command, [filePath], { detached: true, stdio: 'ignore' }).unref();
|
|
275
|
+
} catch (error) {
|
|
276
|
+
console.log(c('yellow', `\nā ļø Could not auto-open file. Please open manually:`));
|
|
277
|
+
console.log(c('cyan', ` ${filePath}\n`));
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Prompt user to select from a list
|
|
283
|
+
*/
|
|
284
|
+
function promptSelect(question, options) {
|
|
285
|
+
return new Promise((resolve) => {
|
|
286
|
+
const rl = readline.createInterface({
|
|
287
|
+
input: process.stdin,
|
|
288
|
+
output: process.stdout
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
console.log(c('bright', `\n${question}\n`));
|
|
292
|
+
|
|
293
|
+
options.forEach((opt, i) => {
|
|
294
|
+
console.log(` ${c('cyan', `[${i + 1}]`)} ${opt.name}${opt.description ? c('dim', ` - ${opt.description.substring(0, 50)}...`) : ''}`);
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
console.log();
|
|
298
|
+
|
|
299
|
+
rl.question(c('bright', 'Enter number: '), (answer) => {
|
|
300
|
+
rl.close();
|
|
301
|
+
const index = parseInt(answer, 10) - 1;
|
|
302
|
+
if (index >= 0 && index < options.length) {
|
|
303
|
+
resolve(options[index]);
|
|
304
|
+
} else {
|
|
305
|
+
console.log(c('red', '\nā Invalid selection.\n'));
|
|
306
|
+
process.exit(1);
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Generate MCP config file and open it
|
|
314
|
+
*/
|
|
315
|
+
async function generateConfigFile() {
|
|
316
|
+
const servers = getMcpServers().filter(s => s.built);
|
|
317
|
+
|
|
318
|
+
if (servers.length === 0) {
|
|
319
|
+
console.log(c('yellow', '\nā ļø No built MCP servers found.'));
|
|
320
|
+
console.log(c('dim', ' Run "npm run build" to build the servers first.\n'));
|
|
321
|
+
process.exit(1);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
console.log(c('bright', '\nš§ MCP Configuration Generator\n'));
|
|
325
|
+
console.log(c('dim', 'ā'.repeat(50)));
|
|
326
|
+
|
|
327
|
+
// Let user select a server
|
|
328
|
+
const selected = await promptSelect('Select an MCP server:', servers);
|
|
329
|
+
|
|
330
|
+
// Get the global npm path
|
|
331
|
+
const globalRoot = getGlobalNpmRoot();
|
|
332
|
+
let serverPath;
|
|
333
|
+
|
|
334
|
+
if (globalRoot) {
|
|
335
|
+
// Use global path for installed package
|
|
336
|
+
serverPath = `${globalRoot}/@deriv-com/fe-mcp-servers/dist/${selected.name}/mcp-server.js`;
|
|
337
|
+
} else {
|
|
338
|
+
// Fallback to local path
|
|
339
|
+
serverPath = selected.path;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Generate config
|
|
343
|
+
const config = {
|
|
344
|
+
mcpServers: {
|
|
345
|
+
[selected.name]: {
|
|
346
|
+
command: 'node',
|
|
347
|
+
args: [serverPath]
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
const configJson = JSON.stringify(config, null, 2);
|
|
353
|
+
|
|
354
|
+
// Create temp file
|
|
355
|
+
const tempDir = os.tmpdir();
|
|
356
|
+
const fileName = 'fe-mcp-config.txt';
|
|
357
|
+
const filePath = path.join(tempDir, fileName);
|
|
358
|
+
|
|
359
|
+
// Write config to file
|
|
360
|
+
fs.writeFileSync(filePath, configJson, 'utf-8');
|
|
361
|
+
|
|
362
|
+
console.log(c('green', `\nā
Configuration generated for ${c('cyan', selected.name)}`));
|
|
363
|
+
console.log(c('dim', 'ā'.repeat(50)));
|
|
364
|
+
console.log(c('bright', '\nConfiguration:\n'));
|
|
365
|
+
console.log(c('cyan', configJson));
|
|
366
|
+
console.log(c('dim', '\nā'.repeat(50)));
|
|
367
|
+
console.log(c('dim', `\nFile saved to: ${filePath}`));
|
|
368
|
+
console.log(c('bright', '\nš Opening file for copy-paste...\n'));
|
|
369
|
+
|
|
370
|
+
// Open the file
|
|
371
|
+
openFile(filePath);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// Parse command line arguments
|
|
375
|
+
const args = process.argv.slice(2);
|
|
376
|
+
const command = args[0];
|
|
377
|
+
|
|
378
|
+
switch (command) {
|
|
379
|
+
case 'list':
|
|
380
|
+
case 'ls':
|
|
381
|
+
case undefined:
|
|
382
|
+
listServers();
|
|
383
|
+
break;
|
|
384
|
+
|
|
385
|
+
case 'code':
|
|
386
|
+
generateConfigFile();
|
|
387
|
+
break;
|
|
388
|
+
|
|
389
|
+
case 'info':
|
|
390
|
+
case 'show':
|
|
391
|
+
if (!args[1]) {
|
|
392
|
+
console.log(c('red', '\nā Please specify a server name.'));
|
|
393
|
+
console.log(c('dim', ' Example: fe-mcp info shift-ai\n'));
|
|
394
|
+
process.exit(1);
|
|
395
|
+
}
|
|
396
|
+
showInfo(args[1]);
|
|
397
|
+
break;
|
|
398
|
+
|
|
399
|
+
case 'config':
|
|
400
|
+
if (!args[1]) {
|
|
401
|
+
console.log(c('red', '\nā Please specify a server name.'));
|
|
402
|
+
console.log(c('dim', ' Example: fe-mcp config shift-ai\n'));
|
|
403
|
+
process.exit(1);
|
|
404
|
+
}
|
|
405
|
+
outputConfig(args[1]);
|
|
406
|
+
break;
|
|
407
|
+
|
|
408
|
+
case 'help':
|
|
409
|
+
case '--help':
|
|
410
|
+
case '-h':
|
|
411
|
+
showHelp();
|
|
412
|
+
break;
|
|
413
|
+
|
|
414
|
+
case 'version':
|
|
415
|
+
case '--version':
|
|
416
|
+
case '-v':
|
|
417
|
+
console.log(`${packageJson.name} v${packageJson.version}`);
|
|
418
|
+
break;
|
|
419
|
+
|
|
420
|
+
default:
|
|
421
|
+
console.log(c('red', `\nā Unknown command: ${command}`));
|
|
422
|
+
showHelp();
|
|
423
|
+
process.exit(1);
|
|
424
|
+
}
|