mcp-sentinel 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.
Files changed (48) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +290 -0
  3. package/bin/mcp-sentinel.js +2 -0
  4. package/dist/aguara.d.ts +4 -0
  5. package/dist/aguara.d.ts.map +1 -0
  6. package/dist/aguara.js +105 -0
  7. package/dist/aguara.js.map +1 -0
  8. package/dist/analyzer.d.ts +9 -0
  9. package/dist/analyzer.d.ts.map +1 -0
  10. package/dist/analyzer.js +42 -0
  11. package/dist/analyzer.js.map +1 -0
  12. package/dist/cli.d.ts +3 -0
  13. package/dist/cli.d.ts.map +1 -0
  14. package/dist/cli.js +176 -0
  15. package/dist/cli.js.map +1 -0
  16. package/dist/config.d.ts +8 -0
  17. package/dist/config.d.ts.map +1 -0
  18. package/dist/config.js +55 -0
  19. package/dist/config.js.map +1 -0
  20. package/dist/diff.d.ts +3 -0
  21. package/dist/diff.d.ts.map +1 -0
  22. package/dist/diff.js +110 -0
  23. package/dist/diff.js.map +1 -0
  24. package/dist/formatter.d.ts +7 -0
  25. package/dist/formatter.d.ts.map +1 -0
  26. package/dist/formatter.js +184 -0
  27. package/dist/formatter.js.map +1 -0
  28. package/dist/index.d.ts +2 -0
  29. package/dist/index.d.ts.map +1 -0
  30. package/dist/index.js +165 -0
  31. package/dist/index.js.map +1 -0
  32. package/dist/markdown.d.ts +3 -0
  33. package/dist/markdown.d.ts.map +1 -0
  34. package/dist/markdown.js +106 -0
  35. package/dist/markdown.js.map +1 -0
  36. package/dist/policy.d.ts +5 -0
  37. package/dist/policy.d.ts.map +1 -0
  38. package/dist/policy.js +162 -0
  39. package/dist/policy.js.map +1 -0
  40. package/dist/scanner.d.ts +17 -0
  41. package/dist/scanner.d.ts.map +1 -0
  42. package/dist/scanner.js +147 -0
  43. package/dist/scanner.js.map +1 -0
  44. package/dist/types.d.ts +135 -0
  45. package/dist/types.d.ts.map +1 -0
  46. package/dist/types.js +2 -0
  47. package/dist/types.js.map +1 -0
  48. package/package.json +66 -0
