From 57ba447475b8e7ec9f352fa6f045dce5933158d5 Mon Sep 17 00:00:00 2001 From: 404ARE <936233544@qq.com> Date: Thu, 8 Oct 2026 17:34:34 +0800 Subject: [PATCH 1/2] fix(mcp): unblock nightly with issuer-safe SDK upgrade Generated-by: OpenAI Codex --- .../licenses/npm/THIRD_PARTY_NOTICES.txt | 227 +++++++++++++++++- package-lock.json | 16 +- packages/cli/THIRD_PARTY_NOTICES.txt | 4 +- packages/mcp/package.json | 2 +- packages/mcp/src/__tests__/oauth.test.ts | 153 ++++++++++-- packages/mcp/src/oauth.ts | 10 +- ... @modelcontextprotocol+client+2.2.0.patch} | 32 +-- patches/README.md | 2 +- 8 files changed, 391 insertions(+), 55 deletions(-) rename patches/{@modelcontextprotocol+client+2.1.0.patch => @modelcontextprotocol+client+2.2.0.patch} (84%) diff --git a/apps/desktop/resources/licenses/npm/THIRD_PARTY_NOTICES.txt b/apps/desktop/resources/licenses/npm/THIRD_PARTY_NOTICES.txt index 33501a5bc5d..7e62f8d604c 100644 --- a/apps/desktop/resources/licenses/npm/THIRD_PARTY_NOTICES.txt +++ b/apps/desktop/resources/licenses/npm/THIRD_PARTY_NOTICES.txt @@ -1454,7 +1454,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================================================ -Package: @modelcontextprotocol/client@2.1.0 +Package: @modelcontextprotocol/client@2.2.0 Declared license: MIT Selected license: MIT Repository: git+https://github.com/modelcontextprotocol/typescript-sdk.git @@ -2129,6 +2129,231 @@ the full license text. ================================================================================ +Package: @modelcontextprotocol/core@2.2.0 +Declared license: MIT +Selected license: MIT +Repository: git+https://github.com/modelcontextprotocol/typescript-sdk.git + +--- LICENSE --- +The MCP project is undergoing a licensing transition from the MIT License to the Apache License, Version 2.0 ("Apache-2.0"). All new code and specification contributions to the project are licensed under Apache-2.0. Documentation contributions (excluding specifications) are licensed under CC-BY-4.0. + +Contributions for which relicensing consent has been obtained are licensed under Apache-2.0. Contributions made by authors who originally licensed their work under the MIT License and who have not yet granted explicit permission to relicense remain licensed under the MIT License. + +No rights beyond those granted by the applicable original license are conveyed for such contributions. + +--- + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to the Licensor for inclusion in the Work by the copyright + owner or by an individual or Legal Entity authorized to submit on behalf + of the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + +--- + +MIT License + +Copyright (c) 2024-2025 Model Context Protocol a Series of LF Projects, LLC. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +--- + +Creative Commons Attribution 4.0 International (CC-BY-4.0) + +Documentation in this project (excluding specifications) is licensed under +CC-BY-4.0. See https://creativecommons.org/licenses/by/4.0/legalcode for +the full license text. + +================================================================================ + Package: @modelcontextprotocol/node@2.1.0 Declared license: MIT Selected license: MIT diff --git a/package-lock.json b/package-lock.json index f9b0c49065d..4f9c96b1bfe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3560,12 +3560,12 @@ "license": "BSD-2-Clause" }, "node_modules/@modelcontextprotocol/client": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/client/-/client-2.1.0.tgz", - "integrity": "sha512-mDVhoy5WjDb0U+4dQPzLcciC2erSex/GRVQqnoZdiuMoE3YiTZdiS7ezNcFwX4XEOWOaj7jZr0kLYnILnL8orA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/client/-/client-2.2.0.tgz", + "integrity": "sha512-LxCou/CSYQ6dwEnjhLZY0KnEuc8V4UJ3IEQCl/uR2yHobSQIEdJKUlKLRYRF5i5FqRGHy1eK7une3aAWDHLtig==", "license": "MIT", "dependencies": { - "@modelcontextprotocol/core": "2.1.0", + "@modelcontextprotocol/core": "2.2.0", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", @@ -3578,9 +3578,9 @@ } }, "node_modules/@modelcontextprotocol/client/node_modules/@modelcontextprotocol/core": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/core/-/core-2.1.0.tgz", - "integrity": "sha512-YdFj5gMRHr0gYNAhTbQDgjLHiEJdIAUYxomhKseUNye7ZGlISQmUoLh2sveFFCiQ7j2YMffT1kgSND0FSfIFjQ==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/core/-/core-2.2.0.tgz", + "integrity": "sha512-iLhmprRmWI8EcosOA3wVvww22z02NkgqhV4fBH6f/odQBsi7xnJc0HGmi21yWO+/iKw2yzqVE127Zhna5/+JXw==", "license": "MIT", "dependencies": { "zod": "^4.2.0" @@ -17354,7 +17354,7 @@ "license": "Apache-2.0", "dependencies": { "@maka/core": "0.1.0", - "@modelcontextprotocol/client": "2.1.0" + "@modelcontextprotocol/client": "2.2.0" }, "devDependencies": { "@modelcontextprotocol/node": "2.1.0", diff --git a/packages/cli/THIRD_PARTY_NOTICES.txt b/packages/cli/THIRD_PARTY_NOTICES.txt index 7055a7f54a2..c127e54002d 100644 --- a/packages/cli/THIRD_PARTY_NOTICES.txt +++ b/packages/cli/THIRD_PARTY_NOTICES.txt @@ -752,7 +752,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================================================ -Package: @modelcontextprotocol/client@2.1.0 +Package: @modelcontextprotocol/client@2.2.0 Declared license: MIT Selected license: MIT Repository: git+https://github.com/modelcontextprotocol/typescript-sdk.git @@ -977,7 +977,7 @@ the full license text. ================================================================================ -Package: @modelcontextprotocol/core@2.1.0 +Package: @modelcontextprotocol/core@2.2.0 Declared license: MIT Selected license: MIT Repository: git+https://github.com/modelcontextprotocol/typescript-sdk.git diff --git a/packages/mcp/package.json b/packages/mcp/package.json index bbfa8ee6807..56c60101447 100644 --- a/packages/mcp/package.json +++ b/packages/mcp/package.json @@ -20,7 +20,7 @@ }, "dependencies": { "@maka/core": "0.1.0", - "@modelcontextprotocol/client": "2.1.0" + "@modelcontextprotocol/client": "2.2.0" }, "devDependencies": { "@modelcontextprotocol/node": "2.1.0", diff --git a/packages/mcp/src/__tests__/oauth.test.ts b/packages/mcp/src/__tests__/oauth.test.ts index 3a299b0b705..c2e27696b9e 100644 --- a/packages/mcp/src/__tests__/oauth.test.ts +++ b/packages/mcp/src/__tests__/oauth.test.ts @@ -139,7 +139,11 @@ describe('McpClientManager OAuth E2E', () => { const storage = createMemoryMcpOAuthStorage(); await storage.set('remote', { serverUrl: fixture.mcpUrl, - tokens: { access_token: fixture.accessToken, token_type: 'Bearer' }, + tokens: { + issuer: new URL(fixture.mcpUrl).origin, + access_token: fixture.accessToken, + token_type: 'Bearer', + }, }); const manager = new McpClientManager({ oauthStorage: storage }); managers.push(manager); @@ -155,8 +159,9 @@ describe('McpClientManager OAuth E2E', () => { const storage = createMemoryMcpOAuthStorage(); await storage.set('remote', { serverUrl: fixture.mcpUrl, - clientInformation: { client_id: 'stored-client' }, + clientInformation: { issuer: new URL(fixture.mcpUrl).origin, client_id: 'stored-client' }, tokens: { + issuer: new URL(fixture.mcpUrl).origin, access_token: 'stale-token', token_type: 'Bearer', refresh_token: fixture.refreshToken, @@ -177,7 +182,11 @@ describe('McpClientManager OAuth E2E', () => { const storage = createMemoryMcpOAuthStorage(); await storage.set('remote', { serverUrl: fixture.mcpUrl, - tokens: { access_token: fixture.accessToken, token_type: 'Bearer' }, + tokens: { + issuer: new URL(fixture.mcpUrl).origin, + access_token: fixture.accessToken, + token_type: 'Bearer', + }, }); const manager = new McpClientManager({ oauthStorage: storage }); managers.push(manager); @@ -199,7 +208,11 @@ describe('McpClientManager OAuth E2E', () => { // the old config, so only the record's own binding can stop the replay. await storage.set('remote', { serverUrl: 'https://old.example/mcp', - tokens: { access_token: fixture.accessToken, token_type: 'Bearer' }, + tokens: { + issuer: new URL(fixture.mcpUrl).origin, + access_token: fixture.accessToken, + token_type: 'Bearer', + }, }); const manager = new McpClientManager({ oauthStorage: storage }); managers.push(manager); @@ -288,7 +301,11 @@ describe('McpClientManager OAuth E2E', () => { const storage = createMemoryMcpOAuthStorage(); await storage.set('remote', { serverUrl: fixture.mcpUrl, - tokens: { access_token: fixture.accessToken, token_type: 'Bearer' }, + tokens: { + issuer: new URL(fixture.mcpUrl).origin, + access_token: fixture.accessToken, + token_type: 'Bearer', + }, }); const manager = new McpClientManager({ oauthStorage: storage }); managers.push(manager); @@ -321,7 +338,11 @@ describe('McpClientManager OAuth E2E', () => { const storage = createMemoryMcpOAuthStorage(); await storage.set('remote', { serverUrl: fixture.mcpUrl, - tokens: { access_token: fixture.accessToken, token_type: 'Bearer' }, + tokens: { + issuer: new URL(fixture.mcpUrl).origin, + access_token: fixture.accessToken, + token_type: 'Bearer', + }, }); const manager = new McpClientManager({ oauthStorage: storage }); managers.push(manager); @@ -374,7 +395,12 @@ describe('McpClientManager OAuth E2E', () => { const storage = createMemoryMcpOAuthStorage(); await storage.set('remote', { serverUrl: fixture.mcpUrl, - tokens: { access_token: fixture.accessToken, token_type: 'Bearer', id_token: idToken }, + tokens: { + issuer: new URL(fixture.mcpUrl).origin, + access_token: fixture.accessToken, + token_type: 'Bearer', + id_token: idToken, + }, }); const manager = new McpClientManager({ oauthStorage: storage }); managers.push(manager); @@ -431,8 +457,9 @@ describe('McpClientManager OAuth E2E', () => { const storage = createMemoryMcpOAuthStorage(); await storage.set('remote', { serverUrl: fixture.mcpUrl, - clientInformation: { client_id: 'stored-client' }, + clientInformation: { issuer: new URL(fixture.mcpUrl).origin, client_id: 'stored-client' }, tokens: { + issuer: new URL(fixture.mcpUrl).origin, access_token: 'stale-token', token_type: 'Bearer', refresh_token: fixture.refreshToken, @@ -492,7 +519,11 @@ describe('McpClientManager OAuth E2E', () => { const storage = createMemoryMcpOAuthStorage(); await storage.set('remote', { serverUrl: fixture.mcpUrl, - tokens: { access_token: fixture.accessToken, token_type: 'Bearer' }, + tokens: { + issuer: new URL(fixture.mcpUrl).origin, + access_token: fixture.accessToken, + token_type: 'Bearer', + }, }); const manager = new McpClientManager({ oauthStorage: storage }); managers.push(manager); @@ -582,8 +613,9 @@ describe('McpClientManager OAuth E2E', () => { }; await memory.set('remote', { serverUrl: fixture.mcpUrl, - clientInformation: { client_id: 'stored-client' }, + clientInformation: { issuer: new URL(fixture.mcpUrl).origin, client_id: 'stored-client' }, tokens: { + issuer: new URL(fixture.mcpUrl).origin, access_token: 'stale-token', token_type: 'Bearer', refresh_token: fixture.refreshToken, @@ -615,7 +647,11 @@ describe('McpClientManager OAuth E2E', () => { const storage = createMemoryMcpOAuthStorage(); await storage.set('remote', { serverUrl: fixture.mcpUrl, - tokens: { access_token: fixture.accessToken, token_type: 'Bearer' }, + tokens: { + issuer: new URL(fixture.mcpUrl).origin, + access_token: fixture.accessToken, + token_type: 'Bearer', + }, }); const manager = new McpClientManager({ oauthStorage: storage }); managers.push(manager); @@ -669,7 +705,11 @@ describe('McpClientManager OAuth E2E', () => { const storage = createMemoryMcpOAuthStorage(); await storage.set('remote', { serverUrl: fixture.mcpUrl, - tokens: { access_token: fixture.accessToken, token_type: 'Bearer' }, + tokens: { + issuer: new URL(fixture.mcpUrl).origin, + access_token: fixture.accessToken, + token_type: 'Bearer', + }, }); const manager = new McpClientManager({ oauthStorage: storage }); managers.push(manager); @@ -875,7 +915,11 @@ describe('McpClientManager OAuth E2E', () => { const storage = createMemoryMcpOAuthStorage(); await storage.set('remote', { serverUrl: fixture.mcpUrl, - tokens: { access_token: fixture.accessToken, token_type: 'Bearer' }, + tokens: { + issuer: new URL(fixture.mcpUrl).origin, + access_token: fixture.accessToken, + token_type: 'Bearer', + }, }); const manager = new McpClientManager({ oauthStorage: storage }); managers.push(manager); @@ -905,7 +949,11 @@ describe('McpClientManager OAuth E2E', () => { await storage.set('remote', { serverUrl: fixture.mcpUrl, generation: 1, - tokens: { access_token: fixture.accessToken, token_type: 'Bearer' }, + tokens: { + issuer: new URL(fixture.mcpUrl).origin, + access_token: fixture.accessToken, + token_type: 'Bearer', + }, }); await manager.sync({ version: MCP_CONFIG_VERSION, mcpServers: {} }); const afterRemoval = await storage.get('remote'); @@ -926,7 +974,11 @@ describe('McpClientManager OAuth E2E', () => { await storage.set('remote', { serverUrl: fixture.mcpUrl, generation: 1, - tokens: { access_token: fixture.accessToken, token_type: 'Bearer' }, + tokens: { + issuer: new URL(fixture.mcpUrl).origin, + access_token: fixture.accessToken, + token_type: 'Bearer', + }, }); await late.sync(config(fixture.mcpUrl)); @@ -939,7 +991,11 @@ describe('McpClientManager OAuth E2E', () => { const memory = createMemoryMcpOAuthStorage(); await memory.set('remote', { serverUrl: fixture.mcpUrl, - tokens: { access_token: fixture.accessToken, token_type: 'Bearer' }, + tokens: { + issuer: new URL(fixture.mcpUrl).origin, + access_token: fixture.accessToken, + token_type: 'Bearer', + }, }); let storageDown = false; const flaky: McpOAuthStorage = { @@ -1064,8 +1120,9 @@ describe('McpClientManager OAuth E2E', () => { const storage = createMemoryMcpOAuthStorage(); await storage.set('remote', { serverUrl: fixture.mcpUrl, - clientInformation: { client_id: 'stored-client' }, + clientInformation: { issuer: new URL(fixture.mcpUrl).origin, client_id: 'stored-client' }, tokens: { + issuer: new URL(fixture.mcpUrl).origin, access_token: 'stale-token', token_type: 'Bearer', refresh_token: fixture.refreshToken, @@ -1099,8 +1156,12 @@ describe('McpClientManager OAuth E2E', () => { const storage = createMemoryMcpOAuthStorage(); // Legacy/hand-written record: credential material, no serverUrl. await storage.set('remote', { - tokens: { access_token: fixture.accessToken, token_type: 'Bearer' }, - clientInformation: { client_id: 'stored-client' }, + tokens: { + issuer: new URL(fixture.mcpUrl).origin, + access_token: fixture.accessToken, + token_type: 'Bearer', + }, + clientInformation: { issuer: new URL(fixture.mcpUrl).origin, client_id: 'stored-client' }, }); const manager = new McpClientManager({ oauthStorage: storage }); managers.push(manager); @@ -1182,6 +1243,38 @@ describe('McpClientManager OAuth E2E', () => { } }); + test('legacy credentials without issuer binding require a fresh sign-in', async () => { + for (const missing of ['tokens', 'clientInformation'] as const) { + const storage = createMemoryMcpOAuthStorage(); + const issuer = 'https://as.example'; + await storage.set('remote', { + serverUrl: 'https://mcp.example/mcp', + tokens: { + ...(missing === 'tokens' ? {} : { issuer }), + access_token: 'old-token', + refresh_token: 'old-refresh', + token_type: 'Bearer', + }, + clientInformation: { + ...(missing === 'clientInformation' ? {} : { issuer }), + client_id: 'old-client', + client_secret: 'old-secret', + }, + }); + const provider = new McpOAuthProvider({ + serverId: 'remote', + serverUrl: 'https://mcp.example/mcp', + storage, + clientName: 'maka', + clientVersion: '0.0.0', + }); + assert.equal(await provider.tokens(), undefined); + await assert.rejects(provider.clientInformation(), McpAuthRequiredError); + assert.equal((await storage.get('remote'))?.tokens, undefined); + assert.equal((await storage.get('remote'))?.clientInformation, undefined); + } + }); + test('static credentials survive restart only with the same configured registration', async () => { const config = { issuer: 'https://as.example', clientId: 'client-a', clientSecret: 'secret-a' }; for (const changed of [ @@ -1226,8 +1319,12 @@ describe('McpClientManager OAuth E2E', () => { const storage = createMemoryMcpOAuthStorage(); await storage.set('remote', { serverUrl: 'https://mcp.example/mcp', - clientInformation: { client_id: 'as-a-client', client_secret: 'as-a-secret' }, - tokens: { access_token: 'as-a-token', token_type: 'Bearer' }, + clientInformation: { + issuer: 'https://as-a.example', + client_id: 'as-a-client', + client_secret: 'as-a-secret', + }, + tokens: { issuer: 'https://as-a.example', access_token: 'as-a-token', token_type: 'Bearer' }, discovery: { authorizationServerUrl: 'https://as-a.example' } as never, }); const provider = new McpOAuthProvider({ @@ -1255,8 +1352,12 @@ describe('McpClientManager OAuth E2E', () => { const storage = createMemoryMcpOAuthStorage(); await storage.set('remote', { serverUrl: 'https://old.example/mcp', - clientInformation: { client_id: 'old-client', client_secret: 'old-secret' }, - tokens: { access_token: 'old-token', token_type: 'Bearer' }, + clientInformation: { + issuer: 'https://as.example', + client_id: 'old-client', + client_secret: 'old-secret', + }, + tokens: { issuer: 'https://as.example', access_token: 'old-token', token_type: 'Bearer' }, discovery: { authorizationServerUrl: 'https://as.example' } as never, generation: 3, version: 7, @@ -1406,7 +1507,11 @@ describe('McpClientManager OAuth E2E', () => { const memory = createMemoryMcpOAuthStorage(); await memory.set('remote', { serverUrl: fixture.mcpUrl, - tokens: { access_token: fixture.accessToken, token_type: 'Bearer' }, + tokens: { + issuer: new URL(fixture.mcpUrl).origin, + access_token: fixture.accessToken, + token_type: 'Bearer', + }, }); let storageDown = false; const flaky: McpOAuthStorage = { diff --git a/packages/mcp/src/oauth.ts b/packages/mcp/src/oauth.ts index 2e53ec5dce8..7fc5d998a25 100644 --- a/packages/mcp/src/oauth.ts +++ b/packages/mcp/src/oauth.ts @@ -404,9 +404,15 @@ export class McpOAuthProvider implements OAuthClientProvider { record.pendingRedirectUrl || record.pendingServerUrl || record.pendingState; + // SDK credentials predating issuer binding cannot safely follow discovery. + // Revoke them instead of adopting whichever issuer the server names next. + const missingIssuer = + (record.tokens !== undefined && !record.tokens.issuer) || + (record.clientInformation !== undefined && !record.clientInformation.issuer); return ( - Boolean(boundable) && - !mcpOAuthRecordBoundTo(record, this.options.serverUrl, this.options.config) + missingIssuer || + (Boolean(boundable) && + !mcpOAuthRecordBoundTo(record, this.options.serverUrl, this.options.config)) ); } diff --git a/patches/@modelcontextprotocol+client+2.1.0.patch b/patches/@modelcontextprotocol+client+2.2.0.patch similarity index 84% rename from patches/@modelcontextprotocol+client+2.1.0.patch rename to patches/@modelcontextprotocol+client+2.2.0.patch index e1997e71dbd..a0f28d6e682 100644 --- a/patches/@modelcontextprotocol+client+2.1.0.patch +++ b/patches/@modelcontextprotocol+client+2.2.0.patch @@ -1,8 +1,8 @@ -diff --git a/node_modules/@modelcontextprotocol/client/dist/src-D0qEN74R.cjs b/node_modules/@modelcontextprotocol/client/dist/src-D0qEN74R.cjs -index 534b4b6..2046548 100644 ---- a/node_modules/@modelcontextprotocol/client/dist/src-D0qEN74R.cjs -+++ b/node_modules/@modelcontextprotocol/client/dist/src-D0qEN74R.cjs -@@ -5625,6 +5625,22 @@ function requestStateAccessor(value) { +diff --git a/node_modules/@modelcontextprotocol/client/dist/src-oZBjf3U1.cjs b/node_modules/@modelcontextprotocol/client/dist/src-oZBjf3U1.cjs +index 001483a..fbb2506 100644 +--- a/node_modules/@modelcontextprotocol/client/dist/src-oZBjf3U1.cjs ++++ b/node_modules/@modelcontextprotocol/client/dist/src-oZBjf3U1.cjs +@@ -5635,6 +5635,22 @@ function requestStateAccessor(value) { /** Shared no-state accessor: the common case allocates nothing per request. */ const NO_REQUEST_STATE = requestStateAccessor(void 0); let writeNegotiatedProtocolVersion; @@ -25,7 +25,7 @@ index 534b4b6..2046548 100644 /** * Implements MCP protocol framing on top of a pluggable transport, including * features like request/response linking, notifications, and progress. -@@ -6128,6 +6144,7 @@ var Protocol = class { +@@ -6138,6 +6154,7 @@ var Protocol = class { const flowStartedAt = Date.now(); let onAbort; let cleanupMessageId; @@ -33,7 +33,7 @@ index 534b4b6..2046548 100644 return new Promise((resolve, reject) => { const earlyReject = (error) => { reject(error); -@@ -6181,7 +6198,7 @@ var Protocol = class { +@@ -6191,7 +6208,7 @@ var Protocol = class { relatedRequestId, resumptionToken, onresumptiontoken @@ -42,7 +42,7 @@ index 534b4b6..2046548 100644 } else requestAbort.abort(); reject(reason instanceof SdkError ? reason : new SdkError(SdkErrorCode.RequestTimeout, String(reason))); }; -@@ -6222,17 +6239,17 @@ var Protocol = class { +@@ -6232,17 +6249,17 @@ var Protocol = class { const timeout = options?.timeout ?? DEFAULT_REQUEST_TIMEOUT_MSEC; const timeoutHandler = () => cancel(new SdkError(SdkErrorCode.RequestTimeout, "Request timed out", { timeout })); this._setupTimeout(messageId, timeout, options?.maxTotalTimeout, timeoutHandler, options?.resetTimeoutOnProgress ?? false); @@ -64,11 +64,11 @@ index 534b4b6..2046548 100644 if (onAbort) options?.signal?.removeEventListener("abort", onAbort); if (cleanupMessageId !== void 0) { this._responseHandlers.delete(cleanupMessageId); -diff --git a/node_modules/@modelcontextprotocol/client/dist/src-DDAAhLnO.mjs b/node_modules/@modelcontextprotocol/client/dist/src-DDAAhLnO.mjs -index 0801440..e84e02d 100644 ---- a/node_modules/@modelcontextprotocol/client/dist/src-DDAAhLnO.mjs -+++ b/node_modules/@modelcontextprotocol/client/dist/src-DDAAhLnO.mjs -@@ -5624,6 +5624,22 @@ function requestStateAccessor(value) { +diff --git a/node_modules/@modelcontextprotocol/client/dist/src-xKF0PJN-.mjs b/node_modules/@modelcontextprotocol/client/dist/src-xKF0PJN-.mjs +index f10b537..265f3ce 100644 +--- a/node_modules/@modelcontextprotocol/client/dist/src-xKF0PJN-.mjs ++++ b/node_modules/@modelcontextprotocol/client/dist/src-xKF0PJN-.mjs +@@ -5634,6 +5634,22 @@ function requestStateAccessor(value) { /** Shared no-state accessor: the common case allocates nothing per request. */ const NO_REQUEST_STATE = requestStateAccessor(void 0); let writeNegotiatedProtocolVersion; @@ -91,7 +91,7 @@ index 0801440..e84e02d 100644 /** * Implements MCP protocol framing on top of a pluggable transport, including * features like request/response linking, notifications, and progress. -@@ -6127,6 +6143,7 @@ var Protocol = class { +@@ -6137,6 +6153,7 @@ var Protocol = class { const flowStartedAt = Date.now(); let onAbort; let cleanupMessageId; @@ -99,7 +99,7 @@ index 0801440..e84e02d 100644 return new Promise((resolve, reject) => { const earlyReject = (error) => { reject(error); -@@ -6180,7 +6197,7 @@ var Protocol = class { +@@ -6190,7 +6207,7 @@ var Protocol = class { relatedRequestId, resumptionToken, onresumptiontoken @@ -108,7 +108,7 @@ index 0801440..e84e02d 100644 } else requestAbort.abort(); reject(reason instanceof SdkError ? reason : new SdkError(SdkErrorCode.RequestTimeout, String(reason))); }; -@@ -6221,17 +6238,17 @@ var Protocol = class { +@@ -6231,17 +6248,17 @@ var Protocol = class { const timeout = options?.timeout ?? DEFAULT_REQUEST_TIMEOUT_MSEC; const timeoutHandler = () => cancel(new SdkError(SdkErrorCode.RequestTimeout, "Request timed out", { timeout })); this._setupTimeout(messageId, timeout, options?.maxTotalTimeout, timeoutHandler, options?.resetTimeoutOnProgress ?? false); diff --git a/patches/README.md b/patches/README.md index 7df8b0e1faf..e41dd37b734 100644 --- a/patches/README.md +++ b/patches/README.md @@ -130,7 +130,7 @@ Before upgrading Zod, re-verify allocation handoff, reentrant parsing, and cycle identity against the new memoizer and container implementations. The Runtime `zod-recursive-contract.test.ts` suite covers both shipped entry points. -## `@modelcontextprotocol/client@2.1.0` +## `@modelcontextprotocol/client@2.2.0` Pending transport sends retain settled request arguments and results through error observers, even after response, abort, timeout, or connection close. From 18026b45051f95f90ca22ad0d3d29d7a79cdd7b9 Mon Sep 17 00:00:00 2001 From: 404ARE <936233544@qq.com> Date: Thu, 8 Oct 2026 17:42:04 +0800 Subject: [PATCH 2/2] fix(release): update MCP patch source license inventory Generated-by: OpenAI Codex --- LICENSE | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/LICENSE b/LICENSE index 1f4a4c95c4f..cfff851951a 100644 --- a/LICENSE +++ b/LICENSE @@ -385,10 +385,10 @@ SOFTWARE. Model Context Protocol client dependency patch -Source: https://www.npmjs.com/package/@modelcontextprotocol/client/v/2.1.0 +Source: https://www.npmjs.com/package/@modelcontextprotocol/client/v/2.2.0 Repository: https://github.com/modelcontextprotocol/typescript-sdk -Version: 2.1.0 -Dependency patch: patches/@modelcontextprotocol+client+2.1.0.patch +Version: 2.2.0 +Dependency patch: patches/@modelcontextprotocol+client+2.2.0.patch Copyright (c) 2024-2025 Model Context Protocol a Series of LF Projects, LLC. Declared package license: MIT