@k08200/mcp-probe 0.1.0 → 0.8.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 +224 -13
- package/dist/checker.d.ts +2 -11
- package/dist/checker.d.ts.map +1 -1
- package/dist/checker.js +92 -9
- package/dist/checker.js.map +1 -1
- package/dist/cli.js +115 -5
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +4 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +122 -0
- package/dist/config.js.map +1 -0
- package/dist/protocols/mcp-client.d.ts.map +1 -1
- package/dist/protocols/mcp-client.js +212 -61
- package/dist/protocols/mcp-client.js.map +1 -1
- package/dist/reporters/badge.d.ts +12 -0
- package/dist/reporters/badge.d.ts.map +1 -0
- package/dist/reporters/badge.js +34 -0
- package/dist/reporters/badge.js.map +1 -0
- package/dist/reporters/github.d.ts +7 -0
- package/dist/reporters/github.d.ts.map +1 -0
- package/dist/reporters/github.js +138 -0
- package/dist/reporters/github.js.map +1 -0
- package/dist/reporters/json-reporter.d.ts +2 -2
- package/dist/reporters/json-reporter.d.ts.map +1 -1
- package/dist/reporters/json-reporter.js.map +1 -1
- package/dist/reporters/terminal.d.ts +2 -1
- package/dist/reporters/terminal.d.ts.map +1 -1
- package/dist/reporters/terminal.js +38 -0
- package/dist/reporters/terminal.js.map +1 -1
- package/dist/types.d.ts +66 -2
- package/dist/types.d.ts.map +1 -1
- package/examples/datadog.tools.json +13 -0
- package/examples/github-actions/fleet.yml +25 -0
- package/examples/github-actions/remote-server.yml +24 -0
- package/examples/github-actions/single-server.yml +21 -0
- package/examples/mcp-probe.config.json +19 -0
- package/examples/recipes/README.md +35 -0
- package/examples/recipes/datadog.tools.json +23 -0
- package/examples/recipes/gmail.tools.json +18 -0
- package/examples/recipes/supabase.tools.json +19 -0
- package/package.json +4 -3
package/dist/config.js
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { dirname, isAbsolute, resolve } from 'path';
|
|
2
|
+
import { existsSync, readFileSync } from 'fs';
|
|
3
|
+
import { checkMcpServer } from './checker.js';
|
|
4
|
+
function isObject(value) {
|
|
5
|
+
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
6
|
+
}
|
|
7
|
+
function validateServer(server, index) {
|
|
8
|
+
if (!isObject(server)) {
|
|
9
|
+
throw new Error(`Invalid config: servers[${index}] must be an object`);
|
|
10
|
+
}
|
|
11
|
+
if (typeof server.name !== 'string' || server.name.length === 0) {
|
|
12
|
+
throw new Error(`Invalid config: servers[${index}].name must be a non-empty string`);
|
|
13
|
+
}
|
|
14
|
+
if (typeof server.target !== 'string' || server.target.length === 0) {
|
|
15
|
+
throw new Error(`Invalid config: servers[${index}].target must be a non-empty string`);
|
|
16
|
+
}
|
|
17
|
+
if (server.serverArgs !== undefined && (!Array.isArray(server.serverArgs) || !server.serverArgs.every((arg) => typeof arg === 'string'))) {
|
|
18
|
+
throw new Error(`Invalid config: servers[${index}].serverArgs must be a string array`);
|
|
19
|
+
}
|
|
20
|
+
if (server.timeoutMs !== undefined && (typeof server.timeoutMs !== 'number' || server.timeoutMs <= 0)) {
|
|
21
|
+
throw new Error(`Invalid config: servers[${index}].timeoutMs must be a positive number`);
|
|
22
|
+
}
|
|
23
|
+
if (server.transport !== undefined && !['stdio', 'http', 'sse'].includes(String(server.transport))) {
|
|
24
|
+
throw new Error(`Invalid config: servers[${index}].transport must be stdio, http, or sse`);
|
|
25
|
+
}
|
|
26
|
+
if (server.headers !== undefined) {
|
|
27
|
+
if (!isObject(server.headers)) {
|
|
28
|
+
throw new Error(`Invalid config: servers[${index}].headers must be an object`);
|
|
29
|
+
}
|
|
30
|
+
for (const [key, value] of Object.entries(server.headers)) {
|
|
31
|
+
if (typeof value !== 'string') {
|
|
32
|
+
throw new Error(`Invalid config: servers[${index}].headers.${key} must be a string`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if (server.probeTools !== undefined && typeof server.probeTools !== 'boolean') {
|
|
37
|
+
throw new Error(`Invalid config: servers[${index}].probeTools must be a boolean`);
|
|
38
|
+
}
|
|
39
|
+
if (server.toolsFile !== undefined && typeof server.toolsFile !== 'string') {
|
|
40
|
+
throw new Error(`Invalid config: servers[${index}].toolsFile must be a string`);
|
|
41
|
+
}
|
|
42
|
+
return server;
|
|
43
|
+
}
|
|
44
|
+
export function loadConfig(configFile) {
|
|
45
|
+
if (!existsSync(configFile)) {
|
|
46
|
+
throw new Error(`Cannot read config file: ${configFile}`);
|
|
47
|
+
}
|
|
48
|
+
let parsed;
|
|
49
|
+
try {
|
|
50
|
+
parsed = JSON.parse(readFileSync(configFile, 'utf8'));
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
throw new Error(`Invalid config JSON: ${configFile}`);
|
|
54
|
+
}
|
|
55
|
+
if (!isObject(parsed)) {
|
|
56
|
+
throw new Error(`Invalid config: root must be an object`);
|
|
57
|
+
}
|
|
58
|
+
if (parsed.timeoutMs !== undefined && (typeof parsed.timeoutMs !== 'number' || parsed.timeoutMs <= 0)) {
|
|
59
|
+
throw new Error(`Invalid config: timeoutMs must be a positive number`);
|
|
60
|
+
}
|
|
61
|
+
if (!Array.isArray(parsed.servers) || parsed.servers.length === 0) {
|
|
62
|
+
throw new Error(`Invalid config: servers must be a non-empty array`);
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
timeoutMs: parsed.timeoutMs,
|
|
66
|
+
servers: parsed.servers.map(validateServer),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function deriveOverallStatus(statuses) {
|
|
70
|
+
if (statuses.includes('fail'))
|
|
71
|
+
return 'fail';
|
|
72
|
+
if (statuses.includes('warn'))
|
|
73
|
+
return 'warn';
|
|
74
|
+
return 'pass';
|
|
75
|
+
}
|
|
76
|
+
function resolveConfigPath(configFile, maybeRelative) {
|
|
77
|
+
if (!maybeRelative || isAbsolute(maybeRelative))
|
|
78
|
+
return maybeRelative;
|
|
79
|
+
return resolve(dirname(configFile), maybeRelative);
|
|
80
|
+
}
|
|
81
|
+
function expandEnvVars(value) {
|
|
82
|
+
return value.replace(/\$\{([A-Z_][A-Z0-9_]*)\}/gi, (match, name) => {
|
|
83
|
+
const envValue = process.env[name];
|
|
84
|
+
if (envValue === undefined) {
|
|
85
|
+
throw new Error(`Environment variable ${name} is not set`);
|
|
86
|
+
}
|
|
87
|
+
return envValue;
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
function expandHeaders(headers) {
|
|
91
|
+
if (!headers)
|
|
92
|
+
return undefined;
|
|
93
|
+
return Object.fromEntries(Object.entries(headers).map(([key, value]) => [key, expandEnvVars(value)]));
|
|
94
|
+
}
|
|
95
|
+
export async function checkConfigFile(configFile, defaultTimeoutMs = 10000) {
|
|
96
|
+
const startTime = Date.now();
|
|
97
|
+
const config = loadConfig(configFile);
|
|
98
|
+
const servers = [];
|
|
99
|
+
for (const server of config.servers) {
|
|
100
|
+
const options = {
|
|
101
|
+
target: server.target,
|
|
102
|
+
serverArgs: server.serverArgs,
|
|
103
|
+
timeoutMs: server.timeoutMs ?? config.timeoutMs ?? defaultTimeoutMs,
|
|
104
|
+
transport: server.transport,
|
|
105
|
+
headers: expandHeaders(server.headers),
|
|
106
|
+
probeTools: server.probeTools,
|
|
107
|
+
toolsFile: resolveConfigPath(configFile, server.toolsFile),
|
|
108
|
+
};
|
|
109
|
+
servers.push({
|
|
110
|
+
name: server.name,
|
|
111
|
+
report: await checkMcpServer(options),
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
return {
|
|
115
|
+
target: configFile,
|
|
116
|
+
timestamp: new Date().toISOString(),
|
|
117
|
+
overallStatus: deriveOverallStatus(servers.map((server) => server.report.overallStatus)),
|
|
118
|
+
servers,
|
|
119
|
+
totalLatencyMs: Date.now() - startTime,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-client.d.ts","sourceRoot":"","sources":["../../src/protocols/mcp-client.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"mcp-client.d.ts","sourceRoot":"","sources":["../../src/protocols/mcp-client.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAkB,MAAM,aAAa,CAAC;AA4H7E,wBAAsB,cAAc,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAwHhF"}
|
|
@@ -1,31 +1,137 @@
|
|
|
1
1
|
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
2
2
|
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
3
|
+
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
4
|
+
import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
|
|
5
|
+
const VERSION = '0.8.0';
|
|
6
|
+
// Known startup warning patterns from official MCP servers — not fatal errors
|
|
7
|
+
const STDERR_WARNING_PATTERNS = [
|
|
8
|
+
/^warn(?:ing)?:/i,
|
|
9
|
+
/deprecat/i,
|
|
10
|
+
/optional.*not found/i,
|
|
11
|
+
/version.*mismatch/i,
|
|
12
|
+
/missing optional/i,
|
|
13
|
+
/checking for updates/i,
|
|
14
|
+
/update available/i,
|
|
15
|
+
];
|
|
16
|
+
function isStderrNoise(line) {
|
|
17
|
+
return STDERR_WARNING_PATTERNS.some((p) => p.test(line));
|
|
18
|
+
}
|
|
3
19
|
function firstMeaningfulLine(text) {
|
|
4
20
|
const lines = text.split('\n').map((l) => l.trim()).filter(Boolean);
|
|
5
|
-
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
21
|
+
const nonNoise = lines.filter((l) => !isStderrNoise(l));
|
|
22
|
+
const target = nonNoise.length > 0 ? nonNoise : lines;
|
|
23
|
+
const errorLine = target.find((l) => /^Error:/i.test(l));
|
|
24
|
+
if (errorLine)
|
|
25
|
+
return errorLine;
|
|
10
26
|
const skip = /^at |^node:|^\^$|^const |^throw |^Require stack/;
|
|
11
|
-
|
|
12
|
-
return meaningful ?? lines[0] ?? text;
|
|
27
|
+
return target.find((l) => !skip.test(l) && l.length > 3) ?? target[0] ?? text;
|
|
13
28
|
}
|
|
14
29
|
function withTimeout(promise, ms, label) {
|
|
15
|
-
|
|
16
|
-
|
|
30
|
+
let timeoutId;
|
|
31
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
32
|
+
timeoutId = setTimeout(() => reject(new Error(`${label} timed out after ${ms}ms`)), ms);
|
|
33
|
+
});
|
|
34
|
+
return Promise.race([promise, timeoutPromise]).finally(() => {
|
|
35
|
+
if (timeoutId)
|
|
36
|
+
clearTimeout(timeoutId);
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
// Fallback: generate minimal inputs from JSON Schema when no sidecar entry exists
|
|
40
|
+
function generateMinimalInput(schema) {
|
|
41
|
+
if (!schema || typeof schema !== 'object')
|
|
42
|
+
return {};
|
|
43
|
+
const s = schema;
|
|
44
|
+
const props = s['properties'];
|
|
45
|
+
if (!props)
|
|
46
|
+
return {};
|
|
47
|
+
const required = s['required'] ?? [];
|
|
48
|
+
const input = {};
|
|
49
|
+
for (const key of required) {
|
|
50
|
+
const prop = props[key];
|
|
51
|
+
if (!prop)
|
|
52
|
+
continue;
|
|
53
|
+
switch (prop['type']) {
|
|
54
|
+
case 'string':
|
|
55
|
+
input[key] = '';
|
|
56
|
+
break;
|
|
57
|
+
case 'number':
|
|
58
|
+
case 'integer':
|
|
59
|
+
input[key] = 0;
|
|
60
|
+
break;
|
|
61
|
+
case 'boolean':
|
|
62
|
+
input[key] = false;
|
|
63
|
+
break;
|
|
64
|
+
case 'array':
|
|
65
|
+
input[key] = [];
|
|
66
|
+
break;
|
|
67
|
+
case 'object':
|
|
68
|
+
input[key] = {};
|
|
69
|
+
break;
|
|
70
|
+
default: input[key] = null;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return input;
|
|
74
|
+
}
|
|
75
|
+
function isAuthError(message, notErrorCodes) {
|
|
76
|
+
if (/401|403|unauthorized|forbidden/i.test(message))
|
|
77
|
+
return true;
|
|
78
|
+
if (notErrorCodes) {
|
|
79
|
+
return notErrorCodes.some((code) => message.includes(String(code)));
|
|
80
|
+
}
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
function toolResultErrorMessage(result) {
|
|
84
|
+
if (!result || typeof result !== 'object')
|
|
85
|
+
return undefined;
|
|
86
|
+
const toolResult = result;
|
|
87
|
+
if (toolResult.isError !== true)
|
|
88
|
+
return undefined;
|
|
89
|
+
if (!Array.isArray(toolResult.content))
|
|
90
|
+
return 'Tool returned an error result';
|
|
91
|
+
const textParts = toolResult.content
|
|
92
|
+
.map((part) => {
|
|
93
|
+
if (!part || typeof part !== 'object')
|
|
94
|
+
return undefined;
|
|
95
|
+
const maybeText = part.text;
|
|
96
|
+
return typeof maybeText === 'string' ? maybeText : undefined;
|
|
97
|
+
})
|
|
98
|
+
.filter((part) => Boolean(part));
|
|
99
|
+
return textParts.join('\n') || 'Tool returned an error result';
|
|
100
|
+
}
|
|
101
|
+
function makeRequestInit(headers) {
|
|
102
|
+
if (!headers || Object.keys(headers).length === 0)
|
|
103
|
+
return undefined;
|
|
104
|
+
return { headers };
|
|
105
|
+
}
|
|
106
|
+
function createTransport(options) {
|
|
107
|
+
const mode = options.transport ?? 'stdio';
|
|
108
|
+
if (mode === 'stdio') {
|
|
109
|
+
if (!options.command) {
|
|
110
|
+
throw new Error('stdio transport requires a command');
|
|
111
|
+
}
|
|
112
|
+
const transport = new StdioClientTransport({
|
|
113
|
+
command: options.command,
|
|
114
|
+
args: options.args ?? [],
|
|
115
|
+
env: { ...process.env },
|
|
116
|
+
stderr: 'pipe',
|
|
117
|
+
});
|
|
118
|
+
const stderrChunks = [];
|
|
119
|
+
transport.stderr?.on('data', (chunk) => stderrChunks.push(chunk));
|
|
120
|
+
return { transport, stderrChunks };
|
|
121
|
+
}
|
|
122
|
+
if (!options.url) {
|
|
123
|
+
throw new Error(`${mode} transport requires a URL target`);
|
|
124
|
+
}
|
|
125
|
+
const url = new URL(options.url);
|
|
126
|
+
const requestInit = makeRequestInit(options.headers);
|
|
127
|
+
const transport = mode === 'sse'
|
|
128
|
+
? new SSEClientTransport(url, { requestInit })
|
|
129
|
+
: new StreamableHTTPClientTransport(url, { requestInit });
|
|
130
|
+
return { transport, stderrChunks: [] };
|
|
17
131
|
}
|
|
18
132
|
export async function probeMcpServer(options) {
|
|
19
|
-
const transport =
|
|
20
|
-
|
|
21
|
-
args: options.args,
|
|
22
|
-
env: { ...process.env },
|
|
23
|
-
stderr: 'pipe',
|
|
24
|
-
});
|
|
25
|
-
// Collect stderr so we can surface crash reasons in error messages
|
|
26
|
-
const stderrChunks = [];
|
|
27
|
-
transport.stderr?.on('data', (chunk) => stderrChunks.push(chunk));
|
|
28
|
-
const client = new Client({ name: 'mcp-probe', version: '0.1.0' }, { capabilities: { roots: { listChanged: false } } });
|
|
133
|
+
const { transport, stderrChunks } = createTransport(options);
|
|
134
|
+
const client = new Client({ name: 'mcp-probe', version: VERSION }, { capabilities: { roots: { listChanged: false } } });
|
|
29
135
|
const connectStart = Date.now();
|
|
30
136
|
try {
|
|
31
137
|
await withTimeout(client.connect(transport), options.timeoutMs, 'Connection');
|
|
@@ -35,53 +141,98 @@ export async function probeMcpServer(options) {
|
|
|
35
141
|
const reason = stderrText
|
|
36
142
|
? firstMeaningfulLine(stderrText)
|
|
37
143
|
: err instanceof Error ? err.message : String(err);
|
|
144
|
+
await client.close().catch(() => undefined);
|
|
38
145
|
throw new Error(reason);
|
|
39
146
|
}
|
|
40
147
|
const connectLatencyMs = Date.now() - connectStart;
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
148
|
+
try {
|
|
149
|
+
const rawServerInfo = client.getServerVersion();
|
|
150
|
+
const rawCaps = client.getServerCapabilities();
|
|
151
|
+
const capabilities = Object.keys(rawCaps ?? {});
|
|
152
|
+
const toolsStart = Date.now();
|
|
153
|
+
const toolsResult = await withTimeout(client.listTools(), options.timeoutMs, 'tools/list');
|
|
154
|
+
const toolsLatencyMs = Date.now() - toolsStart;
|
|
155
|
+
let resourcesLatencyMs;
|
|
156
|
+
let promptsLatencyMs;
|
|
157
|
+
const resourcesList = [];
|
|
158
|
+
const promptsList = [];
|
|
159
|
+
if (rawCaps?.resources) {
|
|
160
|
+
const t = Date.now();
|
|
161
|
+
const result = await withTimeout(client.listResources(), options.timeoutMs, 'resources/list');
|
|
162
|
+
resourcesLatencyMs = Date.now() - t;
|
|
163
|
+
for (const r of result.resources) {
|
|
164
|
+
resourcesList.push({ uri: r.uri, name: r.name, description: r.description });
|
|
165
|
+
}
|
|
57
166
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
167
|
+
if (rawCaps?.prompts) {
|
|
168
|
+
const t = Date.now();
|
|
169
|
+
const result = await withTimeout(client.listPrompts(), options.timeoutMs, 'prompts/list');
|
|
170
|
+
promptsLatencyMs = Date.now() - t;
|
|
171
|
+
for (const p of result.prompts) {
|
|
172
|
+
promptsList.push({ name: p.name, description: p.description });
|
|
173
|
+
}
|
|
65
174
|
}
|
|
175
|
+
let toolCallResults;
|
|
176
|
+
if (options.probeTools && toolsResult.tools.length > 0) {
|
|
177
|
+
toolCallResults = [];
|
|
178
|
+
for (const tool of toolsResult.tools) {
|
|
179
|
+
const sidecarEntry = options.sidecar?.tools[tool.name];
|
|
180
|
+
// Sidecar input beats auto-generated because it can reach the real call path.
|
|
181
|
+
const input = sidecarEntry?.input ?? generateMinimalInput(tool.inputSchema);
|
|
182
|
+
const source = sidecarEntry ? 'sidecar' : 'auto';
|
|
183
|
+
const notErrorCodes = sidecarEntry?.expect?.not_error_code;
|
|
184
|
+
const start = Date.now();
|
|
185
|
+
try {
|
|
186
|
+
const result = await withTimeout(client.callTool({ name: tool.name, arguments: input }), options.timeoutMs, `callTool(${tool.name})`);
|
|
187
|
+
const toolError = toolResultErrorMessage(result);
|
|
188
|
+
if (toolError) {
|
|
189
|
+
const status = isAuthError(toolError, notErrorCodes) ? 'warn' : 'fail';
|
|
190
|
+
toolCallResults.push({
|
|
191
|
+
tool: tool.name,
|
|
192
|
+
status,
|
|
193
|
+
latencyMs: Date.now() - start,
|
|
194
|
+
error: toolError,
|
|
195
|
+
source,
|
|
196
|
+
});
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
toolCallResults.push({ tool: tool.name, status: 'pass', latencyMs: Date.now() - start, source });
|
|
200
|
+
}
|
|
201
|
+
catch (err) {
|
|
202
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
203
|
+
const status = isAuthError(msg, notErrorCodes) ? 'warn' : 'fail';
|
|
204
|
+
toolCallResults.push({
|
|
205
|
+
tool: tool.name,
|
|
206
|
+
status,
|
|
207
|
+
latencyMs: Date.now() - start,
|
|
208
|
+
error: msg,
|
|
209
|
+
source,
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return {
|
|
215
|
+
serverInfo: {
|
|
216
|
+
name: rawServerInfo?.name ?? 'unknown',
|
|
217
|
+
version: rawServerInfo?.version ?? 'unknown',
|
|
218
|
+
capabilities,
|
|
219
|
+
},
|
|
220
|
+
tools: toolsResult.tools.map((t) => ({
|
|
221
|
+
name: t.name,
|
|
222
|
+
description: t.description,
|
|
223
|
+
inputSchema: t.inputSchema,
|
|
224
|
+
})),
|
|
225
|
+
resources: resourcesList,
|
|
226
|
+
prompts: promptsList,
|
|
227
|
+
connectLatencyMs,
|
|
228
|
+
toolsLatencyMs,
|
|
229
|
+
resourcesLatencyMs,
|
|
230
|
+
promptsLatencyMs,
|
|
231
|
+
toolCallResults,
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
finally {
|
|
235
|
+
await client.close().catch(() => undefined);
|
|
66
236
|
}
|
|
67
|
-
await client.close();
|
|
68
|
-
return {
|
|
69
|
-
serverInfo: {
|
|
70
|
-
name: rawServerInfo?.name ?? 'unknown',
|
|
71
|
-
version: rawServerInfo?.version ?? 'unknown',
|
|
72
|
-
capabilities,
|
|
73
|
-
},
|
|
74
|
-
tools: toolsResult.tools.map((t) => ({
|
|
75
|
-
name: t.name,
|
|
76
|
-
description: t.description,
|
|
77
|
-
inputSchema: t.inputSchema,
|
|
78
|
-
})),
|
|
79
|
-
resources: resourcesList,
|
|
80
|
-
prompts: promptsList,
|
|
81
|
-
connectLatencyMs,
|
|
82
|
-
toolsLatencyMs,
|
|
83
|
-
resourcesLatencyMs,
|
|
84
|
-
promptsLatencyMs,
|
|
85
|
-
};
|
|
86
237
|
}
|
|
87
238
|
//# sourceMappingURL=mcp-client.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-client.js","sourceRoot":"","sources":["../../src/protocols/mcp-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;
|
|
1
|
+
{"version":3,"file":"mcp-client.js","sourceRoot":"","sources":["../../src/protocols/mcp-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { BatchReport, CheckReport } from '../types.js';
|
|
2
|
+
type AnyReport = CheckReport | BatchReport;
|
|
3
|
+
export type ShieldsBadge = {
|
|
4
|
+
schemaVersion: 1;
|
|
5
|
+
label: string;
|
|
6
|
+
message: string;
|
|
7
|
+
color: string;
|
|
8
|
+
};
|
|
9
|
+
export declare function buildBadge(report: AnyReport): ShieldsBadge;
|
|
10
|
+
export declare function writeBadgeFile(report: AnyReport, path: string): void;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=badge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"badge.d.ts","sourceRoot":"","sources":["../../src/reporters/badge.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAe,MAAM,aAAa,CAAC;AAEzE,KAAK,SAAS,GAAG,WAAW,GAAG,WAAW,CAAC;AAE3C,MAAM,MAAM,YAAY,GAAG;IACzB,aAAa,EAAE,CAAC,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAuBF,wBAAgB,UAAU,CAAC,MAAM,EAAE,SAAS,GAAG,YAAY,CAO1D;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAGpE"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { dirname } from 'path';
|
|
2
|
+
import { mkdirSync, writeFileSync } from 'fs';
|
|
3
|
+
const COLORS = {
|
|
4
|
+
pass: 'brightgreen',
|
|
5
|
+
warn: 'yellow',
|
|
6
|
+
fail: 'red',
|
|
7
|
+
};
|
|
8
|
+
function isBatchReport(report) {
|
|
9
|
+
return 'servers' in report;
|
|
10
|
+
}
|
|
11
|
+
function batchMessage(report) {
|
|
12
|
+
const passed = report.servers.filter((server) => server.report.overallStatus === 'pass').length;
|
|
13
|
+
const warned = report.servers.filter((server) => server.report.overallStatus === 'warn').length;
|
|
14
|
+
const failed = report.servers.filter((server) => server.report.overallStatus === 'fail').length;
|
|
15
|
+
const parts = [`${passed} pass`];
|
|
16
|
+
if (warned > 0)
|
|
17
|
+
parts.push(`${warned} warn`);
|
|
18
|
+
if (failed > 0)
|
|
19
|
+
parts.push(`${failed} fail`);
|
|
20
|
+
return parts.join(', ');
|
|
21
|
+
}
|
|
22
|
+
export function buildBadge(report) {
|
|
23
|
+
return {
|
|
24
|
+
schemaVersion: 1,
|
|
25
|
+
label: isBatchReport(report) ? 'mcp fleet' : 'mcp probe',
|
|
26
|
+
message: isBatchReport(report) ? batchMessage(report) : report.overallStatus,
|
|
27
|
+
color: COLORS[report.overallStatus],
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
export function writeBadgeFile(report, path) {
|
|
31
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
32
|
+
writeFileSync(path, `${JSON.stringify(buildBadge(report), null, 2)}\n`);
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=badge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"badge.js","sourceRoot":"","sources":["../../src/reporters/badge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC/B,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AAY9C,MAAM,MAAM,GAAgC;IAC1C,IAAI,EAAE,aAAa;IACnB,IAAI,EAAE,QAAQ;IACd,IAAI,EAAE,KAAK;CACZ,CAAC;AAEF,SAAS,aAAa,CAAC,MAAiB;IACtC,OAAO,SAAS,IAAI,MAAM,CAAC;AAC7B,CAAC;AAED,SAAS,YAAY,CAAC,MAAmB;IACvC,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,aAAa,KAAK,MAAM,CAAC,CAAC,MAAM,CAAC;IAChG,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,aAAa,KAAK,MAAM,CAAC,CAAC,MAAM,CAAC;IAChG,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,aAAa,KAAK,MAAM,CAAC,CAAC,MAAM,CAAC;IAEhG,MAAM,KAAK,GAAG,CAAC,GAAG,MAAM,OAAO,CAAC,CAAC;IACjC,IAAI,MAAM,GAAG,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,OAAO,CAAC,CAAC;IAC7C,IAAI,MAAM,GAAG,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,OAAO,CAAC,CAAC;IAC7C,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,MAAiB;IAC1C,OAAO;QACL,aAAa,EAAE,CAAC;QAChB,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW;QACxD,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa;QAC5E,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC;KACpC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAiB,EAAE,IAAY;IAC5D,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,aAAa,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;AAC1E,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { BatchReport, CheckReport } from '../types.js';
|
|
2
|
+
type AnyReport = CheckReport | BatchReport;
|
|
3
|
+
export declare function buildGithubSummary(report: AnyReport): string;
|
|
4
|
+
export declare function buildGithubAnnotations(report: AnyReport): string[];
|
|
5
|
+
export declare function renderGithubActions(report: AnyReport, summaryPath?: string | undefined): void;
|
|
6
|
+
export {};
|
|
7
|
+
//# sourceMappingURL=github.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github.d.ts","sourceRoot":"","sources":["../../src/reporters/github.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAa,WAAW,EAA+B,MAAM,aAAa,CAAC;AAEpG,KAAK,SAAS,GAAG,WAAW,GAAG,WAAW,CAAC;AA6G3C,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,CAE5D;AAmBD,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,EAAE,CAYlE;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,EAAE,WAAW,qBAAkC,GAAG,IAAI,CAQ1G"}
|