mcp-trust 0.1.0 → 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 CHANGED
@@ -7,7 +7,7 @@ npx mcp-doctor
7
7
  ```
8
8
 
9
9
  ```
10
- mcp-doctor v0.1.0
10
+ mcp-doctor v0.2.0
11
11
  Auditing MCP servers installed on this machine
12
12
 
13
13
  [ALIVE] B github [claude] 14 tools, 4 no-arg, 47ms
@@ -79,6 +79,54 @@ mcp-doctor audit --json # machine-readable output
79
79
  mcp-doctor audit --config-only # list configured servers, don't probe
80
80
  mcp-doctor audit --fail-on-dead # exit 1 if any server is dead (for CI)
81
81
  mcp-doctor audit --concurrency 8 # parallelize probes
82
+ mcp-doctor install @scope/pkg # verify an npm package, then add it to your config
83
+ mcp-doctor serve # run as an MCP server exposing mcp_trust_audit
84
+ ```
85
+
86
+ ### `install` — add a server safely
87
+
88
+ Resolves the package on npm, probes it live, then writes it to your config only if it passes. Refuses to add dead or F-graded servers unless you pass `--yes`. Defaults to Claude Desktop; pass `--client cursor` to target Cursor instead.
89
+
90
+ ```bash
91
+ mcp-trust install @modelcontextprotocol/server-github
92
+ mcp-trust install @modelcontextprotocol/server-github --client cursor
93
+ mcp-trust install @scope/pkg --yes # add even F-graded packages
94
+ mcp-trust install @scope/pkg --dry-run # probe + report, don't write
95
+ mcp-trust install @scope/pkg --name my-alias # override the entry name
96
+ ```
97
+
98
+ If the requested name already exists in your config, the new entry is suffixed (`github-2`, `github-3`, …) instead of overwriting.
99
+
100
+ ### `serve` — use mcp-trust from inside an agent
101
+
102
+ Runs mcp-trust as a Model Context Protocol server over stdio, exposing a single tool `mcp_trust_audit` that any MCP client (Claude Desktop, Cursor, Cline, your own agent) can call. The tool takes a list of server configurations, spawns each one, performs a real handshake, and returns a structured report.
103
+
104
+ ```jsonc
105
+ // example call from any MCP client
106
+ {
107
+ "name": "mcp_trust_audit",
108
+ "arguments": {
109
+ "servers": {
110
+ "github": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-github"] },
111
+ "filesystem":{ "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"] }
112
+ },
113
+ "noHealth": false,
114
+ "concurrency": 4
115
+ }
116
+ }
117
+ ```
118
+
119
+ Add it to your client config the same way you'd add any other MCP server:
120
+
121
+ ```json
122
+ {
123
+ "mcpServers": {
124
+ "mcp-trust": {
125
+ "command": "npx",
126
+ "args": ["-y", "mcp-trust", "serve"]
127
+ }
128
+ }
129
+ }
82
130
  ```
83
131
 
84
132
  ### Config locations scanned
@@ -1,2 +1,5 @@
1
1
  export { runAudit } from "./audit.js";
2
2
  export type { AuditOptions } from "./audit.js";
3
+ export { runInstall } from "./install.js";
4
+ export type { InstallOptions } from "./install.js";
5
+ export { runServe } from "./serve.js";
@@ -1,2 +1,4 @@
1
1
  export { runAudit } from "./audit.js";
2
+ export { runInstall } from "./install.js";
3
+ export { runServe } from "./serve.js";
2
4
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { type TargetClient } from "../install/writer.js";
2
+ export interface InstallOptions {
3
+ client?: TargetClient;
4
+ configPath?: string;
5
+ yes?: boolean;
6
+ name?: string;
7
+ noHealth?: boolean;
8
+ dryRun?: boolean;
9
+ }
10
+ export declare function runInstall(pkg: string, opts?: InstallOptions): Promise<void>;
@@ -0,0 +1,98 @@
1
+ import pc from "picocolors";
2
+ import { fetchPackument } from "../install/packument.js";
3
+ import { probeServer } from "../prober/index.js";
4
+ import { checkRepoHealth, scoreServer } from "../checks/index.js";
5
+ import { resolveTarget, addServerToConfig, readExistingServers } from "../install/writer.js";
6
+ import { renderReport, summarize } from "../reporters/index.js";
7
+ function prompt(question) {
8
+ return new Promise((resolve) => {
9
+ process.stdout.write(question);
10
+ process.stdin.setEncoding("utf8");
11
+ process.stdin.once("data", (data) => {
12
+ const answer = data.toString().trim().toLowerCase();
13
+ resolve(answer === "" || answer === "y" || answer === "yes");
14
+ });
15
+ process.stdin.resume();
16
+ });
17
+ }
18
+ function deriveNameFromPackage(pkg) {
19
+ return pkg.replace(/^@[\w.-]+\//, "").replace(/[^a-z0-9-]/gi, "-").toLowerCase();
20
+ }
21
+ export async function runInstall(pkg, opts = {}) {
22
+ if (!pkg || pkg.startsWith("-")) {
23
+ console.error(pc.red("error:") + " install requires a package name, e.g. `mcp-trust install @modelcontextprotocol/server-github`");
24
+ process.exit(2);
25
+ }
26
+ let resolved;
27
+ try {
28
+ console.log(pc.gray(`Resolving ${pkg} on npm…`));
29
+ resolved = await fetchPackument(pkg);
30
+ }
31
+ catch (err) {
32
+ console.error(pc.red("error:") + " " + (err instanceof Error ? err.message : String(err)));
33
+ process.exit(1);
34
+ }
35
+ console.log(pc.bold(resolved.name) + pc.gray(` v${resolved.version}`));
36
+ if (resolved.description)
37
+ console.log(pc.gray(resolved.description));
38
+ if (resolved.repoUrl)
39
+ console.log(pc.gray(resolved.repoUrl));
40
+ console.log();
41
+ const desiredName = opts.name ?? deriveNameFromPackage(resolved.name);
42
+ const target = resolveTarget(opts.client, opts.configPath);
43
+ const existing = readExistingServers(target.path, target.client);
44
+ const collision = existing.find((s) => s.name === desiredName);
45
+ if (collision) {
46
+ console.log(pc.yellow(`A server named "${desiredName}" already exists in ${target.path}`));
47
+ }
48
+ const probeConfig = {
49
+ name: desiredName,
50
+ command: resolved.installCommand,
51
+ args: resolved.installArgs,
52
+ source: target.client,
53
+ configPath: target.path,
54
+ };
55
+ console.log(pc.bold("Probing server before adding…"));
56
+ const probed = await probeServer(probeConfig);
57
+ const token = opts.noHealth ? "" : process.env.GITHUB_TOKEN;
58
+ const health = opts.noHealth ? null : await checkRepoHealth(resolved.installCommand, resolved.installArgs, undefined, token);
59
+ const report = scoreServer(probed, health);
60
+ const reports = [report];
61
+ console.log();
62
+ const summary = summarize(reports);
63
+ renderReport(reports);
64
+ if (report.server.status !== "alive") {
65
+ console.log(pc.red(pc.bold("Server did not respond to the MCP handshake. Refusing to add a non-functional server.")));
66
+ process.exit(1);
67
+ }
68
+ if (report.verdict === "F" && !opts.yes) {
69
+ console.log(pc.yellow("Server scored F. Use --yes to install anyway."));
70
+ process.exit(1);
71
+ }
72
+ if (opts.dryRun) {
73
+ console.log(pc.gray(`[dry-run] Would add "${desiredName}" to ${target.path}`));
74
+ return;
75
+ }
76
+ if (!opts.yes && process.stdin.isTTY) {
77
+ const ok = await prompt(`Add "${desiredName}" to ${target.path}? [Y/n] `);
78
+ if (!ok) {
79
+ console.log(pc.gray("Cancelled."));
80
+ return;
81
+ }
82
+ }
83
+ try {
84
+ const result = addServerToConfig(target.client, target.path, {
85
+ name: desiredName,
86
+ command: resolved.installCommand,
87
+ args: resolved.installArgs,
88
+ });
89
+ console.log();
90
+ console.log(pc.green(pc.bold("Installed.")) + ` Added "${result.finalName}" to ${result.path}`);
91
+ console.log(pc.gray("Run ") + pc.cyan("mcp-trust audit") + pc.gray(" to verify it's still healthy on next run."));
92
+ }
93
+ catch (err) {
94
+ console.error(pc.red("error:") + " " + (err instanceof Error ? err.message : String(err)));
95
+ process.exit(1);
96
+ }
97
+ }
98
+ //# sourceMappingURL=install.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.js","sourceRoot":"","sources":["../../src/commands/install.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare function runServe(): Promise<void>;
@@ -0,0 +1,195 @@
1
+ import * as readline from "node:readline";
2
+ import { probeServer } from "../prober/index.js";
3
+ import { checkRepoHealth, scoreServer } from "../checks/index.js";
4
+ const VERSION = "0.2.0";
5
+ const PROTOCOL_VERSION = "2024-11-05";
6
+ function send(id, payload) {
7
+ const msg = id !== undefined ? { jsonrpc: "2.0", id, ...payload } : { jsonrpc: "2.0", ...payload };
8
+ process.stdout.write(JSON.stringify(msg) + "\n");
9
+ }
10
+ function sendResponse(id, result) {
11
+ send(id, { result });
12
+ }
13
+ function sendError(id, code, message, data) {
14
+ send(id, { error: { code, message, data } });
15
+ }
16
+ function toolResult(text, isError = false) {
17
+ return { content: [{ type: "text", text }], isError };
18
+ }
19
+ function formatReportForAgent(reports) {
20
+ if (reports.length === 0) {
21
+ return "No servers were provided to audit.";
22
+ }
23
+ const lines = [];
24
+ lines.push(`mcp-trust audit: ${reports.length} server${reports.length === 1 ? "" : "s"} audited`);
25
+ lines.push("");
26
+ for (const r of reports) {
27
+ const icon = r.server.status === "alive" ? "ALIVE" : r.server.status.toUpperCase();
28
+ lines.push(`## ${r.server.config.name}`);
29
+ lines.push(` status: ${icon}`);
30
+ lines.push(` verdict: ${r.verdict} (score ${r.score})`);
31
+ lines.push(` source: ${r.server.config.source} (${r.server.config.command})`);
32
+ lines.push(` duration: ${r.server.durationMs}ms`);
33
+ if (r.server.toolCount > 0) {
34
+ lines.push(` tools: ${r.server.toolCount} (${r.server.emptyArgTools} require args)`);
35
+ }
36
+ if (r.server.errorMessage) {
37
+ lines.push(` error: ${r.server.errorMessage}`);
38
+ }
39
+ if (r.health) {
40
+ const age = r.health.lastCommitDaysAgo ?? "?";
41
+ lines.push(` repo: ${r.health.repo} | ${r.health.stars} stars | last commit ${age}d ago | ${r.health.weeklyDownloads} weekly downloads`);
42
+ if (r.health.archived)
43
+ lines.push(" archived: yes");
44
+ if (r.health.cveCount > 0)
45
+ lines.push(` cves: ${r.health.cveCount}`);
46
+ }
47
+ else if (r.server.status === "alive") {
48
+ lines.push(" repo: (health lookup skipped or unavailable)");
49
+ }
50
+ if (r.issues.length > 0) {
51
+ lines.push(" issues:");
52
+ for (const i of r.issues)
53
+ lines.push(` - ${i}`);
54
+ }
55
+ if (r.recommendations.length > 0) {
56
+ lines.push(" recommendations:");
57
+ for (const rec of r.recommendations)
58
+ lines.push(` - ${rec}`);
59
+ }
60
+ lines.push("");
61
+ }
62
+ const alive = reports.filter((r) => r.server.status === "alive").length;
63
+ const failing = reports.length - alive;
64
+ const avg = Math.round(reports.reduce((s, r) => s + r.score, 0) / reports.length);
65
+ lines.push(`summary: ${alive} alive, ${failing} failing, avg score ${avg}`);
66
+ return lines.join("\n");
67
+ }
68
+ function buildServers(input) {
69
+ const out = [];
70
+ for (const [name, def] of Object.entries(input.servers ?? {})) {
71
+ if (!def || typeof def !== "object" || typeof def.command !== "string")
72
+ continue;
73
+ out.push({
74
+ name,
75
+ command: def.command,
76
+ args: Array.isArray(def.args) ? def.args.map(String) : [],
77
+ env: def.env && typeof def.env === "object" ? Object.fromEntries(Object.entries(def.env).map(([k, v]) => [k, String(v)])) : undefined,
78
+ source: "manual",
79
+ configPath: "<mcp-tool-call>",
80
+ });
81
+ }
82
+ return out;
83
+ }
84
+ async function runAuditTool(input) {
85
+ const servers = buildServers(input);
86
+ if (servers.length === 0)
87
+ return [];
88
+ const concurrency = Math.max(1, Math.min(input.concurrency ?? 4, 16));
89
+ const token = process.env.GITHUB_TOKEN;
90
+ const reports = [];
91
+ for (let i = 0; i < servers.length; i += concurrency) {
92
+ const batch = servers.slice(i, i + concurrency);
93
+ const results = await Promise.all(batch.map(async (cfg) => {
94
+ const probed = await probeServer(cfg);
95
+ const health = input.noHealth ? null : await checkRepoHealth(cfg.command, cfg.args, cfg.env, token);
96
+ return scoreServer(probed, health);
97
+ }));
98
+ reports.push(...results);
99
+ }
100
+ return reports;
101
+ }
102
+ const AUDIT_TOOL = {
103
+ name: "mcp_trust_audit",
104
+ description: "Audit a set of MCP server configurations. Spawns each server, performs a real MCP JSON-RPC initialize + tools/list handshake, then scores it A-F based on health, recency, tool surface, and known CVEs. Returns a structured report with issues and recommendations for each server.",
105
+ inputSchema: {
106
+ type: "object",
107
+ properties: {
108
+ servers: {
109
+ type: "object",
110
+ description: "Map of server name to { command, args?, env? }. Each will be spawned and probed.",
111
+ additionalProperties: {
112
+ type: "object",
113
+ properties: {
114
+ command: { type: "string", description: "Executable to run (e.g. 'npx', 'node', 'python')." },
115
+ args: { type: "array", items: { type: "string" }, description: "Arguments to pass." },
116
+ env: { type: "object", additionalProperties: { type: "string" }, description: "Environment variables." },
117
+ },
118
+ required: ["command"],
119
+ },
120
+ },
121
+ noHealth: { type: "boolean", description: "Skip GitHub/npm repo health lookups (faster)." },
122
+ concurrency: { type: "number", description: "Max servers to probe in parallel (default 4, max 16)." },
123
+ },
124
+ required: ["servers"],
125
+ },
126
+ };
127
+ function handleInitialize(id) {
128
+ sendResponse(id, {
129
+ protocolVersion: PROTOCOL_VERSION,
130
+ capabilities: { tools: {} },
131
+ serverInfo: { name: "mcp-trust", version: VERSION },
132
+ });
133
+ }
134
+ function handleToolsList(id) {
135
+ sendResponse(id, { tools: [AUDIT_TOOL] });
136
+ }
137
+ async function handleToolsCall(id, params) {
138
+ if (!params || params.name !== "mcp_trust_audit") {
139
+ sendError(id, -32602, `Unknown tool: ${params?.name ?? "<none>"}`);
140
+ return;
141
+ }
142
+ const args = (params.arguments ?? {});
143
+ if (!args.servers || typeof args.servers !== "object") {
144
+ sendResponse(id, toolResult("Error: 'servers' must be an object mapping name -> {command, args?, env?}", true));
145
+ return;
146
+ }
147
+ try {
148
+ const reports = await runAuditTool(args);
149
+ const text = formatReportForAgent(reports);
150
+ sendResponse(id, toolResult(text, false));
151
+ }
152
+ catch (err) {
153
+ const msg = err instanceof Error ? err.message : String(err);
154
+ sendResponse(id, toolResult(`Audit failed: ${msg}`, true));
155
+ }
156
+ }
157
+ export async function runServe() {
158
+ const rl = readline.createInterface({ input: process.stdin, crlfDelay: Infinity, terminal: false });
159
+ rl.on("line", (line) => {
160
+ const trimmed = line.trim();
161
+ if (!trimmed)
162
+ return;
163
+ let msg;
164
+ try {
165
+ msg = JSON.parse(trimmed);
166
+ }
167
+ catch {
168
+ sendError(undefined, -32700, "Parse error");
169
+ return;
170
+ }
171
+ const { id, method, params } = msg;
172
+ if (method === "initialize") {
173
+ handleInitialize(id ?? 0);
174
+ }
175
+ else if (method === "tools/list") {
176
+ handleToolsList(id ?? 0);
177
+ }
178
+ else if (method === "tools/call") {
179
+ void handleToolsCall(id ?? 0, params);
180
+ }
181
+ else if (method && method.startsWith("notifications/")) {
182
+ // no response for notifications
183
+ }
184
+ else if (method === "ping") {
185
+ sendResponse(id ?? 0, {});
186
+ }
187
+ else if (id !== undefined) {
188
+ sendError(id, -32601, `Method not found: ${method}`);
189
+ }
190
+ });
191
+ rl.on("close", () => {
192
+ process.exit(0);
193
+ });
194
+ }
195
+ //# sourceMappingURL=serve.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serve.js","sourceRoot":"","sources":["../../src/commands/serve.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import pc from "picocolors";
3
3
  import { runAudit } from "./commands/index.js";
4
- const HELP = `${pc.bold("mcp-trust")} ${pc.gray("v0.1.0")}
4
+ import { runInstall } from "./commands/install.js";
5
+ const HELP = `${pc.bold("mcp-trust")} ${pc.gray("v0.2.0")}
5
6
 
6
7
  Audit the MCP servers installed on your machine. Detects dead, dangerous,
7
8
  or fake servers before they hit production.
@@ -11,6 +12,8 @@ ${pc.bold("Usage:")}
11
12
 
12
13
  ${pc.bold("Commands:")}
13
14
  audit Probe all configured MCP servers and report health (default)
15
+ install Verify an npm package is a healthy MCP server, then add it to your config
16
+ serve Run as an MCP server so other agents can call mcp_trust_audit
14
17
  version Print version
15
18
  help Show this message
16
19
 
@@ -25,12 +28,14 @@ ${pc.bold("Examples:")}
25
28
  mcp-trust
26
29
  mcp-trust audit --json
27
30
  mcp-trust audit --fail-on-dead
28
- mcp-trust audit --concurrency 1
31
+ mcp-trust install @modelcontextprotocol/server-github
32
+ mcp-trust serve
29
33
  `;
30
34
  function parseArgs(argv) {
31
35
  const args = argv.slice(2);
32
36
  let command = "audit";
33
37
  const options = {};
38
+ const positional = [];
34
39
  for (let i = 0; i < args.length; i++) {
35
40
  const arg = args[i];
36
41
  if (arg === "help" || arg === "--help" || arg === "-h") {
@@ -39,8 +44,8 @@ function parseArgs(argv) {
39
44
  else if (arg === "version" || arg === "--version" || arg === "-v") {
40
45
  command = "version";
41
46
  }
42
- else if (arg === "audit") {
43
- command = "audit";
47
+ else if (arg === "audit" || arg === "install" || arg === "serve") {
48
+ command = arg;
44
49
  }
45
50
  else if (arg === "--json") {
46
51
  options.json = true;
@@ -52,7 +57,30 @@ function parseArgs(argv) {
52
57
  options.failOnDead = true;
53
58
  }
54
59
  else if (arg === "--no-health") {
55
- options.githubToken = ""; // signal to skip
60
+ options.noHealth = true;
61
+ options.githubToken = "";
62
+ }
63
+ else if (arg === "--yes" || arg === "-y") {
64
+ options.yes = true;
65
+ }
66
+ else if (arg === "--dry-run") {
67
+ options.dryRun = true;
68
+ }
69
+ else if (arg === "--client") {
70
+ const next = args[++i];
71
+ if (next === "claude" || next === "cursor" || next === "codex") {
72
+ options.client = next;
73
+ }
74
+ else {
75
+ console.error(pc.red("error:") + " --client must be one of: claude, cursor, codex");
76
+ process.exit(2);
77
+ }
78
+ }
79
+ else if (arg === "--config-path" || arg === "--config") {
80
+ options.configPath = args[++i];
81
+ }
82
+ else if (arg === "--name") {
83
+ options.name = args[++i];
56
84
  }
57
85
  else if (arg === "--concurrency") {
58
86
  const next = args[++i];
@@ -63,28 +91,50 @@ function parseArgs(argv) {
63
91
  }
64
92
  options.concurrency = n;
65
93
  }
66
- else {
94
+ else if (arg?.startsWith("-")) {
67
95
  console.error(pc.red("error:") + " unknown argument: " + arg);
68
96
  console.error("Run " + pc.cyan("mcp-trust help") + " for usage");
69
97
  process.exit(2);
70
98
  }
99
+ else if (arg) {
100
+ positional.push(arg);
101
+ }
71
102
  }
72
- return { command, options };
103
+ return { command, options, positional };
73
104
  }
74
105
  async function main() {
75
- const { command, options } = parseArgs(process.argv);
106
+ const { command, options, positional } = parseArgs(process.argv);
76
107
  if (command === "help") {
77
108
  console.log(HELP);
78
109
  return;
79
110
  }
80
111
  if (command === "version") {
81
- console.log("mcp-trust v0.1.0");
112
+ console.log("mcp-trust v0.2.0");
82
113
  return;
83
114
  }
84
115
  if (command === "audit") {
85
116
  await runAudit(options);
86
117
  return;
87
118
  }
119
+ if (command === "install") {
120
+ if (positional.length === 0) {
121
+ console.error(pc.red("error:") + " install requires a package name");
122
+ console.error(" e.g. mcp-trust install @modelcontextprotocol/server-github");
123
+ process.exit(2);
124
+ }
125
+ const pkg = positional[0];
126
+ if (!pkg) {
127
+ console.error(pc.red("error:") + " install requires a package name");
128
+ process.exit(2);
129
+ }
130
+ await runInstall(pkg, options);
131
+ return;
132
+ }
133
+ if (command === "serve") {
134
+ const { runServe } = await import("./commands/serve.js");
135
+ await runServe();
136
+ return;
137
+ }
88
138
  }
89
139
  main().catch((err) => {
90
140
  console.error(pc.red("fatal:") + " " + (err instanceof Error ? err.message : String(err)));
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ interface NpmPackument {
2
+ name: string;
3
+ version: string;
4
+ description?: string;
5
+ bin?: Record<string, string> | string;
6
+ main?: string;
7
+ dependencies?: Record<string, string>;
8
+ repository?: {
9
+ url?: string;
10
+ } | string;
11
+ mcpName?: string;
12
+ }
13
+ export interface ResolvedPackage {
14
+ name: string;
15
+ version: string;
16
+ description: string;
17
+ installCommand: string;
18
+ installArgs: string[];
19
+ repoUrl: string | null;
20
+ }
21
+ export declare function fetchPackument(pkg: string): Promise<ResolvedPackage>;
22
+ export declare function resolveFromPackument(data: NpmPackument): ResolvedPackage;
23
+ export {};
@@ -0,0 +1,48 @@
1
+ const NPM_REGISTRY = "https://registry.npmjs.org";
2
+ export async function fetchPackument(pkg) {
3
+ const cleanName = pkg.replace(/^npm:/, "").trim();
4
+ const url = `${NPM_REGISTRY}/${encodeURIComponent(cleanName).replace(/^%40/, "@")}/latest`;
5
+ const res = await fetch(url, { headers: { Accept: "application/json" } });
6
+ if (!res.ok) {
7
+ if (res.status === 404) {
8
+ throw new Error(`Package "${cleanName}" not found on npm`);
9
+ }
10
+ throw new Error(`npm registry returned ${res.status} for ${cleanName}`);
11
+ }
12
+ const data = (await res.json());
13
+ return resolveFromPackument(data);
14
+ }
15
+ export function resolveFromPackument(data) {
16
+ const installCommand = "npx";
17
+ const installArgs = ["-y", data.name];
18
+ let repoUrl = null;
19
+ if (typeof data.repository === "string") {
20
+ repoUrl = data.repository;
21
+ }
22
+ else if (data.repository?.url) {
23
+ repoUrl = data.repository.url;
24
+ }
25
+ if (repoUrl) {
26
+ repoUrl = repoUrl
27
+ .replace(/^git\+/, "")
28
+ .replace(/\.git$/, "")
29
+ .replace(/^git:/, "https:")
30
+ .replace(/^ssh:\/\/git@/, "https://");
31
+ const match = repoUrl.match(/github\.com[/:]([\w.-]+)\/([\w.-]+)/);
32
+ if (match) {
33
+ repoUrl = `https://github.com/${match[1]}/${match[2]}`;
34
+ }
35
+ else {
36
+ repoUrl = null;
37
+ }
38
+ }
39
+ return {
40
+ name: data.name,
41
+ version: data.version,
42
+ description: data.description ?? "",
43
+ installCommand,
44
+ installArgs,
45
+ repoUrl,
46
+ };
47
+ }
48
+ //# sourceMappingURL=packument.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"packument.js","sourceRoot":"","sources":["../../src/install/packument.ts"],"names":[],"mappings":"AAWA,MAAM,YAAY,GAAG,4BAA4B,CAAC;AAWlD,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,GAAW;IAC9C,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAClD,MAAM,GAAG,GAAG,GAAG,YAAY,IAAI,kBAAkB,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,SAAS,CAAC;IAC3F,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE,EAAE,CAAC,CAAC;IAC1E,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CAAC,YAAY,SAAS,oBAAoB,CAAC,CAAC;QAC7D,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,yBAAyB,GAAG,CAAC,MAAM,QAAQ,SAAS,EAAE,CAAC,CAAC;IAC1E,CAAC;IACD,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAiB,CAAC;IAChD,OAAO,oBAAoB,CAAC,IAAI,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,IAAkB;IACrD,MAAM,cAAc,GAAG,KAAK,CAAC;IAC7B,MAAM,WAAW,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IAEtC,IAAI,OAAO,GAAkB,IAAI,CAAC;IAClC,IAAI,OAAO,IAAI,CAAC,UAAU,KAAK,QAAQ,EAAE,CAAC;QACxC,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC;IAC5B,CAAC;SAAM,IAAI,IAAI,CAAC,UAAU,EAAE,GAAG,EAAE,CAAC;QAChC,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;IAChC,CAAC;IACD,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,GAAG,OAAO;aACd,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC;aACrB,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC;aACrB,OAAO,CAAC,OAAO,EAAE,QAAQ,CAAC;aAC1B,OAAO,CAAC,eAAe,EAAE,UAAU,CAAC,CAAC;QACxC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAC;QACnE,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,GAAG,sBAAsB,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;QACzD,CAAC;aAAM,CAAC;YACN,OAAO,GAAG,IAAI,CAAC;QACjB,CAAC;IACH,CAAC;IAED,OAAO;QACL,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,WAAW,EAAE,IAAI,CAAC,WAAW,IAAI,EAAE;QACnC,cAAc;QACd,WAAW;QACX,OAAO;KACR,CAAC;AACJ,CAAC"}
@@ -0,0 +1,17 @@
1
+ import type { ServerConfig } from "../types.js";
2
+ export type TargetClient = "claude" | "cursor" | "codex";
3
+ export declare function addServerToConfig(client: TargetClient, configPath: string, server: {
4
+ name: string;
5
+ command: string;
6
+ args: string[];
7
+ env?: Record<string, string>;
8
+ }): {
9
+ path: string;
10
+ finalName: string;
11
+ written: boolean;
12
+ };
13
+ export declare function resolveTarget(client: TargetClient | undefined, explicitPath: string | undefined): {
14
+ client: TargetClient;
15
+ path: string;
16
+ };
17
+ export declare function readExistingServers(configPath: string, client: TargetClient): ServerConfig[];
@@ -0,0 +1,101 @@
1
+ import { existsSync, readFileSync, writeFileSync, renameSync } from "node:fs";
2
+ import { dirname } from "node:path";
3
+ import { homedir, platform } from "node:os";
4
+ import { join } from "node:path";
5
+ function defaultConfigPath(client) {
6
+ const home = homedir();
7
+ const win = platform() === "win32";
8
+ if (client === "claude") {
9
+ if (win) {
10
+ return join(process.env.APPDATA ?? join(home, "AppData", "Roaming"), "Claude", "claude_desktop_config.json");
11
+ }
12
+ if (platform() === "darwin") {
13
+ return join(home, "Library", "Application Support", "Claude", "claude_desktop_config.json");
14
+ }
15
+ return join(process.env.XDG_CONFIG_HOME ?? join(home, ".config"), "Claude", "claude_desktop_config.json");
16
+ }
17
+ if (client === "cursor") {
18
+ if (win)
19
+ return join(process.env.APPDATA ?? join(home, "AppData", "Roaming"), "Cursor", "mcp.json");
20
+ if (platform() === "darwin")
21
+ return join(home, "Library", "Application Support", "Cursor", "mcp.json");
22
+ return join(process.env.XDG_CONFIG_HOME ?? join(home, ".config"), "Cursor", "mcp.json");
23
+ }
24
+ return join(home, ".codex", "config.toml");
25
+ }
26
+ export function addServerToConfig(client, configPath, server) {
27
+ if (client === "codex") {
28
+ throw new Error("Adding to Codex TOML config is not yet supported");
29
+ }
30
+ let parsed = {};
31
+ if (existsSync(configPath)) {
32
+ try {
33
+ const raw = readFileSync(configPath, "utf8");
34
+ parsed = JSON.parse(raw);
35
+ }
36
+ catch (err) {
37
+ throw new Error(`Failed to read existing config at ${configPath}: ${err instanceof Error ? err.message : String(err)}`);
38
+ }
39
+ }
40
+ const servers = parsed.mcpServers ?? {};
41
+ const finalName = ensureUniqueName(servers, server.name);
42
+ servers[finalName] = {
43
+ command: server.command,
44
+ args: server.args,
45
+ env: server.env,
46
+ };
47
+ parsed.mcpServers = servers;
48
+ const dir = dirname(configPath);
49
+ if (!existsSync(dir)) {
50
+ throw new Error(`Config directory does not exist: ${dir}`);
51
+ }
52
+ const tmpPath = `${configPath}.tmp-${process.pid}-${Date.now()}`;
53
+ try {
54
+ writeFileSync(tmpPath, JSON.stringify(parsed, null, 2) + "\n", "utf8");
55
+ renameSync(tmpPath, configPath);
56
+ }
57
+ catch (err) {
58
+ throw new Error(`Failed to write config at ${configPath}: ${err instanceof Error ? err.message : String(err)}`);
59
+ }
60
+ return { path: configPath, finalName, written: true };
61
+ }
62
+ function ensureUniqueName(existing, desired) {
63
+ if (!(desired in existing))
64
+ return desired;
65
+ let i = 2;
66
+ while (`${desired}-${i}` in existing)
67
+ i++;
68
+ return `${desired}-${i}`;
69
+ }
70
+ export function resolveTarget(client, explicitPath) {
71
+ if (explicitPath) {
72
+ const resolvedClient = client ?? "claude";
73
+ return { client: resolvedClient, path: explicitPath };
74
+ }
75
+ if (!client)
76
+ return { client: "claude", path: defaultConfigPath("claude") };
77
+ return { client, path: defaultConfigPath(client) };
78
+ }
79
+ export function readExistingServers(configPath, client) {
80
+ if (!existsSync(configPath))
81
+ return [];
82
+ if (client === "codex")
83
+ return [];
84
+ try {
85
+ const raw = readFileSync(configPath, "utf8");
86
+ const parsed = JSON.parse(raw);
87
+ const servers = parsed.mcpServers ?? {};
88
+ return Object.entries(servers).map(([name, cfg]) => ({
89
+ name,
90
+ command: cfg.command,
91
+ args: cfg.args ?? [],
92
+ env: cfg.env,
93
+ source: client,
94
+ configPath,
95
+ }));
96
+ }
97
+ catch {
98
+ return [];
99
+ }
100
+ }
101
+ //# sourceMappingURL=writer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"writer.js","sourceRoot":"","sources":["../../src/install/writer.ts"],"names":[],"mappings":"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"}
@@ -89,7 +89,7 @@ export async function probeServer(config) {
89
89
  send(child, 1, "initialize", {
90
90
  protocolVersion: PROTOCOL_VERSION,
91
91
  capabilities: {},
92
- clientInfo: { name: "mcp-doctor", version: "0.1.0" },
92
+ clientInfo: { name: "mcp-doctor", version: "0.2.0" },
93
93
  });
94
94
  });
95
95
  if (initResponse === "hang") {
@@ -25,7 +25,7 @@ function shortStatus(status) {
25
25
  }
26
26
  export function renderReport(reports) {
27
27
  console.log();
28
- console.log(pc.bold(pc.magenta("mcp-trust")) + pc.gray(" v0.1.0"));
28
+ console.log(pc.bold(pc.magenta("mcp-trust")) + pc.gray(" v0.2.0"));
29
29
  console.log(pc.gray("Auditing MCP servers installed on this machine"));
30
30
  console.log();
31
31
  if (reports.length === 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcp-trust",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Audit the MCP servers installed on your machine. Detect dead, dangerous, or fake servers before they hit production.",
5
5
  "type": "module",
6
6
  "bin": "bin/mcp-trust.js",