@kryptosai/mcp-observatory 0.3.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 (80) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +228 -0
  3. package/dist/src/adapters/http.d.ts +5 -0
  4. package/dist/src/adapters/http.js +54 -0
  5. package/dist/src/adapters/http.js.map +1 -0
  6. package/dist/src/adapters/local-process.d.ts +19 -0
  7. package/dist/src/adapters/local-process.js +63 -0
  8. package/dist/src/adapters/local-process.js.map +1 -0
  9. package/dist/src/checks/base.d.ts +28 -0
  10. package/dist/src/checks/base.js +42 -0
  11. package/dist/src/checks/base.js.map +1 -0
  12. package/dist/src/checks/list-check.d.ts +16 -0
  13. package/dist/src/checks/list-check.js +78 -0
  14. package/dist/src/checks/list-check.js.map +1 -0
  15. package/dist/src/checks/prompts.d.ts +2 -0
  16. package/dist/src/checks/prompts.js +11 -0
  17. package/dist/src/checks/prompts.js.map +1 -0
  18. package/dist/src/checks/resources.d.ts +2 -0
  19. package/dist/src/checks/resources.js +163 -0
  20. package/dist/src/checks/resources.js.map +1 -0
  21. package/dist/src/checks/tools-invoke.d.ts +2 -0
  22. package/dist/src/checks/tools-invoke.js +107 -0
  23. package/dist/src/checks/tools-invoke.js.map +1 -0
  24. package/dist/src/checks/tools.d.ts +2 -0
  25. package/dist/src/checks/tools.js +12 -0
  26. package/dist/src/checks/tools.js.map +1 -0
  27. package/dist/src/cli.d.ts +2 -0
  28. package/dist/src/cli.js +266 -0
  29. package/dist/src/cli.js.map +1 -0
  30. package/dist/src/diff.d.ts +2 -0
  31. package/dist/src/diff.js +98 -0
  32. package/dist/src/diff.js.map +1 -0
  33. package/dist/src/discovery.d.ts +7 -0
  34. package/dist/src/discovery.js +116 -0
  35. package/dist/src/discovery.js.map +1 -0
  36. package/dist/src/index.d.ts +9 -0
  37. package/dist/src/index.js +10 -0
  38. package/dist/src/index.js.map +1 -0
  39. package/dist/src/reporters/common.d.ts +7 -0
  40. package/dist/src/reporters/common.js +63 -0
  41. package/dist/src/reporters/common.js.map +1 -0
  42. package/dist/src/reporters/html.d.ts +2 -0
  43. package/dist/src/reporters/html.js +228 -0
  44. package/dist/src/reporters/html.js.map +1 -0
  45. package/dist/src/reporters/markdown.d.ts +2 -0
  46. package/dist/src/reporters/markdown.js +231 -0
  47. package/dist/src/reporters/markdown.js.map +1 -0
  48. package/dist/src/reporters/terminal.d.ts +2 -0
  49. package/dist/src/reporters/terminal.js +110 -0
  50. package/dist/src/reporters/terminal.js.map +1 -0
  51. package/dist/src/runner.d.ts +5 -0
  52. package/dist/src/runner.js +138 -0
  53. package/dist/src/runner.js.map +1 -0
  54. package/dist/src/schema-diff.d.ts +6 -0
  55. package/dist/src/schema-diff.js +73 -0
  56. package/dist/src/schema-diff.js.map +1 -0
  57. package/dist/src/storage.d.ts +6 -0
  58. package/dist/src/storage.js +32 -0
  59. package/dist/src/storage.js.map +1 -0
  60. package/dist/src/types.d.ts +120 -0
  61. package/dist/src/types.js +5 -0
  62. package/dist/src/types.js.map +1 -0
  63. package/dist/src/utils/failure-diagnosis.d.ts +2 -0
  64. package/dist/src/utils/failure-diagnosis.js +90 -0
  65. package/dist/src/utils/failure-diagnosis.js.map +1 -0
  66. package/dist/src/utils/ids.d.ts +2 -0
  67. package/dist/src/utils/ids.js +13 -0
  68. package/dist/src/utils/ids.js.map +1 -0
  69. package/dist/src/utils/schema-stub.d.ts +14 -0
  70. package/dist/src/utils/schema-stub.js +61 -0
  71. package/dist/src/utils/schema-stub.js.map +1 -0
  72. package/dist/src/validate.d.ts +4 -0
  73. package/dist/src/validate.js +97 -0
  74. package/dist/src/validate.js.map +1 -0
  75. package/dist/src/version.d.ts +1 -0
  76. package/dist/src/version.js +21 -0
  77. package/dist/src/version.js.map +1 -0
  78. package/package.json +76 -0
  79. package/schemas/diff-artifact.schema.json +132 -0
  80. package/schemas/run-artifact.schema.json +245 -0
