Skip to content

feat: surface OAuth validation on Catalog cards - #222

Merged
vishu-bh merged 6 commits into
mainfrom
feat/5722-oauth-catalog-ui
Nov 6, 2026
Merged

vishu-bh merged 6 commits into
mainfrom
feat/5722-oauth-catalog-ui

Conversation

@vishu-bh

@vishu-bh vishu-bh commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

Add stored-token connection validation to registered OAuth Catalog cards. Fetch the saved gateway before testing so the exact saved ID and URL are used, show inline results, and support cancellation, retesting, and reauthorization. Keep validation independent of component import and connection status.

Part 4 of the frontend split for IBM/mcp-context-forge#5722. Based on #221 in native GitHub stack #223. Add the catalog cases to the shared browser suite and audit the secret scanner's false positive on the permission expression.

Validation: production build, ESLint, full frontend coverage suite, and OAuth browser tests across both pages. The complete original implementation passed 3,852 frontend tests, 300 BFF tests, 266 browser tests, and 6 live backend smoke tests; coverage thresholds passed. Browser screenshots are not committed.

Native GitHub stack: #223, rooted at main.

  1. feat: define OAuth connection validation contract #219 — Handwritten OAuth compatibility contract; base: main.
  2. feat: add shared OAuth connection validation #220 — Shared validation; base: feat: define OAuth connection validation contract #219's branch.
  3. feat: surface OAuth validation on MCP Servers #221 — MCP Servers UI; base: feat: add shared OAuth connection validation #220's branch.
  4. feat: surface OAuth validation on Catalog cards #222 — Catalog UI; base: feat: surface OAuth validation on MCP Servers #221's branch.

#218 contains the independent E2E typing fix and can merge separately. These PRs replace #216.

@vishu-bh
vishu-bh changed the base branch from feat/5722-oauth-servers-ui to main November 3, 2026 12:15
@vishu-bh
vishu-bh changed the base branch from main to feat/5722-oauth-servers-ui November 3, 2026 12:31
@vishu-bh
vishu-bh added this pull request to stack #223 November 3, 2026 12:31
@vishu-bh
vishu-bh requested review from a-effort and gcgoncalves and removed request for a-effort November 3, 2026 12:47
@vishu-bh
vishu-bh marked this pull request as ready for review November 3, 2026 12:47
@vishu-bh
vishu-bh force-pushed the feat/5722-oauth-catalog-ui branch from 5d539c2 to 99641b3 Compare November 3, 2026 14:34
@vishu-bh
vishu-bh force-pushed the feat/5722-oauth-catalog-ui branch 2 times, most recently from 0c59e8e to c71e85c Compare November 4, 2026 13:15
Base automatically changed from feat/5722-oauth-servers-ui to main November 6, 2026 10:59
Signed-off-by: Vishu Bhatnagar <vishu.bhatnagar@ibm.com>
@vishu-bh
vishu-bh force-pushed the feat/5722-oauth-catalog-ui branch from c71e85c to 3c0a3ea Compare November 6, 2026 11:08
Signed-off-by: Vishu Bhatnagar <vishu.bhatnagar@ibm.com>
@vishu-bh
vishu-bh force-pushed the feat/5722-oauth-catalog-ui branch from 3c0a3ea to ba9a487 Compare November 6, 2026 11:11
@vishu-bh
vishu-bh requested a review from marekdano November 6, 2026 11:12
Signed-off-by: Vishu Bhatnagar <vishu.bhatnagar@ibm.com>

@marekdano marekdano left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

None of the issues are blocking, just major or suggestions

