@yawlabs/mcp-compliance 0.2.0 → 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/dist/index.js CHANGED
@@ -1095,7 +1095,125 @@ function formatJson(report) {
1095
1095
  // src/index.ts
1096
1096
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
1097
1097
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
1098
+
1099
+ // src/mcp/tools.ts
1098
1100
  import { z } from "zod";
1101
+ function registerTools(server) {
1102
+ server.tool(
1103
+ "mcp_compliance_test",
1104
+ "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.",
1105
+ {
1106
+ url: z.string().url().describe("The MCP server URL to test (must be HTTP or HTTPS)")
1107
+ },
1108
+ async ({ url }) => {
1109
+ try {
1110
+ const report = await runComplianceSuite(url);
1111
+ const summary = [
1112
+ `Grade: ${report.grade} (${report.score}%)`,
1113
+ `Overall: ${report.overall}`,
1114
+ `Tests: ${report.summary.passed}/${report.summary.total} passed (${report.summary.requiredPassed}/${report.summary.required} required)`,
1115
+ "",
1116
+ ...report.tests.map(
1117
+ (t) => `${t.passed ? "PASS" : "FAIL"} ${t.name}${t.required ? " (required)" : ""} \u2014 ${t.details}`
1118
+ )
1119
+ ];
1120
+ if (report.serverInfo.name) {
1121
+ summary.unshift(`Server: ${report.serverInfo.name} v${report.serverInfo.version || "?"}`);
1122
+ }
1123
+ if (report.warnings.length > 0) {
1124
+ summary.push("", `Warnings (${report.warnings.length}):`);
1125
+ for (const w of report.warnings) {
1126
+ summary.push(` - ${w}`);
1127
+ }
1128
+ }
1129
+ return {
1130
+ content: [
1131
+ { type: "text", text: summary.join("\n") },
1132
+ { type: "text", text: `
1133
+
1134
+ Full report:
1135
+ ${JSON.stringify(report, null, 2)}` }
1136
+ ]
1137
+ };
1138
+ } catch (err) {
1139
+ return {
1140
+ content: [{ type: "text", text: `Error running compliance test: ${err.message}` }],
1141
+ isError: true
1142
+ };
1143
+ }
1144
+ }
1145
+ );
1146
+ server.tool(
1147
+ "mcp_compliance_badge",
1148
+ "Get the badge markdown embed code for an MCP server. Runs the compliance test suite first to determine the grade.",
1149
+ {
1150
+ url: z.string().url().describe("The MCP server URL to test")
1151
+ },
1152
+ async ({ url }) => {
1153
+ try {
1154
+ const report = await runComplianceSuite(url);
1155
+ const badge = report.badge;
1156
+ return {
1157
+ content: [{
1158
+ type: "text",
1159
+ text: [
1160
+ `Grade: ${report.grade} (${report.score}%)`,
1161
+ "",
1162
+ "Markdown:",
1163
+ badge.markdown,
1164
+ "",
1165
+ "HTML:",
1166
+ badge.html
1167
+ ].join("\n")
1168
+ }]
1169
+ };
1170
+ } catch (err) {
1171
+ return {
1172
+ content: [{ type: "text", text: `Error: ${err.message}` }],
1173
+ isError: true
1174
+ };
1175
+ }
1176
+ }
1177
+ );
1178
+ server.tool(
1179
+ "mcp_compliance_explain",
1180
+ "Explain what a specific compliance test ID checks and why it matters.",
1181
+ {
1182
+ testId: z.string().describe('The test ID to explain (e.g., "transport-post", "lifecycle-init", "tools-schema")')
1183
+ },
1184
+ async ({ testId }) => {
1185
+ const def = TEST_DEFINITIONS.find((t) => t.id === testId);
1186
+ if (!def) {
1187
+ return {
1188
+ content: [{
1189
+ type: "text",
1190
+ text: `Unknown test ID: "${testId}"
1191
+
1192
+ Valid test IDs:
1193
+ ${TEST_DEFINITIONS.map((t) => t.id).join(", ")}`
1194
+ }],
1195
+ isError: true
1196
+ };
1197
+ }
1198
+ return {
1199
+ content: [{
1200
+ type: "text",
1201
+ text: [
1202
+ `Test: ${def.id}`,
1203
+ `Name: ${def.name}`,
1204
+ `Category: ${def.category}`,
1205
+ `Required: ${def.required ? "Yes" : "No"}`,
1206
+ `Spec reference: https://modelcontextprotocol.io/specification/2025-11-25/${def.specRef}`,
1207
+ "",
1208
+ def.description
1209
+ ].join("\n")
1210
+ }]
1211
+ };
1212
+ }
1213
+ );
1214
+ }
1215
+
1216
+ // src/index.ts
1099
1217
  var require2 = createRequire2(import.meta.url);
1100
1218
  var { version } = require2("../package.json");
1101
1219
  function parseHeaderArg(value, prev) {
@@ -1179,85 +1297,7 @@ Error: ${err.message}
1179
1297
  });
1180
1298
  program.command("mcp").description("Start the MCP compliance server (stdio transport)").action(async () => {
1181
1299
  const server = new McpServer({ name: "mcp-compliance", version });
1182
- server.tool(
1183
- "mcp_compliance_test",
1184
- "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.",
1185
- { url: z.string().url().describe("The MCP server URL to test (must be HTTP or HTTPS)") },
1186
- async ({ url }) => {
1187
- try {
1188
- const report = await runComplianceSuite(url);
1189
- const summary = [
1190
- `Grade: ${report.grade} (${report.score}%)`,
1191
- `Overall: ${report.overall}`,
1192
- `Tests: ${report.summary.passed}/${report.summary.total} passed (${report.summary.requiredPassed}/${report.summary.required} required)`,
1193
- "",
1194
- ...report.tests.map(
1195
- (t) => `${t.passed ? "PASS" : "FAIL"} ${t.name}${t.required ? " (required)" : ""} \u2014 ${t.details}`
1196
- )
1197
- ];
1198
- if (report.serverInfo.name) {
1199
- summary.unshift(`Server: ${report.serverInfo.name} v${report.serverInfo.version || "?"}`);
1200
- }
1201
- if (report.warnings.length > 0) {
1202
- summary.push("", `Warnings (${report.warnings.length}):`);
1203
- for (const w of report.warnings) summary.push(` - ${w}`);
1204
- }
1205
- return {
1206
- content: [
1207
- { type: "text", text: summary.join("\n") },
1208
- { type: "text", text: `
1209
-
1210
- Full report:
1211
- ${JSON.stringify(report, null, 2)}` }
1212
- ]
1213
- };
1214
- } catch (err) {
1215
- return { content: [{ type: "text", text: `Error running compliance test: ${err.message}` }], isError: true };
1216
- }
1217
- }
1218
- );
1219
- server.tool(
1220
- "mcp_compliance_badge",
1221
- "Get the badge markdown embed code for an MCP server. Runs the compliance test suite first to determine the grade.",
1222
- { url: z.string().url().describe("The MCP server URL to test") },
1223
- async ({ url }) => {
1224
- try {
1225
- const report = await runComplianceSuite(url);
1226
- const badge = report.badge;
1227
- return {
1228
- content: [{
1229
- type: "text",
1230
- text: [`Grade: ${report.grade} (${report.score}%)`, "", "Markdown:", badge.markdown, "", "HTML:", badge.html].join("\n")
1231
- }]
1232
- };
1233
- } catch (err) {
1234
- return { content: [{ type: "text", text: `Error: ${err.message}` }], isError: true };
1235
- }
1236
- }
1237
- );
1238
- server.tool(
1239
- "mcp_compliance_explain",
1240
- "Explain what a specific compliance test ID checks and why it matters.",
1241
- { testId: z.string().describe('The test ID to explain (e.g., "transport-post", "lifecycle-init", "tools-schema")') },
1242
- async ({ testId }) => {
1243
- const def = TEST_DEFINITIONS.find((t) => t.id === testId);
1244
- if (!def) {
1245
- return {
1246
- content: [{ type: "text", text: `Unknown test ID: "${testId}"
1247
-
1248
- Valid test IDs:
1249
- ${TEST_DEFINITIONS.map((t) => t.id).join(", ")}` }],
1250
- isError: true
1251
- };
1252
- }
1253
- return {
1254
- content: [{
1255
- type: "text",
1256
- text: [`Test: ${def.id}`, `Name: ${def.name}`, `Category: ${def.category}`, `Required: ${def.required ? "Yes" : "No"}`, `Spec reference: https://modelcontextprotocol.io/specification/2025-11-25/${def.specRef}`, "", def.description].join("\n")
1257
- }]
1258
- };
1259
- }
1260
- );
1300
+ registerTools(server);
1261
1301
  const transport = new StdioServerTransport();
1262
1302
  await server.connect(transport);
1263
1303
  });