package/dist/index.js ADDED
@@ -0,0 +1,165 @@
1
+ import { readFile, writeFile } from "node:fs/promises";
2
+ import chalk from "chalk";
3
+ import { parseArgs } from "./cli.js";
4
+ import { connectToServer, getServerInfo, getServerCapabilities, listTools, listResources, listResourceTemplates, listPrompts, getInstructions, disconnect, } from "./scanner.js";
5
+ import { analyzeTools, summarize } from "./analyzer.js";
6
+ import { scanWithAguara } from "./aguara.js";
7
+ import { formatOutput, formatJson, formatDiff, formatPolicyResult, formatError } from "./formatter.js";
8
+ import { formatMarkdown } from "./markdown.js";
9
+ import { diffScans } from "./diff.js";
10
+ import { discoverServers } from "./config.js";
11
+ import { loadPolicy, findPolicy, evaluatePolicy } from "./policy.js";
12
+ function targetLabel(target) {
13
+ if (target.type === "stdio") {
14
+ return `${target.command} ${target.args.join(" ")}`.trim();
15
+ }
16
+ return target.url;
17
+ }
18
+ async function scanServer(target, timeout) {
19
+ const startTime = Date.now();
20
+ const connection = await connectToServer(target, timeout);
21
+ try {
22
+ const server = getServerInfo(connection.client);
23
+ const capabilities = getServerCapabilities(connection.client);
24
+ const [rawTools, resources, resourceTemplates, prompts] = await Promise.all([
25
+ listTools(connection.client, capabilities.tools),
26
+ listResources(connection.client, capabilities.resources),
27
+ listResourceTemplates(connection.client, capabilities.resources),
28
+ listPrompts(connection.client, capabilities.prompts),
29
+ ]);
30
+ const instructions = getInstructions(connection.client);
31
+ const tools = analyzeTools(rawTools);
32
+ const toolSummary = summarize(tools);
33
+ const aguara = await scanWithAguara(rawTools);
34
+ const scanDuration = Date.now() - startTime;
35
+ return {
36
+ server, capabilities, tools, toolSummary,
37
+ resources, resourceTemplates, prompts, instructions,
38
+ aguara, scanDuration,
39
+ };
40
+ }
41
+ finally {
42
+ await disconnect(connection);
43
+ }
44
+ }
45
+ async function loadBaseline(filePath) {
46
+ const raw = await readFile(filePath, "utf-8");
47
+ return JSON.parse(raw);
48
+ }
49
+ async function main() {
50
+ const options = parseArgs(process.argv);
51
+ if (options === null)
52
+ return;
53
+ if (options.noColor) {
54
+ process.env["FORCE_COLOR"] = "0";
55
+ }
56
+ // Discover servers from config files if --config is set
57
+ if (options.config) {
58
+ const discovered = await discoverServers();
59
+ if (discovered.length === 0) {
60
+ console.error(formatError("No MCP servers found in config files."));
61
+ process.exit(1);
62
+ }
63
+ console.log(chalk.bold(`Found ${discovered.length} server(s) in config files:\n`));
64
+ for (const s of discovered) {
65
+ console.log(` ${chalk.dim(s.source)} ${chalk.cyan(s.name)}`);
66
+ options.targets.push(s.target);
67
+ }
68
+ console.log("");
69
+ }
70
+ const results = [];
71
+ for (const target of options.targets) {
72
+ try {
73
+ const result = await scanServer(target, options.timeout);
74
+ results.push(result);
75
+ if (!options.json && options.diff === false) {
76
+ console.log(formatOutput(result));
77
+ }
78
+ }
79
+ catch (err) {
80
+ const label = targetLabel(target);
81
+ const message = err instanceof Error ? err.message : "Unknown error";
82
+ console.error(formatError(`[${label}] ${message}`));
83
+ }
84
+ }
85
+ if (results.length === 0) {
86
+ console.error(formatError("No servers were scanned successfully."));
87
+ process.exit(1);
88
+ }
89
+ // Diff mode
90
+ if (options.diff !== false) {
91
+ const baseline = await loadBaseline(options.diff);
92
+ for (const current of results) {
93
+ const diff = diffScans(baseline, current);
94
+ if (options.json) {
95
+ console.log(JSON.stringify(diff, null, 2));
96
+ }
97
+ else {
98
+ console.log(formatDiff(diff));
99
+ }
100
+ }
101
+ return;
102
+ }
103
+ if (options.json) {
104
+ const output = results.length === 1 ? results[0] : results;
105
+ console.log(formatJson(output));
106
+ }
107
+ if (options.markdown !== false) {
108
+ const md = formatMarkdown(results);
109
+ await writeFile(options.markdown, md, "utf-8");
110
+ console.log(`Report saved to ${options.markdown}`);
111
+ }
112
+ // Policy enforcement
113
+ let policy = null;
114
+ if (options.policy !== false) {
115
+ const policyPath = options.policy === "auto" ? await findPolicy() : options.policy;
116
+ if (policyPath !== null) {
117
+ policy = await loadPolicy(policyPath);
118
+ if (!options.json) {
119
+ console.log(`\n${chalk.bold("\u{1F6E1}\uFE0F Policy:")} ${policyPath}\n`);
120
+ }
121
+ }
122
+ else if (options.policy === "auto") {
123
+ // No policy file found, skip silently
124
+ }
125
+ else {
126
+ console.error(formatError(`Policy file not found: ${options.policy}`));
127
+ process.exit(1);
128
+ }
129
+ }
130
+ if (policy !== null) {
131
+ let anyFailed = false;
132
+ const policyResults = [];
133
+ for (const scanResult of results) {
134
+ const pr = evaluatePolicy(policy, scanResult);
135
+ policyResults.push({ server: scanResult.server.name, result: pr });
136
+ if (!pr.passed)
137
+ anyFailed = true;
138
+ if (!options.json) {
139
+ console.log(formatPolicyResult(pr, scanResult.server.name));
140
+ }
141
+ }
142
+ if (!options.json) {
143
+ console.log("");
144
+ }
145
+ else {
146
+ console.log(JSON.stringify(policyResults, null, 2));
147
+ }
148
+ if (anyFailed) {
149
+ process.exit(2);
150
+ }
151
+ return;
152
+ }
153
+ // CI exit code: exit 2 if aguara found issues
154
+ if (options.failOnFindings) {
155
+ const hasFindings = results.some((r) => r.aguara.findings.length > 0);
156
+ if (hasFindings) {
157
+ process.exit(2);
158
+ }
159
+ }
160
+ }
161
+ main().catch((err) => {
162
+ console.error(formatError(err instanceof Error ? err.message : "Unexpected error"));
163
+ process.exit(1);
164
+ });
165
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { ScanResult } from "./types.js";
2
+ export declare function formatMarkdown(results: ScanResult[]): string;
3
+ //# sourceMappingURL=markdown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../src/markdown.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAgB,MAAM,YAAY,CAAC;AAe3D,wBAAgB,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,MAAM,CAkG5D"}
@@ -0,0 +1,106 @@
1
+ function truncate(text, max) {
2
+ return text.length > max ? text.slice(0, max - 3) + "..." : text;
3
+ }
4
+ function formatToolRow(analyzed) {
5
+ const desc = truncate(analyzed.tool.description, 80);
6
+ const params = analyzed.tool.parameters.map((p) => {
7
+ const req = p.required ? "**" : "";
8
+ return `${req}${p.name}${req} (${p.type})`;
9
+ }).join(", ");
10
+ return `| \`${analyzed.tool.name}\` | ${analyzed.category} | ${desc} | ${params} |`;
11
+ }
12
+ export function formatMarkdown(results) {
13
+ const lines = [];
14
+ const timestamp = new Date().toISOString().split("T")[0];
15
+ lines.push("# MCP Sentinel Report");
16
+ lines.push("");
17
+ lines.push(`Generated: ${timestamp}`);
18
+ lines.push("");
19
+ for (const result of results) {
20
+ lines.push(`## ${result.server.name} v${result.server.version}`);
21
+ lines.push("");
22
+ // Capabilities
23
+ const caps = [];
24
+ if (result.capabilities.tools)
25
+ caps.push("tools");
26
+ if (result.capabilities.resources)
27
+ caps.push("resources");
28
+ if (result.capabilities.prompts)
29
+ caps.push("prompts");
30
+ if (result.capabilities.logging)
31
+ caps.push("logging");
32
+ lines.push(`- **Capabilities:** ${caps.join(", ") || "none"}`);
33
+ lines.push(`- **Scan time:** ${result.scanDuration}ms`);
34
+ lines.push("");
35
+ // Tools
36
+ if (result.tools.length > 0) {
37
+ lines.push(`### Tools (${result.tools.length}: ${result.toolSummary.read} read, ${result.toolSummary.write} write, ${result.toolSummary.admin} admin)`);
38
+ lines.push("");
39
+ lines.push("| Tool | Category | Description | Parameters |");
40
+ lines.push("|------|----------|-------------|------------|");
41
+ for (const tool of result.tools) {
42
+ lines.push(formatToolRow(tool));
43
+ }
44
+ lines.push("");
45
+ }
46
+ // Resources
47
+ if (result.resources.length > 0 || result.resourceTemplates.length > 0) {
48
+ const total = result.resources.length + result.resourceTemplates.length;
49
+ lines.push(`### Resources (${total})`);
50
+ lines.push("");
51
+ lines.push("| URI | Name | Type |");
52
+ lines.push("|-----|------|------|");
53
+ for (const r of result.resources) {
54
+ lines.push(`| \`${r.uri}\` | ${r.name} | ${r.mimeType} |`);
55
+ }
56
+ for (const r of result.resourceTemplates) {
57
+ lines.push(`| \`${r.uriTemplate}\` | ${r.name} | ${r.mimeType} |`);
58
+ }
59
+ lines.push("");
60
+ }
61
+ // Prompts
62
+ if (result.prompts.length > 0) {
63
+ lines.push(`### Prompts (${result.prompts.length})`);
64
+ lines.push("");
65
+ lines.push("| Prompt | Description | Arguments |");
66
+ lines.push("|--------|-------------|-----------|");
67
+ for (const p of result.prompts) {
68
+ const args = p.arguments.map((a) => `${a.required ? "**" : ""}${a.name}${a.required ? "**" : ""}`).join(", ");
69
+ lines.push(`| \`${p.name}\` | ${truncate(p.description, 60)} | ${args} |`);
70
+ }
71
+ lines.push("");
72
+ }
73
+ // Instructions
74
+ if (result.instructions !== null) {
75
+ lines.push("### Server Instructions");
76
+ lines.push("");
77
+ lines.push("```");
78
+ lines.push(result.instructions);
79
+ lines.push("```");
80
+ lines.push("");
81
+ }
82
+ // Aguara
83
+ if (result.aguara.available && result.aguara.findings.length > 0) {
84
+ lines.push("### Security Findings (Aguara)");
85
+ lines.push("");
86
+ lines.push("| Severity | Rule | Description |");
87
+ lines.push("|----------|------|-------------|");
88
+ for (const f of result.aguara.findings) {
89
+ lines.push(`| ${f.severity} | ${f.ruleId} | ${f.ruleName} |`);
90
+ }
91
+ lines.push("");
92
+ lines.push(`> ${result.aguara.summary}`);
93
+ lines.push("");
94
+ }
95
+ else if (!result.aguara.available) {
96
+ lines.push(`> ${result.aguara.summary}`);
97
+ lines.push("");
98
+ }
99
+ }
100
+ lines.push("---");
101
+ lines.push("");
102
+ lines.push("Deep scan: [aguarascan.com](https://aguarascan.com)");
103
+ lines.push("");
104
+ return lines.join("\n");
105
+ }
106
+ //# sourceMappingURL=markdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.js","sourceRoot":"","sources":["../src/markdown.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { Policy, PolicyResult, ScanResult } from "./types.js";
2
+ export declare function evaluatePolicy(policy: Policy, result: ScanResult): PolicyResult;
3
+ export declare function loadPolicy(filePath: string): Promise<Policy>;
4
+ export declare function findPolicy(): Promise<string | null>;
5
+ //# sourceMappingURL=policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAA+B,YAAY,EAAE,UAAU,EAAgB,MAAM,YAAY,CAAC;AAwF9G,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,YAAY,CAqE/E;AAED,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAKlE;AAID,wBAAsB,UAAU,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAUzD"}
package/dist/policy.js ADDED
@@ -0,0 +1,162 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { resolve } from "node:path";
3
+ import { parse as parseYaml } from "yaml";
4
+ const VALID_CATEGORIES = new Set(["read", "write", "admin"]);
5
+ function validatePolicy(raw) {
6
+ if (typeof raw !== "object" || raw === null) {
7
+ throw new Error("Policy file must be a YAML object");
8
+ }
9
+ const obj = raw;
10
+ const rules = {};
11
+ if (obj["deny"] !== undefined) {
12
+ if (typeof obj["deny"] !== "object" || obj["deny"] === null) {
13
+ throw new Error("Policy 'deny' must be an object");
14
+ }
15
+ const deny = obj["deny"];
16
+ rules.deny = {};
17
+ if (deny["categories"] !== undefined) {
18
+ if (!Array.isArray(deny["categories"])) {
19
+ throw new Error("Policy 'deny.categories' must be an array");
20
+ }
21
+ for (const c of deny["categories"]) {
22
+ if (!VALID_CATEGORIES.has(String(c))) {
23
+ throw new Error(`Invalid category '${String(c)}' in deny.categories. Valid: read, write, admin`);
24
+ }
25
+ }
26
+ rules.deny.categories = deny["categories"];
27
+ }
28
+ if (deny["tools"] !== undefined) {
29
+ if (!Array.isArray(deny["tools"])) {
30
+ throw new Error("Policy 'deny.tools' must be an array");
31
+ }
32
+ rules.deny.tools = deny["tools"].map(String);
33
+ }
34
+ }
35
+ if (obj["require"] !== undefined) {
36
+ if (typeof obj["require"] !== "object" || obj["require"] === null) {
37
+ throw new Error("Policy 'require' must be an object");
38
+ }
39
+ const req = obj["require"];
40
+ rules.require = {};
41
+ if (req["aguara"] !== undefined) {
42
+ if (req["aguara"] !== "clean") {
43
+ throw new Error("Policy 'require.aguara' must be 'clean'");
44
+ }
45
+ rules.require.aguara = "clean";
46
+ }
47
+ if (req["maxTools"] !== undefined) {
48
+ const n = Number(req["maxTools"]);
49
+ if (!Number.isInteger(n) || n < 0) {
50
+ throw new Error("Policy 'require.maxTools' must be a non-negative integer");
51
+ }
52
+ rules.require.maxTools = n;
53
+ }
54
+ }
55
+ if (obj["allow"] !== undefined) {
56
+ if (typeof obj["allow"] !== "object" || obj["allow"] === null) {
57
+ throw new Error("Policy 'allow' must be an object");
58
+ }
59
+ const allow = obj["allow"];
60
+ rules.allow = {};
61
+ if (allow["tools"] !== undefined) {
62
+ if (!Array.isArray(allow["tools"])) {
63
+ throw new Error("Policy 'allow.tools' must be an array");
64
+ }
65
+ rules.allow.tools = allow["tools"].map(String);
66
+ }
67
+ }
68
+ return { rules };
69
+ }
70
+ function matchesPattern(name, pattern) {
71
+ if (pattern.includes("*")) {
72
+ const regex = new RegExp("^" + pattern.replace(/\*/g, ".*") + "$");
73
+ return regex.test(name);
74
+ }
75
+ return name === pattern;
76
+ }
77
+ export function evaluatePolicy(policy, result) {
78
+ const violations = [];
79
+ const { rules } = policy;
80
+ const allowedTools = rules.allow?.tools;
81
+ // deny.categories
82
+ if (rules.deny?.categories !== undefined) {
83
+ for (const tool of result.tools) {
84
+ if (rules.deny.categories.includes(tool.category)) {
85
+ // Check if explicitly allowed
86
+ if (allowedTools !== undefined && allowedTools.some((p) => matchesPattern(tool.tool.name, p))) {
87
+ continue;
88
+ }
89
+ violations.push({
90
+ rule: "deny.categories",
91
+ message: `Tool '${tool.tool.name}' has denied category '${tool.category}'`,
92
+ severity: "error",
93
+ });
94
+ }
95
+ }
96
+ }
97
+ // deny.tools
98
+ if (rules.deny?.tools !== undefined) {
99
+ for (const tool of result.tools) {
100
+ for (const pattern of rules.deny.tools) {
101
+ if (matchesPattern(tool.tool.name, pattern)) {
102
+ if (allowedTools !== undefined && allowedTools.some((p) => matchesPattern(tool.tool.name, p))) {
103
+ continue;
104
+ }
105
+ violations.push({
106
+ rule: "deny.tools",
107
+ message: `Tool '${tool.tool.name}' matches denied pattern '${pattern}'`,
108
+ severity: "error",
109
+ });
110
+ }
111
+ }
112
+ }
113
+ }
114
+ // require.aguara
115
+ if (rules.require?.aguara === "clean") {
116
+ if (!result.aguara.available) {
117
+ violations.push({
118
+ rule: "require.aguara",
119
+ message: "Policy requires aguara but it is not installed",
120
+ severity: "error",
121
+ });
122
+ }
123
+ else if (result.aguara.findings.length > 0) {
124
+ violations.push({
125
+ rule: "require.aguara",
126
+ message: `Aguara found ${result.aguara.findings.length} security issue(s)`,
127
+ severity: "error",
128
+ });
129
+ }
130
+ }
131
+ // require.maxTools
132
+ if (rules.require?.maxTools !== undefined) {
133
+ if (result.tools.length > rules.require.maxTools) {
134
+ violations.push({
135
+ rule: "require.maxTools",
136
+ message: `Server exposes ${result.tools.length} tools, policy allows max ${rules.require.maxTools}`,
137
+ severity: "error",
138
+ });
139
+ }
140
+ }
141
+ return { passed: violations.length === 0, violations };
142
+ }
143
+ export async function loadPolicy(filePath) {
144
+ const resolved = resolve(filePath);
145
+ const raw = await readFile(resolved, "utf-8");
146
+ const parsed = parseYaml(raw);
147
+ return validatePolicy(parsed);
148
+ }
149
+ const DEFAULT_PATHS = [".mcp-policy.yml", ".mcp-policy.yaml"];
150
+ export async function findPolicy() {
151
+ for (const path of DEFAULT_PATHS) {
152
+ try {
153
+ await readFile(resolve(path), "utf-8");
154
+ return path;
155
+ }
156
+ catch {
157
+ continue;
158
+ }
159
+ }
160
+ return null;
161
+ }
162
+ //# sourceMappingURL=policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.js","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
2
+ import type { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
3
+ import type { ServerInfo, ServerCapabilities, ServerTarget, ToolInfo, ResourceInfo, ResourceTemplateInfo, PromptInfo } from "./types.js";
4
+ export interface ScanConnection {
5
+ client: Client;
6
+ transport: Transport;
7
+ }
8
+ export declare function connectToServer(target: ServerTarget, timeout: number): Promise<ScanConnection>;
9
+ export declare function getServerInfo(client: Client): ServerInfo;
10
+ export declare function getServerCapabilities(client: Client): ServerCapabilities;
11
+ export declare function listTools(client: Client, supported: boolean): Promise<ToolInfo[]>;
12
+ export declare function listResources(client: Client, supported: boolean): Promise<ResourceInfo[]>;
13
+ export declare function listResourceTemplates(client: Client, supported: boolean): Promise<ResourceTemplateInfo[]>;
14
+ export declare function listPrompts(client: Client, supported: boolean): Promise<PromptInfo[]>;
15
+ export declare function getInstructions(client: Client): string | null;
16
+ export declare function disconnect(connection: ScanConnection): Promise<void>;
17
+ //# sourceMappingURL=scanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAInE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+CAA+C,CAAC;AAC/E,OAAO,KAAK,EACV,UAAU,EACV,kBAAkB,EAClB,YAAY,EACZ,QAAQ,EAER,YAAY,EACZ,oBAAoB,EACpB,UAAU,EAEX,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,SAAS,CAAC;CACtB;AAiBD,wBAAsB,eAAe,CACnC,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,cAAc,CAAC,CAezB;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAMxD;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,kBAAkB,CAQxE;AAwBD,wBAAsB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAUvF;AAED,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAc/F;AAED,wBAAsB,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAc/G;AAED,wBAAsB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAiB3F;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAO7D;AAED,wBAAsB,UAAU,CAAC,UAAU,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAG1E"}
@@ -0,0 +1,147 @@
1
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
2
+ import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
3
+ import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
4
+ import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
5
+ function createTransport(target) {
6
+ switch (target.type) {
7
+ case "stdio":
8
+ return new StdioClientTransport({
9
+ command: target.command,
10
+ args: target.args,
11
+ stderr: "pipe",
12
+ });
13
+ case "sse":
14
+ return new SSEClientTransport(new URL(target.url));
15
+ case "streamable-http":
16
+ return new StreamableHTTPClientTransport(new URL(target.url));
17
+ }
18
+ }
19
+ export async function connectToServer(target, timeout) {
20
+ const transport = createTransport(target);
21
+ const client = new Client({
22
+ name: "mcp-sentinel",
23
+ version: "0.1.0",
24
+ });
25
+ const connectPromise = client.connect(transport);
26
+ const timeoutPromise = new Promise((_resolve, reject) => {
27
+ setTimeout(() => reject(new Error(`Connection timed out after ${timeout}ms`)), timeout);
28
+ });
29
+ await Promise.race([connectPromise, timeoutPromise]);
30
+ return { client, transport };
31
+ }
32
+ export function getServerInfo(client) {
33
+ const info = client.getServerVersion();
34
+ return {
35
+ name: info?.name ?? "unknown",
36
+ version: info?.version ?? "unknown",
37
+ };
38
+ }
39
+ export function getServerCapabilities(client) {
40
+ const caps = client.getServerCapabilities();
41
+ return {
42
+ tools: caps?.tools !== undefined,
43
+ resources: caps?.resources !== undefined,
44
+ prompts: caps?.prompts !== undefined,
45
+ logging: caps?.logging !== undefined,
46
+ };
47
+ }
48
+ function extractSchemaProperties(schema) {
49
+ const properties = schema["properties"];
50
+ if (typeof properties !== "object" || properties === null) {
51
+ return [];
52
+ }
53
+ const requiredArr = Array.isArray(schema["required"]) ? schema["required"] : [];
54
+ const props = properties;
55
+ const result = [];
56
+ for (const [name, def] of Object.entries(props)) {
57
+ result.push({
58
+ name,
59
+ type: typeof def["type"] === "string" ? def["type"] : "unknown",
60
+ required: requiredArr.includes(name),
61
+ description: typeof def["description"] === "string" ? def["description"] : "",
62
+ });
63
+ }
64
+ return result;
65
+ }
66
+ export async function listTools(client, supported) {
67
+ if (!supported)
68
+ return [];
69
+ const result = await client.listTools();
70
+ return result.tools.map((tool) => ({
71
+ name: tool.name,
72
+ description: tool.description ?? "",
73
+ parameters: extractSchemaProperties(tool.inputSchema),
74
+ rawInputSchema: tool.inputSchema,
75
+ }));
76
+ }
77
+ export async function listResources(client, supported) {
78
+ if (!supported)
79
+ return [];
80
+ try {
81
+ const result = await client.listResources();
82
+ return result.resources.map((r) => ({
83
+ uri: r.uri,
84
+ name: r.name ?? "",
85
+ description: typeof r.description === "string" ? r.description : "",
86
+ mimeType: typeof r.mimeType === "string" ? r.mimeType : "",
87
+ }));
88
+ }
89
+ catch {
90
+ return [];
91
+ }
92
+ }
93
+ export async function listResourceTemplates(client, supported) {
94
+ if (!supported)
95
+ return [];
96
+ try {
97
+ const result = await client.listResourceTemplates();
98
+ return result.resourceTemplates.map((r) => ({
99
+ uriTemplate: r.uriTemplate,
100
+ name: r.name ?? "",
101
+ description: typeof r.description === "string" ? r.description : "",
102
+ mimeType: typeof r.mimeType === "string" ? r.mimeType : "",
103
+ }));
104
+ }
105
+ catch {
106
+ return [];
107
+ }
108
+ }
109
+ export async function listPrompts(client, supported) {
110
+ if (!supported)
111
+ return [];
112
+ try {
113
+ const result = await client.listPrompts();
114
+ return result.prompts.map((p) => ({
115
+ name: p.name,
116
+ description: typeof p.description === "string" ? p.description : "",
117
+ arguments: Array.isArray(p.arguments) ? p.arguments.map((a) => ({
118
+ name: a.name,
119
+ description: typeof a.description === "string" ? a.description : "",
120
+ required: a.required === true,
121
+ })) : [],
122
+ }));
123
+ }
124
+ catch {
125
+ return [];
126
+ }
127
+ }
128
+ export function getInstructions(client) {
129
+ try {
130
+ const instructions = client.getInstructions();
131
+ return typeof instructions === "string" && instructions.length > 0 ? instructions : null;
132
+ }
133
+ catch {
134
+ return null;
135
+ }
136
+ }
137
+ export async function disconnect(connection) {
138
+ try {
139
+ await connection.client.close();
140
+ }
141
+ catch { /* cleanup */ }
142
+ try {
143
+ await connection.transport.close();
144
+ }
145
+ catch { /* cleanup */ }
146
+ }
147
+ //# sourceMappingURL=scanner.js.map