Comment thread src/pages/ServerCatalog.tsx Outdated
}
return (
(error instanceof OAuthAuthorizationError && error.description) ||
(error instanceof OAuthAuthorizationError && oauthErrorMessage(intl, error.errorCode)) ||

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

catalogOAuthErrorMessage returns only oauthErrorMessage(intl, error.errorCode). The Servers page appends Provider message: …, so an unlisted code shows only generic guidance here. This is the same issue raised on #221. Please reuse the Servers logic as a shared helper. Also, oauthErrorMessage always returns a string, so the mcpServer.catalog.oauth.authorizationError fallback on line 376 is unreachable for OAuthAuthorizationError.

Comment thread src/pages/ServerCatalog.tsx Outdated
Comment on lines +936 to +937
gateway.authType !== "oauth" ||
gateway.oauthConfig?.grant_type !== "authorization_code"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This resolver checks only enabled, authType !== "oauth" and grant_type. It skips the token status, and the authType comparison is case-sensitive, so "OAuth" is wrongly rejected as request_invalid. Can we use canValidateOAuthConnection(gateway, oauthStatuses[id]), as Servers.tsx does?

Comment on lines +288 to +302
{canTest &&
(!isCatalogOAuthServer(server) ||
oauthStatuses?.[server.gateway_id ?? ""]?.state === "not_applicable" ||
canTestOAuth) && (
<DropdownMenuItem
disabled={
!oauthUsable ||
isAdding ||
isTesting ||
isDisconnecting ||
(isCatalogOAuthServer(server) &&
oauthStatuses?.[server.gateway_id ?? ""]?.state !==
"not_applicable" &&
!!canTestOAuthServer &&
!canTestOAuthServer(server))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicated and overlapping conditions:
The "OAuth and not not_applicable" check appears in this render guard and in disabled, and a third time in handleTest (ServerCatalog.tsx:920-921). canTestOAuth (line 141) and canTestOAuthServer (line 140) overlap, and with !!canTestOAuthServer && (line 301), omitting the prop silently skips the check. Please extract one helper, or collapse the two props into one.

Comment thread src/pages/ServerCatalog.tsx Outdated
) {
return;
}
const handleTest = async (server: CatalogServer) => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

handleTest lost its useCallback**
It is recreated every render. That's harmless today because it's only used through inline lambdas, but it breaks memoization if a child starts depending on it.

Signed-off-by: Vishu Bhatnagar <vishu.bhatnagar@ibm.com>

@marekdano marekdano left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes look good now!
LGTM 🚀

Signed-off-by: Vishu Bhatnagar <vishu.bhatnagar@ibm.com>
Comment thread src/pages/ServerCatalog.tsx Outdated
Comment on lines +459 to +466
ids.forEach((id) => {
void api
.get<MCPServer>(`/v1/mcp-servers/${encodeURIComponent(id)}`, undefined, controller.signal)
.then((gateway) => {
if (!controller.signal.aborted)
setSavedOAuthGateways((previous) => ({ ...previous, [id]: gateway }));
})
.catch(() => undefined);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

useEffect(() => {
  ...
  setSavedOAuthGateways((previous) => Object.fromEntries(Object.entries(previous).filter(...)));
  ids.forEach((id) => {                     // ❌ one GET per registered OAuth gateway, every time ids changes
    void api.get<MCPServer>(`/v1/mcp-servers/${encodeURIComponent(id)}`, undefined, controller.signal)...
  • On first load a catalog page with many registered OAuth servers issues one request per gateway.
  • Whenever oauthGatewayIds changes (pagination, filtering...), the previous controller is aborted and all gateways are re-requested, even those already cached in savedOAuthGateways.

Suggestion: cache responses, fetch only ids missing from the cache and abort only on unmount.

isAdding(server.id) ||
isDisconnecting(server.id)
)
return null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: Add curly brackets for readability.

Signed-off-by: Vishu Bhatnagar <vishu.bhatnagar@ibm.com>
@vishu-bh
vishu-bh requested a review from gcgoncalves November 6, 2026 15:14
@vishu-bh
vishu-bh merged commit ec64b97 into main Nov 6, 2026
3 checks passed
@vishu-bh
vishu-bh deleted the feat/5722-oauth-catalog-ui branch November 6, 2026 16:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants