Skip to content

Comments

Add compatibility for additionalPropertyMap for MCP servers#1255

Open
e19166 wants to merge 2 commits intowso2:mainfrom
e19166:main
Open

Add compatibility for additionalPropertyMap for MCP servers#1255
e19166 wants to merge 2 commits intowso2:mainfrom
e19166:main

Conversation

@e19166
Copy link

@e19166 e19166 commented Feb 23, 2026

Purpose

This PR fixes a bug where the Publisher Lifecycle page would hang in a loading state for MCP Server APIs when tenant-level mandatory additional API properties are configured. The root cause was calling .find() on api.additionalProperties when that field was undefined for MCP servers (REST APIs always had an array). The PR adds defensive handling for both representations (array and additionalPropertiesMap) and ensures mandatory property validation no longer throws. It also includes: revision/deployment detection was improved to properly detect approved deployments (including the special handling used for API Products and null statuses), avoiding false negatives when determining whether the Publish actions should be enabled.

Goals

Preventing direct .find() calls on potentially undefined values stops the JS runtime error and allows the Lifecycle page to finish loading.
Accurately detecting whether deployments exist (and whether one is APPROVED) ensures the UI enables or disables Publish controls correctly.

Approach

  • Validate endpoint availability for MCP servers without assuming additionalProperties exists.
  • Parallelized and hardened fetch logic for revisions and endpoint checks.
  • Added robust mandatory properties check that supports:
    • APIs where additionalProperties is an array of { name, value }
    • MCP servers where additionalPropertiesMap is an object keyed by property name
  • Improved detection of approved deployments (consider null statuses that indicate API Products).
  • Defensive validateMandatoryCustomProperties implementation that checks for both additionalProperties (array) and additionalPropertiesMap (object) and avoids calling .find() on undefined.
  • Endpoint status check and MCP endpoint detection hardened to avoid transient loading errors.

Resolves: wso2/api-manager#4681

Summary by CodeRabbit

  • Bug Fixes
    • Improved validation of required custom properties by supporting multiple shapes of property data and falling back to an alternate data source when the primary structure is missing, ensuring mandatory-property checks remain accurate. Behavior unchanged when no required properties exist; no public APIs were modified.

Copilot AI review requested due to automatic review settings February 23, 2026 14:09
@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@e19166 e19166 self-assigned this Feb 23, 2026
@e19166 e19166 added the bug Something isn't working label Feb 23, 2026
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes a critical runtime error in the Publisher Lifecycle page where calling .find() on undefined would cause the page to hang when tenant-level mandatory additional API properties were configured for MCP Server APIs. The issue occurred because MCP servers use additionalPropertiesMap (an object) instead of additionalProperties (an array) for storing custom properties, but the validation code assumed additionalProperties would always be present as an array.

Changes:

  • Added defensive checks to prevent calling .find() on undefined additionalProperties
  • Implemented fallback logic to use additionalPropertiesMap when additionalProperties is undefined
  • Ensured consistent validation behavior across both data representations

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
CustomizedStepper.jsx Added defensive handling for undefined additionalProperties with fallback to additionalPropertiesMap in mandatory properties validation
LifeCycleUpdate.jsx Added defensive handling for undefined additionalProperties with fallback to additionalPropertiesMap in mandatory properties validation

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@ashera96
Copy link
Contributor

@coderabbitai please review

@coderabbitai
Copy link

coderabbitai bot commented Feb 23, 2026

@ashera96, I'll review the changes now.

✅ Actions performed

Review triggered.

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.

@coderabbitai
Copy link

coderabbitai bot commented Feb 23, 2026

Walkthrough

Two API details components now support fallback validation for mandatory custom properties. Both LifeCycleUpdate and CustomizedStepper check api.additionalProperties first, then fall back to api.additionalPropertiesMap (defaulting to {}) and use boolean coercion for property existence/value checks.

Changes

