Skip to content

Automatic Sync: Merge changes from stable/mi to main#2355

Open
choreo-cicd wants to merge 123 commits into
mainfrom
sync/main-stable/mi-1781179682
Open

Automatic Sync: Merge changes from stable/mi to main#2355
choreo-cicd wants to merge 123 commits into
mainfrom
sync/main-stable/mi-1781179682

Conversation

@choreo-cicd

@choreo-cicd choreo-cicd commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

This PR syncs changes from stable/mi to the main branch.

Automated PR created by GitHub Actions.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added MCP (Model Context Protocol) Server support with configuration forms and tool management from APIs and sequences.
    • Added context warning notifications when project guidance is truncated.
    • Added inbound connector import capability.
    • Added "Start on Load" task option for compatible MI versions.
  • Bug Fixes

    • Improved API creation error handling and validation.
    • Enhanced file path handling across operating systems.
  • Chores

    • Updated dependencies: axios, webpack-dev-server, hono, and tmp.

IsuruMaduranga and others added 30 commits May 27, 2026 00:25
Replace VALID_FILE_EXTENSIONS / VALID_SPECIAL_FILE_NAMES with
BLOCKED_BINARY_EXTENSIONS so the agent can read/write any text file
(including extensionless ones like Dockerfile, Makefile, .gitignore)
while still blocking archives, executables, office docs, images, etc.
Shell sandbox now enforces the same deny-list on mutation paths. The
@-mention picker keeps its own short UX allow-list, decoupled from
the security gate. Also enable XML validation for .dbs data services.
Trim filePath in getReadFileKind() to keep classification consistent with
validateReadableFilePath(), and update shell sandbox error message to
accurately describe all mutation types (write/edit/delete/rename).
Loads a root-level AGENTS.md (CLAUDE.md / Cursor convention) as a tracked
context block. Re-injected only on content drift via the existing
session-context hash system, so it does not waste tokens every turn.

Files over 30 KB are truncated before being shipped to the model. The
block carries an explicit truncation banner so the agent knows context is
missing (and can file_read the tail on demand), and a persistent in-chat
warning segment tells the user. Truncation warnings fire only when the
block is actually being injected, so an unchanged large file does not
re-warn each turn.
- agent.ts: make `saveAgentsMdWarning` failure non-fatal. The live event
  still fires so the user sees the warning this turn; only the JSONL
  replay across reconnects is sacrificed on persistence failure.
- prompt.ts: neutralize embedded `<system-reminder>` / `<user_query>`
  tags in user-authored AGENTS.md so they can't break out of the
  surrounding envelope. Replaces the angle brackets with U+27E8 / U+27E9.
- prompt.ts: fix the `SessionContextBlockHashes.agentsMd` doc comment to
  describe what the code actually hashes (surfaced bytes + truncation
  metadata) instead of the old "full untruncated raw bytes" claim.
- AIChatFooter.tsx: splice the warning before the optimistic streaming
  placeholder. Appending at the end displaced the placeholder, causing
  subsequent content_block / thinking_* events to land in the warning
  bubble instead of the assistant message.
- eventToMessageConverter.ts: drop `(event as any)` cast now that
  `warningMessage` is a typed field on AgentEvent / ChatHistoryEvent.
Fix trivy detected vulnerabilities
Support the startOnLoad attribute for tasks in MI 4.1.0
Instruct agent-mode to flip pom.xml <packaging> to jar and declare
synapse-core when creating a class mediator, otherwise the CApp ships
without the compiled jar and deployment silently fails.

Fixes wso2/product-integrator#1631
file_write and file_edit now append a <system-reminder> to the tool
result whenever the touched file is a class mediator java source
(src/main/java/**/*.java), telling the agent to verify root pom.xml
packaging is "jar" and synapse-core is declared. The prompt-level
guideline alone can be missed; a per-tool reminder makes it harder
to skip.

Related to wso2/product-integrator#1631
Read the project root pom.xml and skip the class mediator reminder
when <packaging>jar</packaging> is already set, so the agent is not
prompted to fix something that is already correct. When packaging is
something else (typically the default "pom"), the reminder reports
the current value to make the required change unambiguous.
…ging

Fix copilot-created class mediators not packed in CApp
- Clarify file_read offset/limit are line-based in AGENTS.md guidance
- Use Math.ceil for KB rounding and improve truncation warning copy
- Add aria-hidden to decorative warning icon
- Dedup context_warning on panel reconnect/event replay
Mirror the POSIX shell sandbox check so the agent cannot mutate
foo.jar, foo.dll, etc. via PowerShell on Windows.
Switch agent file tools to a binary deny-list
Fix trivy detected vulnerabilities
Sync latest changes from release/mi-4.0.2
Merge "micro-integrator-4.0.2" into "stable/mi"
arunans23 and others added 25 commits June 8, 2026 11:42
Add improvements to MCP Server feature.
Show lengthy connection type labels on hover
…nager.ts

Co-authored-by: Chinthaka Jayatilake <37581983+ChinthakaJ98@users.noreply.github.com>
Prepare for MI extension v4.1.0 release
Improve Fill With AI experience with MCP Server
Merge "micro-integrator-4.1.0" into "stable/mi"
@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR updates dependency overrides and package manifests, adds AGENTS.md/context-warning handling for agent mode, and introduces MCP server RPC, project explorer, and visualizer flows across the MI extension.

Changes

Dependency sync

