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 CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "mcphosting-cli",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Connect AI agents to MCP servers. Browse, install, and manage Model Context Protocol servers.",
5
5
  "bin": {
6
- "mcphost": "./dist/index.js"
6
+ "mcphost": "dist/index.js"
7
7
  },
8
8
  "main": "./dist/index.cjs",
9
9
  "module": "./dist/index.js",
@@ -24,7 +24,7 @@
24
24
  "mcp",
25
25
  "model-context-protocol",
26
26
  "claude",
27
- "chatgpt",
27
+ "chatgpt",
28
28
  "cursor",
29
29
  "ai-agents",
30
30
  "mcp-server",
@@ -32,7 +32,7 @@
32
32
  "smithery",
33
33
  "github-mcp",
34
34
  "slack-mcp",
35
- "notion-mcp",
35
+ "notion-mcp",
36
36
  "stripe-mcp",
37
37
  "mcp-marketplace",
38
38
  "ai-tools",
@@ -52,5 +52,10 @@
52
52
  "@types/node": "^20.11.0",
53
53
  "tsup": "^8.0.0",
54
54
  "typescript": "^5.3.0"
55
- }
55
+ },
56
+ "files": [
57
+ "dist",
58
+ "README.md",
59
+ "LICENSE"
60
+ ]
56
61
  }
