@modelcontextprotocol/inspector 2.10.1 → 2.11.0
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/clients/cli/build/index.js +3087 -2771
- package/clients/launcher/build/index.js +4 -1
- package/clients/mcpdo/build/{chunk-2E5EZYNU.js → chunk-O6RN6WMD.js} +362 -78
- package/clients/mcpdo/build/mcp-bin.js +7 -21
- package/clients/mcpdo/build/mcpdod.js +1 -1
- package/clients/tui/build/index.js +421 -119
- package/clients/web/build/index.js +148 -43
- package/clients/web/dist/assets/index-B79AqubU.js +1587 -0
- package/clients/web/dist/assets/{markdown-CZCm46w1.js → markdown-BlYcOtJg.js} +1 -1
- package/clients/web/dist/assets/{prism-light-B0A727v7.js → prism-light-J_CKjs7N.js} +2 -2
- package/clients/web/dist/index.html +1 -1
- package/package.json +14 -9
- package/scripts/install-clients.mjs +68 -28
- package/clients/web/dist/assets/index-DgDEc2gL.js +0 -1589
|
@@ -2707,6 +2707,84 @@ function isJsonDocumentResponse(contentType) {
|
|
|
2707
2707
|
const mediaType = contentType.split(";")[0].trim().toLowerCase();
|
|
2708
2708
|
return mediaType === "application/json" || mediaType.endsWith("+json");
|
|
2709
2709
|
}
|
|
2710
|
+
var SYNTHESIZED_METADATA_HEADER = "x-inspector-oauth-metadata-synthesized";
|
|
2711
|
+
var synthesizedResponses = /* @__PURE__ */ new WeakSet();
|
|
2712
|
+
function isSynthesizedMetadataResponse(response) {
|
|
2713
|
+
return synthesizedResponses.has(response);
|
|
2714
|
+
}
|
|
2715
|
+
var OIDC_WELL_KNOWN = "/.well-known/openid-configuration";
|
|
2716
|
+
var RFC8414_WELL_KNOWN = "/.well-known/oauth-authorization-server";
|
|
2717
|
+
function continuesDiscovery(status) {
|
|
2718
|
+
return status < 500 || status === 502;
|
|
2719
|
+
}
|
|
2720
|
+
function authorizationServerForFinalCandidate(url) {
|
|
2721
|
+
let parsed;
|
|
2722
|
+
try {
|
|
2723
|
+
parsed = new URL(url);
|
|
2724
|
+
} catch {
|
|
2725
|
+
return void 0;
|
|
2726
|
+
}
|
|
2727
|
+
const { pathname } = parsed;
|
|
2728
|
+
if (pathname === OIDC_WELL_KNOWN) return parsed.origin;
|
|
2729
|
+
if (!pathname.endsWith(OIDC_WELL_KNOWN)) return void 0;
|
|
2730
|
+
if (pathname.startsWith(`${RFC8414_WELL_KNOWN}/`) || pathname.startsWith(`${OIDC_WELL_KNOWN}/`)) {
|
|
2731
|
+
return void 0;
|
|
2732
|
+
}
|
|
2733
|
+
return `${parsed.origin}${pathname.slice(0, -OIDC_WELL_KNOWN.length)}`;
|
|
2734
|
+
}
|
|
2735
|
+
function synthesizeAuthorizationServerMetadata(issuer, overrides) {
|
|
2736
|
+
return {
|
|
2737
|
+
issuer,
|
|
2738
|
+
authorization_endpoint: overrides.authorizationUrl ?? new URL("/authorize", issuer).href,
|
|
2739
|
+
token_endpoint: overrides.tokenUrl ?? new URL("/token", issuer).href,
|
|
2740
|
+
registration_endpoint: new URL("/register", issuer).href,
|
|
2741
|
+
response_types_supported: ["code"],
|
|
2742
|
+
code_challenge_methods_supported: ["S256"]
|
|
2743
|
+
};
|
|
2744
|
+
}
|
|
2745
|
+
function requestMethodOf(input, init) {
|
|
2746
|
+
if (init?.method) return init.method.toUpperCase();
|
|
2747
|
+
if (typeof input !== "string" && !(input instanceof URL)) {
|
|
2748
|
+
return input.method.toUpperCase();
|
|
2749
|
+
}
|
|
2750
|
+
return "GET";
|
|
2751
|
+
}
|
|
2752
|
+
function acceptsJson(input, init) {
|
|
2753
|
+
let accept = null;
|
|
2754
|
+
if (init?.headers) {
|
|
2755
|
+
accept = new Headers(init.headers).get("accept");
|
|
2756
|
+
} else if (typeof input !== "string" && !(input instanceof URL)) {
|
|
2757
|
+
accept = input.headers.get("accept");
|
|
2758
|
+
}
|
|
2759
|
+
if (!accept) return false;
|
|
2760
|
+
const mediaTypes = accept.split(",").map((part) => part.split(";")[0].trim().toLowerCase());
|
|
2761
|
+
return mediaTypes.includes("application/json") && !mediaTypes.includes("text/event-stream");
|
|
2762
|
+
}
|
|
2763
|
+
function synthesizedMetadataResponse(input, init, response, overrides) {
|
|
2764
|
+
if (!continuesDiscovery(response.status)) return void 0;
|
|
2765
|
+
if (requestMethodOf(input, init) !== "GET") return void 0;
|
|
2766
|
+
if (!acceptsJson(input, init)) return void 0;
|
|
2767
|
+
const issuer = authorizationServerForFinalCandidate(requestUrlOf(input));
|
|
2768
|
+
if (!issuer) return void 0;
|
|
2769
|
+
void response.body?.cancel().catch(() => {
|
|
2770
|
+
});
|
|
2771
|
+
console.warn(
|
|
2772
|
+
`[oauth] ${issuer} publishes no authorization server metadata; using the configured endpoint override(s) in place of the SDK's /authorize and /token fallbacks.`
|
|
2773
|
+
);
|
|
2774
|
+
const synthesized = new Response(
|
|
2775
|
+
JSON.stringify(synthesizeAuthorizationServerMetadata(issuer, overrides)),
|
|
2776
|
+
{
|
|
2777
|
+
status: 200,
|
|
2778
|
+
statusText: "OK",
|
|
2779
|
+
headers: {
|
|
2780
|
+
"content-type": "application/json",
|
|
2781
|
+
[SYNTHESIZED_METADATA_HEADER]: "endpoint-overrides"
|
|
2782
|
+
}
|
|
2783
|
+
}
|
|
2784
|
+
);
|
|
2785
|
+
synthesizedResponses.add(synthesized);
|
|
2786
|
+
return synthesized;
|
|
2787
|
+
}
|
|
2710
2788
|
function responseWithBody(response, body) {
|
|
2711
2789
|
const headers = new Headers(response.headers);
|
|
2712
2790
|
headers.delete("content-length");
|
|
@@ -2734,7 +2812,9 @@ function withOAuthEndpointOverrides(fetchFn, getOverrides) {
|
|
|
2734
2812
|
const overrides = resolveOverrides();
|
|
2735
2813
|
if (!overrides) return response;
|
|
2736
2814
|
if (!isAuthorizationServerMetadataRequest(input)) return response;
|
|
2737
|
-
if (!response.ok)
|
|
2815
|
+
if (!response.ok) {
|
|
2816
|
+
return synthesizedMetadataResponse(input, init, response, overrides) ?? response;
|
|
2817
|
+
}
|
|
2738
2818
|
if (!isJsonDocumentResponse(response.headers.get("content-type")))
|
|
2739
2819
|
return response;
|
|
2740
2820
|
let parsed;
|
|
@@ -2910,8 +2990,8 @@ import {
|
|
|
2910
2990
|
OAuthMetadataSchema,
|
|
2911
2991
|
OpenIdProviderDiscoveryMetadataSchema
|
|
2912
2992
|
} from "@modelcontextprotocol/core";
|
|
2913
|
-
var
|
|
2914
|
-
var
|
|
2993
|
+
var RFC8414_WELL_KNOWN2 = "/.well-known/oauth-authorization-server";
|
|
2994
|
+
var OIDC_WELL_KNOWN2 = "/.well-known/openid-configuration";
|
|
2915
2995
|
var COMPAT_SOURCE_HEADER = "x-inspector-oauth-metadata-source";
|
|
2916
2996
|
function oidcDiscoveryCandidates(rfc8414Url) {
|
|
2917
2997
|
let url;
|
|
@@ -2920,16 +3000,16 @@ function oidcDiscoveryCandidates(rfc8414Url) {
|
|
|
2920
3000
|
} catch {
|
|
2921
3001
|
return [];
|
|
2922
3002
|
}
|
|
2923
|
-
if (!url.pathname.startsWith(
|
|
2924
|
-
const path7 = url.pathname.slice(
|
|
3003
|
+
if (!url.pathname.startsWith(RFC8414_WELL_KNOWN2)) return [];
|
|
3004
|
+
const path7 = url.pathname.slice(RFC8414_WELL_KNOWN2.length);
|
|
2925
3005
|
if (path7 !== "" && !path7.startsWith("/")) return [];
|
|
2926
|
-
if (path7 === "") return [new URL(
|
|
3006
|
+
if (path7 === "") return [new URL(OIDC_WELL_KNOWN2, url.origin).href];
|
|
2927
3007
|
return [
|
|
2928
|
-
new URL(`${
|
|
2929
|
-
new URL(`${path7}${
|
|
3008
|
+
new URL(`${OIDC_WELL_KNOWN2}${path7}`, url.origin).href,
|
|
3009
|
+
new URL(`${path7}${OIDC_WELL_KNOWN2}`, url.origin).href
|
|
2930
3010
|
];
|
|
2931
3011
|
}
|
|
2932
|
-
function
|
|
3012
|
+
function continuesDiscovery2(status) {
|
|
2933
3013
|
return status >= 400 && status < 500 || status === 502;
|
|
2934
3014
|
}
|
|
2935
3015
|
async function releaseBody(response) {
|
|
@@ -2955,7 +3035,7 @@ function discoveryHeaders(input, init) {
|
|
|
2955
3035
|
}
|
|
2956
3036
|
return new Headers();
|
|
2957
3037
|
}
|
|
2958
|
-
function
|
|
3038
|
+
function requestMethodOf2(input, init) {
|
|
2959
3039
|
if (init?.method) return init.method.toUpperCase();
|
|
2960
3040
|
if (typeof input !== "string" && !(input instanceof URL)) {
|
|
2961
3041
|
return input.method.toUpperCase();
|
|
@@ -2966,8 +3046,8 @@ function withRfc8414OidcCompat(fetchFn) {
|
|
|
2966
3046
|
return async (input, init) => {
|
|
2967
3047
|
const response = await fetchFn(input, init);
|
|
2968
3048
|
if (response.ok) return response;
|
|
2969
|
-
if (!
|
|
2970
|
-
if (
|
|
3049
|
+
if (!continuesDiscovery2(response.status)) return response;
|
|
3050
|
+
if (requestMethodOf2(input, init) !== "GET") return response;
|
|
2971
3051
|
const candidates = oidcDiscoveryCandidates(requestUrlOf3(input));
|
|
2972
3052
|
if (candidates.length === 0) return response;
|
|
2973
3053
|
const headers = discoveryHeaders(input, init);
|
|
@@ -2997,7 +3077,7 @@ function withRfc8414OidcCompat(fetchFn) {
|
|
|
2997
3077
|
releaseBodyDetached(response);
|
|
2998
3078
|
throw callerSignal.reason;
|
|
2999
3079
|
}
|
|
3000
|
-
if (
|
|
3080
|
+
if (continuesDiscovery2(probe.status)) continue;
|
|
3001
3081
|
return response;
|
|
3002
3082
|
}
|
|
3003
3083
|
let parsed;
|
|
@@ -3017,6 +3097,16 @@ function withRfc8414OidcCompat(fetchFn) {
|
|
|
3017
3097
|
}
|
|
3018
3098
|
const source = probe.url || candidate;
|
|
3019
3099
|
releaseBodyDetached(response);
|
|
3100
|
+
if (isSynthesizedMetadataResponse(probe)) {
|
|
3101
|
+
return new Response(body, {
|
|
3102
|
+
status: 200,
|
|
3103
|
+
statusText: "OK",
|
|
3104
|
+
headers: {
|
|
3105
|
+
"content-type": "application/json",
|
|
3106
|
+
[SYNTHESIZED_METADATA_HEADER]: "endpoint-overrides"
|
|
3107
|
+
}
|
|
3108
|
+
});
|
|
3109
|
+
}
|
|
3020
3110
|
console.warn(
|
|
3021
3111
|
`[oauth] ${source} returned RFC 8414 OAuth 2.0 authorization server metadata, not an OpenID provider document. The MCP TypeScript SDK validates that path as OpenID Connect Discovery and would reject it (modelcontextprotocol/typescript-sdk#2733), so the Inspector is handing it to discovery as the RFC 8414 document it is.`
|
|
3022
3112
|
);
|
|
@@ -3497,7 +3587,10 @@ function parseAuthChallengeFromResponse(response, context) {
|
|
|
3497
3587
|
if (status !== 401 && status !== 403) {
|
|
3498
3588
|
return void 0;
|
|
3499
3589
|
}
|
|
3500
|
-
const wwwAuthenticate = response.headers.get("WWW-Authenticate")
|
|
3590
|
+
const wwwAuthenticate = response.headers.get("WWW-Authenticate") || void 0;
|
|
3591
|
+
if (status === 403 && !wwwAuthenticate) {
|
|
3592
|
+
return void 0;
|
|
3593
|
+
}
|
|
3501
3594
|
const bearer = wwwAuthenticate ? parseWwwAuthenticateBearer(wwwAuthenticate) : {};
|
|
3502
3595
|
const requiredScopes = parseScopeString(bearer.scope);
|
|
3503
3596
|
return {
|
|
@@ -4487,6 +4580,17 @@ async function recordNamespaceKeys(stateFilePath, secretStore, namespace, server
|
|
|
4487
4580
|
warnLedgerFailure("update", error);
|
|
4488
4581
|
}
|
|
4489
4582
|
}
|
|
4583
|
+
async function recordedNamespaces(stateFilePath) {
|
|
4584
|
+
try {
|
|
4585
|
+
const ledger = parseLedger(
|
|
4586
|
+
await readStoreFile(namespaceLedgerPath(stateFilePath))
|
|
4587
|
+
);
|
|
4588
|
+
return [...ledger.keys()].reverse();
|
|
4589
|
+
} catch (error) {
|
|
4590
|
+
warnLedgerFailure("read", error);
|
|
4591
|
+
return [];
|
|
4592
|
+
}
|
|
4593
|
+
}
|
|
4490
4594
|
async function purgeSupersededNamespaces(stateFilePath, secretStore, current) {
|
|
4491
4595
|
let ledger;
|
|
4492
4596
|
let location;
|
|
@@ -4650,24 +4754,13 @@ async function adoptSecretsNamespace(filePath, secretStore, locked) {
|
|
|
4650
4754
|
if (raw !== null && snapshot === null) {
|
|
4651
4755
|
throw new OAuthStateFileUnrecognizedError(filePath, "save");
|
|
4652
4756
|
}
|
|
4653
|
-
if (locked) {
|
|
4654
|
-
await purgeSupersededNamespaces(filePath, secretStore, void 0);
|
|
4655
|
-
}
|
|
4656
4757
|
const namespace = newSecretsNamespace();
|
|
4657
|
-
if (snapshot === null)
|
|
4658
|
-
|
|
4659
|
-
|
|
4660
|
-
|
|
4661
|
-
|
|
4662
|
-
|
|
4663
|
-
})),
|
|
4664
|
-
...Object.keys(snapshot.idpSessions).map((issuer) => ({
|
|
4665
|
-
legacyId: oauthIdpSecretServerId(issuer),
|
|
4666
|
-
scopedId: oauthIdpSecretServerId(issuer, namespace),
|
|
4667
|
-
fields: [IDP_SESSION_FIELD]
|
|
4668
|
-
}))
|
|
4669
|
-
];
|
|
4670
|
-
if (moves.length === 0) return namespace;
|
|
4758
|
+
if (snapshot === null || Object.keys(snapshot.servers).length === 0 && Object.keys(snapshot.idpSessions).length === 0) {
|
|
4759
|
+
if (locked) {
|
|
4760
|
+
await purgeSupersededNamespaces(filePath, secretStore, void 0);
|
|
4761
|
+
}
|
|
4762
|
+
return namespace;
|
|
4763
|
+
}
|
|
4671
4764
|
if (!locked) {
|
|
4672
4765
|
throw new SecretStoreUnavailableError(
|
|
4673
4766
|
`Could not save OAuth state: ${filePath} predates per-state-file secret namespaces, and migrating its secret-store entries needs the file lock, which is unavailable here (see the lock warning above). Migrating without it could lose credentials if two processes migrate at once. Nothing was changed; make the lock directory writable and retry \u2014 or, if you cannot, clear this file's stored OAuth state and re-authorize (clearing does not migrate, and the fresh state file mints its namespace without the lock).`
|
|
@@ -4682,10 +4775,24 @@ async function adoptSecretsNamespace(filePath, secretStore, locked) {
|
|
|
4682
4775
|
);
|
|
4683
4776
|
const touched = [];
|
|
4684
4777
|
try {
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
4778
|
+
const values = await readEntrySecrets(
|
|
4779
|
+
snapshot,
|
|
4780
|
+
secretStore,
|
|
4781
|
+
void 0,
|
|
4782
|
+
await recordedNamespaces(filePath)
|
|
4783
|
+
);
|
|
4784
|
+
const copies = [
|
|
4785
|
+
...[...values.servers].map(([url, secrets]) => ({
|
|
4786
|
+
scopedId: oauthSecretServerId(url, namespace),
|
|
4787
|
+
secrets
|
|
4788
|
+
})),
|
|
4789
|
+
...[...values.idpSessions].map(([issuer, secrets]) => ({
|
|
4790
|
+
scopedId: oauthIdpSecretServerId(issuer, namespace),
|
|
4791
|
+
secrets
|
|
4792
|
+
}))
|
|
4793
|
+
];
|
|
4794
|
+
for (const { scopedId, secrets } of copies) {
|
|
4795
|
+
for (const [field, value] of Object.entries(secrets)) {
|
|
4689
4796
|
touched.push({ serverId: scopedId, field, value: null });
|
|
4690
4797
|
await secretStore.set(scopedId, field, value);
|
|
4691
4798
|
}
|
|
@@ -4695,7 +4802,14 @@ async function adoptSecretsNamespace(filePath, secretStore, locked) {
|
|
|
4695
4802
|
await restoreSecretFields(secretStore, touched, warnRestoreFailure);
|
|
4696
4803
|
throw error;
|
|
4697
4804
|
}
|
|
4698
|
-
|
|
4805
|
+
await purgeSupersededNamespaces(filePath, secretStore, namespace);
|
|
4806
|
+
const legacyIds = [
|
|
4807
|
+
...Object.keys(snapshot.servers).map((url) => oauthSecretServerId(url)),
|
|
4808
|
+
...Object.keys(snapshot.idpSessions).map(
|
|
4809
|
+
(issuer) => oauthIdpSecretServerId(issuer)
|
|
4810
|
+
)
|
|
4811
|
+
];
|
|
4812
|
+
for (const legacyId of legacyIds) {
|
|
4699
4813
|
try {
|
|
4700
4814
|
await secretStore.deleteAllForServer(legacyId);
|
|
4701
4815
|
} catch (error) {
|
|
@@ -4748,6 +4862,14 @@ function preserveNonDurableSecrets(diskSecrets, secrets) {
|
|
|
4748
4862
|
return keep;
|
|
4749
4863
|
}
|
|
4750
4864
|
async function writeOAuthSections(filePath, snapshot, sections, secretStore = defaultSecretStore()) {
|
|
4865
|
+
await writeOAuthSectionsFrom(
|
|
4866
|
+
filePath,
|
|
4867
|
+
async () => snapshot,
|
|
4868
|
+
sections,
|
|
4869
|
+
secretStore
|
|
4870
|
+
);
|
|
4871
|
+
}
|
|
4872
|
+
async function writeOAuthSectionsFrom(filePath, resolveSnapshot, sections, secretStore) {
|
|
4751
4873
|
const policy = getPersistTokensPolicy();
|
|
4752
4874
|
const durable = await secretStoreIsDurable(secretStore);
|
|
4753
4875
|
await withOAuthStateLock(filePath, "save", async (locked) => {
|
|
@@ -4831,6 +4953,7 @@ async function writeOAuthSections(filePath, snapshot, sections, secretStore = de
|
|
|
4831
4953
|
unconfirmed = null;
|
|
4832
4954
|
namespace = diskNamespace;
|
|
4833
4955
|
}
|
|
4956
|
+
const snapshot = await resolveSnapshot(disk, namespace);
|
|
4834
4957
|
const effective = sections ? {
|
|
4835
4958
|
servers: sections.servers && [...new Set(sections.servers)],
|
|
4836
4959
|
idpSessions: sections.idpSessions && [
|
|
@@ -4864,7 +4987,8 @@ async function writeOAuthSections(filePath, snapshot, sections, secretStore = de
|
|
|
4864
4987
|
const candidates = [
|
|
4865
4988
|
.../* @__PURE__ */ new Set([
|
|
4866
4989
|
...serverSecretFields(getOwnEntry(disk?.servers, url)),
|
|
4867
|
-
...serverSecretFields(next)
|
|
4990
|
+
...serverSecretFields(next),
|
|
4991
|
+
...[...restoreBaseline.values()].filter((prior) => prior.serverId === serverId).map(({ field }) => field)
|
|
4868
4992
|
])
|
|
4869
4993
|
];
|
|
4870
4994
|
const entryPrior = await snapshotSecretFields(
|
|
@@ -4873,8 +4997,12 @@ async function writeOAuthSections(filePath, snapshot, sections, secretStore = de
|
|
|
4873
4997
|
candidates
|
|
4874
4998
|
);
|
|
4875
4999
|
priorSecrets.push(...entryPrior);
|
|
5000
|
+
const entryPriorValue = new Map(
|
|
5001
|
+
entryPrior.map(({ field, value }) => [field, value])
|
|
5002
|
+
);
|
|
4876
5003
|
if (next === void 0) {
|
|
4877
5004
|
for (const field of candidates) {
|
|
5005
|
+
if (entryPriorValue.get(field) === null) continue;
|
|
4878
5006
|
ourWrites.set(priorKey({ serverId, field }), null);
|
|
4879
5007
|
}
|
|
4880
5008
|
await secretStore.deleteAllForServer(serverId);
|
|
@@ -4889,10 +5017,9 @@ async function writeOAuthSections(filePath, snapshot, sections, secretStore = de
|
|
|
4889
5017
|
}
|
|
4890
5018
|
const { residue, secrets } = splitServerOAuthState(next, policy);
|
|
4891
5019
|
for (const field of candidates) {
|
|
4892
|
-
|
|
4893
|
-
|
|
4894
|
-
|
|
4895
|
-
);
|
|
5020
|
+
const value = secrets[field] ?? null;
|
|
5021
|
+
if (value === entryPriorValue.get(field)) continue;
|
|
5022
|
+
ourWrites.set(priorKey({ serverId, field }), value);
|
|
4896
5023
|
}
|
|
4897
5024
|
setOwnEntry(merged.servers, url, residue);
|
|
4898
5025
|
if (!durable) {
|
|
@@ -5035,26 +5162,52 @@ function secretRequestsFor(snapshot, namespace) {
|
|
|
5035
5162
|
}
|
|
5036
5163
|
return requests;
|
|
5037
5164
|
}
|
|
5038
|
-
|
|
5039
|
-
const
|
|
5040
|
-
|
|
5165
|
+
function fillMissingSecrets(target, source) {
|
|
5166
|
+
for (const [field, value] of Object.entries(source ?? {})) {
|
|
5167
|
+
if (!Object.hasOwn(target, field)) setOwnEntry(target, field, value);
|
|
5168
|
+
}
|
|
5169
|
+
}
|
|
5170
|
+
async function readEntrySecrets(snapshot, secretStore, namespace, fallbacks) {
|
|
5171
|
+
const servers = /* @__PURE__ */ new Map();
|
|
5172
|
+
const idpSessions = /* @__PURE__ */ new Map();
|
|
5173
|
+
for (const url of Object.keys(snapshot.servers)) servers.set(url, {});
|
|
5174
|
+
for (const issuer of Object.keys(snapshot.idpSessions)) {
|
|
5175
|
+
idpSessions.set(issuer, {});
|
|
5176
|
+
}
|
|
5177
|
+
for (const source of [namespace, ...fallbacks]) {
|
|
5178
|
+
const requests = secretRequestsFor(snapshot, source);
|
|
5179
|
+
if (requests.length === 0) break;
|
|
5180
|
+
const values = await secretStoreGetManyStrict(secretStore, requests);
|
|
5181
|
+
for (const [url, target] of servers) {
|
|
5182
|
+
fillMissingSecrets(target, values[oauthSecretServerId(url, source)]);
|
|
5183
|
+
}
|
|
5184
|
+
for (const [issuer, target] of idpSessions) {
|
|
5185
|
+
fillMissingSecrets(
|
|
5186
|
+
target,
|
|
5187
|
+
values[oauthIdpSecretServerId(issuer, source)]
|
|
5188
|
+
);
|
|
5189
|
+
}
|
|
5190
|
+
}
|
|
5191
|
+
return { servers, idpSessions };
|
|
5192
|
+
}
|
|
5193
|
+
async function joinSnapshot(snapshot, secretStore, namespace, fallbacks) {
|
|
5194
|
+
const values = await readEntrySecrets(
|
|
5195
|
+
snapshot,
|
|
5196
|
+
secretStore,
|
|
5197
|
+
namespace,
|
|
5198
|
+
fallbacks
|
|
5199
|
+
);
|
|
5041
5200
|
return {
|
|
5042
5201
|
servers: Object.fromEntries(
|
|
5043
5202
|
Object.entries(snapshot.servers).map(([url, state]) => [
|
|
5044
5203
|
url,
|
|
5045
|
-
joinServerOAuthState(
|
|
5046
|
-
state,
|
|
5047
|
-
values[oauthSecretServerId(url, namespace)] ?? {}
|
|
5048
|
-
)
|
|
5204
|
+
joinServerOAuthState(state, values.servers.get(url) ?? {})
|
|
5049
5205
|
])
|
|
5050
5206
|
),
|
|
5051
5207
|
idpSessions: Object.fromEntries(
|
|
5052
5208
|
Object.entries(snapshot.idpSessions).map(([issuer, session]) => [
|
|
5053
5209
|
issuer,
|
|
5054
|
-
joinIdpSession(
|
|
5055
|
-
session,
|
|
5056
|
-
values[oauthIdpSecretServerId(issuer, namespace)] ?? {}
|
|
5057
|
-
)
|
|
5210
|
+
joinIdpSession(session, values.idpSessions.get(issuer) ?? {})
|
|
5058
5211
|
])
|
|
5059
5212
|
)
|
|
5060
5213
|
};
|
|
@@ -5121,7 +5274,9 @@ async function readOAuthStore(filePath, secretStore = defaultSecretStore()) {
|
|
|
5121
5274
|
warnMigrationFailure(error);
|
|
5122
5275
|
}
|
|
5123
5276
|
}
|
|
5124
|
-
|
|
5277
|
+
const namespace = parseSecretsNamespace(raw);
|
|
5278
|
+
const fallbacks = namespace === void 0 ? await recordedNamespaces(filePath) : [];
|
|
5279
|
+
return joinSnapshot(snapshot, secretStore, namespace, fallbacks);
|
|
5125
5280
|
});
|
|
5126
5281
|
}
|
|
5127
5282
|
async function removeOAuthStore(filePath, secretStore = defaultSecretStore()) {
|
|
@@ -5748,6 +5903,11 @@ var ManagedListState = class extends TypedEventTarget {
|
|
|
5748
5903
|
// rendered by the list panel instead of vanishing into an unhandled
|
|
5749
5904
|
// rejection — which read as "this server has no tools" (#1953).
|
|
5750
5905
|
error = null;
|
|
5906
|
+
// Whether a fetch has committed a list this session. Until it has, the empty
|
|
5907
|
+
// `items` mean "not loaded yet", not "the server has none" — a distinction a
|
|
5908
|
+
// count of the list cannot make from `items` alone (#2607). Set and cleared
|
|
5909
|
+
// just before the `*Change` dispatch, so a reader keyed on that event sees it.
|
|
5910
|
+
loaded = false;
|
|
5751
5911
|
config;
|
|
5752
5912
|
// Debounce a burst of `list_changed` notifications into a single
|
|
5753
5913
|
// refresh (or one indicator light) once it settles.
|
|
@@ -5783,6 +5943,7 @@ var ManagedListState = class extends TypedEventTarget {
|
|
|
5783
5943
|
this.listChangedTimer = null;
|
|
5784
5944
|
}
|
|
5785
5945
|
this.items = [];
|
|
5946
|
+
this.loaded = false;
|
|
5786
5947
|
this.dispatchChange();
|
|
5787
5948
|
this.setListChanged(false);
|
|
5788
5949
|
this.setError(null);
|
|
@@ -5841,6 +6002,14 @@ var ManagedListState = class extends TypedEventTarget {
|
|
|
5841
6002
|
getItems() {
|
|
5842
6003
|
return [...this.items];
|
|
5843
6004
|
}
|
|
6005
|
+
/**
|
|
6006
|
+
* Whether a fetch has committed a list since the last connect. False while
|
|
6007
|
+
* the connect-time load is in flight, when it was deferred (paginated mode),
|
|
6008
|
+
* and after a disconnect. Changes only alongside the `*Change` event (#2607).
|
|
6009
|
+
*/
|
|
6010
|
+
isLoaded() {
|
|
6011
|
+
return this.loaded;
|
|
6012
|
+
}
|
|
5844
6013
|
/** Whether a `list_changed` arrived since the last refresh (indicator on). */
|
|
5845
6014
|
getListChanged() {
|
|
5846
6015
|
return this.listChanged;
|
|
@@ -5934,6 +6103,7 @@ var ManagedListState = class extends TypedEventTarget {
|
|
|
5934
6103
|
/** Commit a fetched list as the current one and notify subscribers. */
|
|
5935
6104
|
applyItems(items) {
|
|
5936
6105
|
this.items = items;
|
|
6106
|
+
this.loaded = true;
|
|
5937
6107
|
this.dispatchChange();
|
|
5938
6108
|
}
|
|
5939
6109
|
dispatchChange() {
|
|
@@ -5944,6 +6114,7 @@ var ManagedListState = class extends TypedEventTarget {
|
|
|
5944
6114
|
this.unsubscribe?.();
|
|
5945
6115
|
this.unsubscribe = null;
|
|
5946
6116
|
this.items = [];
|
|
6117
|
+
this.loaded = false;
|
|
5947
6118
|
}
|
|
5948
6119
|
};
|
|
5949
6120
|
|
|
@@ -7212,6 +7383,10 @@ function checkSkillNameCollisions(entries) {
|
|
|
7212
7383
|
}
|
|
7213
7384
|
|
|
7214
7385
|
// ../../core/mcp/skillsVerification.ts
|
|
7386
|
+
var DEFAULT_SKILL_BUDGET_HINT = {
|
|
7387
|
+
raise: "with the server's skillCatalogMaxSkills / skillCatalogMaxBytes settings",
|
|
7388
|
+
verifyOne: "by verifying this skill alone"
|
|
7389
|
+
};
|
|
7215
7390
|
function reasonOf(err) {
|
|
7216
7391
|
return err instanceof Error ? err.message : String(err);
|
|
7217
7392
|
}
|
|
@@ -7273,7 +7448,7 @@ function responseBytes(result) {
|
|
|
7273
7448
|
}
|
|
7274
7449
|
return total;
|
|
7275
7450
|
}
|
|
7276
|
-
async function verifySkills(client, entries, metadata) {
|
|
7451
|
+
async function verifySkills(client, entries, metadata, budgetHint = DEFAULT_SKILL_BUDGET_HINT) {
|
|
7277
7452
|
const collisions = checkSkillNameCollisions(entries);
|
|
7278
7453
|
const reports = [];
|
|
7279
7454
|
const budget = resolveSkillCatalogBudget(client.getServerSettings?.());
|
|
@@ -7285,7 +7460,7 @@ async function verifySkills(client, entries, metadata) {
|
|
|
7285
7460
|
const files = [];
|
|
7286
7461
|
const declared = entry.resources === DYNAMIC_RESOURCES ? [] : entry.resources;
|
|
7287
7462
|
const manifest = withinBudget ? boundedManifest(declared) : [];
|
|
7288
|
-
let incomplete = !withinBudget ? `Not read: this run already reached its catalog budget of ${budget.maxSkills} skills / ${budget.maxBytes} bytes (raise it
|
|
7463
|
+
let incomplete = !withinBudget ? `Not read: this run already reached its catalog budget of ${budget.maxSkills} skills / ${budget.maxBytes} bytes (raise it ${budgetHint.raise}). Nothing about this skill's files has been checked \u2014 verify it on its own ${budgetHint.verifyOne} to get a verdict.` : manifest.length < declared.length ? `Only ${manifest.length} of ${declared.length} manifest entries were read: the skill exceeds the ${SKILL_MAX_RESOURCE_ENTRIES}-entry / ${SKILL_MAX_TOTAL_BYTES}-byte interoperability limits, so the rest were not fetched and cannot be reported on.` : void 0;
|
|
7289
7464
|
let receivedBytes = 0;
|
|
7290
7465
|
const entryIdentity = skillUriIdentity(entry.uri);
|
|
7291
7466
|
let selfAttempted = false;
|
|
@@ -7423,6 +7598,14 @@ function anySkillUnverifiable(reports) {
|
|
|
7423
7598
|
}
|
|
7424
7599
|
|
|
7425
7600
|
// ../../core/cli/handlers/skills-verify.ts
|
|
7601
|
+
var CLI_SKILL_BUDGET_HINT = {
|
|
7602
|
+
raise: "with --skill-catalog-max-skills / --skill-catalog-max-bytes, or the server's skillCatalogMaxSkills / skillCatalogMaxBytes",
|
|
7603
|
+
verifyOne: "with `--method skills/get --uri <uri> --verify`, where <uri> is this report's uri,"
|
|
7604
|
+
};
|
|
7605
|
+
var MCPDO_SKILL_BUDGET_HINT = {
|
|
7606
|
+
raise: "with skillCatalogMaxSkills / skillCatalogMaxBytes in the connection's catalog entry",
|
|
7607
|
+
verifyOne: "with `mcpdo @<conn> skills/get <uri> --verify`, where <uri> is this report's uri,"
|
|
7608
|
+
};
|
|
7426
7609
|
function skillVerificationExitCode(reports, requireDigests) {
|
|
7427
7610
|
if (allSkillsVerified(reports)) return void 0;
|
|
7428
7611
|
if (anySkillFailed(reports)) return EXIT_CODES.SKILL_NONCONFORMANT;
|
|
@@ -7474,7 +7657,8 @@ function assertSkillsSupported(inspectorClient, method) {
|
|
|
7474
7657
|
}
|
|
7475
7658
|
}
|
|
7476
7659
|
var resourceStreamRefs = /* @__PURE__ */ new WeakMap();
|
|
7477
|
-
async function runMethod(inspectorClient, args) {
|
|
7660
|
+
async function runMethod(inspectorClient, args, options = {}) {
|
|
7661
|
+
const skillBudgetHint = options.skillBudgetHint ?? CLI_SKILL_BUDGET_HINT;
|
|
7478
7662
|
let managedToolsState = null;
|
|
7479
7663
|
let managedResourcesState = null;
|
|
7480
7664
|
let managedResourceTemplatesState = null;
|
|
@@ -7539,7 +7723,8 @@ async function runMethod(inspectorClient, args) {
|
|
|
7539
7723
|
if (args.appInfo) {
|
|
7540
7724
|
result = { ...appInfo };
|
|
7541
7725
|
} else {
|
|
7542
|
-
const
|
|
7726
|
+
const useTask = args.task === true || tool.execution?.taskSupport === "required";
|
|
7727
|
+
const invocation = useTask ? await inspectorClient.callToolStream(
|
|
7543
7728
|
tool,
|
|
7544
7729
|
args.toolArg || {},
|
|
7545
7730
|
args.metadata,
|
|
@@ -7770,7 +7955,8 @@ async function runMethod(inspectorClient, args) {
|
|
|
7770
7955
|
const reports = await verifySkills(
|
|
7771
7956
|
inspectorClient,
|
|
7772
7957
|
skills,
|
|
7773
|
-
args.metadata
|
|
7958
|
+
args.metadata,
|
|
7959
|
+
skillBudgetHint
|
|
7774
7960
|
);
|
|
7775
7961
|
return {
|
|
7776
7962
|
kind: "ndjson",
|
|
@@ -7799,7 +7985,8 @@ async function runMethod(inspectorClient, args) {
|
|
|
7799
7985
|
const reports = await verifySkills(
|
|
7800
7986
|
inspectorClient,
|
|
7801
7987
|
[skill],
|
|
7802
|
-
args.metadata
|
|
7988
|
+
args.metadata,
|
|
7989
|
+
skillBudgetHint
|
|
7803
7990
|
);
|
|
7804
7991
|
return {
|
|
7805
7992
|
kind: "ndjson",
|
|
@@ -10881,10 +11068,10 @@ async function resolveIdpMetadata(issuer, storage, fetchFn) {
|
|
|
10881
11068
|
}
|
|
10882
11069
|
return discoverIdpMetadata(issuer, fetchFn);
|
|
10883
11070
|
}
|
|
10884
|
-
var
|
|
11071
|
+
var OIDC_WELL_KNOWN3 = "/.well-known/openid-configuration";
|
|
10885
11072
|
async function fetchOpenIdConfiguration(issuer, issuerUrl, fetchFn) {
|
|
10886
11073
|
const url = new URL(
|
|
10887
|
-
`${issuerUrl.pathname.replace(/\/$/, "")}${
|
|
11074
|
+
`${issuerUrl.pathname.replace(/\/$/, "")}${OIDC_WELL_KNOWN3}`,
|
|
10888
11075
|
issuerUrl.origin
|
|
10889
11076
|
);
|
|
10890
11077
|
try {
|
|
@@ -12171,7 +12358,11 @@ var OAuthManager = class {
|
|
|
12171
12358
|
};
|
|
12172
12359
|
|
|
12173
12360
|
// ../../core/mcp/remote/remoteClientTransport.ts
|
|
12174
|
-
import {
|
|
12361
|
+
import {
|
|
12362
|
+
SdkError as SdkError5,
|
|
12363
|
+
SdkErrorCode as SdkErrorCode5,
|
|
12364
|
+
SdkHttpError
|
|
12365
|
+
} from "@modelcontextprotocol/client";
|
|
12175
12366
|
|
|
12176
12367
|
// ../../core/mcp/remote/types.ts
|
|
12177
12368
|
function oauthTokensToRemoteAuthState(tokens) {
|
|
@@ -12226,6 +12417,17 @@ function isConnectAuthChallenge(json) {
|
|
|
12226
12417
|
function isConnectTransportError(json) {
|
|
12227
12418
|
return typeof json === "object" && json !== null && "ok" in json && json.ok === false && "kind" in json && json.kind === "transport_error";
|
|
12228
12419
|
}
|
|
12420
|
+
var SDK_ERROR_CODES = new Set(
|
|
12421
|
+
Object.values(SdkErrorCode5)
|
|
12422
|
+
);
|
|
12423
|
+
function toSdkHttpError(message, http) {
|
|
12424
|
+
const code = SDK_ERROR_CODES.has(http.code) ? http.code : SdkErrorCode5.ClientHttpNotImplemented;
|
|
12425
|
+
return new SdkHttpError(code, message, {
|
|
12426
|
+
status: http.status,
|
|
12427
|
+
...http.statusText !== void 0 && { statusText: http.statusText },
|
|
12428
|
+
...http.text !== void 0 && { text: http.text }
|
|
12429
|
+
});
|
|
12430
|
+
}
|
|
12229
12431
|
function legacySessionId(json) {
|
|
12230
12432
|
if (typeof json === "object" && json !== null && "sessionId" in json && typeof json.sessionId === "string" && !("ok" in json)) {
|
|
12231
12433
|
return json.sessionId;
|
|
@@ -12726,6 +12928,9 @@ var RemoteClientTransport = class {
|
|
|
12726
12928
|
});
|
|
12727
12929
|
return;
|
|
12728
12930
|
}
|
|
12931
|
+
if (json.http) {
|
|
12932
|
+
throw toSdkHttpError(json.error, json.http);
|
|
12933
|
+
}
|
|
12729
12934
|
throw new Error(json.error);
|
|
12730
12935
|
}
|
|
12731
12936
|
async requestSend(message, options) {
|
|
@@ -12798,8 +13003,9 @@ var corePackageJson = {
|
|
|
12798
13003
|
version: "0.0.0"
|
|
12799
13004
|
};
|
|
12800
13005
|
var MAX_URL_ELICITATION_RETRIES = 5;
|
|
12801
|
-
|
|
12802
|
-
|
|
13006
|
+
var WEB_CONNECTION_TIMEOUT_REMEDY = "To accommodate a slower server, you may increase the timeout value in Server Settings.";
|
|
13007
|
+
function connectionTimeoutMessage(timeoutMs, remedy = WEB_CONNECTION_TIMEOUT_REMEDY) {
|
|
13008
|
+
return `Connection timed out after ${timeoutMs} ms. ${remedy}`;
|
|
12803
13009
|
}
|
|
12804
13010
|
function createPendingAbortError() {
|
|
12805
13011
|
return new Error("Pending request aborted");
|
|
@@ -12890,6 +13096,7 @@ var InspectorClient = class _InspectorClient extends InspectorClientEventTarget
|
|
|
12890
13096
|
/** Dedupes concurrent ambient auth challenges (reason + scopes). */
|
|
12891
13097
|
ambientAuthChallengeInFlight = /* @__PURE__ */ new Map();
|
|
12892
13098
|
pipeStderr;
|
|
13099
|
+
connectionTimeoutRemedy;
|
|
12893
13100
|
initialLoggingLevel;
|
|
12894
13101
|
// Modern-era per-request log level (#1629). On 2026-07-28 servers
|
|
12895
13102
|
// `logging/setLevel` is gone; the client opts into logs per request via the
|
|
@@ -13127,6 +13334,7 @@ var InspectorClient = class _InspectorClient extends InspectorClientEventTarget
|
|
|
13127
13334
|
this.fetchFn = options.environment.fetch;
|
|
13128
13335
|
this.logger = options.environment.logger ?? silentLogger;
|
|
13129
13336
|
this.pipeStderr = options.pipeStderr ?? false;
|
|
13337
|
+
this.connectionTimeoutRemedy = options.connectionTimeoutRemedy ?? WEB_CONNECTION_TIMEOUT_REMEDY;
|
|
13130
13338
|
this.initialLoggingLevel = options.initialLoggingLevel;
|
|
13131
13339
|
this.sample = options.sample ?? true;
|
|
13132
13340
|
this.elicit = options.elicit ?? true;
|
|
@@ -13868,9 +14076,10 @@ var InspectorClient = class _InspectorClient extends InspectorClientEventTarget
|
|
|
13868
14076
|
// for that upstream gap and should be deleted with it.
|
|
13869
14077
|
//
|
|
13870
14078
|
// Known, accepted side effect of turning intercept on with no stored
|
|
13871
|
-
// tokens: `parseAuthChallengeFromResponse` treats 403
|
|
13872
|
-
// too, so a probe answered
|
|
13873
|
-
//
|
|
14079
|
+
// tokens: `parseAuthChallengeFromResponse` treats a 403 carrying
|
|
14080
|
+
// `WWW-Authenticate` as a challenge too, so a probe answered that way
|
|
14081
|
+
// for a *non-auth* reason (a gateway rejecting the unknown
|
|
14082
|
+
// `server/discover` method, say) now starts OAuth
|
|
13874
14083
|
// discovery instead of letting "auto" fall back to the legacy
|
|
13875
14084
|
// `initialize`. The outcome is a surfaced `oauthError`, not a hang, and
|
|
13876
14085
|
// it goes away with this clause.
|
|
@@ -13937,7 +14146,14 @@ var InspectorClient = class _InspectorClient extends InspectorClientEventTarget
|
|
|
13937
14146
|
const timeoutPromise = new Promise((_, reject) => {
|
|
13938
14147
|
timer = setTimeout(() => {
|
|
13939
14148
|
connectTimedOut = true;
|
|
13940
|
-
reject(
|
|
14149
|
+
reject(
|
|
14150
|
+
new Error(
|
|
14151
|
+
connectionTimeoutMessage(
|
|
14152
|
+
connectTimeoutMs,
|
|
14153
|
+
this.connectionTimeoutRemedy
|
|
14154
|
+
)
|
|
14155
|
+
)
|
|
14156
|
+
);
|
|
13941
14157
|
}, connectTimeoutMs);
|
|
13942
14158
|
});
|
|
13943
14159
|
try {
|
|
@@ -17287,16 +17503,30 @@ function buildConfigFromOptions(options) {
|
|
|
17287
17503
|
const target = options.target ?? [];
|
|
17288
17504
|
const first = target[0];
|
|
17289
17505
|
const rest = target.slice(1);
|
|
17506
|
+
if (first && options.serverUrl) {
|
|
17507
|
+
throw new Error(
|
|
17508
|
+
`Cannot combine a positional target (${first}) with --server-url (${options.serverUrl}). Pass one or the other.`
|
|
17509
|
+
);
|
|
17510
|
+
}
|
|
17290
17511
|
const urlFromTarget = first && (first.startsWith("http://") || first.startsWith("https://")) ? first : null;
|
|
17291
17512
|
const url = urlFromTarget ?? options.serverUrl ?? null;
|
|
17292
17513
|
if (url) {
|
|
17293
|
-
if (rest.length > 0
|
|
17514
|
+
if (rest.length > 0) {
|
|
17294
17515
|
throw new Error("Arguments cannot be passed to a URL-based MCP server.");
|
|
17295
17516
|
}
|
|
17517
|
+
if (options.transport === "stdio") {
|
|
17518
|
+
throw new Error(
|
|
17519
|
+
`stdio transport cannot be used with a URL (${url}). Use --transport http or --transport sse, or pass a local command instead.`
|
|
17520
|
+
);
|
|
17521
|
+
}
|
|
17296
17522
|
let transportType;
|
|
17297
17523
|
const t = options.transport === "http" ? "streamable-http" : options.transport;
|
|
17298
17524
|
if (t === "sse" || t === "streamable-http") {
|
|
17299
17525
|
transportType = t;
|
|
17526
|
+
} else if (t) {
|
|
17527
|
+
throw new Error(
|
|
17528
|
+
`Invalid transport type: ${t}. Valid types are: sse, http, stdio`
|
|
17529
|
+
);
|
|
17300
17530
|
} else {
|
|
17301
17531
|
const u = new URL(url);
|
|
17302
17532
|
if (u.pathname.endsWith("/mcp")) {
|
|
@@ -19078,6 +19308,26 @@ function readInspectorVersion(callerUrl) {
|
|
|
19078
19308
|
);
|
|
19079
19309
|
}
|
|
19080
19310
|
|
|
19311
|
+
// ../../core/cli/handlers/connect-timeout.ts
|
|
19312
|
+
var DEFAULT_CONNECT_TIMEOUT_MS = 15e3;
|
|
19313
|
+
var CLI_CONNECTION_TIMEOUT_REMEDY = "To accommodate a slower server, pass a larger --connect-timeout <ms>, or set connectionTimeout on the server's catalog or config entry.";
|
|
19314
|
+
function withConnectTimeout(settings, connectionTimeout) {
|
|
19315
|
+
if (connectionTimeout === void 0) return settings;
|
|
19316
|
+
if (settings) return { ...settings, connectionTimeout };
|
|
19317
|
+
return {
|
|
19318
|
+
headers: [],
|
|
19319
|
+
metadata: {},
|
|
19320
|
+
env: [],
|
|
19321
|
+
connectionTimeout,
|
|
19322
|
+
requestTimeout: 0,
|
|
19323
|
+
taskTtl: DEFAULT_TASK_TTL_MS,
|
|
19324
|
+
maxFetchRequests: DEFAULT_MAX_FETCH_REQUESTS,
|
|
19325
|
+
autoRefreshOnListChanged: false,
|
|
19326
|
+
paginatedLists: false,
|
|
19327
|
+
roots: []
|
|
19328
|
+
};
|
|
19329
|
+
}
|
|
19330
|
+
|
|
19081
19331
|
// src/connection/auth-helper.ts
|
|
19082
19332
|
import { spawn } from "child_process";
|
|
19083
19333
|
import { createHash as createHash2 } from "crypto";
|
|
@@ -19471,13 +19721,15 @@ async function runEmaIdpInteractiveFlow(active, storage, navigation) {
|
|
|
19471
19721
|
);
|
|
19472
19722
|
const redirectUrlProvider = new MutableRedirectUrlProvider();
|
|
19473
19723
|
redirectUrlProvider.redirectUrl = formatRunnerOAuthRedirectUrl(callbackUrlConfig);
|
|
19724
|
+
const fetchFn = createProxyFetch();
|
|
19474
19725
|
await runRunnerInteractiveOAuth({
|
|
19475
19726
|
client: {
|
|
19476
19727
|
authenticate: async () => {
|
|
19477
19728
|
const { authorizationUrl } = await startIdpOidcAuthorization({
|
|
19478
19729
|
idp: active,
|
|
19479
19730
|
redirectUrl: redirectUrlProvider.redirectUrl,
|
|
19480
|
-
storage
|
|
19731
|
+
storage,
|
|
19732
|
+
fetchFn
|
|
19481
19733
|
});
|
|
19482
19734
|
navigation.navigateToAuthorization(authorizationUrl);
|
|
19483
19735
|
return authorizationUrl;
|
|
@@ -19491,7 +19743,8 @@ async function runEmaIdpInteractiveFlow(active, storage, navigation) {
|
|
|
19491
19743
|
authorizationCode,
|
|
19492
19744
|
iss,
|
|
19493
19745
|
redirectUrl: redirectUrlProvider.redirectUrl,
|
|
19494
|
-
storage
|
|
19746
|
+
storage,
|
|
19747
|
+
fetchFn
|
|
19495
19748
|
});
|
|
19496
19749
|
},
|
|
19497
19750
|
/* v8 ignore next 2 -- only reached when options.authChallenge is set, which this flow never does */
|
|
@@ -19511,7 +19764,13 @@ async function authorizeInFrontend(serverConfig, serverSettings, options) {
|
|
|
19511
19764
|
return;
|
|
19512
19765
|
}
|
|
19513
19766
|
const environment = {
|
|
19514
|
-
transport: createTransportNode
|
|
19767
|
+
transport: createTransportNode,
|
|
19768
|
+
// HTTPS_PROXY / HTTP_PROXY / NO_PROXY, as in the one-shot CLI (#2642):
|
|
19769
|
+
// `InspectorClient` always hands the transport a defined fetch, so the
|
|
19770
|
+
// transport's own proxy fallback never fires — the proxy has to sit here,
|
|
19771
|
+
// at the bottom of the stack, for OAuth discovery and token requests to
|
|
19772
|
+
// reach it. Undefined when no proxy variable is set.
|
|
19773
|
+
fetch: createProxyFetch()
|
|
19515
19774
|
};
|
|
19516
19775
|
const redirectUrlProvider = new MutableRedirectUrlProvider();
|
|
19517
19776
|
const callbackUrlConfig = parseRunnerOAuthCallbackUrl(
|
|
@@ -19545,6 +19804,8 @@ async function authorizeInFrontend(serverConfig, serverSettings, options) {
|
|
|
19545
19804
|
name: "inspector-cli",
|
|
19546
19805
|
version: readInspectorVersion(import.meta.url)
|
|
19547
19806
|
},
|
|
19807
|
+
// Same knobs as the daemon's connect: --connect-timeout or mcp.json (#2615).
|
|
19808
|
+
connectionTimeoutRemedy: CLI_CONNECTION_TIMEOUT_REMEDY,
|
|
19548
19809
|
initialLoggingLevel: "debug",
|
|
19549
19810
|
progress: false,
|
|
19550
19811
|
sample: false,
|
|
@@ -19754,9 +20015,15 @@ function tryReserveAuthFlow(lockPath) {
|
|
|
19754
20015
|
if (!isStale(fs8.statSync(lockPath).mtimeMs)) return false;
|
|
19755
20016
|
const claimPath = `${lockPath}.claim-${process.pid}`;
|
|
19756
20017
|
fs8.renameSync(lockPath, claimPath);
|
|
19757
|
-
|
|
20018
|
+
if (!isStale(fs8.statSync(claimPath).mtimeMs)) {
|
|
20019
|
+
try {
|
|
20020
|
+
fs8.linkSync(claimPath, lockPath);
|
|
20021
|
+
} finally {
|
|
20022
|
+
fs8.rmSync(claimPath, { force: true });
|
|
20023
|
+
}
|
|
20024
|
+
return false;
|
|
20025
|
+
}
|
|
19758
20026
|
fs8.rmSync(claimPath, { force: true });
|
|
19759
|
-
if (claimedFresh) return false;
|
|
19760
20027
|
create();
|
|
19761
20028
|
return true;
|
|
19762
20029
|
} catch {
|
|
@@ -20411,7 +20678,13 @@ async function getLiveConnectionAuthInfo(connection) {
|
|
|
20411
20678
|
}
|
|
20412
20679
|
async function createConnectionClient(serverConfig, serverSettings) {
|
|
20413
20680
|
const environment = {
|
|
20414
|
-
transport: createTransportNode
|
|
20681
|
+
transport: createTransportNode,
|
|
20682
|
+
// HTTPS_PROXY / HTTP_PROXY / NO_PROXY, as in the one-shot CLI (#2642).
|
|
20683
|
+
// `InspectorClient` builds its fetch chain on `environment.fetch ?? fetch`
|
|
20684
|
+
// and always hands the transport the result, so the transport's own
|
|
20685
|
+
// `createProxyFetch()` fallback is never reached — leave this out and the
|
|
20686
|
+
// daemon connects direct. Undefined when no proxy variable is set.
|
|
20687
|
+
fetch: createProxyFetch()
|
|
20415
20688
|
};
|
|
20416
20689
|
const redirectUrlProvider = new MutableRedirectUrlProvider();
|
|
20417
20690
|
if (isOAuthCapableServerConfig(serverConfig)) {
|
|
@@ -20437,6 +20710,9 @@ async function createConnectionClient(serverConfig, serverSettings) {
|
|
|
20437
20710
|
name: CONNECTION_CLIENT_NAME,
|
|
20438
20711
|
version: readInspectorVersion(import.meta.url)
|
|
20439
20712
|
},
|
|
20713
|
+
// `mcpdo connect` takes the same --connect-timeout as the one-shot CLI, so
|
|
20714
|
+
// a timeout names that rather than the web's Server Settings (#2615).
|
|
20715
|
+
connectionTimeoutRemedy: CLI_CONNECTION_TIMEOUT_REMEDY,
|
|
20440
20716
|
initialLoggingLevel: "debug",
|
|
20441
20717
|
progress: false,
|
|
20442
20718
|
sample: false,
|
|
@@ -20493,6 +20769,9 @@ function connectCancelledError() {
|
|
|
20493
20769
|
}
|
|
20494
20770
|
|
|
20495
20771
|
// src/daemon/server.ts
|
|
20772
|
+
var MCPDO_RUN_OPTIONS = {
|
|
20773
|
+
skillBudgetHint: MCPDO_SKILL_BUDGET_HINT
|
|
20774
|
+
};
|
|
20496
20775
|
var autoCancelElicitationChannel = {
|
|
20497
20776
|
request(frame) {
|
|
20498
20777
|
return Promise.resolve({
|
|
@@ -20924,7 +21203,7 @@ var DaemonServer = class _DaemonServer {
|
|
|
20924
21203
|
const clearAmbientSignal = client.setAmbientRequestSignal(signal);
|
|
20925
21204
|
let outcome;
|
|
20926
21205
|
try {
|
|
20927
|
-
outcome = await runMethod(client, methodArgs);
|
|
21206
|
+
outcome = await runMethod(client, methodArgs, MCPDO_RUN_OPTIONS);
|
|
20928
21207
|
} finally {
|
|
20929
21208
|
clearAmbientSignal();
|
|
20930
21209
|
signal?.removeEventListener("abort", onAbort);
|
|
@@ -20968,7 +21247,10 @@ var DaemonServer = class _DaemonServer {
|
|
|
20968
21247
|
const unwire = wireElicitationBridge(client, channel, requestId);
|
|
20969
21248
|
const outcome = (async () => {
|
|
20970
21249
|
try {
|
|
20971
|
-
return toRpcResult(
|
|
21250
|
+
return toRpcResult(
|
|
21251
|
+
await runMethod(client, methodArgs, MCPDO_RUN_OPTIONS),
|
|
21252
|
+
params.method
|
|
21253
|
+
);
|
|
20972
21254
|
} finally {
|
|
20973
21255
|
unwire();
|
|
20974
21256
|
}
|
|
@@ -21087,7 +21369,7 @@ var DaemonServer = class _DaemonServer {
|
|
|
21087
21369
|
params.interactive
|
|
21088
21370
|
);
|
|
21089
21371
|
const methodArgs = stripConnectionFields(params);
|
|
21090
|
-
const outcome = await runMethod(client, methodArgs);
|
|
21372
|
+
const outcome = await runMethod(client, methodArgs, MCPDO_RUN_OPTIONS);
|
|
21091
21373
|
if (outcome.kind !== "stream") {
|
|
21092
21374
|
throw new CliExitCodeError(
|
|
21093
21375
|
EXIT_CODES.USAGE,
|
|
@@ -21336,6 +21618,8 @@ export {
|
|
|
21336
21618
|
resetNodeOAuthStorageCache,
|
|
21337
21619
|
clearAllOAuthClientState,
|
|
21338
21620
|
NodeOAuthStorage,
|
|
21621
|
+
DEFAULT_CONNECT_TIMEOUT_MS,
|
|
21622
|
+
withConnectTimeout,
|
|
21339
21623
|
PLAIN,
|
|
21340
21624
|
styleFromOpts,
|
|
21341
21625
|
isCliAutoOpenForced,
|