@@ -0,0 +1,231 @@
1
+ import { describeCheckList, findChecksByStatus, focusLabel, previewList, recommendRunNextStep, sortChecksByActionability } from "./common.js";
2
+ function table(entries) {
3
+ if (entries.length === 0) {
4
+ return "_None._";
5
+ }
6
+ const header = entries[0];
7
+ const rows = entries.slice(1);
8
+ const divider = header.map(() => "---");
9
+ return [header, divider, ...rows].map((row) => `| ${row.join(" | ")} |`).join("\n");
10
+ }
11
+ function renderEvidence(evidence) {
12
+ if (evidence.length === 0) {
13
+ return "_No evidence was captured._";
14
+ }
15
+ return evidence
16
+ .map((entry) => {
17
+ return [
18
+ `- Endpoint: \`${entry.endpoint}\``,
19
+ ` - Advertised: \`${String(entry.advertised)}\``,
20
+ ` - Responded: \`${String(entry.responded)}\``,
21
+ ` - Minimal shape present: \`${String(entry.minimalShapePresent)}\``,
22
+ ` - Item count: \`${entry.itemCount ?? 0}\``,
23
+ ` - Identifiers: ${previewList(entry.identifiers)}`,
24
+ ` - Diagnostics: ${previewList(entry.diagnostics, 3)}`
25
+ ].join("\n");
26
+ })
27
+ .join("\n");
28
+ }
29
+ function renderRunAtAGlance(artifact) {
30
+ const failingChecks = findChecksByStatus(artifact.checks, "fail");
31
+ const partialChecks = [
32
+ ...findChecksByStatus(artifact.checks, "partial"),
33
+ ...findChecksByStatus(artifact.checks, "flaky")
34
+ ];
35
+ const unsupportedChecks = findChecksByStatus(artifact.checks, "unsupported");
36
+ const skippedChecks = findChecksByStatus(artifact.checks, "skipped");
37
+ return [
38
+ `## At a Glance`,
39
+ ``,
40
+ `- Failing checks: ${describeCheckList(failingChecks)}`,
41
+ `- Partial or flaky checks: ${describeCheckList(partialChecks)}`,
42
+ `- Skipped checks: ${describeCheckList(skippedChecks)}`,
43
+ `- Unsupported checks: ${describeCheckList(unsupportedChecks)}`,
44
+ `- Suggested next step: ${recommendRunNextStep(artifact)}`
45
+ ].join("\n");
46
+ }
47
+ function renderFailureDiagnosis(artifact) {
48
+ if (artifact.fatalError === undefined) {
49
+ return [];
50
+ }
51
+ return [
52
+ `## Failure Diagnosis`,
53
+ ``,
54
+ "```text",
55
+ artifact.fatalError,
56
+ "```",
57
+ ``
58
+ ];
59
+ }
60
+ function renderCheckSection(check) {
61
+ return [
62
+ `### ${check.id} — ${check.status}`,
63
+ ``,
64
+ `Summary: ${check.message}`,
65
+ ``,
66
+ renderEvidence(check.evidence),
67
+ ``
68
+ ];
69
+ }
70
+ function renderRunMarkdown(artifact) {
71
+ const orderedChecks = sortChecksByActionability(artifact.checks);
72
+ return [
73
+ `# MCP Observatory Run Report`,
74
+ ``,
75
+ `Generated at ${artifact.createdAt}`,
76
+ ``,
77
+ `## Target and Environment Metadata`,
78
+ ``,
79
+ `- Target: \`${artifact.target.targetId}\``,
80
+ `- Adapter: \`${artifact.target.adapter}\``,
81
+ `- Command: \`${artifact.target.command} ${artifact.target.args.join(" ")}\``,
82
+ `- Server: \`${artifact.target.serverName ?? "unknown"} ${artifact.target.serverVersion ?? ""}\``,
83
+ `- Platform: \`${artifact.environment.platform}\``,
84
+ `- Node: \`${artifact.environment.nodeVersion}\``,
85
+ ``,
86
+ `## Executive Summary`,
87
+ ``,
88
+ table([
89
+ ["Gate", "Total", "Pass", "Fail", "Partial", "Unsupported", "Flaky", "Skipped"],
90
+ [
91
+ artifact.gate,
92
+ String(artifact.summary.total),
93
+ String(artifact.summary.pass),
94
+ String(artifact.summary.fail),
95
+ String(artifact.summary.partial),
96
+ String(artifact.summary.unsupported),
97
+ String(artifact.summary.flaky),
98
+ String(artifact.summary.skipped)
99
+ ]
100
+ ]),
101
+ ``,
102
+ renderRunAtAGlance(artifact),
103
+ ``,
104
+ `## Regressions and Recoveries`,
105
+ ``,
106
+ `_Use the \`diff\` command against another run artifact to classify regressions and recoveries over time._`,
107
+ ``,
108
+ ...renderFailureDiagnosis(artifact),
109
+ `## Full Capability Status Table`,
110
+ ``,
111
+ table([
112
+ ["Focus", "Check", "Status", "Duration (ms)", "Message"],
113
+ ...orderedChecks.map((check) => [
114
+ focusLabel(check.status),
115
+ check.id,
116
+ check.status,
117
+ check.durationMs.toFixed(2),
118
+ check.message
119
+ ])
120
+ ]),
121
+ ``,
122
+ `## Evidence Snippets`,
123
+ ``,
124
+ ...orderedChecks.flatMap(renderCheckSection),
125
+ `## Reproduction Commands`,
126
+ ``,
127
+ "```bash",
128
+ "npm run cli -- run --target <path-to-target-config.json>",
129
+ "npm run cli -- report --run <path-to-run-artifact.json> --format markdown",
130
+ "```",
131
+ ``,
132
+ `## Artifact Provenance`,
133
+ ``,
134
+ `- Artifact type: \`${artifact.artifactType}\``,
135
+ `- Schema version: \`${artifact.schemaVersion}\``,
136
+ `- Run ID: \`${artifact.runId}\``,
137
+ `- Gate: \`${artifact.gate}\``
138
+ ].join("\n");
139
+ }
140
+ function renderDiffMarkdown(artifact) {
141
+ const regressionList = artifact.regressions.length > 0
142
+ ? artifact.regressions.map((entry) => `- ${entry.id}: ${entry.message}`).join("\n")
143
+ : "_None._";
144
+ const recoveryList = artifact.recoveries.length > 0
145
+ ? artifact.recoveries.map((entry) => `- ${entry.id}: ${entry.message}`).join("\n")
146
+ : "_None._";
147
+ const suggestedNextStep = artifact.regressions.length > 0
148
+ ? `Start with the regressions: ${artifact.regressions.map((entry) => entry.id).join(", ")}.`
149
+ : artifact.recoveries.length > 0
150
+ ? "No regressions were detected. Review recoveries and decide whether they should become part of the expected baseline."
151
+ : "No status movement was detected. Save the diff artifact with the paired run artifacts for future comparison.";
152
+ return [
153
+ `# MCP Observatory Diff Report`,
154
+ ``,
155
+ `Generated at ${artifact.createdAt}`,
156
+ ``,
157
+ `## Target and Environment Metadata`,
158
+ ``,
159
+ `- Base run: \`${artifact.baseRunId}\``,
160
+ `- Head run: \`${artifact.headRunId}\``,
161
+ ``,
162
+ `## Executive Summary`,
163
+ ``,
164
+ table([
165
+ ["Gate", "Regressions", "Recoveries", "Unchanged", "Added", "Removed"],
166
+ [
167
+ artifact.gate,
168
+ String(artifact.summary.regressions),
169
+ String(artifact.summary.recoveries),
170
+ String(artifact.summary.unchanged),
171
+ String(artifact.summary.added),
172
+ String(artifact.summary.removed)
173
+ ]
174
+ ]),
175
+ ``,
176
+ `## At a Glance`,
177
+ ``,
178
+ `- Regressions: ${artifact.regressions.map((entry) => entry.id).join(", ") || "none"}`,
179
+ `- Recoveries: ${artifact.recoveries.map((entry) => entry.id).join(", ") || "none"}`,
180
+ `- Suggested next step: ${suggestedNextStep}`,
181
+ ``,
182
+ `## Regressions`,
183
+ ``,
184
+ regressionList,
185
+ ``,
186
+ `## Recoveries`,
187
+ ``,
188
+ recoveryList,
189
+ ``,
190
+ `## Full Capability Status Table`,
191
+ ``,
192
+ table([
193
+ ["Bucket", "Check", "From", "To", "Message"],
194
+ ...[
195
+ ...artifact.regressions.map((entry) => ["regression", entry]),
196
+ ...artifact.recoveries.map((entry) => ["recovery", entry]),
197
+ ...artifact.unchanged.map((entry) => ["unchanged", entry]),
198
+ ...artifact.added.map((entry) => ["added", entry]),
199
+ ...artifact.removed.map((entry) => ["removed", entry])
200
+ ].map(([bucket, entry]) => [
201
+ bucket,
202
+ entry.id,
203
+ entry.fromStatus ?? "n/a",
204
+ entry.toStatus ?? "n/a",
205
+ entry.message
206
+ ])
207
+ ]),
208
+ ``,
209
+ `## Evidence Snippets`,
210
+ ``,
211
+ `_Diff artifacts summarize status movement. For detailed evidence, inspect the underlying run artifacts._`,
212
+ ``,
213
+ `## Reproduction Commands`,
214
+ ``,
215
+ "```bash",
216
+ "npm run cli -- diff --base <path-to-base-run.json> --head <path-to-head-run.json> --format markdown",
217
+ "```",
218
+ ``,
219
+ `## Artifact Provenance`,
220
+ ``,
221
+ `- Artifact type: \`${artifact.artifactType}\``,
222
+ `- Schema version: \`${artifact.schemaVersion}\``,
223
+ `- Gate: \`${artifact.gate}\``
224
+ ].join("\n");
225
+ }
226
+ export function renderMarkdown(artifact) {
227
+ return artifact.artifactType === "run"
228
+ ? renderRunMarkdown(artifact)
229
+ : renderDiffMarkdown(artifact);
230
+ }
231
+ //# sourceMappingURL=markdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../../src/reporters/markdown.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { DiffArtifact, RunArtifact } from "../types.js";
2
+ export declare function renderTerminal(artifact: RunArtifact | DiffArtifact): string;
@@ -0,0 +1,110 @@
1
+ import { describeCheckList, findChecksByStatus, recommendRunNextStep, sortChecksByActionability } from "./common.js";
2
+ const ANSI = {
3
+ red: "\x1b[31m",
4
+ green: "\x1b[32m",
5
+ yellow: "\x1b[33m",
6
+ dim: "\x1b[2m",
7
+ bold: "\x1b[1m",
8
+ reset: "\x1b[0m",
9
+ };
10
+ function shouldColor() {
11
+ return !process.env["NO_COLOR"] && !process.argv.includes("--no-color");
12
+ }
13
+ function co(code, text) {
14
+ return shouldColor() ? `${code}${text}${ANSI.reset}` : text;
15
+ }
16
+ function colorStatus(status) {
17
+ switch (status) {
18
+ case "pass":
19
+ return co(ANSI.green, status);
20
+ case "fail":
21
+ return co(ANSI.red, status);
22
+ case "partial":
23
+ case "flaky":
24
+ return co(ANSI.yellow, status);
25
+ case "unsupported":
26
+ case "skipped":
27
+ return co(ANSI.dim, status);
28
+ }
29
+ }
30
+ function colorGate(gate) {
31
+ return gate === "pass" ? co(ANSI.green, gate) : co(ANSI.red, gate);
32
+ }
33
+ function formatCheck(check) {
34
+ return `- ${check.id}: ${colorStatus(check.status)} (${check.message})`;
35
+ }
36
+ function formatEntry(entry) {
37
+ const from = entry.fromStatus ?? "n/a";
38
+ const to = entry.toStatus ?? "n/a";
39
+ return `- ${entry.id}: ${from} -> ${to} (${entry.message})`;
40
+ }
41
+ function renderRunTerminal(artifact) {
42
+ const orderedChecks = sortChecksByActionability(artifact.checks);
43
+ const failingChecks = findChecksByStatus(artifact.checks, "fail");
44
+ const partialChecks = [
45
+ ...findChecksByStatus(artifact.checks, "partial"),
46
+ ...findChecksByStatus(artifact.checks, "flaky")
47
+ ];
48
+ const unsupportedChecks = findChecksByStatus(artifact.checks, "unsupported");
49
+ const skippedChecks = findChecksByStatus(artifact.checks, "skipped");
50
+ const lines = [
51
+ co(ANSI.bold, `MCP Observatory Run`),
52
+ `Run ID: ${artifact.runId}`,
53
+ `Gate: ${co(ANSI.bold, colorGate(artifact.gate))}`,
54
+ `Target: ${artifact.target.targetId} (${artifact.target.adapter})`,
55
+ `Server: ${artifact.target.serverName ?? "unknown"} ${artifact.target.serverVersion ?? ""}`.trim(),
56
+ `Counts: pass=${artifact.summary.pass}, fail=${artifact.summary.fail}, partial=${artifact.summary.partial}, unsupported=${artifact.summary.unsupported}, flaky=${artifact.summary.flaky}, skipped=${artifact.summary.skipped}`
57
+ ];
58
+ lines.push(`Actionable now:`);
59
+ lines.push(`- failing checks: ${describeCheckList(failingChecks)}`);
60
+ lines.push(`- partial checks: ${describeCheckList(partialChecks)}`);
61
+ lines.push(`- skipped checks: ${describeCheckList(skippedChecks)}`);
62
+ lines.push(`- unsupported checks: ${describeCheckList(unsupportedChecks)}`);
63
+ lines.push(`Next step: ${recommendRunNextStep(artifact)}`);
64
+ if (artifact.fatalError !== undefined) {
65
+ lines.push("Failure diagnosis:");
66
+ lines.push(...artifact.fatalError.split("\n"));
67
+ }
68
+ lines.push("Checks (most actionable first):");
69
+ for (const check of orderedChecks) {
70
+ lines.push(formatCheck(check));
71
+ }
72
+ return lines.join("\n");
73
+ }
74
+ function renderDiffTerminal(artifact) {
75
+ const lines = [
76
+ co(ANSI.bold, `MCP Observatory Diff`),
77
+ `Base: ${artifact.baseRunId}`,
78
+ `Head: ${artifact.headRunId}`,
79
+ `Gate: ${co(ANSI.bold, colorGate(artifact.gate))}`,
80
+ `Counts: regressions=${artifact.summary.regressions}, recoveries=${artifact.summary.recoveries}, unchanged=${artifact.summary.unchanged}, added=${artifact.summary.added}, removed=${artifact.summary.removed}`
81
+ ];
82
+ if (artifact.regressions.length > 0) {
83
+ lines.push(co(ANSI.red, "Regressions:"));
84
+ lines.push(...artifact.regressions.map((e) => co(ANSI.red, formatEntry(e))));
85
+ }
86
+ if (artifact.recoveries.length > 0) {
87
+ lines.push(co(ANSI.green, "Recoveries:"));
88
+ lines.push(...artifact.recoveries.map((e) => co(ANSI.green, formatEntry(e))));
89
+ }
90
+ if (artifact.unchanged.length > 0) {
91
+ lines.push(co(ANSI.dim, "Unchanged:"));
92
+ lines.push(...artifact.unchanged.map((e) => co(ANSI.dim, formatEntry(e))));
93
+ }
94
+ if (artifact.schemaDrift && artifact.schemaDrift.length > 0) {
95
+ lines.push(co(ANSI.yellow, "Schema Drift:"));
96
+ for (const entry of artifact.schemaDrift) {
97
+ lines.push(co(ANSI.yellow, `- ${entry.name} (${entry.capability}): ${entry.changes.join(", ")}`));
98
+ }
99
+ }
100
+ if (artifact.regressions.length === 0 && artifact.recoveries.length === 0 && (!artifact.schemaDrift || artifact.schemaDrift.length === 0)) {
101
+ lines.push(co(ANSI.dim, "No regressions, recoveries, or schema drift detected."));
102
+ }
103
+ return lines.join("\n");
104
+ }
105
+ export function renderTerminal(artifact) {
106
+ return artifact.artifactType === "run"
107
+ ? renderRunTerminal(artifact)
108
+ : renderDiffTerminal(artifact);
109
+ }
110
+ //# sourceMappingURL=terminal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"terminal.js","sourceRoot":"","sources":["../../../src/reporters/terminal.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { RunArtifact, TargetConfig } from "./types.js";
2
+ export interface RunOptions {
3
+ invokeTools?: boolean;
4
+ }
5
+ export declare function runTarget(target: TargetConfig, options?: RunOptions): Promise<RunArtifact>;
@@ -0,0 +1,138 @@
1
+ import os from "node:os";
2
+ import { HttpAdapter } from "./adapters/http.js";
3
+ import { AdapterConnectError, LocalProcessAdapter } from "./adapters/local-process.js";
4
+ import { runPromptsCheck } from "./checks/prompts.js";
5
+ import { runResourcesCheck } from "./checks/resources.js";
6
+ import { runToolsCheck } from "./checks/tools.js";
7
+ import { runToolsInvokeCheck } from "./checks/tools-invoke.js";
8
+ import { SCHEMA_VERSION } from "./types.js";
9
+ import { buildRunId } from "./utils/ids.js";
10
+ import { TOOL_VERSION } from "./version.js";
11
+ function createEmptyCounts() {
12
+ return {
13
+ total: 0,
14
+ pass: 0,
15
+ fail: 0,
16
+ partial: 0,
17
+ unsupported: 0,
18
+ flaky: 0,
19
+ skipped: 0
20
+ };
21
+ }
22
+ function buildSummary(checks, fatalError) {
23
+ const counts = createEmptyCounts();
24
+ for (const check of checks) {
25
+ counts.total += 1;
26
+ counts[check.status] += 1;
27
+ }
28
+ const gate = fatalError !== undefined || counts.fail > 0 ? "fail" : "pass";
29
+ return {
30
+ ...counts,
31
+ gate
32
+ };
33
+ }
34
+ async function connectTarget(target) {
35
+ if (target.adapter === "http") {
36
+ const adapter = new HttpAdapter();
37
+ return adapter.connect(target);
38
+ }
39
+ const adapter = new LocalProcessAdapter();
40
+ return adapter.connect(target);
41
+ }
42
+ export async function runTarget(target, options) {
43
+ const runId = buildRunId();
44
+ const createdAt = new Date().toISOString();
45
+ let checks = [];
46
+ let fatalError;
47
+ let serverName;
48
+ let serverVersion;
49
+ try {
50
+ const session = await connectTarget(target);
51
+ serverName = session.serverName;
52
+ serverVersion = session.serverVersion;
53
+ try {
54
+ const checkContext = {
55
+ client: session.client,
56
+ serverCapabilities: session.serverCapabilities,
57
+ target,
58
+ timeoutMs: target.timeoutMs ?? 10_000,
59
+ stderrLines: session.stderrLines
60
+ };
61
+ const toolsCheck = await runToolsCheck(checkContext);
62
+ const promptsCheck = await runPromptsCheck(checkContext);
63
+ const resourcesCheck = await runResourcesCheck(checkContext);
64
+ checks = [
65
+ toolsCheck.result,
66
+ promptsCheck.result,
67
+ resourcesCheck.result
68
+ ];
69
+ if (options?.invokeTools) {
70
+ const invokeCheck = await runToolsInvokeCheck(checkContext);
71
+ checks.push(invokeCheck.result);
72
+ }
73
+ }
74
+ finally {
75
+ await session.close();
76
+ }
77
+ }
78
+ catch (error) {
79
+ fatalError = error instanceof Error ? error.message : String(error);
80
+ const skippedMessage = error instanceof AdapterConnectError
81
+ ? "Skipped because startup failed before the MCP session initialized. See the failure diagnosis."
82
+ : "Skipped because the adapter never established a session.";
83
+ checks = [
84
+ {
85
+ id: "tools",
86
+ capability: "tools",
87
+ status: "skipped",
88
+ durationMs: 0,
89
+ message: skippedMessage,
90
+ evidence: []
91
+ },
92
+ {
93
+ id: "prompts",
94
+ capability: "prompts",
95
+ status: "skipped",
96
+ durationMs: 0,
97
+ message: skippedMessage,
98
+ evidence: []
99
+ },
100
+ {
101
+ id: "resources",
102
+ capability: "resources",
103
+ status: "skipped",
104
+ durationMs: 0,
105
+ message: skippedMessage,
106
+ evidence: []
107
+ }
108
+ ];
109
+ }
110
+ const summary = buildSummary(checks, fatalError);
111
+ return {
112
+ artifactType: "run",
113
+ schemaVersion: SCHEMA_VERSION,
114
+ gate: summary.gate,
115
+ runId,
116
+ createdAt,
117
+ toolVersion: TOOL_VERSION,
118
+ target: {
119
+ targetId: target.targetId,
120
+ adapter: target.adapter,
121
+ command: target.adapter === "http" ? target.url : target.command,
122
+ args: target.adapter === "http" ? [] : target.args,
123
+ url: target.adapter === "http" ? target.url : undefined,
124
+ cwd: target.adapter === "http" ? undefined : target.cwd,
125
+ metadata: target.metadata,
126
+ serverName,
127
+ serverVersion
128
+ },
129
+ environment: {
130
+ platform: `${os.platform()} ${os.release()}`,
131
+ nodeVersion: process.version
132
+ },
133
+ summary,
134
+ checks,
135
+ fatalError
136
+ };
137
+ }
138
+ //# sourceMappingURL=runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { CheckId, SchemaDriftEntry } from "./types.js";
2
+ /**
3
+ * Compare two schema maps and return human-readable drift descriptions.
4
+ * Each map is keyed by item name (e.g., tool name) with the schema object as value.
5
+ */
6
+ export declare function diffSchemas(capability: CheckId, base: Record<string, object>, head: Record<string, object>): SchemaDriftEntry[];
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Compare two schema maps and return human-readable drift descriptions.
3
+ * Each map is keyed by item name (e.g., tool name) with the schema object as value.
4
+ */
5
+ export function diffSchemas(capability, base, head) {
6
+ const entries = [];
7
+ const allNames = new Set([...Object.keys(base), ...Object.keys(head)]);
8
+ for (const name of allNames) {
9
+ const baseSchema = base[name];
10
+ const headSchema = head[name];
11
+ if (baseSchema === undefined && headSchema !== undefined) {
12
+ entries.push({ capability, name, changes: [`added (new ${capability.replace("-invoke", "")})`] });
13
+ continue;
14
+ }
15
+ if (baseSchema !== undefined && headSchema === undefined) {
16
+ entries.push({ capability, name, changes: [`removed`] });
17
+ continue;
18
+ }
19
+ if (baseSchema === undefined || headSchema === undefined) {
20
+ continue;
21
+ }
22
+ const changes = compareSchemas(baseSchema, headSchema);
23
+ if (changes.length > 0) {
24
+ entries.push({ capability, name, changes });
25
+ }
26
+ }
27
+ return entries;
28
+ }
29
+ function compareSchemas(base, head) {
30
+ const changes = [];
31
+ // Compare required fields
32
+ const baseRequired = asStringArray(base["required"]);
33
+ const headRequired = asStringArray(head["required"]);
34
+ for (const field of headRequired) {
35
+ if (!baseRequired.includes(field)) {
36
+ changes.push(`added required field '${field}'`);
37
+ }
38
+ }
39
+ for (const field of baseRequired) {
40
+ if (!headRequired.includes(field)) {
41
+ changes.push(`removed required field '${field}'`);
42
+ }
43
+ }
44
+ // Compare properties
45
+ const baseProps = asRecord(base["properties"]);
46
+ const headProps = asRecord(head["properties"]);
47
+ const allProps = new Set([...Object.keys(baseProps), ...Object.keys(headProps)]);
48
+ for (const prop of allProps) {
49
+ const baseProp = baseProps[prop];
50
+ const headProp = headProps[prop];
51
+ if (baseProp === undefined && headProp !== undefined) {
52
+ changes.push(`added property '${prop}'`);
53
+ continue;
54
+ }
55
+ if (baseProp !== undefined && headProp === undefined) {
56
+ changes.push(`removed property '${prop}'`);
57
+ continue;
58
+ }
59
+ if (baseProp !== undefined && headProp !== undefined) {
60
+ if (baseProp["type"] !== headProp["type"]) {
61
+ changes.push(`changed '${prop}' type from '${String(baseProp["type"])}' to '${String(headProp["type"])}'`);
62
+ }
63
+ }
64
+ }
65
+ return changes;
66
+ }
67
+ function asStringArray(value) {
68
+ return Array.isArray(value) ? value.filter((v) => typeof v === "string") : [];
69
+ }
70
+ function asRecord(value) {
71
+ return typeof value === "object" && value !== null ? value : {};
72
+ }
73
+ //# sourceMappingURL=schema-diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-diff.js","sourceRoot":"","sources":["../../src/schema-diff.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { DiffArtifact, RunArtifact } from "./types.js";
2
+ export type Artifact = RunArtifact | DiffArtifact;
3
+ export declare function defaultRunsDirectory(cwd?: string): string;
4
+ export declare function ensureDirectory(directoryPath: string): Promise<void>;
5
+ export declare function writeRunArtifact(artifact: RunArtifact, outDir: string): Promise<string>;
6
+ export declare function readArtifact(filePath: string): Promise<Artifact>;
@@ -0,0 +1,32 @@
1
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { slugify } from "./utils/ids.js";
4
+ import { validateDiffArtifact, validateRunArtifact } from "./validate.js";
5
+ export function defaultRunsDirectory(cwd = process.cwd()) {
6
+ return path.join(cwd, ".mcp-observatory", "runs");
7
+ }
8
+ export async function ensureDirectory(directoryPath) {
9
+ await mkdir(directoryPath, { recursive: true });
10
+ }
11
+ export async function writeRunArtifact(artifact, outDir) {
12
+ await ensureDirectory(outDir);
13
+ const fileName = `${artifact.createdAt.replaceAll(":", "-")}--${slugify(artifact.target.targetId)}.json`;
14
+ const filePath = path.join(outDir, fileName);
15
+ await writeFile(filePath, JSON.stringify(artifact, null, 2) + "\n", "utf8");
16
+ return filePath;
17
+ }
18
+ export async function readArtifact(filePath) {
19
+ const content = await readFile(filePath, "utf8");
20
+ const data = JSON.parse(content);
21
+ if (typeof data === "object" && data !== null && !Array.isArray(data) && data["artifactType"] === "diff") {
22
+ return validateDiffArtifact(data);
23
+ }
24
+ // For run artifacts and target configs (which lack artifactType), return as-is
25
+ // Target configs are validated separately via validateTargetConfig
26
+ if (typeof data === "object" && data !== null && !Array.isArray(data) && data["artifactType"] === "run") {
27
+ return validateRunArtifact(data);
28
+ }
29
+ // Unrecognized shape — return as-is for backwards compat (e.g., target configs read via readArtifact)
30
+ return data;
31
+ }
32
+ //# sourceMappingURL=storage.js.map