@yawlabs/mcp-compliance 0.9.2 → 0.11.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.
@@ -2,7 +2,7 @@ import {
2
2
  SPEC_BASE,
3
3
  TEST_DEFINITIONS,
4
4
  runComplianceSuite
5
- } from "../chunk-FKTEFLK5.js";
5
+ } from "../chunk-DGGPE3ZM.js";
6
6
 
7
7
  // src/mcp/server.ts
8
8
  import { existsSync, readFileSync } from "fs";
package/dist/runner.d.ts CHANGED
@@ -12,6 +12,8 @@ interface TestResult {
12
12
  type Grade = "A" | "B" | "C" | "D" | "F";
13
13
  type Overall = "pass" | "partial" | "fail";
14
14
  interface ComplianceReport {
15
+ /** Stable report-format version. See REPORT_SCHEMA_VERSION. */
16
+ schemaVersion: string;
15
17
  specVersion: string;
16
18
  toolVersion: string;
17
19
  url: string;
@@ -96,6 +98,16 @@ declare function computeScore(tests: TestResult[]): {
96
98
  }>;
97
99
  };
98
100
 
101
+ /**
102
+ * Generate a short, deterministic hash of a URL for badge paths.
103
+ * SHA-256 truncated to 24 hex chars (96 bits of entropy) — matches the
104
+ * server-side hash width used by mcp.hosting for `/compliance/ext/<hash>`.
105
+ *
106
+ * Exported so mcp.hosting (and other consumers) can compute matching
107
+ * hashes when looking up reports/badges by URL. The hash is the canonical
108
+ * key for `/compliance/ext/<hash>` and `/api/compliance/ext/<hash>/badge`.
109
+ */
110
+ declare function urlHash(url: string): string;
99
111
  /**
100
112
  * Generate badge URLs and markdown for a compliance report.
101
113
  * Badge images are served by mcp.hosting.
@@ -135,8 +147,15 @@ interface PreviewOptions {
135
147
  */
136
148
  declare function previewTests(opts?: PreviewOptions): TestDefinition[];
137
149
  interface RunOptions {
138
- /** Optional callback for progress updates */
150
+ /** Optional callback for progress updates (legacy minimal signature). */
139
151
  onProgress?: (testId: string, passed: boolean, details: string) => void;
152
+ /**
153
+ * Optional callback fired after each test completes with the full
154
+ * TestResult (category, required, durationMs, specRef). Prefer this
155
+ * over onProgress for live dashboards and streaming UIs that need
156
+ * structured data per test.
157
+ */
158
+ onTestComplete?: (result: TestResult) => void;
140
159
  /** Extra headers to include on all requests */
141
160
  headers?: Record<string, string>;
142
161
  /** Request timeout in milliseconds (default: 15000) */
@@ -156,4 +175,4 @@ interface RunOptions {
156
175
  */
157
176
  declare function runComplianceSuite(target: string | TransportTarget, options?: RunOptions): Promise<ComplianceReport>;
158
177
 
159
- export { type ComplianceReport, type PreviewOptions, type RunOptions, SPEC_BASE, SPEC_VERSION, TEST_DEFINITIONS, type TestResult, computeGrade, computeScore, generateBadge, parseSSEResponse, previewTests, runComplianceSuite };
178
+ export { type ComplianceReport, type PreviewOptions, type RunOptions, SPEC_BASE, SPEC_VERSION, TEST_DEFINITIONS, type TestResult, computeGrade, computeScore, generateBadge, parseSSEResponse, previewTests, runComplianceSuite, urlHash };
package/dist/runner.js CHANGED
@@ -7,8 +7,9 @@ import {
7
7
  generateBadge,
8
8
  parseSSEResponse,
9
9
  previewTests,
10
- runComplianceSuite
11
- } from "./chunk-FKTEFLK5.js";
10
+ runComplianceSuite,
11
+ urlHash
12
+ } from "./chunk-DGGPE3ZM.js";
12
13
  export {
13
14
  SPEC_BASE,
14
15
  SPEC_VERSION,
@@ -18,5 +19,6 @@ export {
18
19
  generateBadge,
19
20
  parseSSEResponse,
20
21
  previewTests,
21
- runComplianceSuite
22
+ runComplianceSuite,
23
+ urlHash
22
24
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yawlabs/mcp-compliance",
3
- "version": "0.9.2",
3
+ "version": "0.11.0",
4
4
  "description": "CLI tool and MCP server that tests MCP servers for spec compliance",
5
5
  "license": "MIT",
6
6
  "author": "Yaw Labs <contact@yaw.sh> (https://yaw.sh)",
@@ -23,6 +23,7 @@
23
23
  "files": [
24
24
  "dist",
25
25
  "!dist/**/*.test.*",
26
+ "schemas",
26
27
  "README.md",
27
28
  "LICENSE"
28
29
  ],
@@ -47,6 +48,8 @@
47
48
  "devDependencies": {
48
49
  "@biomejs/biome": "^1.9.4",
49
50
  "@types/node": "^25.5.2",
51
+ "ajv": "^8.18.0",
52
+ "ajv-formats": "^3.0.1",
50
53
  "tsup": "^8.4.0",
51
54
  "typescript": "^5.8.3",
52
55
  "vitest": "^3.1.1"
@@ -0,0 +1,165 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://mcp.hosting/schemas/compliance/report.v1.json",
4
+ "title": "MCP Compliance Report",
5
+ "description": "Structured output of the mcp-compliance test suite. Stable, versioned contract — increment schemaVersion on breaking changes. Consumed by mcp.hosting and third-party dashboards.",
6
+ "type": "object",
7
+ "required": [
8
+ "schemaVersion",
9
+ "specVersion",
10
+ "toolVersion",
11
+ "url",
12
+ "timestamp",
13
+ "score",
14
+ "grade",
15
+ "overall",
16
+ "summary",
17
+ "categories",
18
+ "tests",
19
+ "warnings",
20
+ "serverInfo",
21
+ "toolCount",
22
+ "toolNames",
23
+ "resourceCount",
24
+ "resourceNames",
25
+ "promptCount",
26
+ "promptNames",
27
+ "badge"
28
+ ],
29
+ "properties": {
30
+ "schemaVersion": {
31
+ "type": "string",
32
+ "const": "1",
33
+ "description": "Version of this report schema. Breaking changes bump the major version."
34
+ },
35
+ "specVersion": {
36
+ "type": "string",
37
+ "description": "MCP spec version tested against, e.g. \"2025-11-25\"."
38
+ },
39
+ "toolVersion": {
40
+ "type": "string",
41
+ "description": "Version of the mcp-compliance tool that produced this report."
42
+ },
43
+ "url": {
44
+ "type": "string",
45
+ "description": "HTTP URL or stdio display string for the server under test."
46
+ },
47
+ "timestamp": {
48
+ "type": "string",
49
+ "format": "date-time",
50
+ "description": "ISO 8601 timestamp of when the report was generated."
51
+ },
52
+ "score": {
53
+ "type": "number",
54
+ "minimum": 0,
55
+ "maximum": 100,
56
+ "description": "Weighted compliance score: required tests 70%, optional 30%."
57
+ },
58
+ "grade": {
59
+ "type": "string",
60
+ "enum": ["A", "B", "C", "D", "F"],
61
+ "description": "Letter grade derived from score. A>=90, B>=75, C>=60, D>=40, F<40."
62
+ },
63
+ "overall": {
64
+ "type": "string",
65
+ "enum": ["pass", "partial", "fail"],
66
+ "description": "High-level verdict: pass = all required tests passed, partial = some failed, fail = many failed."
67
+ },
68
+ "summary": {
69
+ "type": "object",
70
+ "required": ["total", "passed", "failed", "required", "requiredPassed"],
71
+ "properties": {
72
+ "total": { "type": "integer", "minimum": 0 },
73
+ "passed": { "type": "integer", "minimum": 0 },
74
+ "failed": { "type": "integer", "minimum": 0 },
75
+ "required": { "type": "integer", "minimum": 0 },
76
+ "requiredPassed": { "type": "integer", "minimum": 0 }
77
+ },
78
+ "additionalProperties": false
79
+ },
80
+ "categories": {
81
+ "type": "object",
82
+ "description": "Per-category pass/total counts, keyed by TestCategory.",
83
+ "additionalProperties": {
84
+ "type": "object",
85
+ "required": ["passed", "total"],
86
+ "properties": {
87
+ "passed": { "type": "integer", "minimum": 0 },
88
+ "total": { "type": "integer", "minimum": 0 }
89
+ },
90
+ "additionalProperties": false
91
+ }
92
+ },
93
+ "tests": {
94
+ "type": "array",
95
+ "items": { "$ref": "#/$defs/TestResult" }
96
+ },
97
+ "warnings": {
98
+ "type": "array",
99
+ "items": { "type": "string" },
100
+ "description": "Non-fatal diagnostics from the test run. Capped at 100 entries."
101
+ },
102
+ "serverInfo": {
103
+ "type": "object",
104
+ "required": ["protocolVersion", "name", "version", "capabilities"],
105
+ "properties": {
106
+ "protocolVersion": { "type": ["string", "null"] },
107
+ "name": { "type": ["string", "null"] },
108
+ "version": { "type": ["string", "null"] },
109
+ "capabilities": { "type": "object" }
110
+ },
111
+ "additionalProperties": false
112
+ },
113
+ "toolCount": { "type": "integer", "minimum": 0 },
114
+ "toolNames": { "type": "array", "items": { "type": "string" } },
115
+ "resourceCount": { "type": "integer", "minimum": 0 },
116
+ "resourceNames": { "type": "array", "items": { "type": "string" } },
117
+ "promptCount": { "type": "integer", "minimum": 0 },
118
+ "promptNames": { "type": "array", "items": { "type": "string" } },
119
+ "badge": {
120
+ "type": "object",
121
+ "required": ["imageUrl", "reportUrl", "markdown", "html"],
122
+ "properties": {
123
+ "imageUrl": { "type": "string", "format": "uri" },
124
+ "reportUrl": { "type": "string", "format": "uri" },
125
+ "markdown": { "type": "string" },
126
+ "html": { "type": "string" }
127
+ },
128
+ "additionalProperties": false
129
+ }
130
+ },
131
+ "additionalProperties": false,
132
+ "$defs": {
133
+ "TestResult": {
134
+ "type": "object",
135
+ "required": ["id", "name", "category", "passed", "required", "details", "durationMs"],
136
+ "properties": {
137
+ "id": { "type": "string" },
138
+ "name": { "type": "string" },
139
+ "category": {
140
+ "type": "string",
141
+ "enum": [
142
+ "transport",
143
+ "lifecycle",
144
+ "tools",
145
+ "resources",
146
+ "prompts",
147
+ "errors",
148
+ "schema",
149
+ "security"
150
+ ]
151
+ },
152
+ "passed": { "type": "boolean" },
153
+ "required": { "type": "boolean" },
154
+ "details": { "type": "string" },
155
+ "durationMs": { "type": "integer", "minimum": 0 },
156
+ "specRef": {
157
+ "type": "string",
158
+ "format": "uri",
159
+ "description": "Deep link to the relevant spec section."
160
+ }
161
+ },
162
+ "additionalProperties": false
163
+ }
164
+ }
165
+ }