mcphosting-cli 0.1.0 → 0.1.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/package.json +10 -5
- package/CONTRIBUTING.md +0 -156
- package/src/commands/auth.ts +0 -186
- package/src/commands/connect.ts +0 -172
- package/src/commands/import.ts +0 -213
- package/src/commands/proxy.ts +0 -144
- package/src/commands/search.ts +0 -135
- package/src/commands/servers.ts +0 -131
- package/src/index.ts +0 -130
- package/src/lib/api.ts +0 -137
- package/src/lib/clients.ts +0 -188
- package/src/lib/config.ts +0 -90
- package/src/lib/logger.ts +0 -63
- package/src/types.ts +0 -47
- package/tsconfig.json +0 -26
- package/tsup.config.ts +0 -14
package/src/commands/import.ts
DELETED
|
@@ -1,213 +0,0 @@
|
|
|
1
|
-
import { Command } from 'commander';
|
|
2
|
-
import { readFile, access } from 'fs/promises';
|
|
3
|
-
import { join } from 'path';
|
|
4
|
-
import { homedir } from 'os';
|
|
5
|
-
import { Config } from '../lib/config.js';
|
|
6
|
-
import { ClientManager } from '../lib/clients.js';
|
|
7
|
-
import { Logger } from '../lib/logger.js';
|
|
8
|
-
import chalk from 'chalk';
|
|
9
|
-
|
|
10
|
-
interface SmitheryConfig {
|
|
11
|
-
servers?: Record<string, {
|
|
12
|
-
url?: string;
|
|
13
|
-
command?: string;
|
|
14
|
-
args?: string[];
|
|
15
|
-
env?: Record<string, string>;
|
|
16
|
-
}>;
|
|
17
|
-
mcpServers?: Record<string, {
|
|
18
|
-
url?: string;
|
|
19
|
-
command?: string;
|
|
20
|
-
args?: string[];
|
|
21
|
-
env?: Record<string, string>;
|
|
22
|
-
}>;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export function createImportCommand(): Command {
|
|
26
|
-
return new Command('import')
|
|
27
|
-
.description('Import MCP connections from other tools')
|
|
28
|
-
.option('--from <tool>', 'Import from: smithery', 'smithery')
|
|
29
|
-
.option('--dry-run', 'Show what would be imported without actually importing')
|
|
30
|
-
.option('--config-path <path>', 'Custom config file path')
|
|
31
|
-
.action(async (options) => {
|
|
32
|
-
if (options.from !== 'smithery') {
|
|
33
|
-
Logger.error('Only Smithery import is currently supported');
|
|
34
|
-
Logger.info('Usage: mcphost import --from smithery');
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
await importFromSmitery(options);
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
async function importFromSmitery(options: { dryRun?: boolean; configPath?: string }) {
|
|
43
|
-
const config = new Config();
|
|
44
|
-
const spinner = Logger.spinner('Looking for Smithery config...');
|
|
45
|
-
|
|
46
|
-
try {
|
|
47
|
-
// Try to find Smithery config
|
|
48
|
-
const smitheryPaths = [
|
|
49
|
-
options.configPath,
|
|
50
|
-
join(homedir(), '.smithery', 'config.json'),
|
|
51
|
-
join(homedir(), '.config', 'smithery', 'config.json'),
|
|
52
|
-
join(homedir(), 'Library', 'Application Support', 'smithery', 'config.json'),
|
|
53
|
-
join(process.cwd(), 'smithery.json'),
|
|
54
|
-
join(process.cwd(), '.smithery.json')
|
|
55
|
-
].filter(Boolean) as string[];
|
|
56
|
-
|
|
57
|
-
let smitheryConfigPath: string | null = null;
|
|
58
|
-
for (const path of smitheryPaths) {
|
|
59
|
-
try {
|
|
60
|
-
await access(path);
|
|
61
|
-
smitheryConfigPath = path;
|
|
62
|
-
break;
|
|
63
|
-
} catch {
|
|
64
|
-
// Continue to next path
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (!smitheryConfigPath) {
|
|
69
|
-
spinner.fail('Smithery config not found');
|
|
70
|
-
Logger.warning('Searched locations:');
|
|
71
|
-
smitheryPaths.forEach(path => Logger.dim(` ${path}`));
|
|
72
|
-
Logger.info('\nIf Smithery is installed, you can specify the config path:');
|
|
73
|
-
Logger.info(' mcphost import --from smithery --config-path /path/to/smithery/config.json');
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
spinner.succeed(`Found Smithery config: ${smitheryConfigPath}`);
|
|
78
|
-
|
|
79
|
-
// Read and parse Smithery config
|
|
80
|
-
const loadSpinner = Logger.spinner('Reading Smithery config...');
|
|
81
|
-
const configContent = await readFile(smitheryConfigPath, 'utf-8');
|
|
82
|
-
const smitheryConfig: SmitheryConfig = JSON.parse(configContent);
|
|
83
|
-
|
|
84
|
-
// Extract MCP servers from both possible locations
|
|
85
|
-
const servers = {
|
|
86
|
-
...smitheryConfig.servers,
|
|
87
|
-
...smitheryConfig.mcpServers
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
if (!servers || Object.keys(servers).length === 0) {
|
|
91
|
-
loadSpinner.warn('No MCP servers found in Smithery config');
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const serverEntries = Object.entries(servers);
|
|
96
|
-
loadSpinner.succeed(`Found ${serverEntries.length} MCP server(s) in Smithery config`);
|
|
97
|
-
|
|
98
|
-
if (options.dryRun) {
|
|
99
|
-
console.log('\n' + chalk.bold('🔍 Preview: Would import the following MCP servers:'));
|
|
100
|
-
console.log('');
|
|
101
|
-
|
|
102
|
-
serverEntries.forEach(([slug, serverConfig]) => {
|
|
103
|
-
const url = serverConfig.url || `https://${slug}.mcphost.dev`;
|
|
104
|
-
console.log(`• ${chalk.cyan(slug)}`);
|
|
105
|
-
console.log(` URL: ${chalk.dim(url)}`);
|
|
106
|
-
|
|
107
|
-
if (serverConfig.command) {
|
|
108
|
-
console.log(` Command: ${chalk.dim(serverConfig.command + ' ' + (serverConfig.args?.join(' ') || ''))}`);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
console.log('');
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
Logger.info('Run without --dry-run to perform the import');
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// Actually import the servers
|
|
119
|
-
const importSpinner = Logger.spinner('Importing MCP servers...');
|
|
120
|
-
let imported = 0;
|
|
121
|
-
let skipped = 0;
|
|
122
|
-
|
|
123
|
-
for (const [slug, serverConfig] of serverEntries) {
|
|
124
|
-
try {
|
|
125
|
-
// Check if already exists
|
|
126
|
-
const existing = config.findConnection(slug);
|
|
127
|
-
if (existing) {
|
|
128
|
-
Logger.warning(`Skipping ${slug} - already connected`);
|
|
129
|
-
skipped++;
|
|
130
|
-
continue;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// Determine URL
|
|
134
|
-
let url = serverConfig.url;
|
|
135
|
-
if (!url) {
|
|
136
|
-
// If no URL but has command, try to extract from args
|
|
137
|
-
if (serverConfig.command === 'npx' && serverConfig.args?.[0] === '@mcphosting/cli') {
|
|
138
|
-
url = serverConfig.args[2]; // Should be the URL after 'proxy'
|
|
139
|
-
} else {
|
|
140
|
-
// Default to mcphost.dev format
|
|
141
|
-
url = `https://${slug}.mcphost.dev`;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
if (!url) {
|
|
146
|
-
Logger.warning(`Skipping ${slug} - no URL found`);
|
|
147
|
-
skipped++;
|
|
148
|
-
continue;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// Connect to available clients
|
|
152
|
-
const detectedClients = await ClientManager.detectInstalledClients();
|
|
153
|
-
const availableClients = detectedClients.filter(c => c.exists);
|
|
154
|
-
const connectedClients: string[] = [];
|
|
155
|
-
|
|
156
|
-
for (const client of availableClients) {
|
|
157
|
-
try {
|
|
158
|
-
const success = await ClientManager.addToClient(
|
|
159
|
-
client.name as any,
|
|
160
|
-
slug,
|
|
161
|
-
url
|
|
162
|
-
);
|
|
163
|
-
|
|
164
|
-
if (success) {
|
|
165
|
-
connectedClients.push(client.name);
|
|
166
|
-
}
|
|
167
|
-
} catch (error) {
|
|
168
|
-
// Continue with other clients
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
// Save connection
|
|
173
|
-
config.addConnection({
|
|
174
|
-
slug,
|
|
175
|
-
url,
|
|
176
|
-
clients: connectedClients
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
imported++;
|
|
180
|
-
|
|
181
|
-
} catch (error) {
|
|
182
|
-
Logger.warning(`Failed to import ${slug}: ${error}`);
|
|
183
|
-
skipped++;
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
importSpinner.succeed('Import completed');
|
|
188
|
-
|
|
189
|
-
Logger.success(`✅ Imported ${imported} MCP server(s)`);
|
|
190
|
-
if (skipped > 0) {
|
|
191
|
-
Logger.warning(`⚠️ Skipped ${skipped} server(s)`);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
console.log('');
|
|
195
|
-
Logger.info('Use `mcphost list` to see your imported connections');
|
|
196
|
-
|
|
197
|
-
// Growth hacking message
|
|
198
|
-
console.log('\n' + chalk.green('🎉 Welcome to MCPHosting! Share with your team:'));
|
|
199
|
-
console.log(chalk.cyan('npx @mcphosting/cli import --from smithery'));
|
|
200
|
-
console.log('\n' + chalk.yellow('⭐ Star us: ') + chalk.blue('https://github.com/gorlomi-enzo/mcphosting-cli'));
|
|
201
|
-
console.log('');
|
|
202
|
-
|
|
203
|
-
} catch (error) {
|
|
204
|
-
spinner.fail('Import failed');
|
|
205
|
-
Logger.error(`Error: ${error}`);
|
|
206
|
-
|
|
207
|
-
if (error instanceof SyntaxError) {
|
|
208
|
-
Logger.warning('Invalid JSON in Smithery config file');
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
process.exit(1);
|
|
212
|
-
}
|
|
213
|
-
}
|
package/src/commands/proxy.ts
DELETED
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
import { Command } from 'commander';
|
|
2
|
-
import { Logger } from '../lib/logger.js';
|
|
3
|
-
import { createReadStream, createWriteStream } from 'fs';
|
|
4
|
-
import { Readable, Writable } from 'stream';
|
|
5
|
-
|
|
6
|
-
export function createProxyCommand(): Command {
|
|
7
|
-
return new Command('proxy')
|
|
8
|
-
.description('Start a local STDIO MCP proxy to a remote server')
|
|
9
|
-
.argument('<url>', 'Remote MCP server URL')
|
|
10
|
-
.option('--quiet', 'Suppress startup messages')
|
|
11
|
-
.action(async (url: string, options) => {
|
|
12
|
-
if (!options.quiet) {
|
|
13
|
-
// Log to stderr so it doesn't interfere with STDIO MCP protocol
|
|
14
|
-
console.error('🔗 Proxying via mcphosting.com');
|
|
15
|
-
console.error(`📡 Remote server: ${url}`);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
try {
|
|
19
|
-
await startProxy(url, options.quiet);
|
|
20
|
-
} catch (error) {
|
|
21
|
-
if (!options.quiet) {
|
|
22
|
-
console.error(`❌ Proxy error: ${error}`);
|
|
23
|
-
}
|
|
24
|
-
process.exit(1);
|
|
25
|
-
}
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
async function startProxy(url: string, quiet: boolean = false): Promise<void> {
|
|
30
|
-
// For MVP, implement a simple HTTP proxy that translates STDIO JSON-RPC to HTTP
|
|
31
|
-
// In production, this should use WebSocket or SSE for real-time communication
|
|
32
|
-
|
|
33
|
-
let buffer = '';
|
|
34
|
-
|
|
35
|
-
// Set up JSON-RPC message parsing from stdin
|
|
36
|
-
process.stdin.setEncoding('utf8');
|
|
37
|
-
process.stdin.on('data', async (chunk) => {
|
|
38
|
-
buffer += chunk;
|
|
39
|
-
|
|
40
|
-
// Process complete JSON-RPC messages (newline delimited)
|
|
41
|
-
const lines = buffer.split('\n');
|
|
42
|
-
buffer = lines.pop() || ''; // Keep incomplete line in buffer
|
|
43
|
-
|
|
44
|
-
for (const line of lines) {
|
|
45
|
-
if (line.trim()) {
|
|
46
|
-
try {
|
|
47
|
-
await forwardMessage(url, line, quiet);
|
|
48
|
-
} catch (error) {
|
|
49
|
-
if (!quiet) {
|
|
50
|
-
console.error(`Proxy error: ${error}`);
|
|
51
|
-
}
|
|
52
|
-
// Send error response back to client
|
|
53
|
-
const errorResponse = {
|
|
54
|
-
jsonrpc: '2.0',
|
|
55
|
-
id: null,
|
|
56
|
-
error: {
|
|
57
|
-
code: -32603,
|
|
58
|
-
message: 'Proxy error',
|
|
59
|
-
data: error.toString()
|
|
60
|
-
}
|
|
61
|
-
};
|
|
62
|
-
process.stdout.write(JSON.stringify(errorResponse) + '\n');
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
process.stdin.on('end', () => {
|
|
69
|
-
if (!quiet) {
|
|
70
|
-
console.error('📴 Proxy connection closed');
|
|
71
|
-
}
|
|
72
|
-
process.exit(0);
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
process.stdin.on('error', (error) => {
|
|
76
|
-
if (!quiet) {
|
|
77
|
-
console.error(`Stdin error: ${error}`);
|
|
78
|
-
}
|
|
79
|
-
process.exit(1);
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
// Keep the process alive
|
|
83
|
-
await new Promise(() => {});
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
async function forwardMessage(url: string, message: string, quiet: boolean): Promise<void> {
|
|
87
|
-
try {
|
|
88
|
-
const jsonrpcMessage = JSON.parse(message);
|
|
89
|
-
|
|
90
|
-
// Forward the JSON-RPC message to the remote server via HTTP POST
|
|
91
|
-
const response = await fetch(url, {
|
|
92
|
-
method: 'POST',
|
|
93
|
-
headers: {
|
|
94
|
-
'Content-Type': 'application/json',
|
|
95
|
-
'Accept': 'application/json',
|
|
96
|
-
'User-Agent': '@mcphosting/cli-proxy'
|
|
97
|
-
},
|
|
98
|
-
body: message
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
if (!response.ok) {
|
|
102
|
-
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
const responseData = await response.text();
|
|
106
|
-
|
|
107
|
-
// Forward the response back to stdout
|
|
108
|
-
process.stdout.write(responseData);
|
|
109
|
-
|
|
110
|
-
// Ensure newline for JSON-RPC protocol
|
|
111
|
-
if (!responseData.endsWith('\n')) {
|
|
112
|
-
process.stdout.write('\n');
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
} catch (error) {
|
|
116
|
-
// If we can't parse the original message, send a generic error
|
|
117
|
-
if (error instanceof SyntaxError) {
|
|
118
|
-
const errorResponse = {
|
|
119
|
-
jsonrpc: '2.0',
|
|
120
|
-
id: null,
|
|
121
|
-
error: {
|
|
122
|
-
code: -32700,
|
|
123
|
-
message: 'Parse error',
|
|
124
|
-
data: 'Invalid JSON-RPC message'
|
|
125
|
-
}
|
|
126
|
-
};
|
|
127
|
-
process.stdout.write(JSON.stringify(errorResponse) + '\n');
|
|
128
|
-
} else {
|
|
129
|
-
throw error;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Alternative WebSocket-based proxy for real-time communication
|
|
135
|
-
async function startWebSocketProxy(url: string, quiet: boolean = false): Promise<void> {
|
|
136
|
-
// This would use WebSocket for bidirectional communication
|
|
137
|
-
// Implementation would depend on the remote server supporting WebSocket
|
|
138
|
-
|
|
139
|
-
if (!quiet) {
|
|
140
|
-
console.error('WebSocket proxy not yet implemented, using HTTP proxy');
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
return startProxy(url, quiet);
|
|
144
|
-
}
|
package/src/commands/search.ts
DELETED
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
import { Command } from 'commander';
|
|
2
|
-
import { MCPHostingAPI } from '../lib/api.js';
|
|
3
|
-
import { Config } from '../lib/config.js';
|
|
4
|
-
import { Logger } from '../lib/logger.js';
|
|
5
|
-
import chalk from 'chalk';
|
|
6
|
-
|
|
7
|
-
export function createSearchCommand(): Command {
|
|
8
|
-
return new Command('search')
|
|
9
|
-
.description('Search MCP servers in the marketplace')
|
|
10
|
-
.argument('<query>', 'Search query')
|
|
11
|
-
.option('--limit <number>', 'Maximum number of results', '10')
|
|
12
|
-
.option('--json', 'Output as JSON')
|
|
13
|
-
.action(async (query: string, options) => {
|
|
14
|
-
const config = new Config();
|
|
15
|
-
const api = new MCPHostingAPI(config.token);
|
|
16
|
-
const spinner = Logger.spinner(`Searching for "${query}"...`);
|
|
17
|
-
|
|
18
|
-
try {
|
|
19
|
-
const results = await api.searchMCPs(query);
|
|
20
|
-
spinner.succeed(`Found ${results.length} MCP server(s)`);
|
|
21
|
-
|
|
22
|
-
if (results.length === 0) {
|
|
23
|
-
Logger.info('No MCP servers found matching your query');
|
|
24
|
-
Logger.dim('Try searching for: github, slack, notion, stripe, postgres, filesystem');
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const limit = parseInt(options.limit);
|
|
29
|
-
const limitedResults = results.slice(0, limit);
|
|
30
|
-
|
|
31
|
-
if (options.json) {
|
|
32
|
-
Logger.json(limitedResults);
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
console.log('');
|
|
37
|
-
Logger.bold(`🔍 MCP Marketplace Search Results`);
|
|
38
|
-
console.log('');
|
|
39
|
-
|
|
40
|
-
limitedResults.forEach((server, index) => {
|
|
41
|
-
console.log(chalk.cyan(`${index + 1}. ${server.name}`));
|
|
42
|
-
console.log(` ${chalk.dim(server.description)}`);
|
|
43
|
-
console.log(` ${chalk.yellow('Slug:')} ${server.slug} | ${chalk.yellow('Installs:')} ${server.installs.toLocaleString()} | ${chalk.yellow('Author:')} ${server.author}`);
|
|
44
|
-
console.log(` ${chalk.green('Tools:')} ${server.tools.join(', ')}`);
|
|
45
|
-
|
|
46
|
-
if (server.url) {
|
|
47
|
-
console.log(` ${chalk.blue('Connect:')} ${chalk.dim(`mcphost connect ${server.slug}`)}`);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
console.log('');
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
if (results.length > limit) {
|
|
54
|
-
Logger.dim(`Showing ${limit} of ${results.length} results. Use --limit to see more.`);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
Logger.info('Use `mcphost info <slug>` for detailed information');
|
|
58
|
-
Logger.info('Use `mcphost connect <slug>` to install');
|
|
59
|
-
|
|
60
|
-
} catch (error) {
|
|
61
|
-
spinner.fail('Search failed');
|
|
62
|
-
Logger.error(`Error: ${error}`);
|
|
63
|
-
process.exit(1);
|
|
64
|
-
}
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export function createInfoCommand(): Command {
|
|
69
|
-
return new Command('info')
|
|
70
|
-
.description('Show detailed information about an MCP server')
|
|
71
|
-
.argument('<slug>', 'MCP server slug')
|
|
72
|
-
.option('--json', 'Output as JSON')
|
|
73
|
-
.action(async (slug: string, options) => {
|
|
74
|
-
const config = new Config();
|
|
75
|
-
const api = new MCPHostingAPI(config.token);
|
|
76
|
-
const spinner = Logger.spinner(`Getting info for ${slug}...`);
|
|
77
|
-
|
|
78
|
-
try {
|
|
79
|
-
const server = await api.getMCPInfo(slug);
|
|
80
|
-
|
|
81
|
-
if (!server) {
|
|
82
|
-
spinner.fail(`MCP server not found: ${slug}`);
|
|
83
|
-
Logger.info('Use `mcphost search <query>` to find servers');
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
spinner.succeed('Found server info');
|
|
88
|
-
|
|
89
|
-
if (options.json) {
|
|
90
|
-
Logger.json(server);
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
console.log('');
|
|
95
|
-
console.log(chalk.bold.cyan(`📦 ${server.name}`));
|
|
96
|
-
console.log(chalk.dim(server.description));
|
|
97
|
-
console.log('');
|
|
98
|
-
|
|
99
|
-
const infoTable = [
|
|
100
|
-
{ Property: 'Slug', Value: server.slug },
|
|
101
|
-
{ Property: 'Author', Value: server.author },
|
|
102
|
-
{ Property: 'Installs', Value: server.installs.toLocaleString() },
|
|
103
|
-
{ Property: 'Tools', Value: server.tools.length.toString() }
|
|
104
|
-
];
|
|
105
|
-
|
|
106
|
-
if (server.url) {
|
|
107
|
-
infoTable.push({ Property: 'URL', Value: server.url });
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
Logger.table(infoTable);
|
|
111
|
-
|
|
112
|
-
console.log('');
|
|
113
|
-
console.log(chalk.yellow('🔧 Available Tools:'));
|
|
114
|
-
server.tools.forEach(tool => {
|
|
115
|
-
console.log(` • ${tool}`);
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
console.log('');
|
|
119
|
-
console.log(chalk.green('💡 Quick Start:'));
|
|
120
|
-
console.log(chalk.dim(` mcphost connect ${server.slug}`));
|
|
121
|
-
|
|
122
|
-
// Check if already connected
|
|
123
|
-
const connection = config.findConnection(slug);
|
|
124
|
-
if (connection) {
|
|
125
|
-
console.log('');
|
|
126
|
-
console.log(chalk.blue('ℹ️ Already connected to:'), connection.clients.join(', '));
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
} catch (error) {
|
|
130
|
-
spinner.fail('Failed to get server info');
|
|
131
|
-
Logger.error(`Error: ${error}`);
|
|
132
|
-
process.exit(1);
|
|
133
|
-
}
|
|
134
|
-
});
|
|
135
|
-
}
|
package/src/commands/servers.ts
DELETED
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
import { Command } from 'commander';
|
|
2
|
-
import { Config } from '../lib/config.js';
|
|
3
|
-
import { Logger } from '../lib/logger.js';
|
|
4
|
-
import chalk from 'chalk';
|
|
5
|
-
|
|
6
|
-
export function createServersCommand(): Command {
|
|
7
|
-
const servers = new Command('servers');
|
|
8
|
-
servers.description('Manage your hosted MCP servers');
|
|
9
|
-
|
|
10
|
-
servers
|
|
11
|
-
.command('list')
|
|
12
|
-
.description('List your MCP servers')
|
|
13
|
-
.action(async () => {
|
|
14
|
-
const config = new Config();
|
|
15
|
-
|
|
16
|
-
if (!config.token) {
|
|
17
|
-
Logger.warning('Authentication required');
|
|
18
|
-
Logger.info('Use `mcphost login` to authenticate with MCPHosting');
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
Logger.info('🚧 Server management coming soon!');
|
|
23
|
-
console.log('');
|
|
24
|
-
console.log('This feature will let you:');
|
|
25
|
-
console.log('• List your hosted MCP servers');
|
|
26
|
-
console.log('• View usage analytics');
|
|
27
|
-
console.log('• Manage API keys');
|
|
28
|
-
console.log('• Publish to marketplace');
|
|
29
|
-
console.log('');
|
|
30
|
-
Logger.info('Visit https://mcphosting.com to manage servers in the web dashboard');
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
return servers;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export function createKeysCommand(): Command {
|
|
37
|
-
const keys = new Command('keys');
|
|
38
|
-
keys.description('Manage API keys for your MCP servers');
|
|
39
|
-
|
|
40
|
-
keys
|
|
41
|
-
.command('list')
|
|
42
|
-
.argument('[server-id]', 'Server ID')
|
|
43
|
-
.description('List API keys')
|
|
44
|
-
.action(async (serverId?: string) => {
|
|
45
|
-
const config = new Config();
|
|
46
|
-
|
|
47
|
-
if (!config.token) {
|
|
48
|
-
Logger.warning('Authentication required');
|
|
49
|
-
Logger.info('Use `mcphost login` to authenticate');
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
Logger.info('🚧 API key management coming soon!');
|
|
54
|
-
Logger.info('Visit https://mcphosting.com to manage keys in the web dashboard');
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
keys
|
|
58
|
-
.command('create')
|
|
59
|
-
.argument('<server-id>', 'Server ID')
|
|
60
|
-
.option('--name <name>', 'Key name', 'CLI Key')
|
|
61
|
-
.description('Create a new API key')
|
|
62
|
-
.action(async (serverId: string, options) => {
|
|
63
|
-
const config = new Config();
|
|
64
|
-
|
|
65
|
-
if (!config.token) {
|
|
66
|
-
Logger.warning('Authentication required');
|
|
67
|
-
Logger.info('Use `mcphost login` to authenticate');
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
Logger.info('🚧 API key creation coming soon!');
|
|
72
|
-
Logger.info('Visit https://mcphosting.com to create keys in the web dashboard');
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
keys
|
|
76
|
-
.command('revoke')
|
|
77
|
-
.argument('<key-id>', 'API key ID')
|
|
78
|
-
.description('Revoke an API key')
|
|
79
|
-
.action(async (keyId: string) => {
|
|
80
|
-
const config = new Config();
|
|
81
|
-
|
|
82
|
-
if (!config.token) {
|
|
83
|
-
Logger.warning('Authentication required');
|
|
84
|
-
Logger.info('Use `mcphost login` to authenticate');
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
Logger.info('🚧 API key revocation coming soon!');
|
|
89
|
-
Logger.info('Visit https://mcphosting.com to revoke keys in the web dashboard');
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
return keys;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
export function createPublishCommand(): Command {
|
|
96
|
-
return new Command('publish')
|
|
97
|
-
.description('Publish MCP server to marketplace')
|
|
98
|
-
.argument('[server-id]', 'Server ID to publish')
|
|
99
|
-
.option('--private', 'Keep server private')
|
|
100
|
-
.option('--description <desc>', 'Server description')
|
|
101
|
-
.option('--tags <tags>', 'Comma-separated tags')
|
|
102
|
-
.action(async (serverId?: string, options = {}) => {
|
|
103
|
-
const config = new Config();
|
|
104
|
-
|
|
105
|
-
if (!config.token) {
|
|
106
|
-
Logger.warning('Authentication required');
|
|
107
|
-
Logger.info('Use `mcphost login` to authenticate');
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
Logger.info('🚧 Marketplace publishing coming soon!');
|
|
112
|
-
console.log('');
|
|
113
|
-
console.log('This feature will let you:');
|
|
114
|
-
console.log('• Publish your MCP servers to the marketplace');
|
|
115
|
-
console.log('• Set descriptions and tags');
|
|
116
|
-
console.log('• Configure public/private visibility');
|
|
117
|
-
console.log('• Track usage analytics');
|
|
118
|
-
console.log('');
|
|
119
|
-
Logger.info('Visit https://mcphosting.com to publish servers via the web dashboard');
|
|
120
|
-
|
|
121
|
-
if (serverId) {
|
|
122
|
-
Logger.dim(`Would publish server: ${serverId}`);
|
|
123
|
-
}
|
|
124
|
-
if (options.description) {
|
|
125
|
-
Logger.dim(`Description: ${options.description}`);
|
|
126
|
-
}
|
|
127
|
-
if (options.tags) {
|
|
128
|
-
Logger.dim(`Tags: ${options.tags}`);
|
|
129
|
-
}
|
|
130
|
-
});
|
|
131
|
-
}
|