@slashfi/agents-sdk 0.90.2 → 0.90.5
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/dist/cjs/config-store.js +294 -54
- package/dist/cjs/config-store.js.map +1 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/mcp-client.js +77 -24
- package/dist/cjs/mcp-client.js.map +1 -1
- package/dist/config-store.d.ts +7 -0
- package/dist/config-store.d.ts.map +1 -1
- package/dist/config-store.js +294 -54
- package/dist/config-store.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp-client.d.ts +5 -2
- package/dist/mcp-client.d.ts.map +1 -1
- package/dist/mcp-client.js +77 -24
- package/dist/mcp-client.js.map +1 -1
- package/package.json +1 -1
- package/src/config-store.test.ts +385 -0
- package/src/config-store.ts +408 -74
- package/src/index.ts +4 -1
- package/src/mcp-client.test.ts +80 -0
- package/src/mcp-client.ts +114 -31
package/dist/cjs/config-store.js
CHANGED
|
@@ -480,6 +480,159 @@ function createAdk(fs, options = {}) {
|
|
|
480
480
|
});
|
|
481
481
|
};
|
|
482
482
|
}
|
|
483
|
+
/**
|
|
484
|
+
* Call-time credential lookup: stored ref config first, then the host
|
|
485
|
+
* `resolveCredentials` callback. Does not persist resolved values.
|
|
486
|
+
*/
|
|
487
|
+
async function resolveCallCredential(ctx, field) {
|
|
488
|
+
const stored = await readRefSecret(ctx.name, field);
|
|
489
|
+
if (stored)
|
|
490
|
+
return stored;
|
|
491
|
+
return makeTryResolve(ctx)(field);
|
|
492
|
+
}
|
|
493
|
+
const CALL_BEARER_FIELDS = ["access_token", "api_key", "token"];
|
|
494
|
+
function isBearerAuthField(field) {
|
|
495
|
+
return CALL_BEARER_FIELDS.includes(field);
|
|
496
|
+
}
|
|
497
|
+
/** Legacy cache entries may omit `outbound`; these are never call-time creds. */
|
|
498
|
+
const LEGACY_CONNECT_ONLY_FIELDS = new Set([
|
|
499
|
+
"client_id",
|
|
500
|
+
"client_secret",
|
|
501
|
+
"refresh_token",
|
|
502
|
+
]);
|
|
503
|
+
function isCallOutboundAuthField(field, info) {
|
|
504
|
+
if (info.outbound === false)
|
|
505
|
+
return false;
|
|
506
|
+
if (info.outbound === true)
|
|
507
|
+
return true;
|
|
508
|
+
return !LEGACY_CONNECT_ONLY_FIELDS.has(field);
|
|
509
|
+
}
|
|
510
|
+
function readRegistryDeclaredAuthFields(security) {
|
|
511
|
+
if (!security || typeof security !== "object")
|
|
512
|
+
return undefined;
|
|
513
|
+
const raw = security.authFields;
|
|
514
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw))
|
|
515
|
+
return undefined;
|
|
516
|
+
const out = {};
|
|
517
|
+
for (const [field, meta] of Object.entries(raw)) {
|
|
518
|
+
if (!meta || typeof meta !== "object" || Array.isArray(meta))
|
|
519
|
+
continue;
|
|
520
|
+
const m = meta;
|
|
521
|
+
if (typeof m.required !== "boolean" || typeof m.automated !== "boolean") {
|
|
522
|
+
continue;
|
|
523
|
+
}
|
|
524
|
+
out[field] = { required: m.required, automated: m.automated };
|
|
525
|
+
if (typeof m.outbound === "boolean") {
|
|
526
|
+
out[field].outbound = m.outbound;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
return Object.keys(out).length > 0 ? out : undefined;
|
|
530
|
+
}
|
|
531
|
+
async function mergeRegistryDeclaredAuthFields(fields, declared, canResolve, configKeys, refConfig) {
|
|
532
|
+
if (!declared)
|
|
533
|
+
return fields;
|
|
534
|
+
const next = {};
|
|
535
|
+
for (const [field, meta] of Object.entries(declared)) {
|
|
536
|
+
next[field] = {
|
|
537
|
+
required: meta.required,
|
|
538
|
+
automated: meta.automated,
|
|
539
|
+
present: configKeys.includes(field) || hasCredentialField(refConfig, field),
|
|
540
|
+
resolvable: await canResolve(field),
|
|
541
|
+
...(meta.format && { format: meta.format }),
|
|
542
|
+
...(meta.parts && { parts: meta.parts }),
|
|
543
|
+
...(meta.outbound === false && { outbound: false }),
|
|
544
|
+
};
|
|
545
|
+
}
|
|
546
|
+
return next;
|
|
547
|
+
}
|
|
548
|
+
function bearerFieldSatisfied(accessToken, refConfig, field) {
|
|
549
|
+
if (accessToken)
|
|
550
|
+
return true;
|
|
551
|
+
return hasCredentialField(refConfig, field);
|
|
552
|
+
}
|
|
553
|
+
function fallbackCallAuthFields() {
|
|
554
|
+
return {
|
|
555
|
+
access_token: { required: true, automated: true },
|
|
556
|
+
api_key: { required: false, automated: true },
|
|
557
|
+
token: { required: false, automated: true },
|
|
558
|
+
};
|
|
559
|
+
}
|
|
560
|
+
function headerFieldSatisfied(headers, field) {
|
|
561
|
+
const wanted = normalizeCredentialKey(field);
|
|
562
|
+
return Object.keys(headers).some((key) => normalizeCredentialKey(key) === wanted);
|
|
563
|
+
}
|
|
564
|
+
function resolveHeaderNameForField(field, refConfig) {
|
|
565
|
+
const wanted = normalizeCredentialKey(field);
|
|
566
|
+
const configHeaders = refConfig.headers;
|
|
567
|
+
if (configHeaders &&
|
|
568
|
+
typeof configHeaders === "object" &&
|
|
569
|
+
!Array.isArray(configHeaders)) {
|
|
570
|
+
for (const key of Object.keys(configHeaders)) {
|
|
571
|
+
if (normalizeCredentialKey(key) === wanted)
|
|
572
|
+
return key;
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
// x_api_key → X-API-KEY (registry codegen declares the canonical name;
|
|
576
|
+
// env-resolved keys use the normalized storage field name).
|
|
577
|
+
return field
|
|
578
|
+
.split("_")
|
|
579
|
+
.filter(Boolean)
|
|
580
|
+
.map((part) => part.toUpperCase())
|
|
581
|
+
.join("-");
|
|
582
|
+
}
|
|
583
|
+
/**
|
|
584
|
+
* Supplement call-time credentials from `resolveCredentials` when they
|
|
585
|
+
* are not already present in consumer-config. Stored values and config
|
|
586
|
+
* headers win — this only fills gaps. Walks cached `authFields` as the
|
|
587
|
+
* source of truth (registry-declared when auth-status has run).
|
|
588
|
+
*/
|
|
589
|
+
async function resolveAllCallCredentials(opts) {
|
|
590
|
+
if (!options.resolveCredentials) {
|
|
591
|
+
return {
|
|
592
|
+
accessToken: opts.accessToken,
|
|
593
|
+
resolvedHeaders: opts.resolvedHeaders,
|
|
594
|
+
};
|
|
595
|
+
}
|
|
596
|
+
let accessToken = opts.accessToken;
|
|
597
|
+
let resolvedHeaders = opts.resolvedHeaders;
|
|
598
|
+
const { ctx, refConfig } = opts;
|
|
599
|
+
const cache = await readRegistryCache();
|
|
600
|
+
const authFields = cache.refs[ctx.name]?.authFields ?? fallbackCallAuthFields();
|
|
601
|
+
for (const [field, info] of Object.entries(authFields)) {
|
|
602
|
+
if (!isCallOutboundAuthField(field, info))
|
|
603
|
+
continue;
|
|
604
|
+
if (!info.required && !info.automated)
|
|
605
|
+
continue;
|
|
606
|
+
if (isBearerAuthField(field)) {
|
|
607
|
+
if (bearerFieldSatisfied(accessToken, refConfig, field))
|
|
608
|
+
continue;
|
|
609
|
+
const value = await resolveCallCredential(ctx, field);
|
|
610
|
+
if (value)
|
|
611
|
+
accessToken = accessToken ?? value;
|
|
612
|
+
continue;
|
|
613
|
+
}
|
|
614
|
+
if (hasCredentialField(refConfig, field))
|
|
615
|
+
continue;
|
|
616
|
+
if (resolvedHeaders && headerFieldSatisfied(resolvedHeaders, field)) {
|
|
617
|
+
continue;
|
|
618
|
+
}
|
|
619
|
+
const value = await resolveCallCredential(ctx, field);
|
|
620
|
+
if (!value)
|
|
621
|
+
continue;
|
|
622
|
+
resolvedHeaders = resolvedHeaders ?? {};
|
|
623
|
+
if (!headerFieldSatisfied(resolvedHeaders, field)) {
|
|
624
|
+
resolvedHeaders[resolveHeaderNameForField(field, refConfig)] = value;
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
if (!accessToken) {
|
|
628
|
+
const username = await resolveCallCredential(ctx, "username");
|
|
629
|
+
const password = await resolveCallCredential(ctx, "password");
|
|
630
|
+
if (username && password) {
|
|
631
|
+
accessToken = btoa(`${username}:${password}`);
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
return { accessToken, resolvedHeaders };
|
|
635
|
+
}
|
|
483
636
|
/**
|
|
484
637
|
* Resolve OAuth client credentials (client_id + client_secret) for a
|
|
485
638
|
* ref. Walks: `resolveCredentials` callback → per-ref VCS storage.
|
|
@@ -671,6 +824,79 @@ function createAdk(fs, options = {}) {
|
|
|
671
824
|
return null;
|
|
672
825
|
}
|
|
673
826
|
}
|
|
827
|
+
/**
|
|
828
|
+
* Resolve OAuth server metadata from a registry security scheme.
|
|
829
|
+
* Shared by `ref.auth` and `ref.refreshToken` so both paths discover
|
|
830
|
+
* token endpoints the same way — explicit manifest URLs, RFC 8414
|
|
831
|
+
* discovery via `discoveryUrl`, authorization-server discovery, and
|
|
832
|
+
* finally the MCP upstream URL for redirect-mode agents.
|
|
833
|
+
*/
|
|
834
|
+
async function resolveOAuthMetadataFromSecurity(security, opts) {
|
|
835
|
+
if (!security || security.type !== "oauth2")
|
|
836
|
+
return null;
|
|
837
|
+
const securityExt = security;
|
|
838
|
+
const authCodeFlow = securityExt.flows?.authorizationCode;
|
|
839
|
+
const explicitEndpoint = authCodeFlow?.refreshUrl ?? authCodeFlow?.tokenUrl;
|
|
840
|
+
if (explicitEndpoint) {
|
|
841
|
+
const flowScopes = authCodeFlow
|
|
842
|
+
?.scopes;
|
|
843
|
+
const authUrl = authCodeFlow?.authorizationUrl;
|
|
844
|
+
return {
|
|
845
|
+
issuer: authUrl
|
|
846
|
+
? new URL(authUrl).origin
|
|
847
|
+
: new URL(explicitEndpoint).origin,
|
|
848
|
+
authorization_endpoint: authUrl ?? explicitEndpoint,
|
|
849
|
+
token_endpoint: explicitEndpoint,
|
|
850
|
+
scopes_supported: flowScopes ? Object.keys(flowScopes) : undefined,
|
|
851
|
+
};
|
|
852
|
+
}
|
|
853
|
+
if (securityExt.discoveryUrl) {
|
|
854
|
+
const fromDiscovery = (await tryFetchOAuthMetadata(securityExt.discoveryUrl)) ??
|
|
855
|
+
(await (0, mcp_client_js_1.discoverOAuthMetadata)(securityExt.discoveryUrl));
|
|
856
|
+
if (fromDiscovery)
|
|
857
|
+
return fromDiscovery;
|
|
858
|
+
}
|
|
859
|
+
const authUrl = authCodeFlow?.authorizationUrl;
|
|
860
|
+
if (authUrl) {
|
|
861
|
+
let metadata = await tryFetchOAuthMetadata(authUrl);
|
|
862
|
+
if (!metadata) {
|
|
863
|
+
metadata = await (0, mcp_client_js_1.discoverOAuthMetadata)(new URL(authUrl).origin);
|
|
864
|
+
}
|
|
865
|
+
if (metadata)
|
|
866
|
+
return metadata;
|
|
867
|
+
}
|
|
868
|
+
const serverUrl = opts?.serverUrl;
|
|
869
|
+
if (serverUrl) {
|
|
870
|
+
let metadata = await (0, mcp_client_js_1.discoverOAuthMetadata)(serverUrl);
|
|
871
|
+
if (!metadata) {
|
|
872
|
+
metadata = await (0, mcp_client_js_1.discoverOAuthMetadata)(serverUrl.replace(/\/(mcp|sse)$/, ""));
|
|
873
|
+
}
|
|
874
|
+
if (metadata)
|
|
875
|
+
return metadata;
|
|
876
|
+
}
|
|
877
|
+
return null;
|
|
878
|
+
}
|
|
879
|
+
function resolveClientAuthMethod(security, metadata) {
|
|
880
|
+
const flowAuth = security.flows?.authorizationCode?.clientAuth;
|
|
881
|
+
if (flowAuth)
|
|
882
|
+
return flowAuth;
|
|
883
|
+
const supported = metadata?.token_endpoint_auth_methods_supported;
|
|
884
|
+
if (supported?.length === 1 && supported[0] === "client_secret_basic") {
|
|
885
|
+
return "client_secret_basic";
|
|
886
|
+
}
|
|
887
|
+
const tokenEndpoint = metadata?.token_endpoint;
|
|
888
|
+
if (tokenEndpoint) {
|
|
889
|
+
try {
|
|
890
|
+
if (new URL(tokenEndpoint).hostname === "api.x.com") {
|
|
891
|
+
return "client_secret_basic";
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
catch {
|
|
895
|
+
/* ignore malformed token endpoint */
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
return "client_secret_post";
|
|
899
|
+
}
|
|
674
900
|
/**
|
|
675
901
|
* Build a registryConsumer from the current config.
|
|
676
902
|
* Decrypts secret: values in registry headers/auth before connecting.
|
|
@@ -771,7 +997,8 @@ function createAdk(fs, options = {}) {
|
|
|
771
997
|
if (!found)
|
|
772
998
|
return false;
|
|
773
999
|
for (const r of registries) {
|
|
774
|
-
if (typeof r !== "string" &&
|
|
1000
|
+
if (typeof r !== "string" &&
|
|
1001
|
+
(registryDisplayName(r) === nameOrUrl || registryUrl(r) === nameOrUrl)) {
|
|
775
1002
|
await mutate(r);
|
|
776
1003
|
}
|
|
777
1004
|
}
|
|
@@ -1542,7 +1769,7 @@ function createAdk(fs, options = {}) {
|
|
|
1542
1769
|
const entry = findRef(config.refs ?? [], name);
|
|
1543
1770
|
if (!entry)
|
|
1544
1771
|
throw new Error(`Ref "${name}" not found`);
|
|
1545
|
-
|
|
1772
|
+
let accessToken = (await readRefSecret(name, "access_token")) ??
|
|
1546
1773
|
(await readRefSecret(name, "api_key")) ??
|
|
1547
1774
|
(await readRefSecret(name, "token"));
|
|
1548
1775
|
// Resolve custom headers from config (e.g. { "X-API-Key": "secret:..." })
|
|
@@ -1589,6 +1816,16 @@ function createAdk(fs, options = {}) {
|
|
|
1589
1816
|
}
|
|
1590
1817
|
}
|
|
1591
1818
|
}
|
|
1819
|
+
if (options.resolveCredentials) {
|
|
1820
|
+
const supplemented = await resolveAllCallCredentials({
|
|
1821
|
+
ctx: { name, entry, security: null },
|
|
1822
|
+
refConfig,
|
|
1823
|
+
accessToken,
|
|
1824
|
+
resolvedHeaders,
|
|
1825
|
+
});
|
|
1826
|
+
accessToken = supplemented.accessToken;
|
|
1827
|
+
resolvedHeaders = supplemented.resolvedHeaders;
|
|
1828
|
+
}
|
|
1592
1829
|
const doCall = async (token) => {
|
|
1593
1830
|
// Direct MCP only for redirect/proxy agents with an MCP upstream.
|
|
1594
1831
|
// API-mode agents must go through the registry (it does REST translation).
|
|
@@ -1700,7 +1937,7 @@ function createAdk(fs, options = {}) {
|
|
|
1700
1937
|
async function canResolve(field, oauthMetadata) {
|
|
1701
1938
|
return (await tryResolveField(field, oauthMetadata)) !== null;
|
|
1702
1939
|
}
|
|
1703
|
-
|
|
1940
|
+
let fields = {};
|
|
1704
1941
|
if (security.type === "oauth2") {
|
|
1705
1942
|
const securityExt = security;
|
|
1706
1943
|
const hasRegistration = !!securityExt.dynamicRegistration;
|
|
@@ -1734,6 +1971,7 @@ function createAdk(fs, options = {}) {
|
|
|
1734
1971
|
automated: hasRegistration,
|
|
1735
1972
|
present: configKeys.includes("client_id"),
|
|
1736
1973
|
resolvable: await canResolve("client_id", oauthMetadata),
|
|
1974
|
+
outbound: false,
|
|
1737
1975
|
};
|
|
1738
1976
|
if (needsSecret) {
|
|
1739
1977
|
fields.client_secret = {
|
|
@@ -1741,13 +1979,14 @@ function createAdk(fs, options = {}) {
|
|
|
1741
1979
|
automated: hasRegistration,
|
|
1742
1980
|
present: configKeys.includes("client_secret"),
|
|
1743
1981
|
resolvable: await canResolve("client_secret", oauthMetadata),
|
|
1982
|
+
outbound: false,
|
|
1744
1983
|
};
|
|
1745
1984
|
}
|
|
1746
1985
|
fields.access_token = {
|
|
1747
1986
|
required: true,
|
|
1748
1987
|
automated: accessTokenAutomated,
|
|
1749
1988
|
present: configKeys.includes("access_token"),
|
|
1750
|
-
resolvable:
|
|
1989
|
+
resolvable: await canResolve("access_token"),
|
|
1751
1990
|
};
|
|
1752
1991
|
}
|
|
1753
1992
|
else if (security.type === "apiKey") {
|
|
@@ -1804,7 +2043,12 @@ function createAdk(fs, options = {}) {
|
|
|
1804
2043
|
format: "basic",
|
|
1805
2044
|
parts: [
|
|
1806
2045
|
{ name: "username", label: "Username", secret: false },
|
|
1807
|
-
{
|
|
2046
|
+
{
|
|
2047
|
+
name: "password",
|
|
2048
|
+
label: "Password",
|
|
2049
|
+
secret: true,
|
|
2050
|
+
optional: true,
|
|
2051
|
+
},
|
|
1808
2052
|
],
|
|
1809
2053
|
}),
|
|
1810
2054
|
};
|
|
@@ -1825,7 +2069,8 @@ function createAdk(fs, options = {}) {
|
|
|
1825
2069
|
resolvable: await canResolve("access_token"),
|
|
1826
2070
|
};
|
|
1827
2071
|
}
|
|
1828
|
-
|
|
2072
|
+
fields = await mergeRegistryDeclaredAuthFields(fields, readRegistryDeclaredAuthFields(security), canResolve, configKeys, (entry.config ?? {}));
|
|
2073
|
+
const complete = Object.values(fields).every((f) => !f.required || f.automated || f.present || f.resolvable);
|
|
1829
2074
|
// Persist the slim {required, automated} per-field shape into the
|
|
1830
2075
|
// registry cache so `isRefAuthComplete` can answer subsequent
|
|
1831
2076
|
// host-side "is this ref ready?" checks without re-fetching the
|
|
@@ -1839,6 +2084,7 @@ function createAdk(fs, options = {}) {
|
|
|
1839
2084
|
automated: info.automated,
|
|
1840
2085
|
...(info.format && { format: info.format }),
|
|
1841
2086
|
...(info.parts && { parts: info.parts }),
|
|
2087
|
+
...(info.outbound === false && { outbound: false }),
|
|
1842
2088
|
};
|
|
1843
2089
|
}
|
|
1844
2090
|
await upsertRegistryCacheAuthFields(name, entry.ref, authFields);
|
|
@@ -1936,7 +2182,9 @@ function createAdk(fs, options = {}) {
|
|
|
1936
2182
|
const isBasic = httpSec.scheme === "basic";
|
|
1937
2183
|
if (isBasic) {
|
|
1938
2184
|
const username = opts?.credentials?.["username"] ?? (await tryResolve("username"));
|
|
1939
|
-
const password = opts?.credentials?.["password"] ??
|
|
2185
|
+
const password = opts?.credentials?.["password"] ??
|
|
2186
|
+
(await tryResolve("password")) ??
|
|
2187
|
+
"";
|
|
1940
2188
|
const hasUsername = username !== undefined && username !== null && username !== "";
|
|
1941
2189
|
if (!hasUsername) {
|
|
1942
2190
|
return {
|
|
@@ -1985,21 +2233,9 @@ function createAdk(fs, options = {}) {
|
|
|
1985
2233
|
};
|
|
1986
2234
|
}
|
|
1987
2235
|
const authUrl = authCodeFlow.authorizationUrl;
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
metadata = await (0, mcp_client_js_1.discoverOAuthMetadata)(origin);
|
|
1992
|
-
}
|
|
1993
|
-
// Fallback: construct metadata from the security scheme's explicit URLs
|
|
1994
|
-
if (!metadata && authCodeFlow.tokenUrl) {
|
|
1995
|
-
const flowScopes = authCodeFlow.scopes;
|
|
1996
|
-
metadata = {
|
|
1997
|
-
issuer: new URL(authUrl).origin,
|
|
1998
|
-
authorization_endpoint: authUrl,
|
|
1999
|
-
token_endpoint: authCodeFlow.tokenUrl,
|
|
2000
|
-
scopes_supported: flowScopes ? Object.keys(flowScopes) : undefined,
|
|
2001
|
-
};
|
|
2002
|
-
}
|
|
2236
|
+
const metadata = await resolveOAuthMetadataFromSecurity(security, {
|
|
2237
|
+
serverUrl: entry.url,
|
|
2238
|
+
});
|
|
2003
2239
|
if (!metadata) {
|
|
2004
2240
|
throw new Error(`Could not discover OAuth metadata from ${authUrl}`);
|
|
2005
2241
|
}
|
|
@@ -2087,11 +2323,13 @@ function createAdk(fs, options = {}) {
|
|
|
2087
2323
|
extraParams: authorizationParams,
|
|
2088
2324
|
});
|
|
2089
2325
|
// Persist pending state so handleCallback works across processes
|
|
2326
|
+
const clientAuthMethod = resolveClientAuthMethod(security, metadata);
|
|
2090
2327
|
await storePendingOAuth(state, {
|
|
2091
2328
|
refName: name,
|
|
2092
2329
|
codeVerifier,
|
|
2093
2330
|
clientId,
|
|
2094
2331
|
clientSecret,
|
|
2332
|
+
clientAuthMethod,
|
|
2095
2333
|
tokenEndpoint: metadata.token_endpoint,
|
|
2096
2334
|
redirectUri,
|
|
2097
2335
|
createdAt: Date.now(),
|
|
@@ -2227,43 +2465,43 @@ function createAdk(fs, options = {}) {
|
|
|
2227
2465
|
return null;
|
|
2228
2466
|
const status = await ref.authStatus(name);
|
|
2229
2467
|
const security = status.security;
|
|
2230
|
-
const
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
const
|
|
2234
|
-
|
|
2235
|
-
if (!tokenUrl)
|
|
2468
|
+
const metadata = await resolveOAuthMetadataFromSecurity(security, {
|
|
2469
|
+
serverUrl: entry.url,
|
|
2470
|
+
});
|
|
2471
|
+
const tokenEndpoint = metadata?.token_endpoint;
|
|
2472
|
+
if (!tokenEndpoint)
|
|
2236
2473
|
return null;
|
|
2237
|
-
const oauthClient = await resolveOAuthClient({
|
|
2474
|
+
const oauthClient = await resolveOAuthClient({
|
|
2475
|
+
name,
|
|
2476
|
+
entry,
|
|
2477
|
+
security,
|
|
2478
|
+
metadata,
|
|
2479
|
+
});
|
|
2238
2480
|
if (!oauthClient)
|
|
2239
2481
|
return null;
|
|
2240
|
-
const
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2482
|
+
const clientAuthMethod = resolveClientAuthMethod(security, metadata);
|
|
2483
|
+
const fetchFn = options.fetch ?? globalThis.fetch;
|
|
2484
|
+
let tokens;
|
|
2485
|
+
try {
|
|
2486
|
+
tokens = await (0, mcp_client_js_1.refreshAccessToken)(tokenEndpoint, {
|
|
2487
|
+
refreshToken,
|
|
2488
|
+
clientId: oauthClient.clientId,
|
|
2489
|
+
clientSecret: oauthClient.clientSecret,
|
|
2490
|
+
clientAuthMethod,
|
|
2491
|
+
}, fetchFn);
|
|
2249
2492
|
}
|
|
2250
|
-
|
|
2251
|
-
method: "POST",
|
|
2252
|
-
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
2253
|
-
body: body.toString(),
|
|
2254
|
-
});
|
|
2255
|
-
if (!res.ok)
|
|
2256
|
-
return null;
|
|
2257
|
-
const data = (await res.json());
|
|
2258
|
-
const newAccessToken = data.access_token;
|
|
2259
|
-
if (!newAccessToken)
|
|
2493
|
+
catch {
|
|
2260
2494
|
return null;
|
|
2261
|
-
// Store the new tokens
|
|
2262
|
-
await storeRefSecret(name, "access_token", newAccessToken);
|
|
2263
|
-
if (data.refresh_token && typeof data.refresh_token === "string") {
|
|
2264
|
-
await storeRefSecret(name, "refresh_token", data.refresh_token);
|
|
2265
2495
|
}
|
|
2266
|
-
|
|
2496
|
+
await storeRefSecret(name, "access_token", tokens.accessToken);
|
|
2497
|
+
if (tokens.refreshToken) {
|
|
2498
|
+
await storeRefSecret(name, "refresh_token", tokens.refreshToken);
|
|
2499
|
+
}
|
|
2500
|
+
if (tokens.expiresIn) {
|
|
2501
|
+
const expiresAt = new Date(Date.now() + tokens.expiresIn * 1000).toISOString();
|
|
2502
|
+
await storeRefSecret(name, "expires_at", expiresAt);
|
|
2503
|
+
}
|
|
2504
|
+
return { accessToken: tokens.accessToken };
|
|
2267
2505
|
},
|
|
2268
2506
|
};
|
|
2269
2507
|
// ==========================================
|
|
@@ -2274,13 +2512,15 @@ function createAdk(fs, options = {}) {
|
|
|
2274
2512
|
if (!pending) {
|
|
2275
2513
|
throw new Error(`No pending OAuth flow for state "${params.state}".`);
|
|
2276
2514
|
}
|
|
2515
|
+
const fetchFn = options.fetch ?? globalThis.fetch;
|
|
2277
2516
|
const tokens = await (0, mcp_client_js_1.exchangeCodeForTokens)(pending.tokenEndpoint, {
|
|
2278
2517
|
code: params.code,
|
|
2279
2518
|
codeVerifier: pending.codeVerifier,
|
|
2280
2519
|
clientId: pending.clientId,
|
|
2281
2520
|
clientSecret: pending.clientSecret,
|
|
2282
2521
|
redirectUri: pending.redirectUri,
|
|
2283
|
-
|
|
2522
|
+
clientAuthMethod: pending.clientAuthMethod,
|
|
2523
|
+
}, fetchFn);
|
|
2284
2524
|
await storeRefSecret(pending.refName, "access_token", tokens.accessToken);
|
|
2285
2525
|
if (tokens.refreshToken) {
|
|
2286
2526
|
await storeRefSecret(pending.refName, "refresh_token", tokens.refreshToken);
|