mcpman 0.1.1 → 0.2.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 +4 -2
- package/dist/chunk-6X6Q6UZC.js +141 -0
- package/dist/index.cjs +1350 -144
- package/dist/index.js +1088 -118
- package/dist/trust-scorer-LYC6KZCD.js +77 -0
- package/dist/vault-service-UTZAV6N6.js +29 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
# mcpman
|
|
2
2
|
|
|
3
|
-

|
|
4
|
-
](https://www.npmjs.com/package/mcpman)
|
|
4
|
+
[](https://www.npmjs.com/package/mcpman)
|
|
5
|
+
[](https://github.com/tranhoangtu-it/mcpman)
|
|
6
|
+
[](https://github.com/tranhoangtu-it/mcpman/blob/main/LICENSE)
|
|
5
7
|

|
|
6
8
|
|
|
7
9
|
**The package manager for MCP servers.**
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/core/vault-service.ts
|
|
4
|
+
import crypto from "crypto";
|
|
5
|
+
import fs from "fs";
|
|
6
|
+
import os from "os";
|
|
7
|
+
import path from "path";
|
|
8
|
+
import * as p from "@clack/prompts";
|
|
9
|
+
var _cachedPassword = null;
|
|
10
|
+
process.on("exit", () => {
|
|
11
|
+
_cachedPassword = null;
|
|
12
|
+
});
|
|
13
|
+
function getVaultPath() {
|
|
14
|
+
return path.join(os.homedir(), ".mcpman", "vault.enc");
|
|
15
|
+
}
|
|
16
|
+
function readVault(vaultPath = getVaultPath()) {
|
|
17
|
+
const empty = { version: 1, servers: {} };
|
|
18
|
+
try {
|
|
19
|
+
const raw = fs.readFileSync(vaultPath, "utf-8");
|
|
20
|
+
const parsed = JSON.parse(raw);
|
|
21
|
+
if (parsed.version !== 1 || typeof parsed.servers !== "object") return empty;
|
|
22
|
+
return parsed;
|
|
23
|
+
} catch {
|
|
24
|
+
return empty;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function writeVault(data, vaultPath = getVaultPath()) {
|
|
28
|
+
const dir = path.dirname(vaultPath);
|
|
29
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
30
|
+
const tmp = `${vaultPath}.tmp`;
|
|
31
|
+
fs.writeFileSync(tmp, JSON.stringify(data, null, 2), { mode: 384 });
|
|
32
|
+
if (process.platform !== "win32") {
|
|
33
|
+
fs.chmodSync(tmp, 384);
|
|
34
|
+
}
|
|
35
|
+
fs.renameSync(tmp, vaultPath);
|
|
36
|
+
if (process.platform !== "win32") {
|
|
37
|
+
fs.chmodSync(vaultPath, 384);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function encrypt(value, password2) {
|
|
41
|
+
const salt = crypto.randomBytes(16);
|
|
42
|
+
const key = crypto.pbkdf2Sync(password2, salt, 1e5, 32, "sha256");
|
|
43
|
+
const iv = crypto.randomBytes(16);
|
|
44
|
+
const cipher = crypto.createCipheriv("aes-256-cbc", key, iv);
|
|
45
|
+
const encrypted = Buffer.concat([cipher.update(value, "utf-8"), cipher.final()]);
|
|
46
|
+
return {
|
|
47
|
+
salt: salt.toString("hex"),
|
|
48
|
+
iv: iv.toString("hex"),
|
|
49
|
+
data: encrypted.toString("hex")
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function decrypt(entry, password2) {
|
|
53
|
+
const salt = Buffer.from(entry.salt, "hex");
|
|
54
|
+
const key = crypto.pbkdf2Sync(password2, salt, 1e5, 32, "sha256");
|
|
55
|
+
const iv = Buffer.from(entry.iv, "hex");
|
|
56
|
+
const decipher = crypto.createDecipheriv("aes-256-cbc", key, iv);
|
|
57
|
+
const decrypted = Buffer.concat([
|
|
58
|
+
decipher.update(Buffer.from(entry.data, "hex")),
|
|
59
|
+
decipher.final()
|
|
60
|
+
// throws ERR_OSSL_BAD_DECRYPT on wrong password
|
|
61
|
+
]);
|
|
62
|
+
return decrypted.toString("utf-8");
|
|
63
|
+
}
|
|
64
|
+
async function getMasterPassword(confirm = false) {
|
|
65
|
+
if (_cachedPassword) return _cachedPassword;
|
|
66
|
+
const password2 = await p.password({
|
|
67
|
+
message: "Enter vault master password:",
|
|
68
|
+
validate: (v) => v.length < 8 ? "Password must be at least 8 characters" : void 0
|
|
69
|
+
});
|
|
70
|
+
if (p.isCancel(password2)) {
|
|
71
|
+
p.cancel("Vault access cancelled.");
|
|
72
|
+
process.exit(0);
|
|
73
|
+
}
|
|
74
|
+
if (confirm) {
|
|
75
|
+
const confirm2 = await p.password({ message: "Confirm master password:" });
|
|
76
|
+
if (p.isCancel(confirm2) || confirm2 !== password2) {
|
|
77
|
+
p.cancel("Passwords do not match.");
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
_cachedPassword = password2;
|
|
82
|
+
return _cachedPassword;
|
|
83
|
+
}
|
|
84
|
+
function clearPasswordCache() {
|
|
85
|
+
_cachedPassword = null;
|
|
86
|
+
}
|
|
87
|
+
function setSecret(server, key, value, password2, vaultPath = getVaultPath()) {
|
|
88
|
+
const vault = readVault(vaultPath);
|
|
89
|
+
if (!vault.servers[server]) vault.servers[server] = {};
|
|
90
|
+
vault.servers[server][key] = encrypt(value, password2);
|
|
91
|
+
writeVault(vault, vaultPath);
|
|
92
|
+
}
|
|
93
|
+
function getSecret(server, key, password2, vaultPath = getVaultPath()) {
|
|
94
|
+
const vault = readVault(vaultPath);
|
|
95
|
+
const entry = vault.servers[server]?.[key];
|
|
96
|
+
if (!entry) return null;
|
|
97
|
+
return decrypt(entry, password2);
|
|
98
|
+
}
|
|
99
|
+
function getSecretsForServer(server, password2, vaultPath = getVaultPath()) {
|
|
100
|
+
const vault = readVault(vaultPath);
|
|
101
|
+
const entries = vault.servers[server];
|
|
102
|
+
if (!entries) return {};
|
|
103
|
+
const result = {};
|
|
104
|
+
for (const [k, entry] of Object.entries(entries)) {
|
|
105
|
+
result[k] = decrypt(entry, password2);
|
|
106
|
+
}
|
|
107
|
+
return result;
|
|
108
|
+
}
|
|
109
|
+
function removeSecret(server, key, vaultPath = getVaultPath()) {
|
|
110
|
+
const vault = readVault(vaultPath);
|
|
111
|
+
if (vault.servers[server]) {
|
|
112
|
+
delete vault.servers[server][key];
|
|
113
|
+
if (Object.keys(vault.servers[server]).length === 0) {
|
|
114
|
+
delete vault.servers[server];
|
|
115
|
+
}
|
|
116
|
+
writeVault(vault, vaultPath);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function listSecrets(server, vaultPath = getVaultPath()) {
|
|
120
|
+
const vault = readVault(vaultPath);
|
|
121
|
+
const entries = server ? vault.servers[server] ? { [server]: vault.servers[server] } : {} : vault.servers;
|
|
122
|
+
return Object.entries(entries).map(([srv, keys]) => ({
|
|
123
|
+
server: srv,
|
|
124
|
+
keys: Object.keys(keys)
|
|
125
|
+
}));
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export {
|
|
129
|
+
getVaultPath,
|
|
130
|
+
readVault,
|
|
131
|
+
writeVault,
|
|
132
|
+
encrypt,
|
|
133
|
+
decrypt,
|
|
134
|
+
getMasterPassword,
|
|
135
|
+
clearPasswordCache,
|
|
136
|
+
setSecret,
|
|
137
|
+
getSecret,
|
|
138
|
+
getSecretsForServer,
|
|
139
|
+
removeSecret,
|
|
140
|
+
listSecrets
|
|
141
|
+
};
|