metamcp-cli 0.1.0
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 +154 -0
- package/dist/index.js +912 -0
- package/dist/index.js.map +1 -0
- package/package.json +38 -0
package/README.md
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# metamcp-cli
|
|
2
|
+
|
|
3
|
+
CLI wrapper for [MetaMCP](https://github.com/metatool-ai/metamcp) — auto-detect your IDEs and configure them to use your MetaMCP instance in seconds.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g metamcp-cli
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
> Requires Node.js >= 18 and [uv](https://docs.astral.sh/uv/) (`uvx` must be available for Claude Code / Claude Desktop).
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# Interactive wizard — does everything in one step
|
|
17
|
+
metamcp-cli setup
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Or step by step:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
# 1. Connect to your MetaMCP instance
|
|
24
|
+
metamcp-cli init
|
|
25
|
+
|
|
26
|
+
# 2. See what IDEs you have installed
|
|
27
|
+
metamcp-cli scan
|
|
28
|
+
|
|
29
|
+
# 3. List available endpoints
|
|
30
|
+
metamcp-cli endpoints
|
|
31
|
+
|
|
32
|
+
# 4. Configure your IDEs to use an endpoint
|
|
33
|
+
metamcp-cli use my-endpoint
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Commands
|
|
37
|
+
|
|
38
|
+
| Command | Description |
|
|
39
|
+
|---------|-------------|
|
|
40
|
+
| `setup` | Interactive wizard: connect, pick endpoint, configure IDEs |
|
|
41
|
+
| `init` | Configure MetaMCP instance URL and API key |
|
|
42
|
+
| `scan` | Detect installed MCP clients (IDEs) |
|
|
43
|
+
| `endpoints` | List available MetaMCP endpoints |
|
|
44
|
+
| `namespaces` | List namespaces (requires session auth) |
|
|
45
|
+
| `use <endpoint>` | Configure detected clients to use a MetaMCP endpoint |
|
|
46
|
+
| `status` | Show current configuration and connection status |
|
|
47
|
+
|
|
48
|
+
## Supported Clients
|
|
49
|
+
|
|
50
|
+
| Client | Config Location | Transport |
|
|
51
|
+
|--------|----------------|-----------|
|
|
52
|
+
| Claude Code | `.mcp.json` (project dir) | `uvx mcp-proxy` (streamable HTTP) |
|
|
53
|
+
| VS Code | `.vscode/mcp.json` (project dir) | SSE |
|
|
54
|
+
| Claude Desktop | Global config | `uvx mcp-proxy` (streamable HTTP) |
|
|
55
|
+
| Cursor | `~/.cursor/mcp.json` | SSE |
|
|
56
|
+
| Windsurf | `~/.codeium/windsurf/mcp_config.json` | SSE |
|
|
57
|
+
| Cline | VS Code extension settings | `npx mcp-remote` |
|
|
58
|
+
|
|
59
|
+
## Example
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
$ metamcp-cli setup
|
|
63
|
+
|
|
64
|
+
⚡ MetaMCP Quick Setup
|
|
65
|
+
|
|
66
|
+
? MetaMCP instance URL: https://metamcp.example.com
|
|
67
|
+
? API Key: ****
|
|
68
|
+
✔ Connected to MetaMCP
|
|
69
|
+
|
|
70
|
+
? Select endpoint to use:
|
|
71
|
+
> my-workspace (production) — Production tools
|
|
72
|
+
dev-tools (development) — Dev and testing
|
|
73
|
+
|
|
74
|
+
? Select clients to configure:
|
|
75
|
+
[x] Claude Code
|
|
76
|
+
[x] Cursor
|
|
77
|
+
|
|
78
|
+
✔ Claude Code configured
|
|
79
|
+
✔ Cursor configured
|
|
80
|
+
|
|
81
|
+
✓ Setup complete!
|
|
82
|
+
Instance: https://metamcp.example.com
|
|
83
|
+
Endpoint: my-workspace
|
|
84
|
+
Clients: Claude Code, Cursor
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Generated Configs
|
|
88
|
+
|
|
89
|
+
**Claude Code / Claude Desktop** (`.mcp.json`):
|
|
90
|
+
```json
|
|
91
|
+
{
|
|
92
|
+
"mcpServers": {
|
|
93
|
+
"metamcp": {
|
|
94
|
+
"command": "uvx",
|
|
95
|
+
"args": [
|
|
96
|
+
"mcp-proxy",
|
|
97
|
+
"--transport",
|
|
98
|
+
"streamablehttp",
|
|
99
|
+
"https://metamcp.example.com/metamcp/my-endpoint/mcp"
|
|
100
|
+
],
|
|
101
|
+
"env": {
|
|
102
|
+
"API_ACCESS_TOKEN": "sk_mt_your_api_key_here"
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
**Cursor / VS Code** (SSE):
|
|
110
|
+
```json
|
|
111
|
+
{
|
|
112
|
+
"mcpServers": {
|
|
113
|
+
"metamcp": {
|
|
114
|
+
"url": "https://metamcp.example.com/metamcp/my-endpoint/sse",
|
|
115
|
+
"headers": {
|
|
116
|
+
"Authorization": "Bearer sk_mt_your_api_key_here"
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Options
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
metamcp-cli use <endpoint> --client cursor # Only configure Cursor
|
|
127
|
+
metamcp-cli use <endpoint> --force # Overwrite without asking
|
|
128
|
+
metamcp-cli init --insecure # Allow self-signed certs
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Prerequisites
|
|
132
|
+
|
|
133
|
+
- A running [MetaMCP](https://github.com/metatool-ai/metamcp) instance
|
|
134
|
+
- An API key generated in the MetaMCP dashboard
|
|
135
|
+
- `uvx` (from [uv](https://docs.astral.sh/uv/)) for Claude Code / Claude Desktop
|
|
136
|
+
- `npx` for Cline
|
|
137
|
+
|
|
138
|
+
## How It Works
|
|
139
|
+
|
|
140
|
+
1. Connects to your MetaMCP instance via its public API
|
|
141
|
+
2. Auto-detects which MCP-compatible IDEs are installed on your system
|
|
142
|
+
3. Writes the correct MCP server configuration to each client's config file
|
|
143
|
+
4. Creates backups (`.metamcp-backup`) before modifying any existing config
|
|
144
|
+
|
|
145
|
+
## Security
|
|
146
|
+
|
|
147
|
+
- Config stored at `~/.metamcp-cli/config.json` with `0600` permissions
|
|
148
|
+
- API keys are never logged to stdout
|
|
149
|
+
- Automatic backup before modifying IDE configs
|
|
150
|
+
- API key input is masked during entry
|
|
151
|
+
|
|
152
|
+
## License
|
|
153
|
+
|
|
154
|
+
MIT
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,912 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { Command } from "commander";
|
|
5
|
+
import chalk8 from "chalk";
|
|
6
|
+
|
|
7
|
+
// src/commands/init.ts
|
|
8
|
+
import { input, select, password } from "@inquirer/prompts";
|
|
9
|
+
import chalk from "chalk";
|
|
10
|
+
import ora from "ora";
|
|
11
|
+
|
|
12
|
+
// src/api/metamcp.ts
|
|
13
|
+
var MetaMCPClient = class {
|
|
14
|
+
baseUrl;
|
|
15
|
+
apiKey;
|
|
16
|
+
sessionCookie;
|
|
17
|
+
proxyHeaders;
|
|
18
|
+
constructor(baseUrl, apiKey, sessionCookie, proxyHeaders) {
|
|
19
|
+
this.baseUrl = baseUrl.replace(/\/+$/, "");
|
|
20
|
+
this.apiKey = apiKey;
|
|
21
|
+
this.sessionCookie = sessionCookie;
|
|
22
|
+
this.proxyHeaders = proxyHeaders;
|
|
23
|
+
}
|
|
24
|
+
headers() {
|
|
25
|
+
const h = {
|
|
26
|
+
"Content-Type": "application/json",
|
|
27
|
+
...this.proxyHeaders
|
|
28
|
+
};
|
|
29
|
+
if (this.apiKey) {
|
|
30
|
+
h["Authorization"] = `Bearer ${this.apiKey}`;
|
|
31
|
+
}
|
|
32
|
+
if (this.sessionCookie) {
|
|
33
|
+
h["Cookie"] = this.sessionCookie;
|
|
34
|
+
}
|
|
35
|
+
return h;
|
|
36
|
+
}
|
|
37
|
+
async healthCheck() {
|
|
38
|
+
try {
|
|
39
|
+
const res = await fetch(`${this.baseUrl}/health`, {
|
|
40
|
+
headers: this.headers()
|
|
41
|
+
});
|
|
42
|
+
return res.ok;
|
|
43
|
+
} catch {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
async listPublicEndpoints() {
|
|
48
|
+
const res = await fetch(`${this.baseUrl}/metamcp`, {
|
|
49
|
+
headers: this.headers()
|
|
50
|
+
});
|
|
51
|
+
if (!res.ok) {
|
|
52
|
+
throw new Error(
|
|
53
|
+
`Failed to list endpoints: ${res.status} ${res.statusText}`
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
const data = await res.json();
|
|
57
|
+
return data.endpoints ?? [];
|
|
58
|
+
}
|
|
59
|
+
async signIn(email, password3) {
|
|
60
|
+
const res = await fetch(`${this.baseUrl}/api/auth/sign-in/email`, {
|
|
61
|
+
method: "POST",
|
|
62
|
+
headers: { "Content-Type": "application/json" },
|
|
63
|
+
body: JSON.stringify({ email, password: password3 }),
|
|
64
|
+
redirect: "manual"
|
|
65
|
+
});
|
|
66
|
+
if (!res.ok && res.status !== 302) {
|
|
67
|
+
throw new Error(`Sign-in failed: ${res.status} ${res.statusText}`);
|
|
68
|
+
}
|
|
69
|
+
const cookies = res.headers.getSetCookie?.() ?? [];
|
|
70
|
+
if (cookies.length === 0) {
|
|
71
|
+
const setCookie = res.headers.get("set-cookie");
|
|
72
|
+
if (setCookie) return setCookie;
|
|
73
|
+
throw new Error("Sign-in succeeded but no session cookie was returned.");
|
|
74
|
+
}
|
|
75
|
+
return cookies.join("; ");
|
|
76
|
+
}
|
|
77
|
+
async listNamespaces() {
|
|
78
|
+
if (!this.sessionCookie) {
|
|
79
|
+
throw new Error(
|
|
80
|
+
"Namespace listing requires session auth. Run `metamcp-cli init` with email/password."
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
const res = await fetch(`${this.baseUrl}/trpc/frontend/namespaces.list`, {
|
|
84
|
+
headers: this.headers()
|
|
85
|
+
});
|
|
86
|
+
if (!res.ok) {
|
|
87
|
+
throw new Error(
|
|
88
|
+
`Failed to list namespaces: ${res.status} ${res.statusText}`
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
const data = await res.json();
|
|
92
|
+
return data.result?.data ?? [];
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
// src/config/store.ts
|
|
97
|
+
import fs from "fs";
|
|
98
|
+
import path from "path";
|
|
99
|
+
import os from "os";
|
|
100
|
+
var CONFIG_DIR = path.join(os.homedir(), ".metamcp-cli");
|
|
101
|
+
var CONFIG_FILE = path.join(CONFIG_DIR, "config.json");
|
|
102
|
+
function loadConfig() {
|
|
103
|
+
try {
|
|
104
|
+
if (!fs.existsSync(CONFIG_FILE)) return null;
|
|
105
|
+
const raw = fs.readFileSync(CONFIG_FILE, "utf-8");
|
|
106
|
+
return JSON.parse(raw);
|
|
107
|
+
} catch {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
function saveConfig(config) {
|
|
112
|
+
if (!fs.existsSync(CONFIG_DIR)) {
|
|
113
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
114
|
+
}
|
|
115
|
+
fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), {
|
|
116
|
+
mode: 384
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
function getConfigOrThrow() {
|
|
120
|
+
const config = loadConfig();
|
|
121
|
+
if (!config) {
|
|
122
|
+
throw new Error(
|
|
123
|
+
"MetaMCP CLI is not initialized. Run `metamcp-cli init` first."
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
return config;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// src/commands/init.ts
|
|
130
|
+
async function initCommand(options) {
|
|
131
|
+
console.log(chalk.bold("\n\u{1F527} MetaMCP CLI Setup\n"));
|
|
132
|
+
if (options.insecure) {
|
|
133
|
+
process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = "0";
|
|
134
|
+
}
|
|
135
|
+
const url = await input({
|
|
136
|
+
message: "MetaMCP instance URL:",
|
|
137
|
+
default: "http://localhost:12008",
|
|
138
|
+
validate: (val) => {
|
|
139
|
+
try {
|
|
140
|
+
new URL(val);
|
|
141
|
+
return true;
|
|
142
|
+
} catch {
|
|
143
|
+
return "Please enter a valid URL";
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
const baseUrl = url.replace(/\/+$/, "");
|
|
148
|
+
const authMethod = await select({
|
|
149
|
+
message: "Authentication method:",
|
|
150
|
+
choices: [
|
|
151
|
+
{ name: "API Key", value: "apikey" },
|
|
152
|
+
{ name: "Email / Password", value: "credentials" }
|
|
153
|
+
]
|
|
154
|
+
});
|
|
155
|
+
const config = {
|
|
156
|
+
version: 1,
|
|
157
|
+
instance: { url: baseUrl }
|
|
158
|
+
};
|
|
159
|
+
let apiKey;
|
|
160
|
+
let sessionCookie;
|
|
161
|
+
if (authMethod === "apikey") {
|
|
162
|
+
apiKey = await password({
|
|
163
|
+
message: "API Key:",
|
|
164
|
+
mask: "*"
|
|
165
|
+
});
|
|
166
|
+
config.instance.apiKey = apiKey;
|
|
167
|
+
} else {
|
|
168
|
+
const email = await input({ message: "Email:" });
|
|
169
|
+
const pass = await password({ message: "Password:", mask: "*" });
|
|
170
|
+
const spinner2 = ora("Signing in...").start();
|
|
171
|
+
const client2 = new MetaMCPClient(baseUrl);
|
|
172
|
+
try {
|
|
173
|
+
const cookie = await client2.signIn(email, pass);
|
|
174
|
+
spinner2.succeed("Signed in successfully");
|
|
175
|
+
sessionCookie = cookie;
|
|
176
|
+
config.instance.sessionCookie = cookie;
|
|
177
|
+
} catch (err) {
|
|
178
|
+
spinner2.fail(
|
|
179
|
+
`Sign-in failed: ${err instanceof Error ? err.message : String(err)}`
|
|
180
|
+
);
|
|
181
|
+
process.exit(1);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
const spinner = ora("Validating connection...").start();
|
|
185
|
+
const client = new MetaMCPClient(baseUrl, apiKey, sessionCookie);
|
|
186
|
+
const ok = await client.healthCheck();
|
|
187
|
+
if (!ok) {
|
|
188
|
+
spinner.fail(
|
|
189
|
+
"Could not connect to MetaMCP. Check the URL and ensure the server is running."
|
|
190
|
+
);
|
|
191
|
+
process.exit(1);
|
|
192
|
+
}
|
|
193
|
+
spinner.succeed("Connected to MetaMCP");
|
|
194
|
+
saveConfig(config);
|
|
195
|
+
console.log(chalk.green("\n\u2713 Configuration saved to ~/.metamcp-cli/config.json"));
|
|
196
|
+
console.log(chalk.dim("Next steps:"));
|
|
197
|
+
console.log(chalk.dim(" metamcp-cli setup \u2014 interactive setup wizard"));
|
|
198
|
+
console.log(chalk.dim(" metamcp-cli endpoints \u2014 list available endpoints"));
|
|
199
|
+
console.log(chalk.dim(" metamcp-cli use <name> \u2014 configure your IDEs\n"));
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// src/commands/scan.ts
|
|
203
|
+
import chalk2 from "chalk";
|
|
204
|
+
|
|
205
|
+
// src/clients/detector.ts
|
|
206
|
+
import fs2 from "fs";
|
|
207
|
+
import path2 from "path";
|
|
208
|
+
import os2 from "os";
|
|
209
|
+
import { execSync } from "child_process";
|
|
210
|
+
function getGlobalConfigPath(macPath, winPath, linuxPath) {
|
|
211
|
+
const home = os2.homedir();
|
|
212
|
+
const platform = process.platform;
|
|
213
|
+
let configPath;
|
|
214
|
+
if (platform === "darwin") {
|
|
215
|
+
configPath = path2.join(home, macPath);
|
|
216
|
+
} else if (platform === "win32") {
|
|
217
|
+
configPath = path2.join(home, winPath);
|
|
218
|
+
} else {
|
|
219
|
+
configPath = path2.join(home, linuxPath);
|
|
220
|
+
}
|
|
221
|
+
return fs2.existsSync(configPath) || fs2.existsSync(path2.dirname(configPath)) ? configPath : null;
|
|
222
|
+
}
|
|
223
|
+
function readJsonSafe(filePath) {
|
|
224
|
+
try {
|
|
225
|
+
if (!fs2.existsSync(filePath)) return null;
|
|
226
|
+
return JSON.parse(fs2.readFileSync(filePath, "utf-8"));
|
|
227
|
+
} catch {
|
|
228
|
+
return null;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
function safeWriteMcpConfig(configPath, serverKey, serverConfig) {
|
|
232
|
+
let existing = {};
|
|
233
|
+
if (fs2.existsSync(configPath)) {
|
|
234
|
+
fs2.copyFileSync(configPath, configPath + ".metamcp-backup");
|
|
235
|
+
existing = JSON.parse(fs2.readFileSync(configPath, "utf-8"));
|
|
236
|
+
}
|
|
237
|
+
if (!existing["mcpServers"] || typeof existing["mcpServers"] !== "object") {
|
|
238
|
+
existing["mcpServers"] = {};
|
|
239
|
+
}
|
|
240
|
+
existing["mcpServers"][serverKey] = serverConfig;
|
|
241
|
+
fs2.mkdirSync(path2.dirname(configPath), { recursive: true });
|
|
242
|
+
fs2.writeFileSync(configPath, JSON.stringify(existing, null, 2));
|
|
243
|
+
}
|
|
244
|
+
function hasMcpEntry(configPath, key) {
|
|
245
|
+
const data = readJsonSafe(configPath);
|
|
246
|
+
if (!data) return false;
|
|
247
|
+
const servers = data["mcpServers"];
|
|
248
|
+
return !!servers && key in servers;
|
|
249
|
+
}
|
|
250
|
+
function removeMcpEntry(configPath, key) {
|
|
251
|
+
if (!fs2.existsSync(configPath)) return;
|
|
252
|
+
const data = JSON.parse(fs2.readFileSync(configPath, "utf-8"));
|
|
253
|
+
if (data.mcpServers && key in data.mcpServers) {
|
|
254
|
+
fs2.copyFileSync(configPath, configPath + ".metamcp-backup");
|
|
255
|
+
delete data.mcpServers[key];
|
|
256
|
+
fs2.writeFileSync(configPath, JSON.stringify(data, null, 2));
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
function buildSseConfig(config) {
|
|
260
|
+
const entry = {
|
|
261
|
+
url: `${config.baseUrl}/metamcp/${config.endpointName}/sse`
|
|
262
|
+
};
|
|
263
|
+
if (config.apiKey) {
|
|
264
|
+
entry["headers"] = { Authorization: `Bearer ${config.apiKey}` };
|
|
265
|
+
}
|
|
266
|
+
return entry;
|
|
267
|
+
}
|
|
268
|
+
function buildMcpProxyConfig(config) {
|
|
269
|
+
const url = `${config.baseUrl}/metamcp/${config.endpointName}/mcp`;
|
|
270
|
+
const env = {};
|
|
271
|
+
if (config.apiKey) {
|
|
272
|
+
env["API_ACCESS_TOKEN"] = config.apiKey;
|
|
273
|
+
}
|
|
274
|
+
return {
|
|
275
|
+
command: "uvx",
|
|
276
|
+
args: ["mcp-proxy", "--transport", "streamablehttp", url],
|
|
277
|
+
env
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
function buildStdioBridgeConfig(config) {
|
|
281
|
+
const url = `${config.baseUrl}/metamcp/${config.endpointName}/mcp`;
|
|
282
|
+
const args = ["-y", "mcp-remote", url];
|
|
283
|
+
if (config.apiKey) {
|
|
284
|
+
args.push("--header", `Authorization:Bearer ${config.apiKey}`);
|
|
285
|
+
}
|
|
286
|
+
return { command: "npx", args };
|
|
287
|
+
}
|
|
288
|
+
var MCP_KEY = "metamcp";
|
|
289
|
+
function hasBinary(name) {
|
|
290
|
+
try {
|
|
291
|
+
execSync(`which ${name}`, { stdio: "ignore" });
|
|
292
|
+
return true;
|
|
293
|
+
} catch {
|
|
294
|
+
return false;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
function createClaudeDesktop() {
|
|
298
|
+
const slug = "claude-desktop";
|
|
299
|
+
const name = "Claude Desktop";
|
|
300
|
+
const getPath = () => getGlobalConfigPath(
|
|
301
|
+
"Library/Application Support/Claude/claude_desktop_config.json",
|
|
302
|
+
"AppData/Roaming/Claude/claude_desktop_config.json",
|
|
303
|
+
".config/Claude/claude_desktop_config.json"
|
|
304
|
+
);
|
|
305
|
+
return {
|
|
306
|
+
name,
|
|
307
|
+
slug,
|
|
308
|
+
getConfigPath: getPath,
|
|
309
|
+
isInstalled: () => getPath() !== null,
|
|
310
|
+
hasMetaMCPEntry: () => {
|
|
311
|
+
const p = getPath();
|
|
312
|
+
return p ? hasMcpEntry(p, MCP_KEY) : false;
|
|
313
|
+
},
|
|
314
|
+
writeMetaMCPEntry: (config) => {
|
|
315
|
+
const p = getPath();
|
|
316
|
+
if (!p) throw new Error(`${name} config path not found`);
|
|
317
|
+
safeWriteMcpConfig(p, MCP_KEY, buildMcpProxyConfig(config));
|
|
318
|
+
},
|
|
319
|
+
removeMetaMCPEntry: () => {
|
|
320
|
+
const p = getPath();
|
|
321
|
+
if (p) removeMcpEntry(p, MCP_KEY);
|
|
322
|
+
}
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
function createCursor() {
|
|
326
|
+
const slug = "cursor";
|
|
327
|
+
const name = "Cursor";
|
|
328
|
+
const getPath = () => getGlobalConfigPath(
|
|
329
|
+
".cursor/mcp.json",
|
|
330
|
+
".cursor/mcp.json",
|
|
331
|
+
".cursor/mcp.json"
|
|
332
|
+
);
|
|
333
|
+
return {
|
|
334
|
+
name,
|
|
335
|
+
slug,
|
|
336
|
+
getConfigPath: getPath,
|
|
337
|
+
isInstalled: () => getPath() !== null,
|
|
338
|
+
hasMetaMCPEntry: () => {
|
|
339
|
+
const p = getPath();
|
|
340
|
+
return p ? hasMcpEntry(p, MCP_KEY) : false;
|
|
341
|
+
},
|
|
342
|
+
writeMetaMCPEntry: (config) => {
|
|
343
|
+
const p = getPath();
|
|
344
|
+
if (!p) throw new Error(`${name} config path not found`);
|
|
345
|
+
safeWriteMcpConfig(p, MCP_KEY, buildSseConfig(config));
|
|
346
|
+
},
|
|
347
|
+
removeMetaMCPEntry: () => {
|
|
348
|
+
const p = getPath();
|
|
349
|
+
if (p) removeMcpEntry(p, MCP_KEY);
|
|
350
|
+
}
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
function createWindsurf() {
|
|
354
|
+
const slug = "windsurf";
|
|
355
|
+
const name = "Windsurf";
|
|
356
|
+
const getPath = () => getGlobalConfigPath(
|
|
357
|
+
".codeium/windsurf/mcp_config.json",
|
|
358
|
+
".codeium/windsurf/mcp_config.json",
|
|
359
|
+
".codeium/windsurf/mcp_config.json"
|
|
360
|
+
);
|
|
361
|
+
return {
|
|
362
|
+
name,
|
|
363
|
+
slug,
|
|
364
|
+
getConfigPath: getPath,
|
|
365
|
+
isInstalled: () => getPath() !== null,
|
|
366
|
+
hasMetaMCPEntry: () => {
|
|
367
|
+
const p = getPath();
|
|
368
|
+
return p ? hasMcpEntry(p, MCP_KEY) : false;
|
|
369
|
+
},
|
|
370
|
+
writeMetaMCPEntry: (config) => {
|
|
371
|
+
const p = getPath();
|
|
372
|
+
if (!p) throw new Error(`${name} config path not found`);
|
|
373
|
+
const entry = {
|
|
374
|
+
serverUrl: `${config.baseUrl}/metamcp/${config.endpointName}/sse`
|
|
375
|
+
};
|
|
376
|
+
safeWriteMcpConfig(p, MCP_KEY, entry);
|
|
377
|
+
},
|
|
378
|
+
removeMetaMCPEntry: () => {
|
|
379
|
+
const p = getPath();
|
|
380
|
+
if (p) removeMcpEntry(p, MCP_KEY);
|
|
381
|
+
}
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
function createCline() {
|
|
385
|
+
const slug = "cline";
|
|
386
|
+
const name = "Cline";
|
|
387
|
+
const getPath = () => getGlobalConfigPath(
|
|
388
|
+
"Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json",
|
|
389
|
+
"AppData/Roaming/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json",
|
|
390
|
+
".config/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json"
|
|
391
|
+
);
|
|
392
|
+
return {
|
|
393
|
+
name,
|
|
394
|
+
slug,
|
|
395
|
+
getConfigPath: getPath,
|
|
396
|
+
isInstalled: () => getPath() !== null,
|
|
397
|
+
hasMetaMCPEntry: () => {
|
|
398
|
+
const p = getPath();
|
|
399
|
+
return p ? hasMcpEntry(p, MCP_KEY) : false;
|
|
400
|
+
},
|
|
401
|
+
writeMetaMCPEntry: (config) => {
|
|
402
|
+
const p = getPath();
|
|
403
|
+
if (!p) throw new Error(`${name} config path not found`);
|
|
404
|
+
safeWriteMcpConfig(p, MCP_KEY, buildStdioBridgeConfig(config));
|
|
405
|
+
},
|
|
406
|
+
removeMetaMCPEntry: () => {
|
|
407
|
+
const p = getPath();
|
|
408
|
+
if (p) removeMcpEntry(p, MCP_KEY);
|
|
409
|
+
}
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
function createClaudeCode() {
|
|
413
|
+
const slug = "claude-code";
|
|
414
|
+
const name = "Claude Code";
|
|
415
|
+
const getPath = () => path2.join(process.cwd(), ".mcp.json");
|
|
416
|
+
return {
|
|
417
|
+
name,
|
|
418
|
+
slug,
|
|
419
|
+
getConfigPath: getPath,
|
|
420
|
+
isInstalled: () => hasBinary("claude"),
|
|
421
|
+
hasMetaMCPEntry: () => hasMcpEntry(getPath(), MCP_KEY),
|
|
422
|
+
writeMetaMCPEntry: (config) => {
|
|
423
|
+
safeWriteMcpConfig(getPath(), MCP_KEY, buildMcpProxyConfig(config));
|
|
424
|
+
},
|
|
425
|
+
removeMetaMCPEntry: () => removeMcpEntry(getPath(), MCP_KEY)
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
function createVSCode() {
|
|
429
|
+
const slug = "vscode";
|
|
430
|
+
const name = "VS Code";
|
|
431
|
+
const getPath = () => path2.join(process.cwd(), ".vscode", "mcp.json");
|
|
432
|
+
return {
|
|
433
|
+
name,
|
|
434
|
+
slug,
|
|
435
|
+
getConfigPath: getPath,
|
|
436
|
+
isInstalled: () => hasBinary("code"),
|
|
437
|
+
hasMetaMCPEntry: () => hasMcpEntry(getPath(), MCP_KEY),
|
|
438
|
+
writeMetaMCPEntry: (config) => {
|
|
439
|
+
safeWriteMcpConfig(getPath(), MCP_KEY, buildSseConfig(config));
|
|
440
|
+
},
|
|
441
|
+
removeMetaMCPEntry: () => removeMcpEntry(getPath(), MCP_KEY)
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
var ALL_CLIENTS = [
|
|
445
|
+
createClaudeCode(),
|
|
446
|
+
createVSCode(),
|
|
447
|
+
createClaudeDesktop(),
|
|
448
|
+
createCursor(),
|
|
449
|
+
createWindsurf(),
|
|
450
|
+
createCline()
|
|
451
|
+
];
|
|
452
|
+
function detectClients() {
|
|
453
|
+
return ALL_CLIENTS.filter((c) => c.isInstalled());
|
|
454
|
+
}
|
|
455
|
+
function getClientBySlug(slug) {
|
|
456
|
+
return ALL_CLIENTS.find((c) => c.slug === slug);
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// src/commands/scan.ts
|
|
460
|
+
async function scanCommand() {
|
|
461
|
+
console.log(chalk2.bold("\n\u{1F50D} Scanning for MCP clients...\n"));
|
|
462
|
+
const results = [];
|
|
463
|
+
for (const client of ALL_CLIENTS) {
|
|
464
|
+
const installed = client.isInstalled();
|
|
465
|
+
const configPath = client.getConfigPath();
|
|
466
|
+
const hasEntry = installed && client.hasMetaMCPEntry();
|
|
467
|
+
results.push({
|
|
468
|
+
name: client.name,
|
|
469
|
+
slug: client.slug,
|
|
470
|
+
status: installed ? chalk2.green("Found") : chalk2.dim("Not found"),
|
|
471
|
+
path: configPath ?? "-",
|
|
472
|
+
configured: hasEntry ? chalk2.green("Yes") : chalk2.dim("No")
|
|
473
|
+
});
|
|
474
|
+
}
|
|
475
|
+
const nameWidth = 16;
|
|
476
|
+
const statusWidth = 14;
|
|
477
|
+
const configuredWidth = 14;
|
|
478
|
+
console.log(
|
|
479
|
+
chalk2.bold(
|
|
480
|
+
"Client".padEnd(nameWidth) + "Status".padEnd(statusWidth) + "MetaMCP".padEnd(configuredWidth) + "Config Path"
|
|
481
|
+
)
|
|
482
|
+
);
|
|
483
|
+
console.log("\u2500".repeat(80));
|
|
484
|
+
for (const r of results) {
|
|
485
|
+
console.log(
|
|
486
|
+
r.name.padEnd(nameWidth) + r.status.padEnd(statusWidth + 10) + // extra for chalk escape codes
|
|
487
|
+
r.configured.padEnd(configuredWidth + 10) + chalk2.dim(r.path)
|
|
488
|
+
);
|
|
489
|
+
}
|
|
490
|
+
const config = loadConfig();
|
|
491
|
+
if (config) {
|
|
492
|
+
config.detectedClients = {};
|
|
493
|
+
for (const client of ALL_CLIENTS) {
|
|
494
|
+
const p = client.getConfigPath();
|
|
495
|
+
config.detectedClients[client.slug] = {
|
|
496
|
+
configPath: p ?? "",
|
|
497
|
+
detected: client.isInstalled()
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
saveConfig(config);
|
|
501
|
+
}
|
|
502
|
+
const found = ALL_CLIENTS.filter((c) => c.isInstalled()).length;
|
|
503
|
+
console.log(chalk2.dim(`
|
|
504
|
+
${found} client(s) detected.
|
|
505
|
+
`));
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// src/commands/endpoints.ts
|
|
509
|
+
import chalk3 from "chalk";
|
|
510
|
+
import ora2 from "ora";
|
|
511
|
+
|
|
512
|
+
// src/api/client-from-config.ts
|
|
513
|
+
function clientFromConfig(config) {
|
|
514
|
+
return new MetaMCPClient(
|
|
515
|
+
config.instance.url,
|
|
516
|
+
config.instance.apiKey,
|
|
517
|
+
config.instance.sessionCookie,
|
|
518
|
+
config.instance.proxyHeaders
|
|
519
|
+
);
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
// src/commands/endpoints.ts
|
|
523
|
+
async function endpointsCommand() {
|
|
524
|
+
const config = getConfigOrThrow();
|
|
525
|
+
const client = clientFromConfig(config);
|
|
526
|
+
const spinner = ora2("Fetching endpoints...").start();
|
|
527
|
+
try {
|
|
528
|
+
const endpoints = await client.listPublicEndpoints();
|
|
529
|
+
spinner.stop();
|
|
530
|
+
if (endpoints.length === 0) {
|
|
531
|
+
console.log(chalk3.yellow("\nNo public endpoints found."));
|
|
532
|
+
console.log(chalk3.dim("Create endpoints in the MetaMCP dashboard first.\n"));
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
535
|
+
console.log(chalk3.bold(`
|
|
536
|
+
\u{1F4E1} Endpoints (${endpoints.length})
|
|
537
|
+
`));
|
|
538
|
+
const nameWidth = 20;
|
|
539
|
+
const nsWidth = 20;
|
|
540
|
+
console.log(
|
|
541
|
+
chalk3.bold(
|
|
542
|
+
"Name".padEnd(nameWidth) + "Namespace".padEnd(nsWidth) + "URL"
|
|
543
|
+
)
|
|
544
|
+
);
|
|
545
|
+
console.log("\u2500".repeat(80));
|
|
546
|
+
for (const ep of endpoints) {
|
|
547
|
+
console.log(
|
|
548
|
+
ep.name.padEnd(nameWidth) + (ep.namespace ?? "-").padEnd(nsWidth) + chalk3.dim(ep.endpoints.mcp)
|
|
549
|
+
);
|
|
550
|
+
}
|
|
551
|
+
console.log();
|
|
552
|
+
} catch (err) {
|
|
553
|
+
spinner.fail(
|
|
554
|
+
`Failed to fetch endpoints: ${err instanceof Error ? err.message : String(err)}`
|
|
555
|
+
);
|
|
556
|
+
process.exit(1);
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
// src/commands/namespaces.ts
|
|
561
|
+
import chalk4 from "chalk";
|
|
562
|
+
import ora3 from "ora";
|
|
563
|
+
async function namespacesCommand() {
|
|
564
|
+
const config = getConfigOrThrow();
|
|
565
|
+
const client = clientFromConfig(config);
|
|
566
|
+
const spinner = ora3("Fetching namespaces...").start();
|
|
567
|
+
try {
|
|
568
|
+
const namespaces = await client.listNamespaces();
|
|
569
|
+
spinner.stop();
|
|
570
|
+
if (namespaces.length === 0) {
|
|
571
|
+
console.log(chalk4.yellow("\nNo namespaces found."));
|
|
572
|
+
return;
|
|
573
|
+
}
|
|
574
|
+
console.log(chalk4.bold(`
|
|
575
|
+
\u{1F4E6} Namespaces (${namespaces.length})
|
|
576
|
+
`));
|
|
577
|
+
const nameWidth = 24;
|
|
578
|
+
const scopeWidth = 12;
|
|
579
|
+
console.log(
|
|
580
|
+
chalk4.bold(
|
|
581
|
+
"Name".padEnd(nameWidth) + "Scope".padEnd(scopeWidth) + "Description"
|
|
582
|
+
)
|
|
583
|
+
);
|
|
584
|
+
console.log("\u2500".repeat(70));
|
|
585
|
+
for (const ns of namespaces) {
|
|
586
|
+
console.log(
|
|
587
|
+
ns.name.padEnd(nameWidth) + (ns.isPublic ? "public" : "private").padEnd(scopeWidth) + chalk4.dim(ns.description ?? "-")
|
|
588
|
+
);
|
|
589
|
+
}
|
|
590
|
+
console.log();
|
|
591
|
+
} catch (err) {
|
|
592
|
+
spinner.fail(
|
|
593
|
+
`Failed to fetch namespaces: ${err instanceof Error ? err.message : String(err)}`
|
|
594
|
+
);
|
|
595
|
+
process.exit(1);
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
// src/commands/use.ts
|
|
600
|
+
import chalk5 from "chalk";
|
|
601
|
+
import ora4 from "ora";
|
|
602
|
+
import { confirm, checkbox } from "@inquirer/prompts";
|
|
603
|
+
async function useCommand(endpointName, options) {
|
|
604
|
+
const config = getConfigOrThrow();
|
|
605
|
+
const apiClient = clientFromConfig(config);
|
|
606
|
+
const spinner = ora4("Validating endpoint...").start();
|
|
607
|
+
let endpoints;
|
|
608
|
+
try {
|
|
609
|
+
endpoints = await apiClient.listPublicEndpoints();
|
|
610
|
+
} catch (err) {
|
|
611
|
+
spinner.fail(
|
|
612
|
+
`Failed to fetch endpoints: ${err instanceof Error ? err.message : String(err)}`
|
|
613
|
+
);
|
|
614
|
+
process.exit(1);
|
|
615
|
+
}
|
|
616
|
+
const endpoint = endpoints.find((e) => e.name === endpointName);
|
|
617
|
+
if (!endpoint) {
|
|
618
|
+
spinner.fail(`Endpoint "${endpointName}" not found.`);
|
|
619
|
+
console.log(
|
|
620
|
+
chalk5.dim(
|
|
621
|
+
"Available endpoints: " + endpoints.map((e) => e.name).join(", ")
|
|
622
|
+
)
|
|
623
|
+
);
|
|
624
|
+
process.exit(1);
|
|
625
|
+
}
|
|
626
|
+
spinner.succeed(`Endpoint "${endpointName}" found`);
|
|
627
|
+
let targets;
|
|
628
|
+
if (options.client) {
|
|
629
|
+
const c = getClientBySlug(options.client);
|
|
630
|
+
if (!c) {
|
|
631
|
+
console.log(
|
|
632
|
+
chalk5.red(`Unknown client "${options.client}".`) + chalk5.dim(
|
|
633
|
+
" Available: claude-desktop, cursor, windsurf, cline, claude-code"
|
|
634
|
+
)
|
|
635
|
+
);
|
|
636
|
+
process.exit(1);
|
|
637
|
+
}
|
|
638
|
+
if (!c.isInstalled()) {
|
|
639
|
+
console.log(chalk5.red(`${c.name} is not installed or detected on this system.`));
|
|
640
|
+
process.exit(1);
|
|
641
|
+
}
|
|
642
|
+
targets = [c];
|
|
643
|
+
} else {
|
|
644
|
+
const detected = detectClients();
|
|
645
|
+
if (detected.length === 0) {
|
|
646
|
+
console.log(chalk5.yellow("No MCP clients detected. Run `metamcp-cli scan` to check."));
|
|
647
|
+
process.exit(1);
|
|
648
|
+
}
|
|
649
|
+
const selected = await checkbox({
|
|
650
|
+
message: "Select clients to configure:",
|
|
651
|
+
choices: detected.map((c) => ({
|
|
652
|
+
name: `${c.name}${c.hasMetaMCPEntry() ? chalk5.dim(" (already configured)") : ""}`,
|
|
653
|
+
value: c.slug,
|
|
654
|
+
checked: true
|
|
655
|
+
}))
|
|
656
|
+
});
|
|
657
|
+
if (selected.length === 0) {
|
|
658
|
+
console.log(chalk5.yellow("No clients selected."));
|
|
659
|
+
return;
|
|
660
|
+
}
|
|
661
|
+
targets = selected.map((slug) => getClientBySlug(slug)).filter((c) => c !== void 0);
|
|
662
|
+
}
|
|
663
|
+
const endpointConfig = {
|
|
664
|
+
baseUrl: config.instance.url,
|
|
665
|
+
endpointName,
|
|
666
|
+
apiKey: config.instance.apiKey
|
|
667
|
+
};
|
|
668
|
+
for (const client of targets) {
|
|
669
|
+
const hasExisting = client.hasMetaMCPEntry();
|
|
670
|
+
if (hasExisting && !options.force) {
|
|
671
|
+
const overwrite = await confirm({
|
|
672
|
+
message: `${client.name} already has a MetaMCP config. Overwrite?`,
|
|
673
|
+
default: true
|
|
674
|
+
});
|
|
675
|
+
if (!overwrite) {
|
|
676
|
+
console.log(chalk5.dim(` Skipped ${client.name}`));
|
|
677
|
+
continue;
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
try {
|
|
681
|
+
const s = ora4(`Configuring ${client.name}...`).start();
|
|
682
|
+
client.writeMetaMCPEntry(endpointConfig);
|
|
683
|
+
s.succeed(`${client.name} configured`);
|
|
684
|
+
} catch (err) {
|
|
685
|
+
console.log(
|
|
686
|
+
chalk5.red(
|
|
687
|
+
` Failed to configure ${client.name}: ${err instanceof Error ? err.message : String(err)}`
|
|
688
|
+
)
|
|
689
|
+
);
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
config.activeEndpoint = endpointName;
|
|
693
|
+
saveConfig(config);
|
|
694
|
+
console.log(chalk5.green(`
|
|
695
|
+
\u2713 Active endpoint set to "${endpointName}"`));
|
|
696
|
+
console.log(chalk5.dim("Restart your IDE(s) for the changes to take effect.\n"));
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
// src/commands/status.ts
|
|
700
|
+
import chalk6 from "chalk";
|
|
701
|
+
import ora5 from "ora";
|
|
702
|
+
async function statusCommand() {
|
|
703
|
+
const config = loadConfig();
|
|
704
|
+
if (!config) {
|
|
705
|
+
console.log(chalk6.yellow("\nMetaMCP CLI is not initialized."));
|
|
706
|
+
console.log(chalk6.dim("Run `metamcp-cli init` to get started.\n"));
|
|
707
|
+
return;
|
|
708
|
+
}
|
|
709
|
+
console.log(chalk6.bold("\n\u{1F4CA} MetaMCP CLI Status\n"));
|
|
710
|
+
console.log(chalk6.bold("Instance"));
|
|
711
|
+
console.log(` URL: ${config.instance.url}`);
|
|
712
|
+
console.log(
|
|
713
|
+
` Auth: ${config.instance.apiKey ? "API Key" : config.instance.sessionCookie ? "Session" : chalk6.yellow("Not configured")}`
|
|
714
|
+
);
|
|
715
|
+
const spinner = ora5(" Checking connection...").start();
|
|
716
|
+
const client = clientFromConfig(config);
|
|
717
|
+
const healthy = await client.healthCheck();
|
|
718
|
+
if (healthy) {
|
|
719
|
+
spinner.succeed(" Connection: OK");
|
|
720
|
+
} else {
|
|
721
|
+
spinner.fail(" Connection: Failed");
|
|
722
|
+
}
|
|
723
|
+
console.log(
|
|
724
|
+
`
|
|
725
|
+
${chalk6.bold("Active Endpoint")}: ${config.activeEndpoint ?? chalk6.dim("none")}`
|
|
726
|
+
);
|
|
727
|
+
console.log(chalk6.bold("\nClients"));
|
|
728
|
+
for (const c of ALL_CLIENTS) {
|
|
729
|
+
const installed = c.isInstalled();
|
|
730
|
+
const configured = installed && c.hasMetaMCPEntry();
|
|
731
|
+
const statusStr = !installed ? chalk6.dim("not found") : configured ? chalk6.green("configured") : chalk6.yellow("detected");
|
|
732
|
+
console.log(` ${c.name.padEnd(16)} ${statusStr}`);
|
|
733
|
+
}
|
|
734
|
+
console.log();
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
// src/commands/setup.ts
|
|
738
|
+
import { input as input2, select as select2, password as password2, checkbox as checkbox2, confirm as confirm2 } from "@inquirer/prompts";
|
|
739
|
+
import chalk7 from "chalk";
|
|
740
|
+
import ora6 from "ora";
|
|
741
|
+
async function setupCommand(options) {
|
|
742
|
+
console.log(chalk7.bold("\n\u26A1 MetaMCP Quick Setup\n"));
|
|
743
|
+
if (options.insecure) {
|
|
744
|
+
process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = "0";
|
|
745
|
+
}
|
|
746
|
+
let config = loadConfig();
|
|
747
|
+
let apiClient;
|
|
748
|
+
if (config) {
|
|
749
|
+
console.log(chalk7.dim(`Using existing config: ${config.instance.url}`));
|
|
750
|
+
apiClient = clientFromConfig(config);
|
|
751
|
+
const healthy = await apiClient.healthCheck();
|
|
752
|
+
if (!healthy) {
|
|
753
|
+
console.log(chalk7.yellow("Cannot connect to saved instance. Let's reconfigure.\n"));
|
|
754
|
+
config = null;
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
if (!config) {
|
|
758
|
+
const url = await input2({
|
|
759
|
+
message: "MetaMCP instance URL:",
|
|
760
|
+
default: "http://localhost:12008",
|
|
761
|
+
validate: (val) => {
|
|
762
|
+
try {
|
|
763
|
+
new URL(val);
|
|
764
|
+
return true;
|
|
765
|
+
} catch {
|
|
766
|
+
return "Please enter a valid URL";
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
});
|
|
770
|
+
const baseUrl = url.replace(/\/+$/, "");
|
|
771
|
+
const apiKey = await password2({
|
|
772
|
+
message: "API Key:",
|
|
773
|
+
mask: "*"
|
|
774
|
+
});
|
|
775
|
+
const spinner2 = ora6("Connecting...").start();
|
|
776
|
+
apiClient = new MetaMCPClient(baseUrl, apiKey);
|
|
777
|
+
const healthy = await apiClient.healthCheck();
|
|
778
|
+
if (!healthy) {
|
|
779
|
+
spinner2.fail("Could not connect. Check URL and API key.");
|
|
780
|
+
process.exit(1);
|
|
781
|
+
}
|
|
782
|
+
spinner2.succeed("Connected to MetaMCP");
|
|
783
|
+
config = {
|
|
784
|
+
version: 1,
|
|
785
|
+
instance: { url: baseUrl, apiKey }
|
|
786
|
+
};
|
|
787
|
+
saveConfig(config);
|
|
788
|
+
}
|
|
789
|
+
const spinner = ora6("Fetching endpoints...").start();
|
|
790
|
+
let endpoints;
|
|
791
|
+
try {
|
|
792
|
+
endpoints = await apiClient.listPublicEndpoints();
|
|
793
|
+
} catch (err) {
|
|
794
|
+
spinner.fail(`Failed to fetch endpoints: ${err instanceof Error ? err.message : String(err)}`);
|
|
795
|
+
process.exit(1);
|
|
796
|
+
}
|
|
797
|
+
spinner.stop();
|
|
798
|
+
if (endpoints.length === 0) {
|
|
799
|
+
console.log(chalk7.yellow("\nNo endpoints found. Create one in the MetaMCP dashboard first.\n"));
|
|
800
|
+
process.exit(1);
|
|
801
|
+
}
|
|
802
|
+
const selectedEndpoint = await select2({
|
|
803
|
+
message: "Select endpoint to use:",
|
|
804
|
+
choices: endpoints.map((ep) => ({
|
|
805
|
+
name: `${ep.name}${ep.namespace ? chalk7.dim(` (${ep.namespace})`) : ""}${ep.description ? chalk7.dim(` \u2014 ${ep.description}`) : ""}`,
|
|
806
|
+
value: ep.name
|
|
807
|
+
}))
|
|
808
|
+
});
|
|
809
|
+
const detected = detectClients();
|
|
810
|
+
if (detected.length === 0) {
|
|
811
|
+
console.log(chalk7.yellow("\nNo MCP clients detected on this system."));
|
|
812
|
+
console.log(chalk7.dim("Supported: Claude Desktop, Cursor, Windsurf, Cline, Claude Code\n"));
|
|
813
|
+
config.activeEndpoint = selectedEndpoint;
|
|
814
|
+
saveConfig(config);
|
|
815
|
+
process.exit(1);
|
|
816
|
+
}
|
|
817
|
+
const selectedClients = await checkbox2({
|
|
818
|
+
message: "Select clients to configure:",
|
|
819
|
+
choices: detected.map((c) => ({
|
|
820
|
+
name: `${c.name}${c.hasMetaMCPEntry() ? chalk7.dim(" (already configured)") : ""}`,
|
|
821
|
+
value: c.slug,
|
|
822
|
+
checked: true
|
|
823
|
+
}))
|
|
824
|
+
});
|
|
825
|
+
if (selectedClients.length === 0) {
|
|
826
|
+
console.log(chalk7.yellow("No clients selected."));
|
|
827
|
+
config.activeEndpoint = selectedEndpoint;
|
|
828
|
+
saveConfig(config);
|
|
829
|
+
return;
|
|
830
|
+
}
|
|
831
|
+
const targets = selectedClients.map((slug) => getClientBySlug(slug)).filter((c) => c !== void 0);
|
|
832
|
+
const endpointConfig = {
|
|
833
|
+
baseUrl: config.instance.url,
|
|
834
|
+
endpointName: selectedEndpoint,
|
|
835
|
+
apiKey: config.instance.apiKey
|
|
836
|
+
};
|
|
837
|
+
console.log();
|
|
838
|
+
for (const client of targets) {
|
|
839
|
+
const hasExisting = client.hasMetaMCPEntry();
|
|
840
|
+
if (hasExisting) {
|
|
841
|
+
const overwrite = await confirm2({
|
|
842
|
+
message: `${client.name} already configured. Overwrite?`,
|
|
843
|
+
default: true
|
|
844
|
+
});
|
|
845
|
+
if (!overwrite) {
|
|
846
|
+
console.log(chalk7.dim(` Skipped ${client.name}`));
|
|
847
|
+
continue;
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
try {
|
|
851
|
+
const s = ora6(`Configuring ${client.name}...`).start();
|
|
852
|
+
client.writeMetaMCPEntry(endpointConfig);
|
|
853
|
+
s.succeed(`${client.name} configured`);
|
|
854
|
+
} catch (err) {
|
|
855
|
+
console.log(
|
|
856
|
+
chalk7.red(` Failed: ${client.name} \u2014 ${err instanceof Error ? err.message : String(err)}`)
|
|
857
|
+
);
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
config.activeEndpoint = selectedEndpoint;
|
|
861
|
+
saveConfig(config);
|
|
862
|
+
console.log(chalk7.green(`
|
|
863
|
+
\u2713 Setup complete!`));
|
|
864
|
+
console.log(chalk7.dim(` Instance: ${config.instance.url}`));
|
|
865
|
+
console.log(chalk7.dim(` Endpoint: ${selectedEndpoint}`));
|
|
866
|
+
console.log(chalk7.dim(` Clients: ${targets.map((c) => c.name).join(", ")}`));
|
|
867
|
+
console.log(chalk7.dim("\nRestart your IDE(s) for changes to take effect.\n"));
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
// src/index.ts
|
|
871
|
+
var program = new Command();
|
|
872
|
+
program.name("metamcp-cli").description("CLI wrapper for MetaMCP \u2014 auto-configure MCP clients").version("0.1.0");
|
|
873
|
+
program.command("setup").description("Interactive setup wizard \u2014 connect, pick endpoint, configure IDEs").option("--insecure", "Allow self-signed SSL certificates").action(async (options) => {
|
|
874
|
+
await withErrorHandling(() => setupCommand(options));
|
|
875
|
+
});
|
|
876
|
+
program.command("init").description("Initialize MetaMCP CLI with your instance URL and credentials").option("--insecure", "Allow self-signed SSL certificates").action(async (options) => {
|
|
877
|
+
await withErrorHandling(() => initCommand(options));
|
|
878
|
+
});
|
|
879
|
+
program.command("scan").description("Detect installed MCP clients (IDEs)").action(async () => {
|
|
880
|
+
await withErrorHandling(scanCommand);
|
|
881
|
+
});
|
|
882
|
+
program.command("endpoints").description("List available MetaMCP endpoints").action(async () => {
|
|
883
|
+
await withErrorHandling(endpointsCommand);
|
|
884
|
+
});
|
|
885
|
+
program.command("namespaces").description("List available MetaMCP namespaces (requires session auth)").action(async () => {
|
|
886
|
+
await withErrorHandling(namespacesCommand);
|
|
887
|
+
});
|
|
888
|
+
program.command("use").argument("<endpoint>", "Name of the MetaMCP endpoint to use").description("Configure detected MCP clients to use a MetaMCP endpoint").option("-c, --client <slug>", "Only configure a specific client").option("-f, --force", "Overwrite existing MetaMCP config without asking").action(async (endpoint, options) => {
|
|
889
|
+
await withErrorHandling(() => useCommand(endpoint, options));
|
|
890
|
+
});
|
|
891
|
+
program.command("status").description("Show current MetaMCP CLI configuration and status").action(async () => {
|
|
892
|
+
await withErrorHandling(statusCommand);
|
|
893
|
+
});
|
|
894
|
+
async function withErrorHandling(fn) {
|
|
895
|
+
try {
|
|
896
|
+
await fn();
|
|
897
|
+
} catch (err) {
|
|
898
|
+
if (err instanceof Error) {
|
|
899
|
+
console.error(chalk8.red(`
|
|
900
|
+
Error: ${err.message}`));
|
|
901
|
+
if (process.env["DEBUG"]) {
|
|
902
|
+
console.error(chalk8.dim(err.stack));
|
|
903
|
+
}
|
|
904
|
+
} else {
|
|
905
|
+
console.error(chalk8.red(`
|
|
906
|
+
Error: ${String(err)}`));
|
|
907
|
+
}
|
|
908
|
+
process.exit(1);
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
program.parse();
|
|
912
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/commands/init.ts","../src/api/metamcp.ts","../src/config/store.ts","../src/commands/scan.ts","../src/clients/detector.ts","../src/commands/endpoints.ts","../src/api/client-from-config.ts","../src/commands/namespaces.ts","../src/commands/use.ts","../src/commands/status.ts","../src/commands/setup.ts"],"sourcesContent":["import { Command } from 'commander';\nimport chalk from 'chalk';\nimport { initCommand } from './commands/init.js';\nimport { scanCommand } from './commands/scan.js';\nimport { endpointsCommand } from './commands/endpoints.js';\nimport { namespacesCommand } from './commands/namespaces.js';\nimport { useCommand } from './commands/use.js';\nimport { statusCommand } from './commands/status.js';\nimport { setupCommand } from './commands/setup.js';\n\nconst program = new Command();\n\nprogram\n .name('metamcp-cli')\n .description('CLI wrapper for MetaMCP — auto-configure MCP clients')\n .version('0.1.0');\n\nprogram\n .command('setup')\n .description('Interactive setup wizard — connect, pick endpoint, configure IDEs')\n .option('--insecure', 'Allow self-signed SSL certificates')\n .action(async (options) => {\n await withErrorHandling(() => setupCommand(options));\n });\n\nprogram\n .command('init')\n .description('Initialize MetaMCP CLI with your instance URL and credentials')\n .option('--insecure', 'Allow self-signed SSL certificates')\n .action(async (options) => {\n await withErrorHandling(() => initCommand(options));\n });\n\nprogram\n .command('scan')\n .description('Detect installed MCP clients (IDEs)')\n .action(async () => {\n await withErrorHandling(scanCommand);\n });\n\nprogram\n .command('endpoints')\n .description('List available MetaMCP endpoints')\n .action(async () => {\n await withErrorHandling(endpointsCommand);\n });\n\nprogram\n .command('namespaces')\n .description('List available MetaMCP namespaces (requires session auth)')\n .action(async () => {\n await withErrorHandling(namespacesCommand);\n });\n\nprogram\n .command('use')\n .argument('<endpoint>', 'Name of the MetaMCP endpoint to use')\n .description('Configure detected MCP clients to use a MetaMCP endpoint')\n .option('-c, --client <slug>', 'Only configure a specific client')\n .option('-f, --force', 'Overwrite existing MetaMCP config without asking')\n .action(async (endpoint, options) => {\n await withErrorHandling(() => useCommand(endpoint, options));\n });\n\nprogram\n .command('status')\n .description('Show current MetaMCP CLI configuration and status')\n .action(async () => {\n await withErrorHandling(statusCommand);\n });\n\nasync function withErrorHandling(fn: () => Promise<void>): Promise<void> {\n try {\n await fn();\n } catch (err) {\n if (err instanceof Error) {\n console.error(chalk.red(`\\nError: ${err.message}`));\n if (process.env['DEBUG']) {\n console.error(chalk.dim(err.stack));\n }\n } else {\n console.error(chalk.red(`\\nError: ${String(err)}`));\n }\n process.exit(1);\n }\n}\n\nprogram.parse();\n","import { input, select, password } from '@inquirer/prompts';\nimport chalk from 'chalk';\nimport ora from 'ora';\nimport { MetaMCPClient } from '../api/metamcp.js';\nimport { saveConfig, type MetaMCPConfig } from '../config/store.js';\n\nexport async function initCommand(options: { insecure?: boolean }): Promise<void> {\n console.log(chalk.bold('\\n🔧 MetaMCP CLI Setup\\n'));\n\n if (options.insecure) {\n process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';\n }\n\n const url = await input({\n message: 'MetaMCP instance URL:',\n default: 'http://localhost:12008',\n validate: (val) => {\n try {\n new URL(val);\n return true;\n } catch {\n return 'Please enter a valid URL';\n }\n },\n });\n\n const baseUrl = url.replace(/\\/+$/, '');\n\n const authMethod = await select({\n message: 'Authentication method:',\n choices: [\n { name: 'API Key', value: 'apikey' },\n { name: 'Email / Password', value: 'credentials' },\n ],\n });\n\n const config: MetaMCPConfig = {\n version: 1,\n instance: { url: baseUrl },\n };\n\n let apiKey: string | undefined;\n let sessionCookie: string | undefined;\n\n if (authMethod === 'apikey') {\n apiKey = await password({\n message: 'API Key:',\n mask: '*',\n });\n config.instance.apiKey = apiKey;\n } else {\n const email = await input({ message: 'Email:' });\n const pass = await password({ message: 'Password:', mask: '*' });\n\n const spinner = ora('Signing in...').start();\n const client = new MetaMCPClient(baseUrl);\n\n try {\n const cookie = await client.signIn(email, pass);\n spinner.succeed('Signed in successfully');\n sessionCookie = cookie;\n config.instance.sessionCookie = cookie;\n } catch (err) {\n spinner.fail(\n `Sign-in failed: ${err instanceof Error ? err.message : String(err)}`\n );\n process.exit(1);\n }\n }\n\n // Validate connection\n const spinner = ora('Validating connection...').start();\n const client = new MetaMCPClient(baseUrl, apiKey, sessionCookie);\n const ok = await client.healthCheck();\n\n if (!ok) {\n spinner.fail(\n 'Could not connect to MetaMCP. Check the URL and ensure the server is running.'\n );\n process.exit(1);\n }\n\n spinner.succeed('Connected to MetaMCP');\n\n saveConfig(config);\n console.log(chalk.green('\\n✓ Configuration saved to ~/.metamcp-cli/config.json'));\n console.log(chalk.dim('Next steps:'));\n console.log(chalk.dim(' metamcp-cli setup — interactive setup wizard'));\n console.log(chalk.dim(' metamcp-cli endpoints — list available endpoints'));\n console.log(chalk.dim(' metamcp-cli use <name> — configure your IDEs\\n'));\n}\n","export interface PublicEndpoint {\n name: string;\n description?: string;\n namespace?: string;\n endpoints: {\n mcp: string;\n sse: string;\n api: string;\n };\n}\n\nexport interface Namespace {\n id: string;\n name: string;\n description?: string;\n isPublic: boolean;\n createdAt: string;\n}\n\nexport class MetaMCPClient {\n private baseUrl: string;\n private apiKey?: string;\n private sessionCookie?: string;\n private proxyHeaders?: Record<string, string>;\n\n constructor(\n baseUrl: string,\n apiKey?: string,\n sessionCookie?: string,\n proxyHeaders?: Record<string, string>,\n ) {\n this.baseUrl = baseUrl.replace(/\\/+$/, \"\");\n this.apiKey = apiKey;\n this.sessionCookie = sessionCookie;\n this.proxyHeaders = proxyHeaders;\n }\n\n private headers(): Record<string, string> {\n const h: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n ...this.proxyHeaders,\n };\n if (this.apiKey) {\n h[\"Authorization\"] = `Bearer ${this.apiKey}`;\n }\n if (this.sessionCookie) {\n h[\"Cookie\"] = this.sessionCookie;\n }\n return h;\n }\n\n async healthCheck(): Promise<boolean> {\n try {\n const res = await fetch(`${this.baseUrl}/health`, {\n headers: this.headers(),\n });\n return res.ok;\n } catch {\n return false;\n }\n }\n\n async listPublicEndpoints(): Promise<PublicEndpoint[]> {\n const res = await fetch(`${this.baseUrl}/metamcp`, {\n headers: this.headers(),\n });\n if (!res.ok) {\n throw new Error(\n `Failed to list endpoints: ${res.status} ${res.statusText}`,\n );\n }\n const data = (await res.json()) as { endpoints?: PublicEndpoint[] };\n return data.endpoints ?? [];\n }\n\n async signIn(email: string, password: string): Promise<string> {\n const res = await fetch(`${this.baseUrl}/api/auth/sign-in/email`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ email, password }),\n redirect: \"manual\",\n });\n\n if (!res.ok && res.status !== 302) {\n throw new Error(`Sign-in failed: ${res.status} ${res.statusText}`);\n }\n\n const cookies = res.headers.getSetCookie?.() ?? [];\n if (cookies.length === 0) {\n const setCookie = res.headers.get(\"set-cookie\");\n if (setCookie) return setCookie;\n throw new Error(\"Sign-in succeeded but no session cookie was returned.\");\n }\n return cookies.join(\"; \");\n }\n\n async listNamespaces(): Promise<Namespace[]> {\n if (!this.sessionCookie) {\n throw new Error(\n \"Namespace listing requires session auth. Run `metamcp-cli init` with email/password.\",\n );\n }\n const res = await fetch(`${this.baseUrl}/trpc/frontend/namespaces.list`, {\n headers: this.headers(),\n });\n if (!res.ok) {\n throw new Error(\n `Failed to list namespaces: ${res.status} ${res.statusText}`,\n );\n }\n const data = (await res.json()) as { result?: { data?: Namespace[] } };\n return data.result?.data ?? [];\n }\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\n\nexport interface DetectedClient {\n configPath: string;\n detected: boolean;\n}\n\nexport interface MetaMCPConfig {\n version: 1;\n instance: {\n url: string;\n apiKey?: string;\n sessionCookie?: string;\n proxyHeaders?: Record<string, string>;\n };\n activeEndpoint?: string;\n detectedClients?: Record<string, DetectedClient>;\n}\n\nconst CONFIG_DIR = path.join(os.homedir(), '.metamcp-cli');\nconst CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');\n\nexport function getConfigDir(): string {\n return CONFIG_DIR;\n}\n\nexport function getConfigPath(): string {\n return CONFIG_FILE;\n}\n\nexport function loadConfig(): MetaMCPConfig | null {\n try {\n if (!fs.existsSync(CONFIG_FILE)) return null;\n const raw = fs.readFileSync(CONFIG_FILE, 'utf-8');\n return JSON.parse(raw) as MetaMCPConfig;\n } catch {\n return null;\n }\n}\n\nexport function saveConfig(config: MetaMCPConfig): void {\n if (!fs.existsSync(CONFIG_DIR)) {\n fs.mkdirSync(CONFIG_DIR, { recursive: true });\n }\n fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), {\n mode: 0o600,\n });\n}\n\nexport function getConfigOrThrow(): MetaMCPConfig {\n const config = loadConfig();\n if (!config) {\n throw new Error(\n 'MetaMCP CLI is not initialized. Run `metamcp-cli init` first.'\n );\n }\n return config;\n}\n","import chalk from 'chalk';\nimport { ALL_CLIENTS } from '../clients/detector.js';\nimport { loadConfig, saveConfig, type MetaMCPConfig } from '../config/store.js';\n\nexport async function scanCommand(): Promise<void> {\n console.log(chalk.bold('\\n🔍 Scanning for MCP clients...\\n'));\n\n const results: { name: string; slug: string; status: string; path: string; configured: string }[] = [];\n\n for (const client of ALL_CLIENTS) {\n const installed = client.isInstalled();\n const configPath = client.getConfigPath();\n const hasEntry = installed && client.hasMetaMCPEntry();\n\n results.push({\n name: client.name,\n slug: client.slug,\n status: installed ? chalk.green('Found') : chalk.dim('Not found'),\n path: configPath ?? '-',\n configured: hasEntry ? chalk.green('Yes') : chalk.dim('No'),\n });\n }\n\n // Print table\n const nameWidth = 16;\n const statusWidth = 14;\n const configuredWidth = 14;\n\n console.log(\n chalk.bold(\n 'Client'.padEnd(nameWidth) +\n 'Status'.padEnd(statusWidth) +\n 'MetaMCP'.padEnd(configuredWidth) +\n 'Config Path'\n )\n );\n console.log('─'.repeat(80));\n\n for (const r of results) {\n console.log(\n r.name.padEnd(nameWidth) +\n r.status.padEnd(statusWidth + 10) + // extra for chalk escape codes\n r.configured.padEnd(configuredWidth + 10) +\n chalk.dim(r.path)\n );\n }\n\n // Cache detected clients in config\n const config = loadConfig();\n if (config) {\n config.detectedClients = {};\n for (const client of ALL_CLIENTS) {\n const p = client.getConfigPath();\n config.detectedClients[client.slug] = {\n configPath: p ?? '',\n detected: client.isInstalled(),\n };\n }\n saveConfig(config);\n }\n\n const found = ALL_CLIENTS.filter((c) => c.isInstalled()).length;\n console.log(chalk.dim(`\\n${found} client(s) detected.\\n`));\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\nimport { execSync } from 'node:child_process';\n\nexport interface EndpointConfig {\n baseUrl: string;\n endpointName: string;\n apiKey?: string;\n}\n\nexport interface MCPClient {\n name: string;\n slug: string;\n getConfigPath(): string | null;\n isInstalled(): boolean;\n hasMetaMCPEntry(): boolean;\n writeMetaMCPEntry(config: EndpointConfig): void;\n removeMetaMCPEntry(): void;\n}\n\nfunction getGlobalConfigPath(\n macPath: string,\n winPath: string,\n linuxPath: string\n): string | null {\n const home = os.homedir();\n const platform = process.platform;\n\n let configPath: string;\n if (platform === 'darwin') {\n configPath = path.join(home, macPath);\n } else if (platform === 'win32') {\n configPath = path.join(home, winPath);\n } else {\n configPath = path.join(home, linuxPath);\n }\n\n return fs.existsSync(configPath) || fs.existsSync(path.dirname(configPath))\n ? configPath\n : null;\n}\n\nfunction readJsonSafe(filePath: string): Record<string, unknown> | null {\n try {\n if (!fs.existsSync(filePath)) return null;\n return JSON.parse(fs.readFileSync(filePath, 'utf-8'));\n } catch {\n return null;\n }\n}\n\nfunction safeWriteMcpConfig(\n configPath: string,\n serverKey: string,\n serverConfig: Record<string, unknown>\n): void {\n let existing: Record<string, unknown> = {};\n if (fs.existsSync(configPath)) {\n fs.copyFileSync(configPath, configPath + '.metamcp-backup');\n existing = JSON.parse(fs.readFileSync(configPath, 'utf-8'));\n }\n\n if (!existing['mcpServers'] || typeof existing['mcpServers'] !== 'object') {\n existing['mcpServers'] = {};\n }\n\n (existing['mcpServers'] as Record<string, unknown>)[serverKey] = serverConfig;\n\n fs.mkdirSync(path.dirname(configPath), { recursive: true });\n fs.writeFileSync(configPath, JSON.stringify(existing, null, 2));\n}\n\nfunction hasMcpEntry(configPath: string, key: string): boolean {\n const data = readJsonSafe(configPath);\n if (!data) return false;\n const servers = data['mcpServers'] as Record<string, unknown> | undefined;\n return !!servers && key in servers;\n}\n\nfunction removeMcpEntry(configPath: string, key: string): void {\n if (!fs.existsSync(configPath)) return;\n const data = JSON.parse(fs.readFileSync(configPath, 'utf-8'));\n if (data.mcpServers && key in data.mcpServers) {\n fs.copyFileSync(configPath, configPath + '.metamcp-backup');\n delete data.mcpServers[key];\n fs.writeFileSync(configPath, JSON.stringify(data, null, 2));\n }\n}\n\nfunction buildSseConfig(config: EndpointConfig): Record<string, unknown> {\n const entry: Record<string, unknown> = {\n url: `${config.baseUrl}/metamcp/${config.endpointName}/sse`,\n };\n if (config.apiKey) {\n entry['headers'] = { Authorization: `Bearer ${config.apiKey}` };\n }\n return entry;\n}\n\nfunction buildMcpProxyConfig(config: EndpointConfig): Record<string, unknown> {\n const url = `${config.baseUrl}/metamcp/${config.endpointName}/mcp`;\n const env: Record<string, string> = {};\n if (config.apiKey) {\n env['API_ACCESS_TOKEN'] = config.apiKey;\n }\n return {\n command: 'uvx',\n args: ['mcp-proxy', '--transport', 'streamablehttp', url],\n env,\n };\n}\n\nfunction buildStdioBridgeConfig(config: EndpointConfig): Record<string, unknown> {\n const url = `${config.baseUrl}/metamcp/${config.endpointName}/mcp`;\n const args = ['-y', 'mcp-remote', url];\n if (config.apiKey) {\n args.push('--header', `Authorization:Bearer ${config.apiKey}`);\n }\n return { command: 'npx', args };\n}\n\nconst MCP_KEY = 'metamcp';\n\nfunction hasBinary(name: string): boolean {\n try {\n execSync(`which ${name}`, { stdio: 'ignore' });\n return true;\n } catch {\n return false;\n }\n}\n\n// --- Client implementations ---\n\nfunction createClaudeDesktop(): MCPClient {\n const slug = 'claude-desktop';\n const name = 'Claude Desktop';\n\n const getPath = () =>\n getGlobalConfigPath(\n 'Library/Application Support/Claude/claude_desktop_config.json',\n 'AppData/Roaming/Claude/claude_desktop_config.json',\n '.config/Claude/claude_desktop_config.json'\n );\n\n return {\n name,\n slug,\n getConfigPath: getPath,\n isInstalled: () => getPath() !== null,\n hasMetaMCPEntry: () => {\n const p = getPath();\n return p ? hasMcpEntry(p, MCP_KEY) : false;\n },\n writeMetaMCPEntry: (config) => {\n const p = getPath();\n if (!p) throw new Error(`${name} config path not found`);\n safeWriteMcpConfig(p, MCP_KEY, buildMcpProxyConfig(config));\n },\n removeMetaMCPEntry: () => {\n const p = getPath();\n if (p) removeMcpEntry(p, MCP_KEY);\n },\n };\n}\n\nfunction createCursor(): MCPClient {\n const slug = 'cursor';\n const name = 'Cursor';\n\n const getPath = () =>\n getGlobalConfigPath(\n '.cursor/mcp.json',\n '.cursor/mcp.json',\n '.cursor/mcp.json'\n );\n\n return {\n name,\n slug,\n getConfigPath: getPath,\n isInstalled: () => getPath() !== null,\n hasMetaMCPEntry: () => {\n const p = getPath();\n return p ? hasMcpEntry(p, MCP_KEY) : false;\n },\n writeMetaMCPEntry: (config) => {\n const p = getPath();\n if (!p) throw new Error(`${name} config path not found`);\n safeWriteMcpConfig(p, MCP_KEY, buildSseConfig(config));\n },\n removeMetaMCPEntry: () => {\n const p = getPath();\n if (p) removeMcpEntry(p, MCP_KEY);\n },\n };\n}\n\nfunction createWindsurf(): MCPClient {\n const slug = 'windsurf';\n const name = 'Windsurf';\n\n const getPath = () =>\n getGlobalConfigPath(\n '.codeium/windsurf/mcp_config.json',\n '.codeium/windsurf/mcp_config.json',\n '.codeium/windsurf/mcp_config.json'\n );\n\n return {\n name,\n slug,\n getConfigPath: getPath,\n isInstalled: () => getPath() !== null,\n hasMetaMCPEntry: () => {\n const p = getPath();\n return p ? hasMcpEntry(p, MCP_KEY) : false;\n },\n writeMetaMCPEntry: (config) => {\n const p = getPath();\n if (!p) throw new Error(`${name} config path not found`);\n const entry: Record<string, unknown> = {\n serverUrl: `${config.baseUrl}/metamcp/${config.endpointName}/sse`,\n };\n safeWriteMcpConfig(p, MCP_KEY, entry);\n },\n removeMetaMCPEntry: () => {\n const p = getPath();\n if (p) removeMcpEntry(p, MCP_KEY);\n },\n };\n}\n\nfunction createCline(): MCPClient {\n const slug = 'cline';\n const name = 'Cline';\n\n const getPath = () =>\n getGlobalConfigPath(\n 'Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json',\n 'AppData/Roaming/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json',\n '.config/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json'\n );\n\n return {\n name,\n slug,\n getConfigPath: getPath,\n isInstalled: () => getPath() !== null,\n hasMetaMCPEntry: () => {\n const p = getPath();\n return p ? hasMcpEntry(p, MCP_KEY) : false;\n },\n writeMetaMCPEntry: (config) => {\n const p = getPath();\n if (!p) throw new Error(`${name} config path not found`);\n safeWriteMcpConfig(p, MCP_KEY, buildStdioBridgeConfig(config));\n },\n removeMetaMCPEntry: () => {\n const p = getPath();\n if (p) removeMcpEntry(p, MCP_KEY);\n },\n };\n}\n\nfunction createClaudeCode(): MCPClient {\n const slug = 'claude-code';\n const name = 'Claude Code';\n\n const getPath = () => path.join(process.cwd(), '.mcp.json');\n\n return {\n name,\n slug,\n getConfigPath: getPath,\n isInstalled: () => hasBinary('claude'),\n hasMetaMCPEntry: () => hasMcpEntry(getPath(), MCP_KEY),\n writeMetaMCPEntry: (config) => {\n safeWriteMcpConfig(getPath(), MCP_KEY, buildMcpProxyConfig(config));\n },\n removeMetaMCPEntry: () => removeMcpEntry(getPath(), MCP_KEY),\n };\n}\n\nfunction createVSCode(): MCPClient {\n const slug = 'vscode';\n const name = 'VS Code';\n\n const getPath = () => path.join(process.cwd(), '.vscode', 'mcp.json');\n\n return {\n name,\n slug,\n getConfigPath: getPath,\n isInstalled: () => hasBinary('code'),\n hasMetaMCPEntry: () => hasMcpEntry(getPath(), MCP_KEY),\n writeMetaMCPEntry: (config) => {\n safeWriteMcpConfig(getPath(), MCP_KEY, buildSseConfig(config));\n },\n removeMetaMCPEntry: () => removeMcpEntry(getPath(), MCP_KEY),\n };\n}\n\nexport const ALL_CLIENTS: MCPClient[] = [\n createClaudeCode(),\n createVSCode(),\n createClaudeDesktop(),\n createCursor(),\n createWindsurf(),\n createCline(),\n];\n\nexport function detectClients(): MCPClient[] {\n return ALL_CLIENTS.filter((c) => c.isInstalled());\n}\n\nexport function getClientBySlug(slug: string): MCPClient | undefined {\n return ALL_CLIENTS.find((c) => c.slug === slug);\n}\n","import chalk from 'chalk';\nimport ora from 'ora';\nimport { getConfigOrThrow } from '../config/store.js';\nimport { clientFromConfig } from '../api/client-from-config.js';\n\nexport async function endpointsCommand(): Promise<void> {\n const config = getConfigOrThrow();\n const client = clientFromConfig(config);\n\n const spinner = ora('Fetching endpoints...').start();\n\n try {\n const endpoints = await client.listPublicEndpoints();\n spinner.stop();\n\n if (endpoints.length === 0) {\n console.log(chalk.yellow('\\nNo public endpoints found.'));\n console.log(chalk.dim('Create endpoints in the MetaMCP dashboard first.\\n'));\n return;\n }\n\n console.log(chalk.bold(`\\n📡 Endpoints (${endpoints.length})\\n`));\n\n const nameWidth = 20;\n const nsWidth = 20;\n\n console.log(\n chalk.bold(\n 'Name'.padEnd(nameWidth) +\n 'Namespace'.padEnd(nsWidth) +\n 'URL'\n )\n );\n console.log('─'.repeat(80));\n\n for (const ep of endpoints) {\n console.log(\n ep.name.padEnd(nameWidth) +\n (ep.namespace ?? '-').padEnd(nsWidth) +\n chalk.dim(ep.endpoints.mcp)\n );\n }\n console.log();\n } catch (err) {\n spinner.fail(\n `Failed to fetch endpoints: ${err instanceof Error ? err.message : String(err)}`\n );\n process.exit(1);\n }\n}\n","import { MetaMCPClient } from './metamcp.js';\nimport { type MetaMCPConfig } from '../config/store.js';\n\nexport function clientFromConfig(config: MetaMCPConfig): MetaMCPClient {\n return new MetaMCPClient(\n config.instance.url,\n config.instance.apiKey,\n config.instance.sessionCookie,\n config.instance.proxyHeaders,\n );\n}\n","import chalk from 'chalk';\nimport ora from 'ora';\nimport { getConfigOrThrow } from '../config/store.js';\nimport { clientFromConfig } from '../api/client-from-config.js';\n\nexport async function namespacesCommand(): Promise<void> {\n const config = getConfigOrThrow();\n const client = clientFromConfig(config);\n\n const spinner = ora('Fetching namespaces...').start();\n\n try {\n const namespaces = await client.listNamespaces();\n spinner.stop();\n\n if (namespaces.length === 0) {\n console.log(chalk.yellow('\\nNo namespaces found.'));\n return;\n }\n\n console.log(chalk.bold(`\\n📦 Namespaces (${namespaces.length})\\n`));\n\n const nameWidth = 24;\n const scopeWidth = 12;\n\n console.log(\n chalk.bold(\n 'Name'.padEnd(nameWidth) +\n 'Scope'.padEnd(scopeWidth) +\n 'Description'\n )\n );\n console.log('─'.repeat(70));\n\n for (const ns of namespaces) {\n console.log(\n ns.name.padEnd(nameWidth) +\n (ns.isPublic ? 'public' : 'private').padEnd(scopeWidth) +\n chalk.dim(ns.description ?? '-')\n );\n }\n console.log();\n } catch (err) {\n spinner.fail(\n `Failed to fetch namespaces: ${err instanceof Error ? err.message : String(err)}`\n );\n process.exit(1);\n }\n}\n","import chalk from 'chalk';\nimport ora from 'ora';\nimport { confirm, checkbox } from '@inquirer/prompts';\nimport { getConfigOrThrow, saveConfig } from '../config/store.js';\nimport { clientFromConfig } from '../api/client-from-config.js';\nimport {\n detectClients,\n getClientBySlug,\n type EndpointConfig,\n type MCPClient,\n} from '../clients/detector.js';\n\nexport async function useCommand(\n endpointName: string,\n options: { client?: string; force?: boolean }\n): Promise<void> {\n const config = getConfigOrThrow();\n const apiClient = clientFromConfig(config);\n\n // Validate endpoint exists\n const spinner = ora('Validating endpoint...').start();\n let endpoints;\n try {\n endpoints = await apiClient.listPublicEndpoints();\n } catch (err) {\n spinner.fail(\n `Failed to fetch endpoints: ${err instanceof Error ? err.message : String(err)}`\n );\n process.exit(1);\n }\n\n const endpoint = endpoints.find((e) => e.name === endpointName);\n if (!endpoint) {\n spinner.fail(`Endpoint \"${endpointName}\" not found.`);\n console.log(\n chalk.dim(\n 'Available endpoints: ' + endpoints.map((e) => e.name).join(', ')\n )\n );\n process.exit(1);\n }\n spinner.succeed(`Endpoint \"${endpointName}\" found`);\n\n // Determine which clients to configure\n let targets: MCPClient[];\n\n if (options.client) {\n const c = getClientBySlug(options.client);\n if (!c) {\n console.log(\n chalk.red(`Unknown client \"${options.client}\".`) +\n chalk.dim(\n ' Available: claude-desktop, cursor, windsurf, cline, claude-code'\n )\n );\n process.exit(1);\n }\n if (!c.isInstalled()) {\n console.log(chalk.red(`${c.name} is not installed or detected on this system.`));\n process.exit(1);\n }\n targets = [c];\n } else {\n const detected = detectClients();\n if (detected.length === 0) {\n console.log(chalk.yellow('No MCP clients detected. Run `metamcp-cli scan` to check.'));\n process.exit(1);\n }\n\n const selected = await checkbox({\n message: 'Select clients to configure:',\n choices: detected.map((c) => ({\n name: `${c.name}${c.hasMetaMCPEntry() ? chalk.dim(' (already configured)') : ''}`,\n value: c.slug,\n checked: true,\n })),\n });\n\n if (selected.length === 0) {\n console.log(chalk.yellow('No clients selected.'));\n return;\n }\n\n targets = selected\n .map((slug) => getClientBySlug(slug))\n .filter((c): c is MCPClient => c !== undefined);\n }\n\n const endpointConfig: EndpointConfig = {\n baseUrl: config.instance.url,\n endpointName,\n apiKey: config.instance.apiKey,\n };\n\n // Configure each client\n for (const client of targets) {\n const hasExisting = client.hasMetaMCPEntry();\n\n if (hasExisting && !options.force) {\n const overwrite = await confirm({\n message: `${client.name} already has a MetaMCP config. Overwrite?`,\n default: true,\n });\n if (!overwrite) {\n console.log(chalk.dim(` Skipped ${client.name}`));\n continue;\n }\n }\n\n try {\n const s = ora(`Configuring ${client.name}...`).start();\n client.writeMetaMCPEntry(endpointConfig);\n s.succeed(`${client.name} configured`);\n } catch (err) {\n console.log(\n chalk.red(\n ` Failed to configure ${client.name}: ${err instanceof Error ? err.message : String(err)}`\n )\n );\n }\n }\n\n // Update active endpoint in config\n config.activeEndpoint = endpointName;\n saveConfig(config);\n\n console.log(chalk.green(`\\n✓ Active endpoint set to \"${endpointName}\"`));\n console.log(chalk.dim('Restart your IDE(s) for the changes to take effect.\\n'));\n}\n","import chalk from 'chalk';\nimport ora from 'ora';\nimport { loadConfig } from '../config/store.js';\nimport { clientFromConfig } from '../api/client-from-config.js';\nimport { ALL_CLIENTS } from '../clients/detector.js';\n\nexport async function statusCommand(): Promise<void> {\n const config = loadConfig();\n\n if (!config) {\n console.log(chalk.yellow('\\nMetaMCP CLI is not initialized.'));\n console.log(chalk.dim('Run `metamcp-cli init` to get started.\\n'));\n return;\n }\n\n console.log(chalk.bold('\\n📊 MetaMCP CLI Status\\n'));\n\n // Instance info\n console.log(chalk.bold('Instance'));\n console.log(` URL: ${config.instance.url}`);\n console.log(\n ` Auth: ${config.instance.apiKey ? 'API Key' : config.instance.sessionCookie ? 'Session' : chalk.yellow('Not configured')}`\n );\n\n // Health check\n const spinner = ora(' Checking connection...').start();\n const client = clientFromConfig(config);\n const healthy = await client.healthCheck();\n if (healthy) {\n spinner.succeed(' Connection: OK');\n } else {\n spinner.fail(' Connection: Failed');\n }\n\n // Active endpoint\n console.log(\n `\\n${chalk.bold('Active Endpoint')}: ${config.activeEndpoint ?? chalk.dim('none')}`\n );\n\n // Clients\n console.log(chalk.bold('\\nClients'));\n for (const c of ALL_CLIENTS) {\n const installed = c.isInstalled();\n const configured = installed && c.hasMetaMCPEntry();\n const statusStr = !installed\n ? chalk.dim('not found')\n : configured\n ? chalk.green('configured')\n : chalk.yellow('detected');\n console.log(` ${c.name.padEnd(16)} ${statusStr}`);\n }\n\n console.log();\n}\n","import { input, select, password, checkbox, confirm } from '@inquirer/prompts';\nimport chalk from 'chalk';\nimport ora from 'ora';\nimport { MetaMCPClient } from '../api/metamcp.js';\nimport { loadConfig, saveConfig, type MetaMCPConfig } from '../config/store.js';\nimport { clientFromConfig } from '../api/client-from-config.js';\nimport {\n detectClients,\n getClientBySlug,\n type EndpointConfig,\n type MCPClient,\n} from '../clients/detector.js';\n\nexport async function setupCommand(options: { insecure?: boolean }): Promise<void> {\n console.log(chalk.bold('\\n⚡ MetaMCP Quick Setup\\n'));\n\n if (options.insecure) {\n process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';\n }\n\n // Step 1: Get or create config\n let config = loadConfig();\n let apiClient: MetaMCPClient;\n\n if (config) {\n console.log(chalk.dim(`Using existing config: ${config.instance.url}`));\n apiClient = clientFromConfig(config);\n\n const healthy = await apiClient.healthCheck();\n if (!healthy) {\n console.log(chalk.yellow('Cannot connect to saved instance. Let\\'s reconfigure.\\n'));\n config = null;\n }\n }\n\n if (!config) {\n const url = await input({\n message: 'MetaMCP instance URL:',\n default: 'http://localhost:12008',\n validate: (val) => {\n try { new URL(val); return true; } catch { return 'Please enter a valid URL'; }\n },\n });\n\n const baseUrl = url.replace(/\\/+$/, '');\n\n const apiKey = await password({\n message: 'API Key:',\n mask: '*',\n });\n\n const spinner = ora('Connecting...').start();\n apiClient = new MetaMCPClient(baseUrl, apiKey);\n const healthy = await apiClient.healthCheck();\n\n if (!healthy) {\n spinner.fail('Could not connect. Check URL and API key.');\n process.exit(1);\n }\n spinner.succeed('Connected to MetaMCP');\n\n config = {\n version: 1,\n instance: { url: baseUrl, apiKey },\n };\n saveConfig(config);\n }\n\n // Step 2: Fetch and select endpoint\n const spinner = ora('Fetching endpoints...').start();\n let endpoints;\n try {\n endpoints = await apiClient!.listPublicEndpoints();\n } catch (err) {\n spinner.fail(`Failed to fetch endpoints: ${err instanceof Error ? err.message : String(err)}`);\n process.exit(1);\n }\n spinner.stop();\n\n if (endpoints.length === 0) {\n console.log(chalk.yellow('\\nNo endpoints found. Create one in the MetaMCP dashboard first.\\n'));\n process.exit(1);\n }\n\n const selectedEndpoint = await select({\n message: 'Select endpoint to use:',\n choices: endpoints.map((ep) => ({\n name: `${ep.name}${ep.namespace ? chalk.dim(` (${ep.namespace})`) : ''}${ep.description ? chalk.dim(` — ${ep.description}`) : ''}`,\n value: ep.name,\n })),\n });\n\n // Step 3: Detect and select clients\n const detected = detectClients();\n\n if (detected.length === 0) {\n console.log(chalk.yellow('\\nNo MCP clients detected on this system.'));\n console.log(chalk.dim('Supported: Claude Desktop, Cursor, Windsurf, Cline, Claude Code\\n'));\n // Still save the endpoint selection\n config.activeEndpoint = selectedEndpoint;\n saveConfig(config);\n process.exit(1);\n }\n\n const selectedClients = await checkbox({\n message: 'Select clients to configure:',\n choices: detected.map((c) => ({\n name: `${c.name}${c.hasMetaMCPEntry() ? chalk.dim(' (already configured)') : ''}`,\n value: c.slug,\n checked: true,\n })),\n });\n\n if (selectedClients.length === 0) {\n console.log(chalk.yellow('No clients selected.'));\n config.activeEndpoint = selectedEndpoint;\n saveConfig(config);\n return;\n }\n\n const targets = selectedClients\n .map((slug) => getClientBySlug(slug))\n .filter((c): c is MCPClient => c !== undefined);\n\n // Step 4: Configure clients\n const endpointConfig: EndpointConfig = {\n baseUrl: config.instance.url,\n endpointName: selectedEndpoint,\n apiKey: config.instance.apiKey,\n };\n\n console.log();\n for (const client of targets) {\n const hasExisting = client.hasMetaMCPEntry();\n\n if (hasExisting) {\n const overwrite = await confirm({\n message: `${client.name} already configured. Overwrite?`,\n default: true,\n });\n if (!overwrite) {\n console.log(chalk.dim(` Skipped ${client.name}`));\n continue;\n }\n }\n\n try {\n const s = ora(`Configuring ${client.name}...`).start();\n client.writeMetaMCPEntry(endpointConfig);\n s.succeed(`${client.name} configured`);\n } catch (err) {\n console.log(\n chalk.red(` Failed: ${client.name} — ${err instanceof Error ? err.message : String(err)}`)\n );\n }\n }\n\n // Step 5: Save and show summary\n config.activeEndpoint = selectedEndpoint;\n saveConfig(config);\n\n console.log(chalk.green(`\\n✓ Setup complete!`));\n console.log(chalk.dim(` Instance: ${config.instance.url}`));\n console.log(chalk.dim(` Endpoint: ${selectedEndpoint}`));\n console.log(chalk.dim(` Clients: ${targets.map((c) => c.name).join(', ')}`));\n console.log(chalk.dim('\\nRestart your IDE(s) for changes to take effect.\\n'));\n}\n"],"mappings":"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","names":["chalk","password","spinner","client","chalk","fs","path","os","chalk","chalk","ora","ora","chalk","chalk","ora","ora","chalk","chalk","ora","ora","chalk","chalk","ora","chalk","ora","input","select","password","checkbox","confirm","chalk","ora","chalk","input","password","spinner","ora","select","checkbox","confirm","chalk"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "metamcp-cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "CLI wrapper for MetaMCP — auto-configure MCP clients from your MetaMCP instance",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"metamcp-cli": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsup",
|
|
11
|
+
"dev": "tsup --watch",
|
|
12
|
+
"typecheck": "tsc --noEmit"
|
|
13
|
+
},
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=18.0.0"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist"
|
|
19
|
+
],
|
|
20
|
+
"keywords": [
|
|
21
|
+
"mcp",
|
|
22
|
+
"metamcp",
|
|
23
|
+
"cli",
|
|
24
|
+
"model-context-protocol"
|
|
25
|
+
],
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@inquirer/prompts": "^7.5.0",
|
|
29
|
+
"chalk": "^5.4.1",
|
|
30
|
+
"commander": "^13.1.0",
|
|
31
|
+
"ora": "^8.2.0"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/node": "^22.15.3",
|
|
35
|
+
"tsup": "^8.4.0",
|
|
36
|
+
"typescript": "^5.8.3"
|
|
37
|
+
}
|
|
38
|
+
}
|