perf(auth): gate the override wrapper on the discovery request, and guard disk values
Two suppressed review findings. With an override configured, the wrapper cloned and parsed every successful application/json response — every tools/call result and every resource payload on the direct CLI/TUI transports — only to conclude it was not a metadata document. It now tests the request URL for the RFC 8414 / OIDC well-known paths first, so ordinary traffic costs one string test and is returned untouched. The read path also trusted StoredMCPServer's `string` type for the two override fields, which a hand-edited mcp.json does not honor: the CLI and TUI read the file directly and then `.trim()` these, so a number would crash the server load. Guarded with cleanEndpointOverride, mirroring cleanAuthorizationParams. Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
parent
e5c20608bf
commit
8d6803953c
1 changed files with 162 additions and 18 deletions
|
|
@ -248,6 +248,33 @@ export function oauthAuthorizationParamsFromSettings(
|
|||
return Object.keys(record).length > 0 ? record : undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate one of a server's `oauth` endpoint overrides as it comes off disk,
|
||||
* or `undefined` when there is nothing usable. (#1906)
|
||||
*
|
||||
* Same reasoning as `cleanAuthorizationParams` above: `StoredMCPServer` types
|
||||
* these as `string`, but that is a compile-time promise a hand-edited file does
|
||||
* not keep, and the CLI/TUI read `mcp.json` directly. A non-string reaches
|
||||
* `oauthEndpointOverridesFromSettings`, which calls `.trim()` on it — so without
|
||||
* this the whole server list fails to load. URL *validity* is not checked here;
|
||||
* that happens where the override is applied, so a typo drops one field with a
|
||||
* warning instead of anything louder.
|
||||
*/
|
||||
export function cleanEndpointOverride(
|
||||
value: string | undefined,
|
||||
field: "authorizationUrl" | "tokenUrl",
|
||||
): string | undefined {
|
||||
if (value === undefined) return undefined;
|
||||
// Keep: unreachable per the parameter type, reachable from disk.
|
||||
if (typeof value !== "string") {
|
||||
console.warn(
|
||||
`Ignoring \`oauth.${field}\`: expected a string, got ${typeof value}.`,
|
||||
);
|
||||
return undefined;
|
||||
}
|
||||
return value.trim() || undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collapse a server's endpoint-override fields into the
|
||||
* `InspectorClientOptions.oauth` sub-shape, or `undefined` when neither is set.
|
||||
|
|
@ -381,10 +408,20 @@ export function storedFieldsToInspectorSettings(
|
|||
settings.oauthAuthorizationParams = envRecordToPairs(authorizationParams);
|
||||
}
|
||||
// Truthiness drops empty strings like the credential fields above, so a
|
||||
// cleared field reads back as unset rather than as an empty override. (#1906)
|
||||
if (stored.oauth?.authorizationUrl)
|
||||
settings.oauthAuthorizationUrl = stored.oauth.authorizationUrl;
|
||||
if (stored.oauth?.tokenUrl) settings.oauthTokenUrl = stored.oauth.tokenUrl;
|
||||
// cleared field reads back as unset rather than as an empty override. The
|
||||
// `string` type is a compile-time promise a hand-edited `mcp.json` does not
|
||||
// keep, and only the web client's `/api/servers` route checks it — the CLI and
|
||||
// TUI read the file directly and then call `.trim()` on these in
|
||||
// `oauthEndpointOverridesFromSettings`, so a non-string would crash the server
|
||||
// load. Sanitized like `authorizationParams` above rather than trusted.
|
||||
// (#1906)
|
||||
const authorizationUrl = cleanEndpointOverride(
|
||||
stored.oauth?.authorizationUrl,
|
||||
"authorizationUrl",
|
||||
);
|
||||
if (authorizationUrl) settings.oauthAuthorizationUrl = authorizationUrl;
|
||||
const tokenUrl = cleanEndpointOverride(stored.oauth?.tokenUrl, "tokenUrl");
|
||||
if (tokenUrl) settings.oauthTokenUrl = tokenUrl;
|
||||
if (stored.oauth?.onInsufficientScope) {
|
||||
settings.oauthOnInsufficientScope = stored.oauth.onInsufficientScope;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue