@ai-sdk/mcp 1.0.48 → 1.0.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/dist/index.js +43 -16
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +43 -16
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
- package/src/tool/mcp-client.ts +4 -1
- package/src/tool/mcp-sse-transport.ts +13 -3
- package/src/tool/oauth.ts +30 -4
package/dist/index.mjs
CHANGED
|
@@ -692,15 +692,18 @@ async function discoverOAuthProtectedResourceMetadata(serverUrl, opts, fetchFn =
|
|
|
692
692
|
function buildDiscoveryUrls(authorizationServerUrl) {
|
|
693
693
|
const url = typeof authorizationServerUrl === "string" ? new URL(authorizationServerUrl) : authorizationServerUrl;
|
|
694
694
|
const hasPath = url.pathname !== "/";
|
|
695
|
+
const rootIssuer = url.origin;
|
|
695
696
|
const urlsToTry = [];
|
|
696
697
|
if (!hasPath) {
|
|
697
698
|
urlsToTry.push({
|
|
698
699
|
url: new URL("/.well-known/oauth-authorization-server", url.origin),
|
|
699
|
-
type: "oauth"
|
|
700
|
+
type: "oauth",
|
|
701
|
+
expectedIssuer: rootIssuer
|
|
700
702
|
});
|
|
701
703
|
urlsToTry.push({
|
|
702
704
|
url: new URL("/.well-known/openid-configuration", url.origin),
|
|
703
|
-
type: "oidc"
|
|
705
|
+
type: "oidc",
|
|
706
|
+
expectedIssuer: rootIssuer
|
|
704
707
|
});
|
|
705
708
|
return urlsToTry;
|
|
706
709
|
}
|
|
@@ -708,27 +711,39 @@ function buildDiscoveryUrls(authorizationServerUrl) {
|
|
|
708
711
|
if (pathname.endsWith("/")) {
|
|
709
712
|
pathname = pathname.slice(0, -1);
|
|
710
713
|
}
|
|
714
|
+
const pathIssuer = `${url.origin}${pathname}`;
|
|
711
715
|
urlsToTry.push({
|
|
712
716
|
url: new URL(
|
|
713
717
|
`/.well-known/oauth-authorization-server${pathname}`,
|
|
714
718
|
url.origin
|
|
715
719
|
),
|
|
716
|
-
type: "oauth"
|
|
720
|
+
type: "oauth",
|
|
721
|
+
expectedIssuer: pathIssuer
|
|
717
722
|
});
|
|
718
723
|
urlsToTry.push({
|
|
719
724
|
url: new URL("/.well-known/oauth-authorization-server", url.origin),
|
|
720
|
-
type: "oauth"
|
|
725
|
+
type: "oauth",
|
|
726
|
+
expectedIssuer: rootIssuer
|
|
721
727
|
});
|
|
722
728
|
urlsToTry.push({
|
|
723
729
|
url: new URL(`/.well-known/openid-configuration${pathname}`, url.origin),
|
|
724
|
-
type: "oidc"
|
|
730
|
+
type: "oidc",
|
|
731
|
+
expectedIssuer: pathIssuer
|
|
725
732
|
});
|
|
726
733
|
urlsToTry.push({
|
|
727
734
|
url: new URL(`${pathname}/.well-known/openid-configuration`, url.origin),
|
|
728
|
-
type: "oidc"
|
|
735
|
+
type: "oidc",
|
|
736
|
+
expectedIssuer: pathIssuer
|
|
729
737
|
});
|
|
730
738
|
return urlsToTry;
|
|
731
739
|
}
|
|
740
|
+
function assertMetadataIssuerMatches(metadata, expectedIssuer) {
|
|
741
|
+
if (metadata.issuer !== expectedIssuer) {
|
|
742
|
+
throw new MCPClientOAuthError({
|
|
743
|
+
message: `OAuth authorization server metadata issuer ${metadata.issuer} does not match expected issuer ${expectedIssuer}`
|
|
744
|
+
});
|
|
745
|
+
}
|
|
746
|
+
}
|
|
732
747
|
async function discoverAuthorizationServerMetadata(authorizationServerUrl, {
|
|
733
748
|
fetchFn = fetch,
|
|
734
749
|
protocolVersion = LATEST_PROTOCOL_VERSION
|
|
@@ -736,7 +751,7 @@ async function discoverAuthorizationServerMetadata(authorizationServerUrl, {
|
|
|
736
751
|
var _a3;
|
|
737
752
|
const headers = { "MCP-Protocol-Version": protocolVersion };
|
|
738
753
|
const urlsToTry = buildDiscoveryUrls(authorizationServerUrl);
|
|
739
|
-
for (const { url: endpointUrl, type } of urlsToTry) {
|
|
754
|
+
for (const { url: endpointUrl, type, expectedIssuer } of urlsToTry) {
|
|
740
755
|
const response = await fetchWithCorsRetry(endpointUrl, headers, fetchFn);
|
|
741
756
|
if (!response) {
|
|
742
757
|
continue;
|
|
@@ -750,11 +765,14 @@ async function discoverAuthorizationServerMetadata(authorizationServerUrl, {
|
|
|
750
765
|
);
|
|
751
766
|
}
|
|
752
767
|
if (type === "oauth") {
|
|
753
|
-
|
|
768
|
+
const metadata = OAuthMetadataSchema.parse(await response.json());
|
|
769
|
+
assertMetadataIssuerMatches(metadata, expectedIssuer);
|
|
770
|
+
return metadata;
|
|
754
771
|
} else {
|
|
755
772
|
const metadata = OpenIdProviderDiscoveryMetadataSchema.parse(
|
|
756
773
|
await response.json()
|
|
757
774
|
);
|
|
775
|
+
assertMetadataIssuerMatches(metadata, expectedIssuer);
|
|
758
776
|
if (!((_a3 = metadata.code_challenge_methods_supported) == null ? void 0 : _a3.includes("S256"))) {
|
|
759
777
|
throw new Error(
|
|
760
778
|
`Incompatible OIDC provider at ${endpointUrl}: does not support S256 code challenge method required by MCP specification`
|
|
@@ -1335,7 +1353,7 @@ var SseMCPTransport = class {
|
|
|
1335
1353
|
const stream = response.body.pipeThrough(new TextDecoderStream()).pipeThrough(new EventSourceParserStream());
|
|
1336
1354
|
const reader = stream.getReader();
|
|
1337
1355
|
const processEvents = async () => {
|
|
1338
|
-
var _a4, _b4, _c2;
|
|
1356
|
+
var _a4, _b4, _c2, _d2, _e2;
|
|
1339
1357
|
try {
|
|
1340
1358
|
while (true) {
|
|
1341
1359
|
const { done, value } = await reader.read();
|
|
@@ -1350,24 +1368,32 @@ var SseMCPTransport = class {
|
|
|
1350
1368
|
}
|
|
1351
1369
|
const { event, data } = value;
|
|
1352
1370
|
if (event === "endpoint") {
|
|
1353
|
-
|
|
1354
|
-
|
|
1371
|
+
if (this.endpoint) {
|
|
1372
|
+
continue;
|
|
1373
|
+
}
|
|
1374
|
+
const endpoint = new URL(data, this.url);
|
|
1375
|
+
if (endpoint.origin !== this.url.origin) {
|
|
1376
|
+
this.connected = false;
|
|
1377
|
+
this.endpoint = void 0;
|
|
1378
|
+
(_a4 = this.sseConnection) == null ? void 0 : _a4.close();
|
|
1379
|
+
(_b4 = this.abortController) == null ? void 0 : _b4.abort();
|
|
1355
1380
|
throw new MCPClientError({
|
|
1356
|
-
message: `MCP SSE Transport Error: Endpoint origin does not match connection origin: ${
|
|
1381
|
+
message: `MCP SSE Transport Error: Endpoint origin does not match connection origin: ${endpoint.origin}`
|
|
1357
1382
|
});
|
|
1358
1383
|
}
|
|
1384
|
+
this.endpoint = endpoint;
|
|
1359
1385
|
this.connected = true;
|
|
1360
1386
|
resolve();
|
|
1361
1387
|
} else if (event === "message") {
|
|
1362
1388
|
try {
|
|
1363
1389
|
const message = await parseJSONRPCMessage(data);
|
|
1364
|
-
(
|
|
1390
|
+
(_c2 = this.onmessage) == null ? void 0 : _c2.call(this, message);
|
|
1365
1391
|
} catch (error) {
|
|
1366
1392
|
const e = new MCPClientError({
|
|
1367
1393
|
message: "MCP SSE Transport Error: Failed to parse message",
|
|
1368
1394
|
cause: error
|
|
1369
1395
|
});
|
|
1370
|
-
(
|
|
1396
|
+
(_d2 = this.onerror) == null ? void 0 : _d2.call(this, e);
|
|
1371
1397
|
}
|
|
1372
1398
|
}
|
|
1373
1399
|
}
|
|
@@ -1375,7 +1401,7 @@ var SseMCPTransport = class {
|
|
|
1375
1401
|
if (error instanceof Error && error.name === "AbortError") {
|
|
1376
1402
|
return;
|
|
1377
1403
|
}
|
|
1378
|
-
(
|
|
1404
|
+
(_e2 = this.onerror) == null ? void 0 : _e2.call(this, error);
|
|
1379
1405
|
reject(error);
|
|
1380
1406
|
}
|
|
1381
1407
|
};
|
|
@@ -1397,6 +1423,7 @@ var SseMCPTransport = class {
|
|
|
1397
1423
|
async close() {
|
|
1398
1424
|
var _a3, _b3, _c;
|
|
1399
1425
|
this.connected = false;
|
|
1426
|
+
this.endpoint = void 0;
|
|
1400
1427
|
(_a3 = this.sseConnection) == null ? void 0 : _a3.close();
|
|
1401
1428
|
(_b3 = this.abortController) == null ? void 0 : _b3.abort();
|
|
1402
1429
|
(_c = this.onclose) == null ? void 0 : _c.call(this);
|
|
@@ -2173,7 +2200,7 @@ var DefaultMCPClient = class {
|
|
|
2173
2200
|
_meta
|
|
2174
2201
|
} of definitions.tools) {
|
|
2175
2202
|
const resolvedTitle = title != null ? title : annotations == null ? void 0 : annotations.title;
|
|
2176
|
-
if (schemas !== "automatic" && !(name3
|
|
2203
|
+
if (schemas !== "automatic" && !Object.prototype.hasOwnProperty.call(schemas, name3)) {
|
|
2177
2204
|
continue;
|
|
2178
2205
|
}
|
|
2179
2206
|
const self = this;
|