package/CONTRIBUTING.md DELETED
@@ -1,156 +0,0 @@
1
- # Contributing to MCPHosting CLI
2
-
3
- We love contributions! Here's how to get started.
4
-
5
- ## Development Setup
6
-
7
- 1. **Clone the repository:**
8
- ```bash
9
- git clone https://github.com/gorlomi-enzo/mcphosting-cli.git
10
- cd mcphosting-cli
11
- ```
12
-
13
- 2. **Install dependencies:**
14
- ```bash
15
- npm install
16
- ```
17
-
18
- 3. **Build and test:**
19
- ```bash
20
- npm run build
21
- node dist/index.js --help
22
- ```
23
-
24
- ## Project Structure
25
-
26
- ```
27
- src/
28
- ├── index.ts # CLI entry point
29
- ├── commands/ # Command implementations
30
- │ ├── auth.ts # login/logout/whoami
31
- │ ├── connect.ts # connect/disconnect/list
32
- │ ├── import.ts # import from other tools
33
- │ ├── proxy.ts # STDIO MCP proxy
34
- │ ├── search.ts # search/info marketplace
35
- │ └── servers.ts # server management (stubs)
36
- ├── lib/ # Shared utilities
37
- │ ├── api.ts # MCPHosting API client
38
- │ ├── clients.ts # AI client detection/config
39
- │ ├── config.ts # Local config management
40
- │ └── logger.ts # Pretty console output
41
- └── types.ts # TypeScript definitions
42
- ```
43
-
44
- ## Making Changes
45
-
46
- 1. **Create a feature branch:**
47
- ```bash
48
- git checkout -b feature/my-feature
49
- ```
50
-
51
- 2. **Make your changes:**
52
- - Follow the existing code style
53
- - Add TypeScript types for new code
54
- - Test your changes with `npm run build && node dist/index.js`
55
-
56
- 3. **Test different scenarios:**
57
- ```bash
58
- # Test search
59
- node dist/index.js search github
60
-
61
- # Test connect (dry run)
62
- node dist/index.js connect github --client chatgpt
63
-
64
- # Test help
65
- node dist/index.js --help
66
- node dist/index.js connect --help
67
- ```
68
-
69
- ## Adding New Commands
70
-
71
- 1. **Create the command file** in `src/commands/`
72
- 2. **Export a function** that returns a `Command` object
73
- 3. **Import and add** to `src/index.ts`
74
-
75
- Example:
76
- ```typescript
77
- // src/commands/example.ts
78
- import { Command } from 'commander';
79
- import { Logger } from '../lib/logger.js';
80
-
81
- export function createExampleCommand(): Command {
82
- return new Command('example')
83
- .description('Example command')
84
- .action(async () => {
85
- Logger.success('Hello world!');
86
- });
87
- }
88
-
89
- // src/index.ts
90
- import { createExampleCommand } from './commands/example.js';
91
- program.addCommand(createExampleCommand());
92
- ```
93
-
94
- ## Adding New MCP Servers
95
-
96
- Static MCP servers are defined in `src/lib/api.ts` in the `getStaticMCPs()` method. Add new entries there for testing until the live API is available.
97
-
98
- ## Code Style
99
-
100
- - Use TypeScript with strict mode
101
- - Prefer async/await over Promises
102
- - Use the Logger class for consistent output
103
- - Add help text and examples to commands
104
- - Handle errors gracefully with user-friendly messages
105
-
106
- ## Testing
107
-
108
- Currently manual testing. Run these scenarios:
109
-
110
- ```bash
111
- # Core functionality
112
- npm run build
113
- node dist/index.js search github
114
- node dist/index.js info notion
115
- node dist/index.js list
116
- node dist/index.js connect github --client chatgpt
117
-
118
- # Import testing (will show "not found" unless you have Smithery)
119
- node dist/index.js import --from smithery --dry-run
120
-
121
- # Help testing
122
- node dist/index.js --help
123
- node dist/index.js connect --help
124
- ```
125
-
126
- ## Submitting Changes
127
-
128
- 1. **Commit your changes:**
129
- ```bash
130
- git add .
131
- git commit -m "Add: your feature description"
132
- ```
133
-
134
- 2. **Push your branch:**
135
- ```bash
136
- git push origin feature/my-feature
137
- ```
138
-
139
- 3. **Create a Pull Request** on GitHub
140
-
141
- ## Growth Hacking Features
142
-
143
- When adding commands, remember to include:
144
-
145
- - Helpful error messages with next steps
146
- - Links to GitHub repository in help text
147
- - Sharing prompts after successful actions
148
- - SEO-friendly descriptions and keywords
149
-
150
- ## Need Help?
151
-
152
- - Open an issue on GitHub
153
- - Check existing issues for similar problems
154
- - Join our Discord: https://discord.gg/mcphosting
155
-
156
- Thanks for contributing! 🚀
@@ -1,186 +0,0 @@
1
- import { Command } from 'commander';
2
- import { createServer } from 'http';
3
- import open from 'open';
4
- import { Config } from '../lib/config.js';
5
- import { MCPHostingAPI } from '../lib/api.js';
6
- import { Logger } from '../lib/logger.js';
7
-
8
- export function createAuthCommands(): Command {
9
- const auth = new Command('auth');
10
-
11
- auth
12
- .command('login')
13
- .description('Authenticate with MCPHosting')
14
- .option('--token <token>', 'Provide API token directly')
15
- .action(async (options) => {
16
- const config = new Config();
17
-
18
- if (options.token) {
19
- // Manual token auth
20
- config.token = options.token;
21
-
22
- const api = new MCPHostingAPI(options.token);
23
- const user = await api.whoami();
24
-
25
- if (user) {
26
- config.user = user;
27
- Logger.success(`Logged in as ${user.email}${user.org ? ` (${user.org})` : ''}`);
28
- } else {
29
- Logger.warning('Token saved, but could not verify user info');
30
- }
31
- return;
32
- }
33
-
34
- // Browser OAuth flow
35
- const spinner = Logger.spinner('Starting login flow...');
36
-
37
- let server: any;
38
- let resolved = false;
39
-
40
- try {
41
- const authPromise = new Promise<string>((resolve, reject) => {
42
- server = createServer((req, res) => {
43
- if (req.url?.startsWith('/callback')) {
44
- const url = new URL(req.url, 'http://localhost');
45
- const token = url.searchParams.get('token');
46
-
47
- if (token) {
48
- res.writeHead(200, { 'Content-Type': 'text/html' });
49
- res.end(`
50
- <html>
51
- <body style="font-family: system-ui; text-align: center; padding: 50px;">
52
- <h2>✅ Login Successful!</h2>
53
- <p>You can now close this window and return to your terminal.</p>
54
- </body>
55
- </html>
56
- `);
57
- resolve(token);
58
- } else {
59
- res.writeHead(400, { 'Content-Type': 'text/html' });
60
- res.end(`
61
- <html>
62
- <body style="font-family: system-ui; text-align: center; padding: 50px;">
63
- <h2>❌ Login Failed</h2>
64
- <p>No token received. Please try again.</p>
65
- </body>
66
- </html>
67
- `);
68
- reject(new Error('No token received'));
69
- }
70
- } else {
71
- res.writeHead(404);
72
- res.end('Not found');
73
- }
74
- });
75
-
76
- server.listen(0, () => {
77
- const port = (server.address() as any).port;
78
- const callbackUrl = `http://localhost:${port}/callback`;
79
- const authUrl = `https://mcphosting.com/cli/auth?callback=${encodeURIComponent(callbackUrl)}`;
80
-
81
- setTimeout(() => {
82
- if (!resolved) {
83
- reject(new Error('Login timeout - please try again'));
84
- }
85
- }, 120000); // 2 minute timeout
86
-
87
- open(authUrl).catch(() => {
88
- Logger.warning(`Could not open browser automatically. Please visit: ${authUrl}`);
89
- });
90
- });
91
- });
92
-
93
- const token = await authPromise;
94
- resolved = true;
95
-
96
- spinner.succeed('Login successful!');
97
-
98
- config.token = token;
99
-
100
- const api = new MCPHostingAPI(token);
101
- const user = await api.whoami();
102
-
103
- if (user) {
104
- config.user = user;
105
- Logger.success(`Logged in as ${user.email}${user.org ? ` (${user.org})` : ''}`);
106
- }
107
-
108
- } catch (error) {
109
- spinner.fail('Login failed');
110
- Logger.error(`Login error: ${error}`);
111
- process.exit(1);
112
- } finally {
113
- if (server) {
114
- server.close();
115
- }
116
- }
117
- });
118
-
119
- auth
120
- .command('logout')
121
- .description('Remove stored authentication')
122
- .action(() => {
123
- const config = new Config();
124
- config.token = undefined;
125
- config.user = undefined;
126
- Logger.success('Logged out successfully');
127
- });
128
-
129
- auth
130
- .command('whoami')
131
- .description('Show current user information')
132
- .action(async () => {
133
- const config = new Config();
134
- const token = config.token;
135
-
136
- if (!token) {
137
- Logger.warning('Not logged in. Use `mcphost auth login` to authenticate.');
138
- return;
139
- }
140
-
141
- const user = config.user;
142
- if (user) {
143
- Logger.info(`Logged in as: ${user.email}${user.org ? ` (${user.org})` : ''}`);
144
- } else {
145
- Logger.warning('User info not available. Try logging in again.');
146
- }
147
- });
148
-
149
- return auth;
150
- }
151
-
152
- // Legacy commands (backwards compatibility)
153
- export function createLegacyAuthCommands(): Command[] {
154
- const config = new Config();
155
-
156
- const login = new Command('login')
157
- .description('Authenticate with MCPHosting')
158
- .option('--token <token>', 'Provide API token directly')
159
- .action(async (options) => {
160
- const authCmd = createAuthCommands();
161
- const loginCmd = authCmd.commands.find(cmd => cmd.name() === 'login');
162
- if (loginCmd) {
163
- await loginCmd.action(options);
164
- }
165
- });
166
-
167
- const logout = new Command('logout')
168
- .description('Remove stored authentication')
169
- .action(() => {
170
- config.token = undefined;
171
- config.user = undefined;
172
- Logger.success('Logged out successfully');
173
- });
174
-
175
- const whoami = new Command('whoami')
176
- .description('Show current user information')
177
- .action(async () => {
178
- const authCmd = createAuthCommands();
179
- const whoamiCmd = authCmd.commands.find(cmd => cmd.name() === 'whoami');
180
- if (whoamiCmd) {
181
- await whoamiCmd.action();
182
- }
183
- });
184
-
185
- return [login, logout, whoami];
186
- }
@@ -1,172 +0,0 @@
1
- import { Command } from 'commander';
2
- import { Config } from '../lib/config.js';
3
- import { ClientManager } from '../lib/clients.js';
4
- import { Logger } from '../lib/logger.js';
5
- import { SupportedClient } from '../types.js';
6
- import chalk from 'chalk';
7
-
8
- export function createConnectCommands(): Command {
9
- const connect = new Command('connect')
10
- .description('Connect an MCP server to AI clients')
11
- .argument('<url-or-slug>', 'MCP server URL or slug')
12
- .option('--client <client>', 'Target specific client (claude, cursor, vscode, openclaw, chatgpt)')
13
- .option('--name <name>', 'Custom name for the connection')
14
- .action(async (urlOrSlug: string, options) => {
15
- const config = new Config();
16
- const spinner = Logger.spinner('Setting up MCP connection...');
17
-
18
- try {
19
- const url = ClientManager.resolveUrl(urlOrSlug);
20
- const slug = ClientManager.extractSlug(url);
21
- const name = options.name || slug;
22
-
23
- // Check if already connected
24
- const existing = config.findConnection(slug);
25
- if (existing) {
26
- spinner.warn(`Already connected to ${slug}`);
27
- Logger.info(`Use \`mcphost disconnect ${slug}\` to remove first`);
28
- return;
29
- }
30
-
31
- const clients: string[] = [];
32
-
33
- if (options.client) {
34
- // Connect to specific client
35
- const clientName = options.client as SupportedClient;
36
- const success = await ClientManager.addToClient(clientName, slug, url);
37
-
38
- if (success) {
39
- clients.push(clientName);
40
- spinner.succeed(`Connected to ${clientName}`);
41
- } else {
42
- spinner.fail(`Failed to connect to ${clientName}`);
43
- process.exit(1);
44
- }
45
- } else {
46
- // Auto-detect and connect to all available clients
47
- const detectedClients = await ClientManager.detectInstalledClients();
48
- const availableClients = detectedClients.filter(c => c.exists);
49
-
50
- if (availableClients.length === 0) {
51
- spinner.warn('No supported clients found');
52
- Logger.info('Supported clients: Claude Desktop, Cursor, VS Code, OpenClaw');
53
- Logger.info('Install a client and try again, or use --client chatgpt for web setup');
54
- return;
55
- }
56
-
57
- spinner.text = `Configuring ${availableClients.length} client${availableClients.length > 1 ? 's' : ''}...`;
58
-
59
- for (const client of availableClients) {
60
- try {
61
- const success = await ClientManager.addToClient(
62
- client.name as SupportedClient,
63
- slug,
64
- url
65
- );
66
-
67
- if (success) {
68
- clients.push(client.name);
69
- }
70
- } catch (error) {
71
- Logger.warning(`Failed to configure ${client.name}: ${error}`);
72
- }
73
- }
74
-
75
- spinner.succeed(`Connected to ${clients.length} client${clients.length > 1 ? 's' : ''}`);
76
- }
77
-
78
- // Save connection to config
79
- config.addConnection({
80
- slug,
81
- url,
82
- clients
83
- });
84
-
85
- Logger.success(`🔗 ${name} connected successfully!`);
86
- Logger.dim(` URL: ${url}`);
87
- Logger.dim(` Clients: ${clients.join(', ')}`);
88
-
89
- // Growth hacking: show sharing message after successful connection
90
- console.log('\n' + chalk.green('🎉 Connected! Share with your team:'));
91
- console.log(chalk.cyan(`npx @mcphosting/cli connect ${urlOrSlug}`));
92
- console.log('\n' + chalk.yellow('⭐ Star us: ') + chalk.blue('https://github.com/gorlomi-enzo/mcphosting-cli'));
93
- console.log('');
94
-
95
- } catch (error) {
96
- spinner.fail('Connection failed');
97
- Logger.error(`Error: ${error}`);
98
- process.exit(1);
99
- }
100
- });
101
-
102
- return connect;
103
- }
104
-
105
- export function createDisconnectCommand(): Command {
106
- return new Command('disconnect')
107
- .description('Disconnect an MCP server')
108
- .argument('<slug-or-id>', 'MCP server slug or connection ID')
109
- .action(async (slugOrId: string) => {
110
- const config = new Config();
111
- const connection = config.findConnection(slugOrId);
112
-
113
- if (!connection) {
114
- Logger.error(`Connection not found: ${slugOrId}`);
115
- Logger.info('Use `mcphost list` to see active connections');
116
- return;
117
- }
118
-
119
- const spinner = Logger.spinner(`Disconnecting ${connection.slug}...`);
120
-
121
- try {
122
- const removedFrom = await ClientManager.removeFromAllClients(connection.slug);
123
- config.removeConnection(connection.id);
124
-
125
- spinner.succeed(`Disconnected ${connection.slug}`);
126
-
127
- if (removedFrom.length > 0) {
128
- Logger.info(`Removed from: ${removedFrom.join(', ')}`);
129
- }
130
-
131
- } catch (error) {
132
- spinner.fail('Disconnect failed');
133
- Logger.error(`Error: ${error}`);
134
- }
135
- });
136
- }
137
-
138
- export function createListCommand(): Command {
139
- return new Command('list')
140
- .description('List connected MCP servers')
141
- .option('--json', 'Output as JSON')
142
- .action(async (options) => {
143
- const config = new Config();
144
- const connections = config.connections;
145
-
146
- if (connections.length === 0) {
147
- Logger.info('No MCP connections found');
148
- Logger.dim('Use `mcphost connect <url>` to add one');
149
- return;
150
- }
151
-
152
- if (options.json) {
153
- Logger.json(connections);
154
- return;
155
- }
156
-
157
- Logger.bold(`📋 Connected MCP Servers (${connections.length})`);
158
- console.log('');
159
-
160
- const tableData = connections.map(conn => ({
161
- Slug: conn.slug,
162
- URL: conn.url.length > 50 ? conn.url.slice(0, 47) + '...' : conn.url,
163
- Clients: conn.clients.join(', '),
164
- Added: new Date(conn.addedAt).toLocaleDateString()
165
- }));
166
-
167
- Logger.table(tableData);
168
-
169
- console.log('');
170
- Logger.dim('Use `mcphost disconnect <slug>` to remove a connection');
171
- });
172
- }