From 743bd694baa314d66c56129cbb675690385a263f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 8 Sep 2026 22:53:31 +0000 Subject: [PATCH 1/3] Initial plan From 476260e5ef48c00c2d33f5b2444b556f42d71100 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 8 Sep 2026 23:48:44 +0000 Subject: [PATCH 2/3] test: pin official MCP conformance baseline Co-authored-by: groupthinking <154503486+groupthinking@users.noreply.github.com> --- scripts/testing/official_mcp_conformance.py | 388 ++ .../official-2026-07-28-receipt.json | 3627 +++++++++++++++++ tests/testing/official_mcp_auth_client.mjs | 216 + tests/testing/official_mcp_fixture_server.py | 220 + tests/unit/test_official_mcp_conformance.py | 171 + 5 files changed, 4622 insertions(+) create mode 100644 scripts/testing/official_mcp_conformance.py create mode 100644 tests/fixtures/mcp_conformance/official-2026-07-28-receipt.json create mode 100644 tests/testing/official_mcp_auth_client.mjs create mode 100644 tests/testing/official_mcp_fixture_server.py create mode 100644 tests/unit/test_official_mcp_conformance.py diff --git a/scripts/testing/official_mcp_conformance.py b/scripts/testing/official_mcp_conformance.py new file mode 100644 index 000000000..a1adcb47a --- /dev/null +++ b/scripts/testing/official_mcp_conformance.py @@ -0,0 +1,388 @@ +#!/usr/bin/env python3 +from __future__ import annotations + +import argparse +import json +import socket +import subprocess +import sys +import tempfile +import time +from collections import Counter +from pathlib import Path +from typing import Any + +REPO_ROOT = Path(__file__).resolve().parents[2] +FIXTURE_SERVER = REPO_ROOT / "tests/testing/official_mcp_fixture_server.py" +AUTH_CLIENT = REPO_ROOT / "tests/testing/official_mcp_auth_client.mjs" +DEFAULT_RECEIPT = ( + REPO_ROOT / "tests/fixtures/mcp_conformance/official-2026-07-28-receipt.json" +) +CONFORMANCE_COMMIT = "a983ba93c91e0bb31d0b6849eeb52f0ad1083107" +CONFORMANCE_PACKAGE = ( + f"git+https://github.com/modelcontextprotocol/conformance.git#{CONFORMANCE_COMMIT}" +) +SERVER_SCENARIOS = ( + {"scenario": "tools-list", "spec_version": "2026-07-28", "required": True}, + { + "scenario": "tools-call-simple-text", + "spec_version": "2026-07-28", + "required": True, + }, + {"scenario": "tools-call-error", "spec_version": "2026-07-28", "required": True}, + {"scenario": "server-initialize", "spec_version": "2025-11-25", "required": True}, +) +CLIENT_SCENARIOS = ( + {"scenario": "auth/metadata-var2", "spec_version": "2026-07-28", "required": True}, + { + "scenario": "auth/token-endpoint-auth-basic", + "spec_version": "2026-07-28", + "required": True, + }, + { + "scenario": "auth/token-endpoint-auth-post", + "spec_version": "2026-07-28", + "required": True, + }, + { + "scenario": "auth/token-endpoint-auth-none", + "spec_version": "2026-07-28", + "required": True, + }, +) +EXCLUSIONS = { + "server": [ + { + "reason": "surface-not-implemented", + "scenarios": [ + "server-stateless", + "completion-complete", + "tools-call-image", + "tools-call-audio", + "tools-call-embedded-resource", + "tools-call-mixed-content", + "tools-call-with-progress", + "server-sse-multiple-streams", + "resources-list", + "resources-read-text", + "resources-read-binary", + "resources-templates-read", + "sep-2164-resource-not-found", + "prompts-list", + "prompts-get-simple", + "prompts-get-with-args", + "prompts-get-embedded-resource", + "prompts-get-with-image", + "dns-rebinding-protection", + "caching", + "input-required-result-basic-elicitation", + "input-required-result-basic-sampling", + "input-required-result-basic-list-roots", + "input-required-result-request-state", + "input-required-result-multiple-input-requests", + "input-required-result-multi-round", + "input-required-result-missing-input-response", + "input-required-result-non-tool-request", + "input-required-result-result-type", + "input-required-result-unsupported-methods", + "input-required-result-tampered-state", + "input-required-result-capability-check", + "input-required-result-ignore-extra-params", + "input-required-result-validate-input", + ], + }, + { + "reason": "extension-not-implemented", + "scenarios": [ + "tasks-lifecycle", + "tasks-capability-negotiation", + "tasks-wire-fields", + "tasks-request-state-removal", + "tasks-mrtr-input", + "tasks-request-headers", + "tasks-dispatch-and-envelope", + "tasks-status-notifications", + "tasks-required-task-error", + "tasks-mrtr-composition", + ], + }, + ], + "client": [ + { + "reason": "surface-not-certified-in-this-baseline", + "scenarios": [ + "tools_call", + "request-metadata", + "auth/metadata-default", + "auth/metadata-var1", + "auth/metadata-var3", + "auth/basic-cimd", + "auth/scope-from-www-authenticate", + "auth/scope-from-scopes-supported", + "auth/scope-omitted-when-undefined", + "auth/scope-step-up", + "auth/scope-retry-limit", + "auth/pre-registration", + "auth/resource-mismatch", + "auth/offline-access-scope", + "auth/offline-access-not-supported", + "auth/authorization-server-migration", + "auth/iss-supported", + "auth/iss-not-advertised", + "auth/iss-supported-missing", + "auth/iss-wrong-issuer", + "auth/iss-unexpected", + "auth/iss-normalized", + "auth/metadata-issuer-mismatch", + "sep-2322-client-request-state", + "http-standard-headers", + "http-custom-headers", + "http-invalid-tool-headers", + "json-schema-ref-no-deref", + ], + }, + { + "reason": "extension-not-implemented", + "scenarios": [ + "auth/client-credentials-jwt", + "auth/client-credentials-basic", + "auth/enterprise-managed-authorization", + "auth/dpop", + "auth/dpop-nonce", + "auth/wif-jwt-bearer", + "json-schema-2020-12-preservation", + ], + }, + ], +} + + +def summarize_checks( + checks: list[dict[str, Any]], + *, + required: bool, +) -> dict[str, Any]: + counts = Counter(str(check.get("status", "UNKNOWN")) for check in checks) + blocking = [ + f"{check.get('id', '')}:{check.get('status', 'UNKNOWN')}" + for check in checks + if required and str(check.get("status")) in {"FAILURE", "WARNING"} + ] + return { + "ok": not blocking, + "counts": dict(counts), + "blocking": blocking, + } + + +def _run( + args: list[str], + *, + cwd: Path = REPO_ROOT, +) -> subprocess.CompletedProcess[str]: + return subprocess.run( + args, + cwd=cwd, + text=True, + capture_output=True, + check=False, + ) + + +def _free_port() -> int: + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: + sock.bind(("127.0.0.1", 0)) + return int(sock.getsockname()[1]) + + +def _wait_for_port(port: int, timeout: float = 10.0) -> None: + deadline = time.time() + timeout + while time.time() < deadline: + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: + if sock.connect_ex(("127.0.0.1", port)) == 0: + return + time.sleep(0.05) + raise RuntimeError(f"fixture server did not start on port {port}") + + +def _load_checks(output_dir: Path) -> list[dict[str, Any]]: + candidates = sorted(output_dir.glob("**/checks.json")) + if not candidates: + raise FileNotFoundError(f"no checks.json found under {output_dir}") + return json.loads(candidates[-1].read_text()) + + +def _npx_prefix() -> list[str]: + return [ + "npx", + "--yes", + f"--package={CONFORMANCE_PACKAGE}", + "conformance", + ] + + +def _run_server_scenario(config: dict[str, Any]) -> dict[str, Any]: + port = _free_port() + with tempfile.TemporaryDirectory(prefix="mcp-conformance-server-") as tmpdir: + output_dir = Path(tmpdir) + server = subprocess.Popen( + [sys.executable, str(FIXTURE_SERVER), "--port", str(port)], + cwd=REPO_ROOT, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + ) + try: + _wait_for_port(port) + cmd = _npx_prefix() + [ + "server", + "--url", + f"http://127.0.0.1:{port}/mcp", + "--scenario", + str(config["scenario"]), + "--spec-version", + str(config["spec_version"]), + "-o", + str(output_dir), + ] + result = _run(cmd) + checks = _load_checks(output_dir) + finally: + server.terminate() + server.wait(timeout=5) + + summary = summarize_checks(checks, required=bool(config["required"])) + return { + "leg": "server", + "scenario": config["scenario"], + "spec_version": config["spec_version"], + "required": config["required"], + "exit_code": result.returncode, + "command": cmd, + "stdout": result.stdout, + "stderr": result.stderr, + "checks": checks, + "summary": summary, + } + + +def _run_client_scenario(config: dict[str, Any]) -> dict[str, Any]: + with tempfile.TemporaryDirectory(prefix="mcp-conformance-client-") as tmpdir: + output_dir = Path(tmpdir) + cmd = _npx_prefix() + [ + "client", + "--command", + f"node {AUTH_CLIENT}", + "--scenario", + str(config["scenario"]), + "--spec-version", + str(config["spec_version"]), + "-o", + str(output_dir), + ] + result = _run(cmd) + checks = _load_checks(output_dir) + + summary = summarize_checks(checks, required=bool(config["required"])) + return { + "leg": "client", + "scenario": config["scenario"], + "spec_version": config["spec_version"], + "required": config["required"], + "exit_code": result.returncode, + "command": cmd, + "stdout": result.stdout, + "stderr": result.stderr, + "checks": checks, + "summary": summary, + } + + +def _trimmed(text: str, limit: int = 4000) -> str: + return text if len(text) <= limit else text[:limit] + "\n...[truncated]" + + +def build_receipt(run_records: list[dict[str, Any]]) -> dict[str, Any]: + implementation_commit = _run(["git", "rev-parse", "HEAD"]).stdout.strip() + node_version = _run(["node", "--version"]).stdout.strip() + npm_version = _run(["npm", "--version"]).stdout.strip() + package_json = json.loads((REPO_ROOT / "package.json").read_text()) + + overall_ok = all(record["summary"]["ok"] for record in run_records if record["required"]) + runs = [] + for record in run_records: + runs.append( + { + "leg": record["leg"], + "scenario": record["scenario"], + "spec_version": record["spec_version"], + "required": record["required"], + "exit_code": record["exit_code"], + "summary": record["summary"], + "warnings": [ + check["id"] + for check in record["checks"] + if check.get("status") == "WARNING" + ], + "failures": [ + check["id"] + for check in record["checks"] + if check.get("status") == "FAILURE" + ], + "checks": record["checks"], + "stdout": _trimmed(record["stdout"]), + "stderr": _trimmed(record["stderr"]), + } + ) + + return { + "schema_version": "eventrelay.mcp-conformance-receipt.v1", + "baseline_revision": "2026-07-28", + "generated_at": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()), + "overall_ok": overall_ok, + "conformance": { + "package": CONFORMANCE_PACKAGE, + "commit": CONFORMANCE_COMMIT, + }, + "implementation": { + "commit": implementation_commit, + "sdk_version": package_json["devDependencies"]["@modelcontextprotocol/sdk"], + }, + "versions": { + "python": sys.version.split()[0], + "node": node_version, + "npm": npm_version, + }, + "inventory": { + "certified": { + "server": [entry["scenario"] for entry in SERVER_SCENARIOS], + "client": [entry["scenario"] for entry in CLIENT_SCENARIOS], + }, + "exclusions": EXCLUSIONS, + }, + "runs": runs, + } + + +def run_all() -> dict[str, Any]: + records: list[dict[str, Any]] = [] + for config in SERVER_SCENARIOS: + records.append(_run_server_scenario(dict(config))) + for config in CLIENT_SCENARIOS: + records.append(_run_client_scenario(dict(config))) + return build_receipt(records) + + +def main() -> int: + parser = argparse.ArgumentParser() + parser.add_argument("--receipt", type=Path, default=DEFAULT_RECEIPT) + args = parser.parse_args() + + receipt = run_all() + args.receipt.parent.mkdir(parents=True, exist_ok=True) + args.receipt.write_text(json.dumps(receipt, indent=2) + "\n") + return 0 if receipt["overall_ok"] else 1 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/tests/fixtures/mcp_conformance/official-2026-07-28-receipt.json b/tests/fixtures/mcp_conformance/official-2026-07-28-receipt.json new file mode 100644 index 000000000..7cfa97fc3 --- /dev/null +++ b/tests/fixtures/mcp_conformance/official-2026-07-28-receipt.json @@ -0,0 +1,3627 @@ +{ + "schema_version": "eventrelay.mcp-conformance-receipt.v1", + "baseline_revision": "2026-07-28", + "generated_at": "2026-09-08T23:48:14Z", + "overall_ok": true, + "conformance": { + "package": "git+https://github.com/modelcontextprotocol/conformance.git#a983ba93c91e0bb31d0b6849eeb52f0ad1083107", + "commit": "a983ba93c91e0bb31d0b6849eeb52f0ad1083107" + }, + "implementation": { + "commit": "743bd694baa314d66c56129cbb675690385a263f", + "sdk_version": "^1.30.0" + }, + "versions": { + "python": "3.12.3", + "node": "v24.19.0", + "npm": "11.17.0" + }, + "inventory": { + "certified": { + "server": [ + "tools-list", + "tools-call-simple-text", + "tools-call-error", + "server-initialize" + ], + "client": [ + "auth/metadata-var2", + "auth/token-endpoint-auth-basic", + "auth/token-endpoint-auth-post", + "auth/token-endpoint-auth-none" + ] + }, + "exclusions": { + "server": [ + { + "reason": "surface-not-implemented", + "scenarios": [ + "server-stateless", + "completion-complete", + "tools-call-image", + "tools-call-audio", + "tools-call-embedded-resource", + "tools-call-mixed-content", + "tools-call-with-progress", + "server-sse-multiple-streams", + "resources-list", + "resources-read-text", + "resources-read-binary", + "resources-templates-read", + "sep-2164-resource-not-found", + "prompts-list", + "prompts-get-simple", + "prompts-get-with-args", + "prompts-get-embedded-resource", + "prompts-get-with-image", + "dns-rebinding-protection", + "caching", + "input-required-result-basic-elicitation", + "input-required-result-basic-sampling", + "input-required-result-basic-list-roots", + "input-required-result-request-state", + "input-required-result-multiple-input-requests", + "input-required-result-multi-round", + "input-required-result-missing-input-response", + "input-required-result-non-tool-request", + "input-required-result-result-type", + "input-required-result-unsupported-methods", + "input-required-result-tampered-state", + "input-required-result-capability-check", + "input-required-result-ignore-extra-params", + "input-required-result-validate-input" + ] + }, + { + "reason": "extension-not-implemented", + "scenarios": [ + "tasks-lifecycle", + "tasks-capability-negotiation", + "tasks-wire-fields", + "tasks-request-state-removal", + "tasks-mrtr-input", + "tasks-request-headers", + "tasks-dispatch-and-envelope", + "tasks-status-notifications", + "tasks-required-task-error", + "tasks-mrtr-composition" + ] + } + ], + "client": [ + { + "reason": "surface-not-certified-in-this-baseline", + "scenarios": [ + "tools_call", + "request-metadata", + "auth/metadata-default", + "auth/metadata-var1", + "auth/metadata-var3", + "auth/basic-cimd", + "auth/scope-from-www-authenticate", + "auth/scope-from-scopes-supported", + "auth/scope-omitted-when-undefined", + "auth/scope-step-up", + "auth/scope-retry-limit", + "auth/pre-registration", + "auth/resource-mismatch", + "auth/offline-access-scope", + "auth/offline-access-not-supported", + "auth/authorization-server-migration", + "auth/iss-supported", + "auth/iss-not-advertised", + "auth/iss-supported-missing", + "auth/iss-wrong-issuer", + "auth/iss-unexpected", + "auth/iss-normalized", + "auth/metadata-issuer-mismatch", + "sep-2322-client-request-state", + "http-standard-headers", + "http-custom-headers", + "http-invalid-tool-headers", + "json-schema-ref-no-deref" + ] + }, + { + "reason": "extension-not-implemented", + "scenarios": [ + "auth/client-credentials-jwt", + "auth/client-credentials-basic", + "auth/enterprise-managed-authorization", + "auth/dpop", + "auth/dpop-nonce", + "auth/wif-jwt-bearer", + "json-schema-2020-12-preservation" + ] + } + ] + } + }, + "runs": [ + { + "leg": "server", + "scenario": "tools-list", + "spec_version": "2026-07-28", + "required": true, + "exit_code": 0, + "summary": { + "ok": true, + "counts": { + "SUCCESS": 4 + }, + "blocking": [] + }, + "warnings": [], + "failures": [], + "checks": [ + { + "id": "tools-list", + "name": "ToolsList", + "description": "Server lists available tools with valid structure", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:47:26.913Z", + "specReferences": [ + { + "id": "MCP-Tools-List", + "url": "https://modelcontextprotocol.io/specification/2025-06-18/server/tools#listing-tools" + } + ], + "details": { + "toolCount": 2, + "tools": [ + "test_simple_text", + "test_error_handling" + ] + } + }, + { + "id": "tools-name-format", + "name": "ToolsNameFormat", + "description": "Tool names SHOULD be 1-128 characters and match ^[A-Za-z0-9_.-]+$", + "specReferences": [ + { + "id": "MCP-Tool-Names", + "url": "https://modelcontextprotocol.io/specification/2025-11-25/server/tools#tool-names" + }, + { + "id": "MCP-Tool-Names-Draft", + "url": "https://modelcontextprotocol.io/specification/draft/server/tools#tool-names" + }, + { + "id": "SEP-986-History", + "url": "https://github.com/modelcontextprotocol/modelcontextprotocol/issues/986" + }, + { + "id": "SEP-986-Spec-Integration", + "url": "https://github.com/modelcontextprotocol/modelcontextprotocol/pull/1603" + } + ], + "timestamp": "2026-09-08T23:47:26.913Z", + "status": "SUCCESS", + "details": { + "toolCount": 2, + "results": { + "test_simple_text": "valid", + "test_error_handling": "valid" + } + } + }, + { + "id": "tools-list-deterministic-order", + "name": "ToolsListDeterministicOrder", + "description": "Consecutive tools/list requests return the same tools in the same order", + "specReferences": [ + { + "id": "MCP-Tools-Deterministic-Order", + "url": "https://modelcontextprotocol.io/specification/2026-07-28/server/tools#capabilities" + } + ], + "source": { + "introducedIn": "2026-07-28" + }, + "timestamp": "2026-09-08T23:47:26.961Z", + "status": "SUCCESS", + "details": { + "toolCount": 2, + "probes": 3, + "orders": [ + [ + "test_simple_text", + "test_error_handling" + ], + [ + "test_simple_text", + "test_error_handling" + ], + [ + "test_simple_text", + "test_error_handling" + ] + ] + } + }, + { + "id": "wire-schema-valid", + "name": "WireSchemaValid", + "description": "Every JSON-RPC message the implementation sent is valid per the spec JSON schema for the negotiated spec version", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:47:26.962Z", + "specReferences": [ + { + "id": "MCP-Schema", + "url": "https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/schema/draft/schema.json" + } + ], + "details": { + "messagesValidated": 6, + "violations": [] + } + } + ], + "stdout": "Running client scenario 'tools-list' against server: http://127.0.0.1:59343/mcp\nResults saved to /tmp/mcp-conformance-server-_xtkakss/server-tools-list-2026-09-08T23-47-26-809Z\nChecks:\n\u001b[90m2026-09-08T23:47:26.913Z\u001b[0m [tools-list ] \u001b[32mSUCCESS\u001b[0m Server lists available tools with valid structure\n\u001b[90m2026-09-08T23:47:26.913Z\u001b[0m [tools-name-format ] \u001b[32mSUCCESS\u001b[0m Tool names SHOULD be 1-128 characters and match ^[A-Za-z0-9_.-]+$\n\u001b[90m2026-09-08T23:47:26.961Z\u001b[0m [tools-list-deterministic-order] \u001b[32mSUCCESS\u001b[0m Consecutive tools/list requests return the same tools in the same order\n\u001b[90m2026-09-08T23:47:26.962Z\u001b[0m [wire-schema-valid ] \u001b[32mSUCCESS\u001b[0m Every JSON-RPC message the implementation sent is valid per the spec JSON schema for the negotiated spec version\n\nTest Results:\nPassed: 4/4, 0 failed, 0 warnings\n", + "stderr": "" + }, + { + "leg": "server", + "scenario": "tools-call-simple-text", + "spec_version": "2026-07-28", + "required": true, + "exit_code": 0, + "summary": { + "ok": true, + "counts": { + "SUCCESS": 2 + }, + "blocking": [] + }, + "warnings": [], + "failures": [], + "checks": [ + { + "id": "tools-call-simple-text", + "name": "ToolsCallSimpleText", + "description": "Tool returns simple text content", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:47:33.826Z", + "specReferences": [ + { + "id": "MCP-Tools-Call", + "url": "https://modelcontextprotocol.io/specification/2025-06-18/server/tools#calling-tools" + } + ], + "details": { + "result": { + "resultType": "complete", + "ttlMs": 0, + "cacheScope": "private", + "content": [ + { + "type": "text", + "text": "This is a simple text response for testing." + } + ] + } + } + }, + { + "id": "wire-schema-valid", + "name": "WireSchemaValid", + "description": "Every JSON-RPC message the implementation sent is valid per the spec JSON schema for the negotiated spec version", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:47:33.826Z", + "specReferences": [ + { + "id": "MCP-Schema", + "url": "https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/schema/draft/schema.json" + } + ], + "details": { + "messagesValidated": 2, + "violations": [] + } + } + ], + "stdout": "Running client scenario 'tools-call-simple-text' against server: http://127.0.0.1:59159/mcp\nResults saved to /tmp/mcp-conformance-server-kdog2ok2/server-tools-call-simple-text-2026-09-08T23-47-33-705Z\nChecks:\n\u001b[90m2026-09-08T23:47:33.826Z\u001b[0m [tools-call-simple-text] \u001b[32mSUCCESS\u001b[0m Tool returns simple text content\n\u001b[90m2026-09-08T23:47:33.826Z\u001b[0m [wire-schema-valid ] \u001b[32mSUCCESS\u001b[0m Every JSON-RPC message the implementation sent is valid per the spec JSON schema for the negotiated spec version\n\nTest Results:\nPassed: 2/2, 0 failed, 0 warnings\n", + "stderr": "" + }, + { + "leg": "server", + "scenario": "tools-call-error", + "spec_version": "2026-07-28", + "required": true, + "exit_code": 0, + "summary": { + "ok": true, + "counts": { + "SUCCESS": 2 + }, + "blocking": [] + }, + "warnings": [], + "failures": [], + "checks": [ + { + "id": "tools-call-error", + "name": "ToolsCallError", + "description": "Tool returns error correctly", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:47:40.520Z", + "specReferences": [ + { + "id": "MCP-Error-Handling", + "url": "https://modelcontextprotocol.io/specification/2025-06-18/basic/lifecycle" + } + ], + "details": { + "result": { + "resultType": "complete", + "ttlMs": 0, + "cacheScope": "private", + "isError": true, + "content": [ + { + "type": "text", + "text": "This tool intentionally returns an error for testing" + } + ] + } + } + }, + { + "id": "wire-schema-valid", + "name": "WireSchemaValid", + "description": "Every JSON-RPC message the implementation sent is valid per the spec JSON schema for the negotiated spec version", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:47:40.520Z", + "specReferences": [ + { + "id": "MCP-Schema", + "url": "https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/schema/draft/schema.json" + } + ], + "details": { + "messagesValidated": 2, + "violations": [] + } + } + ], + "stdout": "Running client scenario 'tools-call-error' against server: http://127.0.0.1:40101/mcp\nResults saved to /tmp/mcp-conformance-server-dp6zs4bl/server-tools-call-error-2026-09-08T23-47-40-402Z\nChecks:\n\u001b[90m2026-09-08T23:47:40.520Z\u001b[0m [tools-call-error ] \u001b[32mSUCCESS\u001b[0m Tool returns error correctly\n\u001b[90m2026-09-08T23:47:40.520Z\u001b[0m [wire-schema-valid] \u001b[32mSUCCESS\u001b[0m Every JSON-RPC message the implementation sent is valid per the spec JSON schema for the negotiated spec version\n\nTest Results:\nPassed: 2/2, 0 failed, 0 warnings\n", + "stderr": "" + }, + { + "leg": "server", + "scenario": "server-initialize", + "spec_version": "2025-11-25", + "required": true, + "exit_code": 0, + "summary": { + "ok": true, + "counts": { + "SUCCESS": 2, + "INFO": 1 + }, + "blocking": [] + }, + "warnings": [], + "failures": [], + "checks": [ + { + "id": "server-initialize", + "name": "ServerInitialize", + "description": "Server responds to initialize request with valid structure", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:47:47.245Z", + "specReferences": [ + { + "id": "MCP-Initialize", + "url": "https://modelcontextprotocol.io/specification/2025-06-18/basic/lifecycle#initialization" + } + ], + "details": { + "serverUrl": "http://127.0.0.1:43637/mcp", + "connected": true + } + }, + { + "id": "server-session-id-visible-ascii", + "name": "ServerSessionIdVisibleAscii", + "description": "Server-provided session ID uses only visible ASCII characters", + "status": "INFO", + "timestamp": "2026-09-08T23:47:47.250Z", + "specReferences": [ + { + "id": "MCP-Session-Management", + "url": "https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#session-management" + } + ], + "details": { + "message": "Server did not provide an MCP-Session-Id header (session ID is optional)" + } + }, + { + "id": "wire-schema-valid", + "name": "WireSchemaValid", + "description": "Every JSON-RPC message the implementation sent is valid per the spec JSON schema for the negotiated spec version", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:47:47.250Z", + "specReferences": [ + { + "id": "MCP-Schema", + "url": "https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/schema/2025-11-25/schema.json" + } + ], + "details": { + "messagesValidated": 3, + "violations": [] + } + } + ], + "stdout": "Running client scenario 'server-initialize' against server: http://127.0.0.1:43637/mcp\nResults saved to /tmp/mcp-conformance-server-ivrjj_9b/server-server-initialize-2026-09-08T23-47-47-135Z\nChecks:\n\u001b[90m2026-09-08T23:47:47.245Z\u001b[0m [server-initialize ] \u001b[32mSUCCESS\u001b[0m Server responds to initialize request with valid structure\n\u001b[90m2026-09-08T23:47:47.250Z\u001b[0m [server-session-id-visible-ascii] \u001b[36mINFO \u001b[0m Server-provided session ID uses only visible ASCII characters\n\u001b[90m2026-09-08T23:47:47.250Z\u001b[0m [wire-schema-valid ] \u001b[32mSUCCESS\u001b[0m Every JSON-RPC message the implementation sent is valid per the spec JSON schema for the negotiated spec version\n\nTest Results:\nPassed: 2/2, 0 failed, 0 warnings\n", + "stderr": "" + }, + { + "leg": "client", + "scenario": "auth/metadata-var2", + "spec_version": "2026-07-28", + "required": true, + "exit_code": 1, + "summary": { + "ok": true, + "counts": { + "INFO": 22, + "SUCCESS": 18 + }, + "blocking": [] + }, + "warnings": [], + "failures": [], + "checks": [ + { + "id": "incoming-request", + "name": "Incoming-request", + "description": "Received POST request for /mcp (method: initialize)", + "status": "INFO", + "timestamp": "2026-09-08T23:47:54.010Z", + "details": { + "method": "POST", + "path": "/mcp", + "body": { + "method": "initialize", + "params": { + "protocolVersion": "2025-11-25", + "capabilities": {}, + "clientInfo": { + "name": "eventrelay-conformance-client", + "version": "1.0.0" + } + }, + "jsonrpc": "2.0", + "id": 0 + }, + "mcpMethod": "initialize" + } + }, + { + "id": "outgoing-response", + "name": "Outgoing-response", + "description": "Sent 401 response for POST /mcp (method: initialize)", + "status": "INFO", + "timestamp": "2026-09-08T23:47:54.012Z", + "details": { + "method": "POST", + "path": "/mcp", + "statusCode": 401, + "mcpMethod": "initialize", + "headers": { + "x-powered-by": "Express", + "www-authenticate": "Bearer error=\"invalid_token\", error_description=\"Missing Authorization header\"", + "content-type": "application/json; charset=utf-8", + "content-length": "76", + "etag": "W/\"4c-ptrIdu+3yjAtarglCEu6XVLnz2c\"" + }, + "body": { + "error": "invalid_token", + "error_description": "Missing Authorization header" + } + } + }, + { + "id": "incoming-request", + "name": "Incoming-request", + "description": "Received GET request for /.well-known/oauth-protected-resource/mcp", + "status": "INFO", + "timestamp": "2026-09-08T23:47:54.020Z", + "details": { + "method": "GET", + "path": "/.well-known/oauth-protected-resource/mcp" + } + }, + { + "id": "outgoing-response", + "name": "Outgoing-response", + "description": "Sent 404 response for GET /.well-known/oauth-protected-resource/mcp", + "status": "INFO", + "timestamp": "2026-09-08T23:47:54.021Z", + "details": { + "method": "GET", + "path": "/.well-known/oauth-protected-resource/mcp", + "statusCode": 404, + "headers": { + "x-powered-by": "Express", + "content-security-policy": "default-src 'none'", + "x-content-type-options": "nosniff", + "content-type": "text/html; charset=utf-8", + "content-length": 179 + }, + "body": "\n\n\n\nError\n\n\n
Cannot GET /.well-known/oauth-protected-resource/mcp
\n\n\n" + } + }, + { + "id": "incoming-request", + "name": "Incoming-request", + "description": "Received GET request for /.well-known/oauth-protected-resource", + "status": "INFO", + "timestamp": "2026-09-08T23:47:54.023Z", + "details": { + "method": "GET", + "path": "/.well-known/oauth-protected-resource" + } + }, + { + "id": "prm-pathbased-requested", + "name": "PRMPathBasedRequested", + "description": "Client requested PRM metadata at path-based location", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:47:54.023Z", + "specReferences": [ + { + "id": "RFC-9728", + "url": "https://www.rfc-editor.org/rfc/rfc9728.html#section-3.1" + }, + { + "id": "MCP-2025-06-18-PRM-discovery", + "url": "https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization#protected-resource-metadata-discovery-requirements" + } + ], + "details": { + "url": "/.well-known/oauth-protected-resource", + "path": "/.well-known/oauth-protected-resource" + } + }, + { + "id": "outgoing-response", + "name": "Outgoing-response", + "description": "Sent 200 response for GET /.well-known/oauth-protected-resource", + "status": "INFO", + "timestamp": "2026-09-08T23:47:54.023Z", + "details": { + "method": "GET", + "path": "/.well-known/oauth-protected-resource", + "statusCode": 200, + "headers": { + "x-powered-by": "Express", + "content-type": "application/json; charset=utf-8", + "content-length": "96", + "etag": "W/\"60-61cTAqeQ9s3o3vshSmprUp2i1lo\"" + }, + "body": { + "resource": "http://localhost:46209", + "authorization_servers": [ + "http://localhost:40391/tenant1" + ] + } + } + }, + { + "id": "incoming-auth-request", + "name": "Incoming-auth-request", + "description": "Received GET request for /.well-known/oauth-authorization-server/tenant1", + "status": "INFO", + "timestamp": "2026-09-08T23:47:54.030Z", + "details": { + "method": "GET", + "path": "/.well-known/oauth-authorization-server/tenant1" + } + }, + { + "id": "authorization-server-metadata", + "name": "AuthorizationServerMetadata", + "description": "Client requested authorization server metadata", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:47:54.030Z", + "specReferences": [ + { + "id": "RFC-8414-metadata-request", + "url": "https://www.rfc-editor.org/rfc/rfc8414.html#section-3.1" + }, + { + "id": "MCP-Authorization-metadata-discovery", + "url": "https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization#authorization-server-metadata-discovery" + } + ], + "details": { + "url": "/.well-known/oauth-authorization-server/tenant1", + "path": "/.well-known/oauth-authorization-server/tenant1" + } + }, + { + "id": "outgoing-auth-response", + "name": "Outgoing-auth-response", + "description": "Sent 200 response for GET /.well-known/oauth-authorization-server/tenant1", + "status": "INFO", + "timestamp": "2026-09-08T23:47:54.031Z", + "details": { + "method": "GET", + "path": "/.well-known/oauth-authorization-server/tenant1", + "statusCode": 200, + "headers": { + "x-powered-by": "Express", + "content-type": "application/json; charset=utf-8", + "content-length": "479", + "etag": "W/\"1df-x59Pnsa5T7Y0DJvE8f0aUFKsN2s\"" + }, + "body": { + "issuer": "http://localhost:40391/tenant1", + "authorization_endpoint": "http://localhost:40391/tenant1/authorize", + "token_endpoint": "http://localhost:40391/tenant1/token", + "registration_endpoint": "http://localhost:40391/tenant1/register", + "response_types_supported": [ + "code" + ], + "grant_types_supported": [ + "authorization_code", + "refresh_token" + ], + "code_challenge_methods_supported": [ + "S256" + ], + "authorization_response_iss_parameter_supported": true, + "token_endpoint_auth_methods_supported": [ + "none" + ] + } + } + }, + { + "id": "incoming-auth-request", + "name": "Incoming-auth-request", + "description": "Received POST request for /tenant1/register", + "status": "INFO", + "timestamp": "2026-09-08T23:47:54.035Z", + "details": { + "method": "POST", + "path": "/tenant1/register", + "body": { + "client_name": "eventrelay-conformance-client", + "redirect_uris": [ + "http://localhost:3000/callback" + ], + "application_type": "native" + } + } + }, + { + "id": "client-registration", + "name": "ClientRegistration", + "description": "Client registered with authorization server", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:47:54.035Z", + "specReferences": [ + { + "id": "MCP-Dynamic-client-registration", + "url": "https://modelcontextprotocol.io/specification/2025-11-25/basic/client#dynamic-client-registration" + } + ], + "details": { + "endpoint": "/register", + "clientName": "eventrelay-conformance-client" + } + }, + { + "id": "sep-837-application-type-present", + "name": "DCR application_type specified", + "description": "Client specified application_type \"native\" during Dynamic Client Registration", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:47:54.035Z", + "specReferences": [ + { + "id": "MCP-Dynamic-client-registration", + "url": "https://modelcontextprotocol.io/specification/2025-11-25/basic/client#dynamic-client-registration" + } + ], + "details": { + "application_type": "native" + } + }, + { + "id": "outgoing-auth-response", + "name": "Outgoing-auth-response", + "description": "Sent 201 response for POST /tenant1/register", + "status": "INFO", + "timestamp": "2026-09-08T23:47:54.035Z", + "details": { + "method": "POST", + "path": "/tenant1/register", + "statusCode": 201, + "headers": { + "x-powered-by": "Express", + "content-type": "application/json; charset=utf-8", + "content-length": "164", + "etag": "W/\"a4-TMdgwr0j2yD0GKCOcPKDUR3xJxc\"" + }, + "body": { + "client_id": "test-client-id", + "client_secret": "test-client-secret", + "client_name": "eventrelay-conformance-client", + "redirect_uris": [ + "http://localhost:3000/callback" + ] + } + } + }, + { + "id": "incoming-auth-request", + "name": "Incoming-auth-request", + "description": "Received GET request for /tenant1/authorize", + "status": "INFO", + "timestamp": "2026-09-08T23:47:54.042Z", + "details": { + "method": "GET", + "path": "/tenant1/authorize", + "query": { + "response_type": "code", + "client_id": "test-client-id", + "code_challenge": "rwWoaxCgmEQ8RHMQXPVrKrI8tKEJDlsodFkc-wIo96c", + "code_challenge_method": "S256", + "redirect_uri": "http://localhost:3000/callback", + "resource": "http://localhost:46209" + } + } + }, + { + "id": "authorization-request", + "name": "AuthorizationRequest", + "description": "Client made authorization request", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:47:54.042Z", + "specReferences": [ + { + "id": "OAUTH-2.1-authorization-endpoint", + "url": "https://www.ietf.org/archive/id/draft-ietf-oauth-v2-1-13.html#name-authorization-endpoint" + } + ], + "details": { + "query": { + "response_type": "code", + "client_id": "test-client-id", + "code_challenge": "rwWoaxCgmEQ8RHMQXPVrKrI8tKEJDlsodFkc-wIo96c", + "code_challenge_method": "S256", + "redirect_uri": "http://localhost:3000/callback", + "resource": "http://localhost:46209" + } + } + }, + { + "id": "pkce-code-challenge-sent", + "name": "PKCE Code Challenge", + "description": "Client sent code_challenge in authorization request", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:47:54.042Z", + "specReferences": [ + { + "id": "MCP-PKCE-requirement", + "url": "https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization#authorization-code-protection" + } + ] + }, + { + "id": "pkce-s256-method-used", + "name": "PKCE S256 Method", + "description": "Client used S256 code challenge method", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:47:54.042Z", + "specReferences": [ + { + "id": "MCP-PKCE-requirement", + "url": "https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization#authorization-code-protection" + } + ], + "details": { + "method": "S256" + } + }, + { + "id": "outgoing-auth-response", + "name": "Outgoing-auth-response", + "description": "Sent 302 response for GET /tenant1/authorize", + "status": "INFO", + "timestamp": "2026-09-08T23:47:54.044Z", + "details": { + "method": "GET", + "path": "/tenant1/authorize", + "statusCode": 302, + "headers": { + "x-powered-by": "Express", + "location": "http://localhost:3000/callback?code=test-auth-code&iss=http%3A%2F%2Flocalhost%3A40391%2Ftenant1", + "vary": "Accept", + "content-type": "text/plain; charset=utf-8", + "content-length": "117" + }, + "body": "Found. Redirecting to http://localhost:3000/callback?code=test-auth-code&iss=http%3A%2F%2Flocalhost%3A40391%2Ftenant1" + } + }, + { + "id": "incoming-request", + "name": "Incoming-request", + "description": "Received GET request for /.well-known/oauth-protected-resource/mcp", + "status": "INFO", + "timestamp": "2026-09-08T23:47:54.046Z", + "details": { + "method": "GET", + "path": "/.well-known/oauth-protected-resource/mcp" + } + }, + { + "id": "outgoing-response", + "name": "Outgoing-response", + "description": "Sent 404 response for GET /.well-known/oauth-protected-resource/mcp", + "status": "INFO", + "timestamp": "2026-09-08T23:47:54.046Z", + "details": { + "method": "GET", + "path": "/.well-known/oauth-protected-resource/mcp", + "statusCode": 404, + "headers": { + "x-powered-by": "Express", + "content-security-policy": "default-src 'none'", + "x-content-type-options": "nosniff", + "content-type": "text/html; charset=utf-8", + "content-length": 179 + }, + "body": "\n\n\n\nError\n\n\n
Cannot GET /.well-known/oauth-protected-resource/mcp
\n\n\n" + } + }, + { + "id": "incoming-request", + "name": "Incoming-request", + "description": "Received GET request for /.well-known/oauth-protected-resource", + "status": "INFO", + "timestamp": "2026-09-08T23:47:54.049Z", + "details": { + "method": "GET", + "path": "/.well-known/oauth-protected-resource" + } + }, + { + "id": "prm-pathbased-requested", + "name": "PRMPathBasedRequested", + "description": "Client requested PRM metadata at path-based location", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:47:54.049Z", + "specReferences": [ + { + "id": "RFC-9728", + "url": "https://www.rfc-editor.org/rfc/rfc9728.html#section-3.1" + }, + { + "id": "MCP-2025-06-18-PRM-discovery", + "url": "https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization#protected-resource-metadata-discovery-requirements" + } + ], + "details": { + "url": "/.well-known/oauth-protected-resource", + "path": "/.well-known/oauth-protected-resource" + } + }, + { + "id": "outgoing-response", + "name": "Outgoing-response", + "description": "Sent 200 response for GET /.well-known/oauth-protected-resource", + "status": "INFO", + "timestamp": "2026-09-08T23:47:54.049Z", + "details": { + "method": "GET", + "path": "/.well-known/oauth-protected-resource", + "statusCode": 200, + "headers": { + "x-powered-by": "Express", + "content-type": "application/json; charset=utf-8", + "content-length": "96", + "etag": "W/\"60-61cTAqeQ9s3o3vshSmprUp2i1lo\"" + }, + "body": { + "resource": "http://localhost:46209", + "authorization_servers": [ + "http://localhost:40391/tenant1" + ] + } + } + }, + { + "id": "incoming-auth-request", + "name": "Incoming-auth-request", + "description": "Received GET request for /.well-known/oauth-authorization-server/tenant1", + "status": "INFO", + "timestamp": "2026-09-08T23:47:54.052Z", + "details": { + "method": "GET", + "path": "/.well-known/oauth-authorization-server/tenant1" + } + }, + { + "id": "authorization-server-metadata", + "name": "AuthorizationServerMetadata", + "description": "Client requested authorization server metadata", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:47:54.052Z", + "specReferences": [ + { + "id": "RFC-8414-metadata-request", + "url": "https://www.rfc-editor.org/rfc/rfc8414.html#section-3.1" + }, + { + "id": "MCP-Authorization-metadata-discovery", + "url": "https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization#authorization-server-metadata-discovery" + } + ], + "details": { + "url": "/.well-known/oauth-authorization-server/tenant1", + "path": "/.well-known/oauth-authorization-server/tenant1" + } + }, + { + "id": "outgoing-auth-response", + "name": "Outgoing-auth-response", + "description": "Sent 200 response for GET /.well-known/oauth-authorization-server/tenant1", + "status": "INFO", + "timestamp": "2026-09-08T23:47:54.052Z", + "details": { + "method": "GET", + "path": "/.well-known/oauth-authorization-server/tenant1", + "statusCode": 200, + "headers": { + "x-powered-by": "Express", + "content-type": "application/json; charset=utf-8", + "content-length": "479", + "etag": "W/\"1df-x59Pnsa5T7Y0DJvE8f0aUFKsN2s\"" + }, + "body": { + "issuer": "http://localhost:40391/tenant1", + "authorization_endpoint": "http://localhost:40391/tenant1/authorize", + "token_endpoint": "http://localhost:40391/tenant1/token", + "registration_endpoint": "http://localhost:40391/tenant1/register", + "response_types_supported": [ + "code" + ], + "grant_types_supported": [ + "authorization_code", + "refresh_token" + ], + "code_challenge_methods_supported": [ + "S256" + ], + "authorization_response_iss_parameter_supported": true, + "token_endpoint_auth_methods_supported": [ + "none" + ] + } + } + }, + { + "id": "incoming-auth-request", + "name": "Incoming-auth-request", + "description": "Received POST request for /tenant1/token", + "status": "INFO", + "timestamp": "2026-09-08T23:47:54.057Z", + "details": { + "method": "POST", + "path": "/tenant1/token", + "body": { + "grant_type": "authorization_code", + "code": "test-auth-code", + "code_verifier": "V4y3IwTmW.ircYLUurTklbtf-2uuhHnuQYBeO7bsxQ0", + "redirect_uri": "http://localhost:3000/callback", + "resource": "http://localhost:46209", + "client_id": "test-client-id" + } + } + }, + { + "id": "token-request", + "name": "TokenRequest", + "description": "Client requested access token", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:47:54.058Z", + "specReferences": [ + { + "id": "OAUTH-2.1-token-request", + "url": "https://www.ietf.org/archive/id/draft-ietf-oauth-v2-1-13.html#name-token-request" + } + ], + "details": { + "endpoint": "/token", + "grantType": "authorization_code" + } + }, + { + "id": "pkce-code-verifier-sent", + "name": "PKCE Code Verifier", + "description": "Client sent code_verifier in token request", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:47:54.058Z", + "specReferences": [ + { + "id": "MCP-PKCE-requirement", + "url": "https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization#authorization-code-protection" + } + ] + }, + { + "id": "pkce-verifier-matches-challenge", + "name": "PKCE Verifier Validation", + "description": "code_verifier correctly matches code_challenge (S256)", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:47:54.058Z", + "specReferences": [ + { + "id": "MCP-PKCE-requirement", + "url": "https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization#authorization-code-protection" + } + ], + "details": { + "matches": true, + "storedChallenge": "rwWoaxCgmEQ8RHMQXPVrKrI8tKEJDlsodFkc-wIo96c", + "computedChallenge": "rwWoaxCgmEQ8RHMQXPVrKrI8tKEJDlsodFkc-wIo96c" + } + }, + { + "id": "outgoing-auth-response", + "name": "Outgoing-auth-response", + "description": "Sent 200 response for POST /tenant1/token", + "status": "INFO", + "timestamp": "2026-09-08T23:47:54.058Z", + "details": { + "method": "POST", + "path": "/tenant1/token", + "statusCode": 200, + "headers": { + "x-powered-by": "Express", + "content-type": "application/json; charset=utf-8", + "content-length": "83", + "etag": "W/\"53-2wND0a0ZMq7RW6Df/UhCYSBw1Qg\"" + }, + "body": { + "access_token": "test-token-1788911274058", + "token_type": "Bearer", + "expires_in": 3600 + } + } + }, + { + "id": "incoming-request", + "name": "Incoming-request", + "description": "Received POST request for /mcp (method: initialize)", + "status": "INFO", + "timestamp": "2026-09-08T23:47:54.061Z", + "details": { + "method": "POST", + "path": "/mcp", + "body": { + "method": "initialize", + "params": { + "protocolVersion": "2025-11-25", + "capabilities": {}, + "clientInfo": { + "name": "eventrelay-conformance-client", + "version": "1.0.0" + } + }, + "jsonrpc": "2.0", + "id": 0 + }, + "mcpMethod": "initialize" + } + }, + { + "id": "valid-bearer-token", + "name": "ValidBearerToken", + "description": "Client provided valid bearer token", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:47:54.062Z", + "specReferences": [ + { + "id": "MCP-Access-token-usage", + "url": "https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization#access-token-usage" + } + ], + "details": { + "token": "test-token-1788...", + "scopes": [] + } + }, + { + "id": "outgoing-response", + "name": "Outgoing-response", + "description": "Sent 400 response for POST /mcp (method: initialize)", + "status": "INFO", + "timestamp": "2026-09-08T23:47:54.062Z", + "details": { + "method": "POST", + "path": "/mcp", + "statusCode": 400, + "mcpMethod": "initialize", + "headers": { + "x-powered-by": "Express", + "content-type": "application/json; charset=utf-8", + "content-length": "96", + "etag": "W/\"60-+I3pGWaBJPzWK/0N3EGEE0YM2QY\"" + }, + "body": { + "jsonrpc": "2.0", + "id": 0, + "error": { + "code": -32020, + "message": "Missing MCP-Protocol-Version header" + } + } + } + }, + { + "id": "resource-parameter-in-authorization", + "name": "Resource parameter in authorization request", + "description": "Client included resource parameter in authorization request", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:47:54.082Z", + "specReferences": [ + { + "id": "RFC-8707-Resource-Indicators", + "url": "https://www.rfc-editor.org/rfc/rfc8707.html" + }, + { + "id": "MCP-Resource-Parameter-Implementation", + "url": "https://modelcontextprotocol.io/specification/draft/basic/authorization#resource-parameter-implementation" + } + ], + "details": { + "resource": "http://localhost:46209" + } + }, + { + "id": "resource-parameter-in-token", + "name": "Resource parameter in token request", + "description": "Client included resource parameter in token request", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:47:54.082Z", + "specReferences": [ + { + "id": "RFC-8707-Resource-Indicators", + "url": "https://www.rfc-editor.org/rfc/rfc8707.html" + }, + { + "id": "MCP-Resource-Parameter-Implementation", + "url": "https://modelcontextprotocol.io/specification/draft/basic/authorization#resource-parameter-implementation" + } + ], + "details": { + "resource": "http://localhost:46209" + } + }, + { + "id": "resource-parameter-valid-uri", + "name": "Resource parameter is valid canonical URI", + "description": "Resource parameter is a valid canonical URI (has scheme, no fragment)", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:47:54.082Z", + "specReferences": [ + { + "id": "RFC-8707-Resource-Indicators", + "url": "https://www.rfc-editor.org/rfc/rfc8707.html" + }, + { + "id": "MCP-Resource-Parameter-Implementation", + "url": "https://modelcontextprotocol.io/specification/draft/basic/authorization#resource-parameter-implementation" + } + ], + "details": { + "resource": "http://localhost:46209" + } + }, + { + "id": "resource-parameter-consistency", + "name": "Resource parameter consistency", + "description": "Resource parameter is consistent between authorization and token requests", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:47:54.082Z", + "specReferences": [ + { + "id": "RFC-8707-Resource-Indicators", + "url": "https://www.rfc-editor.org/rfc/rfc8707.html" + }, + { + "id": "MCP-Resource-Parameter-Implementation", + "url": "https://modelcontextprotocol.io/specification/draft/basic/authorization#resource-parameter-implementation" + } + ], + "details": { + "authorizationResource": "http://localhost:46209", + "tokenResource": "http://localhost:46209" + } + }, + { + "id": "resource-parameter-matches-prm", + "name": "Resource parameter matches protected resource metadata", + "description": "Client sent the resource identifier exactly as published in protected resource metadata", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:47:54.082Z", + "specReferences": [ + { + "id": "RFC-8707-Resource-Indicators", + "url": "https://www.rfc-editor.org/rfc/rfc8707.html" + }, + { + "id": "MCP-Resource-Parameter-Implementation", + "url": "https://modelcontextprotocol.io/specification/draft/basic/authorization#resource-parameter-implementation" + }, + { + "id": "MCP-Canonical-Server-URI", + "url": "https://modelcontextprotocol.io/specification/draft/basic/authorization#canonical-server-uri" + }, + { + "id": "RFC-9728-resource-identity", + "url": "https://www.rfc-editor.org/rfc/rfc9728.html#section-3.3" + } + ], + "details": { + "prmResource": "http://localhost:46209", + "authorizationResource": "http://localhost:46209", + "tokenResource": "http://localhost:46209" + } + } + ], + "stdout": "", + "stderr": "Starting scenario: auth/metadata-var2\nExecuting client: node /home/runner/work/EventRelay/EventRelay/tests/testing/official_mcp_auth_client.mjs http://localhost:46209/mcp\n(node:8954) [DEP0190] DeprecationWarning: Passing args to a child process with shell option true can lead to security vulnerabilities, as the arguments are not escaped, only concatenated.\n(Use `node --trace-deprecation ...` to show where the warning was created)\n\nClient exited with code 1\n\nStderr:\nError: Streamable HTTP error: Error POSTing to endpoint: {\"jsonrpc\":\"2.0\",\"id\":0,\"error\":{\"code\":-32020,\"message\":\"Missing MCP-Protocol-Version header\"}}\n at StreamableHTTPClientTransport.send (file:///home/runner/work/EventRelay/EventRelay/node_modules/@modelcontextprotocol/sdk/dist/esm/client/streamableHttp.js:365:23)\n at process.processTicksAndRejections (node:internal/process/task_queues:104:5)\n\nResults saved to /tmp/mcp-conformance-client-m6ywh1oh/auth/metadata-var2-2026-09-08T23-47-53-767Z\nChecks:\n\u001b[90m2026-09-08T23:47:54.010Z\u001b[0m [incoming-request ] \u001b[36mINFO \u001b[0m Received POST request for /mcp (method: initialize)\n\u001b[90m2026-09-08T23:47:54.012Z\u001b[0m [outgoing-response ] \u001b[36mINFO \u001b[0m Sent 401 response for POST /mcp (method: initialize)\n\n\u001b[90m2026-09-08T23:47:54.020Z\u001b[0m [incoming-request ] \u001b[36mINFO \u001b[0m Received GET request for /.well-known/oauth-protected-resource/mcp\n\u001b[90m2026-09-08T23:47:54.021Z\u001b[0m [outgoing-response ] \u001b[36mINFO \u001b[0m Sent 404 response for GET /.well-known/oauth-protected-resource/mcp\n\n\u001b[90m2026-09-08T23:47:54.023Z\u001b[0m [incoming-request ] \u001b[36mINFO \u001b[0m Received GET request for /.well-known/oauth-protected-resource\n\u001b[90m2026-09-08T23:47:54.023Z\u001b[0m [prm-pathbased-requested ] \u001b[32mSUCCESS\u001b[0m Client requested PRM metadata at path-based location\n\u001b[90m2026-09-08T23:47:54.023Z\u001b[0m [outgoing-response ] \u001b[36mINFO \u001b[0m Sent 200 response for GET /.well-known/oauth-protected-resource\n\n\u001b[90m2026-09-08T23:47:54.030Z\u001b[0m [incoming-auth-request ] \u001b[36mINFO \u001b[0m Received GET request for /.well-known/oauth-authorization-server/tenant1\n\u001b[90m2026-09-08T23:47:54.030Z\u001b[0m [authorization-server-metadata ] \u001b[32mSUCCESS\u001b[0m Client requested authorization server metadata\n\u001b[90m2026-09-08T23:47:54.031Z\u001b[0m [outgoing-auth-response ] \u001b[36mINFO \u001b[0m Sent 200 response for GET /.well-known/oauth-authorization-server/tenant1\n\n\u001b[90m2026-09-08T23:47:54.035Z\u001b[0m [incoming-auth-request ] \u001b[36mINFO \u001b[0m Received POST request for /tenant1/register\n\u001b[90m2026-09-08T23:47:54.035Z\u001b[0m [client-registration ] \u001b[32mSUCCESS\u001b[0m Client registered with authorization server\n\u001b[90m2026-09-08T23:47:54.035Z\u001b[0m [sep-837-application-type-present ] \u001b[32mSUCCESS\u001b[0m Client specified application_type \"native\" during Dynamic Client Registration\n\u001b[90m2026-09-08T23:47:54.035Z\u001b[0m [outgoing-auth-response ] \u001b[36mINFO \u001b[0m Sent 201 response for POST /tenant1/register\n\n\u001b[90m2026-09-08T23:47:54.042Z\u001b[0m [incoming-auth-request ] \u001b[36mINFO \u001b[0m Received GET request for /tenant1/authorize\n\u001b[90m2026-09-08T23:47:54.042Z\u001b[0m [authorization-request ] \u001b[32mSUCCESS\u001b[0m Client made authorization request\n\u001b[90m2026-09-08T23:47:54.042Z\u001b[0m [pkce-code-challenge-sent ] \u001b[32mSUCCESS\u001b[0m Client sent code_challenge in authorization request\n\u001b[90m2026-09-08T23:47:54.042Z\u001b[0m [pkce-s256-method-used ] \u001b[32mSUCCESS\u001b[0m Client used S256 code challenge method\n\u001b[90m2026-09-08T23:47:54.044Z\u001b[0m [outgoing-auth-response ] \u001b[36mINFO \u001b[0m Sent 302 response for GET /tenant1/authorize\n\n\u001b[90m2026-09-08T23:47:54.046Z\u001b[0m [incoming-request ] \u001b[36mINFO \u001b[0m Received GET request for /.well-known/oauth-protected-resource/mcp\n\u001b[90m2026-09-08T23:47:54.046Z\u001b[0m [outgoing-response ] \u001b[36mINFO \u001b[0m Sent 404 response for GET /.well-k\n...[truncated]" + }, + { + "leg": "client", + "scenario": "auth/token-endpoint-auth-basic", + "spec_version": "2026-07-28", + "required": true, + "exit_code": 1, + "summary": { + "ok": true, + "counts": { + "INFO": 18, + "SUCCESS": 19 + }, + "blocking": [] + }, + "warnings": [], + "failures": [], + "checks": [ + { + "id": "incoming-request", + "name": "Incoming-request", + "description": "Received POST request for /mcp (method: initialize)", + "status": "INFO", + "timestamp": "2026-09-08T23:48:00.871Z", + "details": { + "method": "POST", + "path": "/mcp", + "body": { + "method": "initialize", + "params": { + "protocolVersion": "2025-11-25", + "capabilities": {}, + "clientInfo": { + "name": "eventrelay-conformance-client", + "version": "1.0.0" + } + }, + "jsonrpc": "2.0", + "id": 0 + }, + "mcpMethod": "initialize" + } + }, + { + "id": "outgoing-response", + "name": "Outgoing-response", + "description": "Sent 401 response for POST /mcp (method: initialize)", + "status": "INFO", + "timestamp": "2026-09-08T23:48:00.873Z", + "details": { + "method": "POST", + "path": "/mcp", + "statusCode": 401, + "mcpMethod": "initialize", + "headers": { + "x-powered-by": "Express", + "www-authenticate": "Bearer error=\"invalid_token\", error_description=\"Missing Authorization header\", resource_metadata=\"http://localhost:46773/.well-known/oauth-protected-resource/mcp\"", + "content-type": "application/json; charset=utf-8", + "content-length": "76", + "etag": "W/\"4c-ptrIdu+3yjAtarglCEu6XVLnz2c\"" + }, + "body": { + "error": "invalid_token", + "error_description": "Missing Authorization header" + } + } + }, + { + "id": "incoming-request", + "name": "Incoming-request", + "description": "Received GET request for /.well-known/oauth-protected-resource/mcp", + "status": "INFO", + "timestamp": "2026-09-08T23:48:00.881Z", + "details": { + "method": "GET", + "path": "/.well-known/oauth-protected-resource/mcp" + } + }, + { + "id": "prm-pathbased-requested", + "name": "PRMPathBasedRequested", + "description": "Client requested PRM metadata at path-based location", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:00.881Z", + "specReferences": [ + { + "id": "RFC-9728", + "url": "https://www.rfc-editor.org/rfc/rfc9728.html#section-3.1" + }, + { + "id": "MCP-2025-06-18-PRM-discovery", + "url": "https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization#protected-resource-metadata-discovery-requirements" + } + ], + "details": { + "url": "/.well-known/oauth-protected-resource/mcp", + "path": "/.well-known/oauth-protected-resource/mcp" + } + }, + { + "id": "outgoing-response", + "name": "Outgoing-response", + "description": "Sent 200 response for GET /.well-known/oauth-protected-resource/mcp", + "status": "INFO", + "timestamp": "2026-09-08T23:48:00.882Z", + "details": { + "method": "GET", + "path": "/.well-known/oauth-protected-resource/mcp", + "statusCode": 200, + "headers": { + "x-powered-by": "Express", + "content-type": "application/json; charset=utf-8", + "content-length": "92", + "etag": "W/\"5c-pPdYsXbZmxVJqA2xjkEnGEnTUbU\"" + }, + "body": { + "resource": "http://localhost:46773/mcp", + "authorization_servers": [ + "http://localhost:35049" + ] + } + } + }, + { + "id": "incoming-auth-request", + "name": "Incoming-auth-request", + "description": "Received GET request for /.well-known/oauth-authorization-server", + "status": "INFO", + "timestamp": "2026-09-08T23:48:00.889Z", + "details": { + "method": "GET", + "path": "/.well-known/oauth-authorization-server" + } + }, + { + "id": "authorization-server-metadata", + "name": "AuthorizationServerMetadata", + "description": "Client requested authorization server metadata", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:00.889Z", + "specReferences": [ + { + "id": "RFC-8414-metadata-request", + "url": "https://www.rfc-editor.org/rfc/rfc8414.html#section-3.1" + }, + { + "id": "MCP-Authorization-metadata-discovery", + "url": "https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization#authorization-server-metadata-discovery" + } + ], + "details": { + "url": "/.well-known/oauth-authorization-server", + "path": "/.well-known/oauth-authorization-server" + } + }, + { + "id": "outgoing-auth-response", + "name": "Outgoing-auth-response", + "description": "Sent 200 response for GET /.well-known/oauth-authorization-server", + "status": "INFO", + "timestamp": "2026-09-08T23:48:00.889Z", + "details": { + "method": "GET", + "path": "/.well-known/oauth-authorization-server", + "statusCode": 200, + "headers": { + "x-powered-by": "Express", + "content-type": "application/json; charset=utf-8", + "content-length": "462", + "etag": "W/\"1ce-aWEEAhA7auFXnE2O6CESHdPJ3T0\"" + }, + "body": { + "issuer": "http://localhost:35049", + "authorization_endpoint": "http://localhost:35049/authorize", + "token_endpoint": "http://localhost:35049/token", + "registration_endpoint": "http://localhost:35049/register", + "response_types_supported": [ + "code" + ], + "grant_types_supported": [ + "authorization_code", + "refresh_token" + ], + "code_challenge_methods_supported": [ + "S256" + ], + "authorization_response_iss_parameter_supported": true, + "token_endpoint_auth_methods_supported": [ + "client_secret_basic" + ] + } + } + }, + { + "id": "incoming-auth-request", + "name": "Incoming-auth-request", + "description": "Received POST request for /register", + "status": "INFO", + "timestamp": "2026-09-08T23:48:00.894Z", + "details": { + "method": "POST", + "path": "/register", + "body": { + "client_name": "eventrelay-conformance-client", + "redirect_uris": [ + "http://localhost:3000/callback" + ], + "application_type": "native" + } + } + }, + { + "id": "client-registration", + "name": "ClientRegistration", + "description": "Client registered with authorization server", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:00.894Z", + "specReferences": [ + { + "id": "MCP-Dynamic-client-registration", + "url": "https://modelcontextprotocol.io/specification/2025-11-25/basic/client#dynamic-client-registration" + } + ], + "details": { + "endpoint": "/register", + "clientName": "eventrelay-conformance-client", + "tokenEndpointAuthMethod": "client_secret_basic" + } + }, + { + "id": "sep-837-application-type-present", + "name": "DCR application_type specified", + "description": "Client specified application_type \"native\" during Dynamic Client Registration", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:00.894Z", + "specReferences": [ + { + "id": "MCP-Dynamic-client-registration", + "url": "https://modelcontextprotocol.io/specification/2025-11-25/basic/client#dynamic-client-registration" + } + ], + "details": { + "application_type": "native" + } + }, + { + "id": "outgoing-auth-response", + "name": "Outgoing-auth-response", + "description": "Sent 201 response for POST /register", + "status": "INFO", + "timestamp": "2026-09-08T23:48:00.894Z", + "details": { + "method": "POST", + "path": "/register", + "statusCode": 201, + "headers": { + "x-powered-by": "Express", + "content-type": "application/json; charset=utf-8", + "content-length": "233", + "etag": "W/\"e9-/NJHNWIufWKRG+L8J+RjiU3ws7M\"" + }, + "body": { + "client_id": "test-client-1788911280894", + "client_secret": "test-secret-1788911280894", + "client_name": "eventrelay-conformance-client", + "redirect_uris": [ + "http://localhost:3000/callback" + ], + "token_endpoint_auth_method": "client_secret_basic" + } + } + }, + { + "id": "incoming-auth-request", + "name": "Incoming-auth-request", + "description": "Received GET request for /authorize", + "status": "INFO", + "timestamp": "2026-09-08T23:48:00.901Z", + "details": { + "method": "GET", + "path": "/authorize", + "query": { + "response_type": "code", + "client_id": "test-client-1788911280894", + "code_challenge": "L7--IPmx6hnGHuOW3TReEmJIAMneez95fkZF9BtjYbI", + "code_challenge_method": "S256", + "redirect_uri": "http://localhost:3000/callback", + "resource": "http://localhost:46773/mcp" + } + } + }, + { + "id": "authorization-request", + "name": "AuthorizationRequest", + "description": "Client made authorization request", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:00.901Z", + "specReferences": [ + { + "id": "OAUTH-2.1-authorization-endpoint", + "url": "https://www.ietf.org/archive/id/draft-ietf-oauth-v2-1-13.html#name-authorization-endpoint" + } + ], + "details": { + "query": { + "response_type": "code", + "client_id": "test-client-1788911280894", + "code_challenge": "L7--IPmx6hnGHuOW3TReEmJIAMneez95fkZF9BtjYbI", + "code_challenge_method": "S256", + "redirect_uri": "http://localhost:3000/callback", + "resource": "http://localhost:46773/mcp" + } + } + }, + { + "id": "pkce-code-challenge-sent", + "name": "PKCE Code Challenge", + "description": "Client sent code_challenge in authorization request", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:00.901Z", + "specReferences": [ + { + "id": "MCP-PKCE-requirement", + "url": "https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization#authorization-code-protection" + } + ] + }, + { + "id": "pkce-s256-method-used", + "name": "PKCE S256 Method", + "description": "Client used S256 code challenge method", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:00.901Z", + "specReferences": [ + { + "id": "MCP-PKCE-requirement", + "url": "https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization#authorization-code-protection" + } + ], + "details": { + "method": "S256" + } + }, + { + "id": "outgoing-auth-response", + "name": "Outgoing-auth-response", + "description": "Sent 302 response for GET /authorize", + "status": "INFO", + "timestamp": "2026-09-08T23:48:00.903Z", + "details": { + "method": "GET", + "path": "/authorize", + "statusCode": 302, + "headers": { + "x-powered-by": "Express", + "location": "http://localhost:3000/callback?code=test-auth-code&iss=http%3A%2F%2Flocalhost%3A35049", + "vary": "Accept", + "content-type": "text/plain; charset=utf-8", + "content-length": "107" + }, + "body": "Found. Redirecting to http://localhost:3000/callback?code=test-auth-code&iss=http%3A%2F%2Flocalhost%3A35049" + } + }, + { + "id": "incoming-request", + "name": "Incoming-request", + "description": "Received GET request for /.well-known/oauth-protected-resource/mcp", + "status": "INFO", + "timestamp": "2026-09-08T23:48:00.906Z", + "details": { + "method": "GET", + "path": "/.well-known/oauth-protected-resource/mcp" + } + }, + { + "id": "prm-pathbased-requested", + "name": "PRMPathBasedRequested", + "description": "Client requested PRM metadata at path-based location", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:00.906Z", + "specReferences": [ + { + "id": "RFC-9728", + "url": "https://www.rfc-editor.org/rfc/rfc9728.html#section-3.1" + }, + { + "id": "MCP-2025-06-18-PRM-discovery", + "url": "https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization#protected-resource-metadata-discovery-requirements" + } + ], + "details": { + "url": "/.well-known/oauth-protected-resource/mcp", + "path": "/.well-known/oauth-protected-resource/mcp" + } + }, + { + "id": "outgoing-response", + "name": "Outgoing-response", + "description": "Sent 200 response for GET /.well-known/oauth-protected-resource/mcp", + "status": "INFO", + "timestamp": "2026-09-08T23:48:00.906Z", + "details": { + "method": "GET", + "path": "/.well-known/oauth-protected-resource/mcp", + "statusCode": 200, + "headers": { + "x-powered-by": "Express", + "content-type": "application/json; charset=utf-8", + "content-length": "92", + "etag": "W/\"5c-pPdYsXbZmxVJqA2xjkEnGEnTUbU\"" + }, + "body": { + "resource": "http://localhost:46773/mcp", + "authorization_servers": [ + "http://localhost:35049" + ] + } + } + }, + { + "id": "incoming-auth-request", + "name": "Incoming-auth-request", + "description": "Received GET request for /.well-known/oauth-authorization-server", + "status": "INFO", + "timestamp": "2026-09-08T23:48:00.909Z", + "details": { + "method": "GET", + "path": "/.well-known/oauth-authorization-server" + } + }, + { + "id": "authorization-server-metadata", + "name": "AuthorizationServerMetadata", + "description": "Client requested authorization server metadata", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:00.909Z", + "specReferences": [ + { + "id": "RFC-8414-metadata-request", + "url": "https://www.rfc-editor.org/rfc/rfc8414.html#section-3.1" + }, + { + "id": "MCP-Authorization-metadata-discovery", + "url": "https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization#authorization-server-metadata-discovery" + } + ], + "details": { + "url": "/.well-known/oauth-authorization-server", + "path": "/.well-known/oauth-authorization-server" + } + }, + { + "id": "outgoing-auth-response", + "name": "Outgoing-auth-response", + "description": "Sent 200 response for GET /.well-known/oauth-authorization-server", + "status": "INFO", + "timestamp": "2026-09-08T23:48:00.909Z", + "details": { + "method": "GET", + "path": "/.well-known/oauth-authorization-server", + "statusCode": 200, + "headers": { + "x-powered-by": "Express", + "content-type": "application/json; charset=utf-8", + "content-length": "462", + "etag": "W/\"1ce-aWEEAhA7auFXnE2O6CESHdPJ3T0\"" + }, + "body": { + "issuer": "http://localhost:35049", + "authorization_endpoint": "http://localhost:35049/authorize", + "token_endpoint": "http://localhost:35049/token", + "registration_endpoint": "http://localhost:35049/register", + "response_types_supported": [ + "code" + ], + "grant_types_supported": [ + "authorization_code", + "refresh_token" + ], + "code_challenge_methods_supported": [ + "S256" + ], + "authorization_response_iss_parameter_supported": true, + "token_endpoint_auth_methods_supported": [ + "client_secret_basic" + ] + } + } + }, + { + "id": "incoming-auth-request", + "name": "Incoming-auth-request", + "description": "Received POST request for /token", + "status": "INFO", + "timestamp": "2026-09-08T23:48:00.915Z", + "details": { + "method": "POST", + "path": "/token", + "body": { + "grant_type": "authorization_code", + "code": "test-auth-code", + "code_verifier": "I.PZVHzjWilIcwHiDiwbsO~YshBbLPX4y5AT7Rjcc2H", + "redirect_uri": "http://localhost:3000/callback", + "resource": "http://localhost:46773/mcp" + } + } + }, + { + "id": "token-request", + "name": "TokenRequest", + "description": "Client requested access token", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:00.915Z", + "specReferences": [ + { + "id": "OAUTH-2.1-token-request", + "url": "https://www.ietf.org/archive/id/draft-ietf-oauth-v2-1-13.html#name-token-request" + } + ], + "details": { + "endpoint": "/token", + "grantType": "authorization_code" + } + }, + { + "id": "pkce-code-verifier-sent", + "name": "PKCE Code Verifier", + "description": "Client sent code_verifier in token request", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:00.915Z", + "specReferences": [ + { + "id": "MCP-PKCE-requirement", + "url": "https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization#authorization-code-protection" + } + ] + }, + { + "id": "pkce-verifier-matches-challenge", + "name": "PKCE Verifier Validation", + "description": "code_verifier correctly matches code_challenge (S256)", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:00.915Z", + "specReferences": [ + { + "id": "MCP-PKCE-requirement", + "url": "https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization#authorization-code-protection" + } + ], + "details": { + "matches": true, + "storedChallenge": "L7--IPmx6hnGHuOW3TReEmJIAMneez95fkZF9BtjYbI", + "computedChallenge": "L7--IPmx6hnGHuOW3TReEmJIAMneez95fkZF9BtjYbI" + } + }, + { + "id": "token-endpoint-auth-method", + "name": "Token endpoint authentication method", + "description": "Client correctly used HTTP Basic authentication (client_secret_basic) for token endpoint", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:00.915Z", + "specReferences": [ + { + "id": "OAUTH-2.1-token-request", + "url": "https://www.ietf.org/archive/id/draft-ietf-oauth-v2-1-13.html#name-token-request" + } + ], + "details": { + "expectedAuthMethod": "client_secret_basic", + "actualAuthMethod": "client_secret_basic", + "hasAuthorizationHeader": true, + "hasBodyClientSecret": false + } + }, + { + "id": "outgoing-auth-response", + "name": "Outgoing-auth-response", + "description": "Sent 200 response for POST /token", + "status": "INFO", + "timestamp": "2026-09-08T23:48:00.916Z", + "details": { + "method": "POST", + "path": "/token", + "statusCode": 200, + "headers": { + "x-powered-by": "Express", + "content-type": "application/json; charset=utf-8", + "content-length": "83", + "etag": "W/\"53-qFHaJmbgAUy2O2/86eZkXeSCnhw\"" + }, + "body": { + "access_token": "test-token-1788911280916", + "token_type": "Bearer", + "expires_in": 3600 + } + } + }, + { + "id": "incoming-request", + "name": "Incoming-request", + "description": "Received POST request for /mcp (method: initialize)", + "status": "INFO", + "timestamp": "2026-09-08T23:48:00.920Z", + "details": { + "method": "POST", + "path": "/mcp", + "body": { + "method": "initialize", + "params": { + "protocolVersion": "2025-11-25", + "capabilities": {}, + "clientInfo": { + "name": "eventrelay-conformance-client", + "version": "1.0.0" + } + }, + "jsonrpc": "2.0", + "id": 0 + }, + "mcpMethod": "initialize" + } + }, + { + "id": "valid-bearer-token", + "name": "ValidBearerToken", + "description": "Client provided valid bearer token", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:00.920Z", + "specReferences": [ + { + "id": "MCP-Access-token-usage", + "url": "https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization#access-token-usage" + } + ], + "details": { + "token": "test-token-1788...", + "scopes": [] + } + }, + { + "id": "outgoing-response", + "name": "Outgoing-response", + "description": "Sent 400 response for POST /mcp (method: initialize)", + "status": "INFO", + "timestamp": "2026-09-08T23:48:00.920Z", + "details": { + "method": "POST", + "path": "/mcp", + "statusCode": 400, + "mcpMethod": "initialize", + "headers": { + "x-powered-by": "Express", + "content-type": "application/json; charset=utf-8", + "content-length": "96", + "etag": "W/\"60-+I3pGWaBJPzWK/0N3EGEE0YM2QY\"" + }, + "body": { + "jsonrpc": "2.0", + "id": 0, + "error": { + "code": -32020, + "message": "Missing MCP-Protocol-Version header" + } + } + } + }, + { + "id": "resource-parameter-in-authorization", + "name": "Resource parameter in authorization request", + "description": "Client included resource parameter in authorization request", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:00.942Z", + "specReferences": [ + { + "id": "RFC-8707-Resource-Indicators", + "url": "https://www.rfc-editor.org/rfc/rfc8707.html" + }, + { + "id": "MCP-Resource-Parameter-Implementation", + "url": "https://modelcontextprotocol.io/specification/draft/basic/authorization#resource-parameter-implementation" + } + ], + "details": { + "resource": "http://localhost:46773/mcp" + } + }, + { + "id": "resource-parameter-in-token", + "name": "Resource parameter in token request", + "description": "Client included resource parameter in token request", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:00.942Z", + "specReferences": [ + { + "id": "RFC-8707-Resource-Indicators", + "url": "https://www.rfc-editor.org/rfc/rfc8707.html" + }, + { + "id": "MCP-Resource-Parameter-Implementation", + "url": "https://modelcontextprotocol.io/specification/draft/basic/authorization#resource-parameter-implementation" + } + ], + "details": { + "resource": "http://localhost:46773/mcp" + } + }, + { + "id": "resource-parameter-valid-uri", + "name": "Resource parameter is valid canonical URI", + "description": "Resource parameter is a valid canonical URI (has scheme, no fragment)", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:00.942Z", + "specReferences": [ + { + "id": "RFC-8707-Resource-Indicators", + "url": "https://www.rfc-editor.org/rfc/rfc8707.html" + }, + { + "id": "MCP-Resource-Parameter-Implementation", + "url": "https://modelcontextprotocol.io/specification/draft/basic/authorization#resource-parameter-implementation" + } + ], + "details": { + "resource": "http://localhost:46773/mcp" + } + }, + { + "id": "resource-parameter-consistency", + "name": "Resource parameter consistency", + "description": "Resource parameter is consistent between authorization and token requests", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:00.942Z", + "specReferences": [ + { + "id": "RFC-8707-Resource-Indicators", + "url": "https://www.rfc-editor.org/rfc/rfc8707.html" + }, + { + "id": "MCP-Resource-Parameter-Implementation", + "url": "https://modelcontextprotocol.io/specification/draft/basic/authorization#resource-parameter-implementation" + } + ], + "details": { + "authorizationResource": "http://localhost:46773/mcp", + "tokenResource": "http://localhost:46773/mcp" + } + }, + { + "id": "resource-parameter-matches-prm", + "name": "Resource parameter matches protected resource metadata", + "description": "Client sent the resource identifier exactly as published in protected resource metadata", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:00.942Z", + "specReferences": [ + { + "id": "RFC-8707-Resource-Indicators", + "url": "https://www.rfc-editor.org/rfc/rfc8707.html" + }, + { + "id": "MCP-Resource-Parameter-Implementation", + "url": "https://modelcontextprotocol.io/specification/draft/basic/authorization#resource-parameter-implementation" + }, + { + "id": "MCP-Canonical-Server-URI", + "url": "https://modelcontextprotocol.io/specification/draft/basic/authorization#canonical-server-uri" + }, + { + "id": "RFC-9728-resource-identity", + "url": "https://www.rfc-editor.org/rfc/rfc9728.html#section-3.3" + } + ], + "details": { + "prmResource": "http://localhost:46773/mcp", + "authorizationResource": "http://localhost:46773/mcp", + "tokenResource": "http://localhost:46773/mcp" + } + } + ], + "stdout": "", + "stderr": "Starting scenario: auth/token-endpoint-auth-basic\nExecuting client: node /home/runner/work/EventRelay/EventRelay/tests/testing/official_mcp_auth_client.mjs http://localhost:46773/mcp\n(node:9098) [DEP0190] DeprecationWarning: Passing args to a child process with shell option true can lead to security vulnerabilities, as the arguments are not escaped, only concatenated.\n(Use `node --trace-deprecation ...` to show where the warning was created)\n\nClient exited with code 1\n\nStderr:\nError: Streamable HTTP error: Error POSTing to endpoint: {\"jsonrpc\":\"2.0\",\"id\":0,\"error\":{\"code\":-32020,\"message\":\"Missing MCP-Protocol-Version header\"}}\n at StreamableHTTPClientTransport.send (file:///home/runner/work/EventRelay/EventRelay/node_modules/@modelcontextprotocol/sdk/dist/esm/client/streamableHttp.js:365:23)\n at process.processTicksAndRejections (node:internal/process/task_queues:104:5)\n\nResults saved to /tmp/mcp-conformance-client-ybhcaa65/auth/token-endpoint-auth-basic-2026-09-08T23-48-00-630Z\nChecks:\n\u001b[90m2026-09-08T23:48:00.871Z\u001b[0m [incoming-request ] \u001b[36mINFO \u001b[0m Received POST request for /mcp (method: initialize)\n\u001b[90m2026-09-08T23:48:00.873Z\u001b[0m [outgoing-response ] \u001b[36mINFO \u001b[0m Sent 401 response for POST /mcp (method: initialize)\n\n\u001b[90m2026-09-08T23:48:00.881Z\u001b[0m [incoming-request ] \u001b[36mINFO \u001b[0m Received GET request for /.well-known/oauth-protected-resource/mcp\n\u001b[90m2026-09-08T23:48:00.881Z\u001b[0m [prm-pathbased-requested ] \u001b[32mSUCCESS\u001b[0m Client requested PRM metadata at path-based location\n\u001b[90m2026-09-08T23:48:00.882Z\u001b[0m [outgoing-response ] \u001b[36mINFO \u001b[0m Sent 200 response for GET /.well-known/oauth-protected-resource/mcp\n\n\u001b[90m2026-09-08T23:48:00.889Z\u001b[0m [incoming-auth-request ] \u001b[36mINFO \u001b[0m Received GET request for /.well-known/oauth-authorization-server\n\u001b[90m2026-09-08T23:48:00.889Z\u001b[0m [authorization-server-metadata ] \u001b[32mSUCCESS\u001b[0m Client requested authorization server metadata\n\u001b[90m2026-09-08T23:48:00.889Z\u001b[0m [outgoing-auth-response ] \u001b[36mINFO \u001b[0m Sent 200 response for GET /.well-known/oauth-authorization-server\n\n\u001b[90m2026-09-08T23:48:00.894Z\u001b[0m [incoming-auth-request ] \u001b[36mINFO \u001b[0m Received POST request for /register\n\u001b[90m2026-09-08T23:48:00.894Z\u001b[0m [client-registration ] \u001b[32mSUCCESS\u001b[0m Client registered with authorization server\n\u001b[90m2026-09-08T23:48:00.894Z\u001b[0m [sep-837-application-type-present ] \u001b[32mSUCCESS\u001b[0m Client specified application_type \"native\" during Dynamic Client Registration\n\u001b[90m2026-09-08T23:48:00.894Z\u001b[0m [outgoing-auth-response ] \u001b[36mINFO \u001b[0m Sent 201 response for POST /register\n\n\u001b[90m2026-09-08T23:48:00.901Z\u001b[0m [incoming-auth-request ] \u001b[36mINFO \u001b[0m Received GET request for /authorize\n\u001b[90m2026-09-08T23:48:00.901Z\u001b[0m [authorization-request ] \u001b[32mSUCCESS\u001b[0m Client made authorization request\n\u001b[90m2026-09-08T23:48:00.901Z\u001b[0m [pkce-code-challenge-sent ] \u001b[32mSUCCESS\u001b[0m Client sent code_challenge in authorization request\n\u001b[90m2026-09-08T23:48:00.901Z\u001b[0m [pkce-s256-method-used ] \u001b[32mSUCCESS\u001b[0m Client used S256 code challenge method\n\u001b[90m2026-09-08T23:48:00.903Z\u001b[0m [outgoing-auth-response ] \u001b[36mINFO \u001b[0m Sent 302 response for GET /authorize\n\n\u001b[90m2026-09-08T23:48:00.906Z\u001b[0m [incoming-request ] \u001b[36mINFO \u001b[0m Received GET request for /.well-known/oauth-protected-resource/mcp\n\u001b[90m2026-09-08T23:48:00.906Z\u001b[0m [prm-pathbased-requested ] \u001b[32mSUCCESS\u001b[0m Client requested PRM metadata at path-based location\n\u001b[90m2026-09-08T23:48:00.906Z\u001b[0m [outgoing-response ] \u001b[36mINFO \u001b[0m Sent 200 response for GET /.well-known/oauth-protected-resource/mcp\n\n\u001b[90m2026-09-08T23:48:00.909Z\u001b[0m [incoming-auth-request ] \u001b[36mINFO \u001b[0m Received GET request for /.well-known/oauth-authorization-server\n...[truncated]" + }, + { + "leg": "client", + "scenario": "auth/token-endpoint-auth-post", + "spec_version": "2026-07-28", + "required": true, + "exit_code": 1, + "summary": { + "ok": true, + "counts": { + "INFO": 18, + "SUCCESS": 19 + }, + "blocking": [] + }, + "warnings": [], + "failures": [], + "checks": [ + { + "id": "incoming-request", + "name": "Incoming-request", + "description": "Received POST request for /mcp (method: initialize)", + "status": "INFO", + "timestamp": "2026-09-08T23:48:07.740Z", + "details": { + "method": "POST", + "path": "/mcp", + "body": { + "method": "initialize", + "params": { + "protocolVersion": "2025-11-25", + "capabilities": {}, + "clientInfo": { + "name": "eventrelay-conformance-client", + "version": "1.0.0" + } + }, + "jsonrpc": "2.0", + "id": 0 + }, + "mcpMethod": "initialize" + } + }, + { + "id": "outgoing-response", + "name": "Outgoing-response", + "description": "Sent 401 response for POST /mcp (method: initialize)", + "status": "INFO", + "timestamp": "2026-09-08T23:48:07.742Z", + "details": { + "method": "POST", + "path": "/mcp", + "statusCode": 401, + "mcpMethod": "initialize", + "headers": { + "x-powered-by": "Express", + "www-authenticate": "Bearer error=\"invalid_token\", error_description=\"Missing Authorization header\", resource_metadata=\"http://localhost:37701/.well-known/oauth-protected-resource/mcp\"", + "content-type": "application/json; charset=utf-8", + "content-length": "76", + "etag": "W/\"4c-ptrIdu+3yjAtarglCEu6XVLnz2c\"" + }, + "body": { + "error": "invalid_token", + "error_description": "Missing Authorization header" + } + } + }, + { + "id": "incoming-request", + "name": "Incoming-request", + "description": "Received GET request for /.well-known/oauth-protected-resource/mcp", + "status": "INFO", + "timestamp": "2026-09-08T23:48:07.750Z", + "details": { + "method": "GET", + "path": "/.well-known/oauth-protected-resource/mcp" + } + }, + { + "id": "prm-pathbased-requested", + "name": "PRMPathBasedRequested", + "description": "Client requested PRM metadata at path-based location", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:07.750Z", + "specReferences": [ + { + "id": "RFC-9728", + "url": "https://www.rfc-editor.org/rfc/rfc9728.html#section-3.1" + }, + { + "id": "MCP-2025-06-18-PRM-discovery", + "url": "https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization#protected-resource-metadata-discovery-requirements" + } + ], + "details": { + "url": "/.well-known/oauth-protected-resource/mcp", + "path": "/.well-known/oauth-protected-resource/mcp" + } + }, + { + "id": "outgoing-response", + "name": "Outgoing-response", + "description": "Sent 200 response for GET /.well-known/oauth-protected-resource/mcp", + "status": "INFO", + "timestamp": "2026-09-08T23:48:07.750Z", + "details": { + "method": "GET", + "path": "/.well-known/oauth-protected-resource/mcp", + "statusCode": 200, + "headers": { + "x-powered-by": "Express", + "content-type": "application/json; charset=utf-8", + "content-length": "92", + "etag": "W/\"5c-C7XxNF7ajKtlbHEWi6KE7b2JNd0\"" + }, + "body": { + "resource": "http://localhost:37701/mcp", + "authorization_servers": [ + "http://localhost:36515" + ] + } + } + }, + { + "id": "incoming-auth-request", + "name": "Incoming-auth-request", + "description": "Received GET request for /.well-known/oauth-authorization-server", + "status": "INFO", + "timestamp": "2026-09-08T23:48:07.756Z", + "details": { + "method": "GET", + "path": "/.well-known/oauth-authorization-server" + } + }, + { + "id": "authorization-server-metadata", + "name": "AuthorizationServerMetadata", + "description": "Client requested authorization server metadata", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:07.756Z", + "specReferences": [ + { + "id": "RFC-8414-metadata-request", + "url": "https://www.rfc-editor.org/rfc/rfc8414.html#section-3.1" + }, + { + "id": "MCP-Authorization-metadata-discovery", + "url": "https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization#authorization-server-metadata-discovery" + } + ], + "details": { + "url": "/.well-known/oauth-authorization-server", + "path": "/.well-known/oauth-authorization-server" + } + }, + { + "id": "outgoing-auth-response", + "name": "Outgoing-auth-response", + "description": "Sent 200 response for GET /.well-known/oauth-authorization-server", + "status": "INFO", + "timestamp": "2026-09-08T23:48:07.756Z", + "details": { + "method": "GET", + "path": "/.well-known/oauth-authorization-server", + "statusCode": 200, + "headers": { + "x-powered-by": "Express", + "content-type": "application/json; charset=utf-8", + "content-length": "461", + "etag": "W/\"1cd-SrMitvotKUUgAgF8X5XJ2Z12/BM\"" + }, + "body": { + "issuer": "http://localhost:36515", + "authorization_endpoint": "http://localhost:36515/authorize", + "token_endpoint": "http://localhost:36515/token", + "registration_endpoint": "http://localhost:36515/register", + "response_types_supported": [ + "code" + ], + "grant_types_supported": [ + "authorization_code", + "refresh_token" + ], + "code_challenge_methods_supported": [ + "S256" + ], + "authorization_response_iss_parameter_supported": true, + "token_endpoint_auth_methods_supported": [ + "client_secret_post" + ] + } + } + }, + { + "id": "incoming-auth-request", + "name": "Incoming-auth-request", + "description": "Received POST request for /register", + "status": "INFO", + "timestamp": "2026-09-08T23:48:07.760Z", + "details": { + "method": "POST", + "path": "/register", + "body": { + "client_name": "eventrelay-conformance-client", + "redirect_uris": [ + "http://localhost:3000/callback" + ], + "application_type": "native" + } + } + }, + { + "id": "client-registration", + "name": "ClientRegistration", + "description": "Client registered with authorization server", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:07.761Z", + "specReferences": [ + { + "id": "MCP-Dynamic-client-registration", + "url": "https://modelcontextprotocol.io/specification/2025-11-25/basic/client#dynamic-client-registration" + } + ], + "details": { + "endpoint": "/register", + "clientName": "eventrelay-conformance-client", + "tokenEndpointAuthMethod": "client_secret_post" + } + }, + { + "id": "sep-837-application-type-present", + "name": "DCR application_type specified", + "description": "Client specified application_type \"native\" during Dynamic Client Registration", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:07.761Z", + "specReferences": [ + { + "id": "MCP-Dynamic-client-registration", + "url": "https://modelcontextprotocol.io/specification/2025-11-25/basic/client#dynamic-client-registration" + } + ], + "details": { + "application_type": "native" + } + }, + { + "id": "outgoing-auth-response", + "name": "Outgoing-auth-response", + "description": "Sent 201 response for POST /register", + "status": "INFO", + "timestamp": "2026-09-08T23:48:07.761Z", + "details": { + "method": "POST", + "path": "/register", + "statusCode": 201, + "headers": { + "x-powered-by": "Express", + "content-type": "application/json; charset=utf-8", + "content-length": "232", + "etag": "W/\"e8-rhs0/Ro6/zXeYVE266AFInGsWOM\"" + }, + "body": { + "client_id": "test-client-1788911287761", + "client_secret": "test-secret-1788911287761", + "client_name": "eventrelay-conformance-client", + "redirect_uris": [ + "http://localhost:3000/callback" + ], + "token_endpoint_auth_method": "client_secret_post" + } + } + }, + { + "id": "incoming-auth-request", + "name": "Incoming-auth-request", + "description": "Received GET request for /authorize", + "status": "INFO", + "timestamp": "2026-09-08T23:48:07.766Z", + "details": { + "method": "GET", + "path": "/authorize", + "query": { + "response_type": "code", + "client_id": "test-client-1788911287761", + "code_challenge": "lgsClOFknwdzLkEex3eiHAcVBRHgWJG0OETu2RhfQ5g", + "code_challenge_method": "S256", + "redirect_uri": "http://localhost:3000/callback", + "resource": "http://localhost:37701/mcp" + } + } + }, + { + "id": "authorization-request", + "name": "AuthorizationRequest", + "description": "Client made authorization request", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:07.767Z", + "specReferences": [ + { + "id": "OAUTH-2.1-authorization-endpoint", + "url": "https://www.ietf.org/archive/id/draft-ietf-oauth-v2-1-13.html#name-authorization-endpoint" + } + ], + "details": { + "query": { + "response_type": "code", + "client_id": "test-client-1788911287761", + "code_challenge": "lgsClOFknwdzLkEex3eiHAcVBRHgWJG0OETu2RhfQ5g", + "code_challenge_method": "S256", + "redirect_uri": "http://localhost:3000/callback", + "resource": "http://localhost:37701/mcp" + } + } + }, + { + "id": "pkce-code-challenge-sent", + "name": "PKCE Code Challenge", + "description": "Client sent code_challenge in authorization request", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:07.767Z", + "specReferences": [ + { + "id": "MCP-PKCE-requirement", + "url": "https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization#authorization-code-protection" + } + ] + }, + { + "id": "pkce-s256-method-used", + "name": "PKCE S256 Method", + "description": "Client used S256 code challenge method", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:07.767Z", + "specReferences": [ + { + "id": "MCP-PKCE-requirement", + "url": "https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization#authorization-code-protection" + } + ], + "details": { + "method": "S256" + } + }, + { + "id": "outgoing-auth-response", + "name": "Outgoing-auth-response", + "description": "Sent 302 response for GET /authorize", + "status": "INFO", + "timestamp": "2026-09-08T23:48:07.769Z", + "details": { + "method": "GET", + "path": "/authorize", + "statusCode": 302, + "headers": { + "x-powered-by": "Express", + "location": "http://localhost:3000/callback?code=test-auth-code&iss=http%3A%2F%2Flocalhost%3A36515", + "vary": "Accept", + "content-type": "text/plain; charset=utf-8", + "content-length": "107" + }, + "body": "Found. Redirecting to http://localhost:3000/callback?code=test-auth-code&iss=http%3A%2F%2Flocalhost%3A36515" + } + }, + { + "id": "incoming-request", + "name": "Incoming-request", + "description": "Received GET request for /.well-known/oauth-protected-resource/mcp", + "status": "INFO", + "timestamp": "2026-09-08T23:48:07.771Z", + "details": { + "method": "GET", + "path": "/.well-known/oauth-protected-resource/mcp" + } + }, + { + "id": "prm-pathbased-requested", + "name": "PRMPathBasedRequested", + "description": "Client requested PRM metadata at path-based location", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:07.771Z", + "specReferences": [ + { + "id": "RFC-9728", + "url": "https://www.rfc-editor.org/rfc/rfc9728.html#section-3.1" + }, + { + "id": "MCP-2025-06-18-PRM-discovery", + "url": "https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization#protected-resource-metadata-discovery-requirements" + } + ], + "details": { + "url": "/.well-known/oauth-protected-resource/mcp", + "path": "/.well-known/oauth-protected-resource/mcp" + } + }, + { + "id": "outgoing-response", + "name": "Outgoing-response", + "description": "Sent 200 response for GET /.well-known/oauth-protected-resource/mcp", + "status": "INFO", + "timestamp": "2026-09-08T23:48:07.771Z", + "details": { + "method": "GET", + "path": "/.well-known/oauth-protected-resource/mcp", + "statusCode": 200, + "headers": { + "x-powered-by": "Express", + "content-type": "application/json; charset=utf-8", + "content-length": "92", + "etag": "W/\"5c-C7XxNF7ajKtlbHEWi6KE7b2JNd0\"" + }, + "body": { + "resource": "http://localhost:37701/mcp", + "authorization_servers": [ + "http://localhost:36515" + ] + } + } + }, + { + "id": "incoming-auth-request", + "name": "Incoming-auth-request", + "description": "Received GET request for /.well-known/oauth-authorization-server", + "status": "INFO", + "timestamp": "2026-09-08T23:48:07.774Z", + "details": { + "method": "GET", + "path": "/.well-known/oauth-authorization-server" + } + }, + { + "id": "authorization-server-metadata", + "name": "AuthorizationServerMetadata", + "description": "Client requested authorization server metadata", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:07.774Z", + "specReferences": [ + { + "id": "RFC-8414-metadata-request", + "url": "https://www.rfc-editor.org/rfc/rfc8414.html#section-3.1" + }, + { + "id": "MCP-Authorization-metadata-discovery", + "url": "https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization#authorization-server-metadata-discovery" + } + ], + "details": { + "url": "/.well-known/oauth-authorization-server", + "path": "/.well-known/oauth-authorization-server" + } + }, + { + "id": "outgoing-auth-response", + "name": "Outgoing-auth-response", + "description": "Sent 200 response for GET /.well-known/oauth-authorization-server", + "status": "INFO", + "timestamp": "2026-09-08T23:48:07.774Z", + "details": { + "method": "GET", + "path": "/.well-known/oauth-authorization-server", + "statusCode": 200, + "headers": { + "x-powered-by": "Express", + "content-type": "application/json; charset=utf-8", + "content-length": "461", + "etag": "W/\"1cd-SrMitvotKUUgAgF8X5XJ2Z12/BM\"" + }, + "body": { + "issuer": "http://localhost:36515", + "authorization_endpoint": "http://localhost:36515/authorize", + "token_endpoint": "http://localhost:36515/token", + "registration_endpoint": "http://localhost:36515/register", + "response_types_supported": [ + "code" + ], + "grant_types_supported": [ + "authorization_code", + "refresh_token" + ], + "code_challenge_methods_supported": [ + "S256" + ], + "authorization_response_iss_parameter_supported": true, + "token_endpoint_auth_methods_supported": [ + "client_secret_post" + ] + } + } + }, + { + "id": "incoming-auth-request", + "name": "Incoming-auth-request", + "description": "Received POST request for /token", + "status": "INFO", + "timestamp": "2026-09-08T23:48:07.779Z", + "details": { + "method": "POST", + "path": "/token", + "body": { + "grant_type": "authorization_code", + "code": "test-auth-code", + "code_verifier": "lF12WMKnAdGDig.DJGL5Fmw6bX8xUWA3J5LA6M2nC8r", + "redirect_uri": "http://localhost:3000/callback", + "resource": "http://localhost:37701/mcp", + "client_id": "test-client-1788911287761", + "client_secret": "test-secret-1788911287761" + } + } + }, + { + "id": "token-request", + "name": "TokenRequest", + "description": "Client requested access token", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:07.779Z", + "specReferences": [ + { + "id": "OAUTH-2.1-token-request", + "url": "https://www.ietf.org/archive/id/draft-ietf-oauth-v2-1-13.html#name-token-request" + } + ], + "details": { + "endpoint": "/token", + "grantType": "authorization_code" + } + }, + { + "id": "pkce-code-verifier-sent", + "name": "PKCE Code Verifier", + "description": "Client sent code_verifier in token request", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:07.779Z", + "specReferences": [ + { + "id": "MCP-PKCE-requirement", + "url": "https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization#authorization-code-protection" + } + ] + }, + { + "id": "pkce-verifier-matches-challenge", + "name": "PKCE Verifier Validation", + "description": "code_verifier correctly matches code_challenge (S256)", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:07.779Z", + "specReferences": [ + { + "id": "MCP-PKCE-requirement", + "url": "https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization#authorization-code-protection" + } + ], + "details": { + "matches": true, + "storedChallenge": "lgsClOFknwdzLkEex3eiHAcVBRHgWJG0OETu2RhfQ5g", + "computedChallenge": "lgsClOFknwdzLkEex3eiHAcVBRHgWJG0OETu2RhfQ5g" + } + }, + { + "id": "token-endpoint-auth-method", + "name": "Token endpoint authentication method", + "description": "Client correctly used client_secret_post for token endpoint", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:07.779Z", + "specReferences": [ + { + "id": "OAUTH-2.1-token-request", + "url": "https://www.ietf.org/archive/id/draft-ietf-oauth-v2-1-13.html#name-token-request" + } + ], + "details": { + "expectedAuthMethod": "client_secret_post", + "actualAuthMethod": "client_secret_post", + "hasAuthorizationHeader": false, + "hasBodyClientSecret": true + } + }, + { + "id": "outgoing-auth-response", + "name": "Outgoing-auth-response", + "description": "Sent 200 response for POST /token", + "status": "INFO", + "timestamp": "2026-09-08T23:48:07.780Z", + "details": { + "method": "POST", + "path": "/token", + "statusCode": 200, + "headers": { + "x-powered-by": "Express", + "content-type": "application/json; charset=utf-8", + "content-length": "83", + "etag": "W/\"53-UjQCRLONv34AYg0bXNjYul+Lw9w\"" + }, + "body": { + "access_token": "test-token-1788911287780", + "token_type": "Bearer", + "expires_in": 3600 + } + } + }, + { + "id": "incoming-request", + "name": "Incoming-request", + "description": "Received POST request for /mcp (method: initialize)", + "status": "INFO", + "timestamp": "2026-09-08T23:48:07.783Z", + "details": { + "method": "POST", + "path": "/mcp", + "body": { + "method": "initialize", + "params": { + "protocolVersion": "2025-11-25", + "capabilities": {}, + "clientInfo": { + "name": "eventrelay-conformance-client", + "version": "1.0.0" + } + }, + "jsonrpc": "2.0", + "id": 0 + }, + "mcpMethod": "initialize" + } + }, + { + "id": "valid-bearer-token", + "name": "ValidBearerToken", + "description": "Client provided valid bearer token", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:07.783Z", + "specReferences": [ + { + "id": "MCP-Access-token-usage", + "url": "https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization#access-token-usage" + } + ], + "details": { + "token": "test-token-1788...", + "scopes": [] + } + }, + { + "id": "outgoing-response", + "name": "Outgoing-response", + "description": "Sent 400 response for POST /mcp (method: initialize)", + "status": "INFO", + "timestamp": "2026-09-08T23:48:07.784Z", + "details": { + "method": "POST", + "path": "/mcp", + "statusCode": 400, + "mcpMethod": "initialize", + "headers": { + "x-powered-by": "Express", + "content-type": "application/json; charset=utf-8", + "content-length": "96", + "etag": "W/\"60-+I3pGWaBJPzWK/0N3EGEE0YM2QY\"" + }, + "body": { + "jsonrpc": "2.0", + "id": 0, + "error": { + "code": -32020, + "message": "Missing MCP-Protocol-Version header" + } + } + } + }, + { + "id": "resource-parameter-in-authorization", + "name": "Resource parameter in authorization request", + "description": "Client included resource parameter in authorization request", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:07.805Z", + "specReferences": [ + { + "id": "RFC-8707-Resource-Indicators", + "url": "https://www.rfc-editor.org/rfc/rfc8707.html" + }, + { + "id": "MCP-Resource-Parameter-Implementation", + "url": "https://modelcontextprotocol.io/specification/draft/basic/authorization#resource-parameter-implementation" + } + ], + "details": { + "resource": "http://localhost:37701/mcp" + } + }, + { + "id": "resource-parameter-in-token", + "name": "Resource parameter in token request", + "description": "Client included resource parameter in token request", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:07.805Z", + "specReferences": [ + { + "id": "RFC-8707-Resource-Indicators", + "url": "https://www.rfc-editor.org/rfc/rfc8707.html" + }, + { + "id": "MCP-Resource-Parameter-Implementation", + "url": "https://modelcontextprotocol.io/specification/draft/basic/authorization#resource-parameter-implementation" + } + ], + "details": { + "resource": "http://localhost:37701/mcp" + } + }, + { + "id": "resource-parameter-valid-uri", + "name": "Resource parameter is valid canonical URI", + "description": "Resource parameter is a valid canonical URI (has scheme, no fragment)", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:07.805Z", + "specReferences": [ + { + "id": "RFC-8707-Resource-Indicators", + "url": "https://www.rfc-editor.org/rfc/rfc8707.html" + }, + { + "id": "MCP-Resource-Parameter-Implementation", + "url": "https://modelcontextprotocol.io/specification/draft/basic/authorization#resource-parameter-implementation" + } + ], + "details": { + "resource": "http://localhost:37701/mcp" + } + }, + { + "id": "resource-parameter-consistency", + "name": "Resource parameter consistency", + "description": "Resource parameter is consistent between authorization and token requests", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:07.805Z", + "specReferences": [ + { + "id": "RFC-8707-Resource-Indicators", + "url": "https://www.rfc-editor.org/rfc/rfc8707.html" + }, + { + "id": "MCP-Resource-Parameter-Implementation", + "url": "https://modelcontextprotocol.io/specification/draft/basic/authorization#resource-parameter-implementation" + } + ], + "details": { + "authorizationResource": "http://localhost:37701/mcp", + "tokenResource": "http://localhost:37701/mcp" + } + }, + { + "id": "resource-parameter-matches-prm", + "name": "Resource parameter matches protected resource metadata", + "description": "Client sent the resource identifier exactly as published in protected resource metadata", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:07.805Z", + "specReferences": [ + { + "id": "RFC-8707-Resource-Indicators", + "url": "https://www.rfc-editor.org/rfc/rfc8707.html" + }, + { + "id": "MCP-Resource-Parameter-Implementation", + "url": "https://modelcontextprotocol.io/specification/draft/basic/authorization#resource-parameter-implementation" + }, + { + "id": "MCP-Canonical-Server-URI", + "url": "https://modelcontextprotocol.io/specification/draft/basic/authorization#canonical-server-uri" + }, + { + "id": "RFC-9728-resource-identity", + "url": "https://www.rfc-editor.org/rfc/rfc9728.html#section-3.3" + } + ], + "details": { + "prmResource": "http://localhost:37701/mcp", + "authorizationResource": "http://localhost:37701/mcp", + "tokenResource": "http://localhost:37701/mcp" + } + } + ], + "stdout": "", + "stderr": "Starting scenario: auth/token-endpoint-auth-post\nExecuting client: node /home/runner/work/EventRelay/EventRelay/tests/testing/official_mcp_auth_client.mjs http://localhost:37701/mcp\n(node:9240) [DEP0190] DeprecationWarning: Passing args to a child process with shell option true can lead to security vulnerabilities, as the arguments are not escaped, only concatenated.\n(Use `node --trace-deprecation ...` to show where the warning was created)\n\nClient exited with code 1\n\nStderr:\nError: Streamable HTTP error: Error POSTing to endpoint: {\"jsonrpc\":\"2.0\",\"id\":0,\"error\":{\"code\":-32020,\"message\":\"Missing MCP-Protocol-Version header\"}}\n at StreamableHTTPClientTransport.send (file:///home/runner/work/EventRelay/EventRelay/node_modules/@modelcontextprotocol/sdk/dist/esm/client/streamableHttp.js:365:23)\n at process.processTicksAndRejections (node:internal/process/task_queues:104:5)\n\nResults saved to /tmp/mcp-conformance-client-wkenofd6/auth/token-endpoint-auth-post-2026-09-08T23-48-07-491Z\nChecks:\n\u001b[90m2026-09-08T23:48:07.740Z\u001b[0m [incoming-request ] \u001b[36mINFO \u001b[0m Received POST request for /mcp (method: initialize)\n\u001b[90m2026-09-08T23:48:07.742Z\u001b[0m [outgoing-response ] \u001b[36mINFO \u001b[0m Sent 401 response for POST /mcp (method: initialize)\n\n\u001b[90m2026-09-08T23:48:07.750Z\u001b[0m [incoming-request ] \u001b[36mINFO \u001b[0m Received GET request for /.well-known/oauth-protected-resource/mcp\n\u001b[90m2026-09-08T23:48:07.750Z\u001b[0m [prm-pathbased-requested ] \u001b[32mSUCCESS\u001b[0m Client requested PRM metadata at path-based location\n\u001b[90m2026-09-08T23:48:07.750Z\u001b[0m [outgoing-response ] \u001b[36mINFO \u001b[0m Sent 200 response for GET /.well-known/oauth-protected-resource/mcp\n\n\u001b[90m2026-09-08T23:48:07.756Z\u001b[0m [incoming-auth-request ] \u001b[36mINFO \u001b[0m Received GET request for /.well-known/oauth-authorization-server\n\u001b[90m2026-09-08T23:48:07.756Z\u001b[0m [authorization-server-metadata ] \u001b[32mSUCCESS\u001b[0m Client requested authorization server metadata\n\u001b[90m2026-09-08T23:48:07.756Z\u001b[0m [outgoing-auth-response ] \u001b[36mINFO \u001b[0m Sent 200 response for GET /.well-known/oauth-authorization-server\n\n\u001b[90m2026-09-08T23:48:07.760Z\u001b[0m [incoming-auth-request ] \u001b[36mINFO \u001b[0m Received POST request for /register\n\u001b[90m2026-09-08T23:48:07.761Z\u001b[0m [client-registration ] \u001b[32mSUCCESS\u001b[0m Client registered with authorization server\n\u001b[90m2026-09-08T23:48:07.761Z\u001b[0m [sep-837-application-type-present ] \u001b[32mSUCCESS\u001b[0m Client specified application_type \"native\" during Dynamic Client Registration\n\u001b[90m2026-09-08T23:48:07.761Z\u001b[0m [outgoing-auth-response ] \u001b[36mINFO \u001b[0m Sent 201 response for POST /register\n\n\u001b[90m2026-09-08T23:48:07.766Z\u001b[0m [incoming-auth-request ] \u001b[36mINFO \u001b[0m Received GET request for /authorize\n\u001b[90m2026-09-08T23:48:07.767Z\u001b[0m [authorization-request ] \u001b[32mSUCCESS\u001b[0m Client made authorization request\n\u001b[90m2026-09-08T23:48:07.767Z\u001b[0m [pkce-code-challenge-sent ] \u001b[32mSUCCESS\u001b[0m Client sent code_challenge in authorization request\n\u001b[90m2026-09-08T23:48:07.767Z\u001b[0m [pkce-s256-method-used ] \u001b[32mSUCCESS\u001b[0m Client used S256 code challenge method\n\u001b[90m2026-09-08T23:48:07.769Z\u001b[0m [outgoing-auth-response ] \u001b[36mINFO \u001b[0m Sent 302 response for GET /authorize\n\n\u001b[90m2026-09-08T23:48:07.771Z\u001b[0m [incoming-request ] \u001b[36mINFO \u001b[0m Received GET request for /.well-known/oauth-protected-resource/mcp\n\u001b[90m2026-09-08T23:48:07.771Z\u001b[0m [prm-pathbased-requested ] \u001b[32mSUCCESS\u001b[0m Client requested PRM metadata at path-based location\n\u001b[90m2026-09-08T23:48:07.771Z\u001b[0m [outgoing-response ] \u001b[36mINFO \u001b[0m Sent 200 response for GET /.well-known/oauth-protected-resource/mcp\n\n\u001b[90m2026-09-08T23:48:07.774Z\u001b[0m [incoming-auth-request ] \u001b[36mINFO \u001b[0m Received GET request for /.well-known/oauth-authorization-server\n\u001b\n...[truncated]" + }, + { + "leg": "client", + "scenario": "auth/token-endpoint-auth-none", + "spec_version": "2026-07-28", + "required": true, + "exit_code": 1, + "summary": { + "ok": true, + "counts": { + "INFO": 18, + "SUCCESS": 19 + }, + "blocking": [] + }, + "warnings": [], + "failures": [], + "checks": [ + { + "id": "incoming-request", + "name": "Incoming-request", + "description": "Received POST request for /mcp (method: initialize)", + "status": "INFO", + "timestamp": "2026-09-08T23:48:14.512Z", + "details": { + "method": "POST", + "path": "/mcp", + "body": { + "method": "initialize", + "params": { + "protocolVersion": "2025-11-25", + "capabilities": {}, + "clientInfo": { + "name": "eventrelay-conformance-client", + "version": "1.0.0" + } + }, + "jsonrpc": "2.0", + "id": 0 + }, + "mcpMethod": "initialize" + } + }, + { + "id": "outgoing-response", + "name": "Outgoing-response", + "description": "Sent 401 response for POST /mcp (method: initialize)", + "status": "INFO", + "timestamp": "2026-09-08T23:48:14.514Z", + "details": { + "method": "POST", + "path": "/mcp", + "statusCode": 401, + "mcpMethod": "initialize", + "headers": { + "x-powered-by": "Express", + "www-authenticate": "Bearer error=\"invalid_token\", error_description=\"Missing Authorization header\", resource_metadata=\"http://localhost:40991/.well-known/oauth-protected-resource/mcp\"", + "content-type": "application/json; charset=utf-8", + "content-length": "76", + "etag": "W/\"4c-ptrIdu+3yjAtarglCEu6XVLnz2c\"" + }, + "body": { + "error": "invalid_token", + "error_description": "Missing Authorization header" + } + } + }, + { + "id": "incoming-request", + "name": "Incoming-request", + "description": "Received GET request for /.well-known/oauth-protected-resource/mcp", + "status": "INFO", + "timestamp": "2026-09-08T23:48:14.522Z", + "details": { + "method": "GET", + "path": "/.well-known/oauth-protected-resource/mcp" + } + }, + { + "id": "prm-pathbased-requested", + "name": "PRMPathBasedRequested", + "description": "Client requested PRM metadata at path-based location", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:14.522Z", + "specReferences": [ + { + "id": "RFC-9728", + "url": "https://www.rfc-editor.org/rfc/rfc9728.html#section-3.1" + }, + { + "id": "MCP-2025-06-18-PRM-discovery", + "url": "https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization#protected-resource-metadata-discovery-requirements" + } + ], + "details": { + "url": "/.well-known/oauth-protected-resource/mcp", + "path": "/.well-known/oauth-protected-resource/mcp" + } + }, + { + "id": "outgoing-response", + "name": "Outgoing-response", + "description": "Sent 200 response for GET /.well-known/oauth-protected-resource/mcp", + "status": "INFO", + "timestamp": "2026-09-08T23:48:14.523Z", + "details": { + "method": "GET", + "path": "/.well-known/oauth-protected-resource/mcp", + "statusCode": 200, + "headers": { + "x-powered-by": "Express", + "content-type": "application/json; charset=utf-8", + "content-length": "92", + "etag": "W/\"5c-0feIEBn49XNTrDPIJoctcmJlPNI\"" + }, + "body": { + "resource": "http://localhost:40991/mcp", + "authorization_servers": [ + "http://localhost:37991" + ] + } + } + }, + { + "id": "incoming-auth-request", + "name": "Incoming-auth-request", + "description": "Received GET request for /.well-known/oauth-authorization-server", + "status": "INFO", + "timestamp": "2026-09-08T23:48:14.528Z", + "details": { + "method": "GET", + "path": "/.well-known/oauth-authorization-server" + } + }, + { + "id": "authorization-server-metadata", + "name": "AuthorizationServerMetadata", + "description": "Client requested authorization server metadata", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:14.528Z", + "specReferences": [ + { + "id": "RFC-8414-metadata-request", + "url": "https://www.rfc-editor.org/rfc/rfc8414.html#section-3.1" + }, + { + "id": "MCP-Authorization-metadata-discovery", + "url": "https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization#authorization-server-metadata-discovery" + } + ], + "details": { + "url": "/.well-known/oauth-authorization-server", + "path": "/.well-known/oauth-authorization-server" + } + }, + { + "id": "outgoing-auth-response", + "name": "Outgoing-auth-response", + "description": "Sent 200 response for GET /.well-known/oauth-authorization-server", + "status": "INFO", + "timestamp": "2026-09-08T23:48:14.529Z", + "details": { + "method": "GET", + "path": "/.well-known/oauth-authorization-server", + "statusCode": 200, + "headers": { + "x-powered-by": "Express", + "content-type": "application/json; charset=utf-8", + "content-length": "447", + "etag": "W/\"1bf-kgVsQRPY5+ql5p1GaRNOBLNGsFo\"" + }, + "body": { + "issuer": "http://localhost:37991", + "authorization_endpoint": "http://localhost:37991/authorize", + "token_endpoint": "http://localhost:37991/token", + "registration_endpoint": "http://localhost:37991/register", + "response_types_supported": [ + "code" + ], + "grant_types_supported": [ + "authorization_code", + "refresh_token" + ], + "code_challenge_methods_supported": [ + "S256" + ], + "authorization_response_iss_parameter_supported": true, + "token_endpoint_auth_methods_supported": [ + "none" + ] + } + } + }, + { + "id": "incoming-auth-request", + "name": "Incoming-auth-request", + "description": "Received POST request for /register", + "status": "INFO", + "timestamp": "2026-09-08T23:48:14.533Z", + "details": { + "method": "POST", + "path": "/register", + "body": { + "client_name": "eventrelay-conformance-client", + "redirect_uris": [ + "http://localhost:3000/callback" + ], + "application_type": "native" + } + } + }, + { + "id": "client-registration", + "name": "ClientRegistration", + "description": "Client registered with authorization server", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:14.533Z", + "specReferences": [ + { + "id": "MCP-Dynamic-client-registration", + "url": "https://modelcontextprotocol.io/specification/2025-11-25/basic/client#dynamic-client-registration" + } + ], + "details": { + "endpoint": "/register", + "clientName": "eventrelay-conformance-client", + "tokenEndpointAuthMethod": "none" + } + }, + { + "id": "sep-837-application-type-present", + "name": "DCR application_type specified", + "description": "Client specified application_type \"native\" during Dynamic Client Registration", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:14.533Z", + "specReferences": [ + { + "id": "MCP-Dynamic-client-registration", + "url": "https://modelcontextprotocol.io/specification/2025-11-25/basic/client#dynamic-client-registration" + } + ], + "details": { + "application_type": "native" + } + }, + { + "id": "outgoing-auth-response", + "name": "Outgoing-auth-response", + "description": "Sent 201 response for POST /register", + "status": "INFO", + "timestamp": "2026-09-08T23:48:14.533Z", + "details": { + "method": "POST", + "path": "/register", + "statusCode": 201, + "headers": { + "x-powered-by": "Express", + "content-type": "application/json; charset=utf-8", + "content-length": "174", + "etag": "W/\"ae-2qOTB47mF4kXc1MU0D+Xv+L9nq8\"" + }, + "body": { + "client_id": "test-client-1788911294533", + "client_name": "eventrelay-conformance-client", + "redirect_uris": [ + "http://localhost:3000/callback" + ], + "token_endpoint_auth_method": "none" + } + } + }, + { + "id": "incoming-auth-request", + "name": "Incoming-auth-request", + "description": "Received GET request for /authorize", + "status": "INFO", + "timestamp": "2026-09-08T23:48:14.539Z", + "details": { + "method": "GET", + "path": "/authorize", + "query": { + "response_type": "code", + "client_id": "test-client-1788911294533", + "code_challenge": "i0Yc_3COLxC3KXFHIy5FatJ-KCXM1Nk1sFYuANxkelU", + "code_challenge_method": "S256", + "redirect_uri": "http://localhost:3000/callback", + "resource": "http://localhost:40991/mcp" + } + } + }, + { + "id": "authorization-request", + "name": "AuthorizationRequest", + "description": "Client made authorization request", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:14.539Z", + "specReferences": [ + { + "id": "OAUTH-2.1-authorization-endpoint", + "url": "https://www.ietf.org/archive/id/draft-ietf-oauth-v2-1-13.html#name-authorization-endpoint" + } + ], + "details": { + "query": { + "response_type": "code", + "client_id": "test-client-1788911294533", + "code_challenge": "i0Yc_3COLxC3KXFHIy5FatJ-KCXM1Nk1sFYuANxkelU", + "code_challenge_method": "S256", + "redirect_uri": "http://localhost:3000/callback", + "resource": "http://localhost:40991/mcp" + } + } + }, + { + "id": "pkce-code-challenge-sent", + "name": "PKCE Code Challenge", + "description": "Client sent code_challenge in authorization request", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:14.539Z", + "specReferences": [ + { + "id": "MCP-PKCE-requirement", + "url": "https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization#authorization-code-protection" + } + ] + }, + { + "id": "pkce-s256-method-used", + "name": "PKCE S256 Method", + "description": "Client used S256 code challenge method", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:14.539Z", + "specReferences": [ + { + "id": "MCP-PKCE-requirement", + "url": "https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization#authorization-code-protection" + } + ], + "details": { + "method": "S256" + } + }, + { + "id": "outgoing-auth-response", + "name": "Outgoing-auth-response", + "description": "Sent 302 response for GET /authorize", + "status": "INFO", + "timestamp": "2026-09-08T23:48:14.541Z", + "details": { + "method": "GET", + "path": "/authorize", + "statusCode": 302, + "headers": { + "x-powered-by": "Express", + "location": "http://localhost:3000/callback?code=test-auth-code&iss=http%3A%2F%2Flocalhost%3A37991", + "vary": "Accept", + "content-type": "text/plain; charset=utf-8", + "content-length": "107" + }, + "body": "Found. Redirecting to http://localhost:3000/callback?code=test-auth-code&iss=http%3A%2F%2Flocalhost%3A37991" + } + }, + { + "id": "incoming-request", + "name": "Incoming-request", + "description": "Received GET request for /.well-known/oauth-protected-resource/mcp", + "status": "INFO", + "timestamp": "2026-09-08T23:48:14.543Z", + "details": { + "method": "GET", + "path": "/.well-known/oauth-protected-resource/mcp" + } + }, + { + "id": "prm-pathbased-requested", + "name": "PRMPathBasedRequested", + "description": "Client requested PRM metadata at path-based location", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:14.543Z", + "specReferences": [ + { + "id": "RFC-9728", + "url": "https://www.rfc-editor.org/rfc/rfc9728.html#section-3.1" + }, + { + "id": "MCP-2025-06-18-PRM-discovery", + "url": "https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization#protected-resource-metadata-discovery-requirements" + } + ], + "details": { + "url": "/.well-known/oauth-protected-resource/mcp", + "path": "/.well-known/oauth-protected-resource/mcp" + } + }, + { + "id": "outgoing-response", + "name": "Outgoing-response", + "description": "Sent 200 response for GET /.well-known/oauth-protected-resource/mcp", + "status": "INFO", + "timestamp": "2026-09-08T23:48:14.543Z", + "details": { + "method": "GET", + "path": "/.well-known/oauth-protected-resource/mcp", + "statusCode": 200, + "headers": { + "x-powered-by": "Express", + "content-type": "application/json; charset=utf-8", + "content-length": "92", + "etag": "W/\"5c-0feIEBn49XNTrDPIJoctcmJlPNI\"" + }, + "body": { + "resource": "http://localhost:40991/mcp", + "authorization_servers": [ + "http://localhost:37991" + ] + } + } + }, + { + "id": "incoming-auth-request", + "name": "Incoming-auth-request", + "description": "Received GET request for /.well-known/oauth-authorization-server", + "status": "INFO", + "timestamp": "2026-09-08T23:48:14.546Z", + "details": { + "method": "GET", + "path": "/.well-known/oauth-authorization-server" + } + }, + { + "id": "authorization-server-metadata", + "name": "AuthorizationServerMetadata", + "description": "Client requested authorization server metadata", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:14.546Z", + "specReferences": [ + { + "id": "RFC-8414-metadata-request", + "url": "https://www.rfc-editor.org/rfc/rfc8414.html#section-3.1" + }, + { + "id": "MCP-Authorization-metadata-discovery", + "url": "https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization#authorization-server-metadata-discovery" + } + ], + "details": { + "url": "/.well-known/oauth-authorization-server", + "path": "/.well-known/oauth-authorization-server" + } + }, + { + "id": "outgoing-auth-response", + "name": "Outgoing-auth-response", + "description": "Sent 200 response for GET /.well-known/oauth-authorization-server", + "status": "INFO", + "timestamp": "2026-09-08T23:48:14.546Z", + "details": { + "method": "GET", + "path": "/.well-known/oauth-authorization-server", + "statusCode": 200, + "headers": { + "x-powered-by": "Express", + "content-type": "application/json; charset=utf-8", + "content-length": "447", + "etag": "W/\"1bf-kgVsQRPY5+ql5p1GaRNOBLNGsFo\"" + }, + "body": { + "issuer": "http://localhost:37991", + "authorization_endpoint": "http://localhost:37991/authorize", + "token_endpoint": "http://localhost:37991/token", + "registration_endpoint": "http://localhost:37991/register", + "response_types_supported": [ + "code" + ], + "grant_types_supported": [ + "authorization_code", + "refresh_token" + ], + "code_challenge_methods_supported": [ + "S256" + ], + "authorization_response_iss_parameter_supported": true, + "token_endpoint_auth_methods_supported": [ + "none" + ] + } + } + }, + { + "id": "incoming-auth-request", + "name": "Incoming-auth-request", + "description": "Received POST request for /token", + "status": "INFO", + "timestamp": "2026-09-08T23:48:14.551Z", + "details": { + "method": "POST", + "path": "/token", + "body": { + "grant_type": "authorization_code", + "code": "test-auth-code", + "code_verifier": "QNjGhOPekA-dm6Cs667wZzhMf7nBT9aRrvQZRwWFxFc", + "redirect_uri": "http://localhost:3000/callback", + "resource": "http://localhost:40991/mcp", + "client_id": "test-client-1788911294533" + } + } + }, + { + "id": "token-request", + "name": "TokenRequest", + "description": "Client requested access token", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:14.551Z", + "specReferences": [ + { + "id": "OAUTH-2.1-token-request", + "url": "https://www.ietf.org/archive/id/draft-ietf-oauth-v2-1-13.html#name-token-request" + } + ], + "details": { + "endpoint": "/token", + "grantType": "authorization_code" + } + }, + { + "id": "pkce-code-verifier-sent", + "name": "PKCE Code Verifier", + "description": "Client sent code_verifier in token request", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:14.551Z", + "specReferences": [ + { + "id": "MCP-PKCE-requirement", + "url": "https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization#authorization-code-protection" + } + ] + }, + { + "id": "pkce-verifier-matches-challenge", + "name": "PKCE Verifier Validation", + "description": "code_verifier correctly matches code_challenge (S256)", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:14.551Z", + "specReferences": [ + { + "id": "MCP-PKCE-requirement", + "url": "https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization#authorization-code-protection" + } + ], + "details": { + "matches": true, + "storedChallenge": "i0Yc_3COLxC3KXFHIy5FatJ-KCXM1Nk1sFYuANxkelU", + "computedChallenge": "i0Yc_3COLxC3KXFHIy5FatJ-KCXM1Nk1sFYuANxkelU" + } + }, + { + "id": "token-endpoint-auth-method", + "name": "Token endpoint authentication method", + "description": "Client correctly used no authentication (public client) for token endpoint", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:14.551Z", + "specReferences": [ + { + "id": "OAUTH-2.1-token-request", + "url": "https://www.ietf.org/archive/id/draft-ietf-oauth-v2-1-13.html#name-token-request" + } + ], + "details": { + "expectedAuthMethod": "none", + "actualAuthMethod": "none", + "hasAuthorizationHeader": false, + "hasBodyClientSecret": false + } + }, + { + "id": "outgoing-auth-response", + "name": "Outgoing-auth-response", + "description": "Sent 200 response for POST /token", + "status": "INFO", + "timestamp": "2026-09-08T23:48:14.552Z", + "details": { + "method": "POST", + "path": "/token", + "statusCode": 200, + "headers": { + "x-powered-by": "Express", + "content-type": "application/json; charset=utf-8", + "content-length": "83", + "etag": "W/\"53-1uuimB8ChZPyacK3p2eMlTR8Eho\"" + }, + "body": { + "access_token": "test-token-1788911294552", + "token_type": "Bearer", + "expires_in": 3600 + } + } + }, + { + "id": "incoming-request", + "name": "Incoming-request", + "description": "Received POST request for /mcp (method: initialize)", + "status": "INFO", + "timestamp": "2026-09-08T23:48:14.555Z", + "details": { + "method": "POST", + "path": "/mcp", + "body": { + "method": "initialize", + "params": { + "protocolVersion": "2025-11-25", + "capabilities": {}, + "clientInfo": { + "name": "eventrelay-conformance-client", + "version": "1.0.0" + } + }, + "jsonrpc": "2.0", + "id": 0 + }, + "mcpMethod": "initialize" + } + }, + { + "id": "valid-bearer-token", + "name": "ValidBearerToken", + "description": "Client provided valid bearer token", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:14.555Z", + "specReferences": [ + { + "id": "MCP-Access-token-usage", + "url": "https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization#access-token-usage" + } + ], + "details": { + "token": "test-token-1788...", + "scopes": [] + } + }, + { + "id": "outgoing-response", + "name": "Outgoing-response", + "description": "Sent 400 response for POST /mcp (method: initialize)", + "status": "INFO", + "timestamp": "2026-09-08T23:48:14.556Z", + "details": { + "method": "POST", + "path": "/mcp", + "statusCode": 400, + "mcpMethod": "initialize", + "headers": { + "x-powered-by": "Express", + "content-type": "application/json; charset=utf-8", + "content-length": "96", + "etag": "W/\"60-+I3pGWaBJPzWK/0N3EGEE0YM2QY\"" + }, + "body": { + "jsonrpc": "2.0", + "id": 0, + "error": { + "code": -32020, + "message": "Missing MCP-Protocol-Version header" + } + } + } + }, + { + "id": "resource-parameter-in-authorization", + "name": "Resource parameter in authorization request", + "description": "Client included resource parameter in authorization request", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:14.576Z", + "specReferences": [ + { + "id": "RFC-8707-Resource-Indicators", + "url": "https://www.rfc-editor.org/rfc/rfc8707.html" + }, + { + "id": "MCP-Resource-Parameter-Implementation", + "url": "https://modelcontextprotocol.io/specification/draft/basic/authorization#resource-parameter-implementation" + } + ], + "details": { + "resource": "http://localhost:40991/mcp" + } + }, + { + "id": "resource-parameter-in-token", + "name": "Resource parameter in token request", + "description": "Client included resource parameter in token request", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:14.576Z", + "specReferences": [ + { + "id": "RFC-8707-Resource-Indicators", + "url": "https://www.rfc-editor.org/rfc/rfc8707.html" + }, + { + "id": "MCP-Resource-Parameter-Implementation", + "url": "https://modelcontextprotocol.io/specification/draft/basic/authorization#resource-parameter-implementation" + } + ], + "details": { + "resource": "http://localhost:40991/mcp" + } + }, + { + "id": "resource-parameter-valid-uri", + "name": "Resource parameter is valid canonical URI", + "description": "Resource parameter is a valid canonical URI (has scheme, no fragment)", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:14.576Z", + "specReferences": [ + { + "id": "RFC-8707-Resource-Indicators", + "url": "https://www.rfc-editor.org/rfc/rfc8707.html" + }, + { + "id": "MCP-Resource-Parameter-Implementation", + "url": "https://modelcontextprotocol.io/specification/draft/basic/authorization#resource-parameter-implementation" + } + ], + "details": { + "resource": "http://localhost:40991/mcp" + } + }, + { + "id": "resource-parameter-consistency", + "name": "Resource parameter consistency", + "description": "Resource parameter is consistent between authorization and token requests", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:14.576Z", + "specReferences": [ + { + "id": "RFC-8707-Resource-Indicators", + "url": "https://www.rfc-editor.org/rfc/rfc8707.html" + }, + { + "id": "MCP-Resource-Parameter-Implementation", + "url": "https://modelcontextprotocol.io/specification/draft/basic/authorization#resource-parameter-implementation" + } + ], + "details": { + "authorizationResource": "http://localhost:40991/mcp", + "tokenResource": "http://localhost:40991/mcp" + } + }, + { + "id": "resource-parameter-matches-prm", + "name": "Resource parameter matches protected resource metadata", + "description": "Client sent the resource identifier exactly as published in protected resource metadata", + "status": "SUCCESS", + "timestamp": "2026-09-08T23:48:14.576Z", + "specReferences": [ + { + "id": "RFC-8707-Resource-Indicators", + "url": "https://www.rfc-editor.org/rfc/rfc8707.html" + }, + { + "id": "MCP-Resource-Parameter-Implementation", + "url": "https://modelcontextprotocol.io/specification/draft/basic/authorization#resource-parameter-implementation" + }, + { + "id": "MCP-Canonical-Server-URI", + "url": "https://modelcontextprotocol.io/specification/draft/basic/authorization#canonical-server-uri" + }, + { + "id": "RFC-9728-resource-identity", + "url": "https://www.rfc-editor.org/rfc/rfc9728.html#section-3.3" + } + ], + "details": { + "prmResource": "http://localhost:40991/mcp", + "authorizationResource": "http://localhost:40991/mcp", + "tokenResource": "http://localhost:40991/mcp" + } + } + ], + "stdout": "", + "stderr": "Starting scenario: auth/token-endpoint-auth-none\nExecuting client: node /home/runner/work/EventRelay/EventRelay/tests/testing/official_mcp_auth_client.mjs http://localhost:40991/mcp\n(node:9383) [DEP0190] DeprecationWarning: Passing args to a child process with shell option true can lead to security vulnerabilities, as the arguments are not escaped, only concatenated.\n(Use `node --trace-deprecation ...` to show where the warning was created)\n\nClient exited with code 1\n\nStderr:\nError: Streamable HTTP error: Error POSTing to endpoint: {\"jsonrpc\":\"2.0\",\"id\":0,\"error\":{\"code\":-32020,\"message\":\"Missing MCP-Protocol-Version header\"}}\n at StreamableHTTPClientTransport.send (file:///home/runner/work/EventRelay/EventRelay/node_modules/@modelcontextprotocol/sdk/dist/esm/client/streamableHttp.js:365:23)\n at process.processTicksAndRejections (node:internal/process/task_queues:104:5)\n\nResults saved to /tmp/mcp-conformance-client-kb91y_h1/auth/token-endpoint-auth-none-2026-09-08T23-48-14-267Z\nChecks:\n\u001b[90m2026-09-08T23:48:14.512Z\u001b[0m [incoming-request ] \u001b[36mINFO \u001b[0m Received POST request for /mcp (method: initialize)\n\u001b[90m2026-09-08T23:48:14.514Z\u001b[0m [outgoing-response ] \u001b[36mINFO \u001b[0m Sent 401 response for POST /mcp (method: initialize)\n\n\u001b[90m2026-09-08T23:48:14.522Z\u001b[0m [incoming-request ] \u001b[36mINFO \u001b[0m Received GET request for /.well-known/oauth-protected-resource/mcp\n\u001b[90m2026-09-08T23:48:14.522Z\u001b[0m [prm-pathbased-requested ] \u001b[32mSUCCESS\u001b[0m Client requested PRM metadata at path-based location\n\u001b[90m2026-09-08T23:48:14.523Z\u001b[0m [outgoing-response ] \u001b[36mINFO \u001b[0m Sent 200 response for GET /.well-known/oauth-protected-resource/mcp\n\n\u001b[90m2026-09-08T23:48:14.528Z\u001b[0m [incoming-auth-request ] \u001b[36mINFO \u001b[0m Received GET request for /.well-known/oauth-authorization-server\n\u001b[90m2026-09-08T23:48:14.528Z\u001b[0m [authorization-server-metadata ] \u001b[32mSUCCESS\u001b[0m Client requested authorization server metadata\n\u001b[90m2026-09-08T23:48:14.529Z\u001b[0m [outgoing-auth-response ] \u001b[36mINFO \u001b[0m Sent 200 response for GET /.well-known/oauth-authorization-server\n\n\u001b[90m2026-09-08T23:48:14.533Z\u001b[0m [incoming-auth-request ] \u001b[36mINFO \u001b[0m Received POST request for /register\n\u001b[90m2026-09-08T23:48:14.533Z\u001b[0m [client-registration ] \u001b[32mSUCCESS\u001b[0m Client registered with authorization server\n\u001b[90m2026-09-08T23:48:14.533Z\u001b[0m [sep-837-application-type-present ] \u001b[32mSUCCESS\u001b[0m Client specified application_type \"native\" during Dynamic Client Registration\n\u001b[90m2026-09-08T23:48:14.533Z\u001b[0m [outgoing-auth-response ] \u001b[36mINFO \u001b[0m Sent 201 response for POST /register\n\n\u001b[90m2026-09-08T23:48:14.539Z\u001b[0m [incoming-auth-request ] \u001b[36mINFO \u001b[0m Received GET request for /authorize\n\u001b[90m2026-09-08T23:48:14.539Z\u001b[0m [authorization-request ] \u001b[32mSUCCESS\u001b[0m Client made authorization request\n\u001b[90m2026-09-08T23:48:14.539Z\u001b[0m [pkce-code-challenge-sent ] \u001b[32mSUCCESS\u001b[0m Client sent code_challenge in authorization request\n\u001b[90m2026-09-08T23:48:14.539Z\u001b[0m [pkce-s256-method-used ] \u001b[32mSUCCESS\u001b[0m Client used S256 code challenge method\n\u001b[90m2026-09-08T23:48:14.541Z\u001b[0m [outgoing-auth-response ] \u001b[36mINFO \u001b[0m Sent 302 response for GET /authorize\n\n\u001b[90m2026-09-08T23:48:14.543Z\u001b[0m [incoming-request ] \u001b[36mINFO \u001b[0m Received GET request for /.well-known/oauth-protected-resource/mcp\n\u001b[90m2026-09-08T23:48:14.543Z\u001b[0m [prm-pathbased-requested ] \u001b[32mSUCCESS\u001b[0m Client requested PRM metadata at path-based location\n\u001b[90m2026-09-08T23:48:14.543Z\u001b[0m [outgoing-response ] \u001b[36mINFO \u001b[0m Sent 200 response for GET /.well-known/oauth-protected-resource/mcp\n\n\u001b[90m2026-09-08T23:48:14.546Z\u001b[0m [incoming-auth-request ] \u001b[36mINFO \u001b[0m Received GET request for /.well-known/oauth-authorization-server\n\u001b\n...[truncated]" + } + ] +} diff --git a/tests/testing/official_mcp_auth_client.mjs b/tests/testing/official_mcp_auth_client.mjs new file mode 100644 index 000000000..0f042404e --- /dev/null +++ b/tests/testing/official_mcp_auth_client.mjs @@ -0,0 +1,216 @@ +#!/usr/bin/env node + +import { Client } from '@modelcontextprotocol/sdk/client/index.js'; +import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js'; +import { + auth, + extractWWWAuthenticateParams, + UnauthorizedError, +} from '@modelcontextprotocol/sdk/client/auth.js'; +import { checkResourceAllowed } from '@modelcontextprotocol/sdk/shared/auth-utils.js'; + +const SCENARIOS = new Set([ + 'auth/metadata-var2', + 'auth/token-endpoint-auth-basic', + 'auth/token-endpoint-auth-post', + 'auth/token-endpoint-auth-none', +]); + +const CIMD_CLIENT_METADATA_URL = + 'https://conformance-test.local/client-metadata.json'; + +class ConformanceOAuthProvider { + constructor(redirectUrl, clientMetadata, clientMetadataUrl) { + this._redirectUrl = redirectUrl; + this._clientMetadata = clientMetadata; + this._clientMetadataUrl = clientMetadataUrl; + } + + get redirectUrl() { + return this._redirectUrl; + } + + get clientMetadata() { + return this._clientMetadata; + } + + get clientMetadataUrl() { + return this._clientMetadataUrl; + } + + clientInformation() { + return this._clientInformation; + } + + saveClientInformation(clientInformation) { + this._clientInformation = clientInformation; + } + + tokens() { + return this._tokens; + } + + saveTokens(tokens) { + this._tokens = tokens; + } + + async redirectToAuthorization(authorizationUrl) { + const response = await fetch(authorizationUrl.toString(), { + redirect: 'manual', + }); + const location = response.headers.get('location'); + if (!location) { + throw new Error(`No redirect location received from ${authorizationUrl}`); + } + const redirectUrl = new URL(location); + const code = redirectUrl.searchParams.get('code'); + if (!code) { + throw new Error('No authorization code in redirect URL'); + } + this._authCode = code; + } + + async getAuthCode() { + if (!this._authCode) { + throw new Error('No authorization code available'); + } + return this._authCode; + } + + saveCodeVerifier(codeVerifier) { + this._codeVerifier = codeVerifier; + } + + codeVerifier() { + if (!this._codeVerifier) { + throw new Error('No code verifier saved'); + } + return this._codeVerifier; + } + + validateResourceURL(defaultResource, configuredResource) { + if (!configuredResource) { + return undefined; + } + if ( + !checkResourceAllowed({ + requestedResource: defaultResource, + configuredResource, + }) + ) { + throw new Error( + `Protected resource ${configuredResource} does not match expected ${defaultResource} (or origin)` + ); + } + return { href: configuredResource }; + } +} + +function unionScopes(prior, challenged) { + const values = [...(prior?.split(' ') ?? []), ...(challenged?.split(' ') ?? [])] + .map((value) => value.trim()) + .filter(Boolean); + return values.length ? [...new Set(values)].join(' ') : undefined; +} + +async function handle401(response, provider, next, serverUrl) { + const { resourceMetadataUrl, scope: challengedScope } = + extractWWWAuthenticateParams(response); + const prior = (await provider.tokens())?.scope; + const scope = unionScopes(prior, challengedScope); + + let result = await auth(provider, { + serverUrl, + resourceMetadataUrl, + scope, + fetchFn: next, + }); + + if (result === 'REDIRECT') { + const authorizationCode = await provider.getAuthCode(); + result = await auth(provider, { + serverUrl, + resourceMetadataUrl, + scope, + authorizationCode, + fetchFn: next, + }); + } + + if (result !== 'AUTHORIZED') { + throw new UnauthorizedError(`Authentication failed with result: ${result}`); + } +} + +function withOAuthRetry(clientName, baseUrl, clientMetadataUrl) { + const provider = new ConformanceOAuthProvider( + 'http://localhost:3000/callback', + { + client_name: clientName, + redirect_uris: ['http://localhost:3000/callback'], + application_type: 'native', + }, + clientMetadataUrl + ); + + return (next) => { + return async (input, init) => { + const makeRequest = async () => { + const headers = new Headers(init?.headers); + const tokens = await provider.tokens(); + if (tokens?.access_token) { + headers.set('Authorization', ['Bearer', tokens.access_token].join(' ')); + } + return next(input, { ...init, headers }); + }; + + let response = await makeRequest(); + if (response.status === 401 || response.status === 403) { + await handle401(response, provider, next, baseUrl); + response = await makeRequest(); + } + if (response.status === 401 || response.status === 403) { + const url = typeof input === 'string' ? input : input.toString(); + throw new UnauthorizedError(`Authentication failed for ${url}`); + } + return response; + }; + }; +} + +async function runAuthClient(serverUrl) { + const client = new Client( + { name: 'eventrelay-conformance-client', version: '1.0.0' }, + { capabilities: {} } + ); + const oauthFetch = withOAuthRetry( + 'eventrelay-conformance-client', + new URL(serverUrl), + CIMD_CLIENT_METADATA_URL + )(fetch); + const transport = new StreamableHTTPClientTransport(new URL(serverUrl), { + fetch: oauthFetch, + }); + await client.connect(transport); + await client.listTools(); + await client.callTool({ name: 'test-tool', arguments: {} }); + await transport.close(); +} + +async function main() { + const scenario = process.env.MCP_CONFORMANCE_SCENARIO; + const serverUrl = process.argv[2]; + + if (!scenario || !serverUrl) { + throw new Error('Usage: MCP_CONFORMANCE_SCENARIO= official_mcp_auth_client.mjs '); + } + if (!SCENARIOS.has(scenario)) { + throw new Error(`Unsupported conformance scenario: ${scenario}`); + } + await runAuthClient(serverUrl); +} + +main().catch((error) => { + console.error(error instanceof Error ? error.stack || error.message : String(error)); + process.exit(1); +}); diff --git a/tests/testing/official_mcp_fixture_server.py b/tests/testing/official_mcp_fixture_server.py new file mode 100644 index 000000000..651799202 --- /dev/null +++ b/tests/testing/official_mcp_fixture_server.py @@ -0,0 +1,220 @@ +#!/usr/bin/env python3 +from __future__ import annotations + +import argparse +import json +from http import HTTPStatus +from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer +from typing import Any + +TOOLS = [ + { + "name": "test_simple_text", + "description": "Return a simple text response for conformance testing.", + "inputSchema": {"type": "object", "properties": {}}, + }, + { + "name": "test_error_handling", + "description": "Return a tool error response for conformance testing.", + "inputSchema": {"type": "object", "properties": {}}, + }, +] + +SERVER_INFO = {"name": "eventrelay-conformance-fixture", "version": "1.0.0"} +STATELESS_RESULT_META = { + "resultType": "complete", + "ttlMs": 0, + "cacheScope": "private", +} + + +def _jsonrpc_result(request_id: Any, result: dict[str, Any]) -> dict[str, Any]: + return {"jsonrpc": "2.0", "id": request_id, "result": result} + + +def _jsonrpc_error( + request_id: Any, + code: int, + message: str, +) -> dict[str, Any]: + return { + "jsonrpc": "2.0", + "id": request_id, + "error": {"code": code, "message": message}, + } + + +def _stateless_result(request_id: Any, result: dict[str, Any]) -> dict[str, Any]: + return _jsonrpc_result(request_id, {**STATELESS_RESULT_META, **result}) + + +class ConformanceFixtureHandler(BaseHTTPRequestHandler): + protocol_version = "HTTP/1.1" + + def do_POST(self) -> None: # noqa: N802 + if self.path != "/mcp": + self._write_json( + HTTPStatus.NOT_FOUND, + _jsonrpc_error(None, -32601, "Method not found"), + ) + return + + payload = self._read_json() + if payload is None: + self._write_json( + HTTPStatus.BAD_REQUEST, + _jsonrpc_error(None, -32700, "Parse error"), + ) + return + + request_id = payload.get("id") + method = payload.get("method") + params = payload.get("params") or {} + + if request_id is None and str(method).startswith("notifications/"): + self.send_response(HTTPStatus.ACCEPTED) + self.send_header("Content-Length", "0") + self.end_headers() + return + + if method == "initialize": + protocol_version = params.get("protocolVersion") or "2025-11-25" + self._write_json( + HTTPStatus.OK, + _jsonrpc_result( + request_id, + { + "protocolVersion": protocol_version, + "capabilities": {"tools": {}}, + "serverInfo": SERVER_INFO, + }, + ), + headers={"MCP-Protocol-Version": protocol_version}, + ) + return + + if method == "server/discover": + self._write_json( + HTTPStatus.OK, + _stateless_result( + request_id, + { + "supportedVersions": ["2026-07-28"], + "capabilities": {"tools": {}}, + "serverInfo": SERVER_INFO, + }, + ), + headers={"MCP-Protocol-Version": "2026-07-28"}, + ) + return + + if method == "tools/list": + self._write_json( + HTTPStatus.OK, + _stateless_result(request_id, {"tools": TOOLS}), + headers={"MCP-Protocol-Version": "2026-07-28"}, + ) + return + + if method == "tools/call": + tool_name = params.get("name") + if tool_name == "test_simple_text": + self._write_json( + HTTPStatus.OK, + _stateless_result( + request_id, + { + "content": [ + { + "type": "text", + "text": "This is a simple text response for testing.", + } + ] + }, + ), + headers={"MCP-Protocol-Version": "2026-07-28"}, + ) + return + if tool_name == "test_error_handling": + self._write_json( + HTTPStatus.OK, + _stateless_result( + request_id, + { + "isError": True, + "content": [ + { + "type": "text", + "text": "This tool intentionally returns an error for testing", + } + ], + }, + ), + headers={"MCP-Protocol-Version": "2026-07-28"}, + ) + return + + self._write_json( + HTTPStatus.NOT_FOUND, + _jsonrpc_error(request_id, -32601, "Method not found"), + ) + + def do_GET(self) -> None: # noqa: N802 + self._write_json( + HTTPStatus.METHOD_NOT_ALLOWED, + _jsonrpc_error(None, -32000, "Method not allowed."), + ) + + def do_DELETE(self) -> None: # noqa: N802 + self._write_json( + HTTPStatus.METHOD_NOT_ALLOWED, + _jsonrpc_error(None, -32000, "Method not allowed."), + ) + + def log_message(self, _format: str, *_args: Any) -> None: + return + + def _read_json(self) -> dict[str, Any] | None: + try: + length = int(self.headers.get("Content-Length", "0")) + except ValueError: + return None + body = self.rfile.read(length) if length > 0 else b"" + try: + return json.loads(body.decode("utf-8")) if body else {} + except json.JSONDecodeError: + return None + + def _write_json( + self, + status: HTTPStatus, + payload: dict[str, Any], + *, + headers: dict[str, str] | None = None, + ) -> None: + encoded = json.dumps(payload).encode("utf-8") + self.send_response(status) + self.send_header("Content-Type", "application/json") + self.send_header("Content-Length", str(len(encoded))) + for name, value in (headers or {}).items(): + self.send_header(name, value) + self.end_headers() + self.wfile.write(encoded) + + +def main() -> int: + parser = argparse.ArgumentParser() + parser.add_argument("--port", type=int, default=38765) + args = parser.parse_args() + server = ThreadingHTTPServer(("127.0.0.1", args.port), ConformanceFixtureHandler) + try: + server.serve_forever() + except KeyboardInterrupt: + pass + finally: + server.server_close() + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/tests/unit/test_official_mcp_conformance.py b/tests/unit/test_official_mcp_conformance.py new file mode 100644 index 000000000..7d51fc6c2 --- /dev/null +++ b/tests/unit/test_official_mcp_conformance.py @@ -0,0 +1,171 @@ +from __future__ import annotations + +import importlib.util +import json +import socket +import subprocess +import sys +import time +from pathlib import Path + +import httpx + + +_ROOT = Path(__file__).resolve().parents[2] +_SCRIPT_PATH = _ROOT / "scripts/testing/official_mcp_conformance.py" +_FIXTURE_SERVER_PATH = _ROOT / "tests/testing/official_mcp_fixture_server.py" + + +def _load_module(): + assert _SCRIPT_PATH.exists(), f"missing harness script: {_SCRIPT_PATH}" + spec = importlib.util.spec_from_file_location("official_mcp_conformance", _SCRIPT_PATH) + module = importlib.util.module_from_spec(spec) + assert spec.loader is not None + spec.loader.exec_module(module) + return module + + +def _free_port() -> int: + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: + sock.bind(("127.0.0.1", 0)) + return int(sock.getsockname()[1]) + + +def _wait_for_port(port: int, timeout: float = 5.0) -> None: + deadline = time.time() + timeout + while time.time() < deadline: + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: + if sock.connect_ex(("127.0.0.1", port)) == 0: + return + time.sleep(0.05) + raise AssertionError(f"fixture server did not start on port {port}") + + +def test_required_checks_fail_closed_on_warning() -> None: + module = _load_module() + + summary = module.summarize_checks( + [ + {"id": "tools-list", "status": "SUCCESS"}, + {"id": "tools-list-deterministic-order", "status": "WARNING"}, + ], + required=True, + ) + + assert summary["ok"] is False + assert summary["blocking"] == ["tools-list-deterministic-order:WARNING"] + + +def test_unscored_failures_do_not_block_receipt() -> None: + module = _load_module() + + summary = module.summarize_checks( + [{"id": "tasks-dispatch-and-envelope", "status": "FAILURE"}], + required=False, + ) + + assert summary["ok"] is True + assert summary["counts"]["FAILURE"] == 1 + assert summary["blocking"] == [] + + +def test_fixture_server_keeps_tools_list_order_stable() -> None: + port = _free_port() + proc = subprocess.Popen( + [sys.executable, str(_FIXTURE_SERVER_PATH), "--port", str(port)], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + ) + try: + _wait_for_port(port) + headers = { + "Content-Type": "application/json", + "Accept": "application/json, text/event-stream", + "MCP-Protocol-Version": "2026-07-28", + } + payload = { + "jsonrpc": "2.0", + "method": "tools/list", + "params": { + "_meta": { + "io.modelcontextprotocol/protocolVersion": "2026-07-28", + "io.modelcontextprotocol/clientCapabilities": {}, + "io.modelcontextprotocol/clientInfo": { + "name": "pytest", + "version": "1.0.0", + }, + } + }, + } + + orders = [] + with httpx.Client(timeout=5.0) as client: + for index in range(1, 4): + response = client.post( + f"http://127.0.0.1:{port}/mcp", + headers=headers, + json={**payload, "id": index}, + ) + response.raise_for_status() + body = response.json() + orders.append([tool["name"] for tool in body["result"]["tools"]]) + + assert orders == [orders[0], orders[0], orders[0]] + finally: + proc.terminate() + proc.wait(timeout=5) + + +def test_fixture_server_returns_202_for_initialized_notification() -> None: + port = _free_port() + proc = subprocess.Popen( + [sys.executable, str(_FIXTURE_SERVER_PATH), "--port", str(port)], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + ) + try: + _wait_for_port(port) + with httpx.Client(timeout=5.0) as client: + initialize = client.post( + f"http://127.0.0.1:{port}/mcp", + headers={ + "Content-Type": "application/json", + "Accept": "application/json, text/event-stream", + "MCP-Protocol-Version": "2025-11-25", + }, + json={ + "jsonrpc": "2.0", + "id": 1, + "method": "initialize", + "params": { + "protocolVersion": "2025-11-25", + "capabilities": {}, + "clientInfo": {"name": "pytest", "version": "1.0.0"}, + }, + }, + ) + initialize.raise_for_status() + notification = client.post( + f"http://127.0.0.1:{port}/mcp", + headers={ + "Content-Type": "application/json", + "Accept": "application/json, text/event-stream", + "MCP-Protocol-Version": "2025-11-25", + }, + content=json.dumps( + { + "jsonrpc": "2.0", + "id": None, + "method": "notifications/initialized", + "params": {}, + } + ), + ) + + assert notification.status_code == 202 + assert notification.text == "" + finally: + proc.terminate() + proc.wait(timeout=5) From edfbc7b31b534e60001eda6369edd2e2f180664d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 8 Sep 2026 23:52:13 +0000 Subject: [PATCH 3/3] test: harden MCP fixture headers Co-authored-by: groupthinking <154503486+groupthinking@users.noreply.github.com> --- .../official-2026-07-28-receipt.json | 674 +++++++++--------- tests/testing/official_mcp_fixture_server.py | 17 +- tests/unit/test_official_mcp_conformance.py | 39 + 3 files changed, 391 insertions(+), 339 deletions(-) diff --git a/tests/fixtures/mcp_conformance/official-2026-07-28-receipt.json b/tests/fixtures/mcp_conformance/official-2026-07-28-receipt.json index 7cfa97fc3..c84f15a85 100644 --- a/tests/fixtures/mcp_conformance/official-2026-07-28-receipt.json +++ b/tests/fixtures/mcp_conformance/official-2026-07-28-receipt.json @@ -1,14 +1,14 @@ { "schema_version": "eventrelay.mcp-conformance-receipt.v1", "baseline_revision": "2026-07-28", - "generated_at": "2026-09-08T23:48:14Z", + "generated_at": "2026-09-08T23:52:06Z", "overall_ok": true, "conformance": { "package": "git+https://github.com/modelcontextprotocol/conformance.git#a983ba93c91e0bb31d0b6849eeb52f0ad1083107", "commit": "a983ba93c91e0bb31d0b6849eeb52f0ad1083107" }, "implementation": { - "commit": "743bd694baa314d66c56129cbb675690385a263f", + "commit": "476260e5ef48c00c2d33f5b2444b556f42d71100", "sdk_version": "^1.30.0" }, "versions": { @@ -159,7 +159,7 @@ "name": "ToolsList", "description": "Server lists available tools with valid structure", "status": "SUCCESS", - "timestamp": "2026-09-08T23:47:26.913Z", + "timestamp": "2026-09-08T23:51:17.472Z", "specReferences": [ { "id": "MCP-Tools-List", @@ -196,7 +196,7 @@ "url": "https://github.com/modelcontextprotocol/modelcontextprotocol/pull/1603" } ], - "timestamp": "2026-09-08T23:47:26.913Z", + "timestamp": "2026-09-08T23:51:17.473Z", "status": "SUCCESS", "details": { "toolCount": 2, @@ -219,7 +219,7 @@ "source": { "introducedIn": "2026-07-28" }, - "timestamp": "2026-09-08T23:47:26.961Z", + "timestamp": "2026-09-08T23:51:17.520Z", "status": "SUCCESS", "details": { "toolCount": 2, @@ -245,7 +245,7 @@ "name": "WireSchemaValid", "description": "Every JSON-RPC message the implementation sent is valid per the spec JSON schema for the negotiated spec version", "status": "SUCCESS", - "timestamp": "2026-09-08T23:47:26.962Z", + "timestamp": "2026-09-08T23:51:17.521Z", "specReferences": [ { "id": "MCP-Schema", @@ -258,7 +258,7 @@ } } ], - "stdout": "Running client scenario 'tools-list' against server: http://127.0.0.1:59343/mcp\nResults saved to /tmp/mcp-conformance-server-_xtkakss/server-tools-list-2026-09-08T23-47-26-809Z\nChecks:\n\u001b[90m2026-09-08T23:47:26.913Z\u001b[0m [tools-list ] \u001b[32mSUCCESS\u001b[0m Server lists available tools with valid structure\n\u001b[90m2026-09-08T23:47:26.913Z\u001b[0m [tools-name-format ] \u001b[32mSUCCESS\u001b[0m Tool names SHOULD be 1-128 characters and match ^[A-Za-z0-9_.-]+$\n\u001b[90m2026-09-08T23:47:26.961Z\u001b[0m [tools-list-deterministic-order] \u001b[32mSUCCESS\u001b[0m Consecutive tools/list requests return the same tools in the same order\n\u001b[90m2026-09-08T23:47:26.962Z\u001b[0m [wire-schema-valid ] \u001b[32mSUCCESS\u001b[0m Every JSON-RPC message the implementation sent is valid per the spec JSON schema for the negotiated spec version\n\nTest Results:\nPassed: 4/4, 0 failed, 0 warnings\n", + "stdout": "Running client scenario 'tools-list' against server: http://127.0.0.1:48389/mcp\nResults saved to /tmp/mcp-conformance-server-ao46vvb6/server-tools-list-2026-09-08T23-51-17-371Z\nChecks:\n\u001b[90m2026-09-08T23:51:17.472Z\u001b[0m [tools-list ] \u001b[32mSUCCESS\u001b[0m Server lists available tools with valid structure\n\u001b[90m2026-09-08T23:51:17.473Z\u001b[0m [tools-name-format ] \u001b[32mSUCCESS\u001b[0m Tool names SHOULD be 1-128 characters and match ^[A-Za-z0-9_.-]+$\n\u001b[90m2026-09-08T23:51:17.520Z\u001b[0m [tools-list-deterministic-order] \u001b[32mSUCCESS\u001b[0m Consecutive tools/list requests return the same tools in the same order\n\u001b[90m2026-09-08T23:51:17.521Z\u001b[0m [wire-schema-valid ] \u001b[32mSUCCESS\u001b[0m Every JSON-RPC message the implementation sent is valid per the spec JSON schema for the negotiated spec version\n\nTest Results:\nPassed: 4/4, 0 failed, 0 warnings\n", "stderr": "" }, { @@ -282,7 +282,7 @@ "name": "ToolsCallSimpleText", "description": "Tool returns simple text content", "status": "SUCCESS", - "timestamp": "2026-09-08T23:47:33.826Z", + "timestamp": "2026-09-08T23:51:24.372Z", "specReferences": [ { "id": "MCP-Tools-Call", @@ -308,7 +308,7 @@ "name": "WireSchemaValid", "description": "Every JSON-RPC message the implementation sent is valid per the spec JSON schema for the negotiated spec version", "status": "SUCCESS", - "timestamp": "2026-09-08T23:47:33.826Z", + "timestamp": "2026-09-08T23:51:24.372Z", "specReferences": [ { "id": "MCP-Schema", @@ -321,7 +321,7 @@ } } ], - "stdout": "Running client scenario 'tools-call-simple-text' against server: http://127.0.0.1:59159/mcp\nResults saved to /tmp/mcp-conformance-server-kdog2ok2/server-tools-call-simple-text-2026-09-08T23-47-33-705Z\nChecks:\n\u001b[90m2026-09-08T23:47:33.826Z\u001b[0m [tools-call-simple-text] \u001b[32mSUCCESS\u001b[0m Tool returns simple text content\n\u001b[90m2026-09-08T23:47:33.826Z\u001b[0m [wire-schema-valid ] \u001b[32mSUCCESS\u001b[0m Every JSON-RPC message the implementation sent is valid per the spec JSON schema for the negotiated spec version\n\nTest Results:\nPassed: 2/2, 0 failed, 0 warnings\n", + "stdout": "Running client scenario 'tools-call-simple-text' against server: http://127.0.0.1:57175/mcp\nResults saved to /tmp/mcp-conformance-server-lmx0h254/server-tools-call-simple-text-2026-09-08T23-51-24-249Z\nChecks:\n\u001b[90m2026-09-08T23:51:24.372Z\u001b[0m [tools-call-simple-text] \u001b[32mSUCCESS\u001b[0m Tool returns simple text content\n\u001b[90m2026-09-08T23:51:24.372Z\u001b[0m [wire-schema-valid ] \u001b[32mSUCCESS\u001b[0m Every JSON-RPC message the implementation sent is valid per the spec JSON schema for the negotiated spec version\n\nTest Results:\nPassed: 2/2, 0 failed, 0 warnings\n", "stderr": "" }, { @@ -345,7 +345,7 @@ "name": "ToolsCallError", "description": "Tool returns error correctly", "status": "SUCCESS", - "timestamp": "2026-09-08T23:47:40.520Z", + "timestamp": "2026-09-08T23:51:31.321Z", "specReferences": [ { "id": "MCP-Error-Handling", @@ -372,7 +372,7 @@ "name": "WireSchemaValid", "description": "Every JSON-RPC message the implementation sent is valid per the spec JSON schema for the negotiated spec version", "status": "SUCCESS", - "timestamp": "2026-09-08T23:47:40.520Z", + "timestamp": "2026-09-08T23:51:31.321Z", "specReferences": [ { "id": "MCP-Schema", @@ -385,7 +385,7 @@ } } ], - "stdout": "Running client scenario 'tools-call-error' against server: http://127.0.0.1:40101/mcp\nResults saved to /tmp/mcp-conformance-server-dp6zs4bl/server-tools-call-error-2026-09-08T23-47-40-402Z\nChecks:\n\u001b[90m2026-09-08T23:47:40.520Z\u001b[0m [tools-call-error ] \u001b[32mSUCCESS\u001b[0m Tool returns error correctly\n\u001b[90m2026-09-08T23:47:40.520Z\u001b[0m [wire-schema-valid] \u001b[32mSUCCESS\u001b[0m Every JSON-RPC message the implementation sent is valid per the spec JSON schema for the negotiated spec version\n\nTest Results:\nPassed: 2/2, 0 failed, 0 warnings\n", + "stdout": "Running client scenario 'tools-call-error' against server: http://127.0.0.1:53465/mcp\nResults saved to /tmp/mcp-conformance-server-xcde4dr8/server-tools-call-error-2026-09-08T23-51-31-196Z\nChecks:\n\u001b[90m2026-09-08T23:51:31.321Z\u001b[0m [tools-call-error ] \u001b[32mSUCCESS\u001b[0m Tool returns error correctly\n\u001b[90m2026-09-08T23:51:31.321Z\u001b[0m [wire-schema-valid] \u001b[32mSUCCESS\u001b[0m Every JSON-RPC message the implementation sent is valid per the spec JSON schema for the negotiated spec version\n\nTest Results:\nPassed: 2/2, 0 failed, 0 warnings\n", "stderr": "" }, { @@ -410,7 +410,7 @@ "name": "ServerInitialize", "description": "Server responds to initialize request with valid structure", "status": "SUCCESS", - "timestamp": "2026-09-08T23:47:47.245Z", + "timestamp": "2026-09-08T23:51:38.274Z", "specReferences": [ { "id": "MCP-Initialize", @@ -418,7 +418,7 @@ } ], "details": { - "serverUrl": "http://127.0.0.1:43637/mcp", + "serverUrl": "http://127.0.0.1:56021/mcp", "connected": true } }, @@ -427,7 +427,7 @@ "name": "ServerSessionIdVisibleAscii", "description": "Server-provided session ID uses only visible ASCII characters", "status": "INFO", - "timestamp": "2026-09-08T23:47:47.250Z", + "timestamp": "2026-09-08T23:51:38.280Z", "specReferences": [ { "id": "MCP-Session-Management", @@ -443,7 +443,7 @@ "name": "WireSchemaValid", "description": "Every JSON-RPC message the implementation sent is valid per the spec JSON schema for the negotiated spec version", "status": "SUCCESS", - "timestamp": "2026-09-08T23:47:47.250Z", + "timestamp": "2026-09-08T23:51:38.280Z", "specReferences": [ { "id": "MCP-Schema", @@ -456,7 +456,7 @@ } } ], - "stdout": "Running client scenario 'server-initialize' against server: http://127.0.0.1:43637/mcp\nResults saved to /tmp/mcp-conformance-server-ivrjj_9b/server-server-initialize-2026-09-08T23-47-47-135Z\nChecks:\n\u001b[90m2026-09-08T23:47:47.245Z\u001b[0m [server-initialize ] \u001b[32mSUCCESS\u001b[0m Server responds to initialize request with valid structure\n\u001b[90m2026-09-08T23:47:47.250Z\u001b[0m [server-session-id-visible-ascii] \u001b[36mINFO \u001b[0m Server-provided session ID uses only visible ASCII characters\n\u001b[90m2026-09-08T23:47:47.250Z\u001b[0m [wire-schema-valid ] \u001b[32mSUCCESS\u001b[0m Every JSON-RPC message the implementation sent is valid per the spec JSON schema for the negotiated spec version\n\nTest Results:\nPassed: 2/2, 0 failed, 0 warnings\n", + "stdout": "Running client scenario 'server-initialize' against server: http://127.0.0.1:56021/mcp\nResults saved to /tmp/mcp-conformance-server-wr_g595t/server-server-initialize-2026-09-08T23-51-38-160Z\nChecks:\n\u001b[90m2026-09-08T23:51:38.274Z\u001b[0m [server-initialize ] \u001b[32mSUCCESS\u001b[0m Server responds to initialize request with valid structure\n\u001b[90m2026-09-08T23:51:38.280Z\u001b[0m [server-session-id-visible-ascii] \u001b[36mINFO \u001b[0m Server-provided session ID uses only visible ASCII characters\n\u001b[90m2026-09-08T23:51:38.280Z\u001b[0m [wire-schema-valid ] \u001b[32mSUCCESS\u001b[0m Every JSON-RPC message the implementation sent is valid per the spec JSON schema for the negotiated spec version\n\nTest Results:\nPassed: 2/2, 0 failed, 0 warnings\n", "stderr": "" }, { @@ -481,7 +481,7 @@ "name": "Incoming-request", "description": "Received POST request for /mcp (method: initialize)", "status": "INFO", - "timestamp": "2026-09-08T23:47:54.010Z", + "timestamp": "2026-09-08T23:51:45.353Z", "details": { "method": "POST", "path": "/mcp", @@ -506,7 +506,7 @@ "name": "Outgoing-response", "description": "Sent 401 response for POST /mcp (method: initialize)", "status": "INFO", - "timestamp": "2026-09-08T23:47:54.012Z", + "timestamp": "2026-09-08T23:51:45.355Z", "details": { "method": "POST", "path": "/mcp", @@ -530,7 +530,7 @@ "name": "Incoming-request", "description": "Received GET request for /.well-known/oauth-protected-resource/mcp", "status": "INFO", - "timestamp": "2026-09-08T23:47:54.020Z", + "timestamp": "2026-09-08T23:51:45.364Z", "details": { "method": "GET", "path": "/.well-known/oauth-protected-resource/mcp" @@ -541,7 +541,7 @@ "name": "Outgoing-response", "description": "Sent 404 response for GET /.well-known/oauth-protected-resource/mcp", "status": "INFO", - "timestamp": "2026-09-08T23:47:54.021Z", + "timestamp": "2026-09-08T23:51:45.365Z", "details": { "method": "GET", "path": "/.well-known/oauth-protected-resource/mcp", @@ -561,7 +561,7 @@ "name": "Incoming-request", "description": "Received GET request for /.well-known/oauth-protected-resource", "status": "INFO", - "timestamp": "2026-09-08T23:47:54.023Z", + "timestamp": "2026-09-08T23:51:45.367Z", "details": { "method": "GET", "path": "/.well-known/oauth-protected-resource" @@ -572,7 +572,7 @@ "name": "PRMPathBasedRequested", "description": "Client requested PRM metadata at path-based location", "status": "SUCCESS", - "timestamp": "2026-09-08T23:47:54.023Z", + "timestamp": "2026-09-08T23:51:45.367Z", "specReferences": [ { "id": "RFC-9728", @@ -593,7 +593,7 @@ "name": "Outgoing-response", "description": "Sent 200 response for GET /.well-known/oauth-protected-resource", "status": "INFO", - "timestamp": "2026-09-08T23:47:54.023Z", + "timestamp": "2026-09-08T23:51:45.367Z", "details": { "method": "GET", "path": "/.well-known/oauth-protected-resource", @@ -602,12 +602,12 @@ "x-powered-by": "Express", "content-type": "application/json; charset=utf-8", "content-length": "96", - "etag": "W/\"60-61cTAqeQ9s3o3vshSmprUp2i1lo\"" + "etag": "W/\"60-jXhMHvEX+PZGQ4I80/MZXGEOo5M\"" }, "body": { - "resource": "http://localhost:46209", + "resource": "http://localhost:44289", "authorization_servers": [ - "http://localhost:40391/tenant1" + "http://localhost:37107/tenant1" ] } } @@ -617,7 +617,7 @@ "name": "Incoming-auth-request", "description": "Received GET request for /.well-known/oauth-authorization-server/tenant1", "status": "INFO", - "timestamp": "2026-09-08T23:47:54.030Z", + "timestamp": "2026-09-08T23:51:45.375Z", "details": { "method": "GET", "path": "/.well-known/oauth-authorization-server/tenant1" @@ -628,7 +628,7 @@ "name": "AuthorizationServerMetadata", "description": "Client requested authorization server metadata", "status": "SUCCESS", - "timestamp": "2026-09-08T23:47:54.030Z", + "timestamp": "2026-09-08T23:51:45.375Z", "specReferences": [ { "id": "RFC-8414-metadata-request", @@ -649,7 +649,7 @@ "name": "Outgoing-auth-response", "description": "Sent 200 response for GET /.well-known/oauth-authorization-server/tenant1", "status": "INFO", - "timestamp": "2026-09-08T23:47:54.031Z", + "timestamp": "2026-09-08T23:51:45.375Z", "details": { "method": "GET", "path": "/.well-known/oauth-authorization-server/tenant1", @@ -658,13 +658,13 @@ "x-powered-by": "Express", "content-type": "application/json; charset=utf-8", "content-length": "479", - "etag": "W/\"1df-x59Pnsa5T7Y0DJvE8f0aUFKsN2s\"" + "etag": "W/\"1df-Evn1/r0opr/ITU52Q3op8J9booM\"" }, "body": { - "issuer": "http://localhost:40391/tenant1", - "authorization_endpoint": "http://localhost:40391/tenant1/authorize", - "token_endpoint": "http://localhost:40391/tenant1/token", - "registration_endpoint": "http://localhost:40391/tenant1/register", + "issuer": "http://localhost:37107/tenant1", + "authorization_endpoint": "http://localhost:37107/tenant1/authorize", + "token_endpoint": "http://localhost:37107/tenant1/token", + "registration_endpoint": "http://localhost:37107/tenant1/register", "response_types_supported": [ "code" ], @@ -687,7 +687,7 @@ "name": "Incoming-auth-request", "description": "Received POST request for /tenant1/register", "status": "INFO", - "timestamp": "2026-09-08T23:47:54.035Z", + "timestamp": "2026-09-08T23:51:45.381Z", "details": { "method": "POST", "path": "/tenant1/register", @@ -705,7 +705,7 @@ "name": "ClientRegistration", "description": "Client registered with authorization server", "status": "SUCCESS", - "timestamp": "2026-09-08T23:47:54.035Z", + "timestamp": "2026-09-08T23:51:45.381Z", "specReferences": [ { "id": "MCP-Dynamic-client-registration", @@ -722,7 +722,7 @@ "name": "DCR application_type specified", "description": "Client specified application_type \"native\" during Dynamic Client Registration", "status": "SUCCESS", - "timestamp": "2026-09-08T23:47:54.035Z", + "timestamp": "2026-09-08T23:51:45.381Z", "specReferences": [ { "id": "MCP-Dynamic-client-registration", @@ -738,7 +738,7 @@ "name": "Outgoing-auth-response", "description": "Sent 201 response for POST /tenant1/register", "status": "INFO", - "timestamp": "2026-09-08T23:47:54.035Z", + "timestamp": "2026-09-08T23:51:45.381Z", "details": { "method": "POST", "path": "/tenant1/register", @@ -764,17 +764,17 @@ "name": "Incoming-auth-request", "description": "Received GET request for /tenant1/authorize", "status": "INFO", - "timestamp": "2026-09-08T23:47:54.042Z", + "timestamp": "2026-09-08T23:51:45.388Z", "details": { "method": "GET", "path": "/tenant1/authorize", "query": { "response_type": "code", "client_id": "test-client-id", - "code_challenge": "rwWoaxCgmEQ8RHMQXPVrKrI8tKEJDlsodFkc-wIo96c", + "code_challenge": "jSi8MOZWNO4dg4ibVwZar6mqtjXDYjsgAUCM31owIxg", "code_challenge_method": "S256", "redirect_uri": "http://localhost:3000/callback", - "resource": "http://localhost:46209" + "resource": "http://localhost:44289" } } }, @@ -783,7 +783,7 @@ "name": "AuthorizationRequest", "description": "Client made authorization request", "status": "SUCCESS", - "timestamp": "2026-09-08T23:47:54.042Z", + "timestamp": "2026-09-08T23:51:45.388Z", "specReferences": [ { "id": "OAUTH-2.1-authorization-endpoint", @@ -794,10 +794,10 @@ "query": { "response_type": "code", "client_id": "test-client-id", - "code_challenge": "rwWoaxCgmEQ8RHMQXPVrKrI8tKEJDlsodFkc-wIo96c", + "code_challenge": "jSi8MOZWNO4dg4ibVwZar6mqtjXDYjsgAUCM31owIxg", "code_challenge_method": "S256", "redirect_uri": "http://localhost:3000/callback", - "resource": "http://localhost:46209" + "resource": "http://localhost:44289" } } }, @@ -806,7 +806,7 @@ "name": "PKCE Code Challenge", "description": "Client sent code_challenge in authorization request", "status": "SUCCESS", - "timestamp": "2026-09-08T23:47:54.042Z", + "timestamp": "2026-09-08T23:51:45.388Z", "specReferences": [ { "id": "MCP-PKCE-requirement", @@ -819,7 +819,7 @@ "name": "PKCE S256 Method", "description": "Client used S256 code challenge method", "status": "SUCCESS", - "timestamp": "2026-09-08T23:47:54.042Z", + "timestamp": "2026-09-08T23:51:45.388Z", "specReferences": [ { "id": "MCP-PKCE-requirement", @@ -835,19 +835,19 @@ "name": "Outgoing-auth-response", "description": "Sent 302 response for GET /tenant1/authorize", "status": "INFO", - "timestamp": "2026-09-08T23:47:54.044Z", + "timestamp": "2026-09-08T23:51:45.390Z", "details": { "method": "GET", "path": "/tenant1/authorize", "statusCode": 302, "headers": { "x-powered-by": "Express", - "location": "http://localhost:3000/callback?code=test-auth-code&iss=http%3A%2F%2Flocalhost%3A40391%2Ftenant1", + "location": "http://localhost:3000/callback?code=test-auth-code&iss=http%3A%2F%2Flocalhost%3A37107%2Ftenant1", "vary": "Accept", "content-type": "text/plain; charset=utf-8", "content-length": "117" }, - "body": "Found. Redirecting to http://localhost:3000/callback?code=test-auth-code&iss=http%3A%2F%2Flocalhost%3A40391%2Ftenant1" + "body": "Found. Redirecting to http://localhost:3000/callback?code=test-auth-code&iss=http%3A%2F%2Flocalhost%3A37107%2Ftenant1" } }, { @@ -855,7 +855,7 @@ "name": "Incoming-request", "description": "Received GET request for /.well-known/oauth-protected-resource/mcp", "status": "INFO", - "timestamp": "2026-09-08T23:47:54.046Z", + "timestamp": "2026-09-08T23:51:45.393Z", "details": { "method": "GET", "path": "/.well-known/oauth-protected-resource/mcp" @@ -866,7 +866,7 @@ "name": "Outgoing-response", "description": "Sent 404 response for GET /.well-known/oauth-protected-resource/mcp", "status": "INFO", - "timestamp": "2026-09-08T23:47:54.046Z", + "timestamp": "2026-09-08T23:51:45.393Z", "details": { "method": "GET", "path": "/.well-known/oauth-protected-resource/mcp", @@ -886,7 +886,7 @@ "name": "Incoming-request", "description": "Received GET request for /.well-known/oauth-protected-resource", "status": "INFO", - "timestamp": "2026-09-08T23:47:54.049Z", + "timestamp": "2026-09-08T23:51:45.396Z", "details": { "method": "GET", "path": "/.well-known/oauth-protected-resource" @@ -897,7 +897,7 @@ "name": "PRMPathBasedRequested", "description": "Client requested PRM metadata at path-based location", "status": "SUCCESS", - "timestamp": "2026-09-08T23:47:54.049Z", + "timestamp": "2026-09-08T23:51:45.396Z", "specReferences": [ { "id": "RFC-9728", @@ -918,7 +918,7 @@ "name": "Outgoing-response", "description": "Sent 200 response for GET /.well-known/oauth-protected-resource", "status": "INFO", - "timestamp": "2026-09-08T23:47:54.049Z", + "timestamp": "2026-09-08T23:51:45.396Z", "details": { "method": "GET", "path": "/.well-known/oauth-protected-resource", @@ -927,12 +927,12 @@ "x-powered-by": "Express", "content-type": "application/json; charset=utf-8", "content-length": "96", - "etag": "W/\"60-61cTAqeQ9s3o3vshSmprUp2i1lo\"" + "etag": "W/\"60-jXhMHvEX+PZGQ4I80/MZXGEOo5M\"" }, "body": { - "resource": "http://localhost:46209", + "resource": "http://localhost:44289", "authorization_servers": [ - "http://localhost:40391/tenant1" + "http://localhost:37107/tenant1" ] } } @@ -942,7 +942,7 @@ "name": "Incoming-auth-request", "description": "Received GET request for /.well-known/oauth-authorization-server/tenant1", "status": "INFO", - "timestamp": "2026-09-08T23:47:54.052Z", + "timestamp": "2026-09-08T23:51:45.399Z", "details": { "method": "GET", "path": "/.well-known/oauth-authorization-server/tenant1" @@ -953,7 +953,7 @@ "name": "AuthorizationServerMetadata", "description": "Client requested authorization server metadata", "status": "SUCCESS", - "timestamp": "2026-09-08T23:47:54.052Z", + "timestamp": "2026-09-08T23:51:45.399Z", "specReferences": [ { "id": "RFC-8414-metadata-request", @@ -974,7 +974,7 @@ "name": "Outgoing-auth-response", "description": "Sent 200 response for GET /.well-known/oauth-authorization-server/tenant1", "status": "INFO", - "timestamp": "2026-09-08T23:47:54.052Z", + "timestamp": "2026-09-08T23:51:45.399Z", "details": { "method": "GET", "path": "/.well-known/oauth-authorization-server/tenant1", @@ -983,13 +983,13 @@ "x-powered-by": "Express", "content-type": "application/json; charset=utf-8", "content-length": "479", - "etag": "W/\"1df-x59Pnsa5T7Y0DJvE8f0aUFKsN2s\"" + "etag": "W/\"1df-Evn1/r0opr/ITU52Q3op8J9booM\"" }, "body": { - "issuer": "http://localhost:40391/tenant1", - "authorization_endpoint": "http://localhost:40391/tenant1/authorize", - "token_endpoint": "http://localhost:40391/tenant1/token", - "registration_endpoint": "http://localhost:40391/tenant1/register", + "issuer": "http://localhost:37107/tenant1", + "authorization_endpoint": "http://localhost:37107/tenant1/authorize", + "token_endpoint": "http://localhost:37107/tenant1/token", + "registration_endpoint": "http://localhost:37107/tenant1/register", "response_types_supported": [ "code" ], @@ -1012,16 +1012,16 @@ "name": "Incoming-auth-request", "description": "Received POST request for /tenant1/token", "status": "INFO", - "timestamp": "2026-09-08T23:47:54.057Z", + "timestamp": "2026-09-08T23:51:45.406Z", "details": { "method": "POST", "path": "/tenant1/token", "body": { "grant_type": "authorization_code", "code": "test-auth-code", - "code_verifier": "V4y3IwTmW.ircYLUurTklbtf-2uuhHnuQYBeO7bsxQ0", + "code_verifier": "GeP~DC2vkUouVgwmUd_Wk0U2rujkkIEnlATJ4YFxsWv", "redirect_uri": "http://localhost:3000/callback", - "resource": "http://localhost:46209", + "resource": "http://localhost:44289", "client_id": "test-client-id" } } @@ -1031,7 +1031,7 @@ "name": "TokenRequest", "description": "Client requested access token", "status": "SUCCESS", - "timestamp": "2026-09-08T23:47:54.058Z", + "timestamp": "2026-09-08T23:51:45.406Z", "specReferences": [ { "id": "OAUTH-2.1-token-request", @@ -1048,7 +1048,7 @@ "name": "PKCE Code Verifier", "description": "Client sent code_verifier in token request", "status": "SUCCESS", - "timestamp": "2026-09-08T23:47:54.058Z", + "timestamp": "2026-09-08T23:51:45.406Z", "specReferences": [ { "id": "MCP-PKCE-requirement", @@ -1061,7 +1061,7 @@ "name": "PKCE Verifier Validation", "description": "code_verifier correctly matches code_challenge (S256)", "status": "SUCCESS", - "timestamp": "2026-09-08T23:47:54.058Z", + "timestamp": "2026-09-08T23:51:45.406Z", "specReferences": [ { "id": "MCP-PKCE-requirement", @@ -1070,8 +1070,8 @@ ], "details": { "matches": true, - "storedChallenge": "rwWoaxCgmEQ8RHMQXPVrKrI8tKEJDlsodFkc-wIo96c", - "computedChallenge": "rwWoaxCgmEQ8RHMQXPVrKrI8tKEJDlsodFkc-wIo96c" + "storedChallenge": "jSi8MOZWNO4dg4ibVwZar6mqtjXDYjsgAUCM31owIxg", + "computedChallenge": "jSi8MOZWNO4dg4ibVwZar6mqtjXDYjsgAUCM31owIxg" } }, { @@ -1079,7 +1079,7 @@ "name": "Outgoing-auth-response", "description": "Sent 200 response for POST /tenant1/token", "status": "INFO", - "timestamp": "2026-09-08T23:47:54.058Z", + "timestamp": "2026-09-08T23:51:45.406Z", "details": { "method": "POST", "path": "/tenant1/token", @@ -1088,10 +1088,10 @@ "x-powered-by": "Express", "content-type": "application/json; charset=utf-8", "content-length": "83", - "etag": "W/\"53-2wND0a0ZMq7RW6Df/UhCYSBw1Qg\"" + "etag": "W/\"53-NPMnJBuWFI2/kTGncSBE/PODZaU\"" }, "body": { - "access_token": "test-token-1788911274058", + "access_token": "test-token-1788911505406", "token_type": "Bearer", "expires_in": 3600 } @@ -1102,7 +1102,7 @@ "name": "Incoming-request", "description": "Received POST request for /mcp (method: initialize)", "status": "INFO", - "timestamp": "2026-09-08T23:47:54.061Z", + "timestamp": "2026-09-08T23:51:45.411Z", "details": { "method": "POST", "path": "/mcp", @@ -1127,7 +1127,7 @@ "name": "ValidBearerToken", "description": "Client provided valid bearer token", "status": "SUCCESS", - "timestamp": "2026-09-08T23:47:54.062Z", + "timestamp": "2026-09-08T23:51:45.411Z", "specReferences": [ { "id": "MCP-Access-token-usage", @@ -1144,7 +1144,7 @@ "name": "Outgoing-response", "description": "Sent 400 response for POST /mcp (method: initialize)", "status": "INFO", - "timestamp": "2026-09-08T23:47:54.062Z", + "timestamp": "2026-09-08T23:51:45.411Z", "details": { "method": "POST", "path": "/mcp", @@ -1171,7 +1171,7 @@ "name": "Resource parameter in authorization request", "description": "Client included resource parameter in authorization request", "status": "SUCCESS", - "timestamp": "2026-09-08T23:47:54.082Z", + "timestamp": "2026-09-08T23:51:45.432Z", "specReferences": [ { "id": "RFC-8707-Resource-Indicators", @@ -1183,7 +1183,7 @@ } ], "details": { - "resource": "http://localhost:46209" + "resource": "http://localhost:44289" } }, { @@ -1191,7 +1191,7 @@ "name": "Resource parameter in token request", "description": "Client included resource parameter in token request", "status": "SUCCESS", - "timestamp": "2026-09-08T23:47:54.082Z", + "timestamp": "2026-09-08T23:51:45.432Z", "specReferences": [ { "id": "RFC-8707-Resource-Indicators", @@ -1203,7 +1203,7 @@ } ], "details": { - "resource": "http://localhost:46209" + "resource": "http://localhost:44289" } }, { @@ -1211,7 +1211,7 @@ "name": "Resource parameter is valid canonical URI", "description": "Resource parameter is a valid canonical URI (has scheme, no fragment)", "status": "SUCCESS", - "timestamp": "2026-09-08T23:47:54.082Z", + "timestamp": "2026-09-08T23:51:45.432Z", "specReferences": [ { "id": "RFC-8707-Resource-Indicators", @@ -1223,7 +1223,7 @@ } ], "details": { - "resource": "http://localhost:46209" + "resource": "http://localhost:44289" } }, { @@ -1231,7 +1231,7 @@ "name": "Resource parameter consistency", "description": "Resource parameter is consistent between authorization and token requests", "status": "SUCCESS", - "timestamp": "2026-09-08T23:47:54.082Z", + "timestamp": "2026-09-08T23:51:45.432Z", "specReferences": [ { "id": "RFC-8707-Resource-Indicators", @@ -1243,8 +1243,8 @@ } ], "details": { - "authorizationResource": "http://localhost:46209", - "tokenResource": "http://localhost:46209" + "authorizationResource": "http://localhost:44289", + "tokenResource": "http://localhost:44289" } }, { @@ -1252,7 +1252,7 @@ "name": "Resource parameter matches protected resource metadata", "description": "Client sent the resource identifier exactly as published in protected resource metadata", "status": "SUCCESS", - "timestamp": "2026-09-08T23:47:54.082Z", + "timestamp": "2026-09-08T23:51:45.432Z", "specReferences": [ { "id": "RFC-8707-Resource-Indicators", @@ -1272,14 +1272,14 @@ } ], "details": { - "prmResource": "http://localhost:46209", - "authorizationResource": "http://localhost:46209", - "tokenResource": "http://localhost:46209" + "prmResource": "http://localhost:44289", + "authorizationResource": "http://localhost:44289", + "tokenResource": "http://localhost:44289" } } ], "stdout": "", - "stderr": "Starting scenario: auth/metadata-var2\nExecuting client: node /home/runner/work/EventRelay/EventRelay/tests/testing/official_mcp_auth_client.mjs http://localhost:46209/mcp\n(node:8954) [DEP0190] DeprecationWarning: Passing args to a child process with shell option true can lead to security vulnerabilities, as the arguments are not escaped, only concatenated.\n(Use `node --trace-deprecation ...` to show where the warning was created)\n\nClient exited with code 1\n\nStderr:\nError: Streamable HTTP error: Error POSTing to endpoint: {\"jsonrpc\":\"2.0\",\"id\":0,\"error\":{\"code\":-32020,\"message\":\"Missing MCP-Protocol-Version header\"}}\n at StreamableHTTPClientTransport.send (file:///home/runner/work/EventRelay/EventRelay/node_modules/@modelcontextprotocol/sdk/dist/esm/client/streamableHttp.js:365:23)\n at process.processTicksAndRejections (node:internal/process/task_queues:104:5)\n\nResults saved to /tmp/mcp-conformance-client-m6ywh1oh/auth/metadata-var2-2026-09-08T23-47-53-767Z\nChecks:\n\u001b[90m2026-09-08T23:47:54.010Z\u001b[0m [incoming-request ] \u001b[36mINFO \u001b[0m Received POST request for /mcp (method: initialize)\n\u001b[90m2026-09-08T23:47:54.012Z\u001b[0m [outgoing-response ] \u001b[36mINFO \u001b[0m Sent 401 response for POST /mcp (method: initialize)\n\n\u001b[90m2026-09-08T23:47:54.020Z\u001b[0m [incoming-request ] \u001b[36mINFO \u001b[0m Received GET request for /.well-known/oauth-protected-resource/mcp\n\u001b[90m2026-09-08T23:47:54.021Z\u001b[0m [outgoing-response ] \u001b[36mINFO \u001b[0m Sent 404 response for GET /.well-known/oauth-protected-resource/mcp\n\n\u001b[90m2026-09-08T23:47:54.023Z\u001b[0m [incoming-request ] \u001b[36mINFO \u001b[0m Received GET request for /.well-known/oauth-protected-resource\n\u001b[90m2026-09-08T23:47:54.023Z\u001b[0m [prm-pathbased-requested ] \u001b[32mSUCCESS\u001b[0m Client requested PRM metadata at path-based location\n\u001b[90m2026-09-08T23:47:54.023Z\u001b[0m [outgoing-response ] \u001b[36mINFO \u001b[0m Sent 200 response for GET /.well-known/oauth-protected-resource\n\n\u001b[90m2026-09-08T23:47:54.030Z\u001b[0m [incoming-auth-request ] \u001b[36mINFO \u001b[0m Received GET request for /.well-known/oauth-authorization-server/tenant1\n\u001b[90m2026-09-08T23:47:54.030Z\u001b[0m [authorization-server-metadata ] \u001b[32mSUCCESS\u001b[0m Client requested authorization server metadata\n\u001b[90m2026-09-08T23:47:54.031Z\u001b[0m [outgoing-auth-response ] \u001b[36mINFO \u001b[0m Sent 200 response for GET /.well-known/oauth-authorization-server/tenant1\n\n\u001b[90m2026-09-08T23:47:54.035Z\u001b[0m [incoming-auth-request ] \u001b[36mINFO \u001b[0m Received POST request for /tenant1/register\n\u001b[90m2026-09-08T23:47:54.035Z\u001b[0m [client-registration ] \u001b[32mSUCCESS\u001b[0m Client registered with authorization server\n\u001b[90m2026-09-08T23:47:54.035Z\u001b[0m [sep-837-application-type-present ] \u001b[32mSUCCESS\u001b[0m Client specified application_type \"native\" during Dynamic Client Registration\n\u001b[90m2026-09-08T23:47:54.035Z\u001b[0m [outgoing-auth-response ] \u001b[36mINFO \u001b[0m Sent 201 response for POST /tenant1/register\n\n\u001b[90m2026-09-08T23:47:54.042Z\u001b[0m [incoming-auth-request ] \u001b[36mINFO \u001b[0m Received GET request for /tenant1/authorize\n\u001b[90m2026-09-08T23:47:54.042Z\u001b[0m [authorization-request ] \u001b[32mSUCCESS\u001b[0m Client made authorization request\n\u001b[90m2026-09-08T23:47:54.042Z\u001b[0m [pkce-code-challenge-sent ] \u001b[32mSUCCESS\u001b[0m Client sent code_challenge in authorization request\n\u001b[90m2026-09-08T23:47:54.042Z\u001b[0m [pkce-s256-method-used ] \u001b[32mSUCCESS\u001b[0m Client used S256 code challenge method\n\u001b[90m2026-09-08T23:47:54.044Z\u001b[0m [outgoing-auth-response ] \u001b[36mINFO \u001b[0m Sent 302 response for GET /tenant1/authorize\n\n\u001b[90m2026-09-08T23:47:54.046Z\u001b[0m [incoming-request ] \u001b[36mINFO \u001b[0m Received GET request for /.well-known/oauth-protected-resource/mcp\n\u001b[90m2026-09-08T23:47:54.046Z\u001b[0m [outgoing-response ] \u001b[36mINFO \u001b[0m Sent 404 response for GET /.well-k\n...[truncated]" + "stderr": "Starting scenario: auth/metadata-var2\nExecuting client: node /home/runner/work/EventRelay/EventRelay/tests/testing/official_mcp_auth_client.mjs http://localhost:44289/mcp\n(node:10622) [DEP0190] DeprecationWarning: Passing args to a child process with shell option true can lead to security vulnerabilities, as the arguments are not escaped, only concatenated.\n(Use `node --trace-deprecation ...` to show where the warning was created)\n\nClient exited with code 1\n\nStderr:\nError: Streamable HTTP error: Error POSTing to endpoint: {\"jsonrpc\":\"2.0\",\"id\":0,\"error\":{\"code\":-32020,\"message\":\"Missing MCP-Protocol-Version header\"}}\n at StreamableHTTPClientTransport.send (file:///home/runner/work/EventRelay/EventRelay/node_modules/@modelcontextprotocol/sdk/dist/esm/client/streamableHttp.js:365:23)\n at process.processTicksAndRejections (node:internal/process/task_queues:104:5)\n\nResults saved to /tmp/mcp-conformance-client-7n8435f8/auth/metadata-var2-2026-09-08T23-51-45-105Z\nChecks:\n\u001b[90m2026-09-08T23:51:45.353Z\u001b[0m [incoming-request ] \u001b[36mINFO \u001b[0m Received POST request for /mcp (method: initialize)\n\u001b[90m2026-09-08T23:51:45.355Z\u001b[0m [outgoing-response ] \u001b[36mINFO \u001b[0m Sent 401 response for POST /mcp (method: initialize)\n\n\u001b[90m2026-09-08T23:51:45.364Z\u001b[0m [incoming-request ] \u001b[36mINFO \u001b[0m Received GET request for /.well-known/oauth-protected-resource/mcp\n\u001b[90m2026-09-08T23:51:45.365Z\u001b[0m [outgoing-response ] \u001b[36mINFO \u001b[0m Sent 404 response for GET /.well-known/oauth-protected-resource/mcp\n\n\u001b[90m2026-09-08T23:51:45.367Z\u001b[0m [incoming-request ] \u001b[36mINFO \u001b[0m Received GET request for /.well-known/oauth-protected-resource\n\u001b[90m2026-09-08T23:51:45.367Z\u001b[0m [prm-pathbased-requested ] \u001b[32mSUCCESS\u001b[0m Client requested PRM metadata at path-based location\n\u001b[90m2026-09-08T23:51:45.367Z\u001b[0m [outgoing-response ] \u001b[36mINFO \u001b[0m Sent 200 response for GET /.well-known/oauth-protected-resource\n\n\u001b[90m2026-09-08T23:51:45.375Z\u001b[0m [incoming-auth-request ] \u001b[36mINFO \u001b[0m Received GET request for /.well-known/oauth-authorization-server/tenant1\n\u001b[90m2026-09-08T23:51:45.375Z\u001b[0m [authorization-server-metadata ] \u001b[32mSUCCESS\u001b[0m Client requested authorization server metadata\n\u001b[90m2026-09-08T23:51:45.375Z\u001b[0m [outgoing-auth-response ] \u001b[36mINFO \u001b[0m Sent 200 response for GET /.well-known/oauth-authorization-server/tenant1\n\n\u001b[90m2026-09-08T23:51:45.381Z\u001b[0m [incoming-auth-request ] \u001b[36mINFO \u001b[0m Received POST request for /tenant1/register\n\u001b[90m2026-09-08T23:51:45.381Z\u001b[0m [client-registration ] \u001b[32mSUCCESS\u001b[0m Client registered with authorization server\n\u001b[90m2026-09-08T23:51:45.381Z\u001b[0m [sep-837-application-type-present ] \u001b[32mSUCCESS\u001b[0m Client specified application_type \"native\" during Dynamic Client Registration\n\u001b[90m2026-09-08T23:51:45.381Z\u001b[0m [outgoing-auth-response ] \u001b[36mINFO \u001b[0m Sent 201 response for POST /tenant1/register\n\n\u001b[90m2026-09-08T23:51:45.388Z\u001b[0m [incoming-auth-request ] \u001b[36mINFO \u001b[0m Received GET request for /tenant1/authorize\n\u001b[90m2026-09-08T23:51:45.388Z\u001b[0m [authorization-request ] \u001b[32mSUCCESS\u001b[0m Client made authorization request\n\u001b[90m2026-09-08T23:51:45.388Z\u001b[0m [pkce-code-challenge-sent ] \u001b[32mSUCCESS\u001b[0m Client sent code_challenge in authorization request\n\u001b[90m2026-09-08T23:51:45.388Z\u001b[0m [pkce-s256-method-used ] \u001b[32mSUCCESS\u001b[0m Client used S256 code challenge method\n\u001b[90m2026-09-08T23:51:45.390Z\u001b[0m [outgoing-auth-response ] \u001b[36mINFO \u001b[0m Sent 302 response for GET /tenant1/authorize\n\n\u001b[90m2026-09-08T23:51:45.393Z\u001b[0m [incoming-request ] \u001b[36mINFO \u001b[0m Received GET request for /.well-known/oauth-protected-resource/mcp\n\u001b[90m2026-09-08T23:51:45.393Z\u001b[0m [outgoing-response ] \u001b[36mINFO \u001b[0m Sent 404 response for GET /.well-\n...[truncated]" }, { "leg": "client", @@ -1303,7 +1303,7 @@ "name": "Incoming-request", "description": "Received POST request for /mcp (method: initialize)", "status": "INFO", - "timestamp": "2026-09-08T23:48:00.871Z", + "timestamp": "2026-09-08T23:51:52.444Z", "details": { "method": "POST", "path": "/mcp", @@ -1328,7 +1328,7 @@ "name": "Outgoing-response", "description": "Sent 401 response for POST /mcp (method: initialize)", "status": "INFO", - "timestamp": "2026-09-08T23:48:00.873Z", + "timestamp": "2026-09-08T23:51:52.446Z", "details": { "method": "POST", "path": "/mcp", @@ -1336,7 +1336,7 @@ "mcpMethod": "initialize", "headers": { "x-powered-by": "Express", - "www-authenticate": "Bearer error=\"invalid_token\", error_description=\"Missing Authorization header\", resource_metadata=\"http://localhost:46773/.well-known/oauth-protected-resource/mcp\"", + "www-authenticate": "Bearer error=\"invalid_token\", error_description=\"Missing Authorization header\", resource_metadata=\"http://localhost:39749/.well-known/oauth-protected-resource/mcp\"", "content-type": "application/json; charset=utf-8", "content-length": "76", "etag": "W/\"4c-ptrIdu+3yjAtarglCEu6XVLnz2c\"" @@ -1352,7 +1352,7 @@ "name": "Incoming-request", "description": "Received GET request for /.well-known/oauth-protected-resource/mcp", "status": "INFO", - "timestamp": "2026-09-08T23:48:00.881Z", + "timestamp": "2026-09-08T23:51:52.455Z", "details": { "method": "GET", "path": "/.well-known/oauth-protected-resource/mcp" @@ -1363,7 +1363,7 @@ "name": "PRMPathBasedRequested", "description": "Client requested PRM metadata at path-based location", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:00.881Z", + "timestamp": "2026-09-08T23:51:52.455Z", "specReferences": [ { "id": "RFC-9728", @@ -1384,7 +1384,7 @@ "name": "Outgoing-response", "description": "Sent 200 response for GET /.well-known/oauth-protected-resource/mcp", "status": "INFO", - "timestamp": "2026-09-08T23:48:00.882Z", + "timestamp": "2026-09-08T23:51:52.456Z", "details": { "method": "GET", "path": "/.well-known/oauth-protected-resource/mcp", @@ -1393,12 +1393,12 @@ "x-powered-by": "Express", "content-type": "application/json; charset=utf-8", "content-length": "92", - "etag": "W/\"5c-pPdYsXbZmxVJqA2xjkEnGEnTUbU\"" + "etag": "W/\"5c-cCdQ1TyFCxDv12q1YWdFACKN+6c\"" }, "body": { - "resource": "http://localhost:46773/mcp", + "resource": "http://localhost:39749/mcp", "authorization_servers": [ - "http://localhost:35049" + "http://localhost:43743" ] } } @@ -1408,7 +1408,7 @@ "name": "Incoming-auth-request", "description": "Received GET request for /.well-known/oauth-authorization-server", "status": "INFO", - "timestamp": "2026-09-08T23:48:00.889Z", + "timestamp": "2026-09-08T23:51:52.463Z", "details": { "method": "GET", "path": "/.well-known/oauth-authorization-server" @@ -1419,7 +1419,7 @@ "name": "AuthorizationServerMetadata", "description": "Client requested authorization server metadata", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:00.889Z", + "timestamp": "2026-09-08T23:51:52.464Z", "specReferences": [ { "id": "RFC-8414-metadata-request", @@ -1440,7 +1440,7 @@ "name": "Outgoing-auth-response", "description": "Sent 200 response for GET /.well-known/oauth-authorization-server", "status": "INFO", - "timestamp": "2026-09-08T23:48:00.889Z", + "timestamp": "2026-09-08T23:51:52.464Z", "details": { "method": "GET", "path": "/.well-known/oauth-authorization-server", @@ -1449,13 +1449,13 @@ "x-powered-by": "Express", "content-type": "application/json; charset=utf-8", "content-length": "462", - "etag": "W/\"1ce-aWEEAhA7auFXnE2O6CESHdPJ3T0\"" + "etag": "W/\"1ce-YFhJJH2dWsMhjJ+jVcYDEh+XnuY\"" }, "body": { - "issuer": "http://localhost:35049", - "authorization_endpoint": "http://localhost:35049/authorize", - "token_endpoint": "http://localhost:35049/token", - "registration_endpoint": "http://localhost:35049/register", + "issuer": "http://localhost:43743", + "authorization_endpoint": "http://localhost:43743/authorize", + "token_endpoint": "http://localhost:43743/token", + "registration_endpoint": "http://localhost:43743/register", "response_types_supported": [ "code" ], @@ -1478,7 +1478,7 @@ "name": "Incoming-auth-request", "description": "Received POST request for /register", "status": "INFO", - "timestamp": "2026-09-08T23:48:00.894Z", + "timestamp": "2026-09-08T23:51:52.469Z", "details": { "method": "POST", "path": "/register", @@ -1496,7 +1496,7 @@ "name": "ClientRegistration", "description": "Client registered with authorization server", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:00.894Z", + "timestamp": "2026-09-08T23:51:52.469Z", "specReferences": [ { "id": "MCP-Dynamic-client-registration", @@ -1514,7 +1514,7 @@ "name": "DCR application_type specified", "description": "Client specified application_type \"native\" during Dynamic Client Registration", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:00.894Z", + "timestamp": "2026-09-08T23:51:52.469Z", "specReferences": [ { "id": "MCP-Dynamic-client-registration", @@ -1530,7 +1530,7 @@ "name": "Outgoing-auth-response", "description": "Sent 201 response for POST /register", "status": "INFO", - "timestamp": "2026-09-08T23:48:00.894Z", + "timestamp": "2026-09-08T23:51:52.469Z", "details": { "method": "POST", "path": "/register", @@ -1539,11 +1539,11 @@ "x-powered-by": "Express", "content-type": "application/json; charset=utf-8", "content-length": "233", - "etag": "W/\"e9-/NJHNWIufWKRG+L8J+RjiU3ws7M\"" + "etag": "W/\"e9-fmquPNg6IVD5Enw9g2ddMfRZFSU\"" }, "body": { - "client_id": "test-client-1788911280894", - "client_secret": "test-secret-1788911280894", + "client_id": "test-client-1788911512469", + "client_secret": "test-secret-1788911512469", "client_name": "eventrelay-conformance-client", "redirect_uris": [ "http://localhost:3000/callback" @@ -1557,17 +1557,17 @@ "name": "Incoming-auth-request", "description": "Received GET request for /authorize", "status": "INFO", - "timestamp": "2026-09-08T23:48:00.901Z", + "timestamp": "2026-09-08T23:51:52.476Z", "details": { "method": "GET", "path": "/authorize", "query": { "response_type": "code", - "client_id": "test-client-1788911280894", - "code_challenge": "L7--IPmx6hnGHuOW3TReEmJIAMneez95fkZF9BtjYbI", + "client_id": "test-client-1788911512469", + "code_challenge": "q8XslQR1t3SnTeMH1oqDFUntILGmIfzlt9SC_1SduRI", "code_challenge_method": "S256", "redirect_uri": "http://localhost:3000/callback", - "resource": "http://localhost:46773/mcp" + "resource": "http://localhost:39749/mcp" } } }, @@ -1576,7 +1576,7 @@ "name": "AuthorizationRequest", "description": "Client made authorization request", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:00.901Z", + "timestamp": "2026-09-08T23:51:52.477Z", "specReferences": [ { "id": "OAUTH-2.1-authorization-endpoint", @@ -1586,11 +1586,11 @@ "details": { "query": { "response_type": "code", - "client_id": "test-client-1788911280894", - "code_challenge": "L7--IPmx6hnGHuOW3TReEmJIAMneez95fkZF9BtjYbI", + "client_id": "test-client-1788911512469", + "code_challenge": "q8XslQR1t3SnTeMH1oqDFUntILGmIfzlt9SC_1SduRI", "code_challenge_method": "S256", "redirect_uri": "http://localhost:3000/callback", - "resource": "http://localhost:46773/mcp" + "resource": "http://localhost:39749/mcp" } } }, @@ -1599,7 +1599,7 @@ "name": "PKCE Code Challenge", "description": "Client sent code_challenge in authorization request", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:00.901Z", + "timestamp": "2026-09-08T23:51:52.477Z", "specReferences": [ { "id": "MCP-PKCE-requirement", @@ -1612,7 +1612,7 @@ "name": "PKCE S256 Method", "description": "Client used S256 code challenge method", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:00.901Z", + "timestamp": "2026-09-08T23:51:52.477Z", "specReferences": [ { "id": "MCP-PKCE-requirement", @@ -1628,19 +1628,19 @@ "name": "Outgoing-auth-response", "description": "Sent 302 response for GET /authorize", "status": "INFO", - "timestamp": "2026-09-08T23:48:00.903Z", + "timestamp": "2026-09-08T23:51:52.479Z", "details": { "method": "GET", "path": "/authorize", "statusCode": 302, "headers": { "x-powered-by": "Express", - "location": "http://localhost:3000/callback?code=test-auth-code&iss=http%3A%2F%2Flocalhost%3A35049", + "location": "http://localhost:3000/callback?code=test-auth-code&iss=http%3A%2F%2Flocalhost%3A43743", "vary": "Accept", "content-type": "text/plain; charset=utf-8", "content-length": "107" }, - "body": "Found. Redirecting to http://localhost:3000/callback?code=test-auth-code&iss=http%3A%2F%2Flocalhost%3A35049" + "body": "Found. Redirecting to http://localhost:3000/callback?code=test-auth-code&iss=http%3A%2F%2Flocalhost%3A43743" } }, { @@ -1648,7 +1648,7 @@ "name": "Incoming-request", "description": "Received GET request for /.well-known/oauth-protected-resource/mcp", "status": "INFO", - "timestamp": "2026-09-08T23:48:00.906Z", + "timestamp": "2026-09-08T23:51:52.482Z", "details": { "method": "GET", "path": "/.well-known/oauth-protected-resource/mcp" @@ -1659,7 +1659,7 @@ "name": "PRMPathBasedRequested", "description": "Client requested PRM metadata at path-based location", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:00.906Z", + "timestamp": "2026-09-08T23:51:52.482Z", "specReferences": [ { "id": "RFC-9728", @@ -1680,7 +1680,7 @@ "name": "Outgoing-response", "description": "Sent 200 response for GET /.well-known/oauth-protected-resource/mcp", "status": "INFO", - "timestamp": "2026-09-08T23:48:00.906Z", + "timestamp": "2026-09-08T23:51:52.482Z", "details": { "method": "GET", "path": "/.well-known/oauth-protected-resource/mcp", @@ -1689,12 +1689,12 @@ "x-powered-by": "Express", "content-type": "application/json; charset=utf-8", "content-length": "92", - "etag": "W/\"5c-pPdYsXbZmxVJqA2xjkEnGEnTUbU\"" + "etag": "W/\"5c-cCdQ1TyFCxDv12q1YWdFACKN+6c\"" }, "body": { - "resource": "http://localhost:46773/mcp", + "resource": "http://localhost:39749/mcp", "authorization_servers": [ - "http://localhost:35049" + "http://localhost:43743" ] } } @@ -1704,7 +1704,7 @@ "name": "Incoming-auth-request", "description": "Received GET request for /.well-known/oauth-authorization-server", "status": "INFO", - "timestamp": "2026-09-08T23:48:00.909Z", + "timestamp": "2026-09-08T23:51:52.484Z", "details": { "method": "GET", "path": "/.well-known/oauth-authorization-server" @@ -1715,7 +1715,7 @@ "name": "AuthorizationServerMetadata", "description": "Client requested authorization server metadata", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:00.909Z", + "timestamp": "2026-09-08T23:51:52.484Z", "specReferences": [ { "id": "RFC-8414-metadata-request", @@ -1736,7 +1736,7 @@ "name": "Outgoing-auth-response", "description": "Sent 200 response for GET /.well-known/oauth-authorization-server", "status": "INFO", - "timestamp": "2026-09-08T23:48:00.909Z", + "timestamp": "2026-09-08T23:51:52.484Z", "details": { "method": "GET", "path": "/.well-known/oauth-authorization-server", @@ -1745,13 +1745,13 @@ "x-powered-by": "Express", "content-type": "application/json; charset=utf-8", "content-length": "462", - "etag": "W/\"1ce-aWEEAhA7auFXnE2O6CESHdPJ3T0\"" + "etag": "W/\"1ce-YFhJJH2dWsMhjJ+jVcYDEh+XnuY\"" }, "body": { - "issuer": "http://localhost:35049", - "authorization_endpoint": "http://localhost:35049/authorize", - "token_endpoint": "http://localhost:35049/token", - "registration_endpoint": "http://localhost:35049/register", + "issuer": "http://localhost:43743", + "authorization_endpoint": "http://localhost:43743/authorize", + "token_endpoint": "http://localhost:43743/token", + "registration_endpoint": "http://localhost:43743/register", "response_types_supported": [ "code" ], @@ -1774,16 +1774,16 @@ "name": "Incoming-auth-request", "description": "Received POST request for /token", "status": "INFO", - "timestamp": "2026-09-08T23:48:00.915Z", + "timestamp": "2026-09-08T23:51:52.489Z", "details": { "method": "POST", "path": "/token", "body": { "grant_type": "authorization_code", "code": "test-auth-code", - "code_verifier": "I.PZVHzjWilIcwHiDiwbsO~YshBbLPX4y5AT7Rjcc2H", + "code_verifier": "spPggNypMXCw~msQY15tEiUa6LbdVSbG2tjPFtr-OE1", "redirect_uri": "http://localhost:3000/callback", - "resource": "http://localhost:46773/mcp" + "resource": "http://localhost:39749/mcp" } } }, @@ -1792,7 +1792,7 @@ "name": "TokenRequest", "description": "Client requested access token", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:00.915Z", + "timestamp": "2026-09-08T23:51:52.490Z", "specReferences": [ { "id": "OAUTH-2.1-token-request", @@ -1809,7 +1809,7 @@ "name": "PKCE Code Verifier", "description": "Client sent code_verifier in token request", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:00.915Z", + "timestamp": "2026-09-08T23:51:52.490Z", "specReferences": [ { "id": "MCP-PKCE-requirement", @@ -1822,7 +1822,7 @@ "name": "PKCE Verifier Validation", "description": "code_verifier correctly matches code_challenge (S256)", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:00.915Z", + "timestamp": "2026-09-08T23:51:52.490Z", "specReferences": [ { "id": "MCP-PKCE-requirement", @@ -1831,8 +1831,8 @@ ], "details": { "matches": true, - "storedChallenge": "L7--IPmx6hnGHuOW3TReEmJIAMneez95fkZF9BtjYbI", - "computedChallenge": "L7--IPmx6hnGHuOW3TReEmJIAMneez95fkZF9BtjYbI" + "storedChallenge": "q8XslQR1t3SnTeMH1oqDFUntILGmIfzlt9SC_1SduRI", + "computedChallenge": "q8XslQR1t3SnTeMH1oqDFUntILGmIfzlt9SC_1SduRI" } }, { @@ -1840,7 +1840,7 @@ "name": "Token endpoint authentication method", "description": "Client correctly used HTTP Basic authentication (client_secret_basic) for token endpoint", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:00.915Z", + "timestamp": "2026-09-08T23:51:52.490Z", "specReferences": [ { "id": "OAUTH-2.1-token-request", @@ -1859,7 +1859,7 @@ "name": "Outgoing-auth-response", "description": "Sent 200 response for POST /token", "status": "INFO", - "timestamp": "2026-09-08T23:48:00.916Z", + "timestamp": "2026-09-08T23:51:52.490Z", "details": { "method": "POST", "path": "/token", @@ -1868,10 +1868,10 @@ "x-powered-by": "Express", "content-type": "application/json; charset=utf-8", "content-length": "83", - "etag": "W/\"53-qFHaJmbgAUy2O2/86eZkXeSCnhw\"" + "etag": "W/\"53-JvMktWoKtaugCcn4dR0yqNkHcQ0\"" }, "body": { - "access_token": "test-token-1788911280916", + "access_token": "test-token-1788911512490", "token_type": "Bearer", "expires_in": 3600 } @@ -1882,7 +1882,7 @@ "name": "Incoming-request", "description": "Received POST request for /mcp (method: initialize)", "status": "INFO", - "timestamp": "2026-09-08T23:48:00.920Z", + "timestamp": "2026-09-08T23:51:52.494Z", "details": { "method": "POST", "path": "/mcp", @@ -1907,7 +1907,7 @@ "name": "ValidBearerToken", "description": "Client provided valid bearer token", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:00.920Z", + "timestamp": "2026-09-08T23:51:52.494Z", "specReferences": [ { "id": "MCP-Access-token-usage", @@ -1924,7 +1924,7 @@ "name": "Outgoing-response", "description": "Sent 400 response for POST /mcp (method: initialize)", "status": "INFO", - "timestamp": "2026-09-08T23:48:00.920Z", + "timestamp": "2026-09-08T23:51:52.495Z", "details": { "method": "POST", "path": "/mcp", @@ -1951,7 +1951,7 @@ "name": "Resource parameter in authorization request", "description": "Client included resource parameter in authorization request", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:00.942Z", + "timestamp": "2026-09-08T23:51:52.518Z", "specReferences": [ { "id": "RFC-8707-Resource-Indicators", @@ -1963,7 +1963,7 @@ } ], "details": { - "resource": "http://localhost:46773/mcp" + "resource": "http://localhost:39749/mcp" } }, { @@ -1971,7 +1971,7 @@ "name": "Resource parameter in token request", "description": "Client included resource parameter in token request", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:00.942Z", + "timestamp": "2026-09-08T23:51:52.518Z", "specReferences": [ { "id": "RFC-8707-Resource-Indicators", @@ -1983,7 +1983,7 @@ } ], "details": { - "resource": "http://localhost:46773/mcp" + "resource": "http://localhost:39749/mcp" } }, { @@ -1991,7 +1991,7 @@ "name": "Resource parameter is valid canonical URI", "description": "Resource parameter is a valid canonical URI (has scheme, no fragment)", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:00.942Z", + "timestamp": "2026-09-08T23:51:52.518Z", "specReferences": [ { "id": "RFC-8707-Resource-Indicators", @@ -2003,7 +2003,7 @@ } ], "details": { - "resource": "http://localhost:46773/mcp" + "resource": "http://localhost:39749/mcp" } }, { @@ -2011,7 +2011,7 @@ "name": "Resource parameter consistency", "description": "Resource parameter is consistent between authorization and token requests", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:00.942Z", + "timestamp": "2026-09-08T23:51:52.518Z", "specReferences": [ { "id": "RFC-8707-Resource-Indicators", @@ -2023,8 +2023,8 @@ } ], "details": { - "authorizationResource": "http://localhost:46773/mcp", - "tokenResource": "http://localhost:46773/mcp" + "authorizationResource": "http://localhost:39749/mcp", + "tokenResource": "http://localhost:39749/mcp" } }, { @@ -2032,7 +2032,7 @@ "name": "Resource parameter matches protected resource metadata", "description": "Client sent the resource identifier exactly as published in protected resource metadata", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:00.942Z", + "timestamp": "2026-09-08T23:51:52.518Z", "specReferences": [ { "id": "RFC-8707-Resource-Indicators", @@ -2052,14 +2052,14 @@ } ], "details": { - "prmResource": "http://localhost:46773/mcp", - "authorizationResource": "http://localhost:46773/mcp", - "tokenResource": "http://localhost:46773/mcp" + "prmResource": "http://localhost:39749/mcp", + "authorizationResource": "http://localhost:39749/mcp", + "tokenResource": "http://localhost:39749/mcp" } } ], "stdout": "", - "stderr": "Starting scenario: auth/token-endpoint-auth-basic\nExecuting client: node /home/runner/work/EventRelay/EventRelay/tests/testing/official_mcp_auth_client.mjs http://localhost:46773/mcp\n(node:9098) [DEP0190] DeprecationWarning: Passing args to a child process with shell option true can lead to security vulnerabilities, as the arguments are not escaped, only concatenated.\n(Use `node --trace-deprecation ...` to show where the warning was created)\n\nClient exited with code 1\n\nStderr:\nError: Streamable HTTP error: Error POSTing to endpoint: {\"jsonrpc\":\"2.0\",\"id\":0,\"error\":{\"code\":-32020,\"message\":\"Missing MCP-Protocol-Version header\"}}\n at StreamableHTTPClientTransport.send (file:///home/runner/work/EventRelay/EventRelay/node_modules/@modelcontextprotocol/sdk/dist/esm/client/streamableHttp.js:365:23)\n at process.processTicksAndRejections (node:internal/process/task_queues:104:5)\n\nResults saved to /tmp/mcp-conformance-client-ybhcaa65/auth/token-endpoint-auth-basic-2026-09-08T23-48-00-630Z\nChecks:\n\u001b[90m2026-09-08T23:48:00.871Z\u001b[0m [incoming-request ] \u001b[36mINFO \u001b[0m Received POST request for /mcp (method: initialize)\n\u001b[90m2026-09-08T23:48:00.873Z\u001b[0m [outgoing-response ] \u001b[36mINFO \u001b[0m Sent 401 response for POST /mcp (method: initialize)\n\n\u001b[90m2026-09-08T23:48:00.881Z\u001b[0m [incoming-request ] \u001b[36mINFO \u001b[0m Received GET request for /.well-known/oauth-protected-resource/mcp\n\u001b[90m2026-09-08T23:48:00.881Z\u001b[0m [prm-pathbased-requested ] \u001b[32mSUCCESS\u001b[0m Client requested PRM metadata at path-based location\n\u001b[90m2026-09-08T23:48:00.882Z\u001b[0m [outgoing-response ] \u001b[36mINFO \u001b[0m Sent 200 response for GET /.well-known/oauth-protected-resource/mcp\n\n\u001b[90m2026-09-08T23:48:00.889Z\u001b[0m [incoming-auth-request ] \u001b[36mINFO \u001b[0m Received GET request for /.well-known/oauth-authorization-server\n\u001b[90m2026-09-08T23:48:00.889Z\u001b[0m [authorization-server-metadata ] \u001b[32mSUCCESS\u001b[0m Client requested authorization server metadata\n\u001b[90m2026-09-08T23:48:00.889Z\u001b[0m [outgoing-auth-response ] \u001b[36mINFO \u001b[0m Sent 200 response for GET /.well-known/oauth-authorization-server\n\n\u001b[90m2026-09-08T23:48:00.894Z\u001b[0m [incoming-auth-request ] \u001b[36mINFO \u001b[0m Received POST request for /register\n\u001b[90m2026-09-08T23:48:00.894Z\u001b[0m [client-registration ] \u001b[32mSUCCESS\u001b[0m Client registered with authorization server\n\u001b[90m2026-09-08T23:48:00.894Z\u001b[0m [sep-837-application-type-present ] \u001b[32mSUCCESS\u001b[0m Client specified application_type \"native\" during Dynamic Client Registration\n\u001b[90m2026-09-08T23:48:00.894Z\u001b[0m [outgoing-auth-response ] \u001b[36mINFO \u001b[0m Sent 201 response for POST /register\n\n\u001b[90m2026-09-08T23:48:00.901Z\u001b[0m [incoming-auth-request ] \u001b[36mINFO \u001b[0m Received GET request for /authorize\n\u001b[90m2026-09-08T23:48:00.901Z\u001b[0m [authorization-request ] \u001b[32mSUCCESS\u001b[0m Client made authorization request\n\u001b[90m2026-09-08T23:48:00.901Z\u001b[0m [pkce-code-challenge-sent ] \u001b[32mSUCCESS\u001b[0m Client sent code_challenge in authorization request\n\u001b[90m2026-09-08T23:48:00.901Z\u001b[0m [pkce-s256-method-used ] \u001b[32mSUCCESS\u001b[0m Client used S256 code challenge method\n\u001b[90m2026-09-08T23:48:00.903Z\u001b[0m [outgoing-auth-response ] \u001b[36mINFO \u001b[0m Sent 302 response for GET /authorize\n\n\u001b[90m2026-09-08T23:48:00.906Z\u001b[0m [incoming-request ] \u001b[36mINFO \u001b[0m Received GET request for /.well-known/oauth-protected-resource/mcp\n\u001b[90m2026-09-08T23:48:00.906Z\u001b[0m [prm-pathbased-requested ] \u001b[32mSUCCESS\u001b[0m Client requested PRM metadata at path-based location\n\u001b[90m2026-09-08T23:48:00.906Z\u001b[0m [outgoing-response ] \u001b[36mINFO \u001b[0m Sent 200 response for GET /.well-known/oauth-protected-resource/mcp\n\n\u001b[90m2026-09-08T23:48:00.909Z\u001b[0m [incoming-auth-request ] \u001b[36mINFO \u001b[0m Received GET request for /.well-known/oauth-authorization-server\n...[truncated]" + "stderr": "Starting scenario: auth/token-endpoint-auth-basic\nExecuting client: node /home/runner/work/EventRelay/EventRelay/tests/testing/official_mcp_auth_client.mjs http://localhost:39749/mcp\n(node:10765) [DEP0190] DeprecationWarning: Passing args to a child process with shell option true can lead to security vulnerabilities, as the arguments are not escaped, only concatenated.\n(Use `node --trace-deprecation ...` to show where the warning was created)\n\nClient exited with code 1\n\nStderr:\nError: Streamable HTTP error: Error POSTing to endpoint: {\"jsonrpc\":\"2.0\",\"id\":0,\"error\":{\"code\":-32020,\"message\":\"Missing MCP-Protocol-Version header\"}}\n at StreamableHTTPClientTransport.send (file:///home/runner/work/EventRelay/EventRelay/node_modules/@modelcontextprotocol/sdk/dist/esm/client/streamableHttp.js:365:23)\n at process.processTicksAndRejections (node:internal/process/task_queues:104:5)\n\nResults saved to /tmp/mcp-conformance-client-yngiyg56/auth/token-endpoint-auth-basic-2026-09-08T23-51-52-182Z\nChecks:\n\u001b[90m2026-09-08T23:51:52.444Z\u001b[0m [incoming-request ] \u001b[36mINFO \u001b[0m Received POST request for /mcp (method: initialize)\n\u001b[90m2026-09-08T23:51:52.446Z\u001b[0m [outgoing-response ] \u001b[36mINFO \u001b[0m Sent 401 response for POST /mcp (method: initialize)\n\n\u001b[90m2026-09-08T23:51:52.455Z\u001b[0m [incoming-request ] \u001b[36mINFO \u001b[0m Received GET request for /.well-known/oauth-protected-resource/mcp\n\u001b[90m2026-09-08T23:51:52.455Z\u001b[0m [prm-pathbased-requested ] \u001b[32mSUCCESS\u001b[0m Client requested PRM metadata at path-based location\n\u001b[90m2026-09-08T23:51:52.456Z\u001b[0m [outgoing-response ] \u001b[36mINFO \u001b[0m Sent 200 response for GET /.well-known/oauth-protected-resource/mcp\n\n\u001b[90m2026-09-08T23:51:52.463Z\u001b[0m [incoming-auth-request ] \u001b[36mINFO \u001b[0m Received GET request for /.well-known/oauth-authorization-server\n\u001b[90m2026-09-08T23:51:52.464Z\u001b[0m [authorization-server-metadata ] \u001b[32mSUCCESS\u001b[0m Client requested authorization server metadata\n\u001b[90m2026-09-08T23:51:52.464Z\u001b[0m [outgoing-auth-response ] \u001b[36mINFO \u001b[0m Sent 200 response for GET /.well-known/oauth-authorization-server\n\n\u001b[90m2026-09-08T23:51:52.469Z\u001b[0m [incoming-auth-request ] \u001b[36mINFO \u001b[0m Received POST request for /register\n\u001b[90m2026-09-08T23:51:52.469Z\u001b[0m [client-registration ] \u001b[32mSUCCESS\u001b[0m Client registered with authorization server\n\u001b[90m2026-09-08T23:51:52.469Z\u001b[0m [sep-837-application-type-present ] \u001b[32mSUCCESS\u001b[0m Client specified application_type \"native\" during Dynamic Client Registration\n\u001b[90m2026-09-08T23:51:52.469Z\u001b[0m [outgoing-auth-response ] \u001b[36mINFO \u001b[0m Sent 201 response for POST /register\n\n\u001b[90m2026-09-08T23:51:52.476Z\u001b[0m [incoming-auth-request ] \u001b[36mINFO \u001b[0m Received GET request for /authorize\n\u001b[90m2026-09-08T23:51:52.477Z\u001b[0m [authorization-request ] \u001b[32mSUCCESS\u001b[0m Client made authorization request\n\u001b[90m2026-09-08T23:51:52.477Z\u001b[0m [pkce-code-challenge-sent ] \u001b[32mSUCCESS\u001b[0m Client sent code_challenge in authorization request\n\u001b[90m2026-09-08T23:51:52.477Z\u001b[0m [pkce-s256-method-used ] \u001b[32mSUCCESS\u001b[0m Client used S256 code challenge method\n\u001b[90m2026-09-08T23:51:52.479Z\u001b[0m [outgoing-auth-response ] \u001b[36mINFO \u001b[0m Sent 302 response for GET /authorize\n\n\u001b[90m2026-09-08T23:51:52.482Z\u001b[0m [incoming-request ] \u001b[36mINFO \u001b[0m Received GET request for /.well-known/oauth-protected-resource/mcp\n\u001b[90m2026-09-08T23:51:52.482Z\u001b[0m [prm-pathbased-requested ] \u001b[32mSUCCESS\u001b[0m Client requested PRM metadata at path-based location\n\u001b[90m2026-09-08T23:51:52.482Z\u001b[0m [outgoing-response ] \u001b[36mINFO \u001b[0m Sent 200 response for GET /.well-known/oauth-protected-resource/mcp\n\n\u001b[90m2026-09-08T23:51:52.484Z\u001b[0m [incoming-auth-request ] \u001b[36mINFO \u001b[0m Received GET request for /.well-known/oauth-authorization-serve\n...[truncated]" }, { "leg": "client", @@ -2083,7 +2083,7 @@ "name": "Incoming-request", "description": "Received POST request for /mcp (method: initialize)", "status": "INFO", - "timestamp": "2026-09-08T23:48:07.740Z", + "timestamp": "2026-09-08T23:51:59.522Z", "details": { "method": "POST", "path": "/mcp", @@ -2108,7 +2108,7 @@ "name": "Outgoing-response", "description": "Sent 401 response for POST /mcp (method: initialize)", "status": "INFO", - "timestamp": "2026-09-08T23:48:07.742Z", + "timestamp": "2026-09-08T23:51:59.524Z", "details": { "method": "POST", "path": "/mcp", @@ -2116,7 +2116,7 @@ "mcpMethod": "initialize", "headers": { "x-powered-by": "Express", - "www-authenticate": "Bearer error=\"invalid_token\", error_description=\"Missing Authorization header\", resource_metadata=\"http://localhost:37701/.well-known/oauth-protected-resource/mcp\"", + "www-authenticate": "Bearer error=\"invalid_token\", error_description=\"Missing Authorization header\", resource_metadata=\"http://localhost:44903/.well-known/oauth-protected-resource/mcp\"", "content-type": "application/json; charset=utf-8", "content-length": "76", "etag": "W/\"4c-ptrIdu+3yjAtarglCEu6XVLnz2c\"" @@ -2132,7 +2132,7 @@ "name": "Incoming-request", "description": "Received GET request for /.well-known/oauth-protected-resource/mcp", "status": "INFO", - "timestamp": "2026-09-08T23:48:07.750Z", + "timestamp": "2026-09-08T23:51:59.533Z", "details": { "method": "GET", "path": "/.well-known/oauth-protected-resource/mcp" @@ -2143,7 +2143,7 @@ "name": "PRMPathBasedRequested", "description": "Client requested PRM metadata at path-based location", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:07.750Z", + "timestamp": "2026-09-08T23:51:59.533Z", "specReferences": [ { "id": "RFC-9728", @@ -2164,7 +2164,7 @@ "name": "Outgoing-response", "description": "Sent 200 response for GET /.well-known/oauth-protected-resource/mcp", "status": "INFO", - "timestamp": "2026-09-08T23:48:07.750Z", + "timestamp": "2026-09-08T23:51:59.533Z", "details": { "method": "GET", "path": "/.well-known/oauth-protected-resource/mcp", @@ -2173,12 +2173,12 @@ "x-powered-by": "Express", "content-type": "application/json; charset=utf-8", "content-length": "92", - "etag": "W/\"5c-C7XxNF7ajKtlbHEWi6KE7b2JNd0\"" + "etag": "W/\"5c-Ff52gbYWSsZY4uraMJOfYWRXVIs\"" }, "body": { - "resource": "http://localhost:37701/mcp", + "resource": "http://localhost:44903/mcp", "authorization_servers": [ - "http://localhost:36515" + "http://localhost:37677" ] } } @@ -2188,7 +2188,7 @@ "name": "Incoming-auth-request", "description": "Received GET request for /.well-known/oauth-authorization-server", "status": "INFO", - "timestamp": "2026-09-08T23:48:07.756Z", + "timestamp": "2026-09-08T23:51:59.541Z", "details": { "method": "GET", "path": "/.well-known/oauth-authorization-server" @@ -2199,7 +2199,7 @@ "name": "AuthorizationServerMetadata", "description": "Client requested authorization server metadata", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:07.756Z", + "timestamp": "2026-09-08T23:51:59.542Z", "specReferences": [ { "id": "RFC-8414-metadata-request", @@ -2220,7 +2220,7 @@ "name": "Outgoing-auth-response", "description": "Sent 200 response for GET /.well-known/oauth-authorization-server", "status": "INFO", - "timestamp": "2026-09-08T23:48:07.756Z", + "timestamp": "2026-09-08T23:51:59.542Z", "details": { "method": "GET", "path": "/.well-known/oauth-authorization-server", @@ -2229,13 +2229,13 @@ "x-powered-by": "Express", "content-type": "application/json; charset=utf-8", "content-length": "461", - "etag": "W/\"1cd-SrMitvotKUUgAgF8X5XJ2Z12/BM\"" + "etag": "W/\"1cd-CmwH+Fbx7Lq8SCi8CWZThGfzBwY\"" }, "body": { - "issuer": "http://localhost:36515", - "authorization_endpoint": "http://localhost:36515/authorize", - "token_endpoint": "http://localhost:36515/token", - "registration_endpoint": "http://localhost:36515/register", + "issuer": "http://localhost:37677", + "authorization_endpoint": "http://localhost:37677/authorize", + "token_endpoint": "http://localhost:37677/token", + "registration_endpoint": "http://localhost:37677/register", "response_types_supported": [ "code" ], @@ -2258,7 +2258,7 @@ "name": "Incoming-auth-request", "description": "Received POST request for /register", "status": "INFO", - "timestamp": "2026-09-08T23:48:07.760Z", + "timestamp": "2026-09-08T23:51:59.547Z", "details": { "method": "POST", "path": "/register", @@ -2276,7 +2276,7 @@ "name": "ClientRegistration", "description": "Client registered with authorization server", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:07.761Z", + "timestamp": "2026-09-08T23:51:59.547Z", "specReferences": [ { "id": "MCP-Dynamic-client-registration", @@ -2294,7 +2294,7 @@ "name": "DCR application_type specified", "description": "Client specified application_type \"native\" during Dynamic Client Registration", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:07.761Z", + "timestamp": "2026-09-08T23:51:59.547Z", "specReferences": [ { "id": "MCP-Dynamic-client-registration", @@ -2310,7 +2310,7 @@ "name": "Outgoing-auth-response", "description": "Sent 201 response for POST /register", "status": "INFO", - "timestamp": "2026-09-08T23:48:07.761Z", + "timestamp": "2026-09-08T23:51:59.548Z", "details": { "method": "POST", "path": "/register", @@ -2319,11 +2319,11 @@ "x-powered-by": "Express", "content-type": "application/json; charset=utf-8", "content-length": "232", - "etag": "W/\"e8-rhs0/Ro6/zXeYVE266AFInGsWOM\"" + "etag": "W/\"e8-Zb1cyNQM0HUP9SkBsRtwRplv2Ac\"" }, "body": { - "client_id": "test-client-1788911287761", - "client_secret": "test-secret-1788911287761", + "client_id": "test-client-1788911519547", + "client_secret": "test-secret-1788911519547", "client_name": "eventrelay-conformance-client", "redirect_uris": [ "http://localhost:3000/callback" @@ -2337,17 +2337,17 @@ "name": "Incoming-auth-request", "description": "Received GET request for /authorize", "status": "INFO", - "timestamp": "2026-09-08T23:48:07.766Z", + "timestamp": "2026-09-08T23:51:59.554Z", "details": { "method": "GET", "path": "/authorize", "query": { "response_type": "code", - "client_id": "test-client-1788911287761", - "code_challenge": "lgsClOFknwdzLkEex3eiHAcVBRHgWJG0OETu2RhfQ5g", + "client_id": "test-client-1788911519547", + "code_challenge": "3-J7ytleHxTRF3piv7TcPOrr0tMh1mwd3tM5QJ_rSu8", "code_challenge_method": "S256", "redirect_uri": "http://localhost:3000/callback", - "resource": "http://localhost:37701/mcp" + "resource": "http://localhost:44903/mcp" } } }, @@ -2356,7 +2356,7 @@ "name": "AuthorizationRequest", "description": "Client made authorization request", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:07.767Z", + "timestamp": "2026-09-08T23:51:59.555Z", "specReferences": [ { "id": "OAUTH-2.1-authorization-endpoint", @@ -2366,11 +2366,11 @@ "details": { "query": { "response_type": "code", - "client_id": "test-client-1788911287761", - "code_challenge": "lgsClOFknwdzLkEex3eiHAcVBRHgWJG0OETu2RhfQ5g", + "client_id": "test-client-1788911519547", + "code_challenge": "3-J7ytleHxTRF3piv7TcPOrr0tMh1mwd3tM5QJ_rSu8", "code_challenge_method": "S256", "redirect_uri": "http://localhost:3000/callback", - "resource": "http://localhost:37701/mcp" + "resource": "http://localhost:44903/mcp" } } }, @@ -2379,7 +2379,7 @@ "name": "PKCE Code Challenge", "description": "Client sent code_challenge in authorization request", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:07.767Z", + "timestamp": "2026-09-08T23:51:59.555Z", "specReferences": [ { "id": "MCP-PKCE-requirement", @@ -2392,7 +2392,7 @@ "name": "PKCE S256 Method", "description": "Client used S256 code challenge method", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:07.767Z", + "timestamp": "2026-09-08T23:51:59.555Z", "specReferences": [ { "id": "MCP-PKCE-requirement", @@ -2408,19 +2408,19 @@ "name": "Outgoing-auth-response", "description": "Sent 302 response for GET /authorize", "status": "INFO", - "timestamp": "2026-09-08T23:48:07.769Z", + "timestamp": "2026-09-08T23:51:59.557Z", "details": { "method": "GET", "path": "/authorize", "statusCode": 302, "headers": { "x-powered-by": "Express", - "location": "http://localhost:3000/callback?code=test-auth-code&iss=http%3A%2F%2Flocalhost%3A36515", + "location": "http://localhost:3000/callback?code=test-auth-code&iss=http%3A%2F%2Flocalhost%3A37677", "vary": "Accept", "content-type": "text/plain; charset=utf-8", "content-length": "107" }, - "body": "Found. Redirecting to http://localhost:3000/callback?code=test-auth-code&iss=http%3A%2F%2Flocalhost%3A36515" + "body": "Found. Redirecting to http://localhost:3000/callback?code=test-auth-code&iss=http%3A%2F%2Flocalhost%3A37677" } }, { @@ -2428,7 +2428,7 @@ "name": "Incoming-request", "description": "Received GET request for /.well-known/oauth-protected-resource/mcp", "status": "INFO", - "timestamp": "2026-09-08T23:48:07.771Z", + "timestamp": "2026-09-08T23:51:59.560Z", "details": { "method": "GET", "path": "/.well-known/oauth-protected-resource/mcp" @@ -2439,7 +2439,7 @@ "name": "PRMPathBasedRequested", "description": "Client requested PRM metadata at path-based location", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:07.771Z", + "timestamp": "2026-09-08T23:51:59.560Z", "specReferences": [ { "id": "RFC-9728", @@ -2460,7 +2460,7 @@ "name": "Outgoing-response", "description": "Sent 200 response for GET /.well-known/oauth-protected-resource/mcp", "status": "INFO", - "timestamp": "2026-09-08T23:48:07.771Z", + "timestamp": "2026-09-08T23:51:59.560Z", "details": { "method": "GET", "path": "/.well-known/oauth-protected-resource/mcp", @@ -2469,12 +2469,12 @@ "x-powered-by": "Express", "content-type": "application/json; charset=utf-8", "content-length": "92", - "etag": "W/\"5c-C7XxNF7ajKtlbHEWi6KE7b2JNd0\"" + "etag": "W/\"5c-Ff52gbYWSsZY4uraMJOfYWRXVIs\"" }, "body": { - "resource": "http://localhost:37701/mcp", + "resource": "http://localhost:44903/mcp", "authorization_servers": [ - "http://localhost:36515" + "http://localhost:37677" ] } } @@ -2484,7 +2484,7 @@ "name": "Incoming-auth-request", "description": "Received GET request for /.well-known/oauth-authorization-server", "status": "INFO", - "timestamp": "2026-09-08T23:48:07.774Z", + "timestamp": "2026-09-08T23:51:59.563Z", "details": { "method": "GET", "path": "/.well-known/oauth-authorization-server" @@ -2495,7 +2495,7 @@ "name": "AuthorizationServerMetadata", "description": "Client requested authorization server metadata", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:07.774Z", + "timestamp": "2026-09-08T23:51:59.563Z", "specReferences": [ { "id": "RFC-8414-metadata-request", @@ -2516,7 +2516,7 @@ "name": "Outgoing-auth-response", "description": "Sent 200 response for GET /.well-known/oauth-authorization-server", "status": "INFO", - "timestamp": "2026-09-08T23:48:07.774Z", + "timestamp": "2026-09-08T23:51:59.563Z", "details": { "method": "GET", "path": "/.well-known/oauth-authorization-server", @@ -2525,13 +2525,13 @@ "x-powered-by": "Express", "content-type": "application/json; charset=utf-8", "content-length": "461", - "etag": "W/\"1cd-SrMitvotKUUgAgF8X5XJ2Z12/BM\"" + "etag": "W/\"1cd-CmwH+Fbx7Lq8SCi8CWZThGfzBwY\"" }, "body": { - "issuer": "http://localhost:36515", - "authorization_endpoint": "http://localhost:36515/authorize", - "token_endpoint": "http://localhost:36515/token", - "registration_endpoint": "http://localhost:36515/register", + "issuer": "http://localhost:37677", + "authorization_endpoint": "http://localhost:37677/authorize", + "token_endpoint": "http://localhost:37677/token", + "registration_endpoint": "http://localhost:37677/register", "response_types_supported": [ "code" ], @@ -2554,18 +2554,18 @@ "name": "Incoming-auth-request", "description": "Received POST request for /token", "status": "INFO", - "timestamp": "2026-09-08T23:48:07.779Z", + "timestamp": "2026-09-08T23:51:59.569Z", "details": { "method": "POST", "path": "/token", "body": { "grant_type": "authorization_code", "code": "test-auth-code", - "code_verifier": "lF12WMKnAdGDig.DJGL5Fmw6bX8xUWA3J5LA6M2nC8r", + "code_verifier": "H8.V6virw_3u9xqsVGyKnVBdVU~U4RAFK7yYqYlGT_T", "redirect_uri": "http://localhost:3000/callback", - "resource": "http://localhost:37701/mcp", - "client_id": "test-client-1788911287761", - "client_secret": "test-secret-1788911287761" + "resource": "http://localhost:44903/mcp", + "client_id": "test-client-1788911519547", + "client_secret": "test-secret-1788911519547" } } }, @@ -2574,7 +2574,7 @@ "name": "TokenRequest", "description": "Client requested access token", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:07.779Z", + "timestamp": "2026-09-08T23:51:59.570Z", "specReferences": [ { "id": "OAUTH-2.1-token-request", @@ -2591,7 +2591,7 @@ "name": "PKCE Code Verifier", "description": "Client sent code_verifier in token request", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:07.779Z", + "timestamp": "2026-09-08T23:51:59.570Z", "specReferences": [ { "id": "MCP-PKCE-requirement", @@ -2604,7 +2604,7 @@ "name": "PKCE Verifier Validation", "description": "code_verifier correctly matches code_challenge (S256)", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:07.779Z", + "timestamp": "2026-09-08T23:51:59.570Z", "specReferences": [ { "id": "MCP-PKCE-requirement", @@ -2613,8 +2613,8 @@ ], "details": { "matches": true, - "storedChallenge": "lgsClOFknwdzLkEex3eiHAcVBRHgWJG0OETu2RhfQ5g", - "computedChallenge": "lgsClOFknwdzLkEex3eiHAcVBRHgWJG0OETu2RhfQ5g" + "storedChallenge": "3-J7ytleHxTRF3piv7TcPOrr0tMh1mwd3tM5QJ_rSu8", + "computedChallenge": "3-J7ytleHxTRF3piv7TcPOrr0tMh1mwd3tM5QJ_rSu8" } }, { @@ -2622,7 +2622,7 @@ "name": "Token endpoint authentication method", "description": "Client correctly used client_secret_post for token endpoint", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:07.779Z", + "timestamp": "2026-09-08T23:51:59.570Z", "specReferences": [ { "id": "OAUTH-2.1-token-request", @@ -2641,7 +2641,7 @@ "name": "Outgoing-auth-response", "description": "Sent 200 response for POST /token", "status": "INFO", - "timestamp": "2026-09-08T23:48:07.780Z", + "timestamp": "2026-09-08T23:51:59.570Z", "details": { "method": "POST", "path": "/token", @@ -2650,10 +2650,10 @@ "x-powered-by": "Express", "content-type": "application/json; charset=utf-8", "content-length": "83", - "etag": "W/\"53-UjQCRLONv34AYg0bXNjYul+Lw9w\"" + "etag": "W/\"53-BoFdhEOG1ChFJbtYNWPGwu0nC1A\"" }, "body": { - "access_token": "test-token-1788911287780", + "access_token": "test-token-1788911519570", "token_type": "Bearer", "expires_in": 3600 } @@ -2664,7 +2664,7 @@ "name": "Incoming-request", "description": "Received POST request for /mcp (method: initialize)", "status": "INFO", - "timestamp": "2026-09-08T23:48:07.783Z", + "timestamp": "2026-09-08T23:51:59.574Z", "details": { "method": "POST", "path": "/mcp", @@ -2689,7 +2689,7 @@ "name": "ValidBearerToken", "description": "Client provided valid bearer token", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:07.783Z", + "timestamp": "2026-09-08T23:51:59.574Z", "specReferences": [ { "id": "MCP-Access-token-usage", @@ -2706,7 +2706,7 @@ "name": "Outgoing-response", "description": "Sent 400 response for POST /mcp (method: initialize)", "status": "INFO", - "timestamp": "2026-09-08T23:48:07.784Z", + "timestamp": "2026-09-08T23:51:59.575Z", "details": { "method": "POST", "path": "/mcp", @@ -2733,7 +2733,7 @@ "name": "Resource parameter in authorization request", "description": "Client included resource parameter in authorization request", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:07.805Z", + "timestamp": "2026-09-08T23:51:59.600Z", "specReferences": [ { "id": "RFC-8707-Resource-Indicators", @@ -2745,7 +2745,7 @@ } ], "details": { - "resource": "http://localhost:37701/mcp" + "resource": "http://localhost:44903/mcp" } }, { @@ -2753,7 +2753,7 @@ "name": "Resource parameter in token request", "description": "Client included resource parameter in token request", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:07.805Z", + "timestamp": "2026-09-08T23:51:59.600Z", "specReferences": [ { "id": "RFC-8707-Resource-Indicators", @@ -2765,7 +2765,7 @@ } ], "details": { - "resource": "http://localhost:37701/mcp" + "resource": "http://localhost:44903/mcp" } }, { @@ -2773,7 +2773,7 @@ "name": "Resource parameter is valid canonical URI", "description": "Resource parameter is a valid canonical URI (has scheme, no fragment)", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:07.805Z", + "timestamp": "2026-09-08T23:51:59.600Z", "specReferences": [ { "id": "RFC-8707-Resource-Indicators", @@ -2785,7 +2785,7 @@ } ], "details": { - "resource": "http://localhost:37701/mcp" + "resource": "http://localhost:44903/mcp" } }, { @@ -2793,7 +2793,7 @@ "name": "Resource parameter consistency", "description": "Resource parameter is consistent between authorization and token requests", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:07.805Z", + "timestamp": "2026-09-08T23:51:59.600Z", "specReferences": [ { "id": "RFC-8707-Resource-Indicators", @@ -2805,8 +2805,8 @@ } ], "details": { - "authorizationResource": "http://localhost:37701/mcp", - "tokenResource": "http://localhost:37701/mcp" + "authorizationResource": "http://localhost:44903/mcp", + "tokenResource": "http://localhost:44903/mcp" } }, { @@ -2814,7 +2814,7 @@ "name": "Resource parameter matches protected resource metadata", "description": "Client sent the resource identifier exactly as published in protected resource metadata", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:07.805Z", + "timestamp": "2026-09-08T23:51:59.600Z", "specReferences": [ { "id": "RFC-8707-Resource-Indicators", @@ -2834,14 +2834,14 @@ } ], "details": { - "prmResource": "http://localhost:37701/mcp", - "authorizationResource": "http://localhost:37701/mcp", - "tokenResource": "http://localhost:37701/mcp" + "prmResource": "http://localhost:44903/mcp", + "authorizationResource": "http://localhost:44903/mcp", + "tokenResource": "http://localhost:44903/mcp" } } ], "stdout": "", - "stderr": "Starting scenario: auth/token-endpoint-auth-post\nExecuting client: node /home/runner/work/EventRelay/EventRelay/tests/testing/official_mcp_auth_client.mjs http://localhost:37701/mcp\n(node:9240) [DEP0190] DeprecationWarning: Passing args to a child process with shell option true can lead to security vulnerabilities, as the arguments are not escaped, only concatenated.\n(Use `node --trace-deprecation ...` to show where the warning was created)\n\nClient exited with code 1\n\nStderr:\nError: Streamable HTTP error: Error POSTing to endpoint: {\"jsonrpc\":\"2.0\",\"id\":0,\"error\":{\"code\":-32020,\"message\":\"Missing MCP-Protocol-Version header\"}}\n at StreamableHTTPClientTransport.send (file:///home/runner/work/EventRelay/EventRelay/node_modules/@modelcontextprotocol/sdk/dist/esm/client/streamableHttp.js:365:23)\n at process.processTicksAndRejections (node:internal/process/task_queues:104:5)\n\nResults saved to /tmp/mcp-conformance-client-wkenofd6/auth/token-endpoint-auth-post-2026-09-08T23-48-07-491Z\nChecks:\n\u001b[90m2026-09-08T23:48:07.740Z\u001b[0m [incoming-request ] \u001b[36mINFO \u001b[0m Received POST request for /mcp (method: initialize)\n\u001b[90m2026-09-08T23:48:07.742Z\u001b[0m [outgoing-response ] \u001b[36mINFO \u001b[0m Sent 401 response for POST /mcp (method: initialize)\n\n\u001b[90m2026-09-08T23:48:07.750Z\u001b[0m [incoming-request ] \u001b[36mINFO \u001b[0m Received GET request for /.well-known/oauth-protected-resource/mcp\n\u001b[90m2026-09-08T23:48:07.750Z\u001b[0m [prm-pathbased-requested ] \u001b[32mSUCCESS\u001b[0m Client requested PRM metadata at path-based location\n\u001b[90m2026-09-08T23:48:07.750Z\u001b[0m [outgoing-response ] \u001b[36mINFO \u001b[0m Sent 200 response for GET /.well-known/oauth-protected-resource/mcp\n\n\u001b[90m2026-09-08T23:48:07.756Z\u001b[0m [incoming-auth-request ] \u001b[36mINFO \u001b[0m Received GET request for /.well-known/oauth-authorization-server\n\u001b[90m2026-09-08T23:48:07.756Z\u001b[0m [authorization-server-metadata ] \u001b[32mSUCCESS\u001b[0m Client requested authorization server metadata\n\u001b[90m2026-09-08T23:48:07.756Z\u001b[0m [outgoing-auth-response ] \u001b[36mINFO \u001b[0m Sent 200 response for GET /.well-known/oauth-authorization-server\n\n\u001b[90m2026-09-08T23:48:07.760Z\u001b[0m [incoming-auth-request ] \u001b[36mINFO \u001b[0m Received POST request for /register\n\u001b[90m2026-09-08T23:48:07.761Z\u001b[0m [client-registration ] \u001b[32mSUCCESS\u001b[0m Client registered with authorization server\n\u001b[90m2026-09-08T23:48:07.761Z\u001b[0m [sep-837-application-type-present ] \u001b[32mSUCCESS\u001b[0m Client specified application_type \"native\" during Dynamic Client Registration\n\u001b[90m2026-09-08T23:48:07.761Z\u001b[0m [outgoing-auth-response ] \u001b[36mINFO \u001b[0m Sent 201 response for POST /register\n\n\u001b[90m2026-09-08T23:48:07.766Z\u001b[0m [incoming-auth-request ] \u001b[36mINFO \u001b[0m Received GET request for /authorize\n\u001b[90m2026-09-08T23:48:07.767Z\u001b[0m [authorization-request ] \u001b[32mSUCCESS\u001b[0m Client made authorization request\n\u001b[90m2026-09-08T23:48:07.767Z\u001b[0m [pkce-code-challenge-sent ] \u001b[32mSUCCESS\u001b[0m Client sent code_challenge in authorization request\n\u001b[90m2026-09-08T23:48:07.767Z\u001b[0m [pkce-s256-method-used ] \u001b[32mSUCCESS\u001b[0m Client used S256 code challenge method\n\u001b[90m2026-09-08T23:48:07.769Z\u001b[0m [outgoing-auth-response ] \u001b[36mINFO \u001b[0m Sent 302 response for GET /authorize\n\n\u001b[90m2026-09-08T23:48:07.771Z\u001b[0m [incoming-request ] \u001b[36mINFO \u001b[0m Received GET request for /.well-known/oauth-protected-resource/mcp\n\u001b[90m2026-09-08T23:48:07.771Z\u001b[0m [prm-pathbased-requested ] \u001b[32mSUCCESS\u001b[0m Client requested PRM metadata at path-based location\n\u001b[90m2026-09-08T23:48:07.771Z\u001b[0m [outgoing-response ] \u001b[36mINFO \u001b[0m Sent 200 response for GET /.well-known/oauth-protected-resource/mcp\n\n\u001b[90m2026-09-08T23:48:07.774Z\u001b[0m [incoming-auth-request ] \u001b[36mINFO \u001b[0m Received GET request for /.well-known/oauth-authorization-server\n\u001b\n...[truncated]" + "stderr": "Starting scenario: auth/token-endpoint-auth-post\nExecuting client: node /home/runner/work/EventRelay/EventRelay/tests/testing/official_mcp_auth_client.mjs http://localhost:44903/mcp\n(node:10907) [DEP0190] DeprecationWarning: Passing args to a child process with shell option true can lead to security vulnerabilities, as the arguments are not escaped, only concatenated.\n(Use `node --trace-deprecation ...` to show where the warning was created)\n\nClient exited with code 1\n\nStderr:\nError: Streamable HTTP error: Error POSTing to endpoint: {\"jsonrpc\":\"2.0\",\"id\":0,\"error\":{\"code\":-32020,\"message\":\"Missing MCP-Protocol-Version header\"}}\n at StreamableHTTPClientTransport.send (file:///home/runner/work/EventRelay/EventRelay/node_modules/@modelcontextprotocol/sdk/dist/esm/client/streamableHttp.js:365:23)\n at process.processTicksAndRejections (node:internal/process/task_queues:104:5)\n\nResults saved to /tmp/mcp-conformance-client-nbgsz69b/auth/token-endpoint-auth-post-2026-09-08T23-51-59-263Z\nChecks:\n\u001b[90m2026-09-08T23:51:59.522Z\u001b[0m [incoming-request ] \u001b[36mINFO \u001b[0m Received POST request for /mcp (method: initialize)\n\u001b[90m2026-09-08T23:51:59.524Z\u001b[0m [outgoing-response ] \u001b[36mINFO \u001b[0m Sent 401 response for POST /mcp (method: initialize)\n\n\u001b[90m2026-09-08T23:51:59.533Z\u001b[0m [incoming-request ] \u001b[36mINFO \u001b[0m Received GET request for /.well-known/oauth-protected-resource/mcp\n\u001b[90m2026-09-08T23:51:59.533Z\u001b[0m [prm-pathbased-requested ] \u001b[32mSUCCESS\u001b[0m Client requested PRM metadata at path-based location\n\u001b[90m2026-09-08T23:51:59.533Z\u001b[0m [outgoing-response ] \u001b[36mINFO \u001b[0m Sent 200 response for GET /.well-known/oauth-protected-resource/mcp\n\n\u001b[90m2026-09-08T23:51:59.541Z\u001b[0m [incoming-auth-request ] \u001b[36mINFO \u001b[0m Received GET request for /.well-known/oauth-authorization-server\n\u001b[90m2026-09-08T23:51:59.542Z\u001b[0m [authorization-server-metadata ] \u001b[32mSUCCESS\u001b[0m Client requested authorization server metadata\n\u001b[90m2026-09-08T23:51:59.542Z\u001b[0m [outgoing-auth-response ] \u001b[36mINFO \u001b[0m Sent 200 response for GET /.well-known/oauth-authorization-server\n\n\u001b[90m2026-09-08T23:51:59.547Z\u001b[0m [incoming-auth-request ] \u001b[36mINFO \u001b[0m Received POST request for /register\n\u001b[90m2026-09-08T23:51:59.547Z\u001b[0m [client-registration ] \u001b[32mSUCCESS\u001b[0m Client registered with authorization server\n\u001b[90m2026-09-08T23:51:59.547Z\u001b[0m [sep-837-application-type-present ] \u001b[32mSUCCESS\u001b[0m Client specified application_type \"native\" during Dynamic Client Registration\n\u001b[90m2026-09-08T23:51:59.548Z\u001b[0m [outgoing-auth-response ] \u001b[36mINFO \u001b[0m Sent 201 response for POST /register\n\n\u001b[90m2026-09-08T23:51:59.554Z\u001b[0m [incoming-auth-request ] \u001b[36mINFO \u001b[0m Received GET request for /authorize\n\u001b[90m2026-09-08T23:51:59.555Z\u001b[0m [authorization-request ] \u001b[32mSUCCESS\u001b[0m Client made authorization request\n\u001b[90m2026-09-08T23:51:59.555Z\u001b[0m [pkce-code-challenge-sent ] \u001b[32mSUCCESS\u001b[0m Client sent code_challenge in authorization request\n\u001b[90m2026-09-08T23:51:59.555Z\u001b[0m [pkce-s256-method-used ] \u001b[32mSUCCESS\u001b[0m Client used S256 code challenge method\n\u001b[90m2026-09-08T23:51:59.557Z\u001b[0m [outgoing-auth-response ] \u001b[36mINFO \u001b[0m Sent 302 response for GET /authorize\n\n\u001b[90m2026-09-08T23:51:59.560Z\u001b[0m [incoming-request ] \u001b[36mINFO \u001b[0m Received GET request for /.well-known/oauth-protected-resource/mcp\n\u001b[90m2026-09-08T23:51:59.560Z\u001b[0m [prm-pathbased-requested ] \u001b[32mSUCCESS\u001b[0m Client requested PRM metadata at path-based location\n\u001b[90m2026-09-08T23:51:59.560Z\u001b[0m [outgoing-response ] \u001b[36mINFO \u001b[0m Sent 200 response for GET /.well-known/oauth-protected-resource/mcp\n\n\u001b[90m2026-09-08T23:51:59.563Z\u001b[0m [incoming-auth-request ] \u001b[36mINFO \u001b[0m Received GET request for /.well-known/oauth-authorization-server\n\n...[truncated]" }, { "leg": "client", @@ -2865,7 +2865,7 @@ "name": "Incoming-request", "description": "Received POST request for /mcp (method: initialize)", "status": "INFO", - "timestamp": "2026-09-08T23:48:14.512Z", + "timestamp": "2026-09-08T23:52:06.621Z", "details": { "method": "POST", "path": "/mcp", @@ -2890,7 +2890,7 @@ "name": "Outgoing-response", "description": "Sent 401 response for POST /mcp (method: initialize)", "status": "INFO", - "timestamp": "2026-09-08T23:48:14.514Z", + "timestamp": "2026-09-08T23:52:06.624Z", "details": { "method": "POST", "path": "/mcp", @@ -2898,7 +2898,7 @@ "mcpMethod": "initialize", "headers": { "x-powered-by": "Express", - "www-authenticate": "Bearer error=\"invalid_token\", error_description=\"Missing Authorization header\", resource_metadata=\"http://localhost:40991/.well-known/oauth-protected-resource/mcp\"", + "www-authenticate": "Bearer error=\"invalid_token\", error_description=\"Missing Authorization header\", resource_metadata=\"http://localhost:40305/.well-known/oauth-protected-resource/mcp\"", "content-type": "application/json; charset=utf-8", "content-length": "76", "etag": "W/\"4c-ptrIdu+3yjAtarglCEu6XVLnz2c\"" @@ -2914,7 +2914,7 @@ "name": "Incoming-request", "description": "Received GET request for /.well-known/oauth-protected-resource/mcp", "status": "INFO", - "timestamp": "2026-09-08T23:48:14.522Z", + "timestamp": "2026-09-08T23:52:06.632Z", "details": { "method": "GET", "path": "/.well-known/oauth-protected-resource/mcp" @@ -2925,7 +2925,7 @@ "name": "PRMPathBasedRequested", "description": "Client requested PRM metadata at path-based location", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:14.522Z", + "timestamp": "2026-09-08T23:52:06.632Z", "specReferences": [ { "id": "RFC-9728", @@ -2946,7 +2946,7 @@ "name": "Outgoing-response", "description": "Sent 200 response for GET /.well-known/oauth-protected-resource/mcp", "status": "INFO", - "timestamp": "2026-09-08T23:48:14.523Z", + "timestamp": "2026-09-08T23:52:06.633Z", "details": { "method": "GET", "path": "/.well-known/oauth-protected-resource/mcp", @@ -2955,12 +2955,12 @@ "x-powered-by": "Express", "content-type": "application/json; charset=utf-8", "content-length": "92", - "etag": "W/\"5c-0feIEBn49XNTrDPIJoctcmJlPNI\"" + "etag": "W/\"5c-T0K4Flktw8U7A9v/kk6RUFxKhJc\"" }, "body": { - "resource": "http://localhost:40991/mcp", + "resource": "http://localhost:40305/mcp", "authorization_servers": [ - "http://localhost:37991" + "http://localhost:39163" ] } } @@ -2970,7 +2970,7 @@ "name": "Incoming-auth-request", "description": "Received GET request for /.well-known/oauth-authorization-server", "status": "INFO", - "timestamp": "2026-09-08T23:48:14.528Z", + "timestamp": "2026-09-08T23:52:06.640Z", "details": { "method": "GET", "path": "/.well-known/oauth-authorization-server" @@ -2981,7 +2981,7 @@ "name": "AuthorizationServerMetadata", "description": "Client requested authorization server metadata", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:14.528Z", + "timestamp": "2026-09-08T23:52:06.640Z", "specReferences": [ { "id": "RFC-8414-metadata-request", @@ -3002,7 +3002,7 @@ "name": "Outgoing-auth-response", "description": "Sent 200 response for GET /.well-known/oauth-authorization-server", "status": "INFO", - "timestamp": "2026-09-08T23:48:14.529Z", + "timestamp": "2026-09-08T23:52:06.641Z", "details": { "method": "GET", "path": "/.well-known/oauth-authorization-server", @@ -3011,13 +3011,13 @@ "x-powered-by": "Express", "content-type": "application/json; charset=utf-8", "content-length": "447", - "etag": "W/\"1bf-kgVsQRPY5+ql5p1GaRNOBLNGsFo\"" + "etag": "W/\"1bf-9foJYAtC4XU7383PRutI9Ti3NLc\"" }, "body": { - "issuer": "http://localhost:37991", - "authorization_endpoint": "http://localhost:37991/authorize", - "token_endpoint": "http://localhost:37991/token", - "registration_endpoint": "http://localhost:37991/register", + "issuer": "http://localhost:39163", + "authorization_endpoint": "http://localhost:39163/authorize", + "token_endpoint": "http://localhost:39163/token", + "registration_endpoint": "http://localhost:39163/register", "response_types_supported": [ "code" ], @@ -3040,7 +3040,7 @@ "name": "Incoming-auth-request", "description": "Received POST request for /register", "status": "INFO", - "timestamp": "2026-09-08T23:48:14.533Z", + "timestamp": "2026-09-08T23:52:06.646Z", "details": { "method": "POST", "path": "/register", @@ -3058,7 +3058,7 @@ "name": "ClientRegistration", "description": "Client registered with authorization server", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:14.533Z", + "timestamp": "2026-09-08T23:52:06.646Z", "specReferences": [ { "id": "MCP-Dynamic-client-registration", @@ -3076,7 +3076,7 @@ "name": "DCR application_type specified", "description": "Client specified application_type \"native\" during Dynamic Client Registration", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:14.533Z", + "timestamp": "2026-09-08T23:52:06.646Z", "specReferences": [ { "id": "MCP-Dynamic-client-registration", @@ -3092,7 +3092,7 @@ "name": "Outgoing-auth-response", "description": "Sent 201 response for POST /register", "status": "INFO", - "timestamp": "2026-09-08T23:48:14.533Z", + "timestamp": "2026-09-08T23:52:06.646Z", "details": { "method": "POST", "path": "/register", @@ -3101,10 +3101,10 @@ "x-powered-by": "Express", "content-type": "application/json; charset=utf-8", "content-length": "174", - "etag": "W/\"ae-2qOTB47mF4kXc1MU0D+Xv+L9nq8\"" + "etag": "W/\"ae-DMm4Mje2XxfKtwXyHETj/BCpQxY\"" }, "body": { - "client_id": "test-client-1788911294533", + "client_id": "test-client-1788911526646", "client_name": "eventrelay-conformance-client", "redirect_uris": [ "http://localhost:3000/callback" @@ -3118,17 +3118,17 @@ "name": "Incoming-auth-request", "description": "Received GET request for /authorize", "status": "INFO", - "timestamp": "2026-09-08T23:48:14.539Z", + "timestamp": "2026-09-08T23:52:06.653Z", "details": { "method": "GET", "path": "/authorize", "query": { "response_type": "code", - "client_id": "test-client-1788911294533", - "code_challenge": "i0Yc_3COLxC3KXFHIy5FatJ-KCXM1Nk1sFYuANxkelU", + "client_id": "test-client-1788911526646", + "code_challenge": "eo92Ht_7xYdv44n-jA57Bh-FVgVTVsvhTsUDgfqKH_o", "code_challenge_method": "S256", "redirect_uri": "http://localhost:3000/callback", - "resource": "http://localhost:40991/mcp" + "resource": "http://localhost:40305/mcp" } } }, @@ -3137,7 +3137,7 @@ "name": "AuthorizationRequest", "description": "Client made authorization request", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:14.539Z", + "timestamp": "2026-09-08T23:52:06.654Z", "specReferences": [ { "id": "OAUTH-2.1-authorization-endpoint", @@ -3147,11 +3147,11 @@ "details": { "query": { "response_type": "code", - "client_id": "test-client-1788911294533", - "code_challenge": "i0Yc_3COLxC3KXFHIy5FatJ-KCXM1Nk1sFYuANxkelU", + "client_id": "test-client-1788911526646", + "code_challenge": "eo92Ht_7xYdv44n-jA57Bh-FVgVTVsvhTsUDgfqKH_o", "code_challenge_method": "S256", "redirect_uri": "http://localhost:3000/callback", - "resource": "http://localhost:40991/mcp" + "resource": "http://localhost:40305/mcp" } } }, @@ -3160,7 +3160,7 @@ "name": "PKCE Code Challenge", "description": "Client sent code_challenge in authorization request", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:14.539Z", + "timestamp": "2026-09-08T23:52:06.654Z", "specReferences": [ { "id": "MCP-PKCE-requirement", @@ -3173,7 +3173,7 @@ "name": "PKCE S256 Method", "description": "Client used S256 code challenge method", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:14.539Z", + "timestamp": "2026-09-08T23:52:06.654Z", "specReferences": [ { "id": "MCP-PKCE-requirement", @@ -3189,19 +3189,19 @@ "name": "Outgoing-auth-response", "description": "Sent 302 response for GET /authorize", "status": "INFO", - "timestamp": "2026-09-08T23:48:14.541Z", + "timestamp": "2026-09-08T23:52:06.656Z", "details": { "method": "GET", "path": "/authorize", "statusCode": 302, "headers": { "x-powered-by": "Express", - "location": "http://localhost:3000/callback?code=test-auth-code&iss=http%3A%2F%2Flocalhost%3A37991", + "location": "http://localhost:3000/callback?code=test-auth-code&iss=http%3A%2F%2Flocalhost%3A39163", "vary": "Accept", "content-type": "text/plain; charset=utf-8", "content-length": "107" }, - "body": "Found. Redirecting to http://localhost:3000/callback?code=test-auth-code&iss=http%3A%2F%2Flocalhost%3A37991" + "body": "Found. Redirecting to http://localhost:3000/callback?code=test-auth-code&iss=http%3A%2F%2Flocalhost%3A39163" } }, { @@ -3209,7 +3209,7 @@ "name": "Incoming-request", "description": "Received GET request for /.well-known/oauth-protected-resource/mcp", "status": "INFO", - "timestamp": "2026-09-08T23:48:14.543Z", + "timestamp": "2026-09-08T23:52:06.659Z", "details": { "method": "GET", "path": "/.well-known/oauth-protected-resource/mcp" @@ -3220,7 +3220,7 @@ "name": "PRMPathBasedRequested", "description": "Client requested PRM metadata at path-based location", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:14.543Z", + "timestamp": "2026-09-08T23:52:06.659Z", "specReferences": [ { "id": "RFC-9728", @@ -3241,7 +3241,7 @@ "name": "Outgoing-response", "description": "Sent 200 response for GET /.well-known/oauth-protected-resource/mcp", "status": "INFO", - "timestamp": "2026-09-08T23:48:14.543Z", + "timestamp": "2026-09-08T23:52:06.659Z", "details": { "method": "GET", "path": "/.well-known/oauth-protected-resource/mcp", @@ -3250,12 +3250,12 @@ "x-powered-by": "Express", "content-type": "application/json; charset=utf-8", "content-length": "92", - "etag": "W/\"5c-0feIEBn49XNTrDPIJoctcmJlPNI\"" + "etag": "W/\"5c-T0K4Flktw8U7A9v/kk6RUFxKhJc\"" }, "body": { - "resource": "http://localhost:40991/mcp", + "resource": "http://localhost:40305/mcp", "authorization_servers": [ - "http://localhost:37991" + "http://localhost:39163" ] } } @@ -3265,7 +3265,7 @@ "name": "Incoming-auth-request", "description": "Received GET request for /.well-known/oauth-authorization-server", "status": "INFO", - "timestamp": "2026-09-08T23:48:14.546Z", + "timestamp": "2026-09-08T23:52:06.662Z", "details": { "method": "GET", "path": "/.well-known/oauth-authorization-server" @@ -3276,7 +3276,7 @@ "name": "AuthorizationServerMetadata", "description": "Client requested authorization server metadata", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:14.546Z", + "timestamp": "2026-09-08T23:52:06.662Z", "specReferences": [ { "id": "RFC-8414-metadata-request", @@ -3297,7 +3297,7 @@ "name": "Outgoing-auth-response", "description": "Sent 200 response for GET /.well-known/oauth-authorization-server", "status": "INFO", - "timestamp": "2026-09-08T23:48:14.546Z", + "timestamp": "2026-09-08T23:52:06.662Z", "details": { "method": "GET", "path": "/.well-known/oauth-authorization-server", @@ -3306,13 +3306,13 @@ "x-powered-by": "Express", "content-type": "application/json; charset=utf-8", "content-length": "447", - "etag": "W/\"1bf-kgVsQRPY5+ql5p1GaRNOBLNGsFo\"" + "etag": "W/\"1bf-9foJYAtC4XU7383PRutI9Ti3NLc\"" }, "body": { - "issuer": "http://localhost:37991", - "authorization_endpoint": "http://localhost:37991/authorize", - "token_endpoint": "http://localhost:37991/token", - "registration_endpoint": "http://localhost:37991/register", + "issuer": "http://localhost:39163", + "authorization_endpoint": "http://localhost:39163/authorize", + "token_endpoint": "http://localhost:39163/token", + "registration_endpoint": "http://localhost:39163/register", "response_types_supported": [ "code" ], @@ -3335,17 +3335,17 @@ "name": "Incoming-auth-request", "description": "Received POST request for /token", "status": "INFO", - "timestamp": "2026-09-08T23:48:14.551Z", + "timestamp": "2026-09-08T23:52:06.667Z", "details": { "method": "POST", "path": "/token", "body": { "grant_type": "authorization_code", "code": "test-auth-code", - "code_verifier": "QNjGhOPekA-dm6Cs667wZzhMf7nBT9aRrvQZRwWFxFc", + "code_verifier": "3.EgAuYyh9W2s4P11Bi8gYHRUfYY5r4uFnJ~UK-jsSZ", "redirect_uri": "http://localhost:3000/callback", - "resource": "http://localhost:40991/mcp", - "client_id": "test-client-1788911294533" + "resource": "http://localhost:40305/mcp", + "client_id": "test-client-1788911526646" } } }, @@ -3354,7 +3354,7 @@ "name": "TokenRequest", "description": "Client requested access token", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:14.551Z", + "timestamp": "2026-09-08T23:52:06.667Z", "specReferences": [ { "id": "OAUTH-2.1-token-request", @@ -3371,7 +3371,7 @@ "name": "PKCE Code Verifier", "description": "Client sent code_verifier in token request", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:14.551Z", + "timestamp": "2026-09-08T23:52:06.667Z", "specReferences": [ { "id": "MCP-PKCE-requirement", @@ -3384,7 +3384,7 @@ "name": "PKCE Verifier Validation", "description": "code_verifier correctly matches code_challenge (S256)", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:14.551Z", + "timestamp": "2026-09-08T23:52:06.667Z", "specReferences": [ { "id": "MCP-PKCE-requirement", @@ -3393,8 +3393,8 @@ ], "details": { "matches": true, - "storedChallenge": "i0Yc_3COLxC3KXFHIy5FatJ-KCXM1Nk1sFYuANxkelU", - "computedChallenge": "i0Yc_3COLxC3KXFHIy5FatJ-KCXM1Nk1sFYuANxkelU" + "storedChallenge": "eo92Ht_7xYdv44n-jA57Bh-FVgVTVsvhTsUDgfqKH_o", + "computedChallenge": "eo92Ht_7xYdv44n-jA57Bh-FVgVTVsvhTsUDgfqKH_o" } }, { @@ -3402,7 +3402,7 @@ "name": "Token endpoint authentication method", "description": "Client correctly used no authentication (public client) for token endpoint", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:14.551Z", + "timestamp": "2026-09-08T23:52:06.667Z", "specReferences": [ { "id": "OAUTH-2.1-token-request", @@ -3421,7 +3421,7 @@ "name": "Outgoing-auth-response", "description": "Sent 200 response for POST /token", "status": "INFO", - "timestamp": "2026-09-08T23:48:14.552Z", + "timestamp": "2026-09-08T23:52:06.668Z", "details": { "method": "POST", "path": "/token", @@ -3430,10 +3430,10 @@ "x-powered-by": "Express", "content-type": "application/json; charset=utf-8", "content-length": "83", - "etag": "W/\"53-1uuimB8ChZPyacK3p2eMlTR8Eho\"" + "etag": "W/\"53-gCpj+9t7XPYdjU7n14YPW/7vfnI\"" }, "body": { - "access_token": "test-token-1788911294552", + "access_token": "test-token-1788911526667", "token_type": "Bearer", "expires_in": 3600 } @@ -3444,7 +3444,7 @@ "name": "Incoming-request", "description": "Received POST request for /mcp (method: initialize)", "status": "INFO", - "timestamp": "2026-09-08T23:48:14.555Z", + "timestamp": "2026-09-08T23:52:06.672Z", "details": { "method": "POST", "path": "/mcp", @@ -3469,7 +3469,7 @@ "name": "ValidBearerToken", "description": "Client provided valid bearer token", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:14.555Z", + "timestamp": "2026-09-08T23:52:06.672Z", "specReferences": [ { "id": "MCP-Access-token-usage", @@ -3486,7 +3486,7 @@ "name": "Outgoing-response", "description": "Sent 400 response for POST /mcp (method: initialize)", "status": "INFO", - "timestamp": "2026-09-08T23:48:14.556Z", + "timestamp": "2026-09-08T23:52:06.672Z", "details": { "method": "POST", "path": "/mcp", @@ -3513,7 +3513,7 @@ "name": "Resource parameter in authorization request", "description": "Client included resource parameter in authorization request", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:14.576Z", + "timestamp": "2026-09-08T23:52:06.695Z", "specReferences": [ { "id": "RFC-8707-Resource-Indicators", @@ -3525,7 +3525,7 @@ } ], "details": { - "resource": "http://localhost:40991/mcp" + "resource": "http://localhost:40305/mcp" } }, { @@ -3533,7 +3533,7 @@ "name": "Resource parameter in token request", "description": "Client included resource parameter in token request", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:14.576Z", + "timestamp": "2026-09-08T23:52:06.695Z", "specReferences": [ { "id": "RFC-8707-Resource-Indicators", @@ -3545,7 +3545,7 @@ } ], "details": { - "resource": "http://localhost:40991/mcp" + "resource": "http://localhost:40305/mcp" } }, { @@ -3553,7 +3553,7 @@ "name": "Resource parameter is valid canonical URI", "description": "Resource parameter is a valid canonical URI (has scheme, no fragment)", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:14.576Z", + "timestamp": "2026-09-08T23:52:06.695Z", "specReferences": [ { "id": "RFC-8707-Resource-Indicators", @@ -3565,7 +3565,7 @@ } ], "details": { - "resource": "http://localhost:40991/mcp" + "resource": "http://localhost:40305/mcp" } }, { @@ -3573,7 +3573,7 @@ "name": "Resource parameter consistency", "description": "Resource parameter is consistent between authorization and token requests", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:14.576Z", + "timestamp": "2026-09-08T23:52:06.695Z", "specReferences": [ { "id": "RFC-8707-Resource-Indicators", @@ -3585,8 +3585,8 @@ } ], "details": { - "authorizationResource": "http://localhost:40991/mcp", - "tokenResource": "http://localhost:40991/mcp" + "authorizationResource": "http://localhost:40305/mcp", + "tokenResource": "http://localhost:40305/mcp" } }, { @@ -3594,7 +3594,7 @@ "name": "Resource parameter matches protected resource metadata", "description": "Client sent the resource identifier exactly as published in protected resource metadata", "status": "SUCCESS", - "timestamp": "2026-09-08T23:48:14.576Z", + "timestamp": "2026-09-08T23:52:06.695Z", "specReferences": [ { "id": "RFC-8707-Resource-Indicators", @@ -3614,14 +3614,14 @@ } ], "details": { - "prmResource": "http://localhost:40991/mcp", - "authorizationResource": "http://localhost:40991/mcp", - "tokenResource": "http://localhost:40991/mcp" + "prmResource": "http://localhost:40305/mcp", + "authorizationResource": "http://localhost:40305/mcp", + "tokenResource": "http://localhost:40305/mcp" } } ], "stdout": "", - "stderr": "Starting scenario: auth/token-endpoint-auth-none\nExecuting client: node /home/runner/work/EventRelay/EventRelay/tests/testing/official_mcp_auth_client.mjs http://localhost:40991/mcp\n(node:9383) [DEP0190] DeprecationWarning: Passing args to a child process with shell option true can lead to security vulnerabilities, as the arguments are not escaped, only concatenated.\n(Use `node --trace-deprecation ...` to show where the warning was created)\n\nClient exited with code 1\n\nStderr:\nError: Streamable HTTP error: Error POSTing to endpoint: {\"jsonrpc\":\"2.0\",\"id\":0,\"error\":{\"code\":-32020,\"message\":\"Missing MCP-Protocol-Version header\"}}\n at StreamableHTTPClientTransport.send (file:///home/runner/work/EventRelay/EventRelay/node_modules/@modelcontextprotocol/sdk/dist/esm/client/streamableHttp.js:365:23)\n at process.processTicksAndRejections (node:internal/process/task_queues:104:5)\n\nResults saved to /tmp/mcp-conformance-client-kb91y_h1/auth/token-endpoint-auth-none-2026-09-08T23-48-14-267Z\nChecks:\n\u001b[90m2026-09-08T23:48:14.512Z\u001b[0m [incoming-request ] \u001b[36mINFO \u001b[0m Received POST request for /mcp (method: initialize)\n\u001b[90m2026-09-08T23:48:14.514Z\u001b[0m [outgoing-response ] \u001b[36mINFO \u001b[0m Sent 401 response for POST /mcp (method: initialize)\n\n\u001b[90m2026-09-08T23:48:14.522Z\u001b[0m [incoming-request ] \u001b[36mINFO \u001b[0m Received GET request for /.well-known/oauth-protected-resource/mcp\n\u001b[90m2026-09-08T23:48:14.522Z\u001b[0m [prm-pathbased-requested ] \u001b[32mSUCCESS\u001b[0m Client requested PRM metadata at path-based location\n\u001b[90m2026-09-08T23:48:14.523Z\u001b[0m [outgoing-response ] \u001b[36mINFO \u001b[0m Sent 200 response for GET /.well-known/oauth-protected-resource/mcp\n\n\u001b[90m2026-09-08T23:48:14.528Z\u001b[0m [incoming-auth-request ] \u001b[36mINFO \u001b[0m Received GET request for /.well-known/oauth-authorization-server\n\u001b[90m2026-09-08T23:48:14.528Z\u001b[0m [authorization-server-metadata ] \u001b[32mSUCCESS\u001b[0m Client requested authorization server metadata\n\u001b[90m2026-09-08T23:48:14.529Z\u001b[0m [outgoing-auth-response ] \u001b[36mINFO \u001b[0m Sent 200 response for GET /.well-known/oauth-authorization-server\n\n\u001b[90m2026-09-08T23:48:14.533Z\u001b[0m [incoming-auth-request ] \u001b[36mINFO \u001b[0m Received POST request for /register\n\u001b[90m2026-09-08T23:48:14.533Z\u001b[0m [client-registration ] \u001b[32mSUCCESS\u001b[0m Client registered with authorization server\n\u001b[90m2026-09-08T23:48:14.533Z\u001b[0m [sep-837-application-type-present ] \u001b[32mSUCCESS\u001b[0m Client specified application_type \"native\" during Dynamic Client Registration\n\u001b[90m2026-09-08T23:48:14.533Z\u001b[0m [outgoing-auth-response ] \u001b[36mINFO \u001b[0m Sent 201 response for POST /register\n\n\u001b[90m2026-09-08T23:48:14.539Z\u001b[0m [incoming-auth-request ] \u001b[36mINFO \u001b[0m Received GET request for /authorize\n\u001b[90m2026-09-08T23:48:14.539Z\u001b[0m [authorization-request ] \u001b[32mSUCCESS\u001b[0m Client made authorization request\n\u001b[90m2026-09-08T23:48:14.539Z\u001b[0m [pkce-code-challenge-sent ] \u001b[32mSUCCESS\u001b[0m Client sent code_challenge in authorization request\n\u001b[90m2026-09-08T23:48:14.539Z\u001b[0m [pkce-s256-method-used ] \u001b[32mSUCCESS\u001b[0m Client used S256 code challenge method\n\u001b[90m2026-09-08T23:48:14.541Z\u001b[0m [outgoing-auth-response ] \u001b[36mINFO \u001b[0m Sent 302 response for GET /authorize\n\n\u001b[90m2026-09-08T23:48:14.543Z\u001b[0m [incoming-request ] \u001b[36mINFO \u001b[0m Received GET request for /.well-known/oauth-protected-resource/mcp\n\u001b[90m2026-09-08T23:48:14.543Z\u001b[0m [prm-pathbased-requested ] \u001b[32mSUCCESS\u001b[0m Client requested PRM metadata at path-based location\n\u001b[90m2026-09-08T23:48:14.543Z\u001b[0m [outgoing-response ] \u001b[36mINFO \u001b[0m Sent 200 response for GET /.well-known/oauth-protected-resource/mcp\n\n\u001b[90m2026-09-08T23:48:14.546Z\u001b[0m [incoming-auth-request ] \u001b[36mINFO \u001b[0m Received GET request for /.well-known/oauth-authorization-server\n\u001b\n...[truncated]" + "stderr": "Starting scenario: auth/token-endpoint-auth-none\nExecuting client: node /home/runner/work/EventRelay/EventRelay/tests/testing/official_mcp_auth_client.mjs http://localhost:40305/mcp\n(node:11049) [DEP0190] DeprecationWarning: Passing args to a child process with shell option true can lead to security vulnerabilities, as the arguments are not escaped, only concatenated.\n(Use `node --trace-deprecation ...` to show where the warning was created)\n\nClient exited with code 1\n\nStderr:\nError: Streamable HTTP error: Error POSTing to endpoint: {\"jsonrpc\":\"2.0\",\"id\":0,\"error\":{\"code\":-32020,\"message\":\"Missing MCP-Protocol-Version header\"}}\n at StreamableHTTPClientTransport.send (file:///home/runner/work/EventRelay/EventRelay/node_modules/@modelcontextprotocol/sdk/dist/esm/client/streamableHttp.js:365:23)\n at process.processTicksAndRejections (node:internal/process/task_queues:104:5)\n\nResults saved to /tmp/mcp-conformance-client-iigu4mya/auth/token-endpoint-auth-none-2026-09-08T23-52-06-368Z\nChecks:\n\u001b[90m2026-09-08T23:52:06.621Z\u001b[0m [incoming-request ] \u001b[36mINFO \u001b[0m Received POST request for /mcp (method: initialize)\n\u001b[90m2026-09-08T23:52:06.624Z\u001b[0m [outgoing-response ] \u001b[36mINFO \u001b[0m Sent 401 response for POST /mcp (method: initialize)\n\n\u001b[90m2026-09-08T23:52:06.632Z\u001b[0m [incoming-request ] \u001b[36mINFO \u001b[0m Received GET request for /.well-known/oauth-protected-resource/mcp\n\u001b[90m2026-09-08T23:52:06.632Z\u001b[0m [prm-pathbased-requested ] \u001b[32mSUCCESS\u001b[0m Client requested PRM metadata at path-based location\n\u001b[90m2026-09-08T23:52:06.633Z\u001b[0m [outgoing-response ] \u001b[36mINFO \u001b[0m Sent 200 response for GET /.well-known/oauth-protected-resource/mcp\n\n\u001b[90m2026-09-08T23:52:06.640Z\u001b[0m [incoming-auth-request ] \u001b[36mINFO \u001b[0m Received GET request for /.well-known/oauth-authorization-server\n\u001b[90m2026-09-08T23:52:06.640Z\u001b[0m [authorization-server-metadata ] \u001b[32mSUCCESS\u001b[0m Client requested authorization server metadata\n\u001b[90m2026-09-08T23:52:06.641Z\u001b[0m [outgoing-auth-response ] \u001b[36mINFO \u001b[0m Sent 200 response for GET /.well-known/oauth-authorization-server\n\n\u001b[90m2026-09-08T23:52:06.646Z\u001b[0m [incoming-auth-request ] \u001b[36mINFO \u001b[0m Received POST request for /register\n\u001b[90m2026-09-08T23:52:06.646Z\u001b[0m [client-registration ] \u001b[32mSUCCESS\u001b[0m Client registered with authorization server\n\u001b[90m2026-09-08T23:52:06.646Z\u001b[0m [sep-837-application-type-present ] \u001b[32mSUCCESS\u001b[0m Client specified application_type \"native\" during Dynamic Client Registration\n\u001b[90m2026-09-08T23:52:06.646Z\u001b[0m [outgoing-auth-response ] \u001b[36mINFO \u001b[0m Sent 201 response for POST /register\n\n\u001b[90m2026-09-08T23:52:06.653Z\u001b[0m [incoming-auth-request ] \u001b[36mINFO \u001b[0m Received GET request for /authorize\n\u001b[90m2026-09-08T23:52:06.654Z\u001b[0m [authorization-request ] \u001b[32mSUCCESS\u001b[0m Client made authorization request\n\u001b[90m2026-09-08T23:52:06.654Z\u001b[0m [pkce-code-challenge-sent ] \u001b[32mSUCCESS\u001b[0m Client sent code_challenge in authorization request\n\u001b[90m2026-09-08T23:52:06.654Z\u001b[0m [pkce-s256-method-used ] \u001b[32mSUCCESS\u001b[0m Client used S256 code challenge method\n\u001b[90m2026-09-08T23:52:06.656Z\u001b[0m [outgoing-auth-response ] \u001b[36mINFO \u001b[0m Sent 302 response for GET /authorize\n\n\u001b[90m2026-09-08T23:52:06.659Z\u001b[0m [incoming-request ] \u001b[36mINFO \u001b[0m Received GET request for /.well-known/oauth-protected-resource/mcp\n\u001b[90m2026-09-08T23:52:06.659Z\u001b[0m [prm-pathbased-requested ] \u001b[32mSUCCESS\u001b[0m Client requested PRM metadata at path-based location\n\u001b[90m2026-09-08T23:52:06.659Z\u001b[0m [outgoing-response ] \u001b[36mINFO \u001b[0m Sent 200 response for GET /.well-known/oauth-protected-resource/mcp\n\n\u001b[90m2026-09-08T23:52:06.662Z\u001b[0m [incoming-auth-request ] \u001b[36mINFO \u001b[0m Received GET request for /.well-known/oauth-authorization-server\n\n...[truncated]" } ] } diff --git a/tests/testing/official_mcp_fixture_server.py b/tests/testing/official_mcp_fixture_server.py index 651799202..47cb80f3e 100644 --- a/tests/testing/official_mcp_fixture_server.py +++ b/tests/testing/official_mcp_fixture_server.py @@ -26,6 +26,7 @@ "ttlMs": 0, "cacheScope": "private", } +ALLOWED_PROTOCOL_VERSIONS = {"2025-11-25", "2026-07-28"} def _jsonrpc_result(request_id: Any, result: dict[str, Any]) -> dict[str, Any]: @@ -48,6 +49,18 @@ def _stateless_result(request_id: Any, result: dict[str, Any]) -> dict[str, Any] return _jsonrpc_result(request_id, {**STATELESS_RESULT_META, **result}) +def _normalize_protocol_version(value: Any) -> str: + if isinstance(value, str) and value in ALLOWED_PROTOCOL_VERSIONS: + return value + return "2025-11-25" + + +def _safe_header_part(value: str) -> str: + if "\r" in value or "\n" in value: + raise ValueError("invalid header value") + return value + + class ConformanceFixtureHandler(BaseHTTPRequestHandler): protocol_version = "HTTP/1.1" @@ -78,7 +91,7 @@ def do_POST(self) -> None: # noqa: N802 return if method == "initialize": - protocol_version = params.get("protocolVersion") or "2025-11-25" + protocol_version = _normalize_protocol_version(params.get("protocolVersion")) self._write_json( HTTPStatus.OK, _jsonrpc_result( @@ -197,7 +210,7 @@ def _write_json( self.send_header("Content-Type", "application/json") self.send_header("Content-Length", str(len(encoded))) for name, value in (headers or {}).items(): - self.send_header(name, value) + self.send_header(_safe_header_part(name), _safe_header_part(value)) self.end_headers() self.wfile.write(encoded) diff --git a/tests/unit/test_official_mcp_conformance.py b/tests/unit/test_official_mcp_conformance.py index 7d51fc6c2..f80ab5ecf 100644 --- a/tests/unit/test_official_mcp_conformance.py +++ b/tests/unit/test_official_mcp_conformance.py @@ -169,3 +169,42 @@ def test_fixture_server_returns_202_for_initialized_notification() -> None: finally: proc.terminate() proc.wait(timeout=5) + + +def test_fixture_server_does_not_reflect_invalid_protocol_version_header() -> None: + port = _free_port() + proc = subprocess.Popen( + [sys.executable, str(_FIXTURE_SERVER_PATH), "--port", str(port)], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + ) + try: + _wait_for_port(port) + with httpx.Client(timeout=5.0) as client: + response = client.post( + f"http://127.0.0.1:{port}/mcp", + headers={ + "Content-Type": "application/json", + "Accept": "application/json, text/event-stream", + "MCP-Protocol-Version": "2025-11-25", + }, + json={ + "jsonrpc": "2.0", + "id": 1, + "method": "initialize", + "params": { + "protocolVersion": "2025-11-25\r\nX-Injected: yes", + "capabilities": {}, + "clientInfo": {"name": "pytest", "version": "1.0.0"}, + }, + }, + ) + + assert response.status_code == 200 + assert response.headers["MCP-Protocol-Version"] == "2025-11-25" + assert response.json()["result"]["protocolVersion"] == "2025-11-25" + assert "X-Injected" not in response.headers + finally: + proc.terminate() + proc.wait(timeout=5)