Skip to content

[UI-REWRITE] Add a shared MCP server status indicator - #130

Merged
gcgoncalves merged 12 commits into
mainfrom
6404-shared-server-status-badge
Sep 24, 2026
Merged

gcgoncalves merged 12 commits into
mainfrom
6404-shared-server-status-badge

Conversation

@a-effort

@a-effort a-effort commented Sep 15, 2026 •

Copy link
Copy Markdown
Contributor

Goal: enable users to be informed of their MCP server health.

Status is shown at the server level and the user can click it to trigger a popover that provides more info. Clicking the authorization needed option starts the OAuth flow instead.

Note: OAuth tokens are held per user per server, so an authorization_code server that a colleague authorized is still unusable for everyone else. GET /oauth/status reports the caller's own token state, and the indicator maps a missing or expired token to that state.

130.mp4

This retires the "warning" status and deletes ServerStatusBadge, which was a placeholder this approach replaces.

Closes IBM/mcp-context-forge#6462
Closes IBM/mcp-context-forge#6464

IBM/mcp-context-forge#6465 stays open: it covers catalog cards, which will be a follow up.

Adds one availability derivation and one indicator for MCP server health,
starting with the servers page.

The "Authorization needed" state is new. OAuth tokens are held per user per
gateway, so an authorization_code server that a colleague authorized is still
unusable for everyone else. The health check treats the resulting 401 as
healthy on purpose, so those rows read Active with zero components today.
GET /oauth/status reports the caller's own token state, and the indicator
maps a missing or expired token to that state.

Retires the "warning" status. Two conflicting definitions existed: unreachable
but seen before, and reachable but stale over five minutes. The first is
Offline by another name; the second fires on any server the health loop has
not reached yet. Unreachable now splits into Offline and Connecting on whether
the server has ever responded.

Deletes ServerStatusBadge, which nothing rendered.

Closes #6464
Closes #6465

Signed-off-by: Anna Effort <anna.effort@ibm.com>
a-effort and others added 2 commits September 16, 2026 13:22
States with nothing to resolve open a popover rather than a modal,
matching the visibility info affordance. Authorization needed starts the
OAuth flow on click instead of describing it behind a dialog, and falls
back to the popover where the caller has no way to run it. Turn on goes,
since Activate is already in the row menu.

Signed-off-by: Anna Effort <anna.effort@ibm.com>
@a-effort a-effort changed the title feat: add a shared MCP server status indicator and detail dialog feat: add a shared MCP server status indicator Sep 17, 2026
a-effort and others added 3 commits September 16, 2026 18:04
Recast the status explanations around the server rather than ContextForge,
and stop showing the last error on inactive servers, where the health loop
leaves it behind from an earlier outage.

Narrow the popover to max-w-xs and anchor it to the end of the status label.

Shorten the compact label to Auth, keeping the full word for screen readers.

Signed-off-by: Anna Effort <anna.effort@ibm.com>
Signed-off-by: Anna Effort <anna.effort@ibm.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Changes recommended

OAuth status synchronization and availability presentation still have correctness issues.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Adds a shared MCP server availability indicator, initially integrated into the servers page.

Changes:

  • Adds centralized availability classification and status details.
  • Integrates per-user OAuth authorization status and actions.
  • Adds translations and tests while removing the unused badge.
File summaries
File Description
src/types/server.ts Adds health and OAuth status types.
src/pages/Servers.tsx Loads OAuth states and handles authorization.
src/pages/Servers.test.tsx Tightens Connect button assertions.
src/lib/serverStatus.ts Defines shared availability logic.
src/lib/serverStatus.test.ts Tests availability classification.
src/i18n/locales/pt-BR/mcpServer.json Adds Portuguese status messages.
src/i18n/locales/es-ES/mcpServer.json Adds Spanish status messages.
src/i18n/locales/en-US/mcpServer.json Adds English status messages.
src/components/servers/ServerStatusIndicator.tsx Implements the shared status control.
src/components/servers/ServerStatusIndicator.test.tsx Tests indicator behavior and accessibility.
src/components/servers/ServerStatusDetail.tsx Renders status explanations and diagnostics.
src/components/servers/ServerStatusBadge.tsx Removes the unused legacy badge.
src/components/servers/ServerStatusBadge.test.tsx Removes obsolete badge tests.
src/components/servers/ServersTable.tsx Integrates the new status indicator.
src/components/servers/ServersTable.test.tsx Tests updated table statuses and actions.
src/api/servers.ts Adds OAuth status retrieval and cancellation typing.
Review details
  • Files reviewed: 16/16 changed files
  • Comments generated: 5
  • Review effort level: Balanced

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/api/servers.ts Outdated
Comment thread src/components/servers/ServerStatusDetail.tsx Outdated
Comment thread src/lib/serverStatus.ts
Comment thread src/pages/Servers.tsx
Comment thread src/pages/Servers.tsx Outdated
@a-effort a-effort changed the title feat: add a shared MCP server status indicator [UI-REWRITE] Add a shared MCP server status indicator Sep 17, 2026
The /oauth/status route rejects more than 100 ids, and a paged-through
server list can exceed that, so getOAuthStatus splits and merges.

A rejected refetch after authorization skipped the status reload and
surfaced as an unhandled rejection at the click handler.

Signed-off-by: Anna Effort <anna.effort@ibm.com>
@a-effort
a-effort force-pushed the 6404-shared-server-status-badge branch from 45a7d1d to 9af64f3 Compare September 18, 2026 00:08
@a-effort a-effort self-assigned this Sep 18, 2026
@a-effort

a-effort commented Sep 18, 2026 •

Copy link
Copy Markdown
Contributor Author

LLM review feedback:

Reviewed the diff and the Copilot thread.

The batch cap fix in getOAuthStatus is correct — chunking at 100 and merging is the right place to handle it, and the test covers the split/merge path and the empty-list short-circuit.

The decision to keep auth outranking inactive is reasonable. Authorizing before enabling is a valid flow and activation stays in the row menu regardless.

The lastError scoping to availability !== 'inactive' is the right boundary given the backend clears it on every successful probe for enabled servers.

The race fix (request-ID versioning + wrapping refetch so the status reload always runs) is correct. The test that forces the refetch to fail and then asserts the status updates anyway closes the gap.

The invisible col-start-1 row-start-1 width-holding approach in ServerStatusIndicator prevents layout shift during the async flow without extra state.

@marekdano

Copy link
Copy Markdown
Contributor

@a-effort - please resolve the conflicts

@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.

Status taxonomy only partially migrated - Minor

File: src/components/gateways/SourceSelection.tsx:63 (also CreateServer.tsx)

These still use local getServerStatus/getStatusConfig with the old draft/warning/offline/active model instead of the new shared serverStatus.ts. The "warning" status the PR description says is retired is still alive here, so the same server can show inconsistent status wording across views.

Suggested fix: migrate these call sites to getServerAvailability/getAvailabilityPresentation in the same PR, or file a fast-follow if scope is intentionally limited.

Comment thread src/lib/serverStatus.ts
Comment thread src/pages/Servers.tsx
Comment on lines +110 to +113
const oauthServerIds = useMemo(
() => allServers.filter((server) => server.authType === "oauth").map((server) => server.id),
[allServers],
);

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.

oauthServerIds is a new array on every allServers change, so the full batched /oauth/status call re-fires on any unrelated refresh (delete, toggle, tag edit, "Load More") — not just OAuth-relevant changes. Per the backend, a non-DB token store serves this via up to 100 sequential per-id Vault lookups with retry/backoff, so this is real latency, not just a wasted round trip.

Suggested fix: memoize more narrowly (e.g. by id set content, not allServers reference) or debounce.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in #131, which moves this into a useOAuthTokenStatuses hook. The memo keys on the joined id string rather than the allServers reference, so the batch call follows which servers are in the list and an unrelated refresh no longer re-fires it.

Signed-off-by: Anna Effort <anna.effort@ibm.com>
The guard tested the availability state, but auth outranks inactive, so a
disabled server whose token had also expired kept rendering the error the
health loop left behind before it was turned off.

Signed-off-by: Anna Effort <anna.effort@ibm.com>
@a-effort

Copy link
Copy Markdown
Contributor Author

You are right that SourceSelection and CreateServer still use the local getServerStatus/getStatusConfig, so the retired warning status still renders there.

That migration is in #131, which is stacked on this branch. Both call sites move to getServerAvailability/getAvailabilityPresentation and the local helpers are gone.

@a-effort
a-effort requested a review from marekdano September 23, 2026 17:24
@a-effort
a-effort added this pull request to stack #152 September 23, 2026 17:31

@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.

Approving on the basis that #131 lands soon to complete the migration

LGTM 🚀

@gcgoncalves
gcgoncalves merged commit 3769c2f into main Sep 24, 2026
5 checks passed
@gcgoncalves
gcgoncalves deleted the 6404-shared-server-status-badge branch September 24, 2026 10:31
a-effort added a commit that referenced this pull request Sep 28, 2026
Main carries #130 squashed and #153's refactor of ServerStatusIndicator
onto the shared status-indicator, so those files take main's version.
Servers.tsx keeps main's inline OAuth status block rather than this
branch's hook, which #150 replaces.

Signed-off-by: Anna Effort <anna.effort@ibm.com>
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.

[Design] MCP server status indicator: servers page [UI-REWRITE]: Surface OAuth authorization state in the MCP servers list

4 participants