@@ -6,127 +6,130 @@ import {
6
6
  // src/mcp/server.ts
7
7
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
8
8
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
9
- import { z } from "zod";
10
9
  import { createRequire } from "module";
11
- var require2 = createRequire(import.meta.url);
12
- var { version } = require2("../../package.json");
13
- var server = new McpServer({
14
- name: "mcp-compliance",
15
- version
16
- });
17
- server.tool(
18
- "mcp_compliance_test",
19
- "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.",
20
- {
21
- url: z.string().url().describe("The MCP server URL to test (must be HTTP or HTTPS)")
22
- },
23
- async ({ url }) => {
24
- try {
25
- const report = await runComplianceSuite(url);
26
- const summary = [
27
- `Grade: ${report.grade} (${report.score}%)`,
28
- `Overall: ${report.overall}`,
29
- `Tests: ${report.summary.passed}/${report.summary.total} passed (${report.summary.requiredPassed}/${report.summary.required} required)`,
30
- "",
31
- ...report.tests.map(
32
- (t) => `${t.passed ? "PASS" : "FAIL"} ${t.name}${t.required ? " (required)" : ""} \u2014 ${t.details}`
33
- )
34
- ];
35
- if (report.serverInfo.name) {
36
- summary.unshift(`Server: ${report.serverInfo.name} v${report.serverInfo.version || "?"}`);
37
- }
38
- if (report.warnings.length > 0) {
39
- summary.push("", `Warnings (${report.warnings.length}):`);
40
- for (const w of report.warnings) {
41
- summary.push(` - ${w}`);
10
+
11
+ // src/mcp/tools.ts
12
+ import { z } from "zod";
13
+ function registerTools(server2) {
14
+ server2.tool(
15
+ "mcp_compliance_test",
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
+ {
18
+ url: z.string().url().describe("The MCP server URL to test (must be HTTP or HTTPS)")
19
+ },
20
+ async ({ url }) => {
21
+ try {
22
+ const report = await runComplianceSuite(url);
23
+ const summary = [
24
+ `Grade: ${report.grade} (${report.score}%)`,
25
+ `Overall: ${report.overall}`,
26
+ `Tests: ${report.summary.passed}/${report.summary.total} passed (${report.summary.requiredPassed}/${report.summary.required} required)`,
27
+ "",
28
+ ...report.tests.map(
29
+ (t) => `${t.passed ? "PASS" : "FAIL"} ${t.name}${t.required ? " (required)" : ""} \u2014 ${t.details}`
30
+ )
31
+ ];
32
+ if (report.serverInfo.name) {
33
+ summary.unshift(`Server: ${report.serverInfo.name} v${report.serverInfo.version || "?"}`);
42
34
  }
43
- }
44
- return {
45
- content: [
46
- { type: "text", text: summary.join("\n") },
47
- { type: "text", text: `
35
+ if (report.warnings.length > 0) {
36
+ summary.push("", `Warnings (${report.warnings.length}):`);
37
+ for (const w of report.warnings) {
38
+ summary.push(` - ${w}`);
39
+ }
40
+ }
41
+ return {
42
+ content: [
43
+ { type: "text", text: summary.join("\n") },
44
+ { type: "text", text: `
48
45
 
49
46
  Full report:
50
47
  ${JSON.stringify(report, null, 2)}` }
51
- ]
52
- };
53
- } catch (err) {
54
- return {
55
- content: [{ type: "text", text: `Error running compliance test: ${err.message}` }],
56
- isError: true
57
- };
48
+ ]
49
+ };
50
+ } catch (err) {
51
+ return {
52
+ content: [{ type: "text", text: `Error running compliance test: ${err.message}` }],
53
+ isError: true
54
+ };
55
+ }
56
+ }
57
+ );
58
+ server2.tool(
59
+ "mcp_compliance_badge",
60
+ "Get the badge markdown embed code for an MCP server. Runs the compliance test suite first to determine the grade.",
61
+ {
62
+ url: z.string().url().describe("The MCP server URL to test")
63
+ },
64
+ async ({ url }) => {
65
+ try {
66
+ const report = await runComplianceSuite(url);
67
+ const badge = report.badge;
68
+ 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
+ }]
81
+ };
82
+ } catch (err) {
83
+ return {
84
+ content: [{ type: "text", text: `Error: ${err.message}` }],
85
+ isError: true
86
+ };
87
+ }
58
88
  }
59
- }
60
- );
61
- server.tool(
62
- "mcp_compliance_badge",
63
- "Get the badge markdown embed code for an MCP server. Runs the compliance test suite first to determine the grade.",
64
- {
65
- url: z.string().url().describe("The MCP server URL to test")
66
- },
67
- async ({ url }) => {
68
- try {
69
- const report = await runComplianceSuite(url);
70
- const badge = report.badge;
89
+ );
90
+ server2.tool(
91
+ "mcp_compliance_explain",
92
+ "Explain what a specific compliance test ID checks and why it matters.",
93
+ {
94
+ testId: z.string().describe('The test ID to explain (e.g., "transport-post", "lifecycle-init", "tools-schema")')
95
+ },
96
+ async ({ testId }) => {
97
+ const def = TEST_DEFINITIONS.find((t) => t.id === testId);
98
+ if (!def) {
99
+ return {
100
+ content: [{
101
+ type: "text",
102
+ text: `Unknown test ID: "${testId}"
103
+
104
+ Valid test IDs:
105
+ ${TEST_DEFINITIONS.map((t) => t.id).join(", ")}`
106
+ }],
107
+ isError: true
108
+ };
109
+ }
71
110
  return {
72
111
  content: [{
73
112
  type: "text",
74
113
  text: [
75
- `Grade: ${report.grade} (${report.score}%)`,
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}`,
76
119
  "",
77
- "Markdown:",
78
- badge.markdown,
79
- "",
80
- "HTML:",
81
- badge.html
120
+ def.description
82
121
  ].join("\n")
83
122
  }]
84
123
  };
85
- } catch (err) {
86
- return {
87
- content: [{ type: "text", text: `Error: ${err.message}` }],
88
- isError: true
89
- };
90
124
  }
91
- }
92
- );
93
- server.tool(
94
- "mcp_compliance_explain",
95
- "Explain what a specific compliance test ID checks and why it matters.",
96
- {
97
- testId: z.string().describe('The test ID to explain (e.g., "transport-post", "lifecycle-init", "tools-schema")')
98
- },
99
- async ({ testId }) => {
100
- const def = TEST_DEFINITIONS.find((t) => t.id === testId);
101
- if (!def) {
102
- const ids = TEST_DEFINITIONS.map((t) => t.id).join(", ");
103
- return {
104
- content: [{
105
- type: "text",
106
- text: `Unknown test ID: "${testId}"
125
+ );
126
+ }
107
127
 
108
- Valid test IDs:
109
- ${ids}`
110
- }],
111
- isError: true
112
- };
113
- }
114
- return {
115
- content: [{
116
- type: "text",
117
- text: [
118
- `Test: ${def.id}`,
119
- `Name: ${def.name}`,
120
- `Category: ${def.category}`,
121
- `Required: ${def.required ? "Yes" : "No"}`,
122
- `Spec reference: https://modelcontextprotocol.io/specification/2025-11-25/${def.specRef}`,
123
- "",
124
- def.description
125
- ].join("\n")
126
- }]
127
- };
128
- }
129
- );
128
+ // src/mcp/server.ts
129
+ var require2 = createRequire(import.meta.url);
130
+ var { version } = require2("../../package.json");
131
+ var server = new McpServer({ name: "mcp-compliance", version });
132
+ registerTools(server);
130
133
  async function main() {
131
134
  const transport = new StdioServerTransport();
132
135
  await server.connect(transport);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yawlabs/mcp-compliance",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "CLI tool and MCP server that tests MCP servers for spec compliance",
5
5
  "license": "MIT",
6
6
  "author": "Yaw Labs (https://yaw.sh)",