@yawlabs/mcp-compliance 0.2.1 → 0.4.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.
@@ -1,2 +1,12 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
1
2
 
2
- export { }
3
+ /**
4
+ * Create and configure the MCP compliance server instance.
5
+ */
6
+ declare function createComplianceServer(): McpServer;
7
+ /**
8
+ * Start the MCP compliance server with stdio transport.
9
+ */
10
+ declare function startServer(): Promise<void>;
11
+
12
+ export { createComplianceServer, startServer };
@@ -1,25 +1,46 @@
1
1
  import {
2
2
  TEST_DEFINITIONS,
3
3
  runComplianceSuite
4
- } from "../chunk-SP24UFRC.js";
4
+ } from "../chunk-KNOSZ3TD.js";
5
5
 
6
6
  // src/mcp/server.ts
7
+ import { createRequire } from "module";
7
8
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
8
9
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
9
- import { createRequire } from "module";
10
10
 
11
11
  // src/mcp/tools.ts
12
12
  import { z } from "zod";
13
- function registerTools(server2) {
14
- server2.tool(
13
+ function registerTools(server) {
14
+ server.tool(
15
15
  "mcp_compliance_test",
16
16
  "Run the full MCP compliance test suite against a server URL. Returns grade (A-F), score, and detailed results for all 43 tests covering transport, lifecycle, tools, resources, prompts, errors, and schema validation.",
17
17
  {
18
- url: z.string().url().describe("The MCP server URL to test (must be HTTP or HTTPS)")
18
+ url: z.string().url().describe("The MCP server URL to test (must be HTTP or HTTPS)"),
19
+ auth: z.string().optional().describe('Authorization header value (e.g., "Bearer tok123")'),
20
+ headers: z.record(z.string()).optional().describe('Additional headers to include on all requests (e.g., {"X-Api-Key": "abc"})'),
21
+ timeout: z.number().optional().describe("Request timeout in milliseconds (default: 15000)"),
22
+ retries: z.number().optional().describe("Number of retries for failed tests (default: 0)"),
23
+ only: z.array(z.string()).optional().describe("Only run tests matching these categories or test IDs"),
24
+ skip: z.array(z.string()).optional().describe("Skip tests matching these categories or test IDs")
25
+ },
26
+ {
27
+ title: "Run MCP Compliance Tests",
28
+ readOnlyHint: true,
29
+ destructiveHint: false,
30
+ idempotentHint: true,
31
+ openWorldHint: true
19
32
  },
20
- async ({ url }) => {
33
+ async ({ url, auth, headers: extraHeaders, timeout, retries, only, skip }) => {
21
34
  try {
22
- const report = await runComplianceSuite(url);
35
+ const headers = { ...extraHeaders };
36
+ if (auth) headers.Authorization = auth;
37
+ const report = await runComplianceSuite(url, {
38
+ headers: Object.keys(headers).length > 0 ? headers : void 0,
39
+ timeout,
40
+ retries,
41
+ only,
42
+ skip
43
+ });
23
44
  const summary = [
24
45
  `Grade: ${report.grade} (${report.score}%)`,
25
46
  `Overall: ${report.overall}`,
@@ -55,29 +76,46 @@ ${JSON.stringify(report, null, 2)}` }
55
76
  }
56
77
  }
57
78
  );
58
- server2.tool(
79
+ server.tool(
59
80
  "mcp_compliance_badge",
60
81
  "Get the badge markdown embed code for an MCP server. Runs the compliance test suite first to determine the grade.",
61
82
  {
62
- url: z.string().url().describe("The MCP server URL to test")
83
+ url: z.string().url().describe("The MCP server URL to test"),
84
+ auth: z.string().optional().describe('Authorization header value (e.g., "Bearer tok123")'),
85
+ headers: z.record(z.string()).optional().describe("Additional headers to include on all requests"),
86
+ timeout: z.number().optional().describe("Request timeout in milliseconds (default: 15000)")
63
87
  },
64
- async ({ url }) => {
88
+ {
89
+ title: "Get Compliance Badge",
90
+ readOnlyHint: true,
91
+ destructiveHint: false,
92
+ idempotentHint: true,
93
+ openWorldHint: true
94
+ },
95
+ async ({ url, auth, headers: extraHeaders, timeout }) => {
65
96
  try {
66
- const report = await runComplianceSuite(url);
97
+ const headers = { ...extraHeaders };
98
+ if (auth) headers.Authorization = auth;
99
+ const report = await runComplianceSuite(url, {
100
+ headers: Object.keys(headers).length > 0 ? headers : void 0,
101
+ timeout
102
+ });
67
103
  const badge = report.badge;
68
104
  return {
69
- content: [{
70
- type: "text",
71
- text: [
72
- `Grade: ${report.grade} (${report.score}%)`,
73
- "",
74
- "Markdown:",
75
- badge.markdown,
76
- "",
77
- "HTML:",
78
- badge.html
79
- ].join("\n")
80
- }]
105
+ content: [
106
+ {
107
+ type: "text",
108
+ text: [
109
+ `Grade: ${report.grade} (${report.score}%)`,
110
+ "",
111
+ "Markdown:",
112
+ badge.markdown,
113
+ "",
114
+ "HTML:",
115
+ badge.html
116
+ ].join("\n")
117
+ }
118
+ ]
81
119
  };
82
120
  } catch (err) {
83
121
  return {
@@ -87,39 +125,52 @@ ${JSON.stringify(report, null, 2)}` }
87
125
  }
88
126
  }
89
127
  );
90
- server2.tool(
128
+ server.tool(
91
129
  "mcp_compliance_explain",
92
130
  "Explain what a specific compliance test ID checks and why it matters.",
93
131
  {
94
132
  testId: z.string().describe('The test ID to explain (e.g., "transport-post", "lifecycle-init", "tools-schema")')
95
133
  },
134
+ {
135
+ title: "Explain Compliance Test",
136
+ readOnlyHint: true,
137
+ destructiveHint: false,
138
+ idempotentHint: true,
139
+ openWorldHint: false
140
+ },
96
141
  async ({ testId }) => {
97
142
  const def = TEST_DEFINITIONS.find((t) => t.id === testId);
98
143
  if (!def) {
99
144
  return {
100
- content: [{
101
- type: "text",
102
- text: `Unknown test ID: "${testId}"
145
+ content: [
146
+ {
147
+ type: "text",
148
+ text: `Unknown test ID: "${testId}"
103
149
 
104
150
  Valid test IDs:
105
151
  ${TEST_DEFINITIONS.map((t) => t.id).join(", ")}`
106
- }],
152
+ }
153
+ ],
107
154
  isError: true
108
155
  };
109
156
  }
110
157
  return {
111
- content: [{
112
- type: "text",
113
- text: [
114
- `Test: ${def.id}`,
115
- `Name: ${def.name}`,
116
- `Category: ${def.category}`,
117
- `Required: ${def.required ? "Yes" : "No"}`,
118
- `Spec reference: https://modelcontextprotocol.io/specification/2025-11-25/${def.specRef}`,
119
- "",
120
- def.description
121
- ].join("\n")
122
- }]
158
+ content: [
159
+ {
160
+ type: "text",
161
+ text: [
162
+ `Test: ${def.id}`,
163
+ `Name: ${def.name}`,
164
+ `Category: ${def.category}`,
165
+ `Required: ${def.required ? "Yes" : "No"}`,
166
+ `Spec reference: https://modelcontextprotocol.io/specification/2025-11-25/${def.specRef}`,
167
+ "",
168
+ def.description,
169
+ "",
170
+ `Fix: ${def.recommendation}`
171
+ ].join("\n")
172
+ }
173
+ ]
123
174
  };
124
175
  }
125
176
  );
@@ -128,13 +179,24 @@ ${TEST_DEFINITIONS.map((t) => t.id).join(", ")}`
128
179
  // src/mcp/server.ts
129
180
  var require2 = createRequire(import.meta.url);
130
181
  var { version } = require2("../../package.json");
131
- var server = new McpServer({ name: "mcp-compliance", version });
132
- registerTools(server);
133
- async function main() {
182
+ function createComplianceServer() {
183
+ const server = new McpServer({ name: "mcp-compliance", version });
184
+ registerTools(server);
185
+ return server;
186
+ }
187
+ async function startServer() {
188
+ const server = createComplianceServer();
134
189
  const transport = new StdioServerTransport();
135
190
  await server.connect(transport);
136
191
  }
137
- main().catch((err) => {
138
- console.error("MCP server error:", err);
139
- process.exit(1);
140
- });
192
+ var isDirectRun = process.argv[1]?.endsWith("mcp/server.js") || process.argv[1]?.endsWith("mcp\\server.js");
193
+ if (isDirectRun) {
194
+ startServer().catch((err) => {
195
+ console.error("MCP server error:", err);
196
+ process.exit(1);
197
+ });
198
+ }
199
+ export {
200
+ createComplianceServer,
201
+ startServer
202
+ };
package/dist/runner.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- type TestCategory = 'transport' | 'lifecycle' | 'tools' | 'resources' | 'prompts' | 'errors' | 'schema';
1
+ type TestCategory = "transport" | "lifecycle" | "tools" | "resources" | "prompts" | "errors" | "schema";
2
2
  interface TestResult {
3
3
  id: string;
4
4
  name: string;
@@ -9,8 +9,8 @@ interface TestResult {
9
9
  durationMs: number;
10
10
  specRef?: string;
11
11
  }
12
- type Grade = 'A' | 'B' | 'C' | 'D' | 'F';
13
- type Overall = 'pass' | 'partial' | 'fail';
12
+ type Grade = "A" | "B" | "C" | "D" | "F";
13
+ type Overall = "pass" | "partial" | "fail";
14
14
  interface ComplianceReport {
15
15
  specVersion: string;
16
16
  toolVersion: string;
@@ -58,6 +58,7 @@ interface TestDefinition {
58
58
  required: boolean;
59
59
  specRef: string;
60
60
  description: string;
61
+ recommendation: string;
61
62
  }
62
63
  /** All 43 test IDs with descriptions for the explain command */
63
64
  declare const TEST_DEFINITIONS: TestDefinition[];
@@ -66,7 +67,7 @@ declare function computeGrade(score: number): Grade;
66
67
  declare function computeScore(tests: TestResult[]): {
67
68
  score: number;
68
69
  grade: Grade;
69
- overall: 'pass' | 'partial' | 'fail';
70
+ overall: "pass" | "partial" | "fail";
70
71
  summary: {
71
72
  total: number;
72
73
  passed: number;
package/dist/runner.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  computeScore,
5
5
  generateBadge,
6
6
  runComplianceSuite
7
- } from "./chunk-SP24UFRC.js";
7
+ } from "./chunk-KNOSZ3TD.js";
8
8
  export {
9
9
  TEST_DEFINITIONS,
10
10
  computeGrade,
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@yawlabs/mcp-compliance",
3
- "version": "0.2.1",
3
+ "version": "0.4.0",
4
4
  "description": "CLI tool and MCP server that tests MCP servers for spec compliance",
5
5
  "license": "MIT",
6
- "author": "Yaw Labs (https://yaw.sh)",
6
+ "author": "Yaw Labs <contact@yaw.sh> (https://yaw.sh)",
7
7
  "type": "module",
8
8
  "exports": {
9
9
  ".": {
@@ -18,14 +18,20 @@
18
18
  },
19
19
  "files": [
20
20
  "dist",
21
- "README.md"
21
+ "!dist/**/*.test.*",
22
+ "README.md",
23
+ "LICENSE"
22
24
  ],
23
25
  "scripts": {
24
26
  "build": "tsup",
25
27
  "dev": "tsup --watch",
26
28
  "test": "vitest run",
27
- "lint": "tsc --noEmit",
28
- "prepublishOnly": "npm run build"
29
+ "lint": "biome check src/",
30
+ "lint:fix": "biome check --write src/",
31
+ "typecheck": "tsc --noEmit",
32
+ "test:ci": "npm run build && npm test",
33
+ "prepublishOnly": "npm run build",
34
+ "start": "node dist/index.js"
29
35
  },
30
36
  "dependencies": {
31
37
  "@modelcontextprotocol/sdk": "^1.29.0",
@@ -35,6 +41,7 @@
35
41
  "zod": "^3.24.4"
36
42
  },
37
43
  "devDependencies": {
44
+ "@biomejs/biome": "^1.9.4",
38
45
  "@types/node": "^25.5.2",
39
46
  "tsup": "^8.4.0",
40
47
  "typescript": "^5.8.3",
@@ -48,11 +55,19 @@
48
55
  "model-context-protocol",
49
56
  "compliance",
50
57
  "testing",
51
- "cli"
58
+ "cli",
59
+ "mcp-server",
60
+ "spec",
61
+ "validation",
62
+ "json-rpc",
63
+ "ai"
52
64
  ],
53
65
  "repository": {
54
66
  "type": "git",
55
- "url": "git+https://github.com/yawlabs/mcp-compliance.git"
67
+ "url": "git+https://github.com/YawLabs/mcp-compliance.git"
68
+ },
69
+ "bugs": {
70
+ "url": "https://github.com/YawLabs/mcp-compliance/issues"
56
71
  },
57
72
  "homepage": "https://mcp.hosting"
58
73
  }