@yawlabs/mcp-compliance 0.14.3 → 0.14.4
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 +1 -1
- package/dist/{chunk-6PF56RRO.js → chunk-2CXRMEZ3.js} +26 -10
- package/dist/index.js +26 -10
- package/dist/mcp/server.js +1 -1
- package/dist/runner.js +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
Built and maintained by [Yaw Labs](https://yaw.sh).
|
|
11
11
|
|
|
12
|
-
[](yaw
|
|
12
|
+
[](https://yaw.sh/mcp/install?name=mcp-compliance&command=npx&args=-y%2C%40yawlabs%2Fmcp-compliance&description=Test%20any%20MCP%20server%20against%20the%20spec%20-%2088-test%20suite%20with%20letter-grade%20scoring&source=https%3A%2F%2Fgithub.com%2FYawLabs%2Fmcp-compliance)
|
|
13
13
|
|
|
14
14
|
One click adds this to your local Yaw MCP config so it's available in every Yaw Terminal session. Or install manually below.
|
|
15
15
|
|
|
@@ -127,10 +127,17 @@ function createHttpTransport(opts) {
|
|
|
127
127
|
}
|
|
128
128
|
return out;
|
|
129
129
|
}
|
|
130
|
-
async function doRawRequest(method, body, extraHeaders, timeout) {
|
|
130
|
+
async function doRawRequest(method, body, extraHeaders, timeout, omitUserHeaders) {
|
|
131
|
+
const base = sessionHeaders();
|
|
132
|
+
if (omitUserHeaders && omitUserHeaders.length > 0) {
|
|
133
|
+
const drop = new Set(omitUserHeaders.map((h) => h.toLowerCase()));
|
|
134
|
+
for (const key of Object.keys(base)) {
|
|
135
|
+
if (drop.has(key.toLowerCase())) delete base[key];
|
|
136
|
+
}
|
|
137
|
+
}
|
|
131
138
|
const headers = {
|
|
132
139
|
Accept: "application/json, text/event-stream",
|
|
133
|
-
...
|
|
140
|
+
...base,
|
|
134
141
|
...extraHeaders
|
|
135
142
|
};
|
|
136
143
|
if (body !== void 0 && !("Content-Type" in headers) && !("content-type" in headers)) {
|
|
@@ -155,7 +162,7 @@ function createHttpTransport(opts) {
|
|
|
155
162
|
async request(method, params, nextId, init) {
|
|
156
163
|
const id = nextId();
|
|
157
164
|
const body = JSON.stringify({ jsonrpc: "2.0", id, method, params: params ?? {} });
|
|
158
|
-
const raw = await doRawRequest("POST", body, init.headers ?? {}, init.timeout);
|
|
165
|
+
const raw = await doRawRequest("POST", body, init.headers ?? {}, init.timeout, init.omitUserHeaders);
|
|
159
166
|
const contentType = (raw.headers["content-type"] || "").toLowerCase();
|
|
160
167
|
let parsed;
|
|
161
168
|
if (contentType.includes("text/event-stream")) {
|
|
@@ -185,7 +192,7 @@ function createHttpTransport(opts) {
|
|
|
185
192
|
},
|
|
186
193
|
async notify(method, params, init) {
|
|
187
194
|
const body = JSON.stringify({ jsonrpc: "2.0", method, ...params ? { params } : {} });
|
|
188
|
-
const raw = await doRawRequest("POST", body, init.headers ?? {}, init.timeout);
|
|
195
|
+
const raw = await doRawRequest("POST", body, init.headers ?? {}, init.timeout, init.omitUserHeaders);
|
|
189
196
|
return { statusCode: raw.statusCode, headers: raw.headers };
|
|
190
197
|
},
|
|
191
198
|
async close() {
|
|
@@ -1451,10 +1458,11 @@ async function runComplianceSuite(target, options = {}) {
|
|
|
1451
1458
|
const retries = options.retries || 0;
|
|
1452
1459
|
let sessionId = null;
|
|
1453
1460
|
let negotiatedProtocolVersion = null;
|
|
1454
|
-
async function mcpRequest(_backendUrl, method, params, idCounter, extraHeaders, timeoutMs) {
|
|
1461
|
+
async function mcpRequest(_backendUrl, method, params, idCounter, extraHeaders, timeoutMs, omitUserHeaders) {
|
|
1455
1462
|
const res = await transport.request(method, params, idCounter, {
|
|
1456
1463
|
timeout: timeoutMs,
|
|
1457
|
-
headers: extraHeaders
|
|
1464
|
+
headers: extraHeaders,
|
|
1465
|
+
omitUserHeaders
|
|
1458
1466
|
});
|
|
1459
1467
|
return {
|
|
1460
1468
|
statusCode: res.statusCode ?? 200,
|
|
@@ -3168,7 +3176,9 @@ async function runComplianceSuite(target, options = {}) {
|
|
|
3168
3176
|
const noAuthHeaders = {};
|
|
3169
3177
|
if (sessionId) noAuthHeaders["mcp-session-id"] = sessionId;
|
|
3170
3178
|
try {
|
|
3171
|
-
const res = await mcpRequest(backendUrl, "ping", void 0, nextId, noAuthHeaders, timeout
|
|
3179
|
+
const res = await mcpRequest(backendUrl, "ping", void 0, nextId, noAuthHeaders, timeout, [
|
|
3180
|
+
"authorization"
|
|
3181
|
+
]);
|
|
3172
3182
|
if (res.statusCode === 401 || res.statusCode === 403) {
|
|
3173
3183
|
return { passed: true, details: `HTTP ${res.statusCode} (unauthenticated request rejected)` };
|
|
3174
3184
|
}
|
|
@@ -3191,7 +3201,9 @@ async function runComplianceSuite(target, options = {}) {
|
|
|
3191
3201
|
const noAuthHeaders = {};
|
|
3192
3202
|
if (sessionId) noAuthHeaders["mcp-session-id"] = sessionId;
|
|
3193
3203
|
try {
|
|
3194
|
-
const res = await mcpRequest(backendUrl, "ping", void 0, nextId, noAuthHeaders, timeout
|
|
3204
|
+
const res = await mcpRequest(backendUrl, "ping", void 0, nextId, noAuthHeaders, timeout, [
|
|
3205
|
+
"authorization"
|
|
3206
|
+
]);
|
|
3195
3207
|
if (res.statusCode === 401) {
|
|
3196
3208
|
const wwwAuth = res.headers["www-authenticate"];
|
|
3197
3209
|
if (wwwAuth) {
|
|
@@ -3226,7 +3238,9 @@ async function runComplianceSuite(target, options = {}) {
|
|
|
3226
3238
|
};
|
|
3227
3239
|
if (sessionId) malformedHeaders["mcp-session-id"] = sessionId;
|
|
3228
3240
|
try {
|
|
3229
|
-
const res = await mcpRequest(backendUrl, "ping", void 0, nextId, malformedHeaders, timeout
|
|
3241
|
+
const res = await mcpRequest(backendUrl, "ping", void 0, nextId, malformedHeaders, timeout, [
|
|
3242
|
+
"authorization"
|
|
3243
|
+
]);
|
|
3230
3244
|
if (res.statusCode === 401 || res.statusCode === 403) {
|
|
3231
3245
|
return { passed: true, details: `HTTP ${res.statusCode} (malformed auth rejected)` };
|
|
3232
3246
|
}
|
|
@@ -3316,7 +3330,9 @@ async function runComplianceSuite(target, options = {}) {
|
|
|
3316
3330
|
"mcp-session-id": sessionId
|
|
3317
3331
|
};
|
|
3318
3332
|
try {
|
|
3319
|
-
const res = await mcpRequest(backendUrl, "ping", void 0, nextId, sessionOnlyHeaders, timeout
|
|
3333
|
+
const res = await mcpRequest(backendUrl, "ping", void 0, nextId, sessionOnlyHeaders, timeout, [
|
|
3334
|
+
"authorization"
|
|
3335
|
+
]);
|
|
3320
3336
|
if (res.statusCode === 401 || res.statusCode === 403) {
|
|
3321
3337
|
return { passed: true, details: `HTTP ${res.statusCode} (session ID alone not sufficient for auth)` };
|
|
3322
3338
|
}
|
package/dist/index.js
CHANGED
|
@@ -117,10 +117,17 @@ function createHttpTransport(opts) {
|
|
|
117
117
|
}
|
|
118
118
|
return out;
|
|
119
119
|
}
|
|
120
|
-
async function doRawRequest(method, body, extraHeaders, timeout) {
|
|
120
|
+
async function doRawRequest(method, body, extraHeaders, timeout, omitUserHeaders) {
|
|
121
|
+
const base = sessionHeaders();
|
|
122
|
+
if (omitUserHeaders && omitUserHeaders.length > 0) {
|
|
123
|
+
const drop = new Set(omitUserHeaders.map((h) => h.toLowerCase()));
|
|
124
|
+
for (const key of Object.keys(base)) {
|
|
125
|
+
if (drop.has(key.toLowerCase())) delete base[key];
|
|
126
|
+
}
|
|
127
|
+
}
|
|
121
128
|
const headers = {
|
|
122
129
|
Accept: "application/json, text/event-stream",
|
|
123
|
-
...
|
|
130
|
+
...base,
|
|
124
131
|
...extraHeaders
|
|
125
132
|
};
|
|
126
133
|
if (body !== void 0 && !("Content-Type" in headers) && !("content-type" in headers)) {
|
|
@@ -145,7 +152,7 @@ function createHttpTransport(opts) {
|
|
|
145
152
|
async request(method, params, nextId, init) {
|
|
146
153
|
const id = nextId();
|
|
147
154
|
const body = JSON.stringify({ jsonrpc: "2.0", id, method, params: params ?? {} });
|
|
148
|
-
const raw = await doRawRequest("POST", body, init.headers ?? {}, init.timeout);
|
|
155
|
+
const raw = await doRawRequest("POST", body, init.headers ?? {}, init.timeout, init.omitUserHeaders);
|
|
149
156
|
const contentType = (raw.headers["content-type"] || "").toLowerCase();
|
|
150
157
|
let parsed;
|
|
151
158
|
if (contentType.includes("text/event-stream")) {
|
|
@@ -175,7 +182,7 @@ function createHttpTransport(opts) {
|
|
|
175
182
|
},
|
|
176
183
|
async notify(method, params, init) {
|
|
177
184
|
const body = JSON.stringify({ jsonrpc: "2.0", method, ...params ? { params } : {} });
|
|
178
|
-
const raw = await doRawRequest("POST", body, init.headers ?? {}, init.timeout);
|
|
185
|
+
const raw = await doRawRequest("POST", body, init.headers ?? {}, init.timeout, init.omitUserHeaders);
|
|
179
186
|
return { statusCode: raw.statusCode, headers: raw.headers };
|
|
180
187
|
},
|
|
181
188
|
async close() {
|
|
@@ -1808,10 +1815,11 @@ async function runComplianceSuite(target, options = {}) {
|
|
|
1808
1815
|
const retries = options.retries || 0;
|
|
1809
1816
|
let sessionId = null;
|
|
1810
1817
|
let negotiatedProtocolVersion = null;
|
|
1811
|
-
async function mcpRequest(_backendUrl, method, params, idCounter, extraHeaders, timeoutMs) {
|
|
1818
|
+
async function mcpRequest(_backendUrl, method, params, idCounter, extraHeaders, timeoutMs, omitUserHeaders) {
|
|
1812
1819
|
const res = await transport.request(method, params, idCounter, {
|
|
1813
1820
|
timeout: timeoutMs,
|
|
1814
|
-
headers: extraHeaders
|
|
1821
|
+
headers: extraHeaders,
|
|
1822
|
+
omitUserHeaders
|
|
1815
1823
|
});
|
|
1816
1824
|
return {
|
|
1817
1825
|
statusCode: res.statusCode ?? 200,
|
|
@@ -3525,7 +3533,9 @@ async function runComplianceSuite(target, options = {}) {
|
|
|
3525
3533
|
const noAuthHeaders = {};
|
|
3526
3534
|
if (sessionId) noAuthHeaders["mcp-session-id"] = sessionId;
|
|
3527
3535
|
try {
|
|
3528
|
-
const res = await mcpRequest(backendUrl, "ping", void 0, nextId, noAuthHeaders, timeout
|
|
3536
|
+
const res = await mcpRequest(backendUrl, "ping", void 0, nextId, noAuthHeaders, timeout, [
|
|
3537
|
+
"authorization"
|
|
3538
|
+
]);
|
|
3529
3539
|
if (res.statusCode === 401 || res.statusCode === 403) {
|
|
3530
3540
|
return { passed: true, details: `HTTP ${res.statusCode} (unauthenticated request rejected)` };
|
|
3531
3541
|
}
|
|
@@ -3548,7 +3558,9 @@ async function runComplianceSuite(target, options = {}) {
|
|
|
3548
3558
|
const noAuthHeaders = {};
|
|
3549
3559
|
if (sessionId) noAuthHeaders["mcp-session-id"] = sessionId;
|
|
3550
3560
|
try {
|
|
3551
|
-
const res = await mcpRequest(backendUrl, "ping", void 0, nextId, noAuthHeaders, timeout
|
|
3561
|
+
const res = await mcpRequest(backendUrl, "ping", void 0, nextId, noAuthHeaders, timeout, [
|
|
3562
|
+
"authorization"
|
|
3563
|
+
]);
|
|
3552
3564
|
if (res.statusCode === 401) {
|
|
3553
3565
|
const wwwAuth = res.headers["www-authenticate"];
|
|
3554
3566
|
if (wwwAuth) {
|
|
@@ -3583,7 +3595,9 @@ async function runComplianceSuite(target, options = {}) {
|
|
|
3583
3595
|
};
|
|
3584
3596
|
if (sessionId) malformedHeaders["mcp-session-id"] = sessionId;
|
|
3585
3597
|
try {
|
|
3586
|
-
const res = await mcpRequest(backendUrl, "ping", void 0, nextId, malformedHeaders, timeout
|
|
3598
|
+
const res = await mcpRequest(backendUrl, "ping", void 0, nextId, malformedHeaders, timeout, [
|
|
3599
|
+
"authorization"
|
|
3600
|
+
]);
|
|
3587
3601
|
if (res.statusCode === 401 || res.statusCode === 403) {
|
|
3588
3602
|
return { passed: true, details: `HTTP ${res.statusCode} (malformed auth rejected)` };
|
|
3589
3603
|
}
|
|
@@ -3673,7 +3687,9 @@ async function runComplianceSuite(target, options = {}) {
|
|
|
3673
3687
|
"mcp-session-id": sessionId
|
|
3674
3688
|
};
|
|
3675
3689
|
try {
|
|
3676
|
-
const res = await mcpRequest(backendUrl, "ping", void 0, nextId, sessionOnlyHeaders, timeout
|
|
3690
|
+
const res = await mcpRequest(backendUrl, "ping", void 0, nextId, sessionOnlyHeaders, timeout, [
|
|
3691
|
+
"authorization"
|
|
3692
|
+
]);
|
|
3677
3693
|
if (res.statusCode === 401 || res.statusCode === 403) {
|
|
3678
3694
|
return { passed: true, details: `HTTP ${res.statusCode} (session ID alone not sufficient for auth)` };
|
|
3679
3695
|
}
|
package/dist/mcp/server.js
CHANGED
package/dist/runner.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yawlabs/mcp-compliance",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.4",
|
|
4
4
|
"mcpName": "io.github.YawLabs/mcp-compliance",
|
|
5
5
|
"description": "CLI tool and MCP server that tests MCP servers for spec compliance",
|
|
6
6
|
"license": "MIT",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"main": "./dist/runner.js",
|
|
21
21
|
"types": "./dist/runner.d.ts",
|
|
22
22
|
"bin": {
|
|
23
|
-
"mcp-compliance": "
|
|
23
|
+
"mcp-compliance": "dist/index.js"
|
|
24
24
|
},
|
|
25
25
|
"files": [
|
|
26
26
|
"dist",
|