Skip to content

Fix MCP proxy "Refetch Server Info" and let it reuse stored credentials - #3046

Merged
Thushani-Jayasekera merged 3 commits into
wso2:mainfrom
Thushani-Jayasekera:final-test
Jul 30, 2026
Merged

Fix MCP proxy "Refetch Server Info" and let it reuse stored credentials#3046
Thushani-Jayasekera merged 3 commits into
wso2:mainfrom
Thushani-Jayasekera:final-test

Conversation

@Thushani-Jayasekera

@Thushani-Jayasekera Thushani-Jayasekera commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Fix MCP proxy "Refetch Server Info" and let it reuse stored credentials

Problem

Clicking Refetch Server Info on an MCP proxy's Backend Connection tab always failed:

{
  "status": "error",
  "code": "VALIDATION_FAILED",
  "message": "Provide either url or proxyId, not both."
}

The UI sent { url, proxyId } on every unedited refetch, but MCPServerInfoFetchRequest
declared the two mutually exclusive (oneOf) and FetchServerInfo rejected the pair
outright. The refetch button was broken for every proxy.

Fixing the immediate error exposed a second, worse gap. auth.value is write-only — it
comes back to the browser masked as ****** — so the only way to refetch with a stored
credential was proxyId, which also forces the stored URL. That left no way to answer
"does my edited endpoint work?" without first re-typing a credential the user may never
have had a copy of. Editing just the URL dead-ended in:

Enter the authentication header value to refetch with the updated endpoint or header.

What changed

url and proxyId are no longer mutually exclusive. Which fields are present now selects
the target and the credential independently, giving three valid shapes:

Request Fetches Using When
{ url, auth? } the supplied URL the supplied credential, or none creation — nothing is stored yet
{ proxyId } the stored URL the stored credential nothing edited
{ url, proxyId } the supplied URL the stored credential new — an unsaved endpoint edit

auth still may never accompany proxyId: whenever a proxy is referenced its stored auth
is authoritative, and an override is rejected rather than silently ignored. A request with
neither url nor proxyId is still rejected.

The supplied URL is used verbatim — no path normalization, no /mcp appended — the
same invariant the proxyId-only flow already guarantees and that
TestFetchServerInfoRefetchUsesStoredURLVerbatim guards.

Backend — platform-api

  • FetchServerInfo (internal/service/mcp.go): dropped the "not both" rejection. When
    proxyId is given, the stored URL and credential are resolved as before, then a
    supplied url overrides the URL only. The auth + proxyId and neither-field
    rejections are unchanged.
  • MCPServerInfoFetchRequest (resources/openapi.yaml): oneOfanyOf (at least one
    of url/proxyId) plus not: required: [proxyId, auth], which expresses "auth never
    with proxyId" without also forbidding the new pair. Field descriptions updated.

Frontend — portals/ai-workspace

  • ExternalServersOverview.handleRefetch: rewritten to pick the shape by which credential
    the fetch runs with
    rather than by "is anything edited". Ordered so a typed credential
    always wins, a cleared/absent auth header fetches unauthenticated, and an edited endpoint
    with an untouched credential takes the new { url, proxyId } path.
  • The remaining dead end is narrower and now says something actionable: renaming the auth
    header while the value stays masked has no valid shape (proxyId would resolve the old
    header name too), so it asks for the value or a save first.
  • MCPServerInfoFetchRequest (src/utils/types.ts): modelled as a union so auth +
    proxyId fails to compile rather than failing at runtime.

Testing

  • go test ./internal/service/ — passes.
    • TestFetchServerInfoSuppliedURLWithStoredCredential (new): asserts the supplied URL is
      contacted verbatim and the proxy's stored credential header still rides along.
    • TestFetchServerInfoRejectsAmbiguousTargets: the "both url and proxyId" case is
      removed (now valid); the auth-with-proxyId and neither-field cases stay.
  • tsc --noEmit — no new errors.
  • Cypress 005-mcp-backend-connection-refetch.cy.js updated: TC-98/TC-100 asserted the old
    url-present shape and now assert url is omitted; TC-102 (new) covers the
    { url, proxyId } path — edited endpoint, credential left masked, no auth on the wire.
    Not executed locally (needs a running stack).

Reviewer notes

Scope of the relaxation. fetchMCPProxyServerInfo is granted by ap:mcp_proxy:read
or ap:mcp_proxy:manage, while updateMCPProxy needs ap:mcp_proxy:update or
manage. So a read-only caller can now have the server attach a proxy's stored
credential to a request aimed at a URL they supply. This was a deliberate call for
simplicity over a same-origin restriction on the supplied URL. Note the capability is not
entirely new — a caller holding update could already reach the same outcome in two steps,
since preserveMCPUpstreamAuthValue carries the stored secret across a URL-only save
(asserted by TC-101) — but it is new at the read tier. If that tier matters, the smallest
follow-up is to require ap:mcp_proxy:update for the url + proxyId shape specifically.

Also in this branch: LLM provider upstream auth defaults to none. Commit e24cb2bbd
had changed the gateway-import path to default an absent upstream auth block to other
(defaultUpstreamAuthToOther); that is reverted here, so mapLLMUpstreamYAMLToModel
defaults to none as before. The AI Workspace provider-creation form is aligned with it:
picking a credential-bearing auth type but leaving the API key empty now records none
rather than other (ServiceProviderNew.tsx). An explicitly chosen other or none is
still preserved either way. Independent of the MCP work above and reviewable separately.

…y of `url` and `proxyId`. Update related tests and types to ensure correct API request structure and validation logic.
…er' as default for gateway-pushed providers. Update related tests and documentation to reflect changes in API request structure and validation logic.
@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@Thushani-Jayasekera, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 49 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: ec642e36-95fe-4269-a97f-9e119a5c6c52

📥 Commits

Reviewing files that changed from the base of the PR and between e24cb2b and 16f6213.

📒 Files selected for processing (1)
  • portals/ai-workspace/src/pages/appShell/appShellPages/serviceProvider/ServiceProviderNew.tsx
📝 Walkthrough

Walkthrough

Changes

LLM upstream authentication defaults

Layer / File(s) Summary
Shared authentication defaulting and gateway import mapping
platform-api/internal/service/llm.go, platform-api/internal/service/artifact_import_llm_provider.go, platform-api/internal/service/llm_test.go
Upstream authentication defaults are centralized; gateway imports now default missing or blank authentication types to other, while explicit types such as none remain unchanged.

MCP endpoint refetch selection

Layer / File(s) Summary
MCP request contract
platform-api/resources/openapi.yaml, portals/ai-workspace/src/utils/types.ts
MCP requests require url or proxyId, allow both together, and disallow auth with proxyId in the API schema and TypeScript type.
Backend target and credential resolution
platform-api/internal/service/mcp.go, platform-api/internal/service/mcp_test.go
FetchServerInfo accepts a supplied URL with a stored proxy, uses the supplied URL verbatim, and retains stored credentials.
Frontend refetch branching and coverage
portals/ai-workspace/src/pages/appShell/appShellPages/externalServers/ExternalServersOverview.tsx, portals/ai-workspace/cypress/e2e/002-mcp-proxies/005-mcp-backend-connection-refetch.cy.js
Refetch payloads now distinguish unchanged endpoints, edited endpoints, and live credentials, with coverage for URL-only edits and proxy credential use.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ExternalServersOverview
  participant FetchServerInfo
  participant StoredProxyConfig
  participant MCPBackend
  ExternalServersOverview->>FetchServerInfo: Send url and proxyId
  FetchServerInfo->>StoredProxyConfig: Load stored URL and credential
  FetchServerInfo->>MCPBackend: Call supplied URL with stored credential
  MCPBackend-->>FetchServerInfo: Return server information
  FetchServerInfo-->>ExternalServersOverview: Return refetch result
Loading

Possibly related PRs

  • wso2/api-platform#2987: Also updates the MCPServerInfoFetchRequest URL, proxy ID, and authentication validation contract.

Suggested reviewers: lasanthas, tharsanan1, malinthaprasan

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title matches the main MCP refetch change and is clear enough for history scanning.
Description check ✅ Passed It covers the problem, solution, and testing well, but some template sections like documentation, security, samples, and test environment are missing.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

…to 'none' for gateway-pushed providers. Update related tests and components to ensure correct behavior and preserve explicit auth types.

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
platform-api/internal/service/llm_test.go (1)

107-124: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Cover credential clearing for credential-less auth.

Add populated-header/value cases for blank, explicit none, and explicit other auth; assert the mapped auth clears both fields. This is the security behavior now centralized in defaultUpstreamAuthType.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@platform-api/internal/service/llm_test.go` around lines 107 - 124, Add
table-driven or equivalent populated-header/value test cases around
mapLLMUpstreamYAMLToModel for blank, explicit none, and explicit other auth
types; assert each mapped auth clears both credential fields while preserving
the expected auth type. Reuse the existing defaultUpstreamAuthType behavior and
test setup without changing unrelated mapping cases.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@platform-api/internal/service/mcp.go`:
- Around line 573-578: Update the MCP endpoint validation around the proxyId and
URL checks to compare the caller-provided URL host with the stored proxy host
before resolving or applying stored credentials. Reject proxyId + URL when hosts
differ, while allowing path and query changes on the same host and preserving
the existing auth restriction.

---

Nitpick comments:
In `@platform-api/internal/service/llm_test.go`:
- Around line 107-124: Add table-driven or equivalent populated-header/value
test cases around mapLLMUpstreamYAMLToModel for blank, explicit none, and
explicit other auth types; assert each mapped auth clears both credential fields
while preserving the expected auth type. Reuse the existing
defaultUpstreamAuthType behavior and test setup without changing unrelated
mapping cases.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 9a61a0ef-2655-4aa5-9625-9458a41f811f

📥 Commits

Reviewing files that changed from the base of the PR and between 50ba54b and e24cb2b.

📒 Files selected for processing (9)
  • platform-api/internal/service/artifact_import_llm_provider.go
  • platform-api/internal/service/llm.go
  • platform-api/internal/service/llm_test.go
  • platform-api/internal/service/mcp.go
  • platform-api/internal/service/mcp_test.go
  • platform-api/resources/openapi.yaml
  • portals/ai-workspace/cypress/e2e/002-mcp-proxies/005-mcp-backend-connection-refetch.cy.js
  • portals/ai-workspace/src/pages/appShell/appShellPages/externalServers/ExternalServersOverview.tsx
  • portals/ai-workspace/src/utils/types.ts

Comment thread platform-api/internal/service/mcp.go
@Thushani-Jayasekera Thushani-Jayasekera changed the title Fix MCP Refetch and llm provider default auth Fix MCP proxy "Refetch Server Info" and let it reuse stored credentials Jul 30, 2026
@Thushani-Jayasekera

Copy link
Copy Markdown
Contributor Author

@CodeRabbit review

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@Thushani-Jayasekera
Thushani-Jayasekera merged commit ac83f4c into wso2:main Jul 30, 2026
10 checks passed
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.

2 participants