acidtest 0.1.3 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +91 -11
- package/dist/index.js +146 -35
- package/dist/index.js.map +1 -1
- package/dist/loaders/mcp-loader.d.ts +28 -0
- package/dist/loaders/mcp-loader.d.ts.map +1 -0
- package/dist/loaders/mcp-loader.js +191 -0
- package/dist/loaders/mcp-loader.js.map +1 -0
- package/dist/mcp-server.d.ts +7 -0
- package/dist/mcp-server.d.ts.map +1 -0
- package/dist/mcp-server.js +159 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/scanner.d.ts +2 -2
- package/dist/scanner.d.ts.map +1 -1
- package/dist/scanner.js +125 -68
- package/dist/scanner.js.map +1 -1
- package/package.json +4 -2
- package/test-fixtures/README.md +157 -0
- package/test-fixtures/fixture-danger/SKILL.md +27 -0
- package/test-fixtures/fixture-danger/handler.ts +29 -0
- package/test-fixtures/fixture-fail/SKILL.md +32 -0
- package/test-fixtures/fixture-fail/handler.ts +26 -0
- package/test-fixtures/fixture-mcp-pass/index.js +26 -0
- package/test-fixtures/fixture-mcp-pass/mcp.json +31 -0
- package/test-fixtures/fixture-pass/SKILL.md +32 -0
- package/test-fixtures/fixture-pass/handler.ts +17 -0
- package/test-fixtures/fixture-warn/SKILL.md +28 -0
- package/test-fixtures/fixture-warn/handler.ts +20 -0
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP server manifest loader
|
|
3
|
+
* Detects and parses MCP server configuration files
|
|
4
|
+
*/
|
|
5
|
+
import { readFileSync, existsSync } from "fs";
|
|
6
|
+
import { join } from "path";
|
|
7
|
+
/**
|
|
8
|
+
* Detect if a directory contains an MCP server manifest
|
|
9
|
+
* Returns the path to the manifest if found, otherwise null
|
|
10
|
+
*/
|
|
11
|
+
export function detectMCPManifest(directory) {
|
|
12
|
+
// Check for various MCP manifest files in order of preference
|
|
13
|
+
const manifestFiles = [
|
|
14
|
+
"mcp.json",
|
|
15
|
+
"server.json",
|
|
16
|
+
"package.json",
|
|
17
|
+
"claude_desktop_config.json",
|
|
18
|
+
];
|
|
19
|
+
for (const filename of manifestFiles) {
|
|
20
|
+
const manifestPath = join(directory, filename);
|
|
21
|
+
if (existsSync(manifestPath)) {
|
|
22
|
+
// For package.json, verify it has MCP-related config
|
|
23
|
+
if (filename === "package.json") {
|
|
24
|
+
try {
|
|
25
|
+
const content = JSON.parse(readFileSync(manifestPath, "utf-8"));
|
|
26
|
+
if (content.mcp || content.mcpServers) {
|
|
27
|
+
return manifestPath;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
return manifestPath;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Parse an MCP manifest file
|
|
43
|
+
*/
|
|
44
|
+
export function parseMCPManifest(manifestPath) {
|
|
45
|
+
const content = readFileSync(manifestPath, "utf-8");
|
|
46
|
+
const rawConfig = JSON.parse(content);
|
|
47
|
+
const filename = manifestPath.split("/").pop();
|
|
48
|
+
// Extract metadata based on format
|
|
49
|
+
let metadata;
|
|
50
|
+
if (filename === "mcp.json" || filename === "server.json") {
|
|
51
|
+
metadata = extractFromMCPJson(rawConfig);
|
|
52
|
+
}
|
|
53
|
+
else if (filename === "package.json") {
|
|
54
|
+
metadata = extractFromPackageJson(rawConfig);
|
|
55
|
+
}
|
|
56
|
+
else if (filename === "claude_desktop_config.json") {
|
|
57
|
+
metadata = extractFromClaudeConfig(rawConfig);
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
throw new Error(`Unsupported MCP manifest format: ${filename}`);
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
format: filename,
|
|
64
|
+
path: manifestPath,
|
|
65
|
+
metadata,
|
|
66
|
+
rawConfig,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Extract metadata from mcp.json or server.json
|
|
71
|
+
*/
|
|
72
|
+
function extractFromMCPJson(config) {
|
|
73
|
+
const metadata = {
|
|
74
|
+
name: config.name || "unknown-mcp-server",
|
|
75
|
+
description: config.description,
|
|
76
|
+
version: config.version,
|
|
77
|
+
};
|
|
78
|
+
// Extract tools
|
|
79
|
+
if (config.tools && Array.isArray(config.tools)) {
|
|
80
|
+
metadata["allowed-tools"] = config.tools.map((tool) => {
|
|
81
|
+
if (typeof tool === "string")
|
|
82
|
+
return tool;
|
|
83
|
+
return tool.name || "unknown-tool";
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
// Extract environment variables
|
|
87
|
+
if (config.env) {
|
|
88
|
+
if (typeof config.env === "object") {
|
|
89
|
+
metadata.env = Object.keys(config.env);
|
|
90
|
+
}
|
|
91
|
+
else if (Array.isArray(config.env)) {
|
|
92
|
+
metadata.env = config.env;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// Extract command/binary
|
|
96
|
+
if (config.command) {
|
|
97
|
+
metadata.bins = [config.command];
|
|
98
|
+
// Add args that look like binaries
|
|
99
|
+
if (config.args && Array.isArray(config.args)) {
|
|
100
|
+
const binaryArgs = config.args.filter((arg) => typeof arg === "string" && !arg.includes("/") && !arg.startsWith("-"));
|
|
101
|
+
if (binaryArgs.length > 0) {
|
|
102
|
+
metadata.bins = [...(metadata.bins || []), ...binaryArgs];
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// Check transport for network implications
|
|
107
|
+
if (config.transport === "sse") {
|
|
108
|
+
// SSE implies network access
|
|
109
|
+
metadata["allowed-tools"] = [
|
|
110
|
+
...(metadata["allowed-tools"] || []),
|
|
111
|
+
"network",
|
|
112
|
+
];
|
|
113
|
+
}
|
|
114
|
+
return metadata;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Extract metadata from package.json with MCP config
|
|
118
|
+
*/
|
|
119
|
+
function extractFromPackageJson(config) {
|
|
120
|
+
const metadata = {
|
|
121
|
+
name: config.name || "unknown-mcp-server",
|
|
122
|
+
description: config.description,
|
|
123
|
+
version: config.version,
|
|
124
|
+
};
|
|
125
|
+
// Check for mcp config
|
|
126
|
+
const mcpConfig = config.mcp || config.mcpServers;
|
|
127
|
+
if (!mcpConfig) {
|
|
128
|
+
return metadata;
|
|
129
|
+
}
|
|
130
|
+
// If mcpConfig is an object with server definitions
|
|
131
|
+
if (typeof mcpConfig === "object" && !Array.isArray(mcpConfig)) {
|
|
132
|
+
// Could be a direct config or a servers map
|
|
133
|
+
if (mcpConfig.tools) {
|
|
134
|
+
// Direct config
|
|
135
|
+
return {
|
|
136
|
+
...metadata,
|
|
137
|
+
...extractFromMCPJson(mcpConfig),
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
// Servers map - take the first server
|
|
142
|
+
const firstServer = Object.values(mcpConfig)[0];
|
|
143
|
+
if (firstServer) {
|
|
144
|
+
return {
|
|
145
|
+
...metadata,
|
|
146
|
+
...extractFromMCPJson(firstServer),
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return metadata;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Extract metadata from claude_desktop_config.json
|
|
155
|
+
*/
|
|
156
|
+
function extractFromClaudeConfig(config) {
|
|
157
|
+
const metadata = {
|
|
158
|
+
name: "claude-desktop-mcp-servers",
|
|
159
|
+
description: "MCP servers from Claude Desktop config",
|
|
160
|
+
};
|
|
161
|
+
// Extract from mcpServers
|
|
162
|
+
if (config.mcpServers && typeof config.mcpServers === "object") {
|
|
163
|
+
const allTools = [];
|
|
164
|
+
const allEnv = [];
|
|
165
|
+
const allBins = [];
|
|
166
|
+
// Combine all servers
|
|
167
|
+
for (const [serverName, serverConfig] of Object.entries(config.mcpServers)) {
|
|
168
|
+
const server = serverConfig;
|
|
169
|
+
// Extract command
|
|
170
|
+
if (server.command) {
|
|
171
|
+
allBins.push(server.command);
|
|
172
|
+
}
|
|
173
|
+
// Extract env
|
|
174
|
+
if (server.env && typeof server.env === "object") {
|
|
175
|
+
allEnv.push(...Object.keys(server.env));
|
|
176
|
+
}
|
|
177
|
+
// Extract tools if present
|
|
178
|
+
if (server.tools && Array.isArray(server.tools)) {
|
|
179
|
+
allTools.push(...server.tools.map((t) => typeof t === "string" ? t : t.name || "unknown-tool"));
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
if (allTools.length > 0)
|
|
183
|
+
metadata["allowed-tools"] = [...new Set(allTools)];
|
|
184
|
+
if (allEnv.length > 0)
|
|
185
|
+
metadata.env = [...new Set(allEnv)];
|
|
186
|
+
if (allBins.length > 0)
|
|
187
|
+
metadata.bins = [...new Set(allBins)];
|
|
188
|
+
}
|
|
189
|
+
return metadata;
|
|
190
|
+
}
|
|
191
|
+
//# sourceMappingURL=mcp-loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-loader.js","sourceRoot":"","sources":["../../src/loaders/mcp-loader.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAC9C,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAsB5B;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,SAAiB;IACjD,8DAA8D;IAC9D,MAAM,aAAa,GAAwB;QACzC,UAAU;QACV,aAAa;QACb,cAAc;QACd,4BAA4B;KAC7B,CAAC;IAEF,KAAK,MAAM,QAAQ,IAAI,aAAa,EAAE,CAAC;QACrC,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QAC/C,IAAI,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YAC7B,qDAAqD;YACrD,IAAI,QAAQ,KAAK,cAAc,EAAE,CAAC;gBAChC,IAAI,CAAC;oBACH,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC;oBAChE,IAAI,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;wBACtC,OAAO,YAAY,CAAC;oBACtB,CAAC;gBACH,CAAC;gBAAC,MAAM,CAAC;oBACP,SAAS;gBACX,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,OAAO,YAAY,CAAC;YACtB,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,YAAoB;IACnD,MAAM,OAAO,GAAG,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IACpD,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACtC,MAAM,QAAQ,GAAG,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAuB,CAAC;IAEpE,mCAAmC;IACnC,IAAI,QAAuB,CAAC;IAE5B,IAAI,QAAQ,KAAK,UAAU,IAAI,QAAQ,KAAK,aAAa,EAAE,CAAC;QAC1D,QAAQ,GAAG,kBAAkB,CAAC,SAAS,CAAC,CAAC;IAC3C,CAAC;SAAM,IAAI,QAAQ,KAAK,cAAc,EAAE,CAAC;QACvC,QAAQ,GAAG,sBAAsB,CAAC,SAAS,CAAC,CAAC;IAC/C,CAAC;SAAM,IAAI,QAAQ,KAAK,4BAA4B,EAAE,CAAC;QACrD,QAAQ,GAAG,uBAAuB,CAAC,SAAS,CAAC,CAAC;IAChD,CAAC;SAAM,CAAC;QACN,MAAM,IAAI,KAAK,CAAC,oCAAoC,QAAQ,EAAE,CAAC,CAAC;IAClE,CAAC;IAED,OAAO;QACL,MAAM,EAAE,QAAQ;QAChB,IAAI,EAAE,YAAY;QAClB,QAAQ;QACR,SAAS;KACV,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAS,kBAAkB,CAAC,MAAW;IACrC,MAAM,QAAQ,GAAkB;QAC9B,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,oBAAoB;QACzC,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,OAAO,EAAE,MAAM,CAAC,OAAO;KACxB,CAAC;IAEF,gBAAgB;IAChB,IAAI,MAAM,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QAChD,QAAQ,CAAC,eAAe,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAS,EAAE,EAAE;YACzD,IAAI,OAAO,IAAI,KAAK,QAAQ;gBAAE,OAAO,IAAI,CAAC;YAC1C,OAAO,IAAI,CAAC,IAAI,IAAI,cAAc,CAAC;QACrC,CAAC,CAAC,CAAC;IACL,CAAC;IAED,gCAAgC;IAChC,IAAI,MAAM,CAAC,GAAG,EAAE,CAAC;QACf,IAAI,OAAO,MAAM,CAAC,GAAG,KAAK,QAAQ,EAAE,CAAC;YACnC,QAAQ,CAAC,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACzC,CAAC;aAAM,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;YACrC,QAAQ,CAAC,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC;QAC5B,CAAC;IACH,CAAC;IAED,yBAAyB;IACzB,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,QAAQ,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAEjC,mCAAmC;QACnC,IAAI,MAAM,CAAC,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9C,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAW,EAAE,EAAE,CACpD,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CACtE,CAAC;YACF,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC1B,QAAQ,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,IAAI,EAAE,CAAC,EAAE,GAAG,UAAU,CAAC,CAAC;YAC5D,CAAC;QACH,CAAC;IACH,CAAC;IAED,2CAA2C;IAC3C,IAAI,MAAM,CAAC,SAAS,KAAK,KAAK,EAAE,CAAC;QAC/B,6BAA6B;QAC7B,QAAQ,CAAC,eAAe,CAAC,GAAG;YAC1B,GAAG,CAAC,QAAQ,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC;YACpC,SAAS;SACV,CAAC;IACJ,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;GAEG;AACH,SAAS,sBAAsB,CAAC,MAAW;IACzC,MAAM,QAAQ,GAAkB;QAC9B,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,oBAAoB;QACzC,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,OAAO,EAAE,MAAM,CAAC,OAAO;KACxB,CAAC;IAEF,uBAAuB;IACvB,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,UAAU,CAAC;IAClD,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,oDAAoD;IACpD,IAAI,OAAO,SAAS,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;QAC/D,4CAA4C;QAC5C,IAAI,SAAS,CAAC,KAAK,EAAE,CAAC;YACpB,gBAAgB;YAChB,OAAO;gBACL,GAAG,QAAQ;gBACX,GAAG,kBAAkB,CAAC,SAAS,CAAC;aACjC,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,sCAAsC;YACtC,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAQ,CAAC;YACvD,IAAI,WAAW,EAAE,CAAC;gBAChB,OAAO;oBACL,GAAG,QAAQ;oBACX,GAAG,kBAAkB,CAAC,WAAW,CAAC;iBACnC,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;GAEG;AACH,SAAS,uBAAuB,CAAC,MAAW;IAC1C,MAAM,QAAQ,GAAkB;QAC9B,IAAI,EAAE,4BAA4B;QAClC,WAAW,EAAE,wCAAwC;KACtD,CAAC;IAEF,0BAA0B;IAC1B,IAAI,MAAM,CAAC,UAAU,IAAI,OAAO,MAAM,CAAC,UAAU,KAAK,QAAQ,EAAE,CAAC;QAC/D,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,MAAM,OAAO,GAAa,EAAE,CAAC;QAE7B,sBAAsB;QACtB,KAAK,MAAM,CAAC,UAAU,EAAE,YAAY,CAAC,IAAI,MAAM,CAAC,OAAO,CACrD,MAAM,CAAC,UAAU,CAClB,EAAE,CAAC;YACF,MAAM,MAAM,GAAG,YAAmB,CAAC;YAEnC,kBAAkB;YAClB,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;gBACnB,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YAC/B,CAAC;YAED,cAAc;YACd,IAAI,MAAM,CAAC,GAAG,IAAI,OAAO,MAAM,CAAC,GAAG,KAAK,QAAQ,EAAE,CAAC;gBACjD,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YAC1C,CAAC;YAED,2BAA2B;YAC3B,IAAI,MAAM,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;gBAChD,QAAQ,CAAC,IAAI,CACX,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAC7B,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,cAAc,CACrD,CACF,CAAC;YACJ,CAAC;QACH,CAAC;QAED,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;YAAE,QAAQ,CAAC,eAAe,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC5E,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;YAAE,QAAQ,CAAC,GAAG,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;QAC3D,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;YAAE,QAAQ,CAAC,IAAI,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;IAChE,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-server.d.ts","sourceRoot":"","sources":["../src/mcp-server.ts"],"names":[],"mappings":";AAEA;;;GAGG"}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* AcidTest MCP Server
|
|
4
|
+
* Exposes AcidTest scanning as an MCP tool for AI agents
|
|
5
|
+
*/
|
|
6
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
7
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
8
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
9
|
+
import { scanSkill, scanAllSkills } from "./scanner.js";
|
|
10
|
+
const VERSION = "0.2.1";
|
|
11
|
+
/**
|
|
12
|
+
* Create and configure the MCP server
|
|
13
|
+
*/
|
|
14
|
+
function createServer() {
|
|
15
|
+
const server = new Server({
|
|
16
|
+
name: "acidtest",
|
|
17
|
+
version: VERSION,
|
|
18
|
+
}, {
|
|
19
|
+
capabilities: {
|
|
20
|
+
tools: {},
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
/**
|
|
24
|
+
* List available tools
|
|
25
|
+
*/
|
|
26
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
27
|
+
return {
|
|
28
|
+
tools: [
|
|
29
|
+
{
|
|
30
|
+
name: "scan_skill",
|
|
31
|
+
description: "Scan an AI agent skill or MCP server for security vulnerabilities. Returns a trust score (0-100) and detailed findings across four security layers: permissions audit, prompt injection detection, code analysis, and cross-reference validation.",
|
|
32
|
+
inputSchema: {
|
|
33
|
+
type: "object",
|
|
34
|
+
properties: {
|
|
35
|
+
path: {
|
|
36
|
+
type: "string",
|
|
37
|
+
description: "Path to the skill directory, SKILL.md file, or MCP server manifest (mcp.json, server.json, package.json)",
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
required: ["path"],
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
name: "scan_all",
|
|
45
|
+
description: "Recursively scan all skills and MCP servers in a directory. Returns an array of scan results with trust scores and findings for each skill/server found.",
|
|
46
|
+
inputSchema: {
|
|
47
|
+
type: "object",
|
|
48
|
+
properties: {
|
|
49
|
+
directory: {
|
|
50
|
+
type: "string",
|
|
51
|
+
description: "Path to the directory containing skills/servers",
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
required: ["directory"],
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
};
|
|
59
|
+
});
|
|
60
|
+
/**
|
|
61
|
+
* Handle tool calls
|
|
62
|
+
*/
|
|
63
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
64
|
+
const { name, arguments: args } = request.params;
|
|
65
|
+
try {
|
|
66
|
+
if (name === "scan_skill") {
|
|
67
|
+
// Validate arguments
|
|
68
|
+
if (!args || typeof args !== "object" || !("path" in args)) {
|
|
69
|
+
return {
|
|
70
|
+
content: [
|
|
71
|
+
{
|
|
72
|
+
type: "text",
|
|
73
|
+
text: "Error: Missing required argument 'path'",
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
isError: true,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
const path = args.path;
|
|
80
|
+
// Run scan
|
|
81
|
+
const result = await scanSkill(path);
|
|
82
|
+
// Return result as JSON
|
|
83
|
+
return {
|
|
84
|
+
content: [
|
|
85
|
+
{
|
|
86
|
+
type: "text",
|
|
87
|
+
text: JSON.stringify(result, null, 2),
|
|
88
|
+
},
|
|
89
|
+
],
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
else if (name === "scan_all") {
|
|
93
|
+
// Validate arguments
|
|
94
|
+
if (!args || typeof args !== "object" || !("directory" in args)) {
|
|
95
|
+
return {
|
|
96
|
+
content: [
|
|
97
|
+
{
|
|
98
|
+
type: "text",
|
|
99
|
+
text: "Error: Missing required argument 'directory'",
|
|
100
|
+
},
|
|
101
|
+
],
|
|
102
|
+
isError: true,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
const directory = args.directory;
|
|
106
|
+
// Run scan
|
|
107
|
+
const results = await scanAllSkills(directory);
|
|
108
|
+
// Return results as JSON
|
|
109
|
+
return {
|
|
110
|
+
content: [
|
|
111
|
+
{
|
|
112
|
+
type: "text",
|
|
113
|
+
text: JSON.stringify(results, null, 2),
|
|
114
|
+
},
|
|
115
|
+
],
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
return {
|
|
120
|
+
content: [
|
|
121
|
+
{
|
|
122
|
+
type: "text",
|
|
123
|
+
text: `Error: Unknown tool '${name}'`,
|
|
124
|
+
},
|
|
125
|
+
],
|
|
126
|
+
isError: true,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
return {
|
|
132
|
+
content: [
|
|
133
|
+
{
|
|
134
|
+
type: "text",
|
|
135
|
+
text: `Error: ${error.message}`,
|
|
136
|
+
},
|
|
137
|
+
],
|
|
138
|
+
isError: true,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
return server;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Start the MCP server
|
|
146
|
+
*/
|
|
147
|
+
async function main() {
|
|
148
|
+
const server = createServer();
|
|
149
|
+
const transport = new StdioServerTransport();
|
|
150
|
+
await server.connect(transport);
|
|
151
|
+
// Log to stderr (stdout is reserved for MCP protocol)
|
|
152
|
+
console.error(`AcidTest MCP Server v${VERSION} running on stdio`);
|
|
153
|
+
}
|
|
154
|
+
// Start server
|
|
155
|
+
main().catch((error) => {
|
|
156
|
+
console.error("Fatal error in MCP server:", error);
|
|
157
|
+
process.exit(1);
|
|
158
|
+
});
|
|
159
|
+
//# sourceMappingURL=mcp-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-server.js","sourceRoot":"","sources":["../src/mcp-server.ts"],"names":[],"mappings":"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"}
|
package/dist/scanner.d.ts
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
* Main scanner orchestrator
|
|
3
3
|
* Coordinates all four scanning layers
|
|
4
4
|
*/
|
|
5
|
-
import type { ScanResult } from
|
|
5
|
+
import type { ScanResult } from "./types.js";
|
|
6
6
|
/**
|
|
7
7
|
* Main scan function
|
|
8
8
|
* Scans a skill directory or SKILL.md file
|
|
9
9
|
*/
|
|
10
10
|
export declare function scanSkill(skillPath: string): Promise<ScanResult>;
|
|
11
11
|
/**
|
|
12
|
-
* Scan multiple skills in a directory
|
|
12
|
+
* Scan multiple skills/MCP servers in a directory
|
|
13
13
|
*/
|
|
14
14
|
export declare function scanAllSkills(directory: string): Promise<ScanResult[]>;
|
|
15
15
|
//# sourceMappingURL=scanner.d.ts.map
|
package/dist/scanner.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,KAAK,EAAmB,UAAU,EAAW,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,KAAK,EAAmB,UAAU,EAAW,MAAM,YAAY,CAAC;AAcvE;;;GAGG;AACH,wBAAsB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAgDtE;AAmMD;;GAEG;AACH,wBAAsB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAuD5E"}
|