Cohort / File(s) Summary
Mandatory Properties Validation
portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/LifeCycle/LifeCycleUpdate.jsx, portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/NewOverview/CustomizedStepper.jsx
Added fallback handling for custom properties validation. Both components now inspect api.additionalProperties (array) first; if not an array, they fall back to api.additionalPropertiesMap (or {}) and perform boolean-coerced checks using \!\! for property existence/value.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I hopped through props both old and new,
Peeked in arrays and maps for truth,
With a twitch and a cheerful cheer,
I found the values hiding here,
Fallbacks bound—now nothing to rue! 🥕

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Linked Issues check ❓ Inconclusive The PR addresses defensive handling for additional properties and publish availability checks, but the linked issue #4681 focuses on broader MCP capabilities, auth flows, and HTTP method handling. Clarify whether all objectives from #4681 (MCP capabilities, auth paths, HTTP method support) are fully addressed or if this PR handles only the publish availability subset.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Out of Scope Changes check ✅ Passed All changes are scoped to fixing the specific bug in LifeCycleUpdate and CustomizedStepper components related to additional properties handling and publish availability checks.
Title check ✅ Passed The PR title 'Add compatibility for additionalPropertyMap for MCP servers' clearly summarizes the main change: adding support for an alternative data structure (additionalPropertiesMap) for MCP server APIs.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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 and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/LifeCycle/LifeCycleUpdate.jsx (1)

265-271: ⚠️ Potential issue | 🟠 Major

loading is never reset to false on error — component hangs indefinitely

loading is only cleared at line 263 inside the happy path of API.getSettings().then(...). If API.getSettings() rejects (inner catch, line 265) or if Promise.all rejects (outer catch, line 269), loading stays true and the component renders <Progress /> forever.

🐛 Proposed fix
             .catch((error) => {
                 console.error('Error fetching settings:', error);
+                this.setState({ loading: false });
             });
         })
         .catch((error) => {
             console.error('Error fetching revisions:', error);
+            this.setState({ loading: false });
         });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/LifeCycle/LifeCycleUpdate.jsx`
around lines 265 - 271, The component leaves the loading state true on errors;
ensure you call setLoading(false) in both error handlers so the spinner stops
when API.getSettings or the outer Promise.all rejects: add setLoading(false)
inside the inner catch for API.getSettings(error) and inside the outer catch for
the Promise.all rejection (where revisions fetch errors are handled), keeping
the existing console.error logging and any contextual error handling around
API.getSettings and Promise.all.
🧹 Nitpick comments (1)
portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/LifeCycle/LifeCycleUpdate.jsx (1)

242-255: Extract the shared mandatory-property validation into a utility function

The same two-branch validation logic (array .find() vs. map lookup with !! coercion) now lives in both LifeCycleUpdate.jsx (lines 242–255) and CustomizedStepper.jsx (lines 306–318). A single shared helper prevents future drift between the two implementations.

♻️ Suggested utility (e.g., in a shared validation module)
+// shared utility, e.g. AppComponents/Shared/Utils/apiValidation.js
+export function checkMandatoryPropertiesFilled(api, requiredPropertyNames) {
+    if (Array.isArray(api.additionalProperties)) {
+        return requiredPropertyNames.every(name => {
+            const prop = api.additionalProperties.find(p => p.name === name);
+            return !!(prop && prop.value !== '');
+        });
+    }
+    const map = api.additionalPropertiesMap || {};
+    return requiredPropertyNames.every(name => {
+        const prop = map[name];
+        return !!(prop && prop.value !== '');
+    });
+}

Then both call sites become a one-liner:

-                            if (api.additionalProperties !== undefined) {
-                                isMandatoryPropertiesAvailable = requiredPropertyNames.every(propertyName => {
-                                    const property = api.additionalProperties.find(
-                                        (prop) => prop.name === propertyName);
-                                    return !!(property && property.value !== '');
-                                });
-                            } else {
-                                const addPropsMap = api.additionalPropertiesMap || {};
-                                isMandatoryPropertiesAvailable = requiredPropertyNames.every(propertyName => {
-                                    const property = addPropsMap[propertyName];
-                                    return !!(property && property.value !== '');
-                                });
-                            }
+                            isMandatoryPropertiesAvailable = checkMandatoryPropertiesFilled(api, requiredPropertyNames);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/LifeCycle/LifeCycleUpdate.jsx`
around lines 242 - 255, Extract the duplicated validation into a shared utility
like isMandatoryPropertiesAvailable(requiredPropertyNames, api) that
encapsulates both branches (api.additionalProperties array with .find and
api.additionalPropertiesMap lookup) and returns a boolean; then replace the
inline blocks in LifeCycleUpdate.jsx (the setState/validation block using
requiredPropertyNames and api.additionalProperties/api.additionalPropertiesMap)
and in CustomizedStepper.jsx (the similar every()/find/map logic) with a single
call to that helper, ensuring the helper uses the same !! coercion and checks
property.value !== '' to preserve behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/LifeCycle/LifeCycleUpdate.jsx`:
- Around line 243-254: The guard using "api.additionalProperties !== undefined"
permits null and causes .find() crashes; change the branch condition to use
Array.isArray(api.additionalProperties) so the array path only runs when
additionalProperties is a real array, and fall back to the map path
(api.additionalPropertiesMap or {}) otherwise; update the logic that sets
isMandatoryPropertiesAvailable in LifeCycleUpdate.jsx (the
api.additionalProperties check and the requiredPropertyNames.every(...) block)
to use Array.isArray(api.additionalProperties) and keep the existing map
handling for non-array values.

In
`@portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/NewOverview/CustomizedStepper.jsx`:
- Around line 306-311: The current check uses "api.additionalProperties !==
undefined" which still allows null and causes .find() to throw; update the guard
to validate it's an array (use Array.isArray(api.additionalProperties)) before
calling setIsMandatoryPropertiesAvailable(...) so the
requiredPropertyNames.every callback only runs when api.additionalProperties is
an actual array; keep the existing logic that uses
api.additionalProperties.find(...) and requiredPropertyNames to determine the
boolean.

---

Outside diff comments:
In
`@portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/LifeCycle/LifeCycleUpdate.jsx`:
- Around line 265-271: The component leaves the loading state true on errors;
ensure you call setLoading(false) in both error handlers so the spinner stops
when API.getSettings or the outer Promise.all rejects: add setLoading(false)
inside the inner catch for API.getSettings(error) and inside the outer catch for
the Promise.all rejection (where revisions fetch errors are handled), keeping
the existing console.error logging and any contextual error handling around
API.getSettings and Promise.all.

---

Nitpick comments:
In
`@portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/LifeCycle/LifeCycleUpdate.jsx`:
- Around line 242-255: Extract the duplicated validation into a shared utility
like isMandatoryPropertiesAvailable(requiredPropertyNames, api) that
encapsulates both branches (api.additionalProperties array with .find and
api.additionalPropertiesMap lookup) and returns a boolean; then replace the
inline blocks in LifeCycleUpdate.jsx (the setState/validation block using
requiredPropertyNames and api.additionalProperties/api.additionalPropertiesMap)
and in CustomizedStepper.jsx (the similar every()/find/map logic) with a single
call to that helper, ensuring the helper uses the same !! coercion and checks
property.value !== '' to preserve behavior.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e10d292 and 4e9c9c9.

📒 Files selected for processing (2)
  • portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/LifeCycle/LifeCycleUpdate.jsx
  • portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/NewOverview/CustomizedStepper.jsx

@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
B Maintainability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

@e19166 e19166 changed the title Prevent .find() on undefined for MCP Server APIs + correct publish availability checks Add compatibility for additionalPropertyMap for MCP servers Feb 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[MCP] APIM 4.6.0 MCP Auth flow is not working with 3rd party clients.

4 participants