From 113caa2502d36ef450d1783a6651b467ad9cffed Mon Sep 17 00:00:00 2001 From: Felix Weinberger Date: Mon, 9 Mar 2026 17:45:56 +0000 Subject: [PATCH 1/4] chore(deps): bump @modelcontextprotocol/conformance to 0.1.15 Pulls sdk@^1.26.0 (resolves to 1.27.1), clearing the Dependabot alert for GHSA-345p-7cg4-v4c7 (cross-client data leak, fixed in 1.26.0). Also removes stale minimumReleaseAgeExclude entries for hono@4.11.4 and @hono/node-server@1.19.9 (both well past 7 days). --- pnpm-lock.yaml | 180 +++++++++++++++++++++++++++++++--- pnpm-workspace.yaml | 2 - test/conformance/package.json | 2 +- 3 files changed, 166 insertions(+), 18 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cc778c3cf..dac3aac38 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -874,8 +874,8 @@ importers: specifier: workspace:^ version: link:../../packages/client '@modelcontextprotocol/conformance': - specifier: 0.1.10 - version: 0.1.10(@cfworker/json-schema@4.1.1)(hono@4.11.4) + specifier: 0.1.15 + version: 0.1.15(@cfworker/json-schema@4.1.1) '@modelcontextprotocol/core': specifier: workspace:^ version: link:../../packages/core @@ -1712,12 +1712,12 @@ packages: '@manypkg/get-packages@1.1.3': resolution: {integrity: sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==} - '@modelcontextprotocol/conformance@0.1.10': - resolution: {integrity: sha512-efzLxW3sNiC48ARADxNkSNSZREdjtQNJ+12MJHCUDSnHZMbiFa7v5SivB2Aja4LCE0ZiWgnG5I5PSNMBrp1xKg==} + '@modelcontextprotocol/conformance@0.1.15': + resolution: {integrity: sha512-B1eNYpv5kas9YFC40su7SWhKHR2DwYzJRpiX6dfWzDWMcDr71myKVj//PwyqUHC7oucs3EJqcqnwvSuUwvenoQ==} hasBin: true - '@modelcontextprotocol/sdk@1.25.2': - resolution: {integrity: sha512-LZFeo4F9M5qOhC/Uc1aQSrBHxMrvxett+9KLHt7OhcExtoiRN9DKgbZffMP/nxjutWDQpfMDfP3nkHI4X9ijww==} + '@modelcontextprotocol/sdk@1.27.1': + resolution: {integrity: sha512-sr6GbP+4edBwFndLbM60gf07z0FQ79gaExpnsjMGePXqFcSSb7t6iscpjk9DhFhwd+mTEQrzNafGP8/iGGFYaA==} engines: {node: '>=18'} peerDependencies: '@cfworker/json-schema': ^4.1.1 @@ -1756,6 +1756,58 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} + '@octokit/auth-token@6.0.0': + resolution: {integrity: sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w==} + engines: {node: '>= 20'} + + '@octokit/core@7.0.6': + resolution: {integrity: sha512-DhGl4xMVFGVIyMwswXeyzdL4uXD5OGILGX5N8Y+f6W7LhC1Ze2poSNrkF/fedpVDHEEZ+PHFW0vL14I+mm8K3Q==} + engines: {node: '>= 20'} + + '@octokit/endpoint@11.0.3': + resolution: {integrity: sha512-FWFlNxghg4HrXkD3ifYbS/IdL/mDHjh9QcsNyhQjN8dplUoZbejsdpmuqdA76nxj2xoWPs7p8uX2SNr9rYu0Ag==} + engines: {node: '>= 20'} + + '@octokit/graphql@9.0.3': + resolution: {integrity: sha512-grAEuupr/C1rALFnXTv6ZQhFuL1D8G5y8CN04RgrO4FIPMrtm+mcZzFG7dcBm+nq+1ppNixu+Jd78aeJOYxlGA==} + engines: {node: '>= 20'} + + '@octokit/openapi-types@27.0.0': + resolution: {integrity: sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA==} + + '@octokit/plugin-paginate-rest@14.0.0': + resolution: {integrity: sha512-fNVRE7ufJiAA3XUrha2omTA39M6IXIc6GIZLvlbsm8QOQCYvpq/LkMNGyFlB1d8hTDzsAXa3OKtybdMAYsV/fw==} + engines: {node: '>= 20'} + peerDependencies: + '@octokit/core': '>=6' + + '@octokit/plugin-request-log@6.0.0': + resolution: {integrity: sha512-UkOzeEN3W91/eBq9sPZNQ7sUBvYCqYbrrD8gTbBuGtHEuycE4/awMXcYvx6sVYo7LypPhmQwwpUe4Yyu4QZN5Q==} + engines: {node: '>= 20'} + peerDependencies: + '@octokit/core': '>=6' + + '@octokit/plugin-rest-endpoint-methods@17.0.0': + resolution: {integrity: sha512-B5yCyIlOJFPqUUeiD0cnBJwWJO8lkJs5d8+ze9QDP6SvfiXSz1BF+91+0MeI1d2yxgOhU/O+CvtiZ9jSkHhFAw==} + engines: {node: '>= 20'} + peerDependencies: + '@octokit/core': '>=6' + + '@octokit/request-error@7.1.0': + resolution: {integrity: sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw==} + engines: {node: '>= 20'} + + '@octokit/request@10.0.8': + resolution: {integrity: sha512-SJZNwY9pur9Agf7l87ywFi14W+Hd9Jg6Ifivsd33+/bGUQIjNujdFiXII2/qSlN2ybqUHfp5xpekMEjIBTjlSw==} + engines: {node: '>= 20'} + + '@octokit/rest@22.0.1': + resolution: {integrity: sha512-Jzbhzl3CEexhnivb1iQ0KJ7s5vvjMWcmRtq5aUsKmKDrRW6z3r84ngmiFKFvpZjpiU/9/S6ITPFRpn5s/3uQJw==} + engines: {node: '>= 20'} + + '@octokit/types@16.0.0': + resolution: {integrity: sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg==} + '@oxc-project/types@0.103.0': resolution: {integrity: sha512-bkiYX5kaXWwUessFRSoXFkGIQTmc6dLGdxuRTrC+h8PSnIdZyuXHHlLAeTmOue5Br/a0/a7dHH0Gca6eXn9MKg==} @@ -2538,6 +2590,9 @@ packages: resolution: {integrity: sha512-B0xUquLkiGLgHhpPBqvl7GWegWBUNuujQ6kXd/r1U38ElPT6Ok8KZ8e+FpUGEc2ZoRQUzq/aUnaKFc/svWUGSg==} hasBin: true + before-after-hook@4.0.0: + resolution: {integrity: sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ==} + better-auth@1.4.17: resolution: {integrity: sha512-VmHGQyKsEahkEs37qguROKg/6ypYpNF13D7v/lkbO7w7Aivz0Bv2h+VyUkH4NzrGY0QBKXi1577mGhDCVwp0ew==} peerDependencies: @@ -3131,8 +3186,8 @@ packages: resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} engines: {node: '>=12.0.0'} - express-rate-limit@7.5.1: - resolution: {integrity: sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==} + express-rate-limit@8.2.1: + resolution: {integrity: sha512-PCZEIEIxqwhzw4KF0n7QF4QqruVTcF73O5kFKUnGOyjbCCgizBBiFaYpd/fnBLUMPw/BWw9OsiN7GgrNYr7j6g==} engines: {node: '>= 16'} peerDependencies: express: '>= 4.11' @@ -3144,6 +3199,9 @@ packages: extendable-error@0.1.7: resolution: {integrity: sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==} + fast-content-type-parse@3.0.0: + resolution: {integrity: sha512-ZvLdcY8P+N8mGQJahJV5G4U88CSvT1rP8ApL6uETe88MBXrBHAkZlSEySdUlyztF7ccb+Znos3TFqaepHxdhBg==} + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -3402,6 +3460,10 @@ packages: resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} engines: {node: '>= 0.4'} + ip-address@10.0.1: + resolution: {integrity: sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==} + engines: {node: '>= 12'} + ipaddr.js@1.9.1: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} @@ -3583,6 +3645,9 @@ packages: json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + json-with-bigint@3.5.7: + resolution: {integrity: sha512-7ei3MdAI5+fJPVnKlW77TKNKwQ5ppSzWvhPuSuINT/GYW9ZOC1eRKOuhV9yHG5aEsUPj9BBx5JIekkmoLHxZOw==} + json5@1.0.2: resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} hasBin: true @@ -4404,9 +4469,16 @@ packages: resolution: {integrity: sha512-y+8YjDFzWdQlSE9N5nzKMT3g4a5UBX1HKowfdXh0uvAnTaqqwqB92Jt4UXBAeKekDs5IaDKyJFR4X1gYVCgXcw==} engines: {node: '>=20.18.1'} + undici@7.22.0: + resolution: {integrity: sha512-RqslV2Us5BrllB+JeiZnK4peryVTndy9Dnqq62S3yYRRTj0tFQCwEniUy2167skdGOy3vqRzEvl1Dm4sV2ReDg==} + engines: {node: '>=20.18.1'} + unenv@2.0.0-rc.24: resolution: {integrity: sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==} + universal-user-agent@7.0.3: + resolution: {integrity: sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==} + universalify@0.1.2: resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} engines: {node: '>= 4.0.0'} @@ -5253,20 +5325,22 @@ snapshots: globby: 11.1.0 read-yaml-file: 1.1.0 - '@modelcontextprotocol/conformance@0.1.10(@cfworker/json-schema@4.1.1)(hono@4.11.4)': + '@modelcontextprotocol/conformance@0.1.15(@cfworker/json-schema@4.1.1)': dependencies: - '@modelcontextprotocol/sdk': 1.25.2(@cfworker/json-schema@4.1.1)(hono@4.11.4)(zod@3.25.76) + '@modelcontextprotocol/sdk': 1.27.1(@cfworker/json-schema@4.1.1)(zod@3.25.76) + '@octokit/rest': 22.0.1 commander: 14.0.2 eventsource-parser: 3.0.6 express: 5.2.1 jose: 6.1.3 + undici: 7.22.0 + yaml: 2.8.2 zod: 3.25.76 transitivePeerDependencies: - '@cfworker/json-schema' - - hono - supports-color - '@modelcontextprotocol/sdk@1.25.2(@cfworker/json-schema@4.1.1)(hono@4.11.4)(zod@3.25.76)': + '@modelcontextprotocol/sdk@1.27.1(@cfworker/json-schema@4.1.1)(zod@3.25.76)': dependencies: '@hono/node-server': 1.19.9(hono@4.11.4) ajv: 8.17.1 @@ -5277,7 +5351,8 @@ snapshots: eventsource: 3.0.7 eventsource-parser: 3.0.6 express: 5.2.1 - express-rate-limit: 7.5.1(express@5.2.1) + express-rate-limit: 8.2.1(express@5.2.1) + hono: 4.11.4 jose: 6.1.3 json-schema-typed: 8.0.2 pkce-challenge: 5.0.1 @@ -5287,7 +5362,6 @@ snapshots: optionalDependencies: '@cfworker/json-schema': 4.1.1 transitivePeerDependencies: - - hono - supports-color '@napi-rs/wasm-runtime@0.2.12': @@ -5322,6 +5396,69 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.20.1 + '@octokit/auth-token@6.0.0': {} + + '@octokit/core@7.0.6': + dependencies: + '@octokit/auth-token': 6.0.0 + '@octokit/graphql': 9.0.3 + '@octokit/request': 10.0.8 + '@octokit/request-error': 7.1.0 + '@octokit/types': 16.0.0 + before-after-hook: 4.0.0 + universal-user-agent: 7.0.3 + + '@octokit/endpoint@11.0.3': + dependencies: + '@octokit/types': 16.0.0 + universal-user-agent: 7.0.3 + + '@octokit/graphql@9.0.3': + dependencies: + '@octokit/request': 10.0.8 + '@octokit/types': 16.0.0 + universal-user-agent: 7.0.3 + + '@octokit/openapi-types@27.0.0': {} + + '@octokit/plugin-paginate-rest@14.0.0(@octokit/core@7.0.6)': + dependencies: + '@octokit/core': 7.0.6 + '@octokit/types': 16.0.0 + + '@octokit/plugin-request-log@6.0.0(@octokit/core@7.0.6)': + dependencies: + '@octokit/core': 7.0.6 + + '@octokit/plugin-rest-endpoint-methods@17.0.0(@octokit/core@7.0.6)': + dependencies: + '@octokit/core': 7.0.6 + '@octokit/types': 16.0.0 + + '@octokit/request-error@7.1.0': + dependencies: + '@octokit/types': 16.0.0 + + '@octokit/request@10.0.8': + dependencies: + '@octokit/endpoint': 11.0.3 + '@octokit/request-error': 7.1.0 + '@octokit/types': 16.0.0 + fast-content-type-parse: 3.0.0 + json-with-bigint: 3.5.7 + universal-user-agent: 7.0.3 + + '@octokit/rest@22.0.1': + dependencies: + '@octokit/core': 7.0.6 + '@octokit/plugin-paginate-rest': 14.0.0(@octokit/core@7.0.6) + '@octokit/plugin-request-log': 6.0.0(@octokit/core@7.0.6) + '@octokit/plugin-rest-endpoint-methods': 17.0.0(@octokit/core@7.0.6) + + '@octokit/types@16.0.0': + dependencies: + '@octokit/openapi-types': 27.0.0 + '@oxc-project/types@0.103.0': {} '@oxc-project/types@0.106.0': {} @@ -5978,6 +6115,8 @@ snapshots: baseline-browser-mapping@2.9.14: {} + before-after-hook@4.0.0: {} + better-auth@1.4.17(better-sqlite3@12.6.2)(vitest@4.0.16(@types/node@24.10.4)(tsx@4.21.0)(yaml@2.8.2)): dependencies: '@better-auth/core': 1.4.17(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.8(zod@4.3.5))(jose@6.1.3)(kysely@0.28.9)(nanostores@1.1.0) @@ -6645,9 +6784,10 @@ snapshots: expect-type@1.3.0: {} - express-rate-limit@7.5.1(express@5.2.1): + express-rate-limit@8.2.1(express@5.2.1): dependencies: express: 5.2.1 + ip-address: 10.0.1 express@5.2.1: dependencies: @@ -6684,6 +6824,8 @@ snapshots: extendable-error@0.1.7: {} + fast-content-type-parse@3.0.0: {} + fast-deep-equal@3.1.3: {} fast-glob@3.3.3: @@ -6940,6 +7082,8 @@ snapshots: hasown: 2.0.2 side-channel: 1.1.0 + ip-address@10.0.1: {} + ipaddr.js@1.9.1: {} is-array-buffer@3.0.5: @@ -7110,6 +7254,8 @@ snapshots: json-stable-stringify-without-jsonify@1.0.1: {} + json-with-bigint@3.5.7: {} + json5@1.0.2: dependencies: minimist: 1.2.8 @@ -8041,10 +8187,14 @@ snapshots: undici@7.18.2: {} + undici@7.22.0: {} + unenv@2.0.0-rc.24: dependencies: pathe: 2.0.3 + universal-user-agent@7.0.3: {} + universalify@0.1.2: {} unpipe@1.0.0: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 0eaa89471..4c1280008 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -57,8 +57,6 @@ linkWorkspacePackages: deep minimumReleaseAge: 10080 # 7 days minimumReleaseAgeExclude: - '@modelcontextprotocol/conformance' - - hono@4.11.4 # fixes https://github.com/advisories/GHSA-3vhc-576x-3qv4 https://github.com/advisories/GHSA-f67f-6cw9-8mq4 - - '@hono/node-server@1.19.9' # https://github.com/honojs/node-server/pull/295 onlyBuiltDependencies: - better-sqlite3 diff --git a/test/conformance/package.json b/test/conformance/package.json index 253afd9a7..8967ff267 100644 --- a/test/conformance/package.json +++ b/test/conformance/package.json @@ -37,7 +37,7 @@ "test:conformance:all": "pnpm run test:conformance:client:all && pnpm run test:conformance:server:all" }, "devDependencies": { - "@modelcontextprotocol/conformance": "0.1.10", + "@modelcontextprotocol/conformance": "0.1.15", "@modelcontextprotocol/client": "workspace:^", "@modelcontextprotocol/server": "workspace:^", "@modelcontextprotocol/core": "workspace:^", From 54fa771a5c25d336a4e40aee41888e0da9c416d8 Mon Sep 17 00:00:00 2001 From: Felix Weinberger Date: Mon, 9 Mar 2026 17:56:09 +0000 Subject: [PATCH 2/4] test(conformance): add expected-failures baseline for unimplemented scenarios MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Conformance 0.1.15 added three scenarios the v2 SDK doesn't implement yet: - client: auth/pre-registration (OAuth without DCR) - client: auth/cross-app-access-complete-flow (SEP-990) - server: dns-rebinding-protection Baseline them via --expected-failures so CI exits 0 on expected failures, 1 on regressions or stale entries (scenario starts passing → must update file). --- test/conformance/expected-failures.yaml | 9 +++++++++ test/conformance/package.json | 8 ++++---- 2 files changed, 13 insertions(+), 4 deletions(-) create mode 100644 test/conformance/expected-failures.yaml diff --git a/test/conformance/expected-failures.yaml b/test/conformance/expected-failures.yaml new file mode 100644 index 000000000..f6d500f5e --- /dev/null +++ b/test/conformance/expected-failures.yaml @@ -0,0 +1,9 @@ +# Conformance scenarios not yet implemented in the v2 TypeScript SDK. +# CI exits 0 if only these fail, exits 1 on unexpected failures or stale entries. + +client: + - auth/pre-registration + - auth/cross-app-access-complete-flow + +server: + - dns-rebinding-protection diff --git a/test/conformance/package.json b/test/conformance/package.json index 8967ff267..db0f04a4d 100644 --- a/test/conformance/package.json +++ b/test/conformance/package.json @@ -28,11 +28,11 @@ "start": "npm run server", "server": "tsx watch --clear-screen=false scripts/cli.ts server", "client": "tsx scripts/cli.ts client", - "test:conformance:client": "conformance client --command 'npx tsx ./src/everythingClient.ts'", - "test:conformance:client:all": "conformance client --command 'npx tsx ./src/everythingClient.ts' --suite all", + "test:conformance:client": "conformance client --command 'npx tsx ./src/everythingClient.ts' --expected-failures ./expected-failures.yaml", + "test:conformance:client:all": "conformance client --command 'npx tsx ./src/everythingClient.ts' --suite all --expected-failures ./expected-failures.yaml", "test:conformance:client:run": "npx tsx ./src/everythingClient.ts", - "test:conformance:server": "scripts/run-server-conformance.sh", - "test:conformance:server:all": "scripts/run-server-conformance.sh --suite all", + "test:conformance:server": "scripts/run-server-conformance.sh --expected-failures ./expected-failures.yaml", + "test:conformance:server:all": "scripts/run-server-conformance.sh --suite all --expected-failures ./expected-failures.yaml", "test:conformance:server:run": "npx tsx ./src/everythingServer.ts", "test:conformance:all": "pnpm run test:conformance:client:all && pnpm run test:conformance:server:all" }, From 62ff4c21a6325b015d31c35b3af157e83aac57cb Mon Sep 17 00:00:00 2001 From: Felix Weinberger Date: Mon, 9 Mar 2026 18:06:06 +0000 Subject: [PATCH 3/4] test(conformance): enable DNS rebinding protection in everything server The SDK has localhostHostValidation() middleware; the conformance test server just wasn't using it. Add it so the dns-rebinding-protection scenario passes instead of baselining it as an expected failure. --- test/conformance/expected-failures.yaml | 3 --- test/conformance/src/everythingServer.ts | 4 ++++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/test/conformance/expected-failures.yaml b/test/conformance/expected-failures.yaml index f6d500f5e..e43c27da6 100644 --- a/test/conformance/expected-failures.yaml +++ b/test/conformance/expected-failures.yaml @@ -4,6 +4,3 @@ client: - auth/pre-registration - auth/cross-app-access-complete-flow - -server: - - dns-rebinding-protection diff --git a/test/conformance/src/everythingServer.ts b/test/conformance/src/everythingServer.ts index bebdcf9a3..25a6feb0f 100644 --- a/test/conformance/src/everythingServer.ts +++ b/test/conformance/src/everythingServer.ts @@ -9,6 +9,7 @@ import { randomUUID } from 'node:crypto'; +import { localhostHostValidation } from '@modelcontextprotocol/express'; import { NodeStreamableHTTPServerTransport } from '@modelcontextprotocol/node'; import type { CallToolResult, EventId, EventStore, GetPromptResult, ReadResourceResult, StreamId } from '@modelcontextprotocol/server'; import { isInitializeRequest, McpServer, ResourceTemplate } from '@modelcontextprotocol/server'; @@ -876,6 +877,9 @@ function createMcpServer() { const app = express(); app.use(express.json()); +// DNS rebinding protection: reject non-localhost Host headers +app.use(localhostHostValidation()); + // Configure CORS to expose Mcp-Session-Id header for browser-based clients app.use( cors({ From 6ff84dabb119da2cb08a0fe6874071234d4643f0 Mon Sep 17 00:00:00 2001 From: Felix Weinberger Date: Wed, 11 Mar 2026 12:53:03 +0000 Subject: [PATCH 4/4] test(conformance): port auth/pre-registration scenario from v1.x Forward-ports PR #1545 from v1.x. The SDK already skips DCR when clientInformation() returns pre-populated credentials; only the conformance adapter wiring was missing. - withOAuthRetry: accept optional existingProvider - everythingClient: register auth/pre-registration handler - expected-failures: drop now-passing scenario --- test/conformance/expected-failures.yaml | 1 - test/conformance/src/everythingClient.ts | 43 +++++++++++++++++++ .../conformance/src/helpers/withOAuthRetry.ts | 21 +++++---- 3 files changed, 55 insertions(+), 10 deletions(-) diff --git a/test/conformance/expected-failures.yaml b/test/conformance/expected-failures.yaml index e43c27da6..a8d1895a0 100644 --- a/test/conformance/expected-failures.yaml +++ b/test/conformance/expected-failures.yaml @@ -2,5 +2,4 @@ # CI exits 0 if only these fail, exits 1 on unexpected failures or stale entries. client: - - auth/pre-registration - auth/cross-app-access-complete-flow diff --git a/test/conformance/src/everythingClient.ts b/test/conformance/src/everythingClient.ts index 211fa41f5..22b255960 100644 --- a/test/conformance/src/everythingClient.ts +++ b/test/conformance/src/everythingClient.ts @@ -15,6 +15,7 @@ import { Client, ClientCredentialsProvider, PrivateKeyJwtProvider, StreamableHTTPClientTransport } from '@modelcontextprotocol/client'; import * as z from 'zod/v4'; +import { ConformanceOAuthProvider } from './helpers/conformanceOAuthProvider.js'; import { logger } from './helpers/logger.js'; import { handle401, withOAuthRetry } from './helpers/withOAuthRetry.js'; @@ -42,6 +43,11 @@ const ClientConformanceContextSchema = z.discriminatedUnion('name', [ name: z.literal('auth/client-credentials-basic'), client_id: z.string(), client_secret: z.string() + }), + z.object({ + name: z.literal('auth/pre-registration'), + client_id: z.string(), + client_secret: z.string() }) ]); @@ -240,6 +246,43 @@ async function runClientCredentialsBasic(serverUrl: string): Promise { registerScenario('auth/client-credentials-basic', runClientCredentialsBasic); +// ============================================================================ +// Pre-registration scenario (no dynamic client registration) +// ============================================================================ + +async function runPreRegistrationClient(serverUrl: string): Promise { + const ctx = parseContext(); + if (ctx.name !== 'auth/pre-registration') { + throw new Error(`Expected pre-registration context, got ${ctx.name}`); + } + + // Create a provider pre-populated with registered credentials, + // so the SDK skips dynamic client registration. + const provider = new ConformanceOAuthProvider('http://localhost:3000/callback', { + client_name: 'conformance-pre-registration', + redirect_uris: ['http://localhost:3000/callback'] + }); + provider.saveClientInformation({ + client_id: ctx.client_id, + client_secret: ctx.client_secret, + redirect_uris: ['http://localhost:3000/callback'] + }); + + const oauthFetch = withOAuthRetry('conformance-pre-registration', new URL(serverUrl), handle401, undefined, provider)(fetch); + + const client = new Client({ name: 'conformance-pre-registration', version: '1.0.0' }, { capabilities: {} }); + 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(); +} + +registerScenario('auth/pre-registration', runPreRegistrationClient); + // ============================================================================ // Elicitation defaults scenario // ============================================================================ diff --git a/test/conformance/src/helpers/withOAuthRetry.ts b/test/conformance/src/helpers/withOAuthRetry.ts index 187b93740..cbed3e238 100644 --- a/test/conformance/src/helpers/withOAuthRetry.ts +++ b/test/conformance/src/helpers/withOAuthRetry.ts @@ -55,16 +55,19 @@ export const withOAuthRetry = ( clientName: string, baseUrl?: string | URL, handle401Fn: typeof handle401 = handle401, - clientMetadataUrl?: string + clientMetadataUrl?: string, + existingProvider?: ConformanceOAuthProvider ): Middleware => { - const provider = new ConformanceOAuthProvider( - 'http://localhost:3000/callback', - { - client_name: clientName, - redirect_uris: ['http://localhost:3000/callback'] - }, - clientMetadataUrl - ); + const provider = + existingProvider ?? + new ConformanceOAuthProvider( + 'http://localhost:3000/callback', + { + client_name: clientName, + redirect_uris: ['http://localhost:3000/callback'] + }, + clientMetadataUrl + ); return (next: FetchLike) => { return async (input: string | URL, init?: RequestInit): Promise => { const makeRequest = async (): Promise => {