Layer / File(s) Summary
Override pins
common/config/rush/.pnpmfile.cjs, common/config/rush/pnpm-config.json, package.json
PNPM override pins and Rush global overrides update axios, hono, qs, tmp, and remove the prior webpack-dev-server/ws override logic.
Workspace manifest bumps
workspaces/*/package.json, workspaces/mi/mi-extension/CHANGELOG.md
Workspace manifests and the changelog are updated for the new extension version, MCP commands, and dependency version bumps.

Agent-mode and debugger flow

Layer / File(s) Summary
AGENTS.md warning pipeline
workspaces/mi/mi-core/src/rpc-types/agent-mode/types.ts, workspaces/mi/mi-extension/src/ai-features/agent-mode/**, workspaces/mi/mi-visualizer/src/views/AIPanel/**
AGENTS.md content is injected, hashed, persisted as context_warning, and rendered in the AI panel with a dedicated warning segment.
File and attachment safety
workspaces/mi/mi-extension/src/ai-features/agent-mode/tools/**, workspaces/mi/mi-extension/src/ai-features/copilot/message-utils.ts
Text-file classification, binary-path blocking, and attachment data URI normalization are updated for agent and copilot workflows.
Debugger launch and cleanup
workspaces/mi/mi-extension/src/debugger/**, workspaces/mi/mi-extension/src/stateMachine.ts, workspaces/mi/mi-extension/src/lang-client/ExtendedLanguageClient.ts, workspaces/mi/mi-extension/src/RPCLayer.ts, workspaces/mi/mi-extension/src/test/e2e-playwright-tests/**
Debugger configuration, launch/disconnect behavior, diagnostics refresh, connector import handling, and related test strings are updated.

MCP server feature

Layer / File(s) Summary
RPC contracts and helpers
workspaces/mi/mi-core/src/rpc-types/**, workspaces/mi/mi-extension/src/util/mcp-server-utils.ts, workspaces/mi/mi-visualizer/src/constants/index.ts
New MCP tool, schema, inbound endpoint, and project-structure types and helpers are added, along with MCP-related constants.
RPC wiring and backend
workspaces/mi/mi-extension/src/rpc-managers/**, workspaces/mi/mi-rpc-client/src/rpc-clients/**, workspaces/mi/mi-extension/src/project-explorer/**, workspaces/mi/mi-extension/src/visualizer/activate.ts
MCP RPC handlers, manager methods, client calls, project-explorer actions, and API cleanup paths are wired through the extension.
Forms and views
workspaces/mi/mi-visualizer/src/views/Forms/MCPServerForm/**, workspaces/mi/mi-visualizer/src/views/Forms/InboundEPform/**, workspaces/mi/mi-visualizer/src/views/Overview/**, workspaces/mi/mi-visualizer/src/MainPanel.tsx, workspaces/mi/mi-visualizer/src/PopupPanel.tsx, workspaces/mi/mi-visualizer/src/components/**, workspaces/mi/mi-visualizer/src/views/Forms/**, workspaces/mi/mi-visualizer/src/views/Diagram/**, workspaces/mi/mi-visualizer/src/views/AddArtifact/index.tsx
New MCP server wizards, tool dialogs, project-structure views, popup routes, and supporting form/UI changes are added and connected to the visualizer.
UI and validation updates
workspaces/mi/mi-visualizer/src/views/Forms/APIform/index.tsx, workspaces/mi/mi-visualizer/src/views/Forms/ConnectionForm/index.tsx, workspaces/mi/mi-visualizer/src/views/Forms/RegistryResourceForm.tsx, workspaces/mi/mi-visualizer/src/views/Forms/TaskForm.tsx, workspaces/mi/mi-visualizer/src/views/Overview/ProjectInformation/index.tsx, workspaces/mi/mi-visualizer/src/views/AIPanel/**, workspaces/mi/mi-visualizer/src/components/NavigationBar/HierachicalPath.tsx, workspaces/mi/mi-visualizer/src/components/View/ViewContent.tsx
API creation feedback, connector matching, registry path normalization, task start-on-load, overview layout, and navigation/chat rendering updates are applied.

Sequence Diagram(s)

sequenceDiagram
  participant MCPServerWizard
  participant MiDiagramRpcManager
  participant ProjectExplorer
  participant MainPanel
  MCPServerWizard->>MiDiagramRpcManager: create local entry and inbound endpoint
  ProjectExplorer->>MiDiagramRpcManager: open/show/delete MCP server
  MainPanel->>MCPServerWizard: render MCPServerForm and MCPServerFromAPIsForm views
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~90+ minutes

Possibly related PRs

Suggested labels

Extension/MI, Checks/Run MI UI Tests

Suggested reviewers

  • hevayo
  • gigara
  • arunans23

Poem

(_/)
( •_•) A rabbit hops through AGENTS.md light,
/ >🍃 and MCP servers bloom in sight.
Wires and warnings softly chime,
New tools, new paths, all in time.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch sync/main-stable/mi-1781179682
⚔️ Resolve merge conflicts
  • Resolve merge conflict in branch sync/main-stable/mi-1781179682

@CLAassistant

CLAassistant commented Jun 11, 2026

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
2 out of 3 committers have signed the CLA.

✅ arunans23
✅ ChinthakaJ98
❌ choreo-cicd
You have signed the CLA already but the status is still pending? Let us recheck it.

@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

Note

Due to the large number of review comments, Critical severity comments were prioritized as inline comments.

Caution

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

⚠️ Outside diff range comments (3)
workspaces/mi/mi-extension/src/ai-features/agent-mode/tools/file_tools.ts (1)

134-151: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Reject special files before the "text" fallback.

This fallback now treats any non-blocked path as text, while the read path explicitly allows absolute paths outside the workspace. That means extensionless special files like /proc/self/environ, /proc/cpuinfo, or /dev/random can pass validation and then get readFileSync'd later, which is both a host-data leak and a potential hang.

Suggested fix
 function validateReadableFilePath(projectPath: string, filePath: string): ValidationResult {
     const securityValidation = validateFilePathSecurity(projectPath, filePath, { allowOutsideProject: true });
     if (!securityValidation.valid) {
         return securityValidation;
     }
+
+    const fullPath = resolveFullPath(projectPath, filePath);
+    if (fs.existsSync(fullPath) && !fs.statSync(fullPath).isFile()) {
+        return {
+            valid: false,
+            error: `Cannot read '${filePath}'. Only regular files are supported.`
+        };
+    }
 
     if (getReadFileKind(filePath) === 'unsupported') {
         return {
             valid: false,
             error: `Cannot read binary file '${filePath}'. The extension is on the blocked-binary list (archives, executables, native libraries, office docs, fonts, audio/video, etc.). Use shell tools for binary inspection if needed.`
🤖 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 `@workspaces/mi/mi-extension/src/ai-features/agent-mode/tools/file_tools.ts`
around lines 134 - 151, getReadFileKind currently falls back to 'text' for any
non-blocked path; update getReadFileKind to detect and reject OS special files
(e.g., paths starting with '/proc/', '/dev/', '/sys/' and other well-known
pseudo-filesystems or device nodes) before the text fallback so they return
'unsupported' instead of 'text'. In practice, add a check near the top of
getReadFileKind (before the hasBlockedBinaryExtension check) that
normalizes/trimmed the path and returns 'unsupported' for absolute
special-system paths and obvious device files; keep the existing
READ_PDF_EXTENSION and READ_IMAGE_EXTENSIONS logic and still call
hasBlockedBinaryExtension for other cases. Ensure you reference getReadFileKind
and hasBlockedBinaryExtension when making the change.
workspaces/mi/mi-extension/src/rpc-managers/mi-diagram/rpc-manager.ts (1)

455-464: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Also clear the API-level fallback default here.

This only removes content[key].defaultRequest. If the last shared payload is deleted, the old top-level content.defaultRequest survives, and Line 544 still falls back to it. That can resurrect a deleted default payload name for APIs.

Suggested fix
                 if (cleanShared.length > 0) {
                     content.requests = cleanShared;
                     if (content.defaultRequest) {
                         delete content.defaultRequest;
                     }
                 } else {
                     content.requests = [];
+                    if (content.defaultRequest) {
+                        delete content.defaultRequest;
+                    }
                 }

Also applies to: 480-482

🤖 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 `@workspaces/mi/mi-extension/src/rpc-managers/mi-diagram/rpc-manager.ts` around
lines 455 - 464, When handling type === "API" in rpc-manager.ts, the code only
deletes content[key].defaultRequest but leaves the top-level
content.defaultRequest intact when shared requests are cleared; update the block
that sets content.requests (and the similar block around the other occurrence
referenced) so that when cleanShared.length === 0 you also delete
content.defaultRequest (or set it to undefined) to ensure the API-level fallback
default is removed; target the branch inside the function that uses the
variables content, cleanShared and type === "API" (and the analogous branch at
the other occurrence) to apply the change.
workspaces/mi/mi-visualizer/src/views/AIPanel/component/AIChatMessage.tsx (1)

281-301: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Exclude context warnings from answer-content detection.

hasAnswerContent doesn’t treat segment.isContextWarning as a system segment, so warning-only synthetic messages can incorrectly show the feedback bar.

Suggested fix
         const isSystemSegment = Boolean(
             segment.isToolCall ||
             segment.isTodoList ||
             segment.isBashOutput ||
             segment.isCompactSummary ||
+            segment.isContextWarning ||
             segment.isFileChanges ||
             segment.isPlan ||
             segment.isThinking
         );

Also applies to: 381-390

🤖 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 `@workspaces/mi/mi-visualizer/src/views/AIPanel/component/AIChatMessage.tsx`
around lines 281 - 301, The hasAnswerContent detection currently treats
system-like segments via the isSystemSegment boolean but omits
segment.isContextWarning, so synthetic messages that only contain context
warnings still count as answer content; update the isSystemSegment expression
inside the parsedSegments.some callback in AIChatMessage.tsx (the
hasAnswerContent computation) to include segment.isContextWarning alongside
segment.isToolCall, segment.isTodoList, segment.isBashOutput,
segment.isCompactSummary, segment.isFileChanges, segment.isPlan, and
segment.isThinking, and apply the same change to the other analogous
hasAnswerContent block later in the file so context warnings are excluded from
answer-content detection.
🟠 Major comments (20)
workspaces/mi/mi-extension/src/project-explorer/activate.ts-486-490 (1)

486-490: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Pass a string path into refreshViewsAfterDelete().

This block still accepts both Uri and string inputs, but the helper expects a string path. When fileUri is a Uri, the delete succeeds and the follow-up refresh call throws, so the user gets a false “Failed to delete …” error after the artifact was already removed.

Suggested fix
 							if (item.contextValue === 'api') {
 								deleteSwagger(fileUri);
                                 deleteApiMetadata(fileUri);
 							}
-							refreshViewsAfterDelete(fileUri);
+							refreshViewsAfterDelete(fileUri.fsPath ?? fileUri);
 						} catch (error) {
 							window.showErrorMessage(`Failed to delete ${item.label}: ${error}`);
 						}
🤖 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 `@workspaces/mi/mi-extension/src/project-explorer/activate.ts` around lines 486
- 490, The call to refreshViewsAfterDelete currently passes fileUri which can be
a Uri and causes a runtime error; update the call site (around deleteSwagger and
deleteApiMetadata in activate.ts) to pass a string path instead by resolving
fileUri to a string (e.g. use fileUri.fsPath when fileUri is a Uri, otherwise
use the value as-is) so refreshViewsAfterDelete always receives a string path.
workspaces/mi/mi-extension/src/project-explorer/activate.ts-680-689 (1)

680-689: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don't require an inbound endpoint to delete every MCP server.

MCPServerTreeItem marks inboundEndpoint as optional, and the delete logic below already handles it conditionally. This guard currently blocks deletion for valid MCP servers that only have a local entry.

Suggested fix
-					if (!localEntryPath || !inboundEndpointPath) {
-						window.showErrorMessage('Could not determine MCP server paths');
+					if (!localEntryPath) {
+						window.showErrorMessage('Could not determine the MCP server local entry path');
 						return;
 					}
🤖 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 `@workspaces/mi/mi-extension/src/project-explorer/activate.ts` around lines 680
- 689, The guard in the 'mcpServer' case is incorrectly requiring
inboundEndpointPath even though MCPServerTreeItem.inboundEndpoint is optional;
update the check to only require localEntryPath (i.e. verify
mcpItem.info?.localEntry?.path exists) and remove the inboundEndpointPath
requirement so deletion can proceed when only a local entry is present; adjust
the window.showErrorMessage text accordingly and keep the rest of the delete
logic (which already handles inboundEndpointPath conditionally) unchanged.
workspaces/mi/mi-extension/src/rpc-managers/ai-features/rpc-manager.ts-950-956 (1)

950-956: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Validate the model payload before returning it over RPC.

A syntactically valid JSON response is not enough here. If the model returns non-string name/description fields or a non-object inputSchema, this method will still forward that malformed payload across the RPC boundary and into the MCP tool flow. Add a runtime shape check and fail closed when it does not match the expected contract.

🧪 Suggested validation
             const cleaned = text.trim().replace(/^```json\s*/i, '').replace(/```\s*$/, '');
             const parsed = JSON.parse(cleaned);
+            const validInputSchema =
+                parsed?.inputSchema &&
+                typeof parsed.inputSchema === 'object' &&
+                !Array.isArray(parsed.inputSchema);
+
+            if (
+                typeof parsed?.name !== 'string' ||
+                typeof parsed?.description !== 'string' ||
+                !validInputSchema
+            ) {
+                throw new Error('Model returned an invalid MCP tool suggestion payload');
+            }
+
             return {
-                name: parsed.name || '',
-                description: parsed.description || '',
-                inputSchema: JSON.stringify(parsed.inputSchema || {}),
+                name: parsed.name,
+                description: parsed.description,
+                inputSchema: JSON.stringify(parsed.inputSchema),
             };
🤖 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 `@workspaces/mi/mi-extension/src/rpc-managers/ai-features/rpc-manager.ts`
around lines 950 - 956, The current code trims and JSON.parses the model output
(variables cleaned/parsed) but does not validate types, so non-string
name/description or non-object inputSchema can be forwarded; add runtime shape
checks after parsing (verify typeof parsed.name === 'string', typeof
parsed.description === 'string', and parsed.inputSchema is a plain object and
not an array), throw an Error to fail closed if validation fails, and only then
return the object using parsed.name, parsed.description and
JSON.stringify(parsed.inputSchema) instead of defaulting to empty values.
workspaces/mi/mi-extension/src/rpc-managers/ai-features/rpc-manager.ts-906-948 (1)

906-948: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Constrain MCP context reads to workspace XML files.

apiXmlPath and sequenceXmlPath come straight from the RPC payload, are read from disk, and are then sent to Anthropic. That turns this endpoint into a local-file disclosure primitive if a webview request is ever tampered with. Resolve the path, reject anything outside this.projectUri, and enforce an .xml extension before reading.

🔒 Suggested guard
+        const path = require('path') as typeof import('path');
         const fs = require('fs') as typeof import('fs');
         const MAX_XML_CHARS = 3000;
+
+        const readWorkspaceXml = (filePath: string): string => {
+            const resolvedPath = fs.realpathSync(filePath);
+            const relativePath = path.relative(this.projectUri, resolvedPath);
+            if (
+                !relativePath ||
+                relativePath.startsWith('..') ||
+                path.isAbsolute(relativePath) ||
+                path.extname(resolvedPath).toLowerCase() !== '.xml'
+            ) {
+                throw new Error('Only workspace XML files can be used as MCP context');
+            }
+
+            let xml = fs.readFileSync(resolvedPath, 'utf8');
+            if (xml.length > MAX_XML_CHARS) {
+                xml = `${xml.slice(0, MAX_XML_CHARS)}\n... (truncated)`;
+            }
+            return xml;
+        };
 
         if (apiXmlPath) {
             try {
-                let xml = fs.readFileSync(apiXmlPath, 'utf8');
-                if (xml.length > MAX_XML_CHARS) xml = xml.slice(0, MAX_XML_CHARS) + '\n... (truncated)';
+                const xml = readWorkspaceXml(apiXmlPath);
                 contextLines.push(`\nAPI resource XML (Synapse configuration):\n${xml}`);
             } catch { /* file unreadable — skip */ }
         }
 
         if (sequenceXmlPath) {
             try {
-                let xml = fs.readFileSync(sequenceXmlPath, 'utf8');
-                if (xml.length > MAX_XML_CHARS) xml = xml.slice(0, MAX_XML_CHARS) + '\n... (truncated)';
+                const xml = readWorkspaceXml(sequenceXmlPath);
                 contextLines.push(`\nSequence implementation XML (Synapse configuration):\n${xml}`);
             } catch { /* file unreadable — skip */ }
         }
🤖 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 `@workspaces/mi/mi-extension/src/rpc-managers/ai-features/rpc-manager.ts`
around lines 906 - 948, The code reads apiXmlPath and sequenceXmlPath directly
from the RPC payload and can disclose arbitrary local files; update the read
logic around apiXmlPath and sequenceXmlPath to: resolve the incoming path with
path.resolve, ensure the resolved path has a .xml extension, verify it is inside
this.projectUri (e.g. by computing path.relative(this.projectUri, resolved) and
rejecting if it starts with '..' or is absolute outside the project), and only
then read and truncate into contextLines (respecting MAX_XML_CHARS); leave
existing variable names (apiXmlPath, sequenceXmlPath, MAX_XML_CHARS,
contextLines) and error handling in place so callers like
getAnthropicClient/generateText are unchanged.
workspaces/mi/mi-extension/src/rpc-managers/mi-diagram/rpc-manager.ts-815-827 (1)

815-827: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Keep the published swagger name consistent with the file you now write.

This block always saves the definition as ${fileName}.yaml, but the generated publish path and the artifact.xml entry still come from getSwaggerName(swaggerDefPath). For .json/.yml inputs, the API can end up referencing a .json/.yml resource that was never written.

Suggested fix
-            const getSwaggerName = (swaggerDefPath: string) => {
-                const ext = path.extname(swaggerDefPath);
-                return `${name}${apiVersion !== "" ? `_v${apiVersion}` : ''}${ext === ".yml" ? ".yaml" : ext }`;
-            };
+            const getSwaggerName = (swaggerDefPath: string) => {
+                const ext = path.extname(swaggerDefPath).toLowerCase();
+                const normalizedExt =
+                    ext === ".json" || ext === ".yml" || ext === ".yaml" ? ".yaml" : ext;
+                return `${name}${apiVersion !== "" ? `_v${apiVersion}` : ''}${normalizedExt}`;
+            };

Also applies to: 830-833

🤖 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 `@workspaces/mi/mi-extension/src/rpc-managers/mi-diagram/rpc-manager.ts` around
lines 815 - 827, The code writes converted JSON/YML inputs to a fixed
`${fileName}.yaml` (swaggerRegPath) but later uses
getSwaggerName(swaggerDefPath) for the published name, causing mismatches;
update the logic so the published swagger name always matches what you write:
compute a single swaggerFileName (e.g., use getSwaggerName(swaggerDefPath) then
if ext is ".json" or ".yml" replace its extension with ".yaml" or alternatively
set swaggerFileName = fileName + ".yaml" and use that value everywhere), use
that swaggerFileName when building swaggerRegPath and when generating the
publish path / artifact.xml entry, and keep parse/stringify/copyFileSync
behavior unchanged (refer to variables swaggerDefPath, fileName, swaggerRegPath
and function getSwaggerName).
workspaces/mi/mi-extension/src/rpc-managers/mi-diagram/rpc-manager.ts-6817-6843 (1)

6817-6843: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Preserve existing inbound endpoint flags when applying MCP edits.

getInboundEndpoint() gives you the current trace and statistics values, but this rewrite drops both from attributes. Updating only port/CORS will silently clear those persisted settings on the inbound endpoint.

Suggested fix
             const attributes: Record<string, string | number | boolean> = {
                 name: current.name,
                 type: current.type,
                 sequence: current.sequence ?? '',
                 onError: current.errorSequence ?? '',
                 suspend: current.suspend,
+                trace: current.trace,
+                statistics: current.statistics,
                 ...(endpointClass && { class: endpointClass }),
             };
🤖 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 `@workspaces/mi/mi-extension/src/rpc-managers/mi-diagram/rpc-manager.ts` around
lines 6817 - 6843, The current rewrite of the inbound endpoint drops persisted
flags (trace and statistics); when building attributes for
getInboundEndpointXmlWrapper you must copy trace and statistics from the
existing inbound endpoint returned by getInboundEndpoint() into the attributes
object (e.g., include ...(current.trace !== undefined && { trace: current.trace
}) and ...(current.statistics !== undefined && { statistics: current.statistics
})), keeping the existing endpointClass handling and other fields, then generate
the xml with getInboundEndpointXmlWrapper and call replaceFullContentToFile as
before.
workspaces/mi/mi-extension/src/util/fileOperations.ts-613-624 (1)

613-624: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

deleteApiMetadata can surface unhandled promise rejections on deletion failures.

Line 613 defines this as async, but Line 622 uses fs.unlinkSync. If unlink throws, the function returns a rejected promise, and current caller usage is fire-and-forget. This can leak unhandled rejections in the extension host. Make this function synchronous (or catch internally) to keep failure handling deterministic.

Suggested fix
-export async function deleteApiMetadata(apiPath: string) {
+export function deleteApiMetadata(apiPath: string): void {
+    try {
     const projectRoot = workspace.getWorkspaceFolder(Uri.file(apiPath))?.uri.fsPath;
     if (!projectRoot) {
         return;
@@
     const metadataFilePath = path.join(projectRoot, 'src', 'main', 'wso2mi', 'resources', 'metadata', metadataFileName);
     if (fs.existsSync(metadataFilePath)) {
         fs.unlinkSync(metadataFilePath);
     }
+    } catch (error) {
+        console.error(`Failed to delete API metadata for ${apiPath}:`, error);
+    }
 }
🤖 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 `@workspaces/mi/mi-extension/src/util/fileOperations.ts` around lines 613 -
624, The async function deleteApiMetadata can throw an unhandled rejection when
fs.unlinkSync fails; make failure deterministic by either removing the async
keyword and keeping synchronous behavior, or catch errors inside the function.
Locate deleteApiMetadata and wrap the metadata deletion (the fs.existsSync /
fs.unlinkSync block) in a try-catch that logs/handles the error, or convert to
fs.unlink with a callback/promisified API and handle the error before returning;
ensure callers no longer receive an unhandled rejected promise.
workspaces/mi/mi-visualizer/src/views/Forms/InboundEPform/index.tsx-176-177 (1)

176-177: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

The store-connector download flow assumes the connector is already installed locally.

selectStoreConnector dereferences .id before checking whether a local connector exists, so clicking a store-only connector throws instead of showing the download prompt. handleAcceptDownload repeats the same assumption before the download runs, so the follow-up schema load still uses stale local state. Branch on a missing local entry first, call requiresDownload(connector) in that case, and after acceptDownload(...) refresh local inbound connectors before resolving the new id.

Suggested fix
 const selectStoreConnector = async (connector: any) => {
-        const connectorId = localConnectors.find((c: any) => c.name === connector.connectorName).id;
-        const response = await rpcClient.getMiDiagramRpcClient().getInboundEPUischema({ connectorName: connectorId });
+        const localEntry = localConnectors.find((c: any) => c.name === connector.connectorName);
+        if (!localEntry) {
+            requiresDownload(connector);
+            return;
+        }
+
+        const response = await rpcClient.getMiDiagramRpcClient().getInboundEPUischema({ connectorName: localEntry.id });

         if (response?.uiSchema) {
             setConnectorSchema(response?.uiSchema);
         } else {
             requiresDownload(connector);
         }
     }

     const handleAcceptDownload = () => {
-        const connectorId = localConnectors.find((c: any) => c.name === inboundOnconfirmation.connectorName).id;
         acceptDownload(async () => {
-            const schema = await rpcClient.getMiDiagramRpcClient().getInboundEPUischema({ connectorName: connectorId });
+            const refreshed = await rpcClient.getMiDiagramRpcClient().getLocalInboundConnectors();
+            const localEntry = refreshed["inbound-connector-data"]?.find(
+                (c: any) => c.name === inboundOnconfirmation.connectorName
+            );
+            if (!localEntry) {
+                throw new Error(`Inbound connector "${inboundOnconfirmation.connectorName}" was not installed`);
+            }
+
+            setLocalConnectors(
+                refreshed["inbound-connector-data"]?.filter(
+                    (connector: any) => !HIDDEN_INBOUND_CONNECTORS.test(connector.name)
+                )
+            );
+
+            const schema = await rpcClient.getMiDiagramRpcClient().getInboundEPUischema({
+                connectorName: localEntry.id
+            });
             setConnectorSchema(schema?.uiSchema);
         });
     };

Also applies to: 226-231

🤖 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 `@workspaces/mi/mi-visualizer/src/views/Forms/InboundEPform/index.tsx` around
lines 176 - 177, selectStoreConnector and handleAcceptDownload currently
dereference local connector .id before verifying existence, causing exceptions
for store-only connectors; change both to first check whether
localConnectors.find(...) returns a value and if not call
requiresDownload(connector) and prompt download, and after acceptDownload(...)
refresh the local inbound connectors list (e.g., re-fetch into localConnectors)
before using its .id; then pass the refreshed id into
rpcClient.getMiDiagramRpcClient().getInboundEPUischema({ connectorName:
connectorId }) so the schema load uses the newly installed connector. Ensure the
same guard/fetch refresh is applied to the other block around the lines
referenced (the follow-up schema load at ~226-231).
workspaces/mi/mi-visualizer/src/Hooks.tsx-54-56 (1)

54-56: ⚠️ Potential issue | 🟠 Major

Move the download-progress listener registration out of render and into useEffect.

workspaces/mi/mi-visualizer/src/Hooks.tsx registers rpcClient.onDownloadProgress(...) directly in the hook body (Lines 54-56), so it runs on every render. Since RpcClient.onDownloadProgress just forwards to messenger.onNotification(...) and doesn’t surface an unsubscribe/disposer, this should be registered once in useEffect and cleaned up on unmount (using the messenger’s unsubscribe/disposer API if available).

🤖 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 `@workspaces/mi/mi-visualizer/src/Hooks.tsx` around lines 54 - 56, The
download-progress listener is being registered on every render because
rpcClient.onDownloadProgress((data: DownloadProgressData) =>
setDownloadProgress(data)) is called in the hook body; move this registration
into a useEffect so it runs once and is cleaned up on unmount. Wrap the
rpcClient.onDownloadProgress call inside useEffect with an empty dependency
array (or include rpcClient if it can change), capture the returned
unsubscribe/disposer from the messenger or rpc client (if available) and call it
in the effect cleanup, and keep the handler using setDownloadProgress to update
state.
workspaces/mi/mi-visualizer/src/views/Forms/MCPServerForm/ToolsList.tsx-81-93 (1)

81-93: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Handle RPC failures from schema conversion to avoid unhandled rejections.

convertMcpJsonSchema is awaited without try/catch in both validation and save paths. A transport/backend failure can break the dialog flow and leave stale state.

💡 Suggested fix
     const validateSchema = async (value: string): Promise<boolean> => {
         if (!value.trim()) {
             setSchemaError(null);
             return true;
         }
-        const { schema } = await rpcClient.getMiDiagramRpcClient().convertMcpJsonSchema({ input: value });
-        if (schema === null) {
-            setSchemaError(INVALID_MCP_SCHEMA_MESSAGE);
-            return false;
-        }
-        setSchemaError(null);
-        return true;
+        try {
+            const { schema } = await rpcClient.getMiDiagramRpcClient().convertMcpJsonSchema({ input: value });
+            if (schema === null) {
+                setSchemaError(INVALID_MCP_SCHEMA_MESSAGE);
+                return false;
+            }
+            setSchemaError(null);
+            return true;
+        } catch {
+            setSchemaError('Schema validation failed. Please try again.');
+            return false;
+        }
     };

     const saveEdit = async () => {
         if (!editingTool) return;
         if (schemaError) return;
-
-        const normalizedSchema = editToolInputSchema.trim()
-            ? (await rpcClient.getMiDiagramRpcClient().convertMcpJsonSchema({ input: editToolInputSchema })).schema
-            : null;
+        let normalizedSchema: string | null = null;
+        try {
+            normalizedSchema = editToolInputSchema.trim()
+                ? (await rpcClient.getMiDiagramRpcClient().convertMcpJsonSchema({ input: editToolInputSchema })).schema
+                : null;
+        } catch {
+            setSchemaError('Schema validation failed. Please try again.');
+            return;
+        }

Also applies to: 95-101

🤖 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 `@workspaces/mi/mi-visualizer/src/views/Forms/MCPServerForm/ToolsList.tsx`
around lines 81 - 93, The validateSchema function (and the similar save/submit
path that calls rpcClient.getMiDiagramRpcClient().convertMcpJsonSchema) must
guard against transport/backend failures: wrap the await rpc call in a
try/catch, on error call setSchemaError with a clear RPC-failure message (or
error.message) and return false, and optionally log the error to avoid leaving
stale state or unhandled rejections; ensure both validateSchema and the save
handler use the same try/catch pattern around convertMcpJsonSchema to
consistently clear or set schema errors and return false on failure.
workspaces/mi/mi-visualizer/src/views/Forms/TaskForm.tsx-267-270 (1)

267-270: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use a minimum-version gate for startOnLoad, not exact-match only.

At Line 269, === 0 enables support only for runtime 4.1.0 and disables it for newer versions (e.g., 4.4.0), which breaks the intended feature gating.

💡 Suggested fix
-            setIsStartOnLoadSupported(compareVersions(runtimeVersion, RUNTIME_VERSION_410) === 0);
+            setIsStartOnLoadSupported(compareVersions(runtimeVersion, RUNTIME_VERSION_410) >= 0);
🤖 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 `@workspaces/mi/mi-visualizer/src/views/Forms/TaskForm.tsx` around lines 267 -
270, The gating currently uses compareVersions(runtimeVersion,
RUNTIME_VERSION_410) === 0 which only allows an exact match to
RUNTIME_VERSION_410; change the check to allow runtimeVersion >=
RUNTIME_VERSION_410 (e.g., compareVersions(...) >= 0) so
setIsStartOnLoadSupported is enabled for 4.1.0 and any newer compatible
runtimes; update the code around getProjectDetails()/runtimeVersion and
RUNTIME_VERSION_410 to use the >=0 comparison.
workspaces/mi/mi-visualizer/src/views/Forms/MCPServerForm/ToolsList.tsx-99-106 (1)

99-106: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Allow users to clear inputSchema instead of restoring the previous value.

At Line 105, inputSchema: normalizedSchema || t.inputSchema restores the old schema when the edit field is intentionally cleared, so schema removal is impossible.

💡 Suggested fix
-        const normalizedSchema = editToolInputSchema.trim()
-            ? (await rpcClient.getMiDiagramRpcClient().convertMcpJsonSchema({ input: editToolInputSchema })).schema
-            : null;
+        const hasSchemaInput = editToolInputSchema.trim().length > 0;
+        const normalizedSchema = hasSchemaInput
+            ? (await rpcClient.getMiDiagramRpcClient().convertMcpJsonSchema({ input: editToolInputSchema })).schema
+            : null;

         const updatedTools = tools.map(t => {
             if (t.id !== editingTool.id) return t;
-            return { ...t, name: editToolName.trim() || t.name, description: editToolDescription, inputSchema: normalizedSchema || t.inputSchema };
+            return {
+                ...t,
+                name: editToolName.trim() || t.name,
+                description: editToolDescription,
+                inputSchema: hasSchemaInput ? normalizedSchema : null
+            };
         });
🤖 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 `@workspaces/mi/mi-visualizer/src/views/Forms/MCPServerForm/ToolsList.tsx`
around lines 99 - 106, The current update merges tools using inputSchema:
normalizedSchema || t.inputSchema which prevents clearing the schema because a
falsy normalizedSchema falls back to the previous value; change that logic so
inputSchema is explicitly set based on the edit input: if
editToolInputSchema.trim() is non-empty use normalizedSchema, otherwise set
inputSchema to null (thus allowing removal). Update the tools.map update (the
updatedTools block that checks t.id === editingTool.id) to use this conditional
so edits that clear editToolInputSchema remove the stored schema instead of
restoring t.inputSchema.
workspaces/mi/mi-visualizer/src/views/Forms/MCPServerForm/AddSequenceToolDialog.tsx-200-213 (1)

200-213: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don't downgrade a failed schema conversion to EMPTY_MCP_SCHEMA.

If convertMcpJsonSchema() returns null here, the submit path still falls back to EMPTY_MCP_SCHEMA, so the tool is created without the schema the user entered. Surface the validation error and abort submission for that item instead.

🤖 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
`@workspaces/mi/mi-visualizer/src/views/Forms/MCPServerForm/AddSequenceToolDialog.tsx`
around lines 200 - 213, In AddSequenceToolDialog where you build `selected` (the
Promise.all mapping), stop falling back to `EMPTY_MCP_SCHEMA` when
`convertMcpJsonSchema()` returns null/invalid: if `converted` is null/undefined
treat that as a validation failure for that `sequenceId` (or `customName`) and
abort the submission path instead of assigning `EMPTY_MCP_SCHEMA`; implement
this by checking the `converted` value after the RPC call and either throw a
descriptive error (to reject the Promise and prevent submit) or add the error to
the component’s validation state so the submit is blocked and the user sees the
conversion error — do not silently replace with `EMPTY_MCP_SCHEMA`. Ensure you
reference `convertMcpJsonSchema`, the `selected` mapping logic, and
`EMPTY_MCP_SCHEMA` when making the change.
workspaces/mi/mi-visualizer/src/views/Forms/MCPServerForm/AddSequenceToolDialog.tsx-110-121 (1)

110-121: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Async schema validation races in both MCP tool dialogs.

Both dialogs call convertMcpJsonSchema() directly from onChange, so late responses can overwrite validation state for newer text. Debounce these requests or tag them and ignore stale completions in both places.

🤖 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
`@workspaces/mi/mi-visualizer/src/views/Forms/MCPServerForm/AddSequenceToolDialog.tsx`
around lines 110 - 121, The validateSchema function currently calls
rpcClient.getMiDiagramRpcClient().convertMcpJsonSchema() directly from onChange,
causing race conditions where late responses can overwrite newer validation
state; modify validateSchema (and the equivalent validator in the other MCP tool
dialog) to either debounce calls or attach a per-call token/sequence id: capture
a unique request id before calling convertMcpJsonSchema(), and when the Promise
resolves only apply setError/clearErrors if the id matches the latest stored
token for that input (or use a short debounce window around onChange to avoid
firing every keystroke). Ensure you update the logic around validateSchema and
any onChange handlers that call convertMcpJsonSchema() so stale responses are
ignored.
workspaces/mi/mi-visualizer/src/views/Forms/InboundEPform/ImportInboundConnector.tsx-43-47 (1)

43-47: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Handle both popup and non-popup completion paths, and invoke provided callbacks.

onImportSuccess and handlePopupClose are part of the component contract but never used; success/cancel currently only close when isPopup is true. This makes non-popup usage a no-op on close/finish and can break parent flow expectations.

Suggested fix
 export function ImportInboundConnectorForm(props: ImportInboundConnectorFormProps) {
@@
             if (response.success) {
-                rpcClient.getMiVisualizerRpcClient().openView({
-                    type: POPUP_EVENT_TYPE.CLOSE_VIEW,
-                    location: { view: null, recentIdentifier: "success" },
-                    isPopup: true
-                });
+                props.onImportSuccess?.();
+                if (props.isPopup) {
+                    rpcClient.getMiVisualizerRpcClient().openView({
+                        type: POPUP_EVENT_TYPE.CLOSE_VIEW,
+                        location: { view: null, recentIdentifier: "success" },
+                        isPopup: true
+                    });
+                } else {
+                    props.handlePopupClose?.();
+                }
@@
     const handleCancel = () => {
         if (props.isPopup) {
             rpcClient.getMiVisualizerRpcClient().openView({
                 type: POPUP_EVENT_TYPE.CLOSE_VIEW,
                 location: { view: null, recentIdentifier: "cancel" },
                 isPopup: true
             });
+        } else {
+            props.handlePopupClose?.();
         }
     }

Also applies to: 66-71, 83-91

🤖 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
`@workspaces/mi/mi-visualizer/src/views/Forms/InboundEPform/ImportInboundConnector.tsx`
around lines 43 - 47, The ImportInboundConnector component currently only closes
popup flows; update its success and cancel/close handlers so they call the
provided callbacks: always call onImportSuccess() from the import/finish success
handler (regardless of isPopup) and, when closing/canceling, call
handlePopupClose() if provided (do this regardless of isPopup so non-popup
parents get notified). Locate the success/finish handler and the cancel/close
handler inside the ImportInboundConnector component (referencing
ImportInboundConnectorFormProps, onImportSuccess, handlePopupClose, and isPopup)
and add the appropriate calls and null-checks for the callbacks.
workspaces/mi/mi-visualizer/src/views/Forms/MCPServerForm/AddAPIToolDialog.tsx-325-334 (1)

325-334: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Reject invalid schema conversion during submit instead of silently replacing it with empty schema.

If convertMcpJsonSchema returns schema: null, the current code still submits using EMPTY_MCP_SCHEMA via converted || EMPTY_MCP_SCHEMA. That accepts invalid user input as a valid empty schema.

Suggested fix
-                let converted: string | null = null;
+                let converted: string | null = null;
                 if (raw) {
                     const { schema } = await rpcClient.getMiDiagramRpcClient().convertMcpJsonSchema({ input: raw });
-                    converted = schema;
+                    if (schema === null) {
+                        setError(`items.${opId}.inputSchema` as const, { message: INVALID_MCP_SCHEMA_MESSAGE });
+                        throw new Error(`Invalid schema for operation ${opId}`);
+                    }
+                    converted = schema;
                 }
                 return {
@@
-                    inputSchema: converted || EMPTY_MCP_SCHEMA,
+                    inputSchema: converted ?? EMPTY_MCP_SCHEMA,
                 };
             }];
         }).map(fn => fn()));
🤖 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
`@workspaces/mi/mi-visualizer/src/views/Forms/MCPServerForm/AddAPIToolDialog.tsx`
around lines 325 - 334, The submit path currently treats a null conversion
result as valid by falling back to EMPTY_MCP_SCHEMA; change it so that after
calling getMiDiagramRpcClient().convertMcpJsonSchema({ input: raw }) you
explicitly check whether schema is null/invalid and abort/raise a validation
error instead of using EMPTY_MCP_SCHEMA (e.g., return/throw a user-facing error
or set form error state), referencing convertMcpJsonSchema and the surrounding
submit logic in AddAPIToolDialog so the form refuses to submit when converted
=== null and prompts the user to fix the input.
workspaces/mi/mi-visualizer/src/views/Forms/MCPServerForm/index.tsx-63-67 (1)

63-67: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Enforce valid TCP port bounds in schema.

Line [63-67] currently accepts any integer, so invalid values (e.g., 0, 70000) can pass client validation and be written into inbound.mcp.port/inbound.http.port at Line [197-198], producing unusable config.

Suggested fix
     port: yup.number()
         .typeError('Port must be a number')
         .required('Port is required')
-        .integer('Port must be an integer'),
+        .integer('Port must be an integer')
+        .min(1, 'Port must be between 1 and 65535')
+        .max(65535, 'Port must be between 1 and 65535'),

Also applies to: 197-198

🤖 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 `@workspaces/mi/mi-visualizer/src/views/Forms/MCPServerForm/index.tsx` around
lines 63 - 67, The port schema currently allows any integer; update the Yup
validation for port in MCPServerForm (the port field in index.tsx) to enforce
TCP bounds by adding .min(1, 'Port must be between 1 and 65535') and .max(65535,
'Port must be between 1 and 65535') to the existing yup.number() chain so
invalid values like 0 or 70000 are rejected before they can be written to
inbound.mcp.port / inbound.http.port.
workspaces/mi/mi-visualizer/src/views/Forms/MCPServerForm/index.tsx-179-209 (1)

179-209: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Avoid partial writes when the second artifact creation fails.

If createLocalEntry succeeds but createInboundEndpoint fails, the project is left in a partial state (orphaned local entry) with no rollback path. This creates cross-artifact inconsistency.

Also applies to: 219-221

🤖 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 `@workspaces/mi/mi-visualizer/src/views/Forms/MCPServerForm/index.tsx` around
lines 179 - 209, The current flow calls createLocalEntry then
createInboundEndpoint, leaving an orphaned local entry if createInboundEndpoint
fails; wrap the two calls so they are atomic: after successfully calling
createLocalEntry (rpcClient.getMiDiagramRpcClient().createLocalEntry) perform
createInboundEndpoint inside a try/catch and on any error call the corresponding
cleanup RPC to remove the created entry (e.g.,
rpcClient.getMiDiagramRpcClient().deleteLocalEntry or equivalent) to rollback,
then rethrow or propagate the original error; alternatively reverse the order
(createInboundEndpoint then createLocalEntry) if safe, but ensure you add
compensating cleanup in both success/failure paths (same for the other
occurrences around lines 219-221).
workspaces/mi/mi-extension/src/util/mcp-server-utils.ts-89-104 (1)

89-104: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Guard $ref dereferencing against recursive cycles.

derefSchema has unbounded recursion. A cyclic reference graph can cause stack overflow and terminate this flow.

Suggested fix
-function derefSchema(spec: any, schema: any): any {
+function derefSchema(spec: any, schema: any, seen = new Set<any>()): any {
     if (!schema || typeof schema !== "object") return schema;
+    if (seen.has(schema)) return schema;
+    seen.add(schema);
     if (schema.$ref) {
         const resolved = resolveRef(spec, schema.$ref);
-        return resolved ? derefSchema(spec, resolved) : schema;
+        return resolved ? derefSchema(spec, resolved, seen) : schema;
     }
     if (schema.allOf) {
         return schema.allOf.reduce((acc: any, s: any) => {
-            const resolved = derefSchema(spec, s);
+            const resolved = derefSchema(spec, s, seen);
             return {
                 ...acc,
                 properties: { ...acc.properties, ...resolved?.properties },
                 required: [...(acc.required || []), ...(resolved?.required || [])],
             };
         }, { type: "object", properties: {} });
     }
     return schema;
 }
🤖 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 `@workspaces/mi/mi-extension/src/util/mcp-server-utils.ts` around lines 89 -
104, The derefSchema function can recurse infinitely on cyclic $ref graphs;
modify derefSchema to accept or create a visited set (e.g., Set<string>) of
resolved reference keys and check this set before calling resolveRef/derefSchema
again: when encountering a schema.$ref, compute a unique ref id (schema.$ref or
resolved pointer), if it's already in visited return the original schema (or a
safe placeholder) to break the cycle, otherwise add it to visited, resolve via
resolveRef and recurse, and remove from visited on return; apply the same
visited-guard when processing schema.allOf entries so derefSchema and resolveRef
use the visited set to avoid stack overflows.
workspaces/mi/mi-extension/src/util/mcp-server-utils.ts-122-130 (1)

122-130: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Include path-level parameters when building API tool input schemas.

extractInputSchema currently reads only operation.parameters, so shared params declared at the path-item level are silently dropped. This can generate incomplete MCP tool schemas and break valid calls downstream.

Suggested fix
-    if (Array.isArray(operation.parameters)) {
-        for (const param of operation.parameters) {
+    const mergedParameters = [
+        ...(Array.isArray(pathItem.parameters) ? pathItem.parameters : []),
+        ...(Array.isArray(operation.parameters) ? operation.parameters : []),
+    ];
+    for (const param of mergedParameters) {
             if ((param.in === "path" || param.in === "query") && param.name && param.schema) {
                 const paramSchema = derefSchema(spec, param.schema);
                 properties[param.name] = { ...paramSchema, ...(param.description ? { description: param.description } : {}) };
                 if (param.required) required.push(param.name);
             }
-        }
-    }
+    }
🤖 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 `@workspaces/mi/mi-extension/src/util/mcp-server-utils.ts` around lines 122 -
130, extractInputSchema only iterates operation.parameters, so path-level
parameters are omitted; update the logic to merge path-item parameters with
operation.parameters (e.g., start from [...(pathItem?.parameters||[]),
...(operation.parameters||[])]) before the Array.isArray check, deduplicate by
parameter name+in with operation-level entries taking precedence, and then call
derefSchema for each param and populate properties and required as the current
loop does (referencing operation.parameters, pathItem.parameters, derefSchema,
properties, required).
🟡 Minor comments (7)
workspaces/mi/mi-extension/src/ai-features/agent-mode/attachment-utils.ts-96-108 (1)

96-108: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Align image validation with the new raw-base64 fallback path.

toImageContentPart(...) accepts raw base64 fallback, but validateAttachments(...) still rejects anything that is not a data URI. This makes the fallback path unreachable for validated inputs.

Suggested fix
     if (images && images.length > 0) {
         for (const image of images) {
-            if (!isValidImageDataUri(image.imageBase64)) {
+            const isDataUri = isValidImageDataUri(image.imageBase64);
+            const isRawBase64 = isValidBase64(image.imageBase64);
+            if (!isDataUri && !isRawBase64) {
                 warnings.push(`Invalid image format: ${image.imageName}`);
             }
         }
     }

Also applies to: 199-203

🤖 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 `@workspaces/mi/mi-extension/src/ai-features/agent-mode/attachment-utils.ts`
around lines 96 - 108, The image converter toImageContentPart supports both
data-URI and raw base64, but validateAttachments still rejects non-data-URI
images, making the raw-base64 path unreachable; update validateAttachments (and
the other validation block that mirrors it around validateAttachments usage) to
accept either a data URI matching /^data:[^;]+;base64,[\s\S]+$/ or a raw base64
string (e.g., /^[A-Za-z0-9+/=]+$/ possibly with whitespace) when attachment.type
=== "image", and ensure the validation error messages reflect both allowed
formats so toImageContentPart can be reached for valid raw-base64 inputs.
workspaces/mi/mi-extension/src/debugger/debugHelper.ts-439-443 (1)

439-443: ⚠️ Potential issue | 🟡 Minor

Suppress “build failed” toast on user-initiated stop
disconnectRequest() calls abortBuildAndRun(), which SIGKILLs activeBuildProcess. The build process still hits the generic non-zero path that unconditionally shows ${path.basename(project)} build failed in the buildProcess.on('close') handler (and similarly rejects with Build process failed), so user cancellation can surface as a build failure UI. Add a cancellation/abort guard (e.g., flag checked by the close/exit handlers) so aborted builds are treated as cancellation rather than failure.

🤖 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 `@workspaces/mi/mi-extension/src/debugger/debugHelper.ts` around lines 439 -
443, The build cancellation currently still triggers the generic failure path
because abortBuildAndRun() kills activeBuildProcess but does not signal the
close/exit handlers; add a cancellation guard: introduce a module-scoped boolean
like buildAborted (or similar) that disconnectRequest()/abortBuildAndRun() sets
to true before treeKill, have the buildProcess.on('close') and on('exit')
handlers check this flag and treat it as a user-cancel (skip showing
`${path.basename(project)} build failed` toast and avoid rejecting with `Build
process failed`), and reset the flag after handling so subsequent builds behave
normally; reference abortBuildAndRun, activeBuildProcess,
buildProcess.on('close')/on('exit'), and disconnectRequest to implement this.
workspaces/mi/mi-extension/CHANGELOG.md-33-33 (1)

33-33: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Hyphenate the compound adjective in this release note.

Line 33 reads better as “Copilot-created class mediators…”.

✏️ Suggested edit
-Fixed: Copilot created class mediators are not getting packed in the CApp ([`#1631`](https://github.com/wso2/product-integrator/issues/1631))
+Fixed: Copilot-created class mediators are not getting packed in the CApp ([`#1631`](https://github.com/wso2/product-integrator/issues/1631))
🤖 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 `@workspaces/mi/mi-extension/CHANGELOG.md` at line 33, Update the release note
string "Fixed: Copilot created class mediators are not getting packed in the
CApp" to hyphenate the compound adjective so it reads "Fixed: Copilot-created
class mediators are not getting packed in the CApp" (i.e., change "Copilot
created" to "Copilot-created").

Source: Linters/SAST tools

workspaces/mi/mi-visualizer/src/views/Forms/TaskForm.tsx-113-115 (1)

113-115: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Reset isStartOnLoadUpdated when loading/resetting form state.

isStartOnLoadUpdated is set to true on toggle but never reset during task/path reload flows, so the Save button can stay enabled without current-session edits.

💡 Suggested fix
             } else {
                 paramConfigs.paramValues = [];
                 setParams(paramConfigs);
                 reset(newTask);
                 setIsNewTask(true);
                 setIsCustomPropsUpdated(false);
+                setIsStartOnLoadUpdated(false);
             }

Also applies to: 575-575

🤖 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 `@workspaces/mi/mi-visualizer/src/views/Forms/TaskForm.tsx` around lines 113 -
115, When the form is loaded or reset, the flag isStartOnLoadUpdated must be
cleared so the Save button reflects current-session edits; update the form
initialization/reset logic (where startOnLoad, isStartOnLoadSupported are set —
e.g., the task/path load handler or the useEffect that initializes form state)
to call setIsStartOnLoadUpdated(false) alongside setting startOnLoad and
setIsStartOnLoadSupported so the "updated" flag is reset whenever a task or path
is reloaded.
workspaces/mi/mi-visualizer/src/views/Forms/MCPServerForm/MCPServerToolsForm.tsx-95-98 (1)

95-98: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add port range validation.

The port validation only checks that it's a number and an integer, but doesn't enforce the valid TCP port range (1-65535). Invalid ports like 0, -1, or 70000 would pass validation but fail at runtime.

🛡️ Proposed fix to add port range validation
     port: yup.number()
         .typeError('Port must be a number')
         .required('Port is required')
-        .integer('Port must be an integer'),
+        .integer('Port must be an integer')
+        .min(1, 'Port must be between 1 and 65535')
+        .max(65535, 'Port must be between 1 and 65535'),
🤖 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
`@workspaces/mi/mi-visualizer/src/views/Forms/MCPServerForm/MCPServerToolsForm.tsx`
around lines 95 - 98, The port schema currently only enforces type and integer;
update the 'port' validation (the yup.number() chain in MCPServerToolsForm.tsx)
to enforce the TCP port range by adding .min(1, 'Port must be between 1 and
65535') and .max(65535, 'Port must be between 1 and 65535') (or an equivalent
.test(...) with the same message) so values like 0, negative numbers, or >65535
are rejected at validation time.
workspaces/mi/mi-visualizer/src/views/Forms/MCPServerForm/MCPServerToolsForm.tsx-213-260 (1)

213-260: ⚠️ Potential issue | 🟡 Minor

Fix useEffect dependency array to include edit mode data
In workspaces/mi/mi-visualizer/src/views/Forms/MCPServerForm/MCPServerToolsForm.tsx (lines 213-260), this useEffect references isEditMode and editData (editData.localEntryPath, editData.inboundEndpointPath, editData.tools), but the dependency array is only [rpcClient, props.path]. Add the relevant isEditMode/editData dependencies (or the specific editData fields used) so the effect reruns when the editing context changes.

🤖 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
`@workspaces/mi/mi-visualizer/src/views/Forms/MCPServerForm/MCPServerToolsForm.tsx`
around lines 213 - 260, The useEffect that defines loadData references
isEditMode and editData (including editData.localEntryPath,
editData.inboundEndpointPath, and editData.tools) but only lists [rpcClient,
props.path] in its dependency array, so it won't re-run when the editing context
changes; update the dependency array of the useEffect to include isEditMode and
the relevant editData fields (or editData as a whole) so loadData re-executes
when those change — i.e., ensure the effect dependencies include isEditMode and
editData (or editData.localEntryPath, editData.inboundEndpointPath,
editData.tools) while keeping rpcClient and props.path to correctly refresh
setTools, setResolvedInboundPath, setValue/setOriginalPort,
setCorsSettings/setOriginalCorsSettings, and setUsedPorts.
workspaces/mi/mi-visualizer/src/views/Forms/MCPServerForm/index.tsx-124-142 (1)

124-142: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Port discovery failure currently leads to a dead-end form state.

On discovery failure, Line [226] keeps the form busy via !!portDiscoveryError, and there is no in-view retry action in the main form branch. Users can get blocked from progressing unless they close/reopen.

Also applies to: 226-227, 312-312

🤖 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 `@workspaces/mi/mi-visualizer/src/views/Forms/MCPServerForm/index.tsx` around
lines 124 - 142, The port discovery error leaves the form blocked because the UI
treats portDiscoveryError as a busy gate; change loadUsedPorts (used in the
useEffect) so that on catch it still clears loading and sets usedPorts to an
empty Set (setUsedPorts(new Set())) and preserves portDiscoveryError for
display, and add an in-form retry action that calls loadUsedPorts (expose
loadUsedPorts or wrap it in a stable callback) so the main form branch no longer
disables progress based on !!portDiscoveryError but instead shows an inline
error + Retry button that re-invokes loadUsedPorts and clears portDiscoveryError
on retry (use setPortDiscoveryError(null) at retry start).

"jsonix": "3.0.0",
"lodash": "4.17.23",
"axios": "1.15.2",
"axios": "1.16.0",

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.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if axios 1.16.0 exists on npm
echo "=== Checking axios 1.16.0 availability ==="
npm view axios@1.16.0 version 2>/dev/null || echo "Version not found"

# Check for security advisories
echo "=== Checking security advisories ==="
gh api graphql -f query='
{
  securityVulnerabilities(first: 10, ecosystem: NPM, package: "axios") {
    nodes {
      advisory {
        summary
        severity
        publishedAt
      }
      vulnerableVersionRange
      firstPatchedVersion {
        identifier
      }
    }
  }
}'

Repository: wso2/vscode-extensions

Length of output: 341


Fix axios version: “1.16.0” appears missing and security check can’t run

  • workspaces/api-designer/api-designer-extension/package.json (line 126) sets axios to "1.16.0", but npm view axios@1.16.0 returns “Version not found” (would likely break installs).
  • The GitHub securityVulnerabilities GraphQL query fails with Requires authentication (HTTP 401); use an unauthenticated advisory source (e.g., OSV/npm audit) for the security scan.
🤖 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 `@workspaces/api-designer/api-designer-extension/package.json` at line 126, The
package.json entry for the axios dependency currently pins "axios": "1.16.0"
which is a non-existent version—update the "axios" dependency value to a valid
published version (query via npm view or use a known stable 1.x version) in the
package.json "axios" field so installs won't fail, and replace the GitHub
GraphQL "securityVulnerabilities" check (which fails with HTTP 401) with an
unauthenticated advisory source such as OSV or npm audit for the security scan
invocation so the vulnerability scan runs without GitHub auth.

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